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
57extern char *src_name;
58extern char *dst_name;
59#define	MAX_CTX  (10)
60#define	LINE_LEN (255)
61#define	BUF_SIZE (16000)
62static int ldap = 0;		/* flag to control initialization */
63struct ctx {
64	int src;
65	int dst;
66	char *src_name;
67	char *dst_name;
68};
69char *osibuff = NULL;
70int osilen = 0;
71char scrbuffer[BUF_SIZE];	/* buffer to accumulate data until a */
72				/* complete LDAPmessage is received  */
73char resultcode[LINE_LEN];	/* These are used */
74char operation[LINE_LEN];	/* by -V option.  */
75char bb[LINE_LEN];
76
77int gi_osibuf[MAX_CTX];
78int otyp[MAX_CTX];
79int olen[MAX_CTX];
80int level[MAX_CTX];
81
82void decode_ldap(char *buf, int len);
83
84#define	X unsigned char
85typedef	X * A;
86#define	INT(a) ((int)(a))
87#define	SCRUB (void) strcat(scrbuffer, bb);
88
89static X	hex;		/* input hex octet */
90static 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
110typedef struct {
111	A	oidname;	/* object identifier string name */
112	X	oidcode[16];	/* object identifier hexa code */
113}	oidelmT;
114typedef oidelmT *oidelmTp;
115
116/*
117 * Snoop's entry point to ldap decoding
118 */
119
120void
121interpret_ldap(flags, data, fraglen, src, dst)
122int flags;
123char *data;
124int fraglen;
125int src;
126int 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
177static 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
271static 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
282static 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
317static 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
353static 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
388typedef struct asndefS {
389char *name;
390int type;
391int application;
392int nbson;
393struct {
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
411static asndefT RTSpasswd = { "RTS Authentification data", SET,  -1, 2, {
412			{"MTA Name", 0, 0},
413			{"MTA Password", 0, 1}}};
414static asndefT RTSudata = { "RTS User data", SET,  -1, 1, {
415			{0, &RTSpasswd, 1}}};
416
417static asndefT baseObject = {"Base Object", PRINTABLE, -1, 0, {0}};
418
419static asndefT scope = {"Scope", ENUM, -1, 3, {
420			{"BaseObject", 0, 0},
421			{"singleLevel", 0, 1},
422			{"wholeSubtree", 0, 2}}};
423
424static asndefT derefAliases = {"DerefAliases", ENUM, -1, 4, {
425			{"neverDerefAliases", 0, 0},
426			{"derefInSearching", 0, 1},
427			{"derefFindingBaseObj", 0, 2},
428			{"derefAlways", 0, 3}}};
429
430static asndefT filter;
431static asndefT and = {"And", SET, -1, 1, {
432			{0, &filter, -1}}};
433static asndefT or = {"Or", SET, -1, 1, {
434			{0, &filter, -1}}};
435static asndefT not = {"Not", SET, -1, 1, {
436			{0, &filter, -1}}};
437static asndefT equalityMatch = {"Equality Match", SEQUENCE, -1, 2, {
438			{"Attr Descr", 0, -1},
439			{"Value", 0, -1}}};
440static 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}}};
445static asndefT greaterOrEqual = {"Greater Or Equal", SEQUENCE, -1, 2, {
446			{"Attr Descr", 0, -1},
447			{"Value", 0, -1}}};
448static asndefT lessOrEqual = {"Less Or Equal", SEQUENCE, -1, 2, {
449			{"Attr Descr", 0, -1},
450			{"Value", 0, -1}}};
451static asndefT approxMatch = {"Approx Match", SEQUENCE, -1, 2, {
452			{"Attr Descr", 0, -1},
453			{"Value", 0, -1}}};
454static asndefT extensibleMatch = {"Extensible Match", SEQUENCE, -1, 4, {
455			{"MatchingRule", 0, 1},
456			{"Type", 0, 2},
457			{"MatchValue", 0, 3},
458			{"dnAttributes", 0, 4}}};
459
460static 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
472static asndefT attributedescription = \
473			{"Attribute Description", PRINTABLE, -1, 0, {0}};
474static asndefT attributes = {"Attribute List", SEQUENCEOF, -1, 1, {
475			{0, &attributedescription, -1}}};
476
477static 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
487static asndefT objectName = {"Object Name", PRINTABLE, -1, 0, {0}};
488
489static asndefT ldapEntry = {"Entry", PRINTABLE, -1, 0, {0}};
490static asndefT relativeLdapEntry = \
491			{"Relative LDAP Entry", PRINTABLE, -1, 0, {0}};
492static asndefT newSuperior = {"New Superior", PRINTABLE, -1, 0, {0}};
493
494static asndefT vals = {"Vals", SET, -1, 1, {
495			{"Value", 0, -1}}};
496
497static asndefT attribute = {"Attribute", SEQUENCE, -1, 2, {
498			{"Type", 0, -1},
499			{0, &vals, -1}}};
500
501static asndefT partialAttributes = {"Partial Attributes", SEQUENCEOF, -1, 1, {
502			{0, &attribute, -1}}};
503
504static asndefT searchResEntry = {"Operation", SEQUENCE, 4, 2, {
505			{0, &objectName, -1},
506			{0, &partialAttributes, -1}}};
507
508static asndefT authChoice = {"Authentication Choice", CHOICE, -1, 2, {
509			{"Authentication: Simple", 0, 0},
510			{"Authentication: SASL", 0, 3}}};
511
512static asndefT bindRequest = {"Operation", SEQUENCE, 0, 3, {
513			{"Version", 0, -1},
514			{0, &objectName, -1},
515			{0, &authChoice, -1}}};
516
517static 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
559static asndefT referral = {"Referral", SEQUENCEOF, -1, 1, {
560			{"LDAP URL", 0, -1}}};
561
562static 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
568static 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
575static asndefT unbindRequest = {"Operation", SEQUENCE, 2, 0, {0}};
576
577static 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
583static asndefT seqModOperation = {"Operation", ENUM, -1, 4, {
584			{"Add", 0, 0},
585			{"Delete", 0, 1},
586			{"Replace", 0, 2}}};
587
588static asndefT seqModModification = {"Modification", SEQUENCE, -1, 1, {
589			{0, &attribute, -1}}};
590
591static asndefT seqModification = {"", SEQUENCE, -1, 2, {
592		    {0, &seqModOperation, -1},
593			{0, &seqModModification, -1}}};
594
595static asndefT modification = {"Modification", SEQUENCEOF, -1, 1, {
596			{0, &seqModification, -1}}};
597
598static asndefT modifyRequest = {"Operation", SEQUENCE, 6, 2, {
599			{0, &objectName, -1},
600			{0, &modification, -1}}};
601
602static 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
608static asndefT addAttributes = {"Attributes", SEQUENCEOF, -1, 1, {
609			{0, &attribute, -1}}};
610
611static asndefT addRequest = {"Operation", SEQUENCE, 8, 2, {
612			{0, &ldapEntry, -1},
613			{0, &addAttributes, -1}}};
614
615static 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
621static asndefT delRequest = {"Operation", SEQUENCE, 10, 1, {
622			{0, &ldapEntry, -1}}};
623
624static 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
630static 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
636static 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
642static asndefT ava = {"Ava", SEQUENCE, -1, 2, {
643			{"Attr Descr", 0, -1},
644			{"Value", 0, -1}}};
645
646static asndefT compareRequest = {"Operation", SEQUENCE, 14, 2, {
647			{0, &ldapEntry, -1},
648			{0, &ava, 0}}};
649
650static 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
656static asndefT abandonRequest = {"Operation", SEQUENCE, 16, 1, {
657		    {"Message ID", 0, -1}}};
658
659static asndefT searchResRef =  {"Operation", SEQUENCEOF, 19, 1, {
660			{"LDAP URL", 0, -1}}};
661
662static asndefT extendedRequest = {"Operation", SEQUENCE, 14, 2, {
663			{"Request Name", 0, 0},
664			{"Request Value", 0, 1}}};
665
666static 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
674static 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
696static asndefT control = {"Control", SEQUENCE, -1, 3, {
697			{"LDAP OID", 0, -1},
698			{"Criticality", 0, -1},
699			{"Control value", 0, -1}}};
700
701static asndefT controls = {"Controls List", SEQUENCEOF, -1, 1, {
702	{0, &control, -1}}};
703
704static asndefT LDAPMessage = { "LDAPMessage", SEQUENCE, -1, 3, {
705			{"Message ID", 0, -1},
706			{0, &protocolOp, -1},
707			{0, &controls, 0}}};
708
709static asndefT MPDU = { "MPDU", SET,  -1, 1,
710			{{0, &LDAPMessage, 0}}};
711
712static int mytype[] = {
7130,			/* EndOfContents	*/
7140,			/* Boolean			*/
7150,			/* Integer			*/
716BITSTRING,	/* BitString		*/
7170,			/* OctetString		*/
7180,			/* Null				*/
7190,			/* Oid				*/
7200,			/* ObjDescriptor	*/
7210,			/* External			*/
7220,			/* Real				*/
723ENUM,		/* Enumerated		*/
7240,			/* Reserved			*/
7250,			/* Reserved			*/
7260,			/* Reserved			*/
7270,			/* Reserved			*/
7280,			/* Reserved			*/
729SEQUENCE,	/* Sequence			*/
730SET,		/* Set				*/
7310,			/* NumericString	*/
7320,			/* PrintableString	*/
7330,			/* T.61String		*/
7340,			/* VideotexString	*/
7350,			/* IA5String		*/
7360,			/* UTCTime			*/
7370,			/* GeneralizedTime	*/
7380,			/* GraphicString	*/
7390,			/* VisibleString	*/
7400,			/* GeneralString	*/
7410,			/* Reserved			*/
7420,			/* Reserved			*/
7430,			/* Reserved			*/
7440,			/* Reserved			*/
745};
746
747/*
748 * Find object identifier in known oid table
749 * A	oid - oid hexa string
750 * int	olg - oid length
751 */
752static int
753oidmap(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 */
779static 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 */
793static char *skipjunk(len, pdu)
794int len;
795char *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 */
837static int
838decpdu(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
1402void
1403init_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}
1412static void
1413ldapdump(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
1447void
1448decode_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