Home | History | Annotate | Download | only in snoop
      1     0    stevel /*
      2     0    stevel  * CDDL HEADER START
      3     0    stevel  *
      4     0    stevel  * The contents of this file are subject to the terms of the
      5  1676       jpk  * Common Development and Distribution License (the "License").
      6  1676       jpk  * You may not use this file except in compliance with the License.
      7     0    stevel  *
      8     0    stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9     0    stevel  * or http://www.opensolaris.org/os/licensing.
     10     0    stevel  * See the License for the specific language governing permissions
     11     0    stevel  * and limitations under the License.
     12     0    stevel  *
     13     0    stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14     0    stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15     0    stevel  * If applicable, add the following below this CDDL HEADER, with the
     16     0    stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17     0    stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18     0    stevel  *
     19     0    stevel  * CDDL HEADER END
     20     0    stevel  */
     21     0    stevel /*
     22  3431  carlsonj  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
     23     0    stevel  * Use is subject to license terms.
     24     0    stevel  */
     25     0    stevel 
     26     0    stevel 
     27     0    stevel #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SunOS */
     28     0    stevel 
     29  1676       jpk #include <stdio.h>
     30  1676       jpk #include <stdlib.h>
     31     0    stevel #include <ctype.h>
     32  1676       jpk #include <strings.h>
     33     0    stevel #include <sys/sysmacros.h>
     34     0    stevel #include <sys/types.h>
     35     0    stevel #include <sys/errno.h>
     36     0    stevel #include <setjmp.h>
     37     0    stevel #include <sys/socket.h>
     38     0    stevel #include <net/if.h>
     39     0    stevel #include <netinet/in_systm.h>
     40     0    stevel #include <netinet/in.h>
     41     0    stevel #include <netinet/ip.h>
     42     0    stevel #include <netinet/if_ether.h>
     43     0    stevel #include "snoop.h"
     44     0    stevel 
     45     0    stevel struct porttable {
     46     0    stevel 	int	pt_num;
     47     0    stevel 	char	*pt_short;
     48     0    stevel };
     49     0    stevel 
     50  1676       jpk static const struct porttable pt_udp[] = {
     51  1676       jpk 	{ IPPORT_ECHO,		"ECHO" },
     52  1676       jpk 	{ IPPORT_DISCARD,	"DISCARD" },
     53  1676       jpk 	{ IPPORT_DAYTIME,	"DAYTIME" },
     54  3431  carlsonj 	{ IPPORT_CHARGEN,	"CHARGEN" },
     55  1676       jpk 	{ IPPORT_TIMESERVER,	"TIME" },
     56  1676       jpk 	{ IPPORT_NAMESERVER,	"NAME" },
     57  3431  carlsonj 	{ IPPORT_DOMAIN,	"DNS" },
     58  4904  rs200217 	{ IPPORT_MDNS,		"MDNS" },
     59  1676       jpk 	{ IPPORT_BOOTPS,	"BOOTPS" },
     60  1676       jpk 	{ IPPORT_BOOTPC,	"BOOTPC" },
     61  1676       jpk 	{ IPPORT_TFTP,		"TFTP" },
     62  1676       jpk 	{ IPPORT_FINGER,	"FINGER" },
     63  1676       jpk /*	{ 111,			"PORTMAP" }, Just Sun RPC */
     64  3431  carlsonj 	{ IPPORT_NTP,		"NTP" },
     65  3431  carlsonj 	{ IPPORT_NETBIOS_NS,	"NBNS" },
     66  3431  carlsonj 	{ IPPORT_NETBIOS_DGM,	"NBDG" },
     67  3431  carlsonj 	{ IPPORT_LDAP,		"LDAP" },
     68  3431  carlsonj 	{ IPPORT_SLP,		"SLP" },
     69     0    stevel /* Mobile IP defines a set of new control messages sent over UDP port 434 */
     70  3431  carlsonj 	{ IPPORT_MIP,		"Mobile IP" },
     71  1676       jpk 	{ IPPORT_BIFFUDP,	"BIFF" },
     72  1676       jpk 	{ IPPORT_WHOSERVER,	"WHO" },
     73  3431  carlsonj 	{ IPPORT_SYSLOG,	"SYSLOG" },
     74  3431  carlsonj 	{ IPPORT_TALK,		"TALK" },
     75  1676       jpk 	{ IPPORT_ROUTESERVER,	"RIP" },
     76  3431  carlsonj 	{ IPPORT_RIPNG,		"RIPng" },
     77  3431  carlsonj 	{ IPPORT_DHCPV6C,	"DHCPv6C" },
     78  3431  carlsonj 	{ IPPORT_DHCPV6S,	"DHCPv6S" },
     79  1676       jpk 	{ 550,			"NEW-RWHO" },
     80  1676       jpk 	{ 560,			"RMONITOR" },
     81  1676       jpk 	{ 561,			"MONITOR" },
     82  3431  carlsonj 	{ IPPORT_SOCKS,		"SOCKS" },
     83  1676       jpk 	{ 0,			NULL }
     84     0    stevel };
     85     0    stevel 
     86  1676       jpk static struct porttable pt_tcp[] = {
     87  1676       jpk 	{ 1,			"TCPMUX" },
     88  1676       jpk 	{ IPPORT_ECHO,		"ECHO" },
     89  1676       jpk 	{ IPPORT_DISCARD,	"DISCARD" },
     90  1676       jpk 	{ IPPORT_SYSTAT,	"SYSTAT" },
     91  1676       jpk 	{ IPPORT_DAYTIME,	"DAYTIME" },
     92  1676       jpk 	{ IPPORT_NETSTAT,	"NETSTAT" },
     93  3431  carlsonj 	{ IPPORT_CHARGEN,	"CHARGEN" },
     94  1676       jpk 	{ 20,			"FTP-DATA" },
     95  1676       jpk 	{ IPPORT_FTP,		"FTP" },
     96  1676       jpk 	{ IPPORT_TELNET,	"TELNET" },
     97  1676       jpk 	{ IPPORT_SMTP,		"SMTP" },
     98  1676       jpk 	{ IPPORT_TIMESERVER,	"TIME" },
     99  1676       jpk 	{ 39,			"RLP" },
    100  1676       jpk 	{ IPPORT_NAMESERVER,	"NAMESERVER" },
    101  1676       jpk 	{ IPPORT_WHOIS,		"NICNAME" },
    102  3431  carlsonj 	{ IPPORT_DOMAIN,	"DNS" },
    103  1676       jpk 	{ 70,			"GOPHER" },
    104  1676       jpk 	{ IPPORT_RJE,		"RJE" },
    105  1676       jpk 	{ IPPORT_FINGER,	"FINGER" },
    106  3431  carlsonj 	{ IPPORT_HTTP,		"HTTP" },
    107  1676       jpk 	{ IPPORT_TTYLINK,	"LINK" },
    108  1676       jpk 	{ IPPORT_SUPDUP,	"SUPDUP" },
    109  1676       jpk 	{ 101,			"HOSTNAME" },
    110  1676       jpk 	{ 102,			"ISO-TSAP" },
    111  1676       jpk 	{ 103,			"X400" },
    112  1676       jpk 	{ 104,			"X400-SND" },
    113  1676       jpk 	{ 105,			"CSNET-NS" },
    114  1676       jpk 	{ 109,			"POP-2" },
    115  1676       jpk /*	{ 111,			"PORTMAP" }, Just Sun RPC */
    116  1676       jpk 	{ 113,			"AUTH" },
    117  1676       jpk 	{ 117,			"UUCP-PATH" },
    118  1676       jpk 	{ 119,			"NNTP" },
    119  3431  carlsonj 	{ IPPORT_NTP,		"NTP" },
    120  3431  carlsonj 	{ IPPORT_NETBIOS_SSN,	"NBT" },
    121  1676       jpk 	{ 143,			"IMAP" },
    122  1676       jpk 	{ 144,			"NeWS" },
    123  3431  carlsonj 	{ IPPORT_LDAP,		"LDAP" },
    124  3431  carlsonj 	{ IPPORT_SLP,		"SLP" },
    125  1676       jpk 	{ 443,			"HTTPS" },
    126  1676       jpk 	{ 445,			"SMB" },
    127  1676       jpk 	{ IPPORT_EXECSERVER,	"EXEC" },
    128  1676       jpk 	{ IPPORT_LOGINSERVER,	"RLOGIN" },
    129  1676       jpk 	{ IPPORT_CMDSERVER,	"RSHELL" },
    130  3431  carlsonj 	{ IPPORT_PRINTER,	"PRINTER" },
    131  1676       jpk 	{ 530,			"COURIER" },
    132  1676       jpk 	{ 540,			"UUCP" },
    133  1676       jpk 	{ 600,			"PCSERVER" },
    134  3431  carlsonj 	{ IPPORT_SOCKS,		"SOCKS" },
    135  1676       jpk 	{ 1524,			"INGRESLOCK" },
    136  1676       jpk 	{ 2904,			"M2UA" },
    137  1676       jpk 	{ 2905,			"M3UA" },
    138  1676       jpk 	{ 6000,			"XWIN" },
    139  3431  carlsonj 	{ IPPORT_HTTP_ALT,	"HTTP (proxy)" },
    140  1676       jpk 	{ 9900,			"IUA" },
    141  1676       jpk 	{ 0,			NULL },
    142     0    stevel };
    143     0    stevel 
    144     0    stevel char *
    145     0    stevel getportname(int proto, in_port_t port)
    146     0    stevel {
    147  1676       jpk 	const struct porttable *p, *pt;
    148     0    stevel 
    149     0    stevel 	switch (proto) {
    150     0    stevel 	case IPPROTO_SCTP: /* fallthru */
    151     0    stevel 	case IPPROTO_TCP: pt = pt_tcp; break;
    152     0    stevel 	case IPPROTO_UDP: pt = pt_udp; break;
    153     0    stevel 	default: return (NULL);
    154     0    stevel 	}
    155     0    stevel 
    156     0    stevel 	for (p = pt; p->pt_num; p++) {
    157     0    stevel 		if (port == p->pt_num)
    158     0    stevel 			return (p->pt_short);
    159     0    stevel 	}
    160     0    stevel 	return (NULL);
    161     0    stevel }
    162     0    stevel 
    163     0    stevel int
    164     0    stevel reservedport(int proto, int port)
    165     0    stevel {
    166  1676       jpk 	const struct porttable *p, *pt;
    167     0    stevel 
    168     0    stevel 	switch (proto) {
    169     0    stevel 	case IPPROTO_TCP: pt = pt_tcp; break;
    170     0    stevel 	case IPPROTO_UDP: pt = pt_udp; break;
    171     0    stevel 	default: return (NULL);
    172     0    stevel 	}
    173     0    stevel 	for (p = pt; p->pt_num; p++) {
    174     0    stevel 		if (port == p->pt_num)
    175     0    stevel 			return (1);
    176     0    stevel 	}
    177     0    stevel 	return (0);
    178     0    stevel }
    179     0    stevel 
    180     0    stevel /*
    181     0    stevel  * Need to be able to register an
    182     0    stevel  * interpreter for transient ports.
    183     0    stevel  * See TFTP interpreter.
    184     0    stevel  */
    185     0    stevel #define	MAXTRANS 64
    186  1676       jpk static struct ttable {
    187     0    stevel 	int t_port;
    188  1676       jpk 	int (*t_proc)(int, char *, int);
    189     0    stevel } transients [MAXTRANS];
    190     0    stevel 
    191     0    stevel int
    192  1676       jpk add_transient(int port, int (*proc)(int, char *, int))
    193     0    stevel {
    194     0    stevel 	static struct ttable *next = transients;
    195     0    stevel 
    196     0    stevel 	next->t_port = port;
    197     0    stevel 	next->t_proc = proc;
    198     0    stevel 
    199     0    stevel 	if (++next >= &transients[MAXTRANS])
    200     0    stevel 		next = transients;
    201     0    stevel 
    202     0    stevel 	return (1);
    203     0    stevel }
    204     0    stevel 
    205     0    stevel static struct ttable *
    206     0    stevel is_transient(int port)
    207     0    stevel {
    208     0    stevel 	struct ttable *p;
    209     0    stevel 
    210     0    stevel 	for (p = transients; p->t_port && p < &transients[MAXTRANS]; p++) {
    211     0    stevel 		if (port == p->t_port)
    212     0    stevel 			return (p);
    213     0    stevel 	}
    214     0    stevel 
    215     0    stevel 	return (NULL);
    216     0    stevel }
    217     0    stevel 
    218     0    stevel void
    219     0    stevel del_transient(int port)
    220     0    stevel {
    221     0    stevel 	struct ttable *p;
    222     0    stevel 
    223     0    stevel 	for (p = transients; p->t_port && p < &transients[MAXTRANS]; p++) {
    224     0    stevel 		if (port == p->t_port)
    225     0    stevel 			p->t_port = -1;
    226     0    stevel 	}
    227     0    stevel }
    228     0    stevel 
    229     0    stevel static void
    230     0    stevel interpret_syslog(int flags, char dir, int port, const char *syslogstr,
    231     0    stevel     int dlen)
    232     0    stevel {
    233     0    stevel 	static const char *pris[] = {
    234     0    stevel 	    "emerg", "alert", "crit", "error", "warn", "notice", "info", "debug"
    235     0    stevel 	};
    236     0    stevel 	static const char *facs[] = {
    237     0    stevel 	    "kern", "user", "mail", "daemon", "auth", "syslog", "lpr", "news",
    238     0    stevel 	    "uucp", NULL, NULL, NULL, NULL, "audit", NULL, "cron", "local0",
    239     0    stevel 	    "local1", "local2", "local3", "local4", "local5", "local6", "local7"
    240     0    stevel 	};
    241     0    stevel 
    242     0    stevel 	int composit;
    243     0    stevel 	int pri = -1;
    244     0    stevel 	int facil = -1;
    245     0    stevel 	boolean_t bogus = B_TRUE;
    246     0    stevel 	int priostrlen = 0;
    247     0    stevel 	int datalen = dlen;
    248     0    stevel 	char unknown[4];	/* for unrecognized ones */
    249     0    stevel 	const char *facilstr = "BAD";
    250     0    stevel 	const char *pristr = "FMT";
    251     0    stevel 	const char *data = syslogstr;
    252     0    stevel 
    253     0    stevel 	/*
    254     0    stevel 	 * Is there enough data to interpret (left bracket + at least 3 chars
    255     0    stevel 	 * which could be digits, right bracket, or space)?
    256     0    stevel 	 */
    257     0    stevel 	if (datalen >= 4 && data != NULL) {
    258     0    stevel 		if (*data == '<') {
    259     0    stevel 			const int FACS_LEN = sizeof (facs) / sizeof (facs[0]);
    260     0    stevel 			char buffer[4];
    261     0    stevel 			char *end;
    262     0    stevel 
    263     0    stevel 			data++;
    264     0    stevel 			datalen--;
    265     0    stevel 
    266  1676       jpk 			(void) strlcpy(buffer, data, sizeof (buffer));
    267     0    stevel 			composit = strtoul(buffer, &end, 0);
    268     0    stevel 			data += end - buffer;
    269     0    stevel 			if (*data == '>') {
    270     0    stevel 				data++;
    271     0    stevel 				datalen -= end - buffer + 1;
    272     0    stevel 
    273     0    stevel 				pri = composit & 0x7;
    274     0    stevel 				facil = (composit & 0xF8) >> 3;
    275     0    stevel 
    276     0    stevel 				if ((facil >= FACS_LEN) ||
    277     0    stevel 				    (facs[facil] == NULL)) {
    278     0    stevel 					snprintf(unknown, sizeof (unknown),
    279     0    stevel 					    "%d", facil);
    280     0    stevel 					facilstr = unknown;
    281     0    stevel 				} else {
    282     0    stevel 					facilstr = facs[facil];
    283     0    stevel 				}
    284     0    stevel 				pristr = pris[pri];
    285     0    stevel 				priostrlen = dlen - datalen;
    286     0    stevel 				bogus = B_FALSE;
    287     0    stevel 			} else {
    288     0    stevel 				data = syslogstr;
    289     0    stevel 				datalen = dlen;
    290     0    stevel 			}
    291     0    stevel 		}
    292     0    stevel 	}
    293     0    stevel 
    294     0    stevel 	if (flags & F_SUM) {
    295     0    stevel 		(void) snprintf(get_sum_line(), MAXLINE,
    296     0    stevel 		    "SYSLOG %c port=%d %s.%s: %s",
    297     0    stevel 		    dir, port, facilstr, pristr,
    298     0    stevel 		    show_string(syslogstr, dlen, 20));
    299     0    stevel 
    300     0    stevel 	}
    301     0    stevel 
    302     0    stevel 	if (flags & F_DTAIL) {
    303     0    stevel 		static char syslog[] = "SYSLOG:  ";
    304     0    stevel 		show_header(syslog, syslog, dlen);
    305     0    stevel 		show_space();
    306  1676       jpk 		(void) snprintf(get_detail_line(0, 0), MAXLINE,
    307     0    stevel 		    "%s%sPriority: %.*s%s(%s.%s)", prot_nest_prefix, syslog,
    308     0    stevel 		    priostrlen, syslogstr, bogus ? "" : " ",
    309     0    stevel 		    facilstr, pristr);
    310  1676       jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    311  4904  rs200217 		    "\"%s\"",
    312  4904  rs200217 		    show_string(syslogstr, dlen, 60));
    313     0    stevel 		show_trailer();
    314     0    stevel 	}
    315     0    stevel }
    316     0    stevel 
    317     0    stevel int src_port, dst_port, curr_proto;
    318     0    stevel 
    319     0    stevel int
    320     0    stevel interpret_reserved(int flags, int proto, in_port_t src, in_port_t dst,
    321     0    stevel     char *data, int dlen)
    322     0    stevel {
    323  1676       jpk 	const char *pn;
    324     0    stevel 	int dir, port, which;
    325     0    stevel 	char pbuff[16], hbuff[32];
    326     0    stevel 	struct ttable *ttabp;
    327     0    stevel 
    328     0    stevel 	src_port = src;
    329     0    stevel 	dst_port = dst;
    330     0    stevel 	curr_proto = proto;
    331     0    stevel 
    332     0    stevel 	pn = getportname(proto, src);
    333     0    stevel 	if (pn != NULL) {
    334     0    stevel 		dir = 'R';
    335     0    stevel 		port = dst;
    336     0    stevel 		which = src;
    337     0    stevel 	} else {
    338     0    stevel 		pn = getportname(proto, dst);
    339     0    stevel 		if (pn == NULL) {
    340     0    stevel 			ttabp = is_transient(src);
    341     0    stevel 			if (ttabp) {
    342     0    stevel 				(ttabp->t_proc)(flags, data, dlen);
    343     0    stevel 				return (1);
    344     0    stevel 			}
    345     0    stevel 			ttabp = is_transient(dst);
    346     0    stevel 			if (ttabp) {
    347     0    stevel 				(ttabp->t_proc)(flags, data, dlen);
    348     0    stevel 				return (1);
    349     0    stevel 			}
    350     0    stevel 			return (0);
    351     0    stevel 		}
    352     0    stevel 
    353     0    stevel 		dir = 'C';
    354     0    stevel 		port = src;
    355     0    stevel 		which = dst;
    356     0    stevel 	}
    357     0    stevel 
    358  4904  rs200217 	if ((dst == IPPORT_DOMAIN || src == IPPORT_DOMAIN ||
    359  4904  rs200217 	    dst == IPPORT_MDNS || src == IPPORT_MDNS) &&
    360  3431  carlsonj 	    proto != IPPROTO_TCP) {
    361  4904  rs200217 		interpret_dns(flags, proto, (uchar_t *)data, dlen, which);
    362     0    stevel 		return (1);
    363     0    stevel 	}
    364     0    stevel 
    365  3431  carlsonj 	if (dst == IPPORT_SYSLOG && proto != IPPROTO_TCP) {
    366     0    stevel 		/*
    367     0    stevel 		 * TCP port 514 is rshell.  UDP port 514 is syslog.
    368     0    stevel 		 */
    369     0    stevel 		interpret_syslog(flags, dir, port, (const char *)data, dlen);
    370     0    stevel 		return (1);
    371     0    stevel 	}
    372     0    stevel 
    373     0    stevel 	if (dlen > 0) {
    374     0    stevel 		switch (which) {
    375  1676       jpk 		case  IPPORT_BOOTPS:
    376  1676       jpk 		case  IPPORT_BOOTPC:
    377  1676       jpk 			(void) interpret_dhcp(flags, (struct dhcp *)data,
    378  1676       jpk 			    dlen);
    379     0    stevel 			return (1);
    380  3431  carlsonj 		case IPPORT_DHCPV6S:
    381  3431  carlsonj 		case IPPORT_DHCPV6C:
    382  3431  carlsonj 			(void) interpret_dhcpv6(flags, (uint8_t *)data, dlen);
    383  3431  carlsonj 			return (1);
    384  1676       jpk 		case  IPPORT_TFTP:
    385  1676       jpk 			(void) interpret_tftp(flags, (struct tftphdr *)data,
    386  1676       jpk 			    dlen);
    387     0    stevel 			return (1);
    388  3431  carlsonj 		case  IPPORT_HTTP:
    389  3431  carlsonj 		case  IPPORT_HTTP_ALT:
    390  1676       jpk 			(void) interpret_http(flags, data, dlen);
    391     0    stevel 			return (1);
    392  3431  carlsonj 		case IPPORT_NTP:
    393  1676       jpk 			(void) interpret_ntp(flags, (struct ntpdata *)data,
    394  1676       jpk 			    dlen);
    395     0    stevel 			return (1);
    396  3431  carlsonj 		case IPPORT_NETBIOS_NS:
    397  1676       jpk 			interpret_netbios_ns(flags, (uchar_t *)data, dlen);
    398     0    stevel 			return (1);
    399  3431  carlsonj 		case IPPORT_NETBIOS_DGM:
    400  1676       jpk 			interpret_netbios_datagram(flags, (uchar_t *)data,
    401  1676       jpk 			    dlen);
    402     0    stevel 			return (1);
    403  3431  carlsonj 		case IPPORT_NETBIOS_SSN:
    404     0    stevel 		case 445:
    405     0    stevel 			/*
    406     0    stevel 			 * SMB on port 445 is a subset of NetBIOS SMB
    407     0    stevel 			 * on port 139.  The same interpreter can be used
    408     0    stevel 			 * for both.
    409     0    stevel 			 */
    410  1676       jpk 			interpret_netbios_ses(flags, (uchar_t *)data, dlen);
    411     0    stevel 			return (1);
    412  3431  carlsonj 		case IPPORT_LDAP:
    413     0    stevel 			interpret_ldap(flags, data, dlen, src, dst);
    414     0    stevel 			return (1);
    415  3431  carlsonj 		case IPPORT_SLP:
    416     0    stevel 			interpret_slp(flags, data, dlen);
    417     0    stevel 			return (1);
    418  3431  carlsonj 		case IPPORT_MIP:
    419     0    stevel 			interpret_mip_cntrlmsg(flags, (uchar_t *)data, dlen);
    420     0    stevel 			return (1);
    421  1676       jpk 		case IPPORT_ROUTESERVER:
    422  1676       jpk 			(void) interpret_rip(flags, (struct rip *)data, dlen);
    423     0    stevel 			return (1);
    424  3431  carlsonj 		case IPPORT_RIPNG:
    425  1676       jpk 			(void) interpret_rip6(flags, (struct rip6 *)data,
    426  1676       jpk 			    dlen);
    427     0    stevel 			return (1);
    428  3431  carlsonj 		case IPPORT_SOCKS:
    429     0    stevel 			if (dir == 'C')
    430  1676       jpk 				(void) interpret_socks_call(flags, data, dlen);
    431     0    stevel 			else
    432  1676       jpk 				(void) interpret_socks_reply(flags, data,
    433  1676       jpk 				    dlen);
    434     0    stevel 			return (1);
    435     0    stevel 		}
    436     0    stevel 	}
    437     0    stevel 
    438     0    stevel 	if (flags & F_SUM) {
    439  1676       jpk 		(void) snprintf(get_sum_line(), MAXLINE,
    440  4904  rs200217 		    "%s %c port=%d %s",
    441  4904  rs200217 		    pn, dir, port,
    442  4904  rs200217 		    show_string(data, dlen, 20));
    443     0    stevel 	}
    444     0    stevel 
    445     0    stevel 	if (flags & F_DTAIL) {
    446  1676       jpk 		(void) snprintf(pbuff, sizeof (pbuff), "%s:  ", pn);
    447  1676       jpk 		(void) snprintf(hbuff, sizeof (hbuff), "%s:  ", pn);
    448     0    stevel 		show_header(pbuff, hbuff, dlen);
    449     0    stevel 		show_space();
    450  1676       jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    451  4904  rs200217 		    "\"%s\"",
    452  4904  rs200217 		    show_string(data, dlen, 60));
    453     0    stevel 		show_trailer();
    454     0    stevel 	}
    455     0    stevel 	return (1);
    456     0    stevel }
    457     0    stevel 
    458     0    stevel char *
    459     0    stevel show_string(const char *str, int dlen, int maxlen)
    460     0    stevel /*
    461     0    stevel  *   Prints len bytes from str enclosed in quotes.
    462     0    stevel  *   If len is negative, length is taken from strlen(str).
    463     0    stevel  *   No more than maxlen bytes will be printed.  Longer
    464     0    stevel  *   strings are flagged with ".." after the closing quote.
    465     0    stevel  *   Non-printing characters are converted to C-style escape
    466     0    stevel  *   codes or octal digits.
    467     0    stevel  */
    468     0    stevel {
    469     0    stevel #define	TBSIZE	256
    470     0    stevel 	static char tbuff[TBSIZE];
    471     0    stevel 	const char *p;
    472     0    stevel 	char *pp;
    473     0    stevel 	int printable = 0;
    474     0    stevel 	int c, len;
    475     0    stevel 
    476     0    stevel 	len = dlen > maxlen ? maxlen : dlen;
    477     0    stevel 	dlen = len;
    478     0    stevel 
    479     0    stevel 	for (p = str, pp = tbuff; len; p++, len--) {
    480     0    stevel 		switch (c = *p & 0xFF) {
    481     0    stevel 		case '\n': (void) strcpy(pp, "\\n"); pp += 2; break;
    482     0    stevel 		case '\b': (void) strcpy(pp, "\\b"); pp += 2; break;
    483     0    stevel 		case '\t': (void) strcpy(pp, "\\t"); pp += 2; break;
    484     0    stevel 		case '\r': (void) strcpy(pp, "\\r"); pp += 2; break;
    485     0    stevel 		case '\f': (void) strcpy(pp, "\\f"); pp += 2; break;
    486     0    stevel 		default:
    487     0    stevel 			if (isascii(c) && isprint(c)) {
    488     0    stevel 				*pp++ = c;
    489     0    stevel 				printable++;
    490     0    stevel 			} else {
    491  1676       jpk 				(void) snprintf(pp, TBSIZE - (pp - tbuff),
    492     0    stevel 					isdigit(*(p + 1)) ?
    493     0    stevel 					"\\%03o" : "\\%o", c);
    494     0    stevel 				pp += strlen(pp);
    495     0    stevel 			}
    496     0    stevel 			break;
    497     0    stevel 		}
    498     0    stevel 		*pp = '\0';
    499     0    stevel 		/*
    500     0    stevel 		 * Check for overflow of temporary buffer.  Allow for
    501     0    stevel 		 * the next character to be a \nnn followed by a trailing
    502     0    stevel 		 * null.  If not, then just bail with what we have.
    503     0    stevel 		 */
    504     0    stevel 		if (pp + 5 >= &tbuff[TBSIZE]) {
    505     0    stevel 			break;
    506     0    stevel 		}
    507     0    stevel 	}
    508     0    stevel 	return (printable > dlen / 2 ? tbuff : "");
    509     0    stevel }
    510