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