Home | History | Annotate | Download | only in snoop
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 #include <stdio.h>
     30 #include <ctype.h>
     31 #include <string.h>
     32 #include <fcntl.h>
     33 #include <string.h>
     34 #include <sys/types.h>
     35 #include <sys/time.h>
     36 #include <sys/stat.h>
     37 #include <sys/uio.h>
     38 #include <unistd.h>
     39 #include <signal.h>
     40 #include <errno.h>
     41 #include <stdlib.h>
     42 #include <sys/wait.h>
     43 #include <sys/socket.h>
     44 #include <sys/sockio.h>
     45 #include <net/if.h>
     46 #include <netinet/in_systm.h>
     47 #include <netinet/in.h>
     48 #include <netinet/ip.h>
     49 #include <netinet/if_ether.h>
     50 #include <netinet/udp.h>
     51 #include "snoop.h"
     52 
     53 #ifndef MIN
     54 #define	MIN(a, b) ((a) < (b) ? (a) : (b))
     55 #endif
     56 
     57 extern char *src_name;
     58 extern char *dst_name;
     59 #define	MAX_CTX  (10)
     60 #define	LINE_LEN (255)
     61 #define	BUF_SIZE (16000)
     62 static int ldap = 0;		/* flag to control initialization */
     63 struct ctx {
     64 	int src;
     65 	int dst;
     66 	char *src_name;
     67 	char *dst_name;
     68 };
     69 char *osibuff = NULL;
     70 int osilen = 0;
     71 char scrbuffer[BUF_SIZE];	/* buffer to accumulate data until a */
     72 				/* complete LDAPmessage is received  */
     73 char resultcode[LINE_LEN];	/* These are used */
     74 char operation[LINE_LEN];	/* by -V option.  */
     75 char bb[LINE_LEN];
     76 
     77 int gi_osibuf[MAX_CTX];
     78 int otyp[MAX_CTX];
     79 int olen[MAX_CTX];
     80 int level[MAX_CTX];
     81 
     82 void decode_ldap(char *buf, int len);
     83 
     84 #define	X unsigned char
     85 typedef	X * A;
     86 #define	INT(a) ((int)(a))
     87 #define	SCRUB (void) strcat(scrbuffer, bb);
     88 
     89 static X	hex;		/* input hex octet */
     90 static A	*PTRaclass;	/* application tag table pointer */
     91 
     92 /*
     93  * ASN.1 Message Printing Macros
     94  */
     95 
     96 #define	asnshw1(a)				{(void)sprintf(bb, a); SCRUB }
     97 #define	asnshw2(a, b)			{(void)sprintf(bb, a, b); SCRUB }
     98 #define	asnshw3(a, b, c)		{(void)sprintf(bb, a, b, c); SCRUB }
     99 #define	asnshw4(a, b, c, d)		{(void)sprintf(bb, a, b, c, d); SCRUB }
    100 #define	asnshw5(a, b, c, d, e)	{(void)sprintf(bb, a, b, c, d, e); SCRUB }
    101 
    102 /*
    103  * Local Types And Variables
    104  */
    105 
    106 /*
    107  * Object identifier oid to name mapping description type
    108  */
    109 
    110 typedef struct {
    111 	A	oidname;	/* object identifier string name */
    112 	X	oidcode[16];	/* object identifier hexa code */
    113 }	oidelmT;
    114 typedef oidelmT *oidelmTp;
    115 
    116 /*
    117  * Snoop's entry point to ldap decoding
    118  */
    119 
    120 void
    121 interpret_ldap(flags, data, fraglen, src, dst)
    122 int flags;
    123 char *data;
    124 int fraglen;
    125 int src;
    126 int dst;
    127 {
    128 
    129 	if (!ldap) {
    130 		init_ldap();
    131 		ldap = 1;
    132 	}
    133 
    134 	(void) decode_ldap(data, fraglen);
    135 
    136 	if (flags & F_DTAIL) {
    137 		/* i.e. when snoop is run with -v (verbose) */
    138 		show_header("LDAP:  ",
    139 		"Lightweight Directory Access Protocol Header", fraglen);
    140 		show_space();
    141 		printf("%s", scrbuffer);
    142 	}
    143 
    144 	if (flags & F_SUM) {
    145 	/* i.e. when snoop is run with -V (summary) */
    146 		(void) strcpy(data, "");
    147 
    148 		if (strlen(operation) != 0) {
    149 			(void) strcat(data, " ");
    150 			(void) strncat(data, operation, 30);
    151 			(void) strcpy(operation, "");
    152 		}
    153 
    154 		if (strlen(resultcode) != 0) {
    155 			(void) strcat(data, " ");
    156 			(void) strncat(data, resultcode, 30);
    157 			(void) strcpy(resultcode, "");
    158 		}
    159 
    160 		if (dst == 389) {
    161 			(void) sprintf(get_sum_line(),
    162 				"LDAP C port=%d%s", src, data);
    163 		}
    164 		if (src == 389) {
    165 			(void) sprintf(get_sum_line(),
    166 				"LDAP R port=%d%s", dst, data);
    167 		}
    168 	}
    169 
    170 	(void) strcpy(scrbuffer, "");
    171 }
    172 
    173 /*
    174  * Known object identifiers: customize to add your own oids
    175  */
    176 
    177 static oidelmT OidTab[] = {
    178 /*
    179  *	X.500 Standardized Attribute Types
    180  */
    181 {(A)"ObjectClass",				{ 0x03, 0x55, 0x04, 0x00 }},
    182 {(A)"AliasObjectName",			{ 0x03, 0x55, 0x04, 0x01 }},
    183 {(A)"KnowledgeInfo",			{ 0x03, 0x55, 0x04, 0x02 }},
    184 {(A)"CommonName",				{ 0x03, 0x55, 0x04, 0x03 }},
    185 {(A)"Surname",					{ 0x03, 0x55, 0x04, 0x04 }},
    186 {(A)"SerialNumber",				{ 0x03, 0x55, 0x04, 0x05 }},
    187 {(A)"CountryName",				{ 0x03, 0x55, 0x04, 0x06 }},
    188 {(A)"LocalityName",				{ 0x03, 0x55, 0x04, 0x07 }},
    189 {(A)"StateOrProvinceName",		{ 0x03, 0x55, 0x04, 0x08 }},
    190 {(A)"StreetAddress",			{ 0x03, 0x55, 0x04, 0x09 }},
    191 {(A)"OrganizationName",			{ 0x03, 0x55, 0x04, 0x0a }},
    192 {(A)"OrganizationUnitName",		{ 0x03, 0x55, 0x04, 0x0b }},
    193 {(A)"Title",					{ 0x03, 0x55, 0x04, 0x0c }},
    194 {(A)"Description",				{ 0x03, 0x55, 0x04, 0x0d }},
    195 {(A)"SearchGuide",				{ 0x03, 0x55, 0x04, 0x0e }},
    196 {(A)"BusinessCategory",			{ 0x03, 0x55, 0x04, 0x0f }},
    197 {(A)"PostalAddress",			{ 0x03, 0x55, 0x04, 0x10 }},
    198 {(A)"PostalCode",				{ 0x03, 0x55, 0x04, 0x11 }},
    199 {(A)"PostOfficeBox",			{ 0x03, 0x55, 0x04, 0x12 }},
    200 {(A)"PhysicalDeliveryOffice",	{ 0x03, 0x55, 0x04, 0x13 }},
    201 {(A)"TelephoneNUmber",			{ 0x03, 0x55, 0x04, 0x14 }},
    202 {(A)"TelexNumber",				{ 0x03, 0x55, 0x04, 0x15 }},
    203 {(A)"TeletexTerminalId",		{ 0x03, 0x55, 0x04, 0x16 }},
    204 {(A)"FaxTelephoneNumber",		{ 0x03, 0x55, 0x04, 0x17 }},
    205 {(A)"X121Address",				{ 0x03, 0x55, 0x04, 0x18 }},
    206 {(A)"IsdnAddress",				{ 0x03, 0x55, 0x04, 0x19 }},
    207 {(A)"RegisteredAddress",		{ 0x03, 0x55, 0x04, 0x1a }},
    208 {(A)"DestinationIndicator",		{ 0x03, 0x55, 0x04, 0x1b }},
    209 {(A)"PreferDeliveryMethod",		{ 0x03, 0x55, 0x04, 0x1c }},
    210 {(A)"PresentationAddress",		{ 0x03, 0x55, 0x04, 0x1d }},
    211 {(A)"SupportedApplContext",		{ 0x03, 0x55, 0x04, 0x1e }},
    212 {(A)"Member",					{ 0x03, 0x55, 0x04, 0x1f }},
    213 {(A)"Owner",					{ 0x03, 0x55, 0x04, 0x20 }},
    214 {(A)"RoleOccupant",				{ 0x03, 0x55, 0x04, 0x21 }},
    215 {(A)"SeeAlso",					{ 0x03, 0x55, 0x04, 0x22 }},
    216 {(A)"Password",					{ 0x03, 0x55, 0x04, 0x23 }},
    217 {(A)"UserCertificate",			{ 0x03, 0x55, 0x04, 0x24 }},
    218 {(A)"CaCertificate",			{ 0x03, 0x55, 0x04, 0x25 }},
    219 {(A)"AuthorityRevList",			{ 0x03, 0x55, 0x04, 0x26 }},
    220 {(A)"CertificateRevList",		{ 0x03, 0x55, 0x04, 0x27 }},
    221 {(A)"CrossCertificatePair",		{ 0x03, 0x55, 0x04, 0x28 }},
    222 
    223 /*
    224  *	X.500 Standardized Object Classes
    225  */
    226 {(A)"Top",					{ 0x03, 0x55, 0x06, 0x00 }},
    227 {(A)"Alias",				{ 0x03, 0x55, 0x06, 0x01 }},
    228 {(A)"Country",				{ 0x03, 0x55, 0x06, 0x02 }},
    229 {(A)"Locality",				{ 0x03, 0x55, 0x06, 0x03 }},
    230 {(A)"Organization",			{ 0x03, 0x55, 0x06, 0x04 }},
    231 {(A)"OrganizationUnit",		{ 0x03, 0x55, 0x06, 0x05 }},
    232 {(A)"Person",				{ 0x03, 0x55, 0x06, 0x06 }},
    233 {(A)"OrganizationPersion",	{ 0x03, 0x55, 0x06, 0x07 }},
    234 {(A)"OrganizationRole",		{ 0x03, 0x55, 0x06, 0x08 }},
    235 {(A)"Group",				{ 0x03, 0x55, 0x06, 0x09 }},
    236 {(A)"ResidentialPerson",	{ 0x03, 0x55, 0x06, 0x0A }},
    237 {(A)"ApplicationProcess",	{ 0x03, 0x55, 0x06, 0x0B }},
    238 {(A)"ApplicationEntity",	{ 0x03, 0x55, 0x06, 0x0C }},
    239 {(A)"Dsa",					{ 0x03, 0x55, 0x06, 0x0D }},
    240 {(A)"Device",				{ 0x03, 0x55, 0x06, 0x0E }},
    241 {(A)"StrongAuthenticUser",	{ 0x03, 0x55, 0x06, 0x0F }},
    242 {(A)"CaAuthority",			{ 0x03, 0x55, 0x06, 0x10 }},
    243 
    244 /*
    245  *	ACSE Protocol Object Identifiers
    246  */
    247 {(A)"Asn1BER-TS",		{ 0x02, 0x51, 0x01 }},
    248 {(A)"Private-TS",		{ 0x06, 0x2b, 0xce, 0x06, 0x01, 0x04, 0x06 }},
    249 {(A)"ACSE-AS",			{ 0x04, 0x52, 0x01, 0x00, 0x01 }},
    250 
    251 /*
    252  *	Directory Protocol Oids
    253  */
    254 {(A)"DirAccess-AC",			{ 0x03, 0x55, 0x03, 0x01 }},
    255 {(A)"DirSystem-AC",			{ 0x03, 0x55, 0x03, 0x02 }},
    256 
    257 {(A)"DirAccess-AS",			{ 0x03, 0x55, 0x09, 0x01 }},
    258 {(A)"DirSystem-AS",			{ 0x03, 0x55, 0x09, 0x02 }},
    259 
    260 /*
    261  *	and add your private object identifiers here ...
    262  */
    263 };
    264 
    265 #define	OIDNB (sizeof (OidTab) / sizeof (oidelmT))	/* total oid nb */
    266 
    267 /*
    268  *	asn.1 tag class definition
    269  */
    270 
    271 static A class[] = {	/* tag class */
    272 	(A)"UNIV ",
    273 	(A)"APPL ",
    274 	(A)"CTXs ",
    275 	(A)"PRIV "
    276 };
    277 
    278 /*
    279  *	universal tag definition
    280  */
    281 
    282 static A uclass[] = {	/* universal tag assignment */
    283 (A)"EndOfContents",			/* 0  */
    284 (A)"Boolean",				/* 1  */
    285 (A)"Integer",				/* 2  */
    286 (A)"BitString",				/* 3  */
    287 (A)"OctetString",			/* 4  */
    288 (A)"Null",				/* 5  */
    289 (A)"Oid",				/* 6  */
    290 (A)"ObjDescriptor",			/* 7  */
    291 (A)"External",				/* 8  */
    292 (A)"Real",				/* 9  */
    293 (A)"Enumerated",			/* 10 */
    294 (A)"Reserved",				/* 11 */
    295 (A)"Reserved",				/* 12 */
    296 (A)"Reserved",				/* 13 */
    297 (A)"Reserved",				/* 14 */
    298 (A)"Reserved",				/* 15 */
    299 (A)"Sequence",				/* 16 */
    300 (A)"Set",				/* 17 */
    301 (A)"NumericString",			/* 18 */
    302 (A)"PrintableString",			/* 19 */
    303 (A)"T.61String",			/* 20 */
    304 (A)"VideotexString",			/* 21 */
    305 (A)"IA5String",				/* 22 */
    306 (A)"UTCTime",				/* 23 */
    307 (A)"GeneralizedTime",			/* 24 */
    308 (A)"GraphicString",			/* 25 */
    309 (A)"VisibleString",			/* 26 */
    310 (A)"GeneralString",			/* 27 */
    311 (A)"Reserved",				/* 28 */
    312 (A)"Reserved",				/* 29 */
    313 (A)"Reserved",				/* 30 */
    314 (A)"Reserved" 				/* 31 */
    315 };
    316 
    317 static A MHSaclass[] = {	/* mhs application tag assignment */
    318 (A)"Bind Request",			/* 0 */
    319 (A)"Bind Response",
    320 (A)"Unbind Request",
    321 (A)"Search Request",
    322 (A)"Search ResEntry",
    323 (A)"Search ResDone",			/* 5 */
    324 (A)"Modify Request",
    325 (A)"Modify Response",
    326 (A)"Add Request",
    327 (A)"Add Response",			/* 9 */
    328 (A)"Del Request",
    329 (A)"Del Response",
    330 (A)"ModDN Request",
    331 (A)"ModDN Response",
    332 (A)"Compare Request",			/* 14 */
    333 (A)"Compare Response",
    334 (A)"Abandon Request",
    335 (A)"",					/* 17 */
    336 (A)"",					/* 18 */
    337 (A)"Search ResRef",			/* 19 */
    338 (A)"",					/* 20 */
    339 (A)"",					/* 21 */
    340 (A)"",					/* 22 */
    341 (A)"Extended Request",
    342 (A)"Extended Response",
    343 (A)"",					/* 25 */
    344 (A)"",					/* 26 */
    345 (A)"",					/* 27 */
    346 (A)"",					/* 28 */
    347 (A)"",					/* 29 */
    348 (A)"",					/* 30 */
    349 (A)"" 					/* 31 */
    350 };
    351 
    352 
    353 static A DFTaclass[] = {	/* Default Application Tag Assignment */
    354 (A)"",				/* 0  */
    355 (A)"",				/* 1  */
    356 (A)"",				/* 2  */
    357 (A)"",				/* 3  */
    358 (A)"",				/* 4  */
    359 (A)"",				/* 5  */
    360 (A)"",				/* 6  */
    361 (A)"",				/* 7  */
    362 (A)"",				/* 8  */
    363 (A)"",				/* 9  */
    364 (A)"",				/* 10 */
    365 (A)"",				/* 11 */
    366 (A)"",				/* 12 */
    367 (A)"",				/* 13 */
    368 (A)"",				/* 14 */
    369 (A)"",				/* 15 */
    370 (A)"",				/* 16 */
    371 (A)"",				/* 17 */
    372 (A)"",				/* 18 */
    373 (A)"",				/* 19 */
    374 (A)"",				/* 20 */
    375 (A)"",				/* 21 */
    376 (A)"",				/* 22 */
    377 (A)"",				/* 23 */
    378 (A)"",				/* 24 */
    379 (A)"",				/* 25 */
    380 (A)"",				/* 26 */
    381 (A)"",				/* 27 */
    382 (A)"",				/* 28 */
    383 (A)"",				/* 29 */
    384 (A)"",				/* 30 */
    385 (A)"" 				/* 31 */
    386 };
    387 
    388 typedef struct asndefS {
    389 char *name;
    390 int type;
    391 int application;
    392 int nbson;
    393 struct {
    394 	char *sonname;
    395 	struct asndefS *sondef;
    396 	long tag;
    397 	} son[50];
    398 } asndefT, * asndefTp;
    399 
    400 #define	SEQUENCE		0x0002
    401 #define	SEQUENCEOF		0x0003
    402 #define	SET				0x0004
    403 #define	PRINTABLE		0x0008
    404 #define	ENUM			0x0010
    405 #define	BITSTRING		0x0020
    406 #define	EXTENSION		0x0040
    407 #define	CONTENTTYPE		0x0080
    408 #define	CONTENT			0x0100
    409 #define	CHOICE			0x0200
    410 
    411 static asndefT RTSpasswd = { "RTS Authentification data", SET,  -1, 2, {
    412 			{"MTA Name", 0, 0},
    413 			{"MTA Password", 0, 1}}};
    414 static asndefT RTSudata = { "RTS User data", SET,  -1, 1, {
    415 			{0, &RTSpasswd, 1}}};
    416 
    417 static asndefT baseObject = {"Base Object", PRINTABLE, -1, 0, {0}};
    418 
    419 static asndefT scope = {"Scope", ENUM, -1, 3, {
    420 			{"BaseObject", 0, 0},
    421 			{"singleLevel", 0, 1},
    422 			{"wholeSubtree", 0, 2}}};
    423 
    424 static asndefT derefAliases = {"DerefAliases", ENUM, -1, 4, {
    425 			{"neverDerefAliases", 0, 0},
    426 			{"derefInSearching", 0, 1},
    427 			{"derefFindingBaseObj", 0, 2},
    428 			{"derefAlways", 0, 3}}};
    429 
    430 static asndefT filter;
    431 static asndefT and = {"And", SET, -1, 1, {
    432 			{0, &filter, -1}}};
    433 static asndefT or = {"Or", SET, -1, 1, {
    434 			{0, &filter, -1}}};
    435 static asndefT not = {"Not", SET, -1, 1, {
    436 			{0, &filter, -1}}};
    437 static asndefT equalityMatch = {"Equality Match", SEQUENCE, -1, 2, {
    438 			{"Attr Descr", 0, -1},
    439 			{"Value", 0, -1}}};
    440 static asndefT substrings = {"Substring", SEQUENCE, -1, 2, {
    441 			{"Type", 0, -1},
    442 			{"Substrings (initial)", 0, 0},
    443 			{"Substrings (any)", 0, 1},
    444 			{"Substring (final)", 0, 2}}};
    445 static asndefT greaterOrEqual = {"Greater Or Equal", SEQUENCE, -1, 2, {
    446 			{"Attr Descr", 0, -1},
    447 			{"Value", 0, -1}}};
    448 static asndefT lessOrEqual = {"Less Or Equal", SEQUENCE, -1, 2, {
    449 			{"Attr Descr", 0, -1},
    450 			{"Value", 0, -1}}};
    451 static asndefT approxMatch = {"Approx Match", SEQUENCE, -1, 2, {
    452 			{"Attr Descr", 0, -1},
    453 			{"Value", 0, -1}}};
    454 static asndefT extensibleMatch = {"Extensible Match", SEQUENCE, -1, 4, {
    455 			{"MatchingRule", 0, 1},
    456 			{"Type", 0, 2},
    457 			{"MatchValue", 0, 3},
    458 			{"dnAttributes", 0, 4}}};
    459 
    460 static asndefT filter = {"Filter", CHOICE, -1, 10, {
    461 			{0, &and, 0},
    462 			{0, &or, 1},
    463 			{0, &not, 2},
    464 			{0, &equalityMatch, 3},
    465 			{0, &substrings, 4},
    466 			{0, &greaterOrEqual, 5},
    467 			{0, &lessOrEqual, 6},
    468 			{"Filter: Present", 0, 7},
    469 			{0, &approxMatch, 8},
    470 			{0, &extensibleMatch, 9}}};
    471 
    472 static asndefT attributedescription = \
    473 			{"Attribute Description", PRINTABLE, -1, 0, {0}};
    474 static asndefT attributes = {"Attribute List", SEQUENCEOF, -1, 1, {
    475 			{0, &attributedescription, -1}}};
    476 
    477 static asndefT searchRequest = {"Operation", SEQUENCE, 3, 8, {
    478 			{0, &baseObject, -1},
    479 			{0, &scope, -1},
    480 			{0, &derefAliases, -1},
    481 			{"SizeLimit", 0, -1},
    482 			{"TimeLimit", 0, -1},
    483 			{"TypesOnly", 0, -1},
    484 			{0, &filter, -1},
    485 			{0, &attributes, -1}}};
    486 
    487 static asndefT objectName = {"Object Name", PRINTABLE, -1, 0, {0}};
    488 
    489 static asndefT ldapEntry = {"Entry", PRINTABLE, -1, 0, {0}};
    490 static asndefT relativeLdapEntry = \
    491 			{"Relative LDAP Entry", PRINTABLE, -1, 0, {0}};
    492 static asndefT newSuperior = {"New Superior", PRINTABLE, -1, 0, {0}};
    493 
    494 static asndefT vals = {"Vals", SET, -1, 1, {
    495 			{"Value", 0, -1}}};
    496 
    497 static asndefT attribute = {"Attribute", SEQUENCE, -1, 2, {
    498 			{"Type", 0, -1},
    499 			{0, &vals, -1}}};
    500 
    501 static asndefT partialAttributes = {"Partial Attributes", SEQUENCEOF, -1, 1, {
    502 			{0, &attribute, -1}}};
    503 
    504 static asndefT searchResEntry = {"Operation", SEQUENCE, 4, 2, {
    505 			{0, &objectName, -1},
    506 			{0, &partialAttributes, -1}}};
    507 
    508 static asndefT authChoice = {"Authentication Choice", CHOICE, -1, 2, {
    509 			{"Authentication: Simple", 0, 0},
    510 			{"Authentication: SASL", 0, 3}}};
    511 
    512 static asndefT bindRequest = {"Operation", SEQUENCE, 0, 3, {
    513 			{"Version", 0, -1},
    514 			{0, &objectName, -1},
    515 			{0, &authChoice, -1}}};
    516 
    517 static asndefT resultCode = {"Result Code", ENUM, -1, 39, {
    518 			{"Success", 0, 0},
    519 			{"Operation Error", 0, 1},
    520 			{"Protocol Error", 0, 2},
    521 			{"Time Limit Exceeded", 0, 3},
    522 			{"Size Limit Exceeded", 0, 4},
    523 			{"Compare False", 0, 5},
    524 			{"Compare True", 0, 6},
    525 			{"Auth Method Not supported", 0, 7},
    526 			{"Strong Auth Required", 0, 8},
    527 			{"Referral", 0, 10},
    528 			{"Admin Limit Exceeded", 0, 11},
    529 			{"Unavailable Critical Extension", 0, 12},
    530 			{"Confidentiality required", 0, 13},
    531 			{"SASL Bind In Progress", 0, 14},
    532 			{"No Such Attribute", 0, 16},
    533 			{"Undefined Attribute Type", 0, 17},
    534 			{"Inappropriate Matching", 0, 18},
    535 			{"Constraint violation", 0, 19},
    536 			{"Attribute or Value Exists", 0, 20},
    537 			{"Invalid Attribute Syntax", 0, 21},
    538 			{"No Such Object", 0, 32},
    539 			{"Alias Problem", 0, 33},
    540 			{"Invalid DN Syntax", 0, 34},
    541 			{"Alias Dereferencing Problem", 0, 36},
    542 			{"Inappropriate Authentication", 0, 48},
    543 			{"Invalid Credentials", 0, 49},
    544 			{"Insufficient Access Rights", 0, 50},
    545 			{"Busy", 0, 51},
    546 			{"Unavailable", 0, 52},
    547 			{"Unwilling To Perform", 0, 53},
    548 			{"Loop Detect", 0, 54},
    549 			{"Naming Violation", 0, 64},
    550 			{"ObjectClass violation", 0, 65},
    551 			{"Not Allowed On Non Leaf", 0, 66},
    552 			{"Not Allowed On RDN", 0, 67},
    553 			{"Entry Already Exists", 0, 68},
    554 			{"ObjectClass Mods Prohibited", 0, 69},
    555 			{"Affects Multiple DSAs", 0, 71},
    556 			{"Other", 0, 80}}};
    557 
    558 
    559 static asndefT referral = {"Referral", SEQUENCEOF, -1, 1, {
    560 			{"LDAP URL", 0, -1}}};
    561 
    562 static asndefT ldapResult = {"LDAP Result", SEQUENCE, -1, 4, {
    563 			{0, &resultCode, -1},
    564 			{"Matched DN", 0, -1},
    565 			{"Error Message", 0, -1},
    566 			{0, &referral, 3}}};
    567 
    568 static asndefT bindResponse = {"Operation", SEQUENCE, 1, 5, {
    569 			{0, &resultCode, -1},
    570 			{"Matched DN", 0, -1},
    571 			{"Error Message", 0, -1},
    572 			{0, &referral, 3},
    573 			{"SASL Credentials", 0, 7}}};
    574 
    575 static asndefT unbindRequest = {"Operation", SEQUENCE, 2, 0, {0}};
    576 
    577 static asndefT searchResDone = {"Operation", SEQUENCE, 5, 4, {
    578 			{0, &resultCode, -1},
    579 			{"Matched DN", 0, -1},
    580 			{"Error Message", 0, -1},
    581 			{0, &referral, 3}}};
    582 
    583 static asndefT seqModOperation = {"Operation", ENUM, -1, 4, {
    584 			{"Add", 0, 0},
    585 			{"Delete", 0, 1},
    586 			{"Replace", 0, 2}}};
    587 
    588 static asndefT seqModModification = {"Modification", SEQUENCE, -1, 1, {
    589 			{0, &attribute, -1}}};
    590 
    591 static asndefT seqModification = {"", SEQUENCE, -1, 2, {
    592 		    {0, &seqModOperation, -1},
    593 			{0, &seqModModification, -1}}};
    594 
    595 static asndefT modification = {"Modification", SEQUENCEOF, -1, 1, {
    596 			{0, &seqModification, -1}}};
    597 
    598 static asndefT modifyRequest = {"Operation", SEQUENCE, 6, 2, {
    599 			{0, &objectName, -1},
    600 			{0, &modification, -1}}};
    601 
    602 static asndefT modifyResponse = {"Operation", SEQUENCE, 7, 4, {
    603 			{0, &resultCode, -1},
    604 			{"Matched DN", 0, -1},
    605 			{"Error Message", 0, -1},
    606 			{0, &referral, 3}}};
    607 
    608 static asndefT addAttributes = {"Attributes", SEQUENCEOF, -1, 1, {
    609 			{0, &attribute, -1}}};
    610 
    611 static asndefT addRequest = {"Operation", SEQUENCE, 8, 2, {
    612 			{0, &ldapEntry, -1},
    613 			{0, &addAttributes, -1}}};
    614 
    615 static asndefT addResponse = {"Operation", SEQUENCE, 9, 4, {
    616 			{0, &resultCode, -1},
    617 			{"Matched DN", 0, -1},
    618 			{"Error Message", 0, -1},
    619 			{0, &referral, 3}}};
    620 
    621 static asndefT delRequest = {"Operation", SEQUENCE, 10, 1, {
    622 			{0, &ldapEntry, -1}}};
    623 
    624 static asndefT delResponse = {"Operation", SEQUENCE, 11, 4, {
    625 			{0, &resultCode, -1},
    626 			{"Matched DN", 0, -1},
    627 			{"Error Message", 0, -1},
    628 			{0, &referral, 3}}};
    629 
    630 static asndefT modifyDNRequest = {"Operation", SEQUENCE, 12, 4, {
    631 			{0, &ldapEntry, -1},
    632 			{0, &relativeLdapEntry, -1},
    633 			{"Delete Old RDN", 0, -1},
    634 			{0, &newSuperior, 0}}};
    635 
    636 static asndefT modifyDNResponse = {"Operation", SEQUENCE, 13, 4, {
    637 			{0, &resultCode, -1},
    638 			{"Matched DN", 0, -1},
    639 			{"Error Message", 0, -1},
    640 			{0, &referral, 3}}};
    641 
    642 static asndefT ava = {"Ava", SEQUENCE, -1, 2, {
    643 			{"Attr Descr", 0, -1},
    644 			{"Value", 0, -1}}};
    645 
    646 static asndefT compareRequest = {"Operation", SEQUENCE, 14, 2, {
    647 			{0, &ldapEntry, -1},
    648 			{0, &ava, 0}}};
    649 
    650 static asndefT compareResponse = {"Operation", SEQUENCE, 15, 4, {
    651 			{0, &resultCode, -1},
    652 			{"Matched DN", 0, -1},
    653 			{"Error Message", 0, -1},
    654 			{0, &referral, 3}}};
    655 
    656 static asndefT abandonRequest = {"Operation", SEQUENCE, 16, 1, {
    657 		    {"Message ID", 0, -1}}};
    658 
    659 static asndefT searchResRef =  {"Operation", SEQUENCEOF, 19, 1, {
    660 			{"LDAP URL", 0, -1}}};
    661 
    662 static asndefT extendedRequest = {"Operation", SEQUENCE, 14, 2, {
    663 			{"Request Name", 0, 0},
    664 			{"Request Value", 0, 1}}};
    665 
    666 static asndefT extendedResponse = {"Operation", SEQUENCE, 24, 6, {
    667 			{0, &resultCode, -1},
    668 			{"Matched DN", 0, -1},
    669 			{"Error Message", 0, -1},
    670 			{0, &referral, 3},
    671 			{"Response Name", 0, 10},
    672 			{"Response", 0, 11}}};
    673 
    674 static asndefT protocolOp = {"Protocol Op", CHOICE, -1, 20, {
    675 			{0, &bindRequest, 0},
    676 			{0, &bindResponse, 1},
    677 			{0, &unbindRequest, 2},
    678 			{0, &searchRequest, 3},
    679 			{0, &searchResEntry, 4},
    680 			{0, &searchResDone, 5},
    681 			{0, &modifyRequest, 6},
    682 			{0, &modifyResponse, 7},
    683 			{0, &addRequest, 8},
    684 			{0, &addResponse, 9},
    685 			{0, &delRequest, 10},
    686 			{0, &delResponse, 11},
    687 			{0, &modifyDNRequest, 12},
    688 			{0, &modifyDNResponse, 13},
    689 			{0, &compareRequest, 14},
    690 			{0, &compareResponse, 15},
    691 			{0, &abandonRequest, 16},
    692 			{0, &searchResRef, 19},
    693 			{0, &extendedRequest, 23},
    694 			{0, &extendedResponse, 24}}};
    695 
    696 static asndefT control = {"Control", SEQUENCE, -1, 3, {
    697 			{"LDAP OID", 0, -1},
    698 			{"Criticality", 0, -1},
    699 			{"Control value", 0, -1}}};
    700 
    701 static asndefT controls = {"Controls List", SEQUENCEOF, -1, 1, {
    702 	{0, &control, -1}}};
    703 
    704 static asndefT LDAPMessage = { "LDAPMessage", SEQUENCE, -1, 3, {
    705 			{"Message ID", 0, -1},
    706 			{0, &protocolOp, -1},
    707 			{0, &controls, 0}}};
    708 
    709 static asndefT MPDU = { "MPDU", SET,  -1, 1,
    710 			{{0, &LDAPMessage, 0}}};
    711 
    712 static int mytype[] = {
    713 0,			/* EndOfContents	*/
    714 0,			/* Boolean			*/
    715 0,			/* Integer			*/
    716 BITSTRING,	/* BitString		*/
    717 0,			/* OctetString		*/
    718 0,			/* Null				*/
    719 0,			/* Oid				*/
    720 0,			/* ObjDescriptor	*/
    721 0,			/* External			*/
    722 0,			/* Real				*/
    723 ENUM,		/* Enumerated		*/
    724 0,			/* Reserved			*/
    725 0,			/* Reserved			*/
    726 0,			/* Reserved			*/
    727 0,			/* Reserved			*/
    728 0,			/* Reserved			*/
    729 SEQUENCE,	/* Sequence			*/
    730 SET,		/* Set				*/
    731 0,			/* NumericString	*/
    732 0,			/* PrintableString	*/
    733 0,			/* T.61String		*/
    734 0,			/* VideotexString	*/
    735 0,			/* IA5String		*/
    736 0,			/* UTCTime			*/
    737 0,			/* GeneralizedTime	*/
    738 0,			/* GraphicString	*/
    739 0,			/* VisibleString	*/
    740 0,			/* GeneralString	*/
    741 0,			/* Reserved			*/
    742 0,			/* Reserved			*/
    743 0,			/* Reserved			*/
    744 0,			/* Reserved			*/
    745 };
    746 
    747 /*
    748  * Find object identifier in known oid table
    749  * A	oid - oid hexa string
    750  * int	olg - oid length
    751  */
    752 static int
    753 oidmap(A oid, int olg)
    754 {
    755 	register int ix, goon;
    756 	register A oidptr, tabptr, tabend;
    757 
    758 /* returns (oid table size) if not found */
    759 
    760 	for (ix = 0; ix < OIDNB; ix++) {
    761 		oidptr = oid; tabptr = (&(OidTab[ix].oidcode[0]));
    762 		if (olg == INT(*tabptr++)) {
    763 			tabend = tabptr + olg;
    764 			goon = 1;
    765 			while (goon != 0 && tabptr < tabend) {
    766 				if (*tabptr++ != *oidptr++)
    767 					goon = 0;
    768 			}
    769 			if (goon != 0)
    770 				return (ix);
    771 		}
    772 	}
    773 	return (OIDNB);
    774 }
    775 
    776 /*
    777  * Read an hexacode and convert it into ASCII
    778  */
    779 static int getnext(int ctxnum)
    780 {
    781 	static X c[3]; /* c[0-3] will contain ascii values on exit */
    782 	hex = 0;
    783 	if (gi_osibuf[ctxnum] == osilen)
    784 		return (-1);
    785 	hex = osibuff[gi_osibuf[ctxnum]++];
    786 	(void) sprintf((char *)c, "%02x", (hex&0x00FF));
    787 	return (0);
    788 }
    789 
    790 /*
    791  * Skip everything that is not an LDAPMessage
    792  */
    793 static char *skipjunk(len, pdu)
    794 int len;
    795 char *pdu;
    796 {
    797 	int tag;
    798 	char *buf = pdu;
    799 	int offset = 0;
    800 	while (len > 0) {
    801 		/* size minumum for a sequence + integer = 5 */
    802 		/* LDAPMessage::= SEQUENCE  */
    803 		if ((len > 5) && (buf[0] == 0x30)) {
    804 			tag = buf[1]&0x00ff;
    805 			if (tag < 0x80) {
    806 				/* length is one one octet */
    807 				offset = 1;
    808 			} else {
    809 				/* length is multiple octet.  */
    810 				offset = 1+ tag&0x007f;
    811 			}
    812 			/* Make sure we don't read past the end */
    813 			/* of the buffer */
    814 			if (len - (1+offset) > 0) {
    815 				/* skip after the length */
    816 				tag = buf[1+offset]&0x00ff;
    817 				if (tag == 0x02) { /* INTEGER */
    818 					/* looks like a valid PDU */
    819 					return (buf);
    820 				}
    821 			}
    822 		}
    823 		len --;
    824 		buf++;
    825 	}
    826 	return (buf);
    827 }
    828 
    829 
    830 #define	GETNEXT(a) (void)getnext(a);
    831 
    832 /*
    833  * main routine: decode a TLV; to be called recursively
    834  *
    835  * pdulen: current pdu's length
    836  */
    837 static int
    838 decpdu(int pdulen, asndefTp ASNDESC, int ctxnum)
    839 {
    840 	X		scrlin[99];	/* screen line */
    841 	X		oidstr[80];	/* oid hexa string */
    842 	int		slen;	/* screen line length */
    843 	int		stlv;	/* sub-tlv length */
    844 	int		oix;	/* oid table index */
    845 	int		effnb;	/* effectively traced octet nb */
    846 	int		i = 0, j = 0;
    847 	int		ai = -2;
    848 	asndefTp SASNDESC = 0;
    849 	asndefTp TMPDESC = 0;
    850 	asndefTp GR_TMPDESC = 0;
    851 	int tmpai = 0;
    852 	int gr_tmpai = 0;
    853 	int dontprint = 0;
    854 	int already = 0;
    855 	static int rlen = 0;	/* tlv's real length */
    856 
    857 	++level[ctxnum];	/* level indicator */
    858 	effnb = 0;
    859 
    860 	/*
    861 	 * Decode the current TLV segment
    862 	 */
    863 	while (pdulen > 1) {
    864 
    865 		if (getnext(ctxnum)) {
    866 			break;
    867 		}
    868 		if (strlen(scrbuffer)) asnshw2("%s  ", "LDAP:");
    869 		/* screen printing according to level indicator */
    870 		for (i = 1; i < level[ctxnum]; ++i) asnshw1("   ");
    871 
    872 		/* get tag */
    873 		otyp[ctxnum] = INT(hex); /* single octet type only */
    874 		--pdulen;
    875 		++effnb;
    876 
    877 		/* get length */
    878 		GETNEXT(ctxnum);
    879 		olen[ctxnum] = INT(hex);	/* tlv length */
    880 		--pdulen;
    881 		++effnb;
    882 
    883 		/* Continuing decoding of current TLV... */
    884 		/*
    885 		 * Snoop's lower layers do not allow us
    886 		 * to know the true length for
    887 		 * datastream protocols like LDAP.
    888 		 */
    889 
    890 		/*
    891 		 * if length is less than 128, we
    892 		 * already have the real TLV length.
    893 		 */
    894 		if (olen[ctxnum] < 128) {	/* short length form */
    895 			rlen = olen[ctxnum];
    896 		} else {		/* long and any form length */
    897 		/* else we do more getnext()'s */
    898 			for (rlen = 0, olen[ctxnum] &= 0x0F;
    899 			(olen[ctxnum]) && (pdulen > 0);
    900 			--olen[ctxnum], --pdulen, ++effnb) {
    901 				GETNEXT(ctxnum);
    902 				rlen = (rlen << 8) | INT(hex);
    903 			}
    904 			if (!rlen) {
    905 				pdulen = 0x7fffffff;
    906 			}
    907 		}
    908 
    909 		/*
    910 		 * print the tag class and number
    911 		 */
    912 		i = otyp[ctxnum]&0x1F;
    913 		switch (otyp[ctxnum] >> 6) {	/* class */
    914 		case 0:	/* universal */
    915 			if (ASNDESC && i != 0) {
    916 				int dobreak = 0;
    917 				switch (ASNDESC->type) {
    918 				case CONTENT:
    919 					SASNDESC = ASNDESC;
    920 					break;
    921 				case SET:
    922 					for (ai = 0;
    923 						ai < ASNDESC->nbson && i < 32 &&
    924 						ASNDESC->son[ai].sondef &&
    925 					/*
    926 					 * For this test SEQUENCE & SEQUENCE OF
    927 					 * are same, so suppress the last bit
    928 					 */
    929 						(ASNDESC->son[ai].sondef
    930 							->type&0xFE)
    931 						!= mytype[i]; ++ai);
    932 					if (ai < ASNDESC->nbson) {
    933 						SASNDESC =
    934 						    ASNDESC->son[ai].sondef;
    935 					if (ASNDESC->son[ai].sonname != NULL) {
    936 
    937 					if (ASNDESC->son[ai].sondef != NULL &&
    938 					    ASNDESC->son[ai].sondef->name !=
    939 					    NULL) {
    940 						asnshw2("%s	", "LDAP:");
    941 						asnshw4(" %c[%s %s]",
    942 						((otyp[ctxnum]&0x20)?'*':' '),
    943 						ASNDESC->son[ai].sonname,
    944 						ASNDESC->son[ai].sondef->name);
    945 					} else {
    946 						asnshw2("%s	", "");
    947 						asnshw3(" %c[%s]",
    948 						((otyp[ctxnum]&0x20)?'*':' '),
    949 						ASNDESC->son[ai].sonname);
    950 					} /* end if */
    951 
    952 					dobreak = 1;
    953 
    954 					} else if (ASNDESC->son[ai].sondef !=
    955 					    NULL &&
    956 					    ASNDESC->son[ai].sondef->name !=
    957 					    NULL) {
    958 						asnshw2("%s	", "LDAP:");
    959 						asnshw3(" %c[%s]",
    960 						((otyp[ctxnum]&0x20)?'*':' '),
    961 						ASNDESC->son[ai].sondef->name);
    962 						dobreak = 1;
    963 					} /* end if */
    964 					} /* end if */
    965 						break;
    966 				case CHOICE:
    967 					if (GR_TMPDESC) {
    968 						ASNDESC = TMPDESC;
    969 						TMPDESC = GR_TMPDESC;
    970 						GR_TMPDESC = 0;
    971 					} else if (TMPDESC) {
    972 						ASNDESC = TMPDESC;
    973 						TMPDESC = 0;
    974 					}
    975 					if (gr_tmpai) {
    976 						ai = tmpai;
    977 						tmpai = gr_tmpai;
    978 						gr_tmpai = 0;
    979 					} else if (tmpai) {
    980 						ai = tmpai;
    981 						tmpai = 0;
    982 					}
    983 					break;
    984 
    985 				case SEQUENCE:
    986 					if (ai == -2) {
    987 						ai = 0;
    988 					} else {
    989 						do {
    990 							ai++;
    991 						} while \
    992 			(ai < ASNDESC->nbson && i < 32 && mytype[i] && \
    993 			ASNDESC->son[ai].sondef &&
    994 					/*
    995 					 * For this test SEQUENCE & SEQUENCE OF
    996 					 * are the same, so suppress last bit
    997 					 */
    998 			(ASNDESC->son[ai].sondef->type&0xFE) != mytype[i]);
    999 					} /* end if */
   1000 					if (ai < ASNDESC->nbson) {
   1001 						SASNDESC = \
   1002 						ASNDESC->son[ai].sondef;
   1003 						if (ASNDESC->son[ai].sonname) {
   1004 							if \
   1005 			(ASNDESC->son[ai].sondef &&
   1006 			ASNDESC->son[ai].sondef->name) {
   1007 								asnshw4 \
   1008 			(" %c[%s %s]", ((otyp[ctxnum]&0x20)?'*':' '),
   1009 			ASNDESC->son[ai].sonname,
   1010 			ASNDESC->son[ai].sondef->name);
   1011 							} else {
   1012 								asnshw3 \
   1013 			(" %c[%s]", ((otyp[ctxnum]&0x20)?'*':' '),
   1014 			ASNDESC->son[ai].sonname);
   1015 							} /* end if */
   1016 							dobreak = 1;
   1017 						} else if \
   1018 			(ASNDESC->son[ai].sondef &&
   1019 			ASNDESC->son[ai].sondef->name) {
   1020 								asnshw3 \
   1021 			(" %c[%s]", ((otyp[ctxnum]&0x20)?'*':' '),
   1022 			ASNDESC->son[ai].sondef->name);
   1023 							dobreak = 1;
   1024 						} /* end if */
   1025 					} /* end if */
   1026 					break;
   1027 				case SEQUENCEOF:
   1028 					ai = 0;
   1029 					SASNDESC = ASNDESC->son[ai].sondef;
   1030 					if (ASNDESC->son[ai].sonname) {
   1031 						if (ASNDESC->son[ai].sondef && \
   1032 			ASNDESC->son[ai].sondef->name) {
   1033 								asnshw4 \
   1034 			(" %c[%s %s]", ((otyp[ctxnum]&0x20)?'*':' '),
   1035 			ASNDESC->son[ai].sonname,
   1036 			ASNDESC->son[ai].sondef->name);
   1037 						} else {
   1038 							asnshw3 \
   1039 			(" %c[%s]", ((otyp[ctxnum]&0x20)?'*':' '),
   1040 			ASNDESC->son[ai].sonname);
   1041 						} /* end if */
   1042 						dobreak = 1;
   1043 					} else if \
   1044 			(ASNDESC->son[ai].sondef &&
   1045 			ASNDESC->son[ai].sondef->name) {
   1046 							asnshw3 \
   1047 			(" %c[%s]", ((otyp[ctxnum]&0x20)?'*':' '),
   1048 			ASNDESC->son[ai].sondef->name);
   1049 						dobreak = 1;
   1050 					} /* end if */
   1051 				} /* end switch */
   1052 				if (dobreak) {
   1053 					break;
   1054 				} /* end if */
   1055 			} /* end if */
   1056 			if (uclass[i]) {
   1057 				asnshw3 \
   1058 			(" %c[%s]", ((otyp[ctxnum]&0x20)?'*':' '), uclass[i]);
   1059 			} else {
   1060 				asnshw4 \
   1061 			(" %c[%s%d]", ((otyp[ctxnum]&0x20)?'*':' '),
   1062 			class[0], i);
   1063 			}
   1064 			break;
   1065 		case 1:		/* application */
   1066 
   1067 		if (ASNDESC) {
   1068 
   1069 				for (ai = 0; ai < ASNDESC->nbson; ++ai) {
   1070 					int i2 = 0;
   1071 
   1072 					if \
   1073 			(ASNDESC->son[ai].sondef &&
   1074 			ASNDESC->son[ai].sondef->type == CHOICE) {
   1075 						while \
   1076 			(i2 < ASNDESC->son[ai].sondef->nbson &&
   1077 			ASNDESC->son[ai].sondef->son[i2].sondef && \
   1078 	ASNDESC->son[ai].sondef->son[i2].sondef->application != i) {
   1079 							i2++;
   1080 							continue;
   1081 						}
   1082 						if \
   1083 			(i2 == ASNDESC->son[ai].sondef->nbson) {
   1084 							ai = ASNDESC->nbson;
   1085 							break;
   1086 						}
   1087 			if (TMPDESC) {
   1088 				GR_TMPDESC = TMPDESC;
   1089 				gr_tmpai = tmpai;
   1090 			}
   1091 					TMPDESC = ASNDESC;
   1092 					ASNDESC = ASNDESC->son[ai].sondef;
   1093 					tmpai = ai;
   1094 					ai = i2;
   1095 					}
   1096 
   1097 					if (ASNDESC->son[ai].sondef && \
   1098 			ASNDESC->son[ai].sondef->application == i) {
   1099 						SASNDESC = \
   1100 			ASNDESC->son[ai].sondef;
   1101 						if (ASNDESC->son[ai].sonname) {
   1102 							if \
   1103 			(ASNDESC->son[ai].sondef->name) {
   1104 								asnshw3 \
   1105 			(" %s %s", ASNDESC->son[ai].sonname,
   1106 			ASNDESC->son[ai].sondef->name);
   1107 							} else {
   1108 								asnshw2 \
   1109 			(" %s", ASNDESC->son[ai].sonname);
   1110 							} /* end if */
   1111 						} else if \
   1112 			(ASNDESC->son[ai].sondef->name) {
   1113 							asnshw2 \
   1114 			(" %s", ASNDESC->son[ai].sondef->name);
   1115 						} /* end if */
   1116 						break;
   1117 					} /* end if */
   1118 				} /* end for */
   1119 				if (ai >= ASNDESC->nbson) {
   1120 					ai = -1;	/* not found */
   1121 				} /* end if */
   1122 			} /* end if */
   1123 			if (PTRaclass[i]) {
   1124 				asnshw5 \
   1125 			(" %c[%s%d: %s]", ((otyp[ctxnum]&0x20)?'*':' '),
   1126 			class[1], i, PTRaclass[i]);
   1127 				(void) strcpy(operation, (char *)PTRaclass[i]);
   1128 			} else {
   1129 				asnshw4 \
   1130 			(" %c[%s%d]", ((otyp[ctxnum]&0x20)?'*':' '), \
   1131 			class[1], i);
   1132 			}
   1133 			break;
   1134 
   1135 		case 2:		/* context-specific */
   1136 
   1137 			if (TMPDESC) {
   1138 				ASNDESC = TMPDESC;
   1139 				TMPDESC = GR_TMPDESC;
   1140 				already = 1;
   1141 			}
   1142 			if (ASNDESC) {
   1143 
   1144 				for (ai = 0; ai < ASNDESC->nbson; ++ai) {
   1145 					if \
   1146 			(!already && ASNDESC->son[ai].sondef &&
   1147 			ASNDESC->son[ai].sondef->type == CHOICE) {
   1148 						int i2 = 0;
   1149 						while \
   1150 			(i2 < ASNDESC->son[ai].sondef->nbson &&
   1151 			ASNDESC->son[ai].sondef->son[i2].tag != i) {
   1152 							i2++;
   1153 							continue;
   1154 						}
   1155 						if (i2 == \
   1156 			ASNDESC->son[ai].sondef->nbson) {
   1157 							ai = ASNDESC->nbson;
   1158 							break;
   1159 						}
   1160 						if (TMPDESC) {
   1161 							GR_TMPDESC = TMPDESC;
   1162 							gr_tmpai = tmpai;
   1163 						}
   1164 						TMPDESC = ASNDESC;
   1165 						ASNDESC = \
   1166 			ASNDESC->son[ai].sondef;
   1167 						tmpai = ai;
   1168 						ai = i2;
   1169 					}
   1170 
   1171 					if \
   1172 			(ASNDESC->son[ai].tag == i) {
   1173 						SASNDESC = \
   1174 			ASNDESC->son[ai].sondef;
   1175 						if (ASNDESC->son[ai].sonname) {
   1176 							if \
   1177 			(ASNDESC->son[ai].sondef &&
   1178 			ASNDESC->son[ai].sondef->name) {
   1179 								asnshw3 \
   1180 			(" %s %s", ASNDESC->son[ai].sonname,
   1181 			ASNDESC->son[ai].sondef->name);
   1182 							} else {
   1183 								asnshw2 \
   1184 			(" %s", ASNDESC->son[ai].sonname);
   1185 							} /* end if */
   1186 						} else if \
   1187 			(ASNDESC->son[ai].sondef &&
   1188 			ASNDESC->son[ai].sondef->name) {
   1189 							asnshw2 \
   1190 			(" %s", ASNDESC->son[ai].sondef->name);
   1191 						} /* end if */
   1192 						break;
   1193 					} /* end if */
   1194 				} /* end for */
   1195 				if (ai >= ASNDESC->nbson) {
   1196 					ai = -1;	/* not found */
   1197 				} /* end if */
   1198 			} /* end if */
   1199 			asnshw3 \
   1200 			(" %c[%d]", ((otyp[ctxnum]&0x20)?'*':' '), i);
   1201 			break;
   1202 
   1203 		case 3:		/* private */
   1204 			asnshw4 \
   1205 			(" %c[%s%d]", ((otyp[ctxnum]&0x20)?'*':' '), \
   1206 			class[3], i);
   1207 		} /* esac: tag */
   1208 
   1209 		/*
   1210 		 * print the length - as a debug tool only.
   1211 		 */
   1212 		/* asnshw2(" Length=%d ",rlen); */
   1213 		asnshw1("\n");
   1214 		if (rlen > pdulen) {
   1215 			asnshw1("*** Decode length error,");
   1216 			asnshw2(" PDU length = %d ***\n", pdulen);
   1217 			rlen = pdulen;
   1218 		}
   1219 
   1220 		/*
   1221 		 * recursive interpretation of the value if constructor
   1222 		 */
   1223 		if (otyp[ctxnum]&0x20) {		/* constructor */
   1224 
   1225 			stlv = decpdu((rlen?rlen:pdulen), \
   1226 			ASNDESC && ai != -1 ?(ai == -2 ? ASNDESC:
   1227 			ASNDESC->son[ai].sondef):0, ctxnum);
   1228 			/* recursive decoding */
   1229 			pdulen -= stlv;
   1230 			effnb += stlv;
   1231 		} else if (otyp[ctxnum] == 0x06) {
   1232 			/*
   1233 			 * interpretation of the object identifier
   1234 			 */
   1235 			for (j = 0; (rlen) && (pdulen > 0); \
   1236 			--rlen, --pdulen, ++effnb) {
   1237 				GETNEXT(ctxnum);
   1238 				oidstr[j++] = hex;
   1239 			}
   1240 
   1241 			/* interpret the object identifier */
   1242 			oidstr[j++] = '\0';
   1243 			oix = oidmap(oidstr, j-1);
   1244 			asnshw1("\n");
   1245 			if (oix >= 0 && oix < OIDNB) {	/* recognized obj id */
   1246 				asnshw2("%s\n", OidTab[oix].oidname);
   1247 			} else {
   1248 				asnshw1("Unknown Oid\n");
   1249 			}
   1250 		} else {
   1251 			/*
   1252 			 * interpretation of other primitive tags
   1253 			 */
   1254 			if (!otyp[ctxnum] && !rlen) {
   1255 			/* end of contents: any form length */
   1256 				pdulen = 0;
   1257 			} else {
   1258 				X   hexstr[5];
   1259 				int k = 0;
   1260 				int klen = rlen;
   1261 				if (SASNDESC && SASNDESC->type == CONTENT && \
   1262 			SASNDESC->nbson && SASNDESC->son[0].sondef) {
   1263 					(void)
   1264 			decpdu(rlen, SASNDESC->son[0].sondef, ctxnum);
   1265 				} else {
   1266 					if (rlen < 200) {
   1267 					for (j = 0, slen = 0; \
   1268 			(rlen) && (pdulen > 0);
   1269 					--rlen, --pdulen, ++effnb) {
   1270 						if (!slen) {
   1271 						    (void) \
   1272 			strcpy((char *)scrlin, "LDAP:  "); j += 7;
   1273 						    for \
   1274 			(i = 0; i < level[ctxnum]; ++i) {
   1275 							scrlin[j++] = ' ';
   1276 							scrlin[j++] = ' ';
   1277 							scrlin[j++] = ' ';
   1278 							scrlin[j++] = ' ';
   1279 						    }
   1280 						}
   1281 
   1282 						GETNEXT(ctxnum);
   1283 						if (k < 5) {
   1284 							hexstr[k++] = hex;
   1285 						} /* end if */
   1286 						if (!isprint(hex)) {
   1287 							hex = '_';
   1288 							dontprint = 1;
   1289 						}
   1290 						scrlin[j++] = hex;
   1291 						if ((slen += 2) >= \
   1292 			(72 - (level[ctxnum] * 3))) {
   1293 							slen = 0;
   1294 							scrlin[j] = 0;
   1295 							if (!dontprint) {
   1296 								asnshw2 \
   1297 			("%s\n", scrlin);
   1298 							}
   1299 							j = 0;
   1300 						}
   1301 					} /* rof: primitive values */
   1302 					if (slen) {
   1303 						scrlin[j] = 0;
   1304 						if (!dontprint) {
   1305 							asnshw2("%s\n", scrlin);
   1306 						}
   1307 					}
   1308 					dontprint = 0;
   1309 				} else {
   1310 					asnshw2("%s  ", "LDAP:");
   1311 				    for (i = 0; i < level[ctxnum]; ++i) {
   1312 						asnshw1("   ");
   1313 						scrlin[j++] = ' ';
   1314 						scrlin[j++] = ' ';
   1315 						scrlin[j++] = ' ';
   1316 					}
   1317 
   1318 				    for (j = 0; (rlen) && (pdulen > 0); \
   1319 			--rlen, --pdulen, ++effnb) {
   1320 						GETNEXT(ctxnum);
   1321 						if (k < 5) {
   1322 							hexstr[k++] = hex;
   1323 						}
   1324 					}
   1325 				    (void) strcpy \
   1326 			((char *)scrlin, \
   1327 			"*** NOT PRINTED - Too long value ***");
   1328 						asnshw2("%s\n", scrlin);
   1329 					}
   1330 
   1331 					if \
   1332 			(SASNDESC && SASNDESC->type == BITSTRING &&\
   1333 			klen <= 5) {
   1334 						unsigned long bitstr = 0;
   1335 						for (i = 1; i < 5; ++i) {
   1336 							bitstr = \
   1337 			((bitstr) << 8) + ((i < klen)?hexstr[i]:0);
   1338 						} /* end for */
   1339 						for \
   1340 			(i = 0; i < SASNDESC->nbson; ++i) {
   1341 							if ((bitstr & \
   1342 			((unsigned long)SASNDESC->son[i].sondef)) ==
   1343 			((unsigned long)SASNDESC->son[i].tag)) {
   1344 								if \
   1345 			(SASNDESC->son[i].sonname) {
   1346 								int k;
   1347 								asnshw2 \
   1348 			("%s  ", "LDAP:");
   1349 								for \
   1350 			(k = 0; k < level[ctxnum]; ++k) {
   1351 								asnshw1("   ");
   1352 								}
   1353 								asnshw2 \
   1354 			("%s", SASNDESC->son[i].sonname);
   1355 								} /* end if */
   1356 							} /* end if */
   1357 						} /* end for */
   1358 					} /* end if */
   1359 					if (SASNDESC && \
   1360 			(SASNDESC->type == ENUM ||
   1361 			SASNDESC->type == CONTENTTYPE) && klen <= 5) {
   1362 						unsigned long value = 0;
   1363 						for (i = 0; i < klen; ++i) {
   1364 							value = \
   1365 			((value) << 8) + hexstr[i];
   1366 						} /* end for */
   1367 						for \
   1368 			(i = 0; i < SASNDESC->nbson; ++i) {
   1369 							if \
   1370 			(value == ((unsigned long)SASNDESC->son[i].tag)) {
   1371 								if \
   1372 			(SASNDESC->son[i].sonname) {
   1373 									int k;
   1374 								asnshw2 \
   1375 			("%s  ", "LDAP:");
   1376 									for \
   1377 			(k = 0; k < level[ctxnum]; ++k) {
   1378 								asnshw1("   ");
   1379 									}
   1380 								asnshw2 \
   1381 			("%s\n", SASNDESC->son[i].sonname);
   1382 									(void) \
   1383 			strcpy(resultcode, SASNDESC->son[i].sonname);
   1384 								} /* end if */
   1385 								break;
   1386 							} /* end if */
   1387 						} /* end for */
   1388 					} /* end if */
   1389 
   1390 				} /* end if */
   1391 			} /* fi: constructor/obj-id/primitive */
   1392 		} /* fi: tag analysis */
   1393 	} /* elihw: len>1 */
   1394 	--level[ctxnum];
   1395 	return (effnb);
   1396 }
   1397 
   1398 
   1399 /* init_ldap initializes various buffers and variables */
   1400 /* it is called one-time (in snoop_filter.c) only. */
   1401 
   1402 void
   1403 init_ldap()
   1404 {
   1405 	int i;
   1406 
   1407 	for (i = 0; i < MAX_CTX; i++) {
   1408 		gi_osibuf[i] = 0;
   1409 		level[i] = 0;
   1410 	}
   1411 }
   1412 static void
   1413 ldapdump(char *data, int datalen)
   1414 {
   1415 	char *p;
   1416 	ushort_t *p16 = (ushort_t *)data;
   1417 	char *p8 = data;
   1418 	int i, left, len;
   1419 	int chunk = 16;  /* 16 bytes per line */
   1420 
   1421 	asnshw1("LDAP: Skipping until next full LDAPMessage\n");
   1422 
   1423 	for (p = data; p < data + datalen; p += chunk) {
   1424 		asnshw2("LDAP:\t%4d: ", p - data);
   1425 		left = (data + datalen) - p;
   1426 		len = MIN(chunk, left);
   1427 		for (i = 0; i < (len / 2); i++)
   1428 			asnshw2("%04x ", ntohs(*p16++) & 0xffff);
   1429 		if (len % 2) {
   1430 			asnshw2("%02x   ", *((unsigned char *)p16));
   1431 		}
   1432 		for (i = 0; i < (chunk - left) / 2; i++)
   1433 			asnshw1("     ");
   1434 
   1435 		asnshw1("   ");
   1436 		for (i = 0; i < len; i++, p8++)
   1437 			asnshw2("%c", isprint(*p8) ? *p8 : '.');
   1438 		asnshw1("\n");
   1439 	}
   1440 
   1441 	asnshw1("LDAP:\n");
   1442 }
   1443 
   1444 /* decode_ldap is the entry point for the main decoding function */
   1445 /* decpdu(). decode_ldap() is only called by interpret_ldap. */
   1446 
   1447 void
   1448 decode_ldap(char *buf, int len)
   1449 {
   1450 	asndefTp ASNDESC = 0;
   1451 	char *newbuf;
   1452 	int skipped = 0;
   1453 
   1454 	PTRaclass = MHSaclass;
   1455 	ASNDESC = &MPDU;
   1456 
   1457 
   1458 	newbuf =  skipjunk(len, buf);
   1459 	if (newbuf > buf) {
   1460 		skipped = newbuf-buf;
   1461 		ldapdump(buf, newbuf-buf);
   1462 	}
   1463 	buf = newbuf;
   1464 	len = len-skipped;
   1465 	osibuff = buf;	/* Undecoded buf is passed by interpret_ldap */
   1466 	osilen = len;	/* length of tcp data is also passed */
   1467 
   1468 	(void) decpdu(len, ASNDESC, 0);
   1469 	gi_osibuf[0] = 0;
   1470 }
   1471