utility.c revision 57416
157416Smarkm/* 257416Smarkm * Copyright (c) 1989, 1993 357416Smarkm * The Regents of the University of California. All rights reserved. 457416Smarkm * 557416Smarkm * Redistribution and use in source and binary forms, with or without 657416Smarkm * modification, are permitted provided that the following conditions 757416Smarkm * are met: 857416Smarkm * 1. Redistributions of source code must retain the above copyright 957416Smarkm * notice, this list of conditions and the following disclaimer. 1057416Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1157416Smarkm * notice, this list of conditions and the following disclaimer in the 1257416Smarkm * documentation and/or other materials provided with the distribution. 1357416Smarkm * 3. All advertising materials mentioning features or use of this software 1457416Smarkm * must display the following acknowledgement: 1557416Smarkm * This product includes software developed by the University of 1657416Smarkm * California, Berkeley and its contributors. 1757416Smarkm * 4. Neither the name of the University nor the names of its contributors 1857416Smarkm * may be used to endorse or promote products derived from this software 1957416Smarkm * without specific prior written permission. 2057416Smarkm * 2157416Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2257416Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2357416Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2457416Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2557416Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2657416Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2757416Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2857416Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2957416Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3057416Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3157416Smarkm * SUCH DAMAGE. 3257416Smarkm */ 3357416Smarkm 3457416Smarkm#define PRINTOPTIONS 3557416Smarkm#include "telnetd.h" 3657416Smarkm 3757416SmarkmRCSID("$Id: utility.c,v 1.22 1999/09/16 20:41:38 assar Exp $"); 3857416Smarkm 3957416Smarkm/* 4057416Smarkm * utility functions performing io related tasks 4157416Smarkm */ 4257416Smarkm 4357416Smarkm/* 4457416Smarkm * ttloop 4557416Smarkm * 4657416Smarkm * A small subroutine to flush the network output buffer, get some 4757416Smarkm * data from the network, and pass it through the telnet state 4857416Smarkm * machine. We also flush the pty input buffer (by dropping its data) 4957416Smarkm * if it becomes too full. 5057416Smarkm * 5157416Smarkm * return 0 if OK or 1 if interrupted by a signal. 5257416Smarkm */ 5357416Smarkm 5457416Smarkmint 5557416Smarkmttloop(void) 5657416Smarkm{ 5757416Smarkm void netflush(void); 5857416Smarkm 5957416Smarkm DIAG(TD_REPORT, { 6057416Smarkm output_data("td: ttloop\r\n"); 6157416Smarkm }); 6257416Smarkm if (nfrontp-nbackp) 6357416Smarkm netflush(); 6457416Smarkm ncc = read(net, netibuf, sizeof netibuf); 6557416Smarkm if (ncc < 0) { 6657416Smarkm if (errno == EINTR) 6757416Smarkm return 1; 6857416Smarkm syslog(LOG_INFO, "ttloop: read: %m\n"); 6957416Smarkm exit(1); 7057416Smarkm } else if (ncc == 0) { 7157416Smarkm syslog(LOG_INFO, "ttloop: peer died: %m\n"); 7257416Smarkm exit(1); 7357416Smarkm } 7457416Smarkm DIAG(TD_REPORT, { 7557416Smarkm output_data("td: ttloop read %d chars\r\n", ncc); 7657416Smarkm }); 7757416Smarkm netip = netibuf; 7857416Smarkm telrcv(); /* state machine */ 7957416Smarkm if (ncc > 0) { 8057416Smarkm pfrontp = pbackp = ptyobuf; 8157416Smarkm telrcv(); 8257416Smarkm } 8357416Smarkm return 0; 8457416Smarkm} /* end of ttloop */ 8557416Smarkm 8657416Smarkm/* 8757416Smarkm * Check a descriptor to see if out of band data exists on it. 8857416Smarkm */ 8957416Smarkmint 9057416Smarkmstilloob(int s) 9157416Smarkm{ 9257416Smarkm static struct timeval timeout = { 0 }; 9357416Smarkm fd_set excepts; 9457416Smarkm int value; 9557416Smarkm 9657416Smarkm do { 9757416Smarkm FD_ZERO(&excepts); 9857416Smarkm FD_SET(s, &excepts); 9957416Smarkm value = select(s+1, 0, 0, &excepts, &timeout); 10057416Smarkm } while ((value == -1) && (errno == EINTR)); 10157416Smarkm 10257416Smarkm if (value < 0) { 10357416Smarkm fatalperror(ourpty, "select"); 10457416Smarkm } 10557416Smarkm if (FD_ISSET(s, &excepts)) { 10657416Smarkm return 1; 10757416Smarkm } else { 10857416Smarkm return 0; 10957416Smarkm } 11057416Smarkm} 11157416Smarkm 11257416Smarkmvoid 11357416Smarkmptyflush(void) 11457416Smarkm{ 11557416Smarkm int n; 11657416Smarkm 11757416Smarkm if ((n = pfrontp - pbackp) > 0) { 11857416Smarkm DIAG((TD_REPORT | TD_PTYDATA), { 11957416Smarkm output_data("td: ptyflush %d chars\r\n", n); 12057416Smarkm }); 12157416Smarkm DIAG(TD_PTYDATA, printdata("pd", pbackp, n)); 12257416Smarkm n = write(ourpty, pbackp, n); 12357416Smarkm } 12457416Smarkm if (n < 0) { 12557416Smarkm if (errno == EWOULDBLOCK || errno == EINTR) 12657416Smarkm return; 12757416Smarkm cleanup(0); 12857416Smarkm } 12957416Smarkm pbackp += n; 13057416Smarkm if (pbackp == pfrontp) 13157416Smarkm pbackp = pfrontp = ptyobuf; 13257416Smarkm} 13357416Smarkm 13457416Smarkm/* 13557416Smarkm * nextitem() 13657416Smarkm * 13757416Smarkm * Return the address of the next "item" in the TELNET data 13857416Smarkm * stream. This will be the address of the next character if 13957416Smarkm * the current address is a user data character, or it will 14057416Smarkm * be the address of the character following the TELNET command 14157416Smarkm * if the current address is a TELNET IAC ("I Am a Command") 14257416Smarkm * character. 14357416Smarkm */ 14457416Smarkmchar * 14557416Smarkmnextitem(char *current) 14657416Smarkm{ 14757416Smarkm if ((*current&0xff) != IAC) { 14857416Smarkm return current+1; 14957416Smarkm } 15057416Smarkm switch (*(current+1)&0xff) { 15157416Smarkm case DO: 15257416Smarkm case DONT: 15357416Smarkm case WILL: 15457416Smarkm case WONT: 15557416Smarkm return current+3; 15657416Smarkm case SB:{ 15757416Smarkm /* loop forever looking for the SE */ 15857416Smarkm char *look = current+2; 15957416Smarkm 16057416Smarkm for (;;) { 16157416Smarkm if ((*look++&0xff) == IAC) { 16257416Smarkm if ((*look++&0xff) == SE) { 16357416Smarkm return look; 16457416Smarkm } 16557416Smarkm } 16657416Smarkm } 16757416Smarkm } 16857416Smarkm default: 16957416Smarkm return current+2; 17057416Smarkm } 17157416Smarkm} 17257416Smarkm 17357416Smarkm 17457416Smarkm/* 17557416Smarkm * netclear() 17657416Smarkm * 17757416Smarkm * We are about to do a TELNET SYNCH operation. Clear 17857416Smarkm * the path to the network. 17957416Smarkm * 18057416Smarkm * Things are a bit tricky since we may have sent the first 18157416Smarkm * byte or so of a previous TELNET command into the network. 18257416Smarkm * So, we have to scan the network buffer from the beginning 18357416Smarkm * until we are up to where we want to be. 18457416Smarkm * 18557416Smarkm * A side effect of what we do, just to keep things 18657416Smarkm * simple, is to clear the urgent data pointer. The principal 18757416Smarkm * caller should be setting the urgent data pointer AFTER calling 18857416Smarkm * us in any case. 18957416Smarkm */ 19057416Smarkmvoid 19157416Smarkmnetclear(void) 19257416Smarkm{ 19357416Smarkm char *thisitem, *next; 19457416Smarkm char *good; 19557416Smarkm#define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 19657416Smarkm ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 19757416Smarkm 19857416Smarkm#ifdef ENCRYPTION 19957416Smarkm thisitem = nclearto > netobuf ? nclearto : netobuf; 20057416Smarkm#else 20157416Smarkm thisitem = netobuf; 20257416Smarkm#endif 20357416Smarkm 20457416Smarkm while ((next = nextitem(thisitem)) <= nbackp) { 20557416Smarkm thisitem = next; 20657416Smarkm } 20757416Smarkm 20857416Smarkm /* Now, thisitem is first before/at boundary. */ 20957416Smarkm 21057416Smarkm#ifdef ENCRYPTION 21157416Smarkm good = nclearto > netobuf ? nclearto : netobuf; 21257416Smarkm#else 21357416Smarkm good = netobuf; /* where the good bytes go */ 21457416Smarkm#endif 21557416Smarkm 21657416Smarkm while (nfrontp > thisitem) { 21757416Smarkm if (wewant(thisitem)) { 21857416Smarkm int length; 21957416Smarkm 22057416Smarkm next = thisitem; 22157416Smarkm do { 22257416Smarkm next = nextitem(next); 22357416Smarkm } while (wewant(next) && (nfrontp > next)); 22457416Smarkm length = next-thisitem; 22557416Smarkm memmove(good, thisitem, length); 22657416Smarkm good += length; 22757416Smarkm thisitem = next; 22857416Smarkm } else { 22957416Smarkm thisitem = nextitem(thisitem); 23057416Smarkm } 23157416Smarkm } 23257416Smarkm 23357416Smarkm nbackp = netobuf; 23457416Smarkm nfrontp = good; /* next byte to be sent */ 23557416Smarkm neturg = 0; 23657416Smarkm} /* end of netclear */ 23757416Smarkm 23857416Smarkm/* 23957416Smarkm * netflush 24057416Smarkm * Send as much data as possible to the network, 24157416Smarkm * handling requests for urgent data. 24257416Smarkm */ 24357416Smarkmvoid 24457416Smarkmnetflush(void) 24557416Smarkm{ 24657416Smarkm int n; 24757416Smarkm extern int not42; 24857416Smarkm 24957416Smarkm if ((n = nfrontp - nbackp) > 0) { 25057416Smarkm DIAG(TD_REPORT, 25157416Smarkm { n += output_data("td: netflush %d chars\r\n", n); 25257416Smarkm }); 25357416Smarkm#ifdef ENCRYPTION 25457416Smarkm if (encrypt_output) { 25557416Smarkm char *s = nclearto ? nclearto : nbackp; 25657416Smarkm if (nfrontp - s > 0) { 25757416Smarkm (*encrypt_output)((unsigned char *)s, nfrontp-s); 25857416Smarkm nclearto = nfrontp; 25957416Smarkm } 26057416Smarkm } 26157416Smarkm#endif 26257416Smarkm /* 26357416Smarkm * if no urgent data, or if the other side appears to be an 26457416Smarkm * old 4.2 client (and thus unable to survive TCP urgent data), 26557416Smarkm * write the entire buffer in non-OOB mode. 26657416Smarkm */ 26757416Smarkm#if 1 /* remove this to make it work between solaris 2.6 and linux */ 26857416Smarkm if ((neturg == 0) || (not42 == 0)) { 26957416Smarkm#endif 27057416Smarkm n = write(net, nbackp, n); /* normal write */ 27157416Smarkm#if 1 /* remove this to make it work between solaris 2.6 and linux */ 27257416Smarkm } else { 27357416Smarkm n = neturg - nbackp; 27457416Smarkm /* 27557416Smarkm * In 4.2 (and 4.3) systems, there is some question about 27657416Smarkm * what byte in a sendOOB operation is the "OOB" data. 27757416Smarkm * To make ourselves compatible, we only send ONE byte 27857416Smarkm * out of band, the one WE THINK should be OOB (though 27957416Smarkm * we really have more the TCP philosophy of urgent data 28057416Smarkm * rather than the Unix philosophy of OOB data). 28157416Smarkm */ 28257416Smarkm if (n > 1) { 28357416Smarkm n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */ 28457416Smarkm } else { 28557416Smarkm n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ 28657416Smarkm } 28757416Smarkm } 28857416Smarkm#endif 28957416Smarkm } 29057416Smarkm if (n < 0) { 29157416Smarkm if (errno == EWOULDBLOCK || errno == EINTR) 29257416Smarkm return; 29357416Smarkm cleanup(0); 29457416Smarkm } 29557416Smarkm nbackp += n; 29657416Smarkm#ifdef ENCRYPTION 29757416Smarkm if (nbackp > nclearto) 29857416Smarkm nclearto = 0; 29957416Smarkm#endif 30057416Smarkm if (nbackp >= neturg) { 30157416Smarkm neturg = 0; 30257416Smarkm } 30357416Smarkm if (nbackp == nfrontp) { 30457416Smarkm nbackp = nfrontp = netobuf; 30557416Smarkm#ifdef ENCRYPTION 30657416Smarkm nclearto = 0; 30757416Smarkm#endif 30857416Smarkm } 30957416Smarkm return; 31057416Smarkm} 31157416Smarkm 31257416Smarkm 31357416Smarkm/* 31457416Smarkm * writenet 31557416Smarkm * 31657416Smarkm * Just a handy little function to write a bit of raw data to the net. 31757416Smarkm * It will force a transmit of the buffer if necessary 31857416Smarkm * 31957416Smarkm * arguments 32057416Smarkm * ptr - A pointer to a character string to write 32157416Smarkm * len - How many bytes to write 32257416Smarkm */ 32357416Smarkmvoid 32457416Smarkmwritenet(unsigned char *ptr, int len) 32557416Smarkm{ 32657416Smarkm /* flush buffer if no room for new data) */ 32757416Smarkm while ((&netobuf[BUFSIZ] - nfrontp) < len) { 32857416Smarkm /* if this fails, don't worry, buffer is a little big */ 32957416Smarkm netflush(); 33057416Smarkm } 33157416Smarkm 33257416Smarkm memmove(nfrontp, ptr, len); 33357416Smarkm nfrontp += len; 33457416Smarkm} 33557416Smarkm 33657416Smarkm 33757416Smarkm/* 33857416Smarkm * miscellaneous functions doing a variety of little jobs follow ... 33957416Smarkm */ 34057416Smarkm 34157416Smarkm 34257416Smarkmvoid fatal(int f, char *msg) 34357416Smarkm{ 34457416Smarkm char buf[BUFSIZ]; 34557416Smarkm 34657416Smarkm snprintf(buf, sizeof(buf), "telnetd: %s.\r\n", msg); 34757416Smarkm#ifdef ENCRYPTION 34857416Smarkm if (encrypt_output) { 34957416Smarkm /* 35057416Smarkm * Better turn off encryption first.... 35157416Smarkm * Hope it flushes... 35257416Smarkm */ 35357416Smarkm encrypt_send_end(); 35457416Smarkm netflush(); 35557416Smarkm } 35657416Smarkm#endif 35757416Smarkm write(f, buf, (int)strlen(buf)); 35857416Smarkm sleep(1); /*XXX*/ 35957416Smarkm exit(1); 36057416Smarkm} 36157416Smarkm 36257416Smarkmvoid 36357416Smarkmfatalperror(int f, const char *msg) 36457416Smarkm{ 36557416Smarkm char buf[BUFSIZ]; 36657416Smarkm 36757416Smarkm snprintf(buf, sizeof(buf), "%s: %s", msg, strerror(errno)); 36857416Smarkm fatal(f, buf); 36957416Smarkm} 37057416Smarkm 37157416Smarkmchar editedhost[32]; 37257416Smarkm 37357416Smarkmvoid edithost(char *pat, char *host) 37457416Smarkm{ 37557416Smarkm char *res = editedhost; 37657416Smarkm 37757416Smarkm if (!pat) 37857416Smarkm pat = ""; 37957416Smarkm while (*pat) { 38057416Smarkm switch (*pat) { 38157416Smarkm 38257416Smarkm case '#': 38357416Smarkm if (*host) 38457416Smarkm host++; 38557416Smarkm break; 38657416Smarkm 38757416Smarkm case '@': 38857416Smarkm if (*host) 38957416Smarkm *res++ = *host++; 39057416Smarkm break; 39157416Smarkm 39257416Smarkm default: 39357416Smarkm *res++ = *pat; 39457416Smarkm break; 39557416Smarkm } 39657416Smarkm if (res == &editedhost[sizeof editedhost - 1]) { 39757416Smarkm *res = '\0'; 39857416Smarkm return; 39957416Smarkm } 40057416Smarkm pat++; 40157416Smarkm } 40257416Smarkm if (*host) 40357416Smarkm strlcpy (res, host, 40457416Smarkm sizeof editedhost - (res - editedhost)); 40557416Smarkm else 40657416Smarkm *res = '\0'; 40757416Smarkm editedhost[sizeof editedhost - 1] = '\0'; 40857416Smarkm} 40957416Smarkm 41057416Smarkmstatic char *putlocation; 41157416Smarkm 41257416Smarkmvoid 41357416Smarkmputstr(char *s) 41457416Smarkm{ 41557416Smarkm 41657416Smarkm while (*s) 41757416Smarkm putchr(*s++); 41857416Smarkm} 41957416Smarkm 42057416Smarkmvoid 42157416Smarkmputchr(int cc) 42257416Smarkm{ 42357416Smarkm *putlocation++ = cc; 42457416Smarkm} 42557416Smarkm 42657416Smarkm/* 42757416Smarkm * This is split on two lines so that SCCS will not see the M 42857416Smarkm * between two % signs and expand it... 42957416Smarkm */ 43057416Smarkmstatic char fmtstr[] = { "%l:%M" "%P on %A, %d %B %Y" }; 43157416Smarkm 43257416Smarkmvoid putf(char *cp, char *where) 43357416Smarkm{ 43457416Smarkm#ifdef HAVE_UNAME 43557416Smarkm struct utsname name; 43657416Smarkm#endif 43757416Smarkm char *slash; 43857416Smarkm time_t t; 43957416Smarkm char db[100]; 44057416Smarkm 44157416Smarkm /* if we don't have uname, set these to sensible values */ 44257416Smarkm char *sysname = "Unix", 44357416Smarkm *machine = "", 44457416Smarkm *release = "", 44557416Smarkm *version = ""; 44657416Smarkm 44757416Smarkm#ifdef HAVE_UNAME 44857416Smarkm uname(&name); 44957416Smarkm sysname=name.sysname; 45057416Smarkm machine=name.machine; 45157416Smarkm release=name.release; 45257416Smarkm version=name.version; 45357416Smarkm#endif 45457416Smarkm 45557416Smarkm putlocation = where; 45657416Smarkm 45757416Smarkm while (*cp) { 45857416Smarkm if (*cp != '%') { 45957416Smarkm putchr(*cp++); 46057416Smarkm continue; 46157416Smarkm } 46257416Smarkm switch (*++cp) { 46357416Smarkm 46457416Smarkm case 't': 46557416Smarkm#ifdef STREAMSPTY 46657416Smarkm /* names are like /dev/pts/2 -- we want pts/2 */ 46757416Smarkm slash = strchr(line+1, '/'); 46857416Smarkm#else 46957416Smarkm slash = strrchr(line, '/'); 47057416Smarkm#endif 47157416Smarkm if (slash == (char *) 0) 47257416Smarkm putstr(line); 47357416Smarkm else 47457416Smarkm putstr(&slash[1]); 47557416Smarkm break; 47657416Smarkm 47757416Smarkm case 'h': 47857416Smarkm putstr(editedhost); 47957416Smarkm break; 48057416Smarkm 48157416Smarkm case 's': 48257416Smarkm putstr(sysname); 48357416Smarkm break; 48457416Smarkm 48557416Smarkm case 'm': 48657416Smarkm putstr(machine); 48757416Smarkm break; 48857416Smarkm 48957416Smarkm case 'r': 49057416Smarkm putstr(release); 49157416Smarkm break; 49257416Smarkm 49357416Smarkm case 'v': 49457416Smarkm putstr(version); 49557416Smarkm break; 49657416Smarkm 49757416Smarkm case 'd': 49857416Smarkm time(&t); 49957416Smarkm strftime(db, sizeof(db), fmtstr, localtime(&t)); 50057416Smarkm putstr(db); 50157416Smarkm break; 50257416Smarkm 50357416Smarkm case '%': 50457416Smarkm putchr('%'); 50557416Smarkm break; 50657416Smarkm } 50757416Smarkm cp++; 50857416Smarkm } 50957416Smarkm} 51057416Smarkm 51157416Smarkm#ifdef DIAGNOSTICS 51257416Smarkm/* 51357416Smarkm * Print telnet options and commands in plain text, if possible. 51457416Smarkm */ 51557416Smarkmvoid 51657416Smarkmprintoption(char *fmt, int option) 51757416Smarkm{ 51857416Smarkm if (TELOPT_OK(option)) 51957416Smarkm output_data("%s %s\r\n", 52057416Smarkm fmt, 52157416Smarkm TELOPT(option)); 52257416Smarkm else if (TELCMD_OK(option)) 52357416Smarkm output_data("%s %s\r\n", 52457416Smarkm fmt, 52557416Smarkm TELCMD(option)); 52657416Smarkm else 52757416Smarkm output_data("%s %d\r\n", 52857416Smarkm fmt, 52957416Smarkm option); 53057416Smarkm return; 53157416Smarkm} 53257416Smarkm 53357416Smarkmvoid 53457416Smarkmprintsub(int direction, unsigned char *pointer, int length) 53557416Smarkm /* '<' or '>' */ 53657416Smarkm /* where suboption data sits */ 53757416Smarkm /* length of suboption data */ 53857416Smarkm{ 53957416Smarkm int i = 0; 54057416Smarkm unsigned char buf[512]; 54157416Smarkm 54257416Smarkm if (!(diagnostic & TD_OPTIONS)) 54357416Smarkm return; 54457416Smarkm 54557416Smarkm if (direction) { 54657416Smarkm output_data("td: %s suboption ", 54757416Smarkm direction == '<' ? "recv" : "send"); 54857416Smarkm if (length >= 3) { 54957416Smarkm int j; 55057416Smarkm 55157416Smarkm i = pointer[length-2]; 55257416Smarkm j = pointer[length-1]; 55357416Smarkm 55457416Smarkm if (i != IAC || j != SE) { 55557416Smarkm output_data("(terminated by "); 55657416Smarkm if (TELOPT_OK(i)) 55757416Smarkm output_data("%s ", 55857416Smarkm TELOPT(i)); 55957416Smarkm else if (TELCMD_OK(i)) 56057416Smarkm output_data("%s ", 56157416Smarkm TELCMD(i)); 56257416Smarkm else 56357416Smarkm output_data("%d ", 56457416Smarkm i); 56557416Smarkm if (TELOPT_OK(j)) 56657416Smarkm output_data("%s", 56757416Smarkm TELOPT(j)); 56857416Smarkm else if (TELCMD_OK(j)) 56957416Smarkm output_data("%s", 57057416Smarkm TELCMD(j)); 57157416Smarkm else 57257416Smarkm output_data("%d", 57357416Smarkm j); 57457416Smarkm output_data(", not IAC SE!) "); 57557416Smarkm } 57657416Smarkm } 57757416Smarkm length -= 2; 57857416Smarkm } 57957416Smarkm if (length < 1) { 58057416Smarkm output_data("(Empty suboption??\?)"); 58157416Smarkm return; 58257416Smarkm } 58357416Smarkm switch (pointer[0]) { 58457416Smarkm case TELOPT_TTYPE: 58557416Smarkm output_data("TERMINAL-TYPE "); 58657416Smarkm switch (pointer[1]) { 58757416Smarkm case TELQUAL_IS: 58857416Smarkm output_data("IS \"%.*s\"", 58957416Smarkm length-2, 59057416Smarkm (char *)pointer+2); 59157416Smarkm break; 59257416Smarkm case TELQUAL_SEND: 59357416Smarkm output_data("SEND"); 59457416Smarkm break; 59557416Smarkm default: 59657416Smarkm output_data("- unknown qualifier %d (0x%x).", 59757416Smarkm pointer[1], pointer[1]); 59857416Smarkm } 59957416Smarkm break; 60057416Smarkm case TELOPT_TSPEED: 60157416Smarkm output_data("TERMINAL-SPEED"); 60257416Smarkm if (length < 2) { 60357416Smarkm output_data(" (empty suboption??\?)"); 60457416Smarkm break; 60557416Smarkm } 60657416Smarkm switch (pointer[1]) { 60757416Smarkm case TELQUAL_IS: 60857416Smarkm output_data(" IS %.*s", length-2, (char *)pointer+2); 60957416Smarkm break; 61057416Smarkm default: 61157416Smarkm if (pointer[1] == 1) 61257416Smarkm output_data(" SEND"); 61357416Smarkm else 61457416Smarkm output_data(" %d (unknown)", pointer[1]); 61557416Smarkm for (i = 2; i < length; i++) { 61657416Smarkm output_data(" ?%d?", pointer[i]); 61757416Smarkm } 61857416Smarkm break; 61957416Smarkm } 62057416Smarkm break; 62157416Smarkm 62257416Smarkm case TELOPT_LFLOW: 62357416Smarkm output_data("TOGGLE-FLOW-CONTROL"); 62457416Smarkm if (length < 2) { 62557416Smarkm output_data(" (empty suboption??\?)"); 62657416Smarkm break; 62757416Smarkm } 62857416Smarkm switch (pointer[1]) { 62957416Smarkm case LFLOW_OFF: 63057416Smarkm output_data(" OFF"); 63157416Smarkm break; 63257416Smarkm case LFLOW_ON: 63357416Smarkm output_data(" ON"); 63457416Smarkm break; 63557416Smarkm case LFLOW_RESTART_ANY: 63657416Smarkm output_data(" RESTART-ANY"); 63757416Smarkm break; 63857416Smarkm case LFLOW_RESTART_XON: 63957416Smarkm output_data(" RESTART-XON"); 64057416Smarkm break; 64157416Smarkm default: 64257416Smarkm output_data(" %d (unknown)", 64357416Smarkm pointer[1]); 64457416Smarkm } 64557416Smarkm for (i = 2; i < length; i++) { 64657416Smarkm output_data(" ?%d?", 64757416Smarkm pointer[i]); 64857416Smarkm } 64957416Smarkm break; 65057416Smarkm 65157416Smarkm case TELOPT_NAWS: 65257416Smarkm output_data("NAWS"); 65357416Smarkm if (length < 2) { 65457416Smarkm output_data(" (empty suboption??\?)"); 65557416Smarkm break; 65657416Smarkm } 65757416Smarkm if (length == 2) { 65857416Smarkm output_data(" ?%d?", 65957416Smarkm pointer[1]); 66057416Smarkm break; 66157416Smarkm } 66257416Smarkm output_data(" %u %u(%u)", 66357416Smarkm pointer[1], 66457416Smarkm pointer[2], 66557416Smarkm (((unsigned int)pointer[1])<<8) + pointer[2]); 66657416Smarkm if (length == 4) { 66757416Smarkm output_data(" ?%d?", 66857416Smarkm pointer[3]); 66957416Smarkm break; 67057416Smarkm } 67157416Smarkm output_data(" %u %u(%u)", 67257416Smarkm pointer[3], 67357416Smarkm pointer[4], 67457416Smarkm (((unsigned int)pointer[3])<<8) + pointer[4]); 67557416Smarkm for (i = 5; i < length; i++) { 67657416Smarkm output_data(" ?%d?", 67757416Smarkm pointer[i]); 67857416Smarkm } 67957416Smarkm break; 68057416Smarkm 68157416Smarkm case TELOPT_LINEMODE: 68257416Smarkm output_data("LINEMODE "); 68357416Smarkm if (length < 2) { 68457416Smarkm output_data(" (empty suboption??\?)"); 68557416Smarkm break; 68657416Smarkm } 68757416Smarkm switch (pointer[1]) { 68857416Smarkm case WILL: 68957416Smarkm output_data("WILL "); 69057416Smarkm goto common; 69157416Smarkm case WONT: 69257416Smarkm output_data("WONT "); 69357416Smarkm goto common; 69457416Smarkm case DO: 69557416Smarkm output_data("DO "); 69657416Smarkm goto common; 69757416Smarkm case DONT: 69857416Smarkm output_data("DONT "); 69957416Smarkm common: 70057416Smarkm if (length < 3) { 70157416Smarkm output_data("(no option??\?)"); 70257416Smarkm break; 70357416Smarkm } 70457416Smarkm switch (pointer[2]) { 70557416Smarkm case LM_FORWARDMASK: 70657416Smarkm output_data("Forward Mask"); 70757416Smarkm for (i = 3; i < length; i++) { 70857416Smarkm output_data(" %x", pointer[i]); 70957416Smarkm } 71057416Smarkm break; 71157416Smarkm default: 71257416Smarkm output_data("%d (unknown)", 71357416Smarkm pointer[2]); 71457416Smarkm for (i = 3; i < length; i++) { 71557416Smarkm output_data(" %d", 71657416Smarkm pointer[i]); 71757416Smarkm } 71857416Smarkm break; 71957416Smarkm } 72057416Smarkm break; 72157416Smarkm 72257416Smarkm case LM_SLC: 72357416Smarkm output_data("SLC"); 72457416Smarkm for (i = 2; i < length - 2; i += 3) { 72557416Smarkm if (SLC_NAME_OK(pointer[i+SLC_FUNC])) 72657416Smarkm output_data(" %s", 72757416Smarkm SLC_NAME(pointer[i+SLC_FUNC])); 72857416Smarkm else 72957416Smarkm output_data(" %d", 73057416Smarkm pointer[i+SLC_FUNC]); 73157416Smarkm switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) { 73257416Smarkm case SLC_NOSUPPORT: 73357416Smarkm output_data(" NOSUPPORT"); 73457416Smarkm break; 73557416Smarkm case SLC_CANTCHANGE: 73657416Smarkm output_data(" CANTCHANGE"); 73757416Smarkm break; 73857416Smarkm case SLC_VARIABLE: 73957416Smarkm output_data(" VARIABLE"); 74057416Smarkm break; 74157416Smarkm case SLC_DEFAULT: 74257416Smarkm output_data(" DEFAULT"); 74357416Smarkm break; 74457416Smarkm } 74557416Smarkm output_data("%s%s%s", 74657416Smarkm pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "", 74757416Smarkm pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "", 74857416Smarkm pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : ""); 74957416Smarkm if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN| 75057416Smarkm SLC_FLUSHOUT| SLC_LEVELBITS)) { 75157416Smarkm output_data("(0x%x)", 75257416Smarkm pointer[i+SLC_FLAGS]); 75357416Smarkm } 75457416Smarkm output_data(" %d;", 75557416Smarkm pointer[i+SLC_VALUE]); 75657416Smarkm if ((pointer[i+SLC_VALUE] == IAC) && 75757416Smarkm (pointer[i+SLC_VALUE+1] == IAC)) 75857416Smarkm i++; 75957416Smarkm } 76057416Smarkm for (; i < length; i++) { 76157416Smarkm output_data(" ?%d?", 76257416Smarkm pointer[i]); 76357416Smarkm } 76457416Smarkm break; 76557416Smarkm 76657416Smarkm case LM_MODE: 76757416Smarkm output_data("MODE "); 76857416Smarkm if (length < 3) { 76957416Smarkm output_data("(no mode??\?)"); 77057416Smarkm break; 77157416Smarkm } 77257416Smarkm { 77357416Smarkm char tbuf[32]; 77457416Smarkm snprintf(tbuf, 77557416Smarkm sizeof(tbuf), 77657416Smarkm "%s%s%s%s%s", 77757416Smarkm pointer[2]&MODE_EDIT ? "|EDIT" : "", 77857416Smarkm pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "", 77957416Smarkm pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "", 78057416Smarkm pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "", 78157416Smarkm pointer[2]&MODE_ACK ? "|ACK" : ""); 78257416Smarkm output_data("%s", 78357416Smarkm tbuf[1] ? &tbuf[1] : "0"); 78457416Smarkm } 78557416Smarkm if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) { 78657416Smarkm output_data(" (0x%x)", 78757416Smarkm pointer[2]); 78857416Smarkm } 78957416Smarkm for (i = 3; i < length; i++) { 79057416Smarkm output_data(" ?0x%x?", 79157416Smarkm pointer[i]); 79257416Smarkm } 79357416Smarkm break; 79457416Smarkm default: 79557416Smarkm output_data("%d (unknown)", 79657416Smarkm pointer[1]); 79757416Smarkm for (i = 2; i < length; i++) { 79857416Smarkm output_data(" %d", pointer[i]); 79957416Smarkm } 80057416Smarkm } 80157416Smarkm break; 80257416Smarkm 80357416Smarkm case TELOPT_STATUS: { 80457416Smarkm char *cp; 80557416Smarkm int j, k; 80657416Smarkm 80757416Smarkm output_data("STATUS"); 80857416Smarkm 80957416Smarkm switch (pointer[1]) { 81057416Smarkm default: 81157416Smarkm if (pointer[1] == TELQUAL_SEND) 81257416Smarkm output_data(" SEND"); 81357416Smarkm else 81457416Smarkm output_data(" %d (unknown)", 81557416Smarkm pointer[1]); 81657416Smarkm for (i = 2; i < length; i++) { 81757416Smarkm output_data(" ?%d?", 81857416Smarkm pointer[i]); 81957416Smarkm } 82057416Smarkm break; 82157416Smarkm case TELQUAL_IS: 82257416Smarkm output_data(" IS\r\n"); 82357416Smarkm 82457416Smarkm for (i = 2; i < length; i++) { 82557416Smarkm switch(pointer[i]) { 82657416Smarkm case DO: cp = "DO"; goto common2; 82757416Smarkm case DONT: cp = "DONT"; goto common2; 82857416Smarkm case WILL: cp = "WILL"; goto common2; 82957416Smarkm case WONT: cp = "WONT"; goto common2; 83057416Smarkm common2: 83157416Smarkm i++; 83257416Smarkm if (TELOPT_OK(pointer[i])) 83357416Smarkm output_data(" %s %s", 83457416Smarkm cp, 83557416Smarkm TELOPT(pointer[i])); 83657416Smarkm else 83757416Smarkm output_data(" %s %d", 83857416Smarkm cp, 83957416Smarkm pointer[i]); 84057416Smarkm 84157416Smarkm output_data("\r\n"); 84257416Smarkm break; 84357416Smarkm 84457416Smarkm case SB: 84557416Smarkm output_data(" SB "); 84657416Smarkm i++; 84757416Smarkm j = k = i; 84857416Smarkm while (j < length) { 84957416Smarkm if (pointer[j] == SE) { 85057416Smarkm if (j+1 == length) 85157416Smarkm break; 85257416Smarkm if (pointer[j+1] == SE) 85357416Smarkm j++; 85457416Smarkm else 85557416Smarkm break; 85657416Smarkm } 85757416Smarkm pointer[k++] = pointer[j++]; 85857416Smarkm } 85957416Smarkm printsub(0, &pointer[i], k - i); 86057416Smarkm if (i < length) { 86157416Smarkm output_data(" SE"); 86257416Smarkm i = j; 86357416Smarkm } else 86457416Smarkm i = j - 1; 86557416Smarkm 86657416Smarkm output_data("\r\n"); 86757416Smarkm 86857416Smarkm break; 86957416Smarkm 87057416Smarkm default: 87157416Smarkm output_data(" %d", 87257416Smarkm pointer[i]); 87357416Smarkm break; 87457416Smarkm } 87557416Smarkm } 87657416Smarkm break; 87757416Smarkm } 87857416Smarkm break; 87957416Smarkm } 88057416Smarkm 88157416Smarkm case TELOPT_XDISPLOC: 88257416Smarkm output_data("X-DISPLAY-LOCATION "); 88357416Smarkm switch (pointer[1]) { 88457416Smarkm case TELQUAL_IS: 88557416Smarkm output_data("IS \"%.*s\"", 88657416Smarkm length-2, 88757416Smarkm (char *)pointer+2); 88857416Smarkm break; 88957416Smarkm case TELQUAL_SEND: 89057416Smarkm output_data("SEND"); 89157416Smarkm break; 89257416Smarkm default: 89357416Smarkm output_data("- unknown qualifier %d (0x%x).", 89457416Smarkm pointer[1], pointer[1]); 89557416Smarkm } 89657416Smarkm break; 89757416Smarkm 89857416Smarkm case TELOPT_NEW_ENVIRON: 89957416Smarkm output_data("NEW-ENVIRON "); 90057416Smarkm goto env_common1; 90157416Smarkm case TELOPT_OLD_ENVIRON: 90257416Smarkm output_data("OLD-ENVIRON"); 90357416Smarkm env_common1: 90457416Smarkm switch (pointer[1]) { 90557416Smarkm case TELQUAL_IS: 90657416Smarkm output_data("IS "); 90757416Smarkm goto env_common; 90857416Smarkm case TELQUAL_SEND: 90957416Smarkm output_data("SEND "); 91057416Smarkm goto env_common; 91157416Smarkm case TELQUAL_INFO: 91257416Smarkm output_data("INFO "); 91357416Smarkm env_common: 91457416Smarkm { 91557416Smarkm int noquote = 2; 91657416Smarkm for (i = 2; i < length; i++ ) { 91757416Smarkm switch (pointer[i]) { 91857416Smarkm case NEW_ENV_VAR: 91957416Smarkm output_data("\" VAR " + noquote); 92057416Smarkm noquote = 2; 92157416Smarkm break; 92257416Smarkm 92357416Smarkm case NEW_ENV_VALUE: 92457416Smarkm output_data("\" VALUE " + noquote); 92557416Smarkm noquote = 2; 92657416Smarkm break; 92757416Smarkm 92857416Smarkm case ENV_ESC: 92957416Smarkm output_data("\" ESC " + noquote); 93057416Smarkm noquote = 2; 93157416Smarkm break; 93257416Smarkm 93357416Smarkm case ENV_USERVAR: 93457416Smarkm output_data("\" USERVAR " + noquote); 93557416Smarkm noquote = 2; 93657416Smarkm break; 93757416Smarkm 93857416Smarkm default: 93957416Smarkm if (isprint(pointer[i]) && pointer[i] != '"') { 94057416Smarkm if (noquote) { 94157416Smarkm output_data ("\""); 94257416Smarkm noquote = 0; 94357416Smarkm } 94457416Smarkm output_data ("%c", pointer[i]); 94557416Smarkm } else { 94657416Smarkm output_data("\" %03o " + noquote, 94757416Smarkm pointer[i]); 94857416Smarkm noquote = 2; 94957416Smarkm } 95057416Smarkm break; 95157416Smarkm } 95257416Smarkm } 95357416Smarkm if (!noquote) 95457416Smarkm output_data ("\""); 95557416Smarkm break; 95657416Smarkm } 95757416Smarkm } 95857416Smarkm break; 95957416Smarkm 96057416Smarkm#ifdef AUTHENTICATION 96157416Smarkm case TELOPT_AUTHENTICATION: 96257416Smarkm output_data("AUTHENTICATION"); 96357416Smarkm 96457416Smarkm if (length < 2) { 96557416Smarkm output_data(" (empty suboption??\?)"); 96657416Smarkm break; 96757416Smarkm } 96857416Smarkm switch (pointer[1]) { 96957416Smarkm case TELQUAL_REPLY: 97057416Smarkm case TELQUAL_IS: 97157416Smarkm output_data(" %s ", 97257416Smarkm (pointer[1] == TELQUAL_IS) ? 97357416Smarkm "IS" : "REPLY"); 97457416Smarkm if (AUTHTYPE_NAME_OK(pointer[2])) 97557416Smarkm output_data("%s ", 97657416Smarkm AUTHTYPE_NAME(pointer[2])); 97757416Smarkm else 97857416Smarkm output_data("%d ", 97957416Smarkm pointer[2]); 98057416Smarkm if (length < 3) { 98157416Smarkm output_data("(partial suboption??\?)"); 98257416Smarkm break; 98357416Smarkm } 98457416Smarkm output_data("%s|%s", 98557416Smarkm ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? 98657416Smarkm "CLIENT" : "SERVER", 98757416Smarkm ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? 98857416Smarkm "MUTUAL" : "ONE-WAY"); 98957416Smarkm 99057416Smarkm auth_printsub(&pointer[1], length - 1, buf, sizeof(buf)); 99157416Smarkm output_data("%s", 99257416Smarkm buf); 99357416Smarkm break; 99457416Smarkm 99557416Smarkm case TELQUAL_SEND: 99657416Smarkm i = 2; 99757416Smarkm output_data(" SEND "); 99857416Smarkm while (i < length) { 99957416Smarkm if (AUTHTYPE_NAME_OK(pointer[i])) 100057416Smarkm output_data("%s ", 100157416Smarkm AUTHTYPE_NAME(pointer[i])); 100257416Smarkm else 100357416Smarkm output_data("%d ", 100457416Smarkm pointer[i]); 100557416Smarkm if (++i >= length) { 100657416Smarkm output_data("(partial suboption??\?)"); 100757416Smarkm break; 100857416Smarkm } 100957416Smarkm output_data("%s|%s ", 101057416Smarkm ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? 101157416Smarkm "CLIENT" : "SERVER", 101257416Smarkm ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? 101357416Smarkm "MUTUAL" : "ONE-WAY"); 101457416Smarkm ++i; 101557416Smarkm } 101657416Smarkm break; 101757416Smarkm 101857416Smarkm case TELQUAL_NAME: 101957416Smarkm i = 2; 102057416Smarkm output_data(" NAME \"%.*s\"", 102157416Smarkm length - 2, 102257416Smarkm pointer); 102357416Smarkm break; 102457416Smarkm 102557416Smarkm default: 102657416Smarkm for (i = 2; i < length; i++) { 102757416Smarkm output_data(" ?%d?", 102857416Smarkm pointer[i]); 102957416Smarkm } 103057416Smarkm break; 103157416Smarkm } 103257416Smarkm break; 103357416Smarkm#endif 103457416Smarkm 103557416Smarkm#ifdef ENCRYPTION 103657416Smarkm case TELOPT_ENCRYPT: 103757416Smarkm output_data("ENCRYPT"); 103857416Smarkm if (length < 2) { 103957416Smarkm output_data(" (empty suboption?)"); 104057416Smarkm break; 104157416Smarkm } 104257416Smarkm switch (pointer[1]) { 104357416Smarkm case ENCRYPT_START: 104457416Smarkm output_data(" START"); 104557416Smarkm break; 104657416Smarkm 104757416Smarkm case ENCRYPT_END: 104857416Smarkm output_data(" END"); 104957416Smarkm break; 105057416Smarkm 105157416Smarkm case ENCRYPT_REQSTART: 105257416Smarkm output_data(" REQUEST-START"); 105357416Smarkm break; 105457416Smarkm 105557416Smarkm case ENCRYPT_REQEND: 105657416Smarkm output_data(" REQUEST-END"); 105757416Smarkm break; 105857416Smarkm 105957416Smarkm case ENCRYPT_IS: 106057416Smarkm case ENCRYPT_REPLY: 106157416Smarkm output_data(" %s ", 106257416Smarkm (pointer[1] == ENCRYPT_IS) ? 106357416Smarkm "IS" : "REPLY"); 106457416Smarkm if (length < 3) { 106557416Smarkm output_data(" (partial suboption?)"); 106657416Smarkm break; 106757416Smarkm } 106857416Smarkm if (ENCTYPE_NAME_OK(pointer[2])) 106957416Smarkm output_data("%s ", 107057416Smarkm ENCTYPE_NAME(pointer[2])); 107157416Smarkm else 107257416Smarkm output_data(" %d (unknown)", 107357416Smarkm pointer[2]); 107457416Smarkm 107557416Smarkm encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf)); 107657416Smarkm output_data("%s", 107757416Smarkm buf); 107857416Smarkm break; 107957416Smarkm 108057416Smarkm case ENCRYPT_SUPPORT: 108157416Smarkm i = 2; 108257416Smarkm output_data(" SUPPORT "); 108357416Smarkm while (i < length) { 108457416Smarkm if (ENCTYPE_NAME_OK(pointer[i])) 108557416Smarkm output_data("%s ", 108657416Smarkm ENCTYPE_NAME(pointer[i])); 108757416Smarkm else 108857416Smarkm output_data("%d ", 108957416Smarkm pointer[i]); 109057416Smarkm i++; 109157416Smarkm } 109257416Smarkm break; 109357416Smarkm 109457416Smarkm case ENCRYPT_ENC_KEYID: 109557416Smarkm output_data(" ENC_KEYID %d", pointer[1]); 109657416Smarkm goto encommon; 109757416Smarkm 109857416Smarkm case ENCRYPT_DEC_KEYID: 109957416Smarkm output_data(" DEC_KEYID %d", pointer[1]); 110057416Smarkm goto encommon; 110157416Smarkm 110257416Smarkm default: 110357416Smarkm output_data(" %d (unknown)", pointer[1]); 110457416Smarkm encommon: 110557416Smarkm for (i = 2; i < length; i++) { 110657416Smarkm output_data(" %d", pointer[i]); 110757416Smarkm } 110857416Smarkm break; 110957416Smarkm } 111057416Smarkm break; 111157416Smarkm#endif 111257416Smarkm 111357416Smarkm default: 111457416Smarkm if (TELOPT_OK(pointer[0])) 111557416Smarkm output_data("%s (unknown)", 111657416Smarkm TELOPT(pointer[0])); 111757416Smarkm else 111857416Smarkm output_data("%d (unknown)", 111957416Smarkm pointer[i]); 112057416Smarkm for (i = 1; i < length; i++) { 112157416Smarkm output_data(" %d", pointer[i]); 112257416Smarkm } 112357416Smarkm break; 112457416Smarkm } 112557416Smarkm output_data("\r\n"); 112657416Smarkm} 112757416Smarkm 112857416Smarkm/* 112957416Smarkm * Dump a data buffer in hex and ascii to the output data stream. 113057416Smarkm */ 113157416Smarkmvoid 113257416Smarkmprintdata(char *tag, char *ptr, int cnt) 113357416Smarkm{ 113457416Smarkm int i; 113557416Smarkm char xbuf[30]; 113657416Smarkm 113757416Smarkm while (cnt) { 113857416Smarkm /* flush net output buffer if no room for new data) */ 113957416Smarkm if ((&netobuf[BUFSIZ] - nfrontp) < 80) { 114057416Smarkm netflush(); 114157416Smarkm } 114257416Smarkm 114357416Smarkm /* add a line of output */ 114457416Smarkm output_data("%s: ", tag); 114557416Smarkm for (i = 0; i < 20 && cnt; i++) { 114657416Smarkm output_data("%02x", *ptr); 114757416Smarkm if (isprint(*ptr)) { 114857416Smarkm xbuf[i] = *ptr; 114957416Smarkm } else { 115057416Smarkm xbuf[i] = '.'; 115157416Smarkm } 115257416Smarkm if (i % 2) { 115357416Smarkm output_data(" "); 115457416Smarkm } 115557416Smarkm cnt--; 115657416Smarkm ptr++; 115757416Smarkm } 115857416Smarkm xbuf[i] = '\0'; 115957416Smarkm output_data(" %s\r\n", xbuf); 116057416Smarkm } 116157416Smarkm} 116257416Smarkm#endif /* DIAGNOSTICS */ 1163