?? utility.c
字號:
/* * Copyright (c) 1989, 1993 * The 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. 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. */#define PRINTOPTIONS#include "telnetd.h"/* RCSID("$KTH: utility.c,v 1.25 2001/05/17 00:34:42 assar Exp $"); *//* * utility functions performing io related tasks *//* * 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. * * return 0 if OK or 1 if interrupted by a signal. */intttloop(void){ void netflush(void); DIAG(TD_REPORT, { output_data("td: ttloop\r\n"); }); if (nfrontp-nbackp) netflush(); ncc = read(net, netibuf, sizeof netibuf); if (ncc < 0) { if (errno == EINTR) return 1; syslog(LOG_INFO, "ttloop: read: %m"); exit(1); } else if (ncc == 0) { syslog(LOG_INFO, "ttloop: peer died"); exit(1); } DIAG(TD_REPORT, { output_data("td: ttloop read %d chars\r\n", ncc); }); netip = netibuf; telrcv(); /* state machine */ if (ncc > 0) { pfrontp = pbackp = ptyobuf; telrcv(); } return 0;} /* end of ttloop *//* * Check a descriptor to see if out of band data exists on it. */intstilloob(int s){ static struct timeval timeout = { 0 }; fd_set excepts; int value; if (s >= FD_SETSIZE) fatal(ourpty, "fd too large"); do { FD_ZERO(&excepts); FD_SET(s, &excepts); value = select(s+1, 0, 0, &excepts, &timeout); } while ((value == -1) && (errno == EINTR)); if (value < 0) { fatalperror(ourpty, "select"); } if (FD_ISSET(s, &excepts)) { return 1; } else { return 0; }}voidptyflush(void){ int n; if ((n = pfrontp - pbackp) > 0) { DIAG((TD_REPORT | TD_PTYDATA), { output_data("td: ptyflush %d chars\r\n", n); }); DIAG(TD_PTYDATA, printdata("pd", pbackp, n)); n = write(ourpty, 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. */char *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 */ char *look = current+2; for (;;) { if ((*look++&0xff) == IAC) { if ((*look++&0xff) == SE) { return look; } } } } default: return current+2; }}/* * 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. */voidnetclear(void){ char *thisitem, *next; char *good;#define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))#ifdef ENCRYPTION thisitem = nclearto > netobuf ? nclearto : netobuf;#else thisitem = netobuf;#endif while ((next = nextitem(thisitem)) <= nbackp) { thisitem = next; } /* Now, thisitem is first before/at boundary. */#ifdef ENCRYPTION 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; memmove(good, thisitem, 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. */voidnetflush(void){ int n; extern int not42; if ((n = nfrontp - nbackp) > 0) { DIAG(TD_REPORT, { n += output_data("td: netflush %d chars\r\n", n); });#ifdef ENCRYPTION 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 1 /* remove this to make it work between solaris 2.6 and linux */ if ((neturg == 0) || (not42 == 0)) {#endif n = write(net, nbackp, n); /* normal write */#if 1 /* remove this to make it work between solaris 2.6 and linux */ } 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 */ } }#endif } if (n < 0) { if (errno == EWOULDBLOCK || errno == EINTR) return; cleanup(0); } nbackp += n;#ifdef ENCRYPTION if (nbackp > nclearto) nclearto = 0;#endif if (nbackp >= neturg) { neturg = 0; } if (nbackp == nfrontp) { nbackp = nfrontp = netobuf;#ifdef ENCRYPTION nclearto = 0;#endif } return;}/* * 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 */voidwritenet(unsigned char *ptr, int len){ /* flush buffer if no room for new data) */ while ((&netobuf[BUFSIZ] - nfrontp) < len) { /* if this fails, don't worry, buffer is a little big */ netflush(); } memmove(nfrontp, ptr, len); nfrontp += len;}/* * miscellaneous functions doing a variety of little jobs follow ... */void fatal(int f, char *msg){ char buf[BUFSIZ]; snprintf(buf, sizeof(buf), "telnetd: %s.\r\n", msg);#ifdef ENCRYPTION if (encrypt_output) { /* * Better turn off encryption first.... * Hope it flushes... */ encrypt_send_end(); netflush(); }#endif write(f, buf, (int)strlen(buf)); sleep(1); /*XXX*/ exit(1);}voidfatalperror_errno(int f, const char *msg, int error){ char buf[BUFSIZ]; snprintf(buf, sizeof(buf), "%s: %s", msg, strerror(error)); fatal(f, buf);}voidfatalperror(int f, const char *msg){ fatalperror_errno(f, msg, errno);}char editedhost[32];void edithost(char *pat, char *host){ char *res = editedhost; 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) strlcpy (res, host, sizeof editedhost - (res - editedhost)); else *res = '\0'; editedhost[sizeof editedhost - 1] = '\0';}static char *putlocation;voidputstr(char *s){ while (*s) putchr(*s++);}voidputchr(int cc){ *putlocation++ = cc;}/* * This is split on two lines so that SCCS will not see the M * between two % signs and expand it... */static char fmtstr[] = { "%l:%M" "%P on %A, %d %B %Y" };void putf(char *cp, char *where){#ifdef HAVE_UNAME struct utsname name;#endif char *slash; time_t t; char db[100]; /* if we don't have uname, set these to sensible values */ char *sysname = "Unix", *machine = "", *release = "", *version = ""; #ifdef HAVE_UNAME uname(&name); sysname=name.sysname; machine=name.machine; release=name.release; version=name.version;#endif putlocation = where; while (*cp) { if (*cp != '%') { putchr(*cp++); continue; } switch (*++cp) { case 't':#ifdef STREAMSPTY /* names are like /dev/pts/2 -- we want pts/2 */ slash = strchr(line+1, '/');#else slash = strrchr(line, '/');#endif if (slash == (char *) 0) putstr(line); else putstr(&slash[1]); break; case 'h': putstr(editedhost); break; case 's': putstr(sysname); break; case 'm': putstr(machine); break; case 'r': putstr(release); break; case 'v': putstr(version); break; case 'd': time(&t); strftime(db, sizeof(db), fmtstr, localtime(&t)); putstr(db); break; case '%': putchr('%'); break; } cp++; }}#ifdef DIAGNOSTICS/* * Print telnet options and commands in plain text, if possible. */voidprintoption(char *fmt, int option){ if (TELOPT_OK(option)) output_data("%s %s\r\n", fmt, TELOPT(option)); else if (TELCMD_OK(option)) output_data("%s %s\r\n", fmt, TELCMD(option)); else output_data("%s %d\r\n", fmt, option); return;}voidprintsub(int direction, unsigned char *pointer, int length) /* '<' or '>' */ /* where suboption data sits */ /* length of suboption data */{ int i = 0;#ifdef AUTHENTICATION unsigned char buf[512];#endif if (!(diagnostic & TD_OPTIONS)) return; if (direction) { output_data("td: %s suboption ", direction == '<' ? "recv" : "send"); if (length >= 3) { int j; i = pointer[length-2]; j = pointer[length-1]; if (i != IAC || j != SE) { output_data("(terminated by "); if (TELOPT_OK(i)) output_data("%s ", TELOPT(i)); else if (TELCMD_OK(i)) output_data("%s ", TELCMD(i)); else output_data("%d ", i); if (TELOPT_OK(j)) output_data("%s", TELOPT(j)); else if (TELCMD_OK(j)) output_data("%s", TELCMD(j)); else output_data("%d", j); output_data(", not IAC SE!) "); } } length -= 2; }
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -