📄 utility.c
字号:
/* * Copyright (c) 1989 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. *//* * From: @(#)utility.c 5.8 (Berkeley) 3/22/91 */char util_rcsid[] = "$Id: utility.c,v 1.11 1999/12/12 14:59:45 dholland Exp $";#define PRINTOPTIONS#include <stdarg.h>#include <sys/utsname.h>#ifdef AUTHENTICATE#include <libtelnet/auth.h>#endif#include "telnetd.h"/* * utility functions performing io related tasks */voidnetoprintf(const char *fmt, ...){ int len, maxsize; va_list ap; int done=0; while (!done) { maxsize = sizeof(netobuf) - (nfrontp - netobuf); va_start(ap, fmt); len = vsnprintf(nfrontp, maxsize, fmt, ap); va_end(ap); if (len<0 || len==maxsize) { /* didn't fit */ netflush(); } else { done = 1; } } nfrontp += len;}/* * ttloop * * A small subroutine to flush the network output buffer, get some data * from the network, and pass it through the telnet state machine. We * also flush the pty input buffer (by dropping its data) if it becomes * too full. */voidttloop(void){ DIAG(TD_REPORT, netoprintf("td: ttloop\r\n");); if (nfrontp-nbackp) { netflush(); } ncc = read(net, netibuf, sizeof(netibuf)); if (ncc < 0) { syslog(LOG_INFO, "ttloop: read: %m\n"); exit(1); } else if (ncc == 0) { syslog(LOG_INFO, "ttloop: peer died: EOF\n"); exit(1); } DIAG(TD_REPORT, netoprintf("td: ttloop read %d chars\r\n", ncc);); netip = netibuf; telrcv(); /* state machine */ if (ncc > 0) { pfrontp = pbackp = ptyobuf; telrcv(); }} /* end of ttloop *//* * Check a descriptor to see if out of band data exists on it. */int stilloob(int s) /* socket number */{ static struct timeval timeout = { 0, 0 }; fd_set excepts; int value; do { FD_ZERO(&excepts); FD_SET(s, &excepts); value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); } while ((value == -1) && (errno == EINTR)); if (value < 0) { fatalperror(pty, "select"); } if (FD_ISSET(s, &excepts)) { return 1; } else { return 0; }}void ptyflush(void){ int n; if ((n = pfrontp - pbackp) > 0) { DIAG((TD_REPORT | TD_PTYDATA), netoprintf("td: ptyflush %d chars\r\n", n);); DIAG(TD_PTYDATA, printdata("pd", pbackp, n)); n = write(pty, pbackp, n); } if (n < 0) { if (errno == EWOULDBLOCK || errno == EINTR) return; cleanup(0); } pbackp += n; if (pbackp == pfrontp) pbackp = pfrontp = ptyobuf;}/* * nextitem() * * Return the address of the next "item" in the TELNET data * stream. This will be the address of the next character if * the current address is a user data character, or it will * be the address of the character following the TELNET command * if the current address is a TELNET IAC ("I Am a Command") * character. */staticchar *nextitem(char *current){ if ((*current&0xff) != IAC) { return current+1; } switch (*(current+1)&0xff) { case DO: case DONT: case WILL: case WONT: return current+3; case SB: /* loop forever looking for the SE */ { register char *look = current+2; for (;;) { if ((*look++&0xff) == IAC) { if ((*look++&0xff) == SE) { return look; } } } } default: return current+2; }} /* end of nextitem *//* * netclear() * * We are about to do a TELNET SYNCH operation. Clear * the path to the network. * * Things are a bit tricky since we may have sent the first * byte or so of a previous TELNET command into the network. * So, we have to scan the network buffer from the beginning * until we are up to where we want to be. * * A side effect of what we do, just to keep things * simple, is to clear the urgent data pointer. The principal * caller should be setting the urgent data pointer AFTER calling * us in any case. */void netclear(void){ register char *thisitem, *next; char *good;#define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))#if defined(ENCRYPT) thisitem = nclearto > netobuf ? nclearto : netobuf;#else thisitem = netobuf;#endif while ((next = nextitem(thisitem)) <= nbackp) { thisitem = next; } /* Now, thisitem is first before/at boundary. */#if defined(ENCRYPT) good = nclearto > netobuf ? nclearto : netobuf;#else good = netobuf; /* where the good bytes go */#endif while (nfrontp > thisitem) { if (wewant(thisitem)) { int length; next = thisitem; do { next = nextitem(next); } while (wewant(next) && (nfrontp > next)); length = next-thisitem; bcopy(thisitem, good, length); good += length; thisitem = next; } else { thisitem = nextitem(thisitem); } } nbackp = netobuf; nfrontp = good; /* next byte to be sent */ neturg = 0;} /* end of netclear *//* * netflush * Send as much data as possible to the network, * handling requests for urgent data. */extern int not42;voidnetflush(void){ int n; if ((n = nfrontp - nbackp) > 0) { DIAG(TD_REPORT, { netoprintf("td: netflush %d chars\r\n", n); n = nfrontp - nbackp; /* update count */ });#if defined(ENCRYPT) if (encrypt_output) { char *s = nclearto ? nclearto : nbackp; if (nfrontp - s > 0) { (*encrypt_output)((unsigned char *)s, nfrontp-s); nclearto = nfrontp; } }#endif /* * if no urgent data, or if the other side appears to be an * old 4.2 client (and thus unable to survive TCP urgent data), * write the entire buffer in non-OOB mode. */ if ((neturg == 0) || (not42 == 0)) { n = write(net, nbackp, n); /* normal write */ } else { n = neturg - nbackp; /* * In 4.2 (and 4.3) systems, there is some question about * what byte in a sendOOB operation is the "OOB" data. * To make ourselves compatible, we only send ONE byte * out of band, the one WE THINK should be OOB (though * we really have more the TCP philosophy of urgent data * rather than the Unix philosophy of OOB data). */ if (n > 1) { n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */ } else { n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ } } } if (n < 0) { if (errno == EWOULDBLOCK || errno == EINTR) return; cleanup(0); } nbackp += n;#if defined(ENCRYPT) if (nbackp > nclearto) nclearto = 0;#endif if (nbackp >= neturg) { neturg = 0; } if (nbackp == nfrontp) { nbackp = nfrontp = netobuf;#if defined(ENCRYPT) nclearto = 0;#endif } return;} /* end of netflush *//* * writenet * * Just a handy little function to write a bit of raw data to the net. * It will force a transmit of the buffer if necessary * * arguments * ptr - A pointer to a character string to write * len - How many bytes to write */void writenet(register unsigned char *ptr, register int len){ /* flush buffer if no room for new data) */ if ((&netobuf[BUFSIZ] - nfrontp) < len) { /* if this fails, don't worry, buffer is a little big */ netflush(); } bcopy(ptr, nfrontp, len); nfrontp += len;} /* end of writenet *//* * miscellaneous functions doing a variety of little jobs follow ... */voidfatal(int f, const char *msg){ char buf[BUFSIZ]; (void) snprintf(buf, sizeof(buf), "telnetd: %s.\r\n", msg);#if defined(ENCRYPT) if (encrypt_output) { /* * Better turn off encryption first.... * Hope it flushes... */ encrypt_send_end(); netflush(); }#endif (void) write(f, buf, (int)strlen(buf)); sleep(1); /*XXX*/ exit(1);}voidfatalperror(int f, const char *msg){ char buf[BUFSIZ]; snprintf(buf, sizeof(buf), "%s: %s\r\n", msg, strerror(errno)); fatal(f, buf);}char editedhost[32];struct utsname kerninfo;voidedithost(const char *pat, const char *host){ char *res = editedhost; uname(&kerninfo); if (!pat) pat = ""; while (*pat) { switch (*pat) { case '#': if (*host) host++; break; case '@': if (*host) *res++ = *host++; break; default: *res++ = *pat; break; } if (res == &editedhost[sizeof editedhost - 1]) { *res = '\0'; return; } pat++; } if (*host) (void) strncpy(res, host, sizeof editedhost - (res - editedhost) -1); else *res = '\0'; editedhost[sizeof editedhost - 1] = '\0';}static char *putlocation;static voidputstr(const char *s){ while (*s) putchr(*s++);}void putchr(int cc){ *putlocation++ = cc;}static char fmtstr[] = { "%H:%M on %A, %d %B %Y" };void putf(const char *cp, char *where){ char *slash; time_t t; char db[100]; if (where) putlocation = where; while (*cp) { if (*cp != '%') { putchr(*cp++); continue; } switch (*++cp) { case 't': slash = strrchr(line, '/'); if (slash == NULL) putstr(line); else putstr(slash+1); break; case 'h': putstr(editedhost); break; case 'd': (void)time(&t); (void)strftime(db, sizeof(db), fmtstr, localtime(&t)); putstr(db); break; case '%': putchr('%'); break; case 'D': { char buff[128]; if (getdomainname(buff,sizeof(buff)) < 0 || buff[0] == '\0' || strcmp(buff, "(none)") == 0) break; putstr(buff); } break; case 'i': { char buff[3]; FILE *fp; int p, c; if ((fp = fopen(ISSUE_FILE, "r")) == NULL) break; p = '\n'; while ((c = fgetc(fp)) != EOF) { if (p == '\n' && c == '#') { do { c = fgetc(fp); } while (c != EOF && c != '\n'); continue; } else if (c == '%') { buff[0] = c; c = fgetc(fp); if (c == EOF) break; buff[1] = c; buff[2] = '\0'; putf(buff, NULL); } else { if (c == '\n') putchr('\r'); putchr(c); p = c; } }; (void) fclose(fp); } return; /* ignore remainder of the banner string */ /*NOTREACHED*/ case 's': putstr(kerninfo.sysname); break; case 'm': putstr(kerninfo.machine); break; case 'r': putstr(kerninfo.release); break; case 'v':#ifdef __linux__ putstr(kerninfo.version);#else puts(kerninfo.version);#endif break; } cp++; }}#ifdef DIAGNOSTICS/* * Print telnet options and commands in plain text, if possible. */voidprintoption(const char *fmt, int option){ if (TELOPT_OK(option)) netoprintf("%s %s\r\n", fmt, TELOPT(option)); else if (TELCMD_OK(option)) netoprintf("%s %s\r\n", fmt, TELCMD(option)); else netoprintf("%s %d\r\n", fmt, option);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -