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