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