📄 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. 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. */#ifndef lintstatic char sccsid[] = "@(#)utility.c 8.2 (Berkeley) 12/15/93";#endif /* not lint */#define PRINTOPTIONS#include "telnetd.h"/* * 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. */ voidttloop(){ void netflush(); DIAG(TD_REPORT, {sprintf(nfrontp, "td: ttloop\r\n"); nfrontp += strlen(nfrontp);}); 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: %m\n"); exit(1); } DIAG(TD_REPORT, {sprintf(nfrontp, "td: ttloop read %d chars\r\n", ncc); nfrontp += strlen(nfrontp);}); 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. */ intstilloob(s) int s; /* socket number */{ static struct timeval timeout = { 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; }} voidptyflush(){ int n; if ((n = pfrontp - pbackp) > 0) { DIAG((TD_REPORT | TD_PTYDATA), { sprintf(nfrontp, "td: ptyflush %d chars\r\n", n); nfrontp += strlen(nfrontp); }); 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. */ char *nextitem(current) 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. */ voidnetclear(){ register 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 /* ENCRYPTION */ thisitem = netobuf;#endif /* ENCRYPTION */ while ((next = nextitem(thisitem)) <= nbackp) { thisitem = next; } /* Now, thisitem is first before/at boundary. */#ifdef ENCRYPTION good = nclearto > netobuf ? nclearto : netobuf;#else /* ENCRYPTION */ good = netobuf; /* where the good bytes go */#endif /* ENCRYPTION */ 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. */ voidnetflush(){ int n; extern int not42; if ((n = nfrontp - nbackp) > 0) { DIAG(TD_REPORT, { sprintf(nfrontp, "td: netflush %d chars\r\n", n); n += strlen(nfrontp); /* get count first */ nfrontp += strlen(nfrontp); /* then move pointer */ });#ifdef ENCRYPTION if (encrypt_output) { char *s = nclearto ? nclearto : nbackp; if (nfrontp - s > 0) { (*encrypt_output)((unsigned char *)s, nfrontp-s); nclearto = nfrontp; } }#endif /* ENCRYPTION */ /* * 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;#ifdef ENCRYPTION if (nbackp > nclearto) nclearto = 0;#endif /* ENCRYPTION */ if (nbackp >= neturg) { neturg = 0; } if (nbackp == nfrontp) { nbackp = nfrontp = netobuf;#ifdef ENCRYPTION nclearto = 0;#endif /* ENCRYPTION */ } 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 */ voidwritenet(ptr, len) 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(f, msg) int f; char *msg;{ char buf[BUFSIZ]; (void) sprintf(buf, "telnetd: %s.\r\n", msg);#ifdef ENCRYPTION if (encrypt_output) { /* * Better turn off encryption first.... * Hope it flushes... */ encrypt_send_end(); netflush(); }#endif /* ENCRYPTION */ (void) write(f, buf, (int)strlen(buf)); sleep(1); /*XXX*/ exit(1);} voidfatalperror(f, msg) int f; char *msg;{ char buf[BUFSIZ], *strerror(); (void) sprintf(buf, "%s: %s\r\n", msg, strerror(errno)); fatal(f, buf);}char editedhost[32]; voidedithost(pat, host) register char *pat; register char *host;{ register char *res = editedhost; char *strncpy(); 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; voidputstr(s) register char *s;{ while (*s) putchr(*s++);} voidputchr(cc) 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" }; voidputf(cp, where) register char *cp; char *where;{ char *slash; time_t t; char db[100];#ifdef STREAMSPTY extern char *index();#else extern char *rindex();#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 = index(line+1, '/');#else slash = rindex(line, '/');#endif if (slash == (char *) 0) 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; } cp++; }}#ifdef DIAGNOSTICS/* * Print telnet options and commands in plain text, if possible. */ voidprintoption(fmt, option) register char *fmt; register int option;{ if (TELOPT_OK(option)) sprintf(nfrontp, "%s %s\r\n", fmt, TELOPT(option)); else if (TELCMD_OK(option)) sprintf(nfrontp, "%s %s\r\n", fmt, TELCMD(option)); else sprintf(nfrontp, "%s %d\r\n", fmt, option); nfrontp += strlen(nfrontp); return;} voidprintsub(direction, pointer, length) char direction; /* '<' or '>' */ unsigned char *pointer; /* where suboption data sits */ int length; /* length of suboption data */{ register int i; char buf[512]; if (!(diagnostic & TD_OPTIONS)) return; if (direction) { sprintf(nfrontp, "td: %s suboption ", direction == '<' ? "recv" : "send"); nfrontp += strlen(nfrontp); if (length >= 3) { register int j; i = pointer[length-2]; j = pointer[length-1]; if (i != IAC || j != SE) { sprintf(nfrontp, "(terminated by "); nfrontp += strlen(nfrontp); if (TELOPT_OK(i)) sprintf(nfrontp, "%s ", TELOPT(i)); else if (TELCMD_OK(i)) sprintf(nfrontp, "%s ", TELCMD(i)); else sprintf(nfrontp, "%d ", i); nfrontp += strlen(nfrontp); if (TELOPT_OK(j)) sprintf(nfrontp, "%s", TELOPT(j)); else if (TELCMD_OK(j)) sprintf(nfrontp, "%s", TELCMD(j)); else sprintf(nfrontp, "%d", j); nfrontp += strlen(nfrontp); sprintf(nfrontp, ", not IAC SE!) "); nfrontp += strlen(nfrontp); } } length -= 2; } if (length < 1) { sprintf(nfrontp, "(Empty suboption??\?)"); nfrontp += strlen(nfrontp); return; } switch (pointer[0]) { case TELOPT_TTYPE: sprintf(nfrontp, "TERMINAL-TYPE "); nfrontp += strlen(nfrontp); switch (pointer[1]) { case TELQUAL_IS: sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2); break; case TELQUAL_SEND: sprintf(nfrontp, "SEND"); break; default: sprintf(nfrontp, "- unknown qualifier %d (0x%x).", pointer[1], pointer[1]); } nfrontp += strlen(nfrontp); break; case TELOPT_TSPEED: sprintf(nfrontp, "TERMINAL-SPEED"); nfrontp += strlen(nfrontp); if (length < 2) { sprintf(nfrontp, " (empty suboption??\?)"); nfrontp += strlen(nfrontp); break; } switch (pointer[1]) { case TELQUAL_IS: sprintf(nfrontp, " IS %.*s", length-2, (char *)pointer+2); nfrontp += strlen(nfrontp); break; default:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -