📄 utility.c
字号:
/* Copyright (C) 1998,2001,2005 Free Software Foundation, Inc. This file is part of GNU Inetutils. GNU Inetutils is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Inetutils is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Inetutils; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */#define TELOPTS#define TELCMDS#define SLC_NAMES#include "telnetd.h"#include <stdarg.h>#ifdef HAVE_TERMIO_H# include <termio.h>#endif#if defined(AUTHENTICATION) || defined(ENCRYPTION)# include <libtelnet/misc.h># define NET_ENCRYPT net_encrypt#else# define NET_ENCRYPT()#endifstatic char netobuf[BUFSIZ+NETSLOP], *nfrontp, *nbackp;static char *neturg; /* one past last byte of urgent data */#ifdef ENCRYPTIONstatic char *nclearto;#endifstatic char ptyobuf[BUFSIZ+NETSLOP], *pfrontp, *pbackp;static char netibuf[BUFSIZ], *netip;static int ncc;static char ptyibuf[BUFSIZ], *ptyip;static int pcc;int not42;static intreadstream (int p, char *ibuf, int bufsize){#ifndef HAVE_STREAMSPTY return read (p, ibuf, bufsize);#else int flags = 0; int ret = 0; struct termios *tsp; struct termio *tp; struct iocblk *ip; char vstop, vstart; int ixon; int newflow; struct strbuf strbufc, strbufd; unsigned char ctlbuf[BUFSIZ]; static int flowstate = -1; strbufc.maxlen = BUFSIZ; strbufc.buf = (char *)ctlbuf; strbufd.maxlen = bufsize-1; strbufd.len = 0; strbufd.buf = ibuf+1; ibuf[0] = 0; ret = getmsg(p, &strbufc, &strbufd, &flags); if (ret < 0) /* error of some sort -- probably EAGAIN */ return -1; if (strbufc.len <= 0 || ctlbuf[0] == M_DATA) { /* data message */ if (strbufd.len > 0) /* real data */ return strbufd.len + 1; /* count header char */ else { /* nothing there */ errno = EAGAIN; return -1; } } /* * It's a control message. Return 1, to look at the flag we set */ switch (ctlbuf[0]) { case M_FLUSH: if (ibuf[1] & FLUSHW) ibuf[0] = TIOCPKT_FLUSHWRITE; return 1; case M_IOCTL: ip = (struct iocblk *) (ibuf+1); switch (ip->ioc_cmd) { case TCSETS: case TCSETSW: case TCSETSF: tsp = (struct termios *) (ibuf + 1 + sizeof(struct iocblk)); vstop = tsp->c_cc[VSTOP]; vstart = tsp->c_cc[VSTART]; ixon = tsp->c_iflag & IXON; break; case TCSETA: case TCSETAW: case TCSETAF: tp = (struct termio *) (ibuf + 1 + sizeof(struct iocblk)); vstop = tp->c_cc[VSTOP]; vstart = tp->c_cc[VSTART]; ixon = tp->c_iflag & IXON; break; default: errno = EAGAIN; return -1; } newflow = (ixon && (vstart == 021) && (vstop == 023)) ? 1 : 0; if (newflow != flowstate) /* it's a change */ { flowstate = newflow; ibuf[0] = newflow ? TIOCPKT_DOSTOP : TIOCPKT_NOSTOP; return 1; } } /* nothing worth doing anything about */ errno = EAGAIN; return -1;#endif /* HAVE_STREAMSPTY */}/* ************************************************************************* *//* Net and PTY I/O functions */voidio_setup (){ pfrontp = pbackp = ptyobuf; nfrontp = nbackp = netobuf;#ifdef ENCRYPTION nclearto = 0;#endif netip = netibuf; ptyip = ptyibuf;}voidset_neturg (){ neturg = nfrontp - 1;}/* net-buffers */voidnet_output_byte (int c){ *nfrontp++ = c;}intnet_output_data (const char *format,...){ va_list args; size_t remaining, ret; va_start (args, format); remaining = BUFSIZ - (nfrontp - netobuf); /* try a netflush() if the room is too low */ if (strlen (format) > remaining || BUFSIZ / 4 > remaining) { netflush (); remaining = BUFSIZ - (nfrontp - netobuf); } ret = vsnprintf (nfrontp, remaining, format, args); nfrontp += ((ret < remaining - 1) ? ret : remaining - 1); va_end (args); return ret;}intnet_output_datalen (const void *buf, size_t l){ size_t remaining; remaining = BUFSIZ - (nfrontp - netobuf); if (remaining < l) { netflush (); remaining = BUFSIZ - (nfrontp - netobuf); } if (remaining < l) return -1; memmove (nfrontp, buf, l); nfrontp += l; return (int) l;}intnet_input_level (){ return ncc;}intnet_output_level (){ return nfrontp - nbackp;}intnet_buffer_is_full (){ return (&netobuf[BUFSIZ] - nfrontp) < 2;}intnet_get_char (int peek){ if (peek) return *netip; else if (ncc > 0) { ncc--; return *netip++ & 0377; }}intnet_read (){ ncc = read (net, netibuf, sizeof (netibuf)); if (ncc < 0 && errno == EWOULDBLOCK) ncc = 0; else if (ncc == 0) { syslog (LOG_INFO, "telnetd: peer died"); cleanup(0); } else if (ncc > 0) { netip = netibuf; DEBUG(debug_report,1, debug_output_data ("td: netread %d chars\r\n", ncc)); DEBUG(debug_net_data,1, printdata("nd", netip, ncc)); } return ncc;}/* PTY buffer functions */intpty_buffer_is_full (){ return (&ptyobuf[BUFSIZ] - pfrontp) < 2;}voidpty_output_byte (int c){ *pfrontp++ = c;} voidpty_output_datalen (const void *data, size_t len){ if ((&ptyobuf[BUFSIZ] - pfrontp) > len) ptyflush (); memcpy (pfrontp, data, len); pfrontp += len;}intpty_input_level (){ return pcc;}intpty_output_level (){ return pfrontp - pbackp;}voidptyflush(){ int n; if ((n = pfrontp - pbackp) > 0) { DEBUG(debug_report, 1, debug_output_data ("td: ptyflush %d chars\r\n", n)); DEBUG(debug_pty_data, 1, 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;}intpty_get_char (int peek){ if (peek) return *ptyip; else if (pcc > 0) { pcc--; return *ptyip++ & 0377; }}intpty_input_putback (const char *str, size_t len){ if (len > &ptyibuf[BUFSIZ] - ptyip) len = &ptyibuf[BUFSIZ] - ptyip; strncpy (ptyip, str, len); pcc += len;}intpty_read (){ pcc = readstream (pty, ptyibuf, BUFSIZ); if (pcc < 0 && (errno == EWOULDBLOCK #ifdef EAGAIN || errno == EAGAIN #endif || errno == EIO)) pcc = 0; ptyip = ptyibuf; DEBUG(debug_report,1, debug_output_data ("ptyread %d chars\r\n", pcc)); DEBUG(debug_pty_data,1, printdata("pty", ptyip, pcc)); return pcc;}/* ************************************************************************* *//* io_drain () * * * 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. */voidio_drain (){ DEBUG(debug_report, 1, debug_output_data("td: ttloop\r\n")); if (nfrontp - nbackp > 0) netflush (); again: ncc = read (net, netibuf, sizeof netibuf); if (ncc < 0) { if (errno == EAGAIN) { syslog (LOG_INFO, "ttloop: retrying"); goto again; } syslog (LOG_INFO, "ttloop: read: %m\n"); exit (1); } else if (ncc == 0) { syslog (LOG_INFO, "ttloop: peer died: %m\n"); exit (1); } DEBUG(debug_report, 1, debug_output_data ("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 s; socket number */intstilloob (int s){ 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"); return FD_ISSET (s, &excepts);}/* * 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 */ { register char *look = current+2; for (;;) if ((*look++&0xff) == IAC && (*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. */#define wewant(p) \ ((nfrontp > p) && ((*p&0xff) == IAC) && \ ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))voidnetclear (){ register char *thisitem, *next; char *good; #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; for (next = thisitem; wewant (next) && nfrontp > next; next = nextitem(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 (){ int n; if ((n = nfrontp - nbackp) > 0) { NET_ENCRYPT (); /* * 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 || !not42) 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -