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