/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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, ¬, 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, j; 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; }