root/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ldap.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <net/if.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
#include <netinet/udp.h>
#include "snoop.h"

#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif

extern char *src_name;
extern char *dst_name;
#define MAX_CTX  (10)
#define LINE_LEN (255)
#define BUF_SIZE (16000)
static int ldap = 0;            /* flag to control initialization */
struct ctx {
        int src;
        int dst;
        char *src_name;
        char *dst_name;
};
char *osibuff = NULL;
int osilen = 0;
char scrbuffer[BUF_SIZE];       /* buffer to accumulate data until a */
                                /* complete LDAPmessage is received  */
char resultcode[LINE_LEN];      /* These are used */
char operation[LINE_LEN];       /* by -V option.  */
char bb[LINE_LEN];

int gi_osibuf[MAX_CTX];
int otyp[MAX_CTX];
int olen[MAX_CTX];
int level[MAX_CTX];

void decode_ldap(char *buf, int len);

#define X unsigned char
typedef X * A;
#define INT(a) ((int)(a))
#define SCRUB (void) strcat(scrbuffer, bb);

static X        hex;            /* input hex octet */
static A        *PTRaclass;     /* application tag table pointer */

/*
 * ASN.1 Message Printing Macros
 */

#define asnshw1(a)                              {(void)sprintf(bb, a); SCRUB }
#define asnshw2(a, b)                   {(void)sprintf(bb, a, b); SCRUB }
#define asnshw3(a, b, c)                {(void)sprintf(bb, a, b, c); SCRUB }
#define asnshw4(a, b, c, d)             {(void)sprintf(bb, a, b, c, d); SCRUB }
#define asnshw5(a, b, c, d, e)  {(void)sprintf(bb, a, b, c, d, e); SCRUB }

/*
 * Local Types And Variables
 */

/*
 * Object identifier oid to name mapping description type
 */

typedef struct {
        A       oidname;        /* object identifier string name */
        X       oidcode[16];    /* object identifier hexa code */
}       oidelmT;
typedef oidelmT *oidelmTp;

/*
 * Snoop's entry point to ldap decoding
 */

void
interpret_ldap(flags, data, fraglen, src, dst)
int flags;
char *data;
int fraglen;
int src;
int dst;
{

        if (!ldap) {
                init_ldap();
                ldap = 1;
        }

        (void) decode_ldap(data, fraglen);

        if (flags & F_DTAIL) {
                /* i.e. when snoop is run with -v (verbose) */
                show_header("LDAP:  ",
                "Lightweight Directory Access Protocol Header", fraglen);
                show_space();
                printf("%s", scrbuffer);
        }

        if (flags & F_SUM) {
        /* i.e. when snoop is run with -V (summary) */
                (void) strcpy(data, "");

                if (strlen(operation) != 0) {
                        (void) strcat(data, " ");
                        (void) strncat(data, operation, 30);
                        (void) strcpy(operation, "");
                }

                if (strlen(resultcode) != 0) {
                        (void) strcat(data, " ");
                        (void) strncat(data, resultcode, 30);
                        (void) strcpy(resultcode, "");
                }

                if (dst == 389) {
                        (void) sprintf(get_sum_line(),
                                "LDAP C port=%d%s", src, data);
                }
                if (src == 389) {
                        (void) sprintf(get_sum_line(),
                                "LDAP R port=%d%s", dst, data);
                }
        }

        (void) strcpy(scrbuffer, "");
}

/*
 * Known object identifiers: customize to add your own oids
 */

static oidelmT OidTab[] = {
/*
 *      X.500 Standardized Attribute Types
 */
{(A)"ObjectClass",                              { 0x03, 0x55, 0x04, 0x00 }},
{(A)"AliasObjectName",                  { 0x03, 0x55, 0x04, 0x01 }},
{(A)"KnowledgeInfo",                    { 0x03, 0x55, 0x04, 0x02 }},
{(A)"CommonName",                               { 0x03, 0x55, 0x04, 0x03 }},
{(A)"Surname",                                  { 0x03, 0x55, 0x04, 0x04 }},
{(A)"SerialNumber",                             { 0x03, 0x55, 0x04, 0x05 }},
{(A)"CountryName",                              { 0x03, 0x55, 0x04, 0x06 }},
{(A)"LocalityName",                             { 0x03, 0x55, 0x04, 0x07 }},
{(A)"StateOrProvinceName",              { 0x03, 0x55, 0x04, 0x08 }},
{(A)"StreetAddress",                    { 0x03, 0x55, 0x04, 0x09 }},
{(A)"OrganizationName",                 { 0x03, 0x55, 0x04, 0x0a }},
{(A)"OrganizationUnitName",             { 0x03, 0x55, 0x04, 0x0b }},
{(A)"Title",                                    { 0x03, 0x55, 0x04, 0x0c }},
{(A)"Description",                              { 0x03, 0x55, 0x04, 0x0d }},
{(A)"SearchGuide",                              { 0x03, 0x55, 0x04, 0x0e }},
{(A)"BusinessCategory",                 { 0x03, 0x55, 0x04, 0x0f }},
{(A)"PostalAddress",                    { 0x03, 0x55, 0x04, 0x10 }},
{(A)"PostalCode",                               { 0x03, 0x55, 0x04, 0x11 }},
{(A)"PostOfficeBox",                    { 0x03, 0x55, 0x04, 0x12 }},
{(A)"PhysicalDeliveryOffice",   { 0x03, 0x55, 0x04, 0x13 }},
{(A)"TelephoneNUmber",                  { 0x03, 0x55, 0x04, 0x14 }},
{(A)"TelexNumber",                              { 0x03, 0x55, 0x04, 0x15 }},
{(A)"TeletexTerminalId",                { 0x03, 0x55, 0x04, 0x16 }},
{(A)"FaxTelephoneNumber",               { 0x03, 0x55, 0x04, 0x17 }},
{(A)"X121Address",                              { 0x03, 0x55, 0x04, 0x18 }},
{(A)"IsdnAddress",                              { 0x03, 0x55, 0x04, 0x19 }},
{(A)"RegisteredAddress",                { 0x03, 0x55, 0x04, 0x1a }},
{(A)"DestinationIndicator",             { 0x03, 0x55, 0x04, 0x1b }},
{(A)"PreferDeliveryMethod",             { 0x03, 0x55, 0x04, 0x1c }},
{(A)"PresentationAddress",              { 0x03, 0x55, 0x04, 0x1d }},
{(A)"SupportedApplContext",             { 0x03, 0x55, 0x04, 0x1e }},
{(A)"Member",                                   { 0x03, 0x55, 0x04, 0x1f }},
{(A)"Owner",                                    { 0x03, 0x55, 0x04, 0x20 }},
{(A)"RoleOccupant",                             { 0x03, 0x55, 0x04, 0x21 }},
{(A)"SeeAlso",                                  { 0x03, 0x55, 0x04, 0x22 }},
{(A)"Password",                                 { 0x03, 0x55, 0x04, 0x23 }},
{(A)"UserCertificate",                  { 0x03, 0x55, 0x04, 0x24 }},
{(A)"CaCertificate",                    { 0x03, 0x55, 0x04, 0x25 }},
{(A)"AuthorityRevList",                 { 0x03, 0x55, 0x04, 0x26 }},
{(A)"CertificateRevList",               { 0x03, 0x55, 0x04, 0x27 }},
{(A)"CrossCertificatePair",             { 0x03, 0x55, 0x04, 0x28 }},

/*
 *      X.500 Standardized Object Classes
 */
{(A)"Top",                                      { 0x03, 0x55, 0x06, 0x00 }},
{(A)"Alias",                            { 0x03, 0x55, 0x06, 0x01 }},
{(A)"Country",                          { 0x03, 0x55, 0x06, 0x02 }},
{(A)"Locality",                         { 0x03, 0x55, 0x06, 0x03 }},
{(A)"Organization",                     { 0x03, 0x55, 0x06, 0x04 }},
{(A)"OrganizationUnit",         { 0x03, 0x55, 0x06, 0x05 }},
{(A)"Person",                           { 0x03, 0x55, 0x06, 0x06 }},
{(A)"OrganizationPersion",      { 0x03, 0x55, 0x06, 0x07 }},
{(A)"OrganizationRole",         { 0x03, 0x55, 0x06, 0x08 }},
{(A)"Group",                            { 0x03, 0x55, 0x06, 0x09 }},
{(A)"ResidentialPerson",        { 0x03, 0x55, 0x06, 0x0A }},
{(A)"ApplicationProcess",       { 0x03, 0x55, 0x06, 0x0B }},
{(A)"ApplicationEntity",        { 0x03, 0x55, 0x06, 0x0C }},
{(A)"Dsa",                                      { 0x03, 0x55, 0x06, 0x0D }},
{(A)"Device",                           { 0x03, 0x55, 0x06, 0x0E }},
{(A)"StrongAuthenticUser",      { 0x03, 0x55, 0x06, 0x0F }},
{(A)"CaAuthority",                      { 0x03, 0x55, 0x06, 0x10 }},

/*
 *      ACSE Protocol Object Identifiers
 */
{(A)"Asn1BER-TS",               { 0x02, 0x51, 0x01 }},
{(A)"Private-TS",               { 0x06, 0x2b, 0xce, 0x06, 0x01, 0x04, 0x06 }},
{(A)"ACSE-AS",                  { 0x04, 0x52, 0x01, 0x00, 0x01 }},

/*
 *      Directory Protocol Oids
 */
{(A)"DirAccess-AC",                     { 0x03, 0x55, 0x03, 0x01 }},
{(A)"DirSystem-AC",                     { 0x03, 0x55, 0x03, 0x02 }},

{(A)"DirAccess-AS",                     { 0x03, 0x55, 0x09, 0x01 }},
{(A)"DirSystem-AS",                     { 0x03, 0x55, 0x09, 0x02 }},

/*
 *      and add your private object identifiers here ...
 */
};

#define OIDNB (sizeof (OidTab) / sizeof (oidelmT))      /* total oid nb */

/*
 *      asn.1 tag class definition
 */

static A class[] = {    /* tag class */
        (A)"UNIV ",
        (A)"APPL ",
        (A)"CTXs ",
        (A)"PRIV "
};

/*
 *      universal tag definition
 */

static A uclass[] = {   /* universal tag assignment */
(A)"EndOfContents",                     /* 0  */
(A)"Boolean",                           /* 1  */
(A)"Integer",                           /* 2  */
(A)"BitString",                         /* 3  */
(A)"OctetString",                       /* 4  */
(A)"Null",                              /* 5  */
(A)"Oid",                               /* 6  */
(A)"ObjDescriptor",                     /* 7  */
(A)"External",                          /* 8  */
(A)"Real",                              /* 9  */
(A)"Enumerated",                        /* 10 */
(A)"Reserved",                          /* 11 */
(A)"Reserved",                          /* 12 */
(A)"Reserved",                          /* 13 */
(A)"Reserved",                          /* 14 */
(A)"Reserved",                          /* 15 */
(A)"Sequence",                          /* 16 */
(A)"Set",                               /* 17 */
(A)"NumericString",                     /* 18 */
(A)"PrintableString",                   /* 19 */
(A)"T.61String",                        /* 20 */
(A)"VideotexString",                    /* 21 */
(A)"IA5String",                         /* 22 */
(A)"UTCTime",                           /* 23 */
(A)"GeneralizedTime",                   /* 24 */
(A)"GraphicString",                     /* 25 */
(A)"VisibleString",                     /* 26 */
(A)"GeneralString",                     /* 27 */
(A)"Reserved",                          /* 28 */
(A)"Reserved",                          /* 29 */
(A)"Reserved",                          /* 30 */
(A)"Reserved"                           /* 31 */
};

static A MHSaclass[] = {        /* mhs application tag assignment */
(A)"Bind Request",                      /* 0 */
(A)"Bind Response",
(A)"Unbind Request",
(A)"Search Request",
(A)"Search ResEntry",
(A)"Search ResDone",                    /* 5 */
(A)"Modify Request",
(A)"Modify Response",
(A)"Add Request",
(A)"Add Response",                      /* 9 */
(A)"Del Request",
(A)"Del Response",
(A)"ModDN Request",
(A)"ModDN Response",
(A)"Compare Request",                   /* 14 */
(A)"Compare Response",
(A)"Abandon Request",
(A)"",                                  /* 17 */
(A)"",                                  /* 18 */
(A)"Search ResRef",                     /* 19 */
(A)"",                                  /* 20 */
(A)"",                                  /* 21 */
(A)"",                                  /* 22 */
(A)"Extended Request",
(A)"Extended Response",
(A)"",                                  /* 25 */
(A)"",                                  /* 26 */
(A)"",                                  /* 27 */
(A)"",                                  /* 28 */
(A)"",                                  /* 29 */
(A)"",                                  /* 30 */
(A)""                                   /* 31 */
};


static A DFTaclass[] = {        /* Default Application Tag Assignment */
(A)"",                          /* 0  */
(A)"",                          /* 1  */
(A)"",                          /* 2  */
(A)"",                          /* 3  */
(A)"",                          /* 4  */
(A)"",                          /* 5  */
(A)"",                          /* 6  */
(A)"",                          /* 7  */
(A)"",                          /* 8  */
(A)"",                          /* 9  */
(A)"",                          /* 10 */
(A)"",                          /* 11 */
(A)"",                          /* 12 */
(A)"",                          /* 13 */
(A)"",                          /* 14 */
(A)"",                          /* 15 */
(A)"",                          /* 16 */
(A)"",                          /* 17 */
(A)"",                          /* 18 */
(A)"",                          /* 19 */
(A)"",                          /* 20 */
(A)"",                          /* 21 */
(A)"",                          /* 22 */
(A)"",                          /* 23 */
(A)"",                          /* 24 */
(A)"",                          /* 25 */
(A)"",                          /* 26 */
(A)"",                          /* 27 */
(A)"",                          /* 28 */
(A)"",                          /* 29 */
(A)"",                          /* 30 */
(A)""                           /* 31 */
};

typedef struct asndefS {
char *name;
int type;
int application;
int nbson;
struct {
        char *sonname;
        struct asndefS *sondef;
        long tag;
        } son[50];
} asndefT, * asndefTp;

#define SEQUENCE                0x0002
#define SEQUENCEOF              0x0003
#define SET                             0x0004
#define PRINTABLE               0x0008
#define ENUM                    0x0010
#define BITSTRING               0x0020
#define EXTENSION               0x0040
#define CONTENTTYPE             0x0080
#define CONTENT                 0x0100
#define CHOICE                  0x0200

static asndefT RTSpasswd = { "RTS Authentification data", SET,  -1, 2, {
                        {"MTA Name", 0, 0},
                        {"MTA Password", 0, 1}}};
static asndefT RTSudata = { "RTS User data", SET,  -1, 1, {
                        {0, &RTSpasswd, 1}}};

static asndefT baseObject = {"Base Object", PRINTABLE, -1, 0, {0}};

static asndefT scope = {"Scope", ENUM, -1, 3, {
                        {"BaseObject", 0, 0},
                        {"singleLevel", 0, 1},
                        {"wholeSubtree", 0, 2}}};

static asndefT derefAliases = {"DerefAliases", ENUM, -1, 4, {
                        {"neverDerefAliases", 0, 0},
                        {"derefInSearching", 0, 1},
                        {"derefFindingBaseObj", 0, 2},
                        {"derefAlways", 0, 3}}};

static asndefT filter;
static asndefT and = {"And", SET, -1, 1, {
                        {0, &filter, -1}}};
static asndefT or = {"Or", SET, -1, 1, {
                        {0, &filter, -1}}};
static asndefT not = {"Not", SET, -1, 1, {
                        {0, &filter, -1}}};
static asndefT equalityMatch = {"Equality Match", SEQUENCE, -1, 2, {
                        {"Attr Descr", 0, -1},
                        {"Value", 0, -1}}};
static asndefT substrings = {"Substring", SEQUENCE, -1, 2, {
                        {"Type", 0, -1},
                        {"Substrings (initial)", 0, 0},
                        {"Substrings (any)", 0, 1},
                        {"Substring (final)", 0, 2}}};
static asndefT greaterOrEqual = {"Greater Or Equal", SEQUENCE, -1, 2, {
                        {"Attr Descr", 0, -1},
                        {"Value", 0, -1}}};
static asndefT lessOrEqual = {"Less Or Equal", SEQUENCE, -1, 2, {
                        {"Attr Descr", 0, -1},
                        {"Value", 0, -1}}};
static asndefT approxMatch = {"Approx Match", SEQUENCE, -1, 2, {
                        {"Attr Descr", 0, -1},
                        {"Value", 0, -1}}};
static asndefT extensibleMatch = {"Extensible Match", SEQUENCE, -1, 4, {
                        {"MatchingRule", 0, 1},
                        {"Type", 0, 2},
                        {"MatchValue", 0, 3},
                        {"dnAttributes", 0, 4}}};

static asndefT filter = {"Filter", CHOICE, -1, 10, {
                        {0, &and, 0},
                        {0, &or, 1},
                        {0, &not, 2},
                        {0, &equalityMatch, 3},
                        {0, &substrings, 4},
                        {0, &greaterOrEqual, 5},
                        {0, &lessOrEqual, 6},
                        {"Filter: Present", 0, 7},
                        {0, &approxMatch, 8},
                        {0, &extensibleMatch, 9}}};

static asndefT attributedescription = \
                        {"Attribute Description", PRINTABLE, -1, 0, {0}};
static asndefT attributes = {"Attribute List", SEQUENCEOF, -1, 1, {
                        {0, &attributedescription, -1}}};

static asndefT searchRequest = {"Operation", SEQUENCE, 3, 8, {
                        {0, &baseObject, -1},
                        {0, &scope, -1},
                        {0, &derefAliases, -1},
                        {"SizeLimit", 0, -1},
                        {"TimeLimit", 0, -1},
                        {"TypesOnly", 0, -1},
                        {0, &filter, -1},
                        {0, &attributes, -1}}};

static asndefT objectName = {"Object Name", PRINTABLE, -1, 0, {0}};

static asndefT ldapEntry = {"Entry", PRINTABLE, -1, 0, {0}};
static asndefT relativeLdapEntry = \
                        {"Relative LDAP Entry", PRINTABLE, -1, 0, {0}};
static asndefT newSuperior = {"New Superior", PRINTABLE, -1, 0, {0}};

static asndefT vals = {"Vals", SET, -1, 1, {
                        {"Value", 0, -1}}};

static asndefT attribute = {"Attribute", SEQUENCE, -1, 2, {
                        {"Type", 0, -1},
                        {0, &vals, -1}}};

static asndefT partialAttributes = {"Partial Attributes", SEQUENCEOF, -1, 1, {
                        {0, &attribute, -1}}};

static asndefT searchResEntry = {"Operation", SEQUENCE, 4, 2, {
                        {0, &objectName, -1},
                        {0, &partialAttributes, -1}}};

static asndefT authChoice = {"Authentication Choice", CHOICE, -1, 2, {
                        {"Authentication: Simple", 0, 0},
                        {"Authentication: SASL", 0, 3}}};

static asndefT bindRequest = {"Operation", SEQUENCE, 0, 3, {
                        {"Version", 0, -1},
                        {0, &objectName, -1},
                        {0, &authChoice, -1}}};

static asndefT resultCode = {"Result Code", ENUM, -1, 39, {
                        {"Success", 0, 0},
                        {"Operation Error", 0, 1},
                        {"Protocol Error", 0, 2},
                        {"Time Limit Exceeded", 0, 3},
                        {"Size Limit Exceeded", 0, 4},
                        {"Compare False", 0, 5},
                        {"Compare True", 0, 6},
                        {"Auth Method Not supported", 0, 7},
                        {"Strong Auth Required", 0, 8},
                        {"Referral", 0, 10},
                        {"Admin Limit Exceeded", 0, 11},
                        {"Unavailable Critical Extension", 0, 12},
                        {"Confidentiality required", 0, 13},
                        {"SASL Bind In Progress", 0, 14},
                        {"No Such Attribute", 0, 16},
                        {"Undefined Attribute Type", 0, 17},
                        {"Inappropriate Matching", 0, 18},
                        {"Constraint violation", 0, 19},
                        {"Attribute or Value Exists", 0, 20},
                        {"Invalid Attribute Syntax", 0, 21},
                        {"No Such Object", 0, 32},
                        {"Alias Problem", 0, 33},
                        {"Invalid DN Syntax", 0, 34},
                        {"Alias Dereferencing Problem", 0, 36},
                        {"Inappropriate Authentication", 0, 48},
                        {"Invalid Credentials", 0, 49},
                        {"Insufficient Access Rights", 0, 50},
                        {"Busy", 0, 51},
                        {"Unavailable", 0, 52},
                        {"Unwilling To Perform", 0, 53},
                        {"Loop Detect", 0, 54},
                        {"Naming Violation", 0, 64},
                        {"ObjectClass violation", 0, 65},
                        {"Not Allowed On Non Leaf", 0, 66},
                        {"Not Allowed On RDN", 0, 67},
                        {"Entry Already Exists", 0, 68},
                        {"ObjectClass Mods Prohibited", 0, 69},
                        {"Affects Multiple DSAs", 0, 71},
                        {"Other", 0, 80}}};


static asndefT referral = {"Referral", SEQUENCEOF, -1, 1, {
                        {"LDAP URL", 0, -1}}};

static asndefT ldapResult = {"LDAP Result", SEQUENCE, -1, 4, {
                        {0, &resultCode, -1},
                        {"Matched DN", 0, -1},
                        {"Error Message", 0, -1},
                        {0, &referral, 3}}};

static asndefT bindResponse = {"Operation", SEQUENCE, 1, 5, {
                        {0, &resultCode, -1},
                        {"Matched DN", 0, -1},
                        {"Error Message", 0, -1},
                        {0, &referral, 3},
                        {"SASL Credentials", 0, 7}}};

static asndefT unbindRequest = {"Operation", SEQUENCE, 2, 0, {0}};

static asndefT searchResDone = {"Operation", SEQUENCE, 5, 4, {
                        {0, &resultCode, -1},
                        {"Matched DN", 0, -1},
                        {"Error Message", 0, -1},
                        {0, &referral, 3}}};

static asndefT seqModOperation = {"Operation", ENUM, -1, 4, {
                        {"Add", 0, 0},
                        {"Delete", 0, 1},
                        {"Replace", 0, 2}}};

static asndefT seqModModification = {"Modification", SEQUENCE, -1, 1, {
                        {0, &attribute, -1}}};

static asndefT seqModification = {"", SEQUENCE, -1, 2, {
                    {0, &seqModOperation, -1},
                        {0, &seqModModification, -1}}};

static asndefT modification = {"Modification", SEQUENCEOF, -1, 1, {
                        {0, &seqModification, -1}}};

static asndefT modifyRequest = {"Operation", SEQUENCE, 6, 2, {
                        {0, &objectName, -1},
                        {0, &modification, -1}}};

static asndefT modifyResponse = {"Operation", SEQUENCE, 7, 4, {
                        {0, &resultCode, -1},
                        {"Matched DN", 0, -1},
                        {"Error Message", 0, -1},
                        {0, &referral, 3}}};

static asndefT addAttributes = {"Attributes", SEQUENCEOF, -1, 1, {
                        {0, &attribute, -1}}};

static asndefT addRequest = {"Operation", SEQUENCE, 8, 2, {
                        {0, &ldapEntry, -1},
                        {0, &addAttributes, -1}}};

static asndefT addResponse = {"Operation", SEQUENCE, 9, 4, {
                        {0, &resultCode, -1},
                        {"Matched DN", 0, -1},
                        {"Error Message", 0, -1},
                        {0, &referral, 3}}};

static asndefT delRequest = {"Operation", SEQUENCE, 10, 1, {
                        {0, &ldapEntry, -1}}};

static asndefT delResponse = {"Operation", SEQUENCE, 11, 4, {
                        {0, &resultCode, -1},
                        {"Matched DN", 0, -1},
                        {"Error Message", 0, -1},
                        {0, &referral, 3}}};

static asndefT modifyDNRequest = {"Operation", SEQUENCE, 12, 4, {
                        {0, &ldapEntry, -1},
                        {0, &relativeLdapEntry, -1},
                        {"Delete Old RDN", 0, -1},
                        {0, &newSuperior, 0}}};

static asndefT modifyDNResponse = {"Operation", SEQUENCE, 13, 4, {
                        {0, &resultCode, -1},
                        {"Matched DN", 0, -1},
                        {"Error Message", 0, -1},
                        {0, &referral, 3}}};

static asndefT ava = {"Ava", SEQUENCE, -1, 2, {
                        {"Attr Descr", 0, -1},
                        {"Value", 0, -1}}};

static asndefT compareRequest = {"Operation", SEQUENCE, 14, 2, {
                        {0, &ldapEntry, -1},
                        {0, &ava, 0}}};

static asndefT compareResponse = {"Operation", SEQUENCE, 15, 4, {
                        {0, &resultCode, -1},
                        {"Matched DN", 0, -1},
                        {"Error Message", 0, -1},
                        {0, &referral, 3}}};

static asndefT abandonRequest = {"Operation", SEQUENCE, 16, 1, {
                    {"Message ID", 0, -1}}};

static asndefT searchResRef =  {"Operation", SEQUENCEOF, 19, 1, {
                        {"LDAP URL", 0, -1}}};

static asndefT extendedRequest = {"Operation", SEQUENCE, 14, 2, {
                        {"Request Name", 0, 0},
                        {"Request Value", 0, 1}}};

static asndefT extendedResponse = {"Operation", SEQUENCE, 24, 6, {
                        {0, &resultCode, -1},
                        {"Matched DN", 0, -1},
                        {"Error Message", 0, -1},
                        {0, &referral, 3},
                        {"Response Name", 0, 10},
                        {"Response", 0, 11}}};

static asndefT protocolOp = {"Protocol Op", CHOICE, -1, 20, {
                        {0, &bindRequest, 0},
                        {0, &bindResponse, 1},
                        {0, &unbindRequest, 2},
                        {0, &searchRequest, 3},
                        {0, &searchResEntry, 4},
                        {0, &searchResDone, 5},
                        {0, &modifyRequest, 6},
                        {0, &modifyResponse, 7},
                        {0, &addRequest, 8},
                        {0, &addResponse, 9},
                        {0, &delRequest, 10},
                        {0, &delResponse, 11},
                        {0, &modifyDNRequest, 12},
                        {0, &modifyDNResponse, 13},
                        {0, &compareRequest, 14},
                        {0, &compareResponse, 15},
                        {0, &abandonRequest, 16},
                        {0, &searchResRef, 19},
                        {0, &extendedRequest, 23},
                        {0, &extendedResponse, 24}}};

static asndefT control = {"Control", SEQUENCE, -1, 3, {
                        {"LDAP OID", 0, -1},
                        {"Criticality", 0, -1},
                        {"Control value", 0, -1}}};

static asndefT controls = {"Controls List", SEQUENCEOF, -1, 1, {
        {0, &control, -1}}};

static asndefT LDAPMessage = { "LDAPMessage", SEQUENCE, -1, 3, {
                        {"Message ID", 0, -1},
                        {0, &protocolOp, -1},
                        {0, &controls, 0}}};

static asndefT MPDU = { "MPDU", SET,  -1, 1,
                        {{0, &LDAPMessage, 0}}};

static int mytype[] = {
0,                      /* EndOfContents        */
0,                      /* Boolean                      */
0,                      /* Integer                      */
BITSTRING,      /* BitString            */
0,                      /* OctetString          */
0,                      /* Null                         */
0,                      /* Oid                          */
0,                      /* ObjDescriptor        */
0,                      /* External                     */
0,                      /* Real                         */
ENUM,           /* Enumerated           */
0,                      /* Reserved                     */
0,                      /* Reserved                     */
0,                      /* Reserved                     */
0,                      /* Reserved                     */
0,                      /* Reserved                     */
SEQUENCE,       /* Sequence                     */
SET,            /* Set                          */
0,                      /* NumericString        */
0,                      /* PrintableString      */
0,                      /* T.61String           */
0,                      /* VideotexString       */
0,                      /* IA5String            */
0,                      /* UTCTime                      */
0,                      /* GeneralizedTime      */
0,                      /* GraphicString        */
0,                      /* VisibleString        */
0,                      /* GeneralString        */
0,                      /* Reserved                     */
0,                      /* Reserved                     */
0,                      /* Reserved                     */
0,                      /* Reserved                     */
};

/*
 * Find object identifier in known oid table
 * A    oid - oid hexa string
 * int  olg - oid length
 */
static int
oidmap(A oid, int olg)
{
        register int ix, goon;
        register A oidptr, tabptr, tabend;

/* returns (oid table size) if not found */

        for (ix = 0; ix < OIDNB; ix++) {
                oidptr = oid; tabptr = (&(OidTab[ix].oidcode[0]));
                if (olg == INT(*tabptr++)) {
                        tabend = tabptr + olg;
                        goon = 1;
                        while (goon != 0 && tabptr < tabend) {
                                if (*tabptr++ != *oidptr++)
                                        goon = 0;
                        }
                        if (goon != 0)
                                return (ix);
                }
        }
        return (OIDNB);
}

/*
 * Read an hexacode and convert it into ASCII
 */
static int getnext(int ctxnum)
{
        static X c[3]; /* c[0-3] will contain ascii values on exit */
        hex = 0;
        if (gi_osibuf[ctxnum] == osilen)
                return (-1);
        hex = osibuff[gi_osibuf[ctxnum]++];
        (void) sprintf((char *)c, "%02x", (hex&0x00FF));
        return (0);
}

/*
 * Skip everything that is not an LDAPMessage
 */
static char *skipjunk(len, pdu)
int len;
char *pdu;
{
        int tag;
        char *buf = pdu;
        int offset = 0;
        while (len > 0) {
                /* size minumum for a sequence + integer = 5 */
                /* LDAPMessage::= SEQUENCE  */
                if ((len > 5) && (buf[0] == 0x30)) {
                        tag = buf[1]&0x00ff;
                        if (tag < 0x80) {
                                /* length is one one octet */
                                offset = 1;
                        } else {
                                /* length is multiple octet.  */
                                offset = 1+ tag&0x007f;
                        }
                        /* Make sure we don't read past the end */
                        /* of the buffer */
                        if (len - (1+offset) > 0) {
                                /* skip after the length */
                                tag = buf[1+offset]&0x00ff;
                                if (tag == 0x02) { /* INTEGER */
                                        /* looks like a valid PDU */
                                        return (buf);
                                }
                        }
                }
                len --;
                buf++;
        }
        return (buf);
}


#define GETNEXT(a) (void)getnext(a);

/*
 * main routine: decode a TLV; to be called recursively
 *
 * pdulen: current pdu's length
 */
static int
decpdu(int pdulen, asndefTp ASNDESC, int ctxnum)
{
        X               scrlin[99];     /* screen line */
        X               oidstr[80];     /* oid hexa string */
        int             slen;   /* screen line length */
        int             stlv;   /* sub-tlv length */
        int             oix;    /* oid table index */
        int             effnb;  /* effectively traced octet nb */
        int             i = 0, j = 0;
        int             ai = -2;
        asndefTp SASNDESC = 0;
        asndefTp TMPDESC = 0;
        asndefTp GR_TMPDESC = 0;
        int tmpai = 0;
        int gr_tmpai = 0;
        int dontprint = 0;
        int already = 0;
        static int rlen = 0;    /* tlv's real length */

        ++level[ctxnum];        /* level indicator */
        effnb = 0;

        /*
         * Decode the current TLV segment
         */
        while (pdulen > 1) {

                if (getnext(ctxnum)) {
                        break;
                }
                if (strlen(scrbuffer)) asnshw2("%s  ", "LDAP:");
                /* screen printing according to level indicator */
                for (i = 1; i < level[ctxnum]; ++i) asnshw1("   ");

                /* get tag */
                otyp[ctxnum] = INT(hex); /* single octet type only */
                --pdulen;
                ++effnb;

                /* get length */
                GETNEXT(ctxnum);
                olen[ctxnum] = INT(hex);        /* tlv length */
                --pdulen;
                ++effnb;

                /* Continuing decoding of current TLV... */
                /*
                 * Snoop's lower layers do not allow us
                 * to know the true length for
                 * datastream protocols like LDAP.
                 */

                /*
                 * if length is less than 128, we
                 * already have the real TLV length.
                 */
                if (olen[ctxnum] < 128) {       /* short length form */
                        rlen = olen[ctxnum];
                } else {                /* long and any form length */
                /* else we do more getnext()'s */
                        for (rlen = 0, olen[ctxnum] &= 0x0F;
                        (olen[ctxnum]) && (pdulen > 0);
                        --olen[ctxnum], --pdulen, ++effnb) {
                                GETNEXT(ctxnum);
                                rlen = (rlen << 8) | INT(hex);
                        }
                        if (!rlen) {
                                pdulen = 0x7fffffff;
                        }
                }

                /*
                 * print the tag class and number
                 */
                i = otyp[ctxnum]&0x1F;
                switch (otyp[ctxnum] >> 6) {    /* class */
                case 0: /* universal */
                        if (ASNDESC && i != 0) {
                                int dobreak = 0;
                                switch (ASNDESC->type) {
                                case CONTENT:
                                        SASNDESC = ASNDESC;
                                        break;
                                case SET:
                                        for (ai = 0;
                                                ai < ASNDESC->nbson && i < 32 &&
                                                ASNDESC->son[ai].sondef &&
                                        /*
                                         * For this test SEQUENCE & SEQUENCE OF
                                         * are same, so suppress the last bit
                                         */
                                                (ASNDESC->son[ai].sondef
                                                        ->type&0xFE)
                                                != mytype[i]; ++ai);
                                        if (ai < ASNDESC->nbson) {
                                                SASNDESC =
                                                    ASNDESC->son[ai].sondef;
                                        if (ASNDESC->son[ai].sonname != NULL) {

                                        if (ASNDESC->son[ai].sondef != NULL &&
                                            ASNDESC->son[ai].sondef->name !=
                                            NULL) {
                                                asnshw2("%s     ", "LDAP:");
                                                asnshw4(" %c[%s %s]",
                                                ((otyp[ctxnum]&0x20)?'*':' '),
                                                ASNDESC->son[ai].sonname,
                                                ASNDESC->son[ai].sondef->name);
                                        } else {
                                                asnshw2("%s     ", "");
                                                asnshw3(" %c[%s]",
                                                ((otyp[ctxnum]&0x20)?'*':' '),
                                                ASNDESC->son[ai].sonname);
                                        } /* end if */

                                        dobreak = 1;

                                        } else if (ASNDESC->son[ai].sondef !=
                                            NULL &&
                                            ASNDESC->son[ai].sondef->name !=
                                            NULL) {
                                                asnshw2("%s     ", "LDAP:");
                                                asnshw3(" %c[%s]",
                                                ((otyp[ctxnum]&0x20)?'*':' '),
                                                ASNDESC->son[ai].sondef->name);
                                                dobreak = 1;
                                        } /* end if */
                                        } /* end if */
                                                break;
                                case CHOICE:
                                        if (GR_TMPDESC) {
                                                ASNDESC = TMPDESC;
                                                TMPDESC = GR_TMPDESC;
                                                GR_TMPDESC = 0;
                                        } else if (TMPDESC) {
                                                ASNDESC = TMPDESC;
                                                TMPDESC = 0;
                                        }
                                        if (gr_tmpai) {
                                                ai = tmpai;
                                                tmpai = gr_tmpai;
                                                gr_tmpai = 0;
                                        } else if (tmpai) {
                                                ai = tmpai;
                                                tmpai = 0;
                                        }
                                        break;

                                case SEQUENCE:
                                        if (ai == -2) {
                                                ai = 0;
                                        } else {
                                                do {
                                                        ai++;
                                                } while \
                        (ai < ASNDESC->nbson && i < 32 && mytype[i] && \
                        ASNDESC->son[ai].sondef &&
                                        /*
                                         * For this test SEQUENCE & SEQUENCE OF
                                         * are the same, so suppress last bit
                                         */
                        (ASNDESC->son[ai].sondef->type&0xFE) != mytype[i]);
                                        } /* end if */
                                        if (ai < ASNDESC->nbson) {
                                                SASNDESC = \
                                                ASNDESC->son[ai].sondef;
                                                if (ASNDESC->son[ai].sonname) {
                                                        if \
                        (ASNDESC->son[ai].sondef &&
                        ASNDESC->son[ai].sondef->name) {
                                                                asnshw4 \
                        (" %c[%s %s]", ((otyp[ctxnum]&0x20)?'*':' '),
                        ASNDESC->son[ai].sonname,
                        ASNDESC->son[ai].sondef->name);
                                                        } else {
                                                                asnshw3 \
                        (" %c[%s]", ((otyp[ctxnum]&0x20)?'*':' '),
                        ASNDESC->son[ai].sonname);
                                                        } /* end if */
                                                        dobreak = 1;
                                                } else if \
                        (ASNDESC->son[ai].sondef &&
                        ASNDESC->son[ai].sondef->name) {
                                                                asnshw3 \
                        (" %c[%s]", ((otyp[ctxnum]&0x20)?'*':' '),
                        ASNDESC->son[ai].sondef->name);
                                                        dobreak = 1;
                                                } /* end if */
                                        } /* end if */
                                        break;
                                case SEQUENCEOF:
                                        ai = 0;
                                        SASNDESC = ASNDESC->son[ai].sondef;
                                        if (ASNDESC->son[ai].sonname) {
                                                if (ASNDESC->son[ai].sondef && \
                        ASNDESC->son[ai].sondef->name) {
                                                                asnshw4 \
                        (" %c[%s %s]", ((otyp[ctxnum]&0x20)?'*':' '),
                        ASNDESC->son[ai].sonname,
                        ASNDESC->son[ai].sondef->name);
                                                } else {
                                                        asnshw3 \
                        (" %c[%s]", ((otyp[ctxnum]&0x20)?'*':' '),
                        ASNDESC->son[ai].sonname);
                                                } /* end if */
                                                dobreak = 1;
                                        } else if \
                        (ASNDESC->son[ai].sondef &&
                        ASNDESC->son[ai].sondef->name) {
                                                        asnshw3 \
                        (" %c[%s]", ((otyp[ctxnum]&0x20)?'*':' '),
                        ASNDESC->son[ai].sondef->name);
                                                dobreak = 1;
                                        } /* end if */
                                } /* end switch */
                                if (dobreak) {
                                        break;
                                } /* end if */
                        } /* end if */
                        if (uclass[i]) {
                                asnshw3 \
                        (" %c[%s]", ((otyp[ctxnum]&0x20)?'*':' '), uclass[i]);
                        } else {
                                asnshw4 \
                        (" %c[%s%d]", ((otyp[ctxnum]&0x20)?'*':' '),
                        class[0], i);
                        }
                        break;
                case 1:         /* application */

                if (ASNDESC) {

                                for (ai = 0; ai < ASNDESC->nbson; ++ai) {
                                        int i2 = 0;

                                        if \
                        (ASNDESC->son[ai].sondef &&
                        ASNDESC->son[ai].sondef->type == CHOICE) {
                                                while \
                        (i2 < ASNDESC->son[ai].sondef->nbson &&
                        ASNDESC->son[ai].sondef->son[i2].sondef && \
        ASNDESC->son[ai].sondef->son[i2].sondef->application != i) {
                                                        i2++;
                                                        continue;
                                                }
                                                if \
                        (i2 == ASNDESC->son[ai].sondef->nbson) {
                                                        ai = ASNDESC->nbson;
                                                        break;
                                                }
                        if (TMPDESC) {
                                GR_TMPDESC = TMPDESC;
                                gr_tmpai = tmpai;
                        }
                                        TMPDESC = ASNDESC;
                                        ASNDESC = ASNDESC->son[ai].sondef;
                                        tmpai = ai;
                                        ai = i2;
                                        }

                                        if (ASNDESC->son[ai].sondef && \
                        ASNDESC->son[ai].sondef->application == i) {
                                                SASNDESC = \
                        ASNDESC->son[ai].sondef;
                                                if (ASNDESC->son[ai].sonname) {
                                                        if \
                        (ASNDESC->son[ai].sondef->name) {
                                                                asnshw3 \
                        (" %s %s", ASNDESC->son[ai].sonname,
                        ASNDESC->son[ai].sondef->name);
                                                        } else {
                                                                asnshw2 \
                        (" %s", ASNDESC->son[ai].sonname);
                                                        } /* end if */
                                                } else if \
                        (ASNDESC->son[ai].sondef->name) {
                                                        asnshw2 \
                        (" %s", ASNDESC->son[ai].sondef->name);
                                                } /* end if */
                                                break;
                                        } /* end if */
                                } /* end for */
                                if (ai >= ASNDESC->nbson) {
                                        ai = -1;        /* not found */
                                } /* end if */
                        } /* end if */
                        if (PTRaclass[i]) {
                                asnshw5 \
                        (" %c[%s%d: %s]", ((otyp[ctxnum]&0x20)?'*':' '),
                        class[1], i, PTRaclass[i]);
                                (void) strcpy(operation, (char *)PTRaclass[i]);
                        } else {
                                asnshw4 \
                        (" %c[%s%d]", ((otyp[ctxnum]&0x20)?'*':' '), \
                        class[1], i);
                        }
                        break;

                case 2:         /* context-specific */

                        if (TMPDESC) {
                                ASNDESC = TMPDESC;
                                TMPDESC = GR_TMPDESC;
                                already = 1;
                        }
                        if (ASNDESC) {

                                for (ai = 0; ai < ASNDESC->nbson; ++ai) {
                                        if \
                        (!already && ASNDESC->son[ai].sondef &&
                        ASNDESC->son[ai].sondef->type == CHOICE) {
                                                int i2 = 0;
                                                while \
                        (i2 < ASNDESC->son[ai].sondef->nbson &&
                        ASNDESC->son[ai].sondef->son[i2].tag != i) {
                                                        i2++;
                                                        continue;
                                                }
                                                if (i2 == \
                        ASNDESC->son[ai].sondef->nbson) {
                                                        ai = ASNDESC->nbson;
                                                        break;
                                                }
                                                if (TMPDESC) {
                                                        GR_TMPDESC = TMPDESC;
                                                        gr_tmpai = tmpai;
                                                }
                                                TMPDESC = ASNDESC;
                                                ASNDESC = \
                        ASNDESC->son[ai].sondef;
                                                tmpai = ai;
                                                ai = i2;
                                        }

                                        if \
                        (ASNDESC->son[ai].tag == i) {
                                                SASNDESC = \
                        ASNDESC->son[ai].sondef;
                                                if (ASNDESC->son[ai].sonname) {
                                                        if \
                        (ASNDESC->son[ai].sondef &&
                        ASNDESC->son[ai].sondef->name) {
                                                                asnshw3 \
                        (" %s %s", ASNDESC->son[ai].sonname,
                        ASNDESC->son[ai].sondef->name);
                                                        } else {
                                                                asnshw2 \
                        (" %s", ASNDESC->son[ai].sonname);
                                                        } /* end if */
                                                } else if \
                        (ASNDESC->son[ai].sondef &&
                        ASNDESC->son[ai].sondef->name) {
                                                        asnshw2 \
                        (" %s", ASNDESC->son[ai].sondef->name);
                                                } /* end if */
                                                break;
                                        } /* end if */
                                } /* end for */
                                if (ai >= ASNDESC->nbson) {
                                        ai = -1;        /* not found */
                                } /* end if */
                        } /* end if */
                        asnshw3 \
                        (" %c[%d]", ((otyp[ctxnum]&0x20)?'*':' '), i);
                        break;

                case 3:         /* private */
                        asnshw4 \
                        (" %c[%s%d]", ((otyp[ctxnum]&0x20)?'*':' '), \
                        class[3], i);
                } /* esac: tag */

                /*
                 * print the length - as a debug tool only.
                 */
                /* asnshw2(" Length=%d ",rlen); */
                asnshw1("\n");
                if (rlen > pdulen) {
                        asnshw1("*** Decode length error,");
                        asnshw2(" PDU length = %d ***\n", pdulen);
                        rlen = pdulen;
                }

                /*
                 * recursive interpretation of the value if constructor
                 */
                if (otyp[ctxnum]&0x20) {                /* constructor */

                        stlv = decpdu((rlen?rlen:pdulen), \
                        ASNDESC && ai != -1 ?(ai == -2 ? ASNDESC:
                        ASNDESC->son[ai].sondef):0, ctxnum);
                        /* recursive decoding */
                        pdulen -= stlv;
                        effnb += stlv;
                } else if (otyp[ctxnum] == 0x06) {
                        /*
                         * interpretation of the object identifier
                         */
                        for (j = 0; (rlen) && (pdulen > 0); \
                        --rlen, --pdulen, ++effnb) {
                                GETNEXT(ctxnum);
                                oidstr[j++] = hex;
                        }

                        /* interpret the object identifier */
                        oidstr[j++] = '\0';
                        oix = oidmap(oidstr, j-1);
                        asnshw1("\n");
                        if (oix >= 0 && oix < OIDNB) {  /* recognized obj id */
                                asnshw2("%s\n", OidTab[oix].oidname);
                        } else {
                                asnshw1("Unknown Oid\n");
                        }
                } else {
                        /*
                         * interpretation of other primitive tags
                         */
                        if (!otyp[ctxnum] && !rlen) {
                        /* end of contents: any form length */
                                pdulen = 0;
                        } else {
                                X   hexstr[5];
                                int k = 0;
                                int klen = rlen;
                                if (SASNDESC && SASNDESC->type == CONTENT && \
                        SASNDESC->nbson && SASNDESC->son[0].sondef) {
                                        (void)
                        decpdu(rlen, SASNDESC->son[0].sondef, ctxnum);
                                } else {
                                        if (rlen < 200) {
                                        for (j = 0, slen = 0; \
                        (rlen) && (pdulen > 0);
                                        --rlen, --pdulen, ++effnb) {
                                                if (!slen) {
                                                    (void) \
                        strcpy((char *)scrlin, "LDAP:  "); j += 7;
                                                    for \
                        (i = 0; i < level[ctxnum]; ++i) {
                                                        scrlin[j++] = ' ';
                                                        scrlin[j++] = ' ';
                                                        scrlin[j++] = ' ';
                                                        scrlin[j++] = ' ';
                                                    }
                                                }

                                                GETNEXT(ctxnum);
                                                if (k < 5) {
                                                        hexstr[k++] = hex;
                                                } /* end if */
                                                if (!isprint(hex)) {
                                                        hex = '_';
                                                        dontprint = 1;
                                                }
                                                scrlin[j++] = hex;
                                                if ((slen += 2) >= \
                        (72 - (level[ctxnum] * 3))) {
                                                        slen = 0;
                                                        scrlin[j] = 0;
                                                        if (!dontprint) {
                                                                asnshw2 \
                        ("%s\n", scrlin);
                                                        }
                                                        j = 0;
                                                }
                                        } /* rof: primitive values */
                                        if (slen) {
                                                scrlin[j] = 0;
                                                if (!dontprint) {
                                                        asnshw2("%s\n", scrlin);
                                                }
                                        }
                                        dontprint = 0;
                                } else {
                                        asnshw2("%s  ", "LDAP:");
                                    for (i = 0; i < level[ctxnum]; ++i) {
                                                asnshw1("   ");
                                                scrlin[j++] = ' ';
                                                scrlin[j++] = ' ';
                                                scrlin[j++] = ' ';
                                        }

                                    for (j = 0; (rlen) && (pdulen > 0); \
                        --rlen, --pdulen, ++effnb) {
                                                GETNEXT(ctxnum);
                                                if (k < 5) {
                                                        hexstr[k++] = hex;
                                                }
                                        }
                                    (void) strcpy \
                        ((char *)scrlin, \
                        "*** NOT PRINTED - Too long value ***");
                                                asnshw2("%s\n", scrlin);
                                        }

                                        if \
                        (SASNDESC && SASNDESC->type == BITSTRING &&\
                        klen <= 5) {
                                                unsigned long bitstr = 0;
                                                for (i = 1; i < 5; ++i) {
                                                        bitstr = \
                        ((bitstr) << 8) + ((i < klen)?hexstr[i]:0);
                                                } /* end for */
                                                for \
                        (i = 0; i < SASNDESC->nbson; ++i) {
                                                        if ((bitstr & \
                        ((unsigned long)SASNDESC->son[i].sondef)) ==
                        ((unsigned long)SASNDESC->son[i].tag)) {
                                                                if \
                        (SASNDESC->son[i].sonname) {
                                                                int k;
                                                                asnshw2 \
                        ("%s  ", "LDAP:");
                                                                for \
                        (k = 0; k < level[ctxnum]; ++k) {
                                                                asnshw1("   ");
                                                                }
                                                                asnshw2 \
                        ("%s", SASNDESC->son[i].sonname);
                                                                } /* end if */
                                                        } /* end if */
                                                } /* end for */
                                        } /* end if */
                                        if (SASNDESC && \
                        (SASNDESC->type == ENUM ||
                        SASNDESC->type == CONTENTTYPE) && klen <= 5) {
                                                unsigned long value = 0;
                                                for (i = 0; i < klen; ++i) {
                                                        value = \
                        ((value) << 8) + hexstr[i];
                                                } /* end for */
                                                for \
                        (i = 0; i < SASNDESC->nbson; ++i) {
                                                        if \
                        (value == ((unsigned long)SASNDESC->son[i].tag)) {
                                                                if \
                        (SASNDESC->son[i].sonname) {
                                                                        int k;
                                                                asnshw2 \
                        ("%s  ", "LDAP:");
                                                                        for \
                        (k = 0; k < level[ctxnum]; ++k) {
                                                                asnshw1("   ");
                                                                        }
                                                                asnshw2 \
                        ("%s\n", SASNDESC->son[i].sonname);
                                                                        (void) \
                        strcpy(resultcode, SASNDESC->son[i].sonname);
                                                                } /* end if */
                                                                break;
                                                        } /* end if */
                                                } /* end for */
                                        } /* end if */

                                } /* end if */
                        } /* fi: constructor/obj-id/primitive */
                } /* fi: tag analysis */
        } /* elihw: len>1 */
        --level[ctxnum];
        return (effnb);
}


/* init_ldap initializes various buffers and variables */
/* it is called one-time (in snoop_filter.c) only. */

void
init_ldap()
{
        int i;

        for (i = 0; i < MAX_CTX; i++) {
                gi_osibuf[i] = 0;
                level[i] = 0;
        }
}
static void
ldapdump(char *data, int datalen)
{
        char *p;
        ushort_t *p16 = (ushort_t *)data;
        char *p8 = data;
        int i, left, len;
        int chunk = 16;  /* 16 bytes per line */

        asnshw1("LDAP: Skipping until next full LDAPMessage\n");

        for (p = data; p < data + datalen; p += chunk) {
                asnshw2("LDAP:\t%4d: ", p - data);
                left = (data + datalen) - p;
                len = MIN(chunk, left);
                for (i = 0; i < (len / 2); i++)
                        asnshw2("%04x ", ntohs(*p16++) & 0xffff);
                if (len % 2) {
                        asnshw2("%02x   ", *((unsigned char *)p16));
                }
                for (i = 0; i < (chunk - left) / 2; i++)
                        asnshw1("     ");

                asnshw1("   ");
                for (i = 0; i < len; i++, p8++)
                        asnshw2("%c", isprint(*p8) ? *p8 : '.');
                asnshw1("\n");
        }

        asnshw1("LDAP:\n");
}

/* decode_ldap is the entry point for the main decoding function */
/* decpdu(). decode_ldap() is only called by interpret_ldap. */

void
decode_ldap(char *buf, int len)
{
        asndefTp ASNDESC = 0;
        char *newbuf;
        int skipped = 0;

        PTRaclass = MHSaclass;
        ASNDESC = &MPDU;


        newbuf =  skipjunk(len, buf);
        if (newbuf > buf) {
                skipped = newbuf-buf;
                ldapdump(buf, newbuf-buf);
        }
        buf = newbuf;
        len = len-skipped;
        osibuff = buf;  /* Undecoded buf is passed by interpret_ldap */
        osilen = len;   /* length of tcp data is also passed */

        (void) decpdu(len, ASNDESC, 0);
        gi_osibuf[0] = 0;
}