snoop_ldap.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* 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 2000-2002 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#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 **
**----------------------------------------------**
*/
static oidmap(oid, olg)
A oid; /* oid hexa string */
int olg; /* oid length */
{
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++)) {
for (tabend = tabptr + olg, goon = 1;
(goon) && (tabptr < tabend); ) {
if (*tabptr++ != *oidptr++) goon = 0;
}
if (goon)
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);
}
/*
**----------------------------------------------------------**
** main routine: decode a TLV; to be called recursively **
**----------------------------------------------------------**
*/
#define GETNEXT(a) (void)getnext(a);
static int decpdu(pdulen, ASNDESC, ctxnum)
int pdulen; /* current pdu's length */
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) {
if (ASNDESC-> \
son[ai].sondef && ASNDESC->son[ai].sondef->name)
{
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 &&
ASNDESC->son[ai].sondef->name) {
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;
}