diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 11:11:40 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 11:11:40 +0000 |
commit | 7731832751ab9f3c6ddeb66f186d3d7fa1934a6d (patch) | |
tree | e91015872543a59be2aad26c2fea02e41b57005d /contrib/slapd-modules | |
parent | Initial commit. (diff) | |
download | openldap-upstream/2.4.57+dfsg.tar.xz openldap-upstream/2.4.57+dfsg.zip |
Adding upstream version 2.4.57+dfsg.upstream/2.4.57+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'contrib/slapd-modules')
116 files changed, 35715 insertions, 0 deletions
diff --git a/contrib/slapd-modules/README b/contrib/slapd-modules/README new file mode 100644 index 0000000..d9ff34d --- /dev/null +++ b/contrib/slapd-modules/README @@ -0,0 +1,61 @@ +Copyright 2008-2021 The OpenLDAP Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted only as authorized by the OpenLDAP +Public License. + +This directory contains native-API slapd modules (overlays etc): + +acl (plugins) + Plugins implementing access rules. Currently one plugin + which implements access control based on posixGroup membership. + +addpartial (overlay) + Treat Add requests as Modify requests if the entry exists. + +allop (overlay) + Return operational attributes for root DSE even when not + requested, since some clients expect this. + +autogroup (overlay) + Automated updates of group memberships. + +cloak (overlay) + Hide specific attributes unless explicitely requested + +comp_match (plugin) + Component Matching rules (RFC 3687). + +denyop (overlay) + Deny selected operations, returning unwillingToPerform. + +dsaschema (plugin) + Permit loading DSA-specific schema, including operational attrs. + +lastbind (overlay) + Record the last successful authentication on an entry. + +lastmod (overlay) + Track the time of the last write operation to a database. + +nops (overlay) + Remove null operations, e.g. changing a value to same as before. + +nssov (listener overlay) + Handle NSS lookup requests through a local Unix Domain socket. + +passwd (plugins) + Support additional password mechanisms. + Currently Kerberos, Netscape MTA-MD5 and RADIUS. + +proxyOld (plugin) + Proxy Authorization compatibility with obsolete internet-draft. + +smbk5pwd (overlay) + Make the PasswordModify Extended Operation update Kerberos + keys and Samba password hashes as well as userPassword. + +trace (overlay) + Trace overlay invocation. + +$OpenLDAP$ diff --git a/contrib/slapd-modules/acl/Makefile b/contrib/slapd-modules/acl/Makefile new file mode 100644 index 0000000..40a8e9e --- /dev/null +++ b/contrib/slapd-modules/acl/Makefile @@ -0,0 +1,50 @@ +# $OpenLDAP$ + +LDAP_SRC = ../../.. +LDAP_BUILD = $(LDAP_SRC) +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +CC = gcc +OPT = -g -O2 -Wall +DEFS = +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) + +PROGRAMS = posixgroup.la gssacl.la +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +posixgroup.la: posixgroup.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +gssacl.la: gssacl.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + diff --git a/contrib/slapd-modules/acl/README.gssacl b/contrib/slapd-modules/acl/README.gssacl new file mode 100644 index 0000000..368b178 --- /dev/null +++ b/contrib/slapd-modules/acl/README.gssacl @@ -0,0 +1,32 @@ +This directory contains native slapd plugins that implement access rules. + +gssacl.c contains a simple example that implements access control +based on GSS naming extensions attributes. + +To use the acl-gssacl plugin, add: + +moduleload acl-gssacl.so + +to your slapd configuration file. +It is configured using + +access to <what> + by dynacl/gss/<attribute>.[.{base,regex,expand}]=<valpat> {<level>|<priv(s)>} + +The default is "exact"; in case of "expand", "<valpat>" results from +the expansion of submatches in the "<what>" portion. "<level>|<priv(s)>" +describe the level of privilege this rule can assume. + +Use Makefile to compile this plugin or use a command line similar to: + +gcc -shared -I../../../include -I../../../servers/slapd -Wall -g \ + -o acl-gssacl.so gssacl.c + + +--- +Copyright 2011 PADL Software Pty Ltd. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted only as authorized by the OpenLDAP +Public License. + diff --git a/contrib/slapd-modules/acl/README.posixgroup b/contrib/slapd-modules/acl/README.posixgroup new file mode 100644 index 0000000..30f4e38 --- /dev/null +++ b/contrib/slapd-modules/acl/README.posixgroup @@ -0,0 +1,35 @@ +This directory contains native slapd plugins that implement access rules. + +posixgroup.c contains a simple example that implements access control +based on posixGroup membership, loosely inspired by ITS#3849. It should +be made clear that this access control policy does not reflect any +standard track model of handling access control, and should be +essentially viewed as an illustration of the use of the dynamic +extension of access control within slapd. + +To use the acl-posixgroup plugin, add: + +moduleload acl-posixgroup.so + +to your slapd configuration file; it requires "nis.schema" to be loaded. +It is configured using + +access to <what> + by dynacl/posixGroup[.{exact,expand}]=<dnpat> {<level>|<priv(s)} + +The default is "exact"; in case of "expand", "<dnpat>" results from +the expansion of submatches in the "<what>" portion. "<level>|<priv(s)>" +describe the level of privilege this rule can assume. + +Use Makefile to compile this plugin or use a command line similar to: + +gcc -shared -I../../../include -I../../../servers/slapd -Wall -g \ + -o acl-posixgroup.so posixgroup.c + +--- +Copyright 2005-2021 The OpenLDAP Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted only as authorized by the OpenLDAP +Public License. + diff --git a/contrib/slapd-modules/acl/gssacl.c b/contrib/slapd-modules/acl/gssacl.c new file mode 100644 index 0000000..2fba789 --- /dev/null +++ b/contrib/slapd-modules/acl/gssacl.c @@ -0,0 +1,316 @@ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2011 PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ + +#include <portable.h> + +#include <ac/string.h> +#include <slap.h> +#include <lutil.h> + +#include <sasl/sasl.h> +#include <gssapi/gssapi.h> +#include <gssapi/gssapi_ext.h> + +#define ACL_BUF_SIZE 1024 + +typedef struct gssattr_t { + slap_style_t gssattr_style; + struct berval gssattr_name; /* asserted name */ + struct berval gssattr_value; /* asserted value */ +} gssattr_t; + +static int gssattr_dynacl_destroy( void *priv ); + +static int +regex_matches( + struct berval *pat, /* pattern to expand and match against */ + char *str, /* string to match against pattern */ + struct berval *dn_matches, /* buffer with $N expansion variables from DN */ + struct berval *val_matches, /* buffer with $N expansion variables from val */ + AclRegexMatches *matches /* offsets in buffer for $N expansion variables */ +); + +static int +gssattr_dynacl_parse( + const char *fname, + int lineno, + const char *opts, + slap_style_t style, + const char *pattern, + void **privp ) +{ + gssattr_t *gssattr; + + gssattr = (gssattr_t *)ch_calloc( 1, sizeof( gssattr_t ) ); + + if ( opts == NULL || opts[0] == '\0' ) { + fprintf( stderr, "%s line %d: GSS ACL: no attribute specified.\n", + fname, lineno ); + goto cleanup; + } + + if ( pattern == NULL || pattern[0] == '\0' ) { + fprintf( stderr, "%s line %d: GSS ACL: no attribute value specified.\n", + fname, lineno ); + goto cleanup; + } + + gssattr->gssattr_style = style; + + switch ( gssattr->gssattr_style ) { + case ACL_STYLE_BASE: + case ACL_STYLE_REGEX: + case ACL_STYLE_EXPAND: + break; + default: + fprintf( stderr, "%s line %d: GSS ACL: unsupported style \"%s\".\n", + fname, lineno, style_strings[style] ); + goto cleanup; + break; + } + + ber_str2bv( opts, 0, 1, &gssattr->gssattr_name ); + ber_str2bv( pattern, 0, 1, &gssattr->gssattr_value ); + + *privp = (void *)gssattr; + return 0; + +cleanup: + (void)gssattr_dynacl_destroy( (void *)gssattr ); + + return 1; +} + +static int +gssattr_dynacl_unparse( + void *priv, + struct berval *bv ) +{ + gssattr_t *gssattr = (gssattr_t *)priv; + char *ptr; + + bv->bv_len = STRLENOF( " dynacl/gss/.expand=" ) + + gssattr->gssattr_name.bv_len + + gssattr->gssattr_value.bv_len; + bv->bv_val = ch_malloc( bv->bv_len + 1 ); + + ptr = lutil_strcopy( bv->bv_val, " dynacl/gss/" ); + ptr = lutil_strncopy( ptr, gssattr->gssattr_name.bv_val, + gssattr->gssattr_name.bv_len ); + switch ( gssattr->gssattr_style ) { + case ACL_STYLE_BASE: + ptr = lutil_strcopy( ptr, ".exact=" ); + break; + case ACL_STYLE_REGEX: + ptr = lutil_strcopy( ptr, ".regex=" ); + break; + case ACL_STYLE_EXPAND: + ptr = lutil_strcopy( ptr, ".expand=" ); + break; + default: + assert( 0 ); + break; + } + + ptr = lutil_strncopy( ptr, gssattr->gssattr_value.bv_val, + gssattr->gssattr_value.bv_len ); + + ptr[ 0 ] = '\0'; + + bv->bv_len = ptr - bv->bv_val; + + return 0; +} + +static int +gssattr_dynacl_mask( + void *priv, + Operation *op, + Entry *target, + AttributeDescription *desc, + struct berval *val, + int nmatch, + regmatch_t *matches, + slap_access_t *grant, + slap_access_t *deny ) +{ + gssattr_t *gssattr = (gssattr_t *)priv; + sasl_conn_t *sasl_ctx = op->o_conn->c_sasl_authctx; + gss_name_t gss_name = GSS_C_NO_NAME; + OM_uint32 major, minor; + int more = -1; + int authenticated, complete; + gss_buffer_desc attr = GSS_C_EMPTY_BUFFER; + int granted = 0; + + ACL_INVALIDATE( *deny ); + + if ( sasl_ctx == NULL || + sasl_getprop( sasl_ctx, SASL_GSS_PEER_NAME, (const void **)&gss_name) != 0 || + gss_name == GSS_C_NO_NAME ) { + return 0; + } + + attr.length = gssattr->gssattr_name.bv_len; + attr.value = gssattr->gssattr_name.bv_val; + + while ( more != 0 ) { + AclRegexMatches amatches = { 0 }; + gss_buffer_desc gss_value = GSS_C_EMPTY_BUFFER; + gss_buffer_desc gss_display_value = GSS_C_EMPTY_BUFFER; + struct berval bv_value; + + major = gss_get_name_attribute( &minor, gss_name, &attr, + &authenticated, &complete, + &gss_value, &gss_display_value, &more ); + if ( GSS_ERROR( major ) ) { + break; + } else if ( authenticated == 0 ) { + gss_release_buffer( &minor, &gss_value ); + gss_release_buffer( &minor, &gss_display_value ); + continue; + } + + bv_value.bv_len = gss_value.length; + bv_value.bv_val = (char *)gss_value.value; + + if ( !ber_bvccmp( &gssattr->gssattr_value, '*' ) ) { + if ( gssattr->gssattr_style != ACL_STYLE_BASE ) { + amatches.dn_count = nmatch; + AC_MEMCPY( amatches.dn_data, matches, sizeof( amatches.dn_data ) ); + } + + switch ( gssattr->gssattr_style ) { + case ACL_STYLE_REGEX: + /* XXX assumes value NUL terminated */ + granted = regex_matches( &gssattr->gssattr_value, bv_value.bv_val, + &target->e_nname, val, &amatches ); + break; + case ACL_STYLE_EXPAND: { + struct berval bv; + char buf[ACL_BUF_SIZE]; + + bv.bv_len = sizeof( buf ) - 1; + bv.bv_val = buf; + + granted = ( acl_string_expand( &bv, &gssattr->gssattr_value, + &target->e_nname, val, + &amatches ) == 0 ) && + ( ber_bvstrcmp( &bv, &bv_value) == 0 ); + break; + } + case ACL_STYLE_BASE: + granted = ( ber_bvstrcmp( &gssattr->gssattr_value, &bv_value ) == 0 ); + break; + default: + assert(0); + break; + } + } else { + granted = 1; + } + + gss_release_buffer( &minor, &gss_value ); + gss_release_buffer( &minor, &gss_display_value ); + + if ( granted ) { + break; + } + } + + if ( granted ) { + ACL_LVL_ASSIGN_WRITE( *grant ); + } + + return 0; +} + +static int +gssattr_dynacl_destroy( + void *priv ) +{ + gssattr_t *gssattr = (gssattr_t *)priv; + + if ( gssattr != NULL ) { + if ( !BER_BVISNULL( &gssattr->gssattr_name ) ) { + ber_memfree( gssattr->gssattr_name.bv_val ); + } + if ( !BER_BVISNULL( &gssattr->gssattr_value ) ) { + ber_memfree( gssattr->gssattr_value.bv_val ); + } + ch_free( gssattr ); + } + + return 0; +} + +static struct slap_dynacl_t gssattr_dynacl = { + "gss", + gssattr_dynacl_parse, + gssattr_dynacl_unparse, + gssattr_dynacl_mask, + gssattr_dynacl_destroy +}; + +int +init_module( int argc, char *argv[] ) +{ + return slap_dynacl_register( &gssattr_dynacl ); +} + + +static int +regex_matches( + struct berval *pat, /* pattern to expand and match against */ + char *str, /* string to match against pattern */ + struct berval *dn_matches, /* buffer with $N expansion variables from DN */ + struct berval *val_matches, /* buffer with $N expansion variables from val */ + AclRegexMatches *matches /* offsets in buffer for $N expansion variables */ +) +{ + regex_t re; + char newbuf[ACL_BUF_SIZE]; + struct berval bv; + int rc; + + bv.bv_len = sizeof( newbuf ) - 1; + bv.bv_val = newbuf; + + if (str == NULL) { + str = ""; + }; + + acl_string_expand( &bv, pat, dn_matches, val_matches, matches ); + rc = regcomp( &re, newbuf, REG_EXTENDED|REG_ICASE ); + if ( rc ) { + char error[ACL_BUF_SIZE]; + regerror( rc, &re, error, sizeof( error ) ); + + Debug( LDAP_DEBUG_TRACE, + "compile( \"%s\", \"%s\") failed %s\n", + pat->bv_val, str, error ); + return( 0 ); + } + + rc = regexec( &re, str, 0, NULL, 0 ); + regfree( &re ); + + Debug( LDAP_DEBUG_TRACE, + "=> regex_matches: string: %s\n", str, 0, 0 ); + Debug( LDAP_DEBUG_TRACE, + "=> regex_matches: rc: %d %s\n", + rc, !rc ? "matches" : "no matches", 0 ); + return( !rc ); +} + diff --git a/contrib/slapd-modules/acl/posixgroup.c b/contrib/slapd-modules/acl/posixgroup.c new file mode 100644 index 0000000..bc1a008 --- /dev/null +++ b/contrib/slapd-modules/acl/posixgroup.c @@ -0,0 +1,329 @@ +/* posixgroup.c */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 1998-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ + +#include <portable.h> + +#include <ac/string.h> +#include <slap.h> +#include <lutil.h> + +/* Need dynacl... */ + +#ifdef SLAP_DYNACL + +typedef struct pg_t { + slap_style_t pg_style; + struct berval pg_pat; +} pg_t; + +static ObjectClass *pg_posixGroup; +static AttributeDescription *pg_memberUid; +static ObjectClass *pg_posixAccount; +static AttributeDescription *pg_uidNumber; + +static int pg_dynacl_destroy( void *priv ); + +static int +pg_dynacl_parse( + const char *fname, + int lineno, + const char *opts, + slap_style_t style, + const char *pattern, + void **privp ) +{ + pg_t *pg; + int rc; + const char *text = NULL; + struct berval pat; + + ber_str2bv( pattern, 0, 0, &pat ); + + pg = ch_calloc( 1, sizeof( pg_t ) ); + + pg->pg_style = style; + + switch ( pg->pg_style ) { + case ACL_STYLE_BASE: + rc = dnNormalize( 0, NULL, NULL, &pat, &pg->pg_pat, NULL ); + if ( rc != LDAP_SUCCESS ) { + fprintf( stderr, "%s line %d: posixGroup ACL: " + "unable to normalize DN \"%s\".\n", + fname, lineno, pattern ); + goto cleanup; + } + break; + + case ACL_STYLE_EXPAND: + ber_dupbv( &pg->pg_pat, &pat ); + break; + + default: + fprintf( stderr, "%s line %d: posixGroup ACL: " + "unsupported style \"%s\".\n", + fname, lineno, style_strings[ pg->pg_style ] ); + goto cleanup; + } + + /* TODO: use opts to allow the use of different + * group objects and member attributes */ + if ( pg_posixGroup == NULL ) { + pg_posixGroup = oc_find( "posixGroup" ); + if ( pg_posixGroup == NULL ) { + fprintf( stderr, "%s line %d: posixGroup ACL: " + "unable to lookup \"posixGroup\" " + "objectClass.\n", + fname, lineno ); + goto cleanup; + } + + pg_posixAccount = oc_find( "posixAccount" ); + if ( pg_posixGroup == NULL ) { + fprintf( stderr, "%s line %d: posixGroup ACL: " + "unable to lookup \"posixAccount\" " + "objectClass.\n", + fname, lineno ); + goto cleanup; + } + + rc = slap_str2ad( "memberUid", &pg_memberUid, &text ); + if ( rc != LDAP_SUCCESS ) { + fprintf( stderr, "%s line %d: posixGroup ACL: " + "unable to lookup \"memberUid\" " + "attributeDescription (%d: %s).\n", + fname, lineno, rc, text ); + goto cleanup; + } + + rc = slap_str2ad( "uidNumber", &pg_uidNumber, &text ); + if ( rc != LDAP_SUCCESS ) { + fprintf( stderr, "%s line %d: posixGroup ACL: " + "unable to lookup \"uidNumber\" " + "attributeDescription (%d: %s).\n", + fname, lineno, rc, text ); + goto cleanup; + } + } + + *privp = (void *)pg; + return 0; + +cleanup: + (void)pg_dynacl_destroy( (void *)pg ); + + return 1; +} + +static int +pg_dynacl_unparse( + void *priv, + struct berval *bv ) +{ + pg_t *pg = (pg_t *)priv; + char *ptr; + + bv->bv_len = STRLENOF( " dynacl/posixGroup.expand=" ) + pg->pg_pat.bv_len; + bv->bv_val = ch_malloc( bv->bv_len + 1 ); + + ptr = lutil_strcopy( bv->bv_val, " dynacl/posixGroup" ); + + switch ( pg->pg_style ) { + case ACL_STYLE_BASE: + ptr = lutil_strcopy( ptr, ".exact=" ); + break; + + case ACL_STYLE_EXPAND: + ptr = lutil_strcopy( ptr, ".expand=" ); + break; + + default: + assert( 0 ); + } + + ptr = lutil_strncopy( ptr, pg->pg_pat.bv_val, pg->pg_pat.bv_len ); + ptr[ 0 ] = '\0'; + + bv->bv_len = ptr - bv->bv_val; + + return 0; +} + +static int +pg_dynacl_mask( + void *priv, + Operation *op, + Entry *target, + AttributeDescription *desc, + struct berval *val, + int nmatch, + regmatch_t *matches, + slap_access_t *grant, + slap_access_t *deny ) +{ + pg_t *pg = (pg_t *)priv; + Entry *group = NULL, + *user = NULL; + int rc; + Backend *be = op->o_bd, + *group_be = NULL, + *user_be = NULL; + struct berval group_ndn; + + ACL_INVALIDATE( *deny ); + + /* get user */ + if ( target && dn_match( &target->e_nname, &op->o_ndn ) ) { + user = target; + rc = LDAP_SUCCESS; + + } else { + user_be = op->o_bd = select_backend( &op->o_ndn, 0 ); + if ( op->o_bd == NULL ) { + op->o_bd = be; + return 0; + } + rc = be_entry_get_rw( op, &op->o_ndn, pg_posixAccount, pg_uidNumber, 0, &user ); + } + + if ( rc != LDAP_SUCCESS || user == NULL ) { + op->o_bd = be; + return 0; + } + + /* get target */ + if ( pg->pg_style == ACL_STYLE_EXPAND ) { + char buf[ 1024 ]; + struct berval bv; + AclRegexMatches amatches = { 0 }; + + amatches.dn_count = nmatch; + AC_MEMCPY( amatches.dn_data, matches, sizeof( amatches.dn_data ) ); + + bv.bv_len = sizeof( buf ) - 1; + bv.bv_val = buf; + + if ( acl_string_expand( &bv, &pg->pg_pat, + &target->e_nname, + NULL, &amatches ) ) + { + goto cleanup; + } + + if ( dnNormalize( 0, NULL, NULL, &bv, &group_ndn, + op->o_tmpmemctx ) != LDAP_SUCCESS ) + { + /* did not expand to a valid dn */ + goto cleanup; + } + + } else { + group_ndn = pg->pg_pat; + } + + if ( target && dn_match( &target->e_nname, &group_ndn ) ) { + group = target; + rc = LDAP_SUCCESS; + + } else { + group_be = op->o_bd = select_backend( &group_ndn, 0 ); + if ( op->o_bd == NULL ) { + goto cleanup; + } + rc = be_entry_get_rw( op, &group_ndn, pg_posixGroup, pg_memberUid, 0, &group ); + } + + if ( group_ndn.bv_val != pg->pg_pat.bv_val ) { + op->o_tmpfree( group_ndn.bv_val, op->o_tmpmemctx ); + } + + if ( rc == LDAP_SUCCESS && group != NULL ) { + Attribute *a_uid, + *a_member; + + a_uid = attr_find( user->e_attrs, pg_uidNumber ); + if ( !a_uid || !BER_BVISNULL( &a_uid->a_nvals[ 1 ] ) ) { + rc = LDAP_NO_SUCH_ATTRIBUTE; + + } else { + a_member = attr_find( group->e_attrs, pg_memberUid ); + if ( !a_member ) { + rc = LDAP_NO_SUCH_ATTRIBUTE; + + } else { + rc = value_find_ex( pg_memberUid, + SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | + SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, + a_member->a_nvals, &a_uid->a_nvals[ 0 ], + op->o_tmpmemctx ); + } + } + + } else { + rc = LDAP_NO_SUCH_OBJECT; + } + + + if ( rc == LDAP_SUCCESS ) { + ACL_LVL_ASSIGN_WRITE( *grant ); + } + +cleanup:; + if ( group != NULL && group != target ) { + op->o_bd = group_be; + be_entry_release_r( op, group ); + op->o_bd = be; + } + + if ( user != NULL && user != target ) { + op->o_bd = user_be; + be_entry_release_r( op, user ); + op->o_bd = be; + } + + return 0; +} + +static int +pg_dynacl_destroy( + void *priv ) +{ + pg_t *pg = (pg_t *)priv; + + if ( pg != NULL ) { + if ( !BER_BVISNULL( &pg->pg_pat ) ) { + ber_memfree( pg->pg_pat.bv_val ); + } + ch_free( pg ); + } + + return 0; +} + +static struct slap_dynacl_t pg_dynacl = { + "posixGroup", + pg_dynacl_parse, + pg_dynacl_unparse, + pg_dynacl_mask, + pg_dynacl_destroy +}; + +int +init_module( int argc, char *argv[] ) +{ + return slap_dynacl_register( &pg_dynacl ); +} + +#endif /* SLAP_DYNACL */ diff --git a/contrib/slapd-modules/addpartial/Makefile b/contrib/slapd-modules/addpartial/Makefile new file mode 100644 index 0000000..a999d7f --- /dev/null +++ b/contrib/slapd-modules/addpartial/Makefile @@ -0,0 +1,46 @@ +# $OpenLDAP$ + +LDAP_SRC = ../../.. +LDAP_BUILD = $(LDAP_SRC) +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +CC = gcc +OPT = -g -O2 -Wall +DEFS = +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) + +PROGRAMS = addpartial.la +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +addpartial.la: addpartial-overlay.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + diff --git a/contrib/slapd-modules/addpartial/README b/contrib/slapd-modules/addpartial/README new file mode 100644 index 0000000..e2cb2ce --- /dev/null +++ b/contrib/slapd-modules/addpartial/README @@ -0,0 +1,72 @@ +addpartial Overlay README + +DESCRIPTION + This package contains an OpenLDAP overlay called "addpartial" that + intercepts add requests, determines if the entry exists, determines what + attributes, if any, have changed, and modifies those attributes. If the + entry does not exist, the add request falls through and proceeds normally. + If the entry exists but no changes have been detected, the client receives + LDAP_SUCCESS (I suppose it is debatable what to do in this case, but this is + the most clean for my use. The LDAP_SUCCESS lets me know that the entry I + sent slapd == the entry already in my slapd DB. Perhaps this behavior + should be configurable in the future). + + When a change is found, the addpartial overlay will replace all values for + the attribute (if an attribute does not exist in the new entry but exists + in the entry in the slapd DB, a replace will be done with an empty list of + values). + + Once a modify takes place, the syncprov overlay will properly process the + change, provided that addpartial is the first overlay to run. Please see + the CAVEATS for more specifics about this. + + The addpartial overlay makes it easy to replicate full entries to a slapd + instance without worrying about the differences between entries or even if + the entry exists. Using ldapadd to add entries, the addpartial overlay can + compare about 500 records per second. The intent of the addpartial overlay + is to make it easy to replicate records from a source that is not an LDAP + instance, such as a database. The overlay is also useful in places where it + is easier to create full entries rather than comparing an entry with an + entry that must be retrieved (with ldapsearch or similar) from an existing + slapd DB to find changes. + + The addpartial overlay has been used in production since August 2004 and has + processed millions of records without incident. + +BUILDING + A Makefile is included, please set your LDAP_SRC directory properly. + +INSTALLATION + After compiling the addpartial overlay, add the following to your + slapd.conf: + + ### slapd.conf + ... + moduleload addpartial.so + ... + # after database directive... + # this overlay should be the last overlay in the config file to ensure that + # it properly intercepts the add request + overlay addpartial + ... + ### end slapd.conf + +CAVEATS + - In order to ensure that addpartial does what it needs to do, it should be + the last overlay configured so it will run before the other overlays. + This is especially important if you are using syncrepl, as the modify that + addpartial does will muck with the locking that takes place in the + syncprov overlay. + +--- +Copyright 2004-2021 The OpenLDAP Foundation. +Portions Copyright (C) Virginia Tech, David Hawes. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted only as authorized by the OpenLDAP +Public License. + +A copy of this license is available in file LICENSE in the +top-level directory of the distribution or, alternatively, at +http://www.OpenLDAP.org/license.html. diff --git a/contrib/slapd-modules/addpartial/addpartial-overlay.c b/contrib/slapd-modules/addpartial/addpartial-overlay.c new file mode 100644 index 0000000..355c8ba --- /dev/null +++ b/contrib/slapd-modules/addpartial/addpartial-overlay.c @@ -0,0 +1,349 @@ +/* addpartial-overlay.c */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2004-2021 The OpenLDAP Foundation. + * Portions Copyright (C) 2004 Virginia Tech, David Hawes. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * http://www.OpenLDAP.org/license.html. + */ +/* ACKNOLEDGEDMENTS: + * This work was initially developed by David Hawes of Virginia Tech + * for inclusion in OpenLDAP Software. + */ +/* addpartial-overlay + * + * This is an OpenLDAP overlay that intercepts ADD requests, determines if a + * change has actually taken place for that record, and then performs a modify + * request for those values that have changed (modified, added, deleted). If + * the record has not changed in any way, it is ignored. If the record does not + * exist, the record falls through to the normal add mechanism. This overlay is + * useful for replicating from sources that are not LDAPs where it is easier to + * build entire records than to determine the changes (i.e. a database). + */ + +#include "portable.h" +#include "slap.h" + +static int collect_error_msg_cb( Operation *op, SlapReply *rs); + +static slap_overinst addpartial; + +/** + * The meat of the overlay. Search for the record, determine changes, take + * action or fall through. + */ +static int addpartial_add( Operation *op, SlapReply *rs) +{ + Operation nop = *op; + Entry *toAdd = NULL; + Entry *found = NULL; + slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; + int rc; + + toAdd = op->oq_add.rs_e; + + Debug(LDAP_DEBUG_TRACE, "%s: toAdd->e_nname.bv_val: %s\n", + addpartial.on_bi.bi_type, toAdd->e_nname.bv_val,0); + + /* if the user doesn't have access, fall through to the normal ADD */ + if(!access_allowed(op, toAdd, slap_schema.si_ad_entry, + NULL, ACL_WRITE, NULL)) + { + return SLAP_CB_CONTINUE; + } + + rc = overlay_entry_get_ov(&nop, &nop.o_req_ndn, NULL, NULL, 0, &found, on); + + if(rc != LDAP_SUCCESS) + { + Debug(LDAP_DEBUG_TRACE, + "%s: no entry found, falling through to normal add\n", + addpartial.on_bi.bi_type, 0, 0); + return SLAP_CB_CONTINUE; + } + else + { + Debug(LDAP_DEBUG_TRACE, "%s: found the dn\n", addpartial.on_bi.bi_type, + 0,0); + + if(found) + { + Attribute *attr = NULL; + Attribute *at = NULL; + int ret; + Modifications *mods = NULL; + Modifications **modtail = &mods; + Modifications *mod = NULL; + + Debug(LDAP_DEBUG_TRACE, "%s: have an entry!\n", + addpartial.on_bi.bi_type,0,0); + + /* determine if the changes are in the found entry */ + for(attr = toAdd->e_attrs; attr; attr = attr->a_next) + { + if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue; + + at = attr_find(found->e_attrs, attr->a_desc); + if(!at) + { + Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s not found!\n", + addpartial.on_bi.bi_type, + attr->a_desc->ad_cname.bv_val,0); + mod = (Modifications *) ch_malloc(sizeof( + Modifications)); + mod->sml_flags = 0; + mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES; + mod->sml_op &= LDAP_MOD_OP; + mod->sml_next = NULL; + mod->sml_desc = attr->a_desc; + mod->sml_type = attr->a_desc->ad_cname; + mod->sml_values = attr->a_vals; + mod->sml_nvalues = attr->a_nvals; + mod->sml_numvals = attr->a_numvals; + *modtail = mod; + modtail = &mod->sml_next; + } + else + { + MatchingRule *mr = attr->a_desc->ad_type->sat_equality; + struct berval *bv; + const char *text; + int acount , bcount; + Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s found\n", + addpartial.on_bi.bi_type, + attr->a_desc->ad_cname.bv_val,0); + + for(bv = attr->a_vals, acount = 0; bv->bv_val != NULL; + bv++, acount++) + { + /* count num values for attr */ + } + for(bv = at->a_vals, bcount = 0; bv->bv_val != NULL; + bv++, bcount++) + { + /* count num values for attr */ + } + if(acount != bcount) + { + Debug(LDAP_DEBUG_TRACE, "%s: acount != bcount, %s\n", + addpartial.on_bi.bi_type, + "replace all",0); + mod = (Modifications *) ch_malloc(sizeof( + Modifications)); + mod->sml_flags = 0; + mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES; + mod->sml_op &= LDAP_MOD_OP; + mod->sml_next = NULL; + mod->sml_desc = attr->a_desc; + mod->sml_type = attr->a_desc->ad_cname; + mod->sml_values = attr->a_vals; + mod->sml_nvalues = attr->a_nvals; + mod->sml_numvals = attr->a_numvals; + *modtail = mod; + modtail = &mod->sml_next; + continue; + } + + for(bv = attr->a_vals; bv->bv_val != NULL; bv++) + { + struct berval *v; + ret = -1; + + for(v = at->a_vals; v->bv_val != NULL; v++) + { + int r; + if(mr && ((r = value_match(&ret, attr->a_desc, mr, + SLAP_MR_VALUE_OF_ASSERTION_SYNTAX, + bv, v, &text)) == 0)) + { + if(ret == 0) + break; + } + else + { + Debug(LDAP_DEBUG_TRACE, + "%s: \tvalue DNE, r: %d \n", + addpartial.on_bi.bi_type, + r,0); + ret = strcmp(bv->bv_val, v->bv_val); + if(ret == 0) + break; + } + } + + if(ret == 0) + { + Debug(LDAP_DEBUG_TRACE, + "%s: \tvalue %s exists, ret: %d\n", + addpartial.on_bi.bi_type, bv->bv_val, ret); + } + else + { + Debug(LDAP_DEBUG_TRACE, + "%s: \tvalue %s DNE, ret: %d\n", + addpartial.on_bi.bi_type, bv->bv_val, ret); + mod = (Modifications *) ch_malloc(sizeof( + Modifications)); + mod->sml_flags = 0; + mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES; + mod->sml_op &= LDAP_MOD_OP; + mod->sml_next = NULL; + mod->sml_desc = attr->a_desc; + mod->sml_type = attr->a_desc->ad_cname; + mod->sml_values = attr->a_vals; + mod->sml_nvalues = attr->a_nvals; + mod->sml_numvals = attr->a_numvals; + *modtail = mod; + modtail = &mod->sml_next; + break; + } + } + } + } + + /* determine if any attributes were deleted */ + for(attr = found->e_attrs; attr; attr = attr->a_next) + { + if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue; + + at = NULL; + at = attr_find(toAdd->e_attrs, attr->a_desc); + if(!at) + { + Debug(LDAP_DEBUG_TRACE, + "%s: Attribute %s not found in new entry!!!\n", + addpartial.on_bi.bi_type, + attr->a_desc->ad_cname.bv_val, 0); + mod = (Modifications *) ch_malloc(sizeof( + Modifications)); + mod->sml_flags = 0; + mod->sml_op = LDAP_MOD_REPLACE; + mod->sml_next = NULL; + mod->sml_desc = attr->a_desc; + mod->sml_type = attr->a_desc->ad_cname; + mod->sml_values = NULL; + mod->sml_nvalues = NULL; + mod->sml_numvals = 0; + *modtail = mod; + modtail = &mod->sml_next; + } + else + { + Debug(LDAP_DEBUG_TRACE, + "%s: Attribute %s found in new entry\n", + addpartial.on_bi.bi_type, + at->a_desc->ad_cname.bv_val, 0); + } + } + + overlay_entry_release_ov(&nop, found, 0, on); + + if(mods) + { + Modifications *m = NULL; + Modifications *toDel; + int modcount; + slap_callback nullcb = { NULL, collect_error_msg_cb, + NULL, NULL }; + + Debug(LDAP_DEBUG_TRACE, "%s: mods to do...\n", + addpartial.on_bi.bi_type, 0, 0); + + nop.o_tag = LDAP_REQ_MODIFY; + nop.orm_modlist = mods; + nop.orm_no_opattrs = 0; + nop.o_callback = &nullcb; + nop.o_bd->bd_info = (BackendInfo *) on->on_info; + + for(m = mods, modcount = 0; m; m = m->sml_next, + modcount++) + { + /* count number of mods */ + } + + Debug(LDAP_DEBUG_TRACE, "%s: number of mods: %d\n", + addpartial.on_bi.bi_type, modcount, 0); + + if(nop.o_bd->be_modify) + { + SlapReply nrs = { REP_RESULT }; + rc = (nop.o_bd->be_modify)(&nop, &nrs); + } + + if(rc == LDAP_SUCCESS) + { + Debug(LDAP_DEBUG_TRACE, + "%s: modify successful\n", + addpartial.on_bi.bi_type, 0, 0); + } + else + { + Debug(LDAP_DEBUG_TRACE, "%s: modify unsuccessful: %d\n", + addpartial.on_bi.bi_type, rc, 0); + rs->sr_err = rc; + if(nullcb.sc_private) + { + rs->sr_text = nullcb.sc_private; + } + } + + Debug(LDAP_DEBUG_TRACE, "%s: freeing mods...\n", + addpartial.on_bi.bi_type, 0, 0); + + for(toDel = mods; toDel; toDel = mods) + { + mods = mods->sml_next; + ch_free(toDel); + } + } + else + { + Debug(LDAP_DEBUG_TRACE, "%s: no mods to process\n", + addpartial.on_bi.bi_type, 0, 0); + } + } + else + { + Debug(LDAP_DEBUG_TRACE, "%s: no entry!\n", + addpartial.on_bi.bi_type, 0, 0); + } + + op->o_callback = NULL; + send_ldap_result( op, rs ); + ch_free((void *)rs->sr_text); + rs->sr_text = NULL; + + return LDAP_SUCCESS; + } +} + +static int collect_error_msg_cb( Operation *op, SlapReply *rs) +{ + if(rs->sr_text) + { + op->o_callback->sc_private = (void *) ch_strdup(rs->sr_text); + } + + return LDAP_SUCCESS; +} + +int addpartial_init() +{ + addpartial.on_bi.bi_type = "addpartial"; + addpartial.on_bi.bi_op_add = addpartial_add; + + return (overlay_register(&addpartial)); +} + +int init_module(int argc, char *argv[]) +{ + return addpartial_init(); +} diff --git a/contrib/slapd-modules/allop/Makefile b/contrib/slapd-modules/allop/Makefile new file mode 100644 index 0000000..1af134c --- /dev/null +++ b/contrib/slapd-modules/allop/Makefile @@ -0,0 +1,46 @@ +# $OpenLDAP$ + +LDAP_SRC = ../../.. +LDAP_BUILD = $(LDAP_SRC) +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +CC = gcc +OPT = -g -O2 -Wall +DEFS = +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) + +PROGRAMS = allop.la +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +allop.la: allop.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + diff --git a/contrib/slapd-modules/allop/README b/contrib/slapd-modules/allop/README new file mode 100644 index 0000000..6809d34 --- /dev/null +++ b/contrib/slapd-modules/allop/README @@ -0,0 +1,26 @@ +This directory contains a slapd overlay, allop. +The intended usage is as a global overlay for use with those clients +that do not make use of the RFC3673 allOp ("+") in the requested +attribute list, but expect all operational attributes to be returned. +Usage: add to slapd.conf(5) + +moduleload path/to/allop.so + +overlay allop +allop-URI <ldapURI> + +if the allop-URI is not given, the rootDSE, i.e. "ldap:///??base", +is assumed. + +Use Makefile to compile this plugin or use a command line similar to: + +gcc -shared -I../../../include -I../../../servers/slapd -Wall -g \ + -o allop.so allop.c + +--- +Copyright 2004-2021 The OpenLDAP Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted only as authorized by the OpenLDAP +Public License. + diff --git a/contrib/slapd-modules/allop/allop.c b/contrib/slapd-modules/allop/allop.c new file mode 100644 index 0000000..fc7d0f6 --- /dev/null +++ b/contrib/slapd-modules/allop/allop.c @@ -0,0 +1,261 @@ +/* allop.c - returns all operational attributes when appropriate */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2005-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by Pierangelo Masarati for inclusion in + * OpenLDAP Software. + */ + +/* + * The intended usage is as a global overlay for use with those clients + * that do not make use of the RFC3673 allOp ("+") in the requested + * attribute list, but expect all operational attributes to be returned. + * Usage: add + * + +overlay allop +allop-URI <ldapURI> + + * + * if the allop-URI is not given, the rootDSE, i.e. "ldap:///??base", + * is assumed. + */ + +#include "portable.h" + +#include <stdio.h> +#include <ac/string.h> + +#include "slap.h" +#include "config.h" + +#define SLAP_OVER_VERSION_REQUIRE(major,minor,patch) \ + ( \ + ( LDAP_VENDOR_VERSION_MAJOR == X || LDAP_VENDOR_VERSION_MAJOR >= (major) ) \ + && ( LDAP_VENDOR_VERSION_MINOR == X || LDAP_VENDOR_VERSION_MINOR >= (minor) ) \ + && ( LDAP_VENDOR_VERSION_PATCH == X || LDAP_VENDOR_VERSION_PATCH >= (patch) ) \ + ) + +#if !SLAP_OVER_VERSION_REQUIRE(2,3,0) +#error "version mismatch" +#endif + +typedef struct allop_t { + struct berval ao_ndn; + int ao_scope; +} allop_t; + +static int +allop_db_config( + BackendDB *be, + const char *fname, + int lineno, + int argc, + char **argv ) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + allop_t *ao = (allop_t *)on->on_bi.bi_private; + + if ( strcasecmp( argv[ 0 ], "allop-uri" ) == 0 ) { + LDAPURLDesc *lud; + struct berval dn, + ndn; + int scope, + rc = LDAP_SUCCESS; + + if ( argc != 2 ) { + fprintf( stderr, "%s line %d: " + "need exactly 1 arg " + "in \"allop-uri <ldapURI>\" " + "directive.\n", + fname, lineno ); + return 1; + } + + if ( ldap_url_parse( argv[ 1 ], &lud ) != LDAP_URL_SUCCESS ) { + return -1; + } + + scope = lud->lud_scope; + if ( scope == LDAP_SCOPE_DEFAULT ) { + scope = LDAP_SCOPE_BASE; + } + + if ( lud->lud_dn == NULL || lud->lud_dn[ 0 ] == '\0' ) { + if ( scope == LDAP_SCOPE_BASE ) { + BER_BVZERO( &ndn ); + + } else { + ber_str2bv( "", 0, 1, &ndn ); + } + + } else { + + ber_str2bv( lud->lud_dn, 0, 0, &dn ); + rc = dnNormalize( 0, NULL, NULL, &dn, &ndn, NULL ); + } + + ldap_free_urldesc( lud ); + if ( rc != LDAP_SUCCESS ) { + return -1; + } + + if ( BER_BVISNULL( &ndn ) ) { + /* rootDSE */ + if ( ao != NULL ) { + ch_free( ao->ao_ndn.bv_val ); + ch_free( ao ); + on->on_bi.bi_private = NULL; + } + + } else { + if ( ao == NULL ) { + ao = ch_calloc( 1, sizeof( allop_t ) ); + on->on_bi.bi_private = (void *)ao; + + } else { + ch_free( ao->ao_ndn.bv_val ); + } + + ao->ao_ndn = ndn; + ao->ao_scope = scope; + } + + } else { + return SLAP_CONF_UNKNOWN; + } + + return 0; +} + +static int +allop_db_destroy( BackendDB *be, ConfigReply *cr ) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + allop_t *ao = (allop_t *)on->on_bi.bi_private; + + if ( ao != NULL ) { + assert( !BER_BVISNULL( &ao->ao_ndn ) ); + + ch_free( ao->ao_ndn.bv_val ); + ch_free( ao ); + on->on_bi.bi_private = NULL; + } + + return 0; +} + +static int +allop_op_search( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + allop_t *ao = (allop_t *)on->on_bi.bi_private; + + slap_mask_t mask; + int i, + add_allUser = 0; + + if ( ao == NULL ) { + if ( !BER_BVISEMPTY( &op->o_req_ndn ) + || op->ors_scope != LDAP_SCOPE_BASE ) + { + return SLAP_CB_CONTINUE; + } + + } else { + if ( !dnIsSuffix( &op->o_req_ndn, &ao->ao_ndn ) ) { + return SLAP_CB_CONTINUE; + } + + switch ( ao->ao_scope ) { + case LDAP_SCOPE_BASE: + if ( op->o_req_ndn.bv_len != ao->ao_ndn.bv_len ) { + return SLAP_CB_CONTINUE; + } + break; + + case LDAP_SCOPE_ONELEVEL: + if ( op->ors_scope == LDAP_SCOPE_BASE ) { + struct berval rdn = op->o_req_ndn; + + rdn.bv_len -= ao->ao_ndn.bv_len + STRLENOF( "," ); + if ( !dnIsOneLevelRDN( &rdn ) ) { + return SLAP_CB_CONTINUE; + } + + break; + } + return SLAP_CB_CONTINUE; + + case LDAP_SCOPE_SUBTREE: + break; + } + } + + mask = slap_attr_flags( op->ors_attrs ); + if ( SLAP_OPATTRS( mask ) ) { + return SLAP_CB_CONTINUE; + } + + if ( !SLAP_USERATTRS( mask ) ) { + return SLAP_CB_CONTINUE; + } + + i = 0; + if ( op->ors_attrs == NULL ) { + add_allUser = 1; + + } else { + for ( ; !BER_BVISNULL( &op->ors_attrs[ i ].an_name ); i++ ) + ; + } + + op->ors_attrs = op->o_tmprealloc( op->ors_attrs, + sizeof( AttributeName ) * ( i + add_allUser + 2 ), + op->o_tmpmemctx ); + + if ( add_allUser ) { + op->ors_attrs[ i ] = slap_anlist_all_user_attributes[ 0 ]; + i++; + } + + op->ors_attrs[ i ] = slap_anlist_all_operational_attributes[ 0 ]; + + BER_BVZERO( &op->ors_attrs[ i + 1 ].an_name ); + + return SLAP_CB_CONTINUE; +} + +static slap_overinst allop; + +int +allop_init() +{ + allop.on_bi.bi_type = "allop"; + + allop.on_bi.bi_db_config = allop_db_config; + allop.on_bi.bi_db_destroy = allop_db_destroy; + + allop.on_bi.bi_op_search = allop_op_search; + + return overlay_register( &allop ); +} + +int +init_module( int argc, char *argv[] ) +{ + return allop_init(); +} + diff --git a/contrib/slapd-modules/allop/slapo-allop.5 b/contrib/slapd-modules/allop/slapo-allop.5 new file mode 100644 index 0000000..9bb7d83 --- /dev/null +++ b/contrib/slapd-modules/allop/slapo-allop.5 @@ -0,0 +1,63 @@ +.TH SLAPO-ALLOP 5 "RELEASEDATE" "OpenLDAP LDVERSION" +.\" Copyright 2005-2021 The OpenLDAP Foundation All Rights Reserved. +.\" Copying restrictions apply. See COPYRIGHT/LICENSE. +.\" $OpenLDAP$ +.SH NAME +slapo-allop \- All Operational Attributes overlay +.SH SYNOPSIS +ETCDIR/slapd.conf +.SH DESCRIPTION +The All Operational Attributes overlay is designed to allow slapd to +interoperate with dumb clients that expect all attributes, including +operational ones, to be returned when "*" or an empty attribute list +is requested, as opposed to RFC2251 and RFC3673. +.SH CONFIGURATION +These +.B slapd.conf +options apply to the All Operational overlay. +They should appear after the +.B overlay +directive and before any subsequent +.B database +directive. +.TP +.B allop-URI <ldapURI> +Specify the base and the scope of search operations that trigger the overlay. +By default, it is "ldap:///??base", i.e. it only applies to the rootDSE. +This requires the overlay to be instantited as global. + +.SH EXAMPLES +.LP +default behavior: only affects requests to the rootDSE +.nf + # global + overlay allop +.fi +.LP +affects all requests +.nf + # global + overlay allop + allop-URI "ldap:///??sub" +.fi +.LP +affects only requests directed to the suffix of a database +.nf + # per database + database bdb + suffix "dc=example,dc=com" + # database specific directives ... + overlay allop + allop-URI "ldap:///dc=example,dc=com??base" +.fi + +.SH FILES +.TP +ETCDIR/slapd.conf +default slapd configuration file +.SH SEE ALSO +.BR slapd.conf (5). + +.SH ACKNOWLEDGEMENTS +.P +This module was written in 2005 by Pierangelo Masarati for SysNet s.n.c. diff --git a/contrib/slapd-modules/allowed/Makefile b/contrib/slapd-modules/allowed/Makefile new file mode 100644 index 0000000..b0ba0c7 --- /dev/null +++ b/contrib/slapd-modules/allowed/Makefile @@ -0,0 +1,58 @@ +# $OpenLDAP$ +# This work is part of OpenLDAP Software <http://www.openldap.org/>. +# +# Copyright 1998-2021 The OpenLDAP Foundation. +# Copyright 2004 Howard Chu, Symas Corp. All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted only as authorized by the OpenLDAP +# Public License. +# +# A copy of this license is available in the file LICENSE in the +# top-level directory of the distribution or, alternatively, at +# <http://www.OpenLDAP.org/license.html>. + +LDAP_SRC = ../../.. +LDAP_BUILD = $(LDAP_SRC) +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +CC = gcc +OPT = -g -O2 -Wall +DEFS = -DSLAPD_OVER_ALLOWED=SLAPD_MOD_DYNAMIC +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) + +PROGRAMS = allowed.la +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +allowed.la: allowed.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + diff --git a/contrib/slapd-modules/allowed/README b/contrib/slapd-modules/allowed/README new file mode 100644 index 0000000..e3372c1 --- /dev/null +++ b/contrib/slapd-modules/allowed/README @@ -0,0 +1,73 @@ +This directory contains a slapd overlay, "allowed". + + --- o --- o --- o --- + +It adds to entries returned by search operations the value of attributes + +"allowedAttributes" + <http://msdn.microsoft.com/en-us/library/ms675217(VS.85).aspx> + +"allowedAttributesEffective" + <http://msdn.microsoft.com/en-us/library/ms675218(VS.85).aspx> + +"allowedChildClasses" + <http://msdn.microsoft.com/en-us/library/ms675219(VS.85).aspx> + +"allowedChildClassesEffective" + <http://msdn.microsoft.com/en-us/library/ms675220(VS.85).aspx> + +No other use is made of those attributes: they cannot be compared, +they cannot be used in search filters, they cannot be used in ACLs, ... + + --- o --- o --- o --- + +Usage: add to slapd.conf(5) + + +moduleload path/to/allowed.so +overlay allowed + +or add + +dn: olcOverlay={0}allowed,olcDatabase={1}bdb,cn=config +objectClass: olcOverlayConfig +olcOverlay: {0}allowed + +as a child of the database that's intended to support this feature +(replace "olcDatabase={1}bdb,cn=config" with the appropriate parent); +or use + +dn: olcOverlay={0}allowed,olcDatabase={-1}frontend,cn=config +objectClass: olcOverlayConfig +olcOverlay: {0}allowed + +if it's supposed to be global. + + --- o --- o --- o --- + +Use Makefile to compile this plugin or use a command line similar to: + +gcc -shared -I../../../include -I../../../servers/slapd -Wall -g \ + -o allowed.so allowed.c + +--- +This work is part of OpenLDAP Software <http://www.openldap.org/>. + +Copyright 2006-2021 The OpenLDAP Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted only as authorized by the OpenLDAP +Public License. + +Redistribution and use in source and binary forms, with or without +modification, are permitted only as authorized by the OpenLDAP +Public License. + +A copy of this license is available in the file LICENSE in the +top-level directory of the distribution or, alternatively, at +<http://www.OpenLDAP.org/license.html>. + +ACKNOWLEDGEMENTS: +This work was initially developed by Pierangelo Masarati for inclusion in +OpenLDAP Software. + diff --git a/contrib/slapd-modules/allowed/allowed.c b/contrib/slapd-modules/allowed/allowed.c new file mode 100644 index 0000000..e824abe --- /dev/null +++ b/contrib/slapd-modules/allowed/allowed.c @@ -0,0 +1,507 @@ +/* allowed.c - add allowed attributes based on ACL */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2006-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by Pierangelo Masarati for inclusion in + * OpenLDAP Software. + */ + +/* + * Rationale: return in allowedAttributes the attributes required/allowed + * by the objectClasses that are currently present in an object; return + * in allowedAttributesEffective the subset of the above that can be written + * by the identity that performs the search. + * + * Caveats: + * - right now, the overlay assumes that all values of the objectClass + * attribute will be returned in rs->sr_entry; this may not be true + * in general, but it usually is for back-bdb/back-hdb. To generalize, + * the search request should be analyzed, and if allowedAttributes or + * allowedAttributesEffective are requested, add objectClass to the + * requested attributes + * - it assumes that there is no difference between write-add and + * write-delete + * - it assumes that access rules do not depend on the values of the + * attributes or on the contents of the entry (attr/val, filter, ...) + * allowedAttributes and allowedAttributesEffective cannot be used + * in filters or in compare + */ + +#include "portable.h" + +/* define SLAPD_OVER_ALLOWED=2 to build as run-time loadable module */ +#ifdef SLAPD_OVER_ALLOWED + +#include "slap.h" + +/* + * NOTE: part of the schema definition reported below is taken + * from Microsoft schema definitions (OID, NAME, SYNTAX); + * + * EQUALITY is taken from + * <http://www.redhat.com/archives/fedora-directory-devel/2006-August/msg00007.html> + * (posted by Andrew Bartlett) + * + * The rest is guessed. Specifically + * + * DESC briefly describes the purpose + * + * NO-USER-MODIFICATION is added to make attributes operational + * + * USAGE is set to "dSAOperation" as per ITS#7493, + * to prevent replication, since this information + * is generated (based on ACL and identity of request) + * and not stored. + */ + +#define AA_SCHEMA_AT "1.2.840.113556.1.4" + +static AttributeDescription + *ad_allowedChildClasses, + *ad_allowedChildClassesEffective, + *ad_allowedAttributes, + *ad_allowedAttributesEffective; + +static struct { + char *at; + AttributeDescription **ad; +} aa_attrs[] = { + { "( " AA_SCHEMA_AT ".911 " + "NAME 'allowedChildClasses' " + "EQUALITY objectIdentifierMatch " + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 " + /* added by me :) */ + "DESC 'Child classes allowed for a given object' " + "NO-USER-MODIFICATION " + "USAGE dSAOperation )", &ad_allowedChildClasses }, + { "( " AA_SCHEMA_AT ".912 " + "NAME 'allowedChildClassesEffective' " + "EQUALITY objectIdentifierMatch " + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 " + /* added by me :) */ + "DESC 'Child classes allowed for a given object according to ACLs' " + "NO-USER-MODIFICATION " + "USAGE dSAOperation )", &ad_allowedChildClassesEffective }, + { "( " AA_SCHEMA_AT ".913 " + "NAME 'allowedAttributes' " + "EQUALITY objectIdentifierMatch " + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 " + /* added by me :) */ + "DESC 'Attributes allowed for a given object' " + "NO-USER-MODIFICATION " + "USAGE dSAOperation )", &ad_allowedAttributes }, + { "( " AA_SCHEMA_AT ".914 " + "NAME 'allowedAttributesEffective' " + "EQUALITY objectIdentifierMatch " + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 " + /* added by me :) */ + "DESC 'Attributes allowed for a given object according to ACLs' " + "NO-USER-MODIFICATION " + "USAGE dSAOperation )", &ad_allowedAttributesEffective }, + + /* TODO: add objectClass stuff? */ + + { NULL, NULL } +}; + +static int +aa_add_at( AttributeType *at, AttributeType ***atpp ) +{ + int i = 0; + + if ( *atpp ) { + for ( i = 0; (*atpp)[ i ] != NULL; i++ ) { + if ( (*atpp)[ i ] == at ) { + break; + } + } + + if ( (*atpp)[ i ] != NULL ) { + return 0; + } + } + + *atpp = ch_realloc( *atpp, sizeof( AttributeType * ) * ( i + 2 ) ); + (*atpp)[ i ] = at; + (*atpp)[ i + 1 ] = NULL; + + return 0; +} + +static int +aa_add_oc( ObjectClass *oc, ObjectClass ***ocpp, AttributeType ***atpp ) +{ + int i = 0; + + if ( *ocpp ) { + for ( ; (*ocpp)[ i ] != NULL; i++ ) { + if ( (*ocpp)[ i ] == oc ) { + break; + } + } + + if ( (*ocpp)[ i ] != NULL ) { + return 0; + } + } + + *ocpp = ch_realloc( *ocpp, sizeof( ObjectClass * ) * ( i + 2 ) ); + (*ocpp)[ i ] = oc; + (*ocpp)[ i + 1 ] = NULL; + + if ( oc->soc_required ) { + int i; + + for ( i = 0; oc->soc_required[ i ] != NULL; i++ ) { + aa_add_at( oc->soc_required[ i ], atpp ); + } + } + + if ( oc->soc_allowed ) { + int i; + + for ( i = 0; oc->soc_allowed[ i ] != NULL; i++ ) { + aa_add_at( oc->soc_allowed[ i ], atpp ); + } + } + + return 0; +} + +static int +aa_operational( Operation *op, SlapReply *rs ) +{ + Attribute *a, **ap; + AccessControlState acl_state = ACL_STATE_INIT; + struct berval *v; + AttributeType **atp = NULL; + ObjectClass **ocp = NULL; + +#define GOT_NONE (0x0U) +#define GOT_C (0x1U) +#define GOT_CE (0x2U) +#define GOT_A (0x4U) +#define GOT_AE (0x8U) +#define GOT_ALL (GOT_C|GOT_CE|GOT_A|GOT_AE) + int got = GOT_NONE; + + /* only add if requested */ + if ( SLAP_OPATTRS( rs->sr_attr_flags ) ) { + got = GOT_ALL; + + } else { + if ( ad_inlist( ad_allowedChildClasses, rs->sr_attrs ) ) { + got |= GOT_C; + } + + if ( ad_inlist( ad_allowedChildClassesEffective, rs->sr_attrs ) ) { + got |= GOT_CE; + } + + if ( ad_inlist( ad_allowedAttributes, rs->sr_attrs ) ) { + got |= GOT_A; + } + + if ( ad_inlist( ad_allowedAttributesEffective, rs->sr_attrs ) ) { + got |= GOT_AE; + } + } + + if ( got == GOT_NONE ) { + return SLAP_CB_CONTINUE; + } + + /* shouldn't be called without an entry; please check */ + assert( rs->sr_entry != NULL ); + + for ( ap = &rs->sr_operational_attrs; *ap != NULL; ap = &(*ap)->a_next ) + /* go to last */ ; + + /* see caveats; this is not guaranteed for all backends */ + a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_objectClass ); + if ( a == NULL ) { + goto do_oc; + } + + /* if client has no access to objectClass attribute; don't compute */ + if ( !access_allowed( op, rs->sr_entry, slap_schema.si_ad_objectClass, + NULL, ACL_READ, &acl_state ) ) + { + return SLAP_CB_CONTINUE; + } + + for ( v = a->a_nvals; !BER_BVISNULL( v ); v++ ) { + ObjectClass *oc = oc_bvfind( v ); + + assert( oc != NULL ); + + /* if client has no access to specific value, don't compute */ + if ( !access_allowed( op, rs->sr_entry, + slap_schema.si_ad_objectClass, + &oc->soc_cname, ACL_READ, &acl_state ) ) + { + continue; + } + + aa_add_oc( oc, &ocp, &atp ); + + if ( oc->soc_sups ) { + int i; + + for ( i = 0; oc->soc_sups[ i ] != NULL; i++ ) { + aa_add_oc( oc->soc_sups[ i ], &ocp, &atp ); + } + } + } + + ch_free( ocp ); + + if ( atp != NULL ) { + BerVarray bv_allowed = NULL, + bv_effective = NULL; + int i, ja = 0, je = 0; + + for ( i = 0; atp[ i ] != NULL; i++ ) + /* just count */ ; + + if ( got & GOT_A ) { + bv_allowed = ber_memalloc( sizeof( struct berval ) * ( i + 1 ) ); + } + if ( got & GOT_AE ) { + bv_effective = ber_memalloc( sizeof( struct berval ) * ( i + 1 ) ); + } + + for ( i = 0, ja = 0, je = 0; atp[ i ] != NULL; i++ ) { + if ( got & GOT_A ) { + ber_dupbv( &bv_allowed[ ja ], &atp[ i ]->sat_cname ); + ja++; + } + + if ( got & GOT_AE ) { + AttributeDescription *ad = NULL; + const char *text = NULL; + + if ( slap_bv2ad( &atp[ i ]->sat_cname, &ad, &text ) ) { + /* log? */ + continue; + } + + if ( access_allowed( op, rs->sr_entry, + ad, NULL, ACL_WRITE, NULL ) ) + { + ber_dupbv( &bv_effective[ je ], &atp[ i ]->sat_cname ); + je++; + } + } + } + + ch_free( atp ); + + if ( ( got & GOT_A ) && ja > 0 ) { + BER_BVZERO( &bv_allowed[ ja ] ); + *ap = attr_alloc( ad_allowedAttributes ); + (*ap)->a_vals = bv_allowed; + (*ap)->a_nvals = bv_allowed; + (*ap)->a_numvals = ja; + ap = &(*ap)->a_next; + } + + if ( ( got & GOT_AE ) && je > 0 ) { + BER_BVZERO( &bv_effective[ je ] ); + *ap = attr_alloc( ad_allowedAttributesEffective ); + (*ap)->a_vals = bv_effective; + (*ap)->a_nvals = bv_effective; + (*ap)->a_numvals = je; + ap = &(*ap)->a_next; + } + + *ap = NULL; + } + +do_oc:; + if ( ( got & GOT_C ) || ( got & GOT_CE ) ) { + BerVarray bv_allowed = NULL, + bv_effective = NULL; + int i, ja = 0, je = 0; + + ObjectClass *oc; + + for ( i = 0, oc_start( &oc ); oc != NULL; oc_next( &oc ) ) { + /* we can only add AUXILIARY objectClasses */ + if ( oc->soc_kind != LDAP_SCHEMA_AUXILIARY ) { + continue; + } + + i++; + } + + if ( got & GOT_C ) { + bv_allowed = ber_memalloc( sizeof( struct berval ) * ( i + 1 ) ); + } + if ( got & GOT_CE ) { + bv_effective = ber_memalloc( sizeof( struct berval ) * ( i + 1 ) ); + } + + for ( oc_start( &oc ); oc != NULL; oc_next( &oc ) ) { + /* we can only add AUXILIARY objectClasses */ + if ( oc->soc_kind != LDAP_SCHEMA_AUXILIARY ) { + continue; + } + + if ( got & GOT_C ) { + ber_dupbv( &bv_allowed[ ja ], &oc->soc_cname ); + ja++; + } + + if ( got & GOT_CE ) { + if ( !access_allowed( op, rs->sr_entry, + slap_schema.si_ad_objectClass, + &oc->soc_cname, ACL_WRITE, NULL ) ) + { + goto done_ce; + } + + if ( oc->soc_required ) { + for ( i = 0; oc->soc_required[ i ] != NULL; i++ ) { + AttributeDescription *ad = NULL; + const char *text = NULL; + + if ( slap_bv2ad( &oc->soc_required[ i ]->sat_cname, &ad, &text ) ) { + /* log? */ + continue; + } + + if ( !access_allowed( op, rs->sr_entry, + ad, NULL, ACL_WRITE, NULL ) ) + { + goto done_ce; + } + } + } + + ber_dupbv( &bv_effective[ je ], &oc->soc_cname ); + je++; + } +done_ce:; + } + + if ( ( got & GOT_C ) && ja > 0 ) { + BER_BVZERO( &bv_allowed[ ja ] ); + *ap = attr_alloc( ad_allowedChildClasses ); + (*ap)->a_vals = bv_allowed; + (*ap)->a_nvals = bv_allowed; + (*ap)->a_numvals = ja; + ap = &(*ap)->a_next; + } + + if ( ( got & GOT_CE ) && je > 0 ) { + BER_BVZERO( &bv_effective[ je ] ); + *ap = attr_alloc( ad_allowedChildClassesEffective ); + (*ap)->a_vals = bv_effective; + (*ap)->a_nvals = bv_effective; + (*ap)->a_numvals = je; + ap = &(*ap)->a_next; + } + + *ap = NULL; + } + + return SLAP_CB_CONTINUE; +} + +static slap_overinst aa; + +#if LDAP_VENDOR_VERSION_MINOR != X && LDAP_VENDOR_VERSION_MINOR <= 3 +/* backport register_at() from HEAD, to allow building with OL <= 2.3 */ +static int +register_at( char *def, AttributeDescription **rad, int dupok ) +{ + LDAPAttributeType *at; + int code, freeit = 0; + const char *err; + AttributeDescription *ad = NULL; + + at = ldap_str2attributetype( def, &code, &err, LDAP_SCHEMA_ALLOW_ALL ); + if ( !at ) { + Debug( LDAP_DEBUG_ANY, + "register_at: AttributeType \"%s\": %s, %s\n", + def, ldap_scherr2str(code), err ); + return code; + } + + code = at_add( at, 0, NULL, &err ); + if ( code ) { + if ( code == SLAP_SCHERR_ATTR_DUP && dupok ) { + freeit = 1; + + } else { + ldap_attributetype_free( at ); + Debug( LDAP_DEBUG_ANY, + "register_at: AttributeType \"%s\": %s, %s\n", + def, scherr2str(code), err ); + return code; + } + } + code = slap_str2ad( at->at_names[0], &ad, &err ); + if ( freeit || code ) { + ldap_attributetype_free( at ); + } else { + ldap_memfree( at ); + } + if ( code ) { + Debug( LDAP_DEBUG_ANY, "register_at: AttributeType \"%s\": %s\n", + def, err, 0 ); + } + if ( rad ) *rad = ad; + return code; +} +#endif + +#if SLAPD_OVER_ALLOWED == SLAPD_MOD_DYNAMIC +static +#endif /* SLAPD_OVER_ALLOWED == SLAPD_MOD_DYNAMIC */ +int +aa_initialize( void ) +{ + int i; + + aa.on_bi.bi_type = "allowed"; + + aa.on_bi.bi_operational = aa_operational; + + /* aa schema integration */ + for ( i = 0; aa_attrs[i].at; i++ ) { + int code; + + code = register_at( aa_attrs[i].at, aa_attrs[i].ad, 0 ); + if ( code ) { + Debug( LDAP_DEBUG_ANY, + "aa_initialize: register_at failed\n", 0, 0, 0 ); + return -1; + } + } + + return overlay_register( &aa ); +} + +#if SLAPD_OVER_ALLOWED == SLAPD_MOD_DYNAMIC +int +init_module( int argc, char *argv[] ) +{ + return aa_initialize(); +} +#endif /* SLAPD_OVER_ALLOWED == SLAPD_MOD_DYNAMIC */ + +#endif /* SLAPD_OVER_ALLOWED */ diff --git a/contrib/slapd-modules/autogroup/Makefile b/contrib/slapd-modules/autogroup/Makefile new file mode 100644 index 0000000..efd9678 --- /dev/null +++ b/contrib/slapd-modules/autogroup/Makefile @@ -0,0 +1,46 @@ +# $OpenLDAP$ + +LDAP_SRC = ../../.. +LDAP_BUILD = $(LDAP_SRC) +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +CC = gcc +OPT = -g -O2 -Wall +DEFS = +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) + +PROGRAMS = autogroup.la +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +autogroup.la: autogroup.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + diff --git a/contrib/slapd-modules/autogroup/README b/contrib/slapd-modules/autogroup/README new file mode 100644 index 0000000..be32282 --- /dev/null +++ b/contrib/slapd-modules/autogroup/README @@ -0,0 +1,120 @@ +autogroup overlay Readme + +DESCRIPTION + The autogroup overlay allows automated updates of group memberships which + meet the requirements of any filter contained in the group definition. + The filters are built from LDAP URI-valued attributes. Any time an object + is added/deleted/updated, it is tested for compliance with the filters, + and its membership is accordingly updated. For searches and compares + it behaves like a static group. + If the attribute part of the URI is filled, the group entry is populated + by the values of this attribute in the entries resulting from the search. + +BUILDING + A Makefile is included. + +CONFIGURATION + # dyngroup.schema: + The dyngroup schema must be modified, adding the 'member' attribute + to the MAY clause of the groupOfURLs object class, i.e.: + + objectClass ( NetscapeLDAPobjectClass:33 + NAME 'groupOfURLs' + SUP top STRUCTURAL + MUST cn + MAY ( memberURL $ businessCategory $ description $ o $ ou $ + owner $ seeAlso $ member) ) + + + # slapd.conf: + + moduleload /path/to/autogroup.so + Loads the overlay (OpenLDAP must be built with --enable-modules). + + overlay autogroup + This directive adds the autogroup overlay to the current database. + + autogroup-attrset <group-oc> <URL-ad> <member-ad> + This configuration option is defined for the autogroup overlay. + It may have multiple occurrences, and it must appear after the + overlay directive. + + The value <group-oc> is the name of the objectClass that represents + the group. + + The value <URL-ad> is the name of the attributeDescription that + contains the URI that is converted to the filters. If no URI is + present, there will be no members in that group. It must be a subtype + of labeledURI. + + The value <member-ad> is the name of the attributeDescription that + specifies the member attribute. User modification of this attribute + is disabled for consistency. + + autogroup-memberof-ad <memberof-ad> + This configuration option is defined for the autogroup overlay. + + It defines the attribute that is used by the memberOf overlay + to store the names of groups that an entry is member of; it must be + DN-valued. It should be set to the same value as + memberof-memberof-ad. It defaults to 'memberOf'. + + +EXAMPLE + ### slapd.conf + include /path/to/dyngroup.schema + # ... + moduleload /path/to/autogroup.so + # ... + + database <database> + # ... + + overlay autogroup + autogroup-attrset groupOfURLs memberURL member + ### end slapd.conf + + ### slapd.conf + include /path/to/dyngroup.schema + # ... + moduleload /path/to/autogroup.so + moduleload /path/to/memberof.so + # ... + + database <database> + #... + + overlay memberof + memberof-memberof-ad foo + + overlay autogroup + autogroup-attrset groupOfURLs memberURL member + autogroup-memberof-ad foo + ### end slapd.conf + +CAVEATS + As with static groups, update operations on groups with a large number + of members may be slow. + If the attribute part of the URI is specified, modify and delete operations + are more difficult to handle. In these cases the overlay will try to detect + if groups have been modified and then simply refresh them. This can cause + performance hits if the search specified by the URI deals with a significant + number of entries. + +ACKNOWLEDGEMENTS + This module was originally written in 2007 by Michał Szulczyński. Further + enhancements were contributed by Howard Chu, Raphael Ouazana, + Norbert Pueschel, and Christian Manal. + +--- +Copyright 1998-2021 The OpenLDAP Foundation. +Portions Copyright (C) 2007 Michał Szulczyński. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted only as authorized by the OpenLDAP +Public License. + +A copy of this license is available in file LICENSE in the +top-level directory of the distribution or, alternatively, at +http://www.OpenLDAP.org/license.html. diff --git a/contrib/slapd-modules/autogroup/autogroup.c b/contrib/slapd-modules/autogroup/autogroup.c new file mode 100644 index 0000000..8caf082 --- /dev/null +++ b/contrib/slapd-modules/autogroup/autogroup.c @@ -0,0 +1,2234 @@ +/* autogroup.c - automatic group overlay */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2007-2021 The OpenLDAP Foundation. + * Portions Copyright 2007 Michał Szulczyński. + * Portions Copyright 2009 Howard Chu. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by Michał Szulczyński for inclusion in + * OpenLDAP Software. Additional significant contributors include: + * Howard Chu + * Raphael Ouazana + * Norbert Pueschel + * Christian Manal + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/string.h> + +#include "slap.h" +#include "config.h" +#include "lutil.h" + +#ifndef SLAPD_MEMBEROF_ATTR +#define SLAPD_MEMBEROF_ATTR "memberOf" +#endif + +static slap_overinst autogroup; + +/* Filter represents the memberURL of a group. */ +typedef struct autogroup_filter_t { + struct berval agf_dn; /* The base DN in memberURL */ + struct berval agf_ndn; + struct berval agf_filterstr; + Filter *agf_filter; + int agf_scope; + AttributeName *agf_anlist; + struct autogroup_filter_t *agf_next; +} autogroup_filter_t; + +/* Description of group attributes. */ +typedef struct autogroup_def_t { + ObjectClass *agd_oc; + AttributeDescription *agd_member_url_ad; + AttributeDescription *agd_member_ad; + struct autogroup_def_t *agd_next; +} autogroup_def_t; + +/* Represents the group entry. */ +typedef struct autogroup_entry_t { + BerValue age_dn; + BerValue age_ndn; + autogroup_filter_t *age_filter; /* List of filters made from memberURLs */ + autogroup_def_t *age_def; /* Attribute definition */ + ldap_pvt_thread_mutex_t age_mutex; + int age_mustrefresh; /* Defined in request to refresh in response */ + int age_modrdn_olddnmodified; /* Defined in request to refresh in response */ + struct autogroup_entry_t *age_next; +} autogroup_entry_t; + +/* Holds pointers to attribute definitions and groups. */ +typedef struct autogroup_info_t { + autogroup_def_t *agi_def; /* Group attributes definitions. */ + autogroup_entry_t *agi_entry; /* Group entries. */ + AttributeDescription *agi_memberof_ad; /* memberOf attribute description */ + ldap_pvt_thread_mutex_t agi_mutex; +} autogroup_info_t; + +/* Search callback for adding groups initially. */ +typedef struct autogroup_sc_t { + autogroup_info_t *ags_info; /* Group definitions and entries. */ + autogroup_def_t *ags_def; /* Attributes definition of the group being added. */ +} autogroup_sc_t; + +/* Used for adding members, found when searching, to a group. */ +typedef struct autogroup_ga_t { + autogroup_entry_t *agg_group; /* The group to which the members will be added. */ + autogroup_filter_t *agg_filter; /* Current filter */ + Entry *agg_entry; /* Used in autogroup_member_search_cb to modify + this entry with the search results. */ + + Modifications *agg_mod; /* Used in autogroup_member_search_modify_cb to hold the + search results which will be added to the group. */ + + Modifications *agg_mod_last; /* Used in autogroup_member_search_modify_cb so we don't + have to search for the last mod added. */ +} autogroup_ga_t; + + +/* +** dn, ndn - the DN of the member to add +** age - the group to which the member DN will be added +*/ +static int +autogroup_add_member_to_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + Modifications *modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) ); + SlapReply sreply = {REP_RESULT}; + BerValue *vals, *nvals; + slap_callback cb = { NULL, slap_null_cb, NULL, NULL }; + Operation o = *op; + unsigned long opid = op->o_opid; + OpExtra oex; + + assert( dn != NULL ); + assert( ndn != NULL ); + Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_member_to_group adding <%s> to <%s>\n", + dn->bv_val, age->age_dn.bv_val, 0); + + vals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) ); + nvals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) ); + ber_dupbv( vals, dn ); + BER_BVZERO( &vals[ 1 ] ); + ber_dupbv( nvals, ndn ); + BER_BVZERO( &nvals[ 1 ] ); + + modlist->sml_op = LDAP_MOD_ADD; + modlist->sml_desc = age->age_def->agd_member_ad; + modlist->sml_type = age->age_def->agd_member_ad->ad_cname; + modlist->sml_values = vals; + modlist->sml_nvalues = nvals; + modlist->sml_numvals = 1; + modlist->sml_flags = SLAP_MOD_INTERNAL; + modlist->sml_next = NULL; + + o.o_opid = 0; /* shared with op, saved above */ + o.o_tag = LDAP_REQ_MODIFY; + o.o_callback = &cb; + o.orm_modlist = modlist; + o.o_dn = op->o_bd->be_rootdn; + o.o_ndn = op->o_bd->be_rootndn; + o.o_req_dn = age->age_dn; + o.o_req_ndn = age->age_ndn; + o.o_permissive_modify = 1; + o.o_dont_replicate = 1; + o.orm_no_opattrs = 1; + o.o_managedsait = SLAP_CONTROL_CRITICAL; + o.o_relax = SLAP_CONTROL_CRITICAL; + + oex.oe_key = (void *)&autogroup; + LDAP_SLIST_INSERT_HEAD( &o.o_extra, &oex, oe_next ); + + o.o_bd->bd_info = (BackendInfo *)on->on_info; + (void)op->o_bd->be_modify( &o, &sreply ); + o.o_bd->bd_info = (BackendInfo *)on; + + LDAP_SLIST_REMOVE( &o.o_extra, &oex, OpExtra, oe_next ); + + slap_mods_free( modlist, 1 ); + op->o_opid = opid; + + return sreply.sr_err; +} + +/* +** e - the entry where to get the attribute values +** age - the group to which the values will be added +*/ +static int +autogroup_add_member_values_to_group( Operation *op, struct berval *dn, autogroup_entry_t *age, Attribute *attr ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + Modifications modlist; + SlapReply sreply = {REP_RESULT}; + slap_callback cb = { NULL, slap_null_cb, NULL, NULL }; + Operation o = *op; + unsigned long opid = op->o_opid; + OpExtra oex; + + Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_member_values_to_group adding <%s> to <%s>\n", + dn->bv_val, age->age_dn.bv_val, 0); + + modlist.sml_op = LDAP_MOD_ADD; + modlist.sml_desc = age->age_def->agd_member_ad; + modlist.sml_type = age->age_def->agd_member_ad->ad_cname; + modlist.sml_values = attr->a_vals; + modlist.sml_nvalues = attr->a_nvals; + modlist.sml_numvals = attr->a_numvals; + modlist.sml_flags = SLAP_MOD_INTERNAL; + modlist.sml_next = NULL; + + o.o_opid = 0; + o.o_tag = LDAP_REQ_MODIFY; + o.o_callback = &cb; + o.orm_modlist = &modlist; + o.o_dn = op->o_bd->be_rootdn; + o.o_ndn = op->o_bd->be_rootndn; + o.o_req_dn = age->age_dn; + o.o_req_ndn = age->age_ndn; + o.o_permissive_modify = 1; + o.o_dont_replicate = 1; + o.orm_no_opattrs = 1; + o.o_managedsait = SLAP_CONTROL_CRITICAL; + o.o_relax = SLAP_CONTROL_CRITICAL; + + oex.oe_key = (void *)&autogroup; + LDAP_SLIST_INSERT_HEAD( &o.o_extra, &oex, oe_next ); + + o.o_bd->bd_info = (BackendInfo *)on->on_info; + (void)op->o_bd->be_modify( &o, &sreply ); + o.o_bd->bd_info = (BackendInfo *)on; + op->o_opid = opid; + LDAP_SLIST_REMOVE( &o.o_extra, &oex, OpExtra, oe_next ); + + return sreply.sr_err; +} + +/* +** dn,ndn - the DN to be deleted +** age - the group from which the DN will be deleted +** If we pass a NULL dn and ndn, all members are deleted from the group. +*/ +static int +autogroup_delete_member_from_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + Modifications *modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) ); + SlapReply sreply = {REP_RESULT}; + BerValue *vals, *nvals; + slap_callback cb = { NULL, slap_null_cb, NULL, NULL }; + Operation o = *op; + unsigned long opid = op->o_opid; + OpExtra oex; + + if ( dn == NULL || ndn == NULL ) { + Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing all members from <%s>\n", + age->age_dn.bv_val, 0 ,0); + + modlist->sml_values = NULL; + modlist->sml_nvalues = NULL; + modlist->sml_numvals = 0; + } else { + Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing <%s> from <%s>\n", + dn->bv_val, age->age_dn.bv_val, 0); + + vals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) ); + nvals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) ); + ber_dupbv( vals, dn ); + BER_BVZERO( &vals[ 1 ] ); + ber_dupbv( nvals, ndn ); + BER_BVZERO( &nvals[ 1 ] ); + + modlist->sml_values = vals; + modlist->sml_nvalues = nvals; + modlist->sml_numvals = 1; + } + + + modlist->sml_op = LDAP_MOD_DELETE; + modlist->sml_desc = age->age_def->agd_member_ad; + modlist->sml_type = age->age_def->agd_member_ad->ad_cname; + modlist->sml_flags = SLAP_MOD_INTERNAL; + modlist->sml_next = NULL; + + o.o_opid = 0; + o.o_callback = &cb; + o.o_tag = LDAP_REQ_MODIFY; + o.orm_modlist = modlist; + o.o_dn = op->o_bd->be_rootdn; + o.o_ndn = op->o_bd->be_rootndn; + o.o_req_dn = age->age_dn; + o.o_req_ndn = age->age_ndn; + o.o_relax = SLAP_CONTROL_CRITICAL; + o.o_managedsait = SLAP_CONTROL_CRITICAL; + o.o_permissive_modify = 1; + o.o_dont_replicate = 1; + o.orm_no_opattrs = 1; + + oex.oe_key = (void *)&autogroup; + LDAP_SLIST_INSERT_HEAD( &o.o_extra, &oex, oe_next ); + + o.o_bd->bd_info = (BackendInfo *)on->on_info; + (void)op->o_bd->be_modify( &o, &sreply ); + o.o_bd->bd_info = (BackendInfo *)on; + + LDAP_SLIST_REMOVE( &o.o_extra, &oex, OpExtra, oe_next ); + + slap_mods_free( modlist, 1 ); + + op->o_opid = opid; + return sreply.sr_err; +} + +/* +** e - the entry where to get the attribute values +** age - the group from which the values will be deleted +*/ +static int +autogroup_delete_member_values_from_group( Operation *op, struct berval *dn, autogroup_entry_t *age, Attribute *attr ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + Modifications modlist; + SlapReply sreply = {REP_RESULT}; + slap_callback cb = { NULL, slap_null_cb, NULL, NULL }; + Operation o = *op; + unsigned long opid = op->o_opid; + OpExtra oex; + + Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_values_from_group removing <%s> from <%s>\n", + dn->bv_val, age->age_dn.bv_val, 0); + + modlist.sml_op = LDAP_MOD_DELETE; + modlist.sml_desc = age->age_def->agd_member_ad; + modlist.sml_type = age->age_def->agd_member_ad->ad_cname; + modlist.sml_values = attr->a_vals; + modlist.sml_nvalues = attr->a_nvals; + modlist.sml_numvals = attr->a_numvals; + modlist.sml_flags = SLAP_MOD_INTERNAL; + modlist.sml_next = NULL; + + o.o_opid = 0; + o.o_tag = LDAP_REQ_MODIFY; + o.o_callback = &cb; + o.orm_modlist = &modlist; + o.o_dn = op->o_bd->be_rootdn; + o.o_ndn = op->o_bd->be_rootndn; + o.o_req_dn = age->age_dn; + o.o_req_ndn = age->age_ndn; + o.o_permissive_modify = 1; + o.o_dont_replicate = 1; + o.orm_no_opattrs = 1; + o.o_managedsait = SLAP_CONTROL_CRITICAL; + o.o_relax = SLAP_CONTROL_CRITICAL; + + oex.oe_key = (void *)&autogroup; + LDAP_SLIST_INSERT_HEAD( &o.o_extra, &oex, oe_next ); + + o.o_bd->bd_info = (BackendInfo *)on->on_info; + (void)op->o_bd->be_modify( &o, &sreply ); + o.o_bd->bd_info = (BackendInfo *)on; + op->o_opid = opid; + + LDAP_SLIST_REMOVE( &o.o_extra, &oex, OpExtra, oe_next ); + + return sreply.sr_err; +} + +/* +** Callback used to add entries to a group, +** which are going to be written in the database +** (used in bi_op_add) +** The group is passed in autogroup_ga_t->agg_group +*/ +static int +autogroup_member_search_cb( Operation *op, SlapReply *rs ) +{ + assert( op->o_tag == LDAP_REQ_SEARCH ); + + if ( rs->sr_type == REP_SEARCH ) { + autogroup_ga_t *agg = (autogroup_ga_t *)op->o_callback->sc_private; + autogroup_entry_t *age = agg->agg_group; + autogroup_filter_t *agf = agg->agg_filter; + Modification mod; + const char *text = NULL; + char textbuf[1024]; + struct berval *vals, *nvals; + struct berval lvals[ 2 ], lnvals[ 2 ]; + int numvals; + + Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_cb <%s>\n", + rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0); + + if ( agf->agf_anlist ) { + Attribute *attr = attrs_find( rs->sr_entry->e_attrs, agf->agf_anlist[0].an_desc ); + if (attr) { + vals = attr->a_vals; + nvals = attr->a_nvals; + numvals = attr->a_numvals; + } else { + // Nothing to add + return 0; + } + } else { + lvals[ 0 ] = rs->sr_entry->e_name; + BER_BVZERO( &lvals[ 1 ] ); + lnvals[ 0 ] = rs->sr_entry->e_nname; + BER_BVZERO( &lnvals[ 1 ] ); + vals = lvals; + nvals = lnvals; + numvals = 1; + } + + mod.sm_op = LDAP_MOD_ADD; + mod.sm_desc = age->age_def->agd_member_ad; + mod.sm_type = age->age_def->agd_member_ad->ad_cname; + mod.sm_values = vals; + mod.sm_nvalues = nvals; + mod.sm_numvals = numvals; + + modify_add_values( agg->agg_entry, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) ); + } + + return 0; +} + +/* +** Callback used to add entries to a group, which is already in the database. +** (used in on_response) +** The group is passed in autogroup_ga_t->agg_group +** NOTE: Very slow. +*/ +static int +autogroup_member_search_modify_cb( Operation *op, SlapReply *rs ) +{ + assert( op->o_tag == LDAP_REQ_SEARCH ); + + if ( rs->sr_type == REP_SEARCH ) { + autogroup_ga_t *agg = (autogroup_ga_t *)op->o_callback->sc_private; + autogroup_entry_t *age = agg->agg_group; + autogroup_filter_t *agf = agg->agg_filter; + Modifications *modlist; + struct berval *vals, *nvals; + struct berval lvals[ 2 ], lnvals[ 2 ]; + int numvals; + + Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_modify_cb <%s>\n", + rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0); + + if ( agf->agf_anlist ) { + Attribute *attr = attrs_find( rs->sr_entry->e_attrs, agf->agf_anlist[0].an_desc ); + if (attr) { + vals = attr->a_vals; + nvals = attr->a_nvals; + numvals = attr->a_numvals; + } else { + // Nothing to add + return 0; + } + } else { + lvals[ 0 ] = rs->sr_entry->e_name; + BER_BVZERO( &lvals[ 1 ] ); + lnvals[ 0 ] = rs->sr_entry->e_nname; + BER_BVZERO( &lnvals[ 1 ] ); + vals = lvals; + nvals = lnvals; + numvals = 1; + } + + if ( numvals ) { + modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) ); + + modlist->sml_op = LDAP_MOD_ADD; + modlist->sml_desc = age->age_def->agd_member_ad; + modlist->sml_type = age->age_def->agd_member_ad->ad_cname; + + ber_bvarray_dup_x( &modlist->sml_values, vals, NULL ); + ber_bvarray_dup_x( &modlist->sml_nvalues, nvals, NULL ); + modlist->sml_numvals = numvals; + + modlist->sml_flags = SLAP_MOD_INTERNAL; + modlist->sml_next = NULL; + + if ( agg->agg_mod == NULL ) { + agg->agg_mod = modlist; + agg->agg_mod_last = modlist; + } else { + agg->agg_mod_last->sml_next = modlist; + agg->agg_mod_last = modlist; + } + } + + } + + return 0; +} + + +/* +** Adds all entries matching the passed filter to the specified group. +** If modify == 1, then we modify the group's entry in the database using be_modify. +** If modify == 0, then, we must supply a rw entry for the group, +** because we only modify the entry, without calling be_modify. +** e - the group entry, to which the members will be added +** age - the group +** agf - the filter +*/ +static int +autogroup_add_members_from_filter( Operation *op, Entry *e, autogroup_entry_t *age, autogroup_filter_t *agf, int modify) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + Operation o = *op; + SlapReply rs = { REP_SEARCH }; + slap_callback cb = { 0 }; + slap_callback null_cb = { NULL, slap_null_cb, NULL, NULL }; + autogroup_ga_t agg; + OpExtra oex; + + Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_members_from_filter <%s>\n", + age->age_dn.bv_val, 0, 0); + + o.ors_attrsonly = 0; + o.o_tag = LDAP_REQ_SEARCH; + + o.o_dn = op->o_bd->be_rootdn; + o.o_ndn = op->o_bd->be_rootndn; + o.o_req_dn = agf->agf_dn; + o.o_req_ndn = agf->agf_ndn; + + o.ors_filterstr = agf->agf_filterstr; + o.ors_filter = agf->agf_filter; + + o.ors_scope = agf->agf_scope; + o.ors_deref = LDAP_DEREF_NEVER; + o.ors_limit = NULL; + o.ors_tlimit = SLAP_NO_LIMIT; + o.ors_slimit = SLAP_NO_LIMIT; + o.ors_attrs = agf->agf_anlist ? agf->agf_anlist : slap_anlist_no_attrs; + o.o_do_not_cache = 1; + + agg.agg_group = age; + agg.agg_filter = agf; + agg.agg_mod = NULL; + agg.agg_mod_last = NULL; + agg.agg_entry = e; + cb.sc_private = &agg; + + if ( modify == 1 ) { + cb.sc_response = autogroup_member_search_modify_cb; + } else { + cb.sc_response = autogroup_member_search_cb; + } + + cb.sc_cleanup = NULL; + cb.sc_next = NULL; + + o.o_callback = &cb; + + o.o_bd->bd_info = (BackendInfo *)on->on_info; + op->o_bd->be_search( &o, &rs ); + o.o_bd->bd_info = (BackendInfo *)on; + + if ( modify == 1 && agg.agg_mod ) { + unsigned long opid = op->o_opid; + + rs_reinit( &rs, REP_RESULT ); + + o = *op; + o.o_opid = 0; + o.o_callback = &null_cb; + o.o_tag = LDAP_REQ_MODIFY; + o.orm_modlist = agg.agg_mod; + o.o_dn = op->o_bd->be_rootdn; + o.o_ndn = op->o_bd->be_rootndn; + o.o_req_dn = age->age_dn; + o.o_req_ndn = age->age_ndn; + o.o_relax = SLAP_CONTROL_CRITICAL; + o.o_managedsait = SLAP_CONTROL_NONCRITICAL; + o.o_permissive_modify = 1; + o.o_dont_replicate = 1; + o.orm_no_opattrs = 1; + + oex.oe_key = (void *)&autogroup; + LDAP_SLIST_INSERT_HEAD( &o.o_extra, &oex, oe_next ); + + o.o_bd->bd_info = (BackendInfo *)on->on_info; + (void)op->o_bd->be_modify( &o, &rs ); + o.o_bd->bd_info = (BackendInfo *)on; + + LDAP_SLIST_REMOVE( &o.o_extra, &oex, OpExtra, oe_next ); + + slap_mods_free(agg.agg_mod, 1); + op->o_opid = opid; + } + + return 0; +} + +/* +** Adds a group to the internal list from the passed entry. +** scan specifies whether to add all maching members to the group. +** modify specifies whether to modify the given group entry (when modify == 0), +** or to modify the group entry in the database (when modify == 1 and e = NULL and ndn != NULL). +** agi - pointer to the groups and the attribute definitions +** agd - the attribute definition of the added group +** e - the entry representing the group, can be NULL if the ndn is specified, and modify == 1 +** ndn - the DN of the group, can be NULL if we give a non-NULL e +*/ +static int +autogroup_add_group( Operation *op, autogroup_info_t *agi, autogroup_def_t *agd, Entry *e, BerValue *ndn, int scan, int modify) +{ + autogroup_entry_t **agep = &agi->agi_entry; + autogroup_filter_t *agf, *agf_prev = NULL; + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + LDAPURLDesc *lud = NULL; + Attribute *a; + BerValue *bv, dn; + int rc = 0, match = 1, null_entry = 0; + + if ( e == NULL ) { + if ( overlay_entry_get_ov( op, ndn, NULL, NULL, 0, &e, on ) != + LDAP_SUCCESS || e == NULL ) { + Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot get entry for <%s>\n", ndn->bv_val, 0, 0); + return 1; + } + + null_entry = 1; + } + + Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_group <%s>\n", + e->e_name.bv_val, 0, 0); + + if ( agi->agi_entry != NULL ) { + for ( ; *agep ; agep = &(*agep)->age_next ) { + dnMatch( &match, 0, NULL, NULL, &e->e_nname, &(*agep)->age_ndn ); + if ( match == 0 ) { + Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group already exists: <%s>\n", e->e_name.bv_val,0,0); + return 1; + } + /* goto last */; + } + } + + + *agep = (autogroup_entry_t *)ch_calloc( 1, sizeof( autogroup_entry_t ) ); + ldap_pvt_thread_mutex_init( &(*agep)->age_mutex ); + (*agep)->age_def = agd; + (*agep)->age_filter = NULL; + (*agep)->age_mustrefresh = 0; + (*agep)->age_modrdn_olddnmodified = 0; + + ber_dupbv( &(*agep)->age_dn, &e->e_name ); + ber_dupbv( &(*agep)->age_ndn, &e->e_nname ); + + a = attrs_find( e->e_attrs, agd->agd_member_url_ad ); + + if ( null_entry == 1 ) { + a = attrs_dup( a ); + overlay_entry_release_ov( op, e, 0, on ); + } + + if( a == NULL ) { + Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group has no memberURL\n", 0,0,0); + } else { + for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) { + + agf = (autogroup_filter_t*)ch_calloc( 1, sizeof( autogroup_filter_t ) ); + + if ( ldap_url_parse( bv->bv_val, &lud ) != LDAP_URL_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot parse url <%s>\n", bv->bv_val,0,0); + /* FIXME: error? */ + ch_free( agf ); + continue; + } + + agf->agf_scope = lud->lud_scope; + + if ( lud->lud_dn == NULL ) { + BER_BVSTR( &dn, "" ); + } else { + ber_str2bv( lud->lud_dn, 0, 0, &dn ); + } + + rc = dnPrettyNormal( NULL, &dn, &agf->agf_dn, &agf->agf_ndn, NULL ); + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot normalize DN <%s>\n", dn.bv_val,0,0); + /* FIXME: error? */ + goto cleanup; + } + + if ( lud->lud_filter != NULL ) { + ber_str2bv( lud->lud_filter, 0, 1, &agf->agf_filterstr); + agf->agf_filter = str2filter( lud->lud_filter ); + } else { + Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: URL filter is missing <%s>\n", bv->bv_val,0,0); + /* FIXME: error? */ + goto cleanup; + } + + if ( lud->lud_attrs != NULL ) { + int i; + + for ( i=0 ; lud->lud_attrs[i]!=NULL ; i++) { + /* Just counting */; + } + + if ( i > 1 ) { + Debug( LDAP_DEBUG_ANY, "autogroup_add_group: too many attributes specified in url <%s>\n", + bv->bv_val, 0, 0); + /* FIXME: error? */ + filter_free( agf->agf_filter ); + ch_free( agf->agf_filterstr.bv_val ); + ch_free( agf->agf_dn.bv_val ); + ch_free( agf->agf_ndn.bv_val ); + ldap_free_urldesc( lud ); + ch_free( agf ); + continue; + } + + agf->agf_anlist = str2anlist( NULL, lud->lud_attrs[0], "," ); + + if ( agf->agf_anlist == NULL ) { + Debug( LDAP_DEBUG_ANY, "autogroup_add_group: unable to find AttributeDescription \"%s\".\n", + lud->lud_attrs[0], 0, 0 ); + /* FIXME: error? */ + filter_free( agf->agf_filter ); + ch_free( agf->agf_filterstr.bv_val ); + ch_free( agf->agf_dn.bv_val ); + ch_free( agf->agf_ndn.bv_val ); + ldap_free_urldesc( lud ); + ch_free( agf ); + continue; + } + } + + agf->agf_next = NULL; + + if( (*agep)->age_filter == NULL ) { + (*agep)->age_filter = agf; + } + + if( agf_prev != NULL ) { + agf_prev->agf_next = agf; + } + + agf_prev = agf; + + if ( scan == 1 ){ + autogroup_add_members_from_filter( op, e, (*agep), agf, modify ); + } + + Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: added memberURL DN <%s> with filter <%s>\n", + agf->agf_ndn.bv_val, agf->agf_filterstr.bv_val, 0); + + ldap_free_urldesc( lud ); + + continue; + + +cleanup:; + + ch_free( agf->agf_ndn.bv_val ); + ch_free( agf->agf_dn.bv_val ); + ldap_free_urldesc( lud ); + ch_free( agf ); + } + } + + if ( null_entry == 1 ) { + attrs_free( a ); + } + return rc; +} + +/* +** Used when opening the database to add all existing +** groups from the database to our internal list. +*/ +static int +autogroup_group_add_cb( Operation *op, SlapReply *rs ) +{ + assert( op->o_tag == LDAP_REQ_SEARCH ); + + if ( rs->sr_type == REP_SEARCH ) { + autogroup_sc_t *ags = (autogroup_sc_t *)op->o_callback->sc_private; + + Debug(LDAP_DEBUG_TRACE, "==> autogroup_group_add_cb <%s>\n", + rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0); + + autogroup_add_group( op, ags->ags_info, ags->ags_def, rs->sr_entry, NULL, 0, 0); + } + + return 0; +} + +typedef struct ag_addinfo { + slap_overinst *on; + Entry *e; + autogroup_def_t *agd; +} ag_addinfo; + +static int +autogroup_add_entry_cb( Operation *op, SlapReply *rs ) +{ + slap_callback *sc = op->o_callback; + ag_addinfo *aa = sc->sc_private; + slap_overinst *on = aa->on; + autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private; + BackendInfo *bi = op->o_bd->bd_info; + + if ( rs->sr_err != LDAP_SUCCESS ) + goto done; + + op->o_bd->bd_info = (BackendInfo *)on; + ldap_pvt_thread_mutex_lock( &agi->agi_mutex ); + if ( aa->agd ) { + autogroup_add_group( op, agi, aa->agd, aa->e, NULL, 1 , 0); + } else { + autogroup_entry_t *age; + autogroup_filter_t *agf; + struct berval odn, ondn; + int rc; + + /* must use rootdn when calling test_filter */ + odn = op->o_dn; + ondn = op->o_ndn; + op->o_dn = op->o_bd->be_rootdn; + op->o_ndn = op->o_bd->be_rootndn; + + for ( age = agi->agi_entry; age ; age = age->age_next ) { + ldap_pvt_thread_mutex_lock( &age->age_mutex ); + + /* Check if any of the filters are the suffix to the entry DN. + If yes, we can test that filter against the entry. */ + + for ( agf = age->age_filter; agf ; agf = agf->agf_next ) { + if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) { + rc = test_filter( op, aa->e, agf->agf_filter ); + if ( rc == LDAP_COMPARE_TRUE ) { + if ( agf->agf_anlist ) { + Attribute *a = attr_find( aa->e->e_attrs, agf->agf_anlist[0].an_desc ); + if ( a ) + autogroup_add_member_values_to_group( op, &op->o_req_dn, age, a ); + } else { + autogroup_add_member_to_group( op, &aa->e->e_name, &aa->e->e_nname, age ); + } + break; + } + } + } + ldap_pvt_thread_mutex_unlock( &age->age_mutex ); + } + op->o_dn = odn; + op->o_ndn = ondn; + } + ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); + + op->o_bd->bd_info = bi; + +done: + op->o_callback = sc->sc_next; + op->o_tmpfree( sc, op->o_tmpmemctx ); + + return SLAP_CB_CONTINUE; +} + +/* +** When adding a group, we first strip any existing members, +** and add all which match the filters ourselfs. +*/ +static int +autogroup_add_entry( Operation *op, SlapReply *rs) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private; + autogroup_def_t *agd = agi->agi_def; + slap_callback *sc = NULL; + ag_addinfo *aa = NULL; + + Debug( LDAP_DEBUG_TRACE, "==> autogroup_add_entry <%s>\n", + op->ora_e->e_name.bv_val, 0, 0); + + sc = op->o_tmpcalloc( sizeof(slap_callback) + sizeof(ag_addinfo), 1, op->o_tmpmemctx ); + sc->sc_private = (sc+1); + sc->sc_response = autogroup_add_entry_cb; + aa = sc->sc_private; + aa->on = on; + aa->e = op->ora_e; + sc->sc_next = op->o_callback; + op->o_callback = sc; + + /* Check if it's a group. */ + for ( ; agd ; agd = agd->agd_next ) { + if ( is_entry_objectclass_or_sub( op->ora_e, agd->agd_oc ) ) { + Modification mod; + const char *text = NULL; + char textbuf[1024]; + + mod.sm_op = LDAP_MOD_DELETE; + mod.sm_desc = agd->agd_member_ad; + mod.sm_type = agd->agd_member_ad->ad_cname; + mod.sm_values = NULL; + mod.sm_nvalues = NULL; + + /* We don't want any member attributes added by the user. */ + modify_delete_values( op->ora_e, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) ); + + aa->agd = agd; + + break; + } + } + + return SLAP_CB_CONTINUE; +} + +/* +** agi - internal group and attribute definitions list +** e - the group to remove from the internal list +*/ +static int +autogroup_delete_group( autogroup_info_t *agi, autogroup_entry_t *e ) +{ + autogroup_entry_t *age = agi->agi_entry, + *age_prev = NULL, + *age_next; + int rc = 1; + + Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_group <%s>\n", + age->age_dn.bv_val, 0, 0); + + for ( age_next = age ; age_next ; age_prev = age, age = age_next ) { + age_next = age->age_next; + + if ( age == e ) { + autogroup_filter_t *agf = age->age_filter, + *agf_next; + + if ( age_prev != NULL ) { + age_prev->age_next = age_next; + } else { + agi->agi_entry = NULL; + } + + ch_free( age->age_dn.bv_val ); + ch_free( age->age_ndn.bv_val ); + + for( agf_next = agf ; agf_next ; agf = agf_next ){ + agf_next = agf->agf_next; + + filter_free( agf->agf_filter ); + ch_free( agf->agf_filterstr.bv_val ); + ch_free( agf->agf_dn.bv_val ); + ch_free( agf->agf_ndn.bv_val ); + anlist_free( agf->agf_anlist, 1, NULL ); + ch_free( agf ); + } + + ldap_pvt_thread_mutex_unlock( &age->age_mutex ); + ldap_pvt_thread_mutex_destroy( &age->age_mutex ); + ch_free( age ); + + rc = 0; + return rc; + + } + } + + Debug( LDAP_DEBUG_TRACE, "autogroup_delete_group: group <%s> not found, should not happen\n", age->age_dn.bv_val, 0, 0); + + return rc; + +} + +static int +autogroup_delete_entry( Operation *op, SlapReply *rs) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private; + autogroup_entry_t *age, *age_prev, *age_next; + autogroup_filter_t *agf; + Entry *e; + int matched_group = 0, rc = 0; + struct berval odn, ondn; + OpExtra *oex; + + LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) { + if ( oex->oe_key == (void *)&autogroup ) + return SLAP_CB_CONTINUE; + } + + Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_entry <%s>\n", op->o_req_dn.bv_val, 0, 0); + + ldap_pvt_thread_mutex_lock( &agi->agi_mutex ); + + if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) != + LDAP_SUCCESS || e == NULL ) { + Debug( LDAP_DEBUG_TRACE, "autogroup_delete_entry: cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0); + ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); + return SLAP_CB_CONTINUE; + } + + /* Check if the entry to be deleted is one of our groups. */ + for ( age_next = agi->agi_entry ; age_next ; age_prev = age ) { + age = age_next; + ldap_pvt_thread_mutex_lock( &age->age_mutex ); + age_next = age->age_next; + + if ( is_entry_objectclass_or_sub( e, age->age_def->agd_oc ) ) { + int match = 1; + + matched_group = 1; + + dnMatch( &match, 0, NULL, NULL, &e->e_nname, &age->age_ndn ); + + if ( match == 0 ) { + autogroup_delete_group( agi, age ); + break; + } + } + + ldap_pvt_thread_mutex_unlock( &age->age_mutex ); + } + + if ( matched_group == 1 ) { + overlay_entry_release_ov( op, e, 0, on ); + ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); + return SLAP_CB_CONTINUE; + } + + /* Check if the entry matches any of the groups. + If yes, we can delete the entry from that group. */ + + odn = op->o_dn; + ondn = op->o_ndn; + op->o_dn = op->o_bd->be_rootdn; + op->o_ndn = op->o_bd->be_rootndn; + + for ( age = agi->agi_entry ; age ; age = age->age_next ) { + ldap_pvt_thread_mutex_lock( &age->age_mutex ); + + for ( agf = age->age_filter; agf ; agf = agf->agf_next ) { + if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) { + rc = test_filter( op, e, agf->agf_filter ); + if ( rc == LDAP_COMPARE_TRUE ) { + /* If the attribute is retrieved from the entry, we don't know what to delete + ** So the group must be entirely refreshed + ** But the refresh can't be done now because the entry is not deleted + ** So the group is marked as mustrefresh + */ + if ( agf->agf_anlist ) { + age->age_mustrefresh = 1; + } else { + autogroup_delete_member_from_group( op, &e->e_name, &e->e_nname, age ); + } + break; + } + } + } + ldap_pvt_thread_mutex_unlock( &age->age_mutex ); + } + op->o_dn = odn; + op->o_ndn = ondn; + + overlay_entry_release_ov( op, e, 0, on ); + ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); + + return SLAP_CB_CONTINUE; +} + +static int +autogroup_response( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private; + autogroup_def_t *agd = agi->agi_def; + autogroup_entry_t *age; + autogroup_filter_t *agf; + BerValue new_dn, new_ndn, pdn; + Entry *e, *group; + Attribute *a, *ea, *attrs; + int is_olddn, is_newdn, is_value_refresh, dn_equal; + OpExtra *oex; + + LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) { + if ( oex->oe_key == (void *)&autogroup ) + break; + } + + /* Handle all cases where a refresh of the group is needed */ + if ( op->o_tag == LDAP_REQ_DELETE || op->o_tag == LDAP_REQ_MODIFY ) { + if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !oex ) { + + ldap_pvt_thread_mutex_lock( &agi->agi_mutex ); + + for ( age = agi->agi_entry ; age ; age = age->age_next ) { + /* Request detected that the group must be refreshed */ + + ldap_pvt_thread_mutex_lock( &age->age_mutex ); + + if ( age->age_mustrefresh ) { + autogroup_delete_member_from_group( op, NULL, NULL, age) ; + + for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) { + autogroup_add_members_from_filter( op, NULL, age, agf, 1 ); + } + } + + ldap_pvt_thread_mutex_unlock( &age->age_mutex ); + } + + ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); + } + } else if ( op->o_tag == LDAP_REQ_MODRDN ) { + if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !oex ) { + + Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODRDN from <%s>\n", op->o_req_dn.bv_val, 0, 0); + + ldap_pvt_thread_mutex_lock( &agi->agi_mutex ); + + if ( op->oq_modrdn.rs_newSup ) { + pdn = *op->oq_modrdn.rs_newSup; + } else { + dnParent( &op->o_req_dn, &pdn ); + } + build_new_dn( &new_dn, &pdn, &op->orr_newrdn, op->o_tmpmemctx ); + + if ( op->oq_modrdn.rs_nnewSup ) { + pdn = *op->oq_modrdn.rs_nnewSup; + } else { + dnParent( &op->o_req_ndn, &pdn ); + } + build_new_dn( &new_ndn, &pdn, &op->orr_nnewrdn, op->o_tmpmemctx ); + + Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN to <%s>\n", new_dn.bv_val, 0, 0); + + dnMatch( &dn_equal, 0, NULL, NULL, &op->o_req_ndn, &new_ndn ); + + if ( overlay_entry_get_ov( op, &new_ndn, NULL, NULL, 0, &e, on ) != + LDAP_SUCCESS || e == NULL ) { + Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get entry for <%s>\n", new_dn.bv_val, 0, 0); + ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); + return SLAP_CB_CONTINUE; + } + + a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass ); + + + if ( a == NULL ) { + Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN entry <%s> has no objectClass\n", new_dn.bv_val, 0, 0); + overlay_entry_release_ov( op, e, 0, on ); + ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); + return SLAP_CB_CONTINUE; + } + + + /* If a groups DN is modified, just update age_dn/ndn of that group with the new DN. */ + for ( ; agd; agd = agd->agd_next ) { + + if ( value_find_ex( slap_schema.si_ad_objectClass, + SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | + SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, + a->a_nvals, &agd->agd_oc->soc_cname, + op->o_tmpmemctx ) == 0 ) + { + for ( age = agi->agi_entry ; age ; age = age->age_next ) { + int match = 1; + + dnMatch( &match, 0, NULL, NULL, &age->age_ndn, &op->o_req_ndn ); + if ( match == 0 ) { + Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN updating group's DN to <%s>\n", new_dn.bv_val, 0, 0); + ber_dupbv( &age->age_dn, &new_dn ); + ber_dupbv( &age->age_ndn, &new_ndn ); + + op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx ); + op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx ); + overlay_entry_release_ov( op, e, 0, on ); + ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); + return SLAP_CB_CONTINUE; + } + } + + } + } + + /* For each group: + 1. check if the orginal entry's DN is in the group. + 2. chceck if the any of the group filter's base DN is a suffix of the new DN + + If 1 and 2 are both false, we do nothing. + If 1 and 2 is true, we remove the old DN from the group, and add the new DN. + If 1 is false, and 2 is true, we check the entry against the group's filters, + and add it's DN to the group. + If 1 is true, and 2 is false, we delete the entry's DN from the group. + */ + attrs = attrs_dup( e->e_attrs ); + overlay_entry_release_ov( op, e, 0, on ); + for ( age = agi->agi_entry ; age ; age = age->age_next ) { + is_olddn = 0; + is_newdn = 0; + is_value_refresh = 0; + + ldap_pvt_thread_mutex_lock( &age->age_mutex ); + + if ( age->age_filter && age->age_filter->agf_anlist ) { + ea = attrs_find( attrs, age->age_filter->agf_anlist[0].an_desc ); + } + else { + ea = NULL; + } + + if ( age->age_modrdn_olddnmodified ) { + /* Resquest already marked this group to be updated */ + is_olddn = 1; + is_value_refresh = 1; + age->age_modrdn_olddnmodified = 0; + } else { + + if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) != + LDAP_SUCCESS || group == NULL ) { + Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get group entry <%s>\n", age->age_dn.bv_val, 0, 0); + + op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx ); + op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx ); + + attrs_free( attrs ); + ldap_pvt_thread_mutex_unlock( &age->age_mutex ); + ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); + return SLAP_CB_CONTINUE; + } + + a = attrs_find( group->e_attrs, age->age_def->agd_member_ad ); + + if ( a != NULL ) { + if ( value_find_ex( age->age_def->agd_member_ad, + SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | + SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, + a->a_nvals, ea ? ea->a_nvals : &op->o_req_ndn, op->o_tmpmemctx ) == 0 ) + { + is_olddn = 1; + } + + } + + overlay_entry_release_ov( op, group, 0, on ); + + } + + for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) { + if ( dnIsSuffix( &new_ndn, &agf->agf_ndn ) ) { + /* TODO: should retest filter as it could imply conditions on the dn */ + is_newdn = 1; + break; + } + } + + + if ( is_value_refresh ) { + if ( is_olddn != is_newdn ) { + /* group refresh */ + autogroup_delete_member_from_group( op, NULL, NULL, age) ; + + for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) { + autogroup_add_members_from_filter( op, NULL, age, agf, 1 ); + } + } + ldap_pvt_thread_mutex_unlock( &age->age_mutex ); + continue; + } + if ( is_olddn == 1 && is_newdn == 0 ) { + if ( ea ) + autogroup_delete_member_values_from_group( op, &new_dn, age, ea ); + else + autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age ); + } else + if ( is_olddn == 0 && is_newdn == 1 ) { + Entry etmp; + struct berval odn, ondn; + etmp.e_name = op->o_req_dn; + etmp.e_nname = op->o_req_ndn; + etmp.e_attrs = attrs; + odn = op->o_dn; + ondn = op->o_ndn; + op->o_dn = op->o_bd->be_rootdn; + op->o_ndn = op->o_bd->be_rootndn; + + for ( agf = age->age_filter; agf; agf = agf->agf_next ) { + if ( test_filter( op, &etmp, agf->agf_filter ) == LDAP_COMPARE_TRUE ) { + if ( ea ) { + autogroup_add_member_values_to_group( op, &new_dn, age, ea ); + } else + autogroup_add_member_to_group( op, &new_dn, &new_ndn, age ); + break; + } + } + op->o_dn = odn; + op->o_ndn = ondn; + } else + if ( is_olddn == 1 && is_newdn == 1 && dn_equal != 0 ) { + if ( ea ) { + /* group refresh */ + autogroup_delete_member_from_group( op, NULL, NULL, age) ; + + for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) { + autogroup_add_members_from_filter( op, NULL, age, agf, 1 ); + } + } + else { + autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age ); + autogroup_add_member_to_group( op, &new_dn, &new_ndn, age ); + } + } + + ldap_pvt_thread_mutex_unlock( &age->age_mutex ); + } + + op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx ); + op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx ); + + attrs_free( attrs ); + + ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); + } + } + + if ( op->o_tag == LDAP_REQ_MODIFY ) { + if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !oex ) { + Entry etmp; + struct berval odn, ondn; + Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODIFY <%s>\n", op->o_req_dn.bv_val, 0, 0); + + ldap_pvt_thread_mutex_lock( &agi->agi_mutex ); + + if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) != + LDAP_SUCCESS || e == NULL ) { + Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0); + ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); + return SLAP_CB_CONTINUE; + } + + a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass ); + + + if ( a == NULL ) { + Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0); + overlay_entry_release_ov( op, e, 0, on ); + ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); + return SLAP_CB_CONTINUE; + } + + /* If we modify a group's memberURL, we have to delete all of it's members, + and add them anew, because we cannot tell from which memberURL a member was added. */ + for ( ; agd; agd = agd->agd_next ) { + + if ( value_find_ex( slap_schema.si_ad_objectClass, + SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | + SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, + a->a_nvals, &agd->agd_oc->soc_cname, + op->o_tmpmemctx ) == 0 ) + { + Modifications *m; + int match = 1; + + m = op->orm_modlist; + + for ( age = agi->agi_entry ; age ; age = age->age_next ) { + ldap_pvt_thread_mutex_lock( &age->age_mutex ); + + dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn ); + + if ( match == 0 ) { + for ( ; m ; m = m->sml_next ) { + if ( m->sml_desc == age->age_def->agd_member_url_ad ) { + autogroup_def_t *group_agd = age->age_def; + Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY changing memberURL for group <%s>\n", + op->o_req_dn.bv_val, 0, 0); + + overlay_entry_release_ov( op, e, 0, on ); + + autogroup_delete_member_from_group( op, NULL, NULL, age ); + autogroup_delete_group( agi, age ); + + autogroup_add_group( op, agi, group_agd, NULL, &op->o_req_ndn, 1, 1); + + ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); + return SLAP_CB_CONTINUE; + } + } + + ldap_pvt_thread_mutex_unlock( &age->age_mutex ); + break; + } + + ldap_pvt_thread_mutex_unlock( &age->age_mutex ); + } + + overlay_entry_release_ov( op, e, 0, on ); + ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); + return SLAP_CB_CONTINUE; + } + } + + /* When modifying any of the attributes of an entry, we must + check if the entry is in any of our groups, and if + the modified entry maches any of the filters of that group. + + If the entry exists in a group, but the modified attributes do + not match any of the group's filters, we delete the entry from that group. + If the entry doesn't exist in a group, but matches a filter, + we add it to that group. + */ + attrs = attrs_dup( e->e_attrs ); + overlay_entry_release_ov( op, e, 0, on ); + etmp.e_name = op->o_req_dn; + etmp.e_nname = op->o_req_ndn; + etmp.e_attrs = attrs; + odn = op->o_dn; + ondn = op->o_ndn; + op->o_dn = op->o_bd->be_rootdn; + op->o_ndn = op->o_bd->be_rootndn; + + for ( age = agi->agi_entry ; age ; age = age->age_next ) { + is_olddn = 0; + is_newdn = 0; + + ldap_pvt_thread_mutex_lock( &age->age_mutex ); + + if ( age->age_filter && age->age_filter->agf_anlist ) { + ea = attrs_find( attrs, age->age_filter->agf_anlist[0].an_desc ); + } + else { + ea = NULL; + } + + if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) != + LDAP_SUCCESS || group == NULL ) { + Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n", + age->age_dn.bv_val, 0, 0); + + attrs_free( attrs ); + ldap_pvt_thread_mutex_unlock( &age->age_mutex ); + ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); + op->o_dn = odn; + op->o_ndn = ondn; + return SLAP_CB_CONTINUE; + } + + a = attrs_find( group->e_attrs, age->age_def->agd_member_ad ); + + if ( a != NULL ) { + if ( value_find_ex( age->age_def->agd_member_ad, + SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | + SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, + a->a_nvals, ea ? ea->a_nvals : &op->o_req_ndn, op->o_tmpmemctx ) == 0 ) + { + is_olddn = 1; + } + + } + + overlay_entry_release_ov( op, group, 0, on ); + + for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) { + if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) { + if ( test_filter( op, &etmp, agf->agf_filter ) == LDAP_COMPARE_TRUE ) { + is_newdn = 1; + break; + } + } + } + + if ( is_olddn == 1 && is_newdn == 0 ) { + if(ea) + autogroup_delete_member_values_from_group( op, &op->o_req_dn, age, ea ); + else + autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age ); + } else + if ( is_olddn == 0 && is_newdn == 1 ) { + if(ea) + autogroup_add_member_values_to_group( op, &op->o_req_dn, age, ea ); + else + autogroup_add_member_to_group( op, &op->o_req_dn, &op->o_req_ndn, age ); + } + + ldap_pvt_thread_mutex_unlock( &age->age_mutex ); + } + + op->o_dn = odn; + op->o_ndn = ondn; + attrs_free( attrs ); + + ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); + } + } + + return SLAP_CB_CONTINUE; +} + +/* +** Detect if filter contains a memberOf check for dn +*/ +static int +autogroup_memberOf_filter( Filter *f, BerValue *dn, AttributeDescription *memberof_ad ) +{ + int result = 0; + if ( f == NULL ) return 0; + + switch ( f->f_choice & SLAPD_FILTER_MASK ) { + case LDAP_FILTER_AND: + case LDAP_FILTER_OR: + case LDAP_FILTER_NOT: + for ( f = f->f_un.f_un_complex; f && !result; f = f->f_next ) { + result = result || autogroup_memberOf_filter( f, dn, memberof_ad ); + } + break; + case LDAP_FILTER_EQUALITY: + result = ( f->f_ava->aa_desc == memberof_ad && + ber_bvcmp( &f->f_ava->aa_value, dn ) == 0 ); + break; + default: + break; + } + + return result; +} + +/* +** When modifing a group, we must deny any modifications to the member attribute, +** because the group would be inconsistent. +*/ +static int +autogroup_modify_entry( Operation *op, SlapReply *rs) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private; + autogroup_def_t *agd = agi->agi_def; + autogroup_entry_t *age; + Entry *e; + Attribute *a; + struct berval odn, ondn; + OpExtra *oex; + + LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) { + if ( oex->oe_key == (void *)&autogroup ) + return SLAP_CB_CONTINUE; + } + + Debug( LDAP_DEBUG_TRACE, "==> autogroup_modify_entry <%s>\n", op->o_req_dn.bv_val, 0, 0); + ldap_pvt_thread_mutex_lock( &agi->agi_mutex ); + + if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) != + LDAP_SUCCESS || e == NULL ) { + Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0); + ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); + return SLAP_CB_CONTINUE; + } + + odn = op->o_dn; + ondn = op->o_ndn; + op->o_dn = op->o_bd->be_rootdn; + op->o_ndn = op->o_bd->be_rootndn; + + /* Must refresh groups if a matching member value is modified OR filter contains memberOf=DN */ + for ( age = agi->agi_entry; age ; age = age->age_next ) { + autogroup_filter_t *agf; + for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) { + if ( agf->agf_anlist ) { + Modifications *m; + for ( m = op->orm_modlist ; m ; m = m->sml_next ) { + if ( m->sml_desc == agf->agf_anlist[0].an_desc ) { + if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) { + int rc = test_filter( op, e, agf->agf_filter ); + if ( rc == LDAP_COMPARE_TRUE ) { + age->age_mustrefresh = 1; + } + } + } + } + } + + if ( autogroup_memberOf_filter( agf->agf_filter, &op->o_req_ndn, agi->agi_memberof_ad ) ) { + age->age_mustrefresh = 1; + } + } + } + op->o_dn = odn; + op->o_ndn = ondn; + + a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass ); + + if ( a == NULL ) { + Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0); + ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); + return SLAP_CB_CONTINUE; + } + + + for ( ; agd; agd = agd->agd_next ) { + + if ( value_find_ex( slap_schema.si_ad_objectClass, + SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | + SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, + a->a_nvals, &agd->agd_oc->soc_cname, + op->o_tmpmemctx ) == 0 ) + { + Modifications *m; + int match = 1; + + m = op->orm_modlist; + + for ( age = agi->agi_entry ; age ; age = age->age_next ) { + dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn ); + + if ( match == 0 ) { + for ( ; m ; m = m->sml_next ) { + if ( m->sml_desc == age->age_def->agd_member_ad ) { + overlay_entry_release_ov( op, e, 0, on ); + ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); + Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry attempted to modify group's <%s> member attribute\n", op->o_req_dn.bv_val, 0, 0); + send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, "attempt to modify dynamic group member attribute"); + return LDAP_CONSTRAINT_VIOLATION; + } + } + break; + } + } + + /* an entry may only have one dynamic group class */ + break; + } + } + + overlay_entry_release_ov( op, e, 0, on ); + ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); + return SLAP_CB_CONTINUE; +} + +/* +** Detect if the olddn is part of a group and so if the group should be refreshed +*/ +static int +autogroup_modrdn_entry( Operation *op, SlapReply *rs) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private; + autogroup_entry_t *age; + Entry *e; + struct berval odn, ondn; + OpExtra *oex; + + LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) { + if ( oex->oe_key == (void *)&autogroup ) + return SLAP_CB_CONTINUE; + } + + Debug( LDAP_DEBUG_TRACE, "==> autogroup_modrdn_entry <%s>\n", op->o_req_dn.bv_val, 0, 0); + ldap_pvt_thread_mutex_lock( &agi->agi_mutex ); + + if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) != + LDAP_SUCCESS || e == NULL ) { + Debug( LDAP_DEBUG_TRACE, "autogroup_modrdn_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0); + ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); + return SLAP_CB_CONTINUE; + } + + odn = op->o_dn; + ondn = op->o_ndn; + op->o_dn = op->o_bd->be_rootdn; + op->o_ndn = op->o_bd->be_rootndn; + + /* Must check if a dn is modified */ + for ( age = agi->agi_entry; age ; age = age->age_next ) { + autogroup_filter_t *agf; + for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) { + if ( agf->agf_anlist ) { + if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) { + int rc = test_filter( op, e, agf->agf_filter ); + if ( rc == LDAP_COMPARE_TRUE ) { + age->age_modrdn_olddnmodified = 1; + } + } + } + } + } + op->o_dn = odn; + op->o_ndn = ondn; + + overlay_entry_release_ov( op, e, 0, on ); + ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); + return SLAP_CB_CONTINUE; +} + +/* +** Builds a filter for searching for the +** group entries, according to the objectClass. +*/ +static int +autogroup_build_def_filter( autogroup_def_t *agd, Operation *op ) +{ + char *ptr; + + Debug( LDAP_DEBUG_TRACE, "==> autogroup_build_def_filter\n", 0, 0, 0); + + op->ors_filterstr.bv_len = STRLENOF( "(=)" ) + + slap_schema.si_ad_objectClass->ad_cname.bv_len + + agd->agd_oc->soc_cname.bv_len; + ptr = op->ors_filterstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len + 1, op->o_tmpmemctx ); + *ptr++ = '('; + ptr = lutil_strcopy( ptr, slap_schema.si_ad_objectClass->ad_cname.bv_val ); + *ptr++ = '='; + ptr = lutil_strcopy( ptr, agd->agd_oc->soc_cname.bv_val ); + *ptr++ = ')'; + *ptr = '\0'; + + op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val ); + + assert( op->ors_filterstr.bv_len == ptr - op->ors_filterstr.bv_val ); + + return 0; +} + +enum { + AG_ATTRSET = 1, + AG_MEMBER_OF_AD, + AG_LAST +}; + +static ConfigDriver ag_cfgen; + +static ConfigTable agcfg[] = { + { "autogroup-attrset", "group-oc> <URL-ad> <member-ad", + 4, 4, 0, ARG_MAGIC|AG_ATTRSET, ag_cfgen, + "( OLcfgCtAt:2.1 NAME 'olcAGattrSet' " + "DESC 'Automatic groups: <group objectClass>, <URL attributeDescription>, <member attributeDescription>' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString " + "X-ORDERED 'VALUES' )", + NULL, NULL }, + + { "autogroup-memberof-ad", "memberOf attribute", + 2, 2, 0, ARG_MAGIC|AG_MEMBER_OF_AD, ag_cfgen, + "( OLcfgCtAt:2.2 NAME 'olcAGmemberOfAd' " + "DESC 'memberOf attribute' " + "SYNTAX OMsDirectoryString SINGLE-VALUE )", + NULL, NULL }, + + { NULL, NULL, 0, 0, 0, ARG_IGNORED } +}; + +static ConfigOCs agocs[] = { + { "( OLcfgCtOc:2.1 " + "NAME 'olcAutomaticGroups' " + "DESC 'Automatic groups configuration' " + "SUP olcOverlayConfig " + "MAY ( " + "olcAGattrSet " + "$ olcAGmemberOfAd " + ")" + ")", + Cft_Overlay, agcfg, NULL, NULL }, + { NULL, 0, NULL } +}; + + +static int +ag_cfgen( ConfigArgs *c ) +{ + slap_overinst *on = (slap_overinst *)c->bi; + autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private; + autogroup_def_t *agd; + autogroup_entry_t *age; + + int rc = 0, i; + + Debug( LDAP_DEBUG_TRACE, "==> autogroup_cfgen\n", 0, 0, 0); + + if( agi == NULL ) { + agi = (autogroup_info_t*)ch_calloc( 1, sizeof(autogroup_info_t) ); + ldap_pvt_thread_mutex_init( &agi->agi_mutex ); + agi->agi_def = NULL; + agi->agi_entry = NULL; + on->on_bi.bi_private = (void *)agi; + } + + agd = agi->agi_def; + age = agi->agi_entry; + + if ( c->op == SLAP_CONFIG_EMIT ) { + + switch( c->type ){ + case AG_ATTRSET: + for ( i = 0 ; agd ; i++, agd = agd->agd_next ) { + struct berval bv; + char *ptr = c->cr_msg; + + assert(agd->agd_oc != NULL); + assert(agd->agd_member_url_ad != NULL); + assert(agd->agd_member_ad != NULL); + + ptr += snprintf( c->cr_msg, sizeof( c->cr_msg ), + SLAP_X_ORDERED_FMT "%s %s %s", i, + agd->agd_oc->soc_cname.bv_val, + agd->agd_member_url_ad->ad_cname.bv_val, + agd->agd_member_ad->ad_cname.bv_val ); + + bv.bv_val = c->cr_msg; + bv.bv_len = ptr - bv.bv_val; + value_add_one ( &c->rvalue_vals, &bv ); + + } + break; + + case AG_MEMBER_OF_AD: + if ( agi->agi_memberof_ad != NULL ){ + value_add_one( &c->rvalue_vals, &agi->agi_memberof_ad->ad_cname ); + } + break; + + default: + assert( 0 ); + return 1; + } + + return rc; + + }else if ( c->op == LDAP_MOD_DELETE ) { + if ( c->valx < 0) { + autogroup_def_t *agd_next; + autogroup_entry_t *age_next; + autogroup_filter_t *agf = age->age_filter, + *agf_next; + + for ( agd_next = agd; agd_next; agd = agd_next ) { + agd_next = agd->agd_next; + + ch_free( agd ); + } + + for ( age_next = age ; age_next ; age = age_next ) { + age_next = age->age_next; + + ch_free( age->age_dn.bv_val ); + ch_free( age->age_ndn.bv_val ); + + for( agf_next = agf ; agf_next ; agf = agf_next ){ + agf_next = agf->agf_next; + + filter_free( agf->agf_filter ); + ch_free( agf->agf_filterstr.bv_val ); + ch_free( agf->agf_dn.bv_val ); + ch_free( agf->agf_ndn.bv_val ); + anlist_free( agf->agf_anlist, 1, NULL ); + ch_free( agf ); + } + + ldap_pvt_thread_mutex_init( &age->age_mutex ); + ch_free( age ); + } + + ch_free( agi ); + on->on_bi.bi_private = NULL; + + } else { + autogroup_def_t **agdp; + autogroup_entry_t *age_next, *age_prev; + autogroup_filter_t *agf, + *agf_next; + + for ( i = 0, agdp = &agi->agi_def; + i < c->valx; i++ ) + { + if ( *agdp == NULL) { + return 1; + } + agdp = &(*agdp)->agd_next; + } + + agd = *agdp; + *agdp = agd->agd_next; + + for ( age_next = age , age_prev = NULL ; age_next ; age_prev = age, age = age_next ) { + age_next = age->age_next; + + if( age->age_def == agd ) { + agf = age->age_filter; + + ch_free( age->age_dn.bv_val ); + ch_free( age->age_ndn.bv_val ); + + for ( agf_next = agf; agf_next ; agf = agf_next ) { + agf_next = agf->agf_next; + filter_free( agf->agf_filter ); + ch_free( agf->agf_filterstr.bv_val ); + ch_free( agf->agf_dn.bv_val ); + ch_free( agf->agf_ndn.bv_val ); + anlist_free( agf->agf_anlist, 1, NULL ); + ch_free( agf ); + } + + ldap_pvt_thread_mutex_destroy( &age->age_mutex ); + ch_free( age ); + + age = age_prev; + + if( age_prev != NULL ) { + age_prev->age_next = age_next; + } + } + } + + ch_free( agd ); + agd = agi->agi_def; + + } + + return rc; + } + + switch(c->type){ + case AG_ATTRSET: { + autogroup_def_t **agdp, + *agd_next = NULL; + ObjectClass *oc = NULL; + AttributeDescription *member_url_ad = NULL, + *member_ad = NULL; + const char *text; + + + oc = oc_find( c->argv[ 1 ] ); + if( oc == NULL ){ + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": " + "unable to find ObjectClass \"%s\"", + c->argv[ 1 ] ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", + c->log, c->cr_msg, 0 ); + return 1; + } + + + rc = slap_str2ad( c->argv[ 2 ], &member_url_ad, &text ); + if( rc != LDAP_SUCCESS ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": " + "unable to find AttributeDescription \"%s\"", + c->argv[ 2 ] ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", + c->log, c->cr_msg, 0 ); + return 1; + } + + if( !is_at_subtype( member_url_ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": " + "AttributeDescription \"%s\" ", + "must be of a subtype \"labeledURI\"", + c->argv[ 2 ] ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", + c->log, c->cr_msg, 0 ); + return 1; + } + + rc = slap_str2ad( c->argv[3], &member_ad, &text ); + if( rc != LDAP_SUCCESS ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": " + "unable to find AttributeDescription \"%s\"", + c->argv[ 3 ] ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", + c->log, c->cr_msg, 0 ); + return 1; + } + + for ( agdp = &agi->agi_def ; *agdp ; agdp = &(*agdp)->agd_next ) { + /* The same URL attribute / member attribute pair + * cannot be repeated */ + + if ( (*agdp)->agd_member_url_ad == member_url_ad && (*agdp)->agd_member_ad == member_ad ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": " + "URL attributeDescription \"%s\" already mapped", + member_ad->ad_cname.bv_val ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", + c->log, c->cr_msg, 0 ); +/* return 1; //warning*/ + } + } + + if ( c->valx > 0 ) { + int i; + + for ( i = 0, agdp = &agi->agi_def ; + i < c->valx; i++ ) + { + if ( *agdp == NULL ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": " + "invalid index {%d}", + c->valx ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", + c->log, c->cr_msg, 0 ); + + return 1; + } + agdp = &(*agdp)->agd_next; + } + agd_next = *agdp; + + } else { + for ( agdp = &agi->agi_def; *agdp; + agdp = &(*agdp)->agd_next ) + /* goto last */; + } + + *agdp = (autogroup_def_t *)ch_calloc( 1, sizeof(autogroup_info_t)); + + (*agdp)->agd_oc = oc; + (*agdp)->agd_member_url_ad = member_url_ad; + (*agdp)->agd_member_ad = member_ad; + (*agdp)->agd_next = agd_next; + + } break; + + case AG_MEMBER_OF_AD: { + AttributeDescription *memberof_ad = NULL; + const char *text; + + rc = slap_str2ad( c->argv[ 1 ], &memberof_ad, &text ); + if( rc != LDAP_SUCCESS ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "\"autogroup-memberof-ad <memberof-ad>\": " + "unable to find AttributeDescription \"%s\"", + c->argv[ 1 ] ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", + c->log, c->cr_msg, 0 ); + return 1; + } + + if ( !is_at_syntax( memberof_ad->ad_type, SLAPD_DN_SYNTAX ) /* e.g. "member" */ + && !is_at_syntax( memberof_ad->ad_type, SLAPD_NAMEUID_SYNTAX ) ) /* e.g. "uniqueMember" */ + { + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "memberof attribute=\"%s\" must either " + "have DN (%s) or nameUID (%s) syntax", + c->argv[ 1 ], SLAPD_DN_SYNTAX, SLAPD_NAMEUID_SYNTAX ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", + c->log, c->cr_msg, 0 ); + return 1; + } + + agi->agi_memberof_ad = memberof_ad; + + } break; + + default: + rc = 1; + break; + } + + return rc; +} + +extern int slapMode; + +/* +** Do a search for all the groups in the +** database, and add them to out internal list. +*/ +static int +autogroup_db_open( + BackendDB *be, + ConfigReply *cr ) +{ + slap_overinst *on = (slap_overinst *) be->bd_info; + autogroup_info_t *agi = on->on_bi.bi_private; + autogroup_def_t *agd; + autogroup_sc_t ags; + Operation *op; + slap_callback cb = { 0 }; + + void *thrctx = ldap_pvt_thread_pool_context(); + Connection conn = { 0 }; + OperationBuffer opbuf; + + Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_open\n", 0, 0, 0); + + if ( agi == NULL || !( slapMode & SLAP_SERVER_MODE )) { + return 0; + } + + connection_fake_init( &conn, &opbuf, thrctx ); + op = &opbuf.ob_op; + + op->ors_attrsonly = 0; + op->o_tag = LDAP_REQ_SEARCH; + op->o_dn = be->be_rootdn; + op->o_ndn = be->be_rootndn; + + op->o_req_dn = be->be_suffix[0]; + op->o_req_ndn = be->be_nsuffix[0]; + + op->ors_scope = LDAP_SCOPE_SUBTREE; + op->ors_deref = LDAP_DEREF_NEVER; + op->ors_limit = NULL; + op->ors_tlimit = SLAP_NO_LIMIT; + op->ors_slimit = SLAP_NO_LIMIT; + op->ors_attrs = slap_anlist_no_attrs; + op->o_do_not_cache = 1; + + op->o_bd = be; + op->o_bd->bd_info = (BackendInfo *)on->on_info; + + ags.ags_info = agi; + cb.sc_private = &ags; + cb.sc_response = autogroup_group_add_cb; + cb.sc_cleanup = NULL; + cb.sc_next = NULL; + + op->o_callback = &cb; + + for (agd = agi->agi_def ; agd ; agd = agd->agd_next) { + SlapReply rs = { REP_RESULT }; + + autogroup_build_def_filter(agd, op); + + ags.ags_def = agd; + + op->o_bd->be_search( op, &rs ); + + filter_free_x( op, op->ors_filter, 1 ); + op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx ); + } + + if( ! agi->agi_memberof_ad ){ + int rc; + const char *text = NULL; + + rc = slap_str2ad( SLAPD_MEMBEROF_ATTR, &agi->agi_memberof_ad, &text ); + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, "autogroup_db_open: " + "unable to find attribute=\"%s\": %s (%d)\n", + SLAPD_MEMBEROF_ATTR, text, rc ); + return rc; + } + } + + return 0; +} + +static int +autogroup_db_close( + BackendDB *be, + ConfigReply *cr ) +{ + slap_overinst *on = (slap_overinst *) be->bd_info; + + Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_close\n", 0, 0, 0); + + if ( on->on_bi.bi_private ) { + autogroup_info_t *agi = on->on_bi.bi_private; + autogroup_entry_t *age = agi->agi_entry, + *age_next; + autogroup_filter_t *agf, *agf_next; + + for ( age_next = age; age_next; age = age_next ) { + age_next = age->age_next; + + ch_free( age->age_dn.bv_val ); + ch_free( age->age_ndn.bv_val ); + + agf = age->age_filter; + + for ( agf_next = agf; agf_next; agf = agf_next ) { + agf_next = agf->agf_next; + + filter_free( agf->agf_filter ); + ch_free( agf->agf_filterstr.bv_val ); + ch_free( agf->agf_dn.bv_val ); + ch_free( agf->agf_ndn.bv_val ); + anlist_free( agf->agf_anlist, 1, NULL ); + ch_free( agf ); + } + + ldap_pvt_thread_mutex_destroy( &age->age_mutex ); + ch_free( age ); + } + } + + return 0; +} + +static int +autogroup_db_destroy( + BackendDB *be, + ConfigReply *cr ) +{ + slap_overinst *on = (slap_overinst *) be->bd_info; + + Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_destroy\n", 0, 0, 0); + + if ( on->on_bi.bi_private ) { + autogroup_info_t *agi = on->on_bi.bi_private; + autogroup_def_t *agd = agi->agi_def, + *agd_next; + + for ( agd_next = agd; agd_next; agd = agd_next ) { + agd_next = agd->agd_next; + + ch_free( agd ); + } + + ldap_pvt_thread_mutex_destroy( &agi->agi_mutex ); + ch_free( agi ); + } + + return 0; +} + +static +int +autogroup_initialize(void) +{ + int rc = 0; + autogroup.on_bi.bi_type = "autogroup"; + + autogroup.on_bi.bi_db_open = autogroup_db_open; + autogroup.on_bi.bi_db_close = autogroup_db_close; + autogroup.on_bi.bi_db_destroy = autogroup_db_destroy; + + autogroup.on_bi.bi_op_add = autogroup_add_entry; + autogroup.on_bi.bi_op_delete = autogroup_delete_entry; + autogroup.on_bi.bi_op_modify = autogroup_modify_entry; + autogroup.on_bi.bi_op_modrdn = autogroup_modrdn_entry; + + autogroup.on_response = autogroup_response; + + autogroup.on_bi.bi_cf_ocs = agocs; + + rc = config_register_schema( agcfg, agocs ); + if ( rc ) { + return rc; + } + + return overlay_register( &autogroup ); +} + +int +init_module( int argc, char *argv[] ) +{ + return autogroup_initialize(); +} diff --git a/contrib/slapd-modules/autogroup/slapo-autogroup.5 b/contrib/slapd-modules/autogroup/slapo-autogroup.5 new file mode 100644 index 0000000..c2ed916 --- /dev/null +++ b/contrib/slapd-modules/autogroup/slapo-autogroup.5 @@ -0,0 +1,102 @@ +.TH SLAPO-AUTOGROUP 5 "RELEASEDATE" "OpenLDAP LDVERSION" +.\" Copyright 1998-2021 The OpenLDAP Foundation All Rights Reserved. +.\" Portions Copyright \[u00A9] 2007 Michał Szulczyński. +.\" Copying restrictions apply. See the COPYRIGHT file. +.\" $OpenLDAP$ +.SH NAME +\FCslapo-autogroup\FT \- automatic updates of group memberships which meet the +requirements of any filter contained in the group definition. +.SH SYNOPSIS +In \FCslapd.conf\FT: + ... + \FCinclude ETCDIR/schema/dyngroup.schema\FT + ... + \FCmoduleload autogroup.so\FT + ... + \FCdatabase\FT ... + ... + \FCoverlay autogroup\FT + \FCautogroup-attrset groupOfURLs memberURL member\FT +.SH DESCRIPTION +The +.B autogroup +overlay to +.BR slapd (8) +allows automated updates of group memberships which meet the requirements +of any filter contained in the group definition. The filters are built from +LDAP URI-valued attributes. Any time an object is added/deleted/updated, it is +tested for compliance with the filters, and its membership is accordingly +updated. For searches and compares, it behaves like a static group. +If the attribute part of the URI is filled, the group entry is populated by +the values of this attribute in the entries resulting from the search. +.SH CONFIGURATION +Either +.BR \FCslapd.conf\FT (5) +or the \FCcn=config\FT methodology of +.BR \FCslapd-config\FT (5) +may be used for configuring autogroup. Both syntaxes are provided +here for convenience: +.TP +.B \FCautogroup-attrset\FT <group-oc> <URL-ad> <member-ad> +.TP +.B \FColcAGattrSet:\FT <group-oc> <URL-ad> <member-ad> +This defines the objectclass-attribute-URI mappings defining the +automatically managed groups, and may appear multiple times. + +The value <group-oc> is the name of the objectClass that represents +the group. + +The value <URL-ad> is the name of the attributeDescription that +contains the URI that is converted to the filters. If no URI is +present, there will be no members in that group. It must be a subtype +of labeledURI. + +The value <member-ad> is the name of the attributeDescription that +specifies the member attribute. User modification of this attribute is +disabled for consistency. +.TP +.B \FCautogroup-memberof-ad\FT <memberof-ad> +.TP +.B \FColcAGmemberOfAd\FT <memberof-ad> +This defines the attribute that is used by the memberOf overlay to +store the names of groups that an entry is member of; it must be +DN-valued. It should be set to the same value as +memberof-memberof-ad. It defaults to 'memberOf'. +.SH EXAMPLES +As above in SYNOPSIS, or with memberof: + + ... + \FCinclude ETCDIR/schema/dyngroup.schema\FT + \FCinclude ETCDIR/schema/memberof.schema\FT + ... + \FCmoduleload autogroup.so\FT + \FCmoduleload memberof.so\FT + ... + \FCdatabase\FT ... + ... + \FCoverlay memberof\FT + \FCmemberof-memberof-ad\FT foo + ... + \FCoverlay autogroup\FT + \FCautogroup-attrset groupOfURLs memberURL member\FT + \FCautogroup-memberof-ad\FT foo +.SH CAVEATS +As with static groups, update operations on groups with a large number +of members may be slow. If the attribute part of the URI is specified, +modify and delete operations are more difficult to handle. In these +cases the overlay will try to detect if groups have been modified and +then simply refresh them. This can cause performance hits if the +search specified by the URI deals with a significant number of +entries. +.SH ACKNOWLEDGEMENTS +This module was originally written in 2007 by Michał +Szulczyński. Further enhancements were contributed by Howard +Chu, Raphael Ouazana, Norbert Pueschel, and Christian Manal. Manpage +updates provided by Emily Backes. +.SH SEE ALSO +.BR slapd.conf (5), +.BR slapd (8). +.SH Copyrights +Copyright 1998-2021 The OpenLDAP Foundation. +Portions Copyright \[u00A9] 2007 Michał Szulczyński. +All rights reserved. diff --git a/contrib/slapd-modules/cloak/Makefile b/contrib/slapd-modules/cloak/Makefile new file mode 100644 index 0000000..424e3b7 --- /dev/null +++ b/contrib/slapd-modules/cloak/Makefile @@ -0,0 +1,46 @@ +# $OpenLDAP$ + +LDAP_SRC = ../../.. +LDAP_BUILD = $(LDAP_SRC) +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +CC = gcc +OPT = -g -O2 -Wall +DEFS = -DSLAPD_OVER_CLOAK=SLAPD_MOD_DYNAMIC +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) + +PROGRAMS = cloak.la +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +cloak.la: cloak.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + diff --git a/contrib/slapd-modules/cloak/cloak.c b/contrib/slapd-modules/cloak/cloak.c new file mode 100644 index 0000000..7045354 --- /dev/null +++ b/contrib/slapd-modules/cloak/cloak.c @@ -0,0 +1,354 @@ +/* cloak.c - Overlay to hide some attribute except if explicitely requested */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2008-2021 The OpenLDAP Foundation. + * Portions Copyright 2008 Emmanuel Dreyfus + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This work was originally developed by the Emmanuel Dreyfus for + * inclusion in OpenLDAP Software. + */ + +#include "portable.h" + +#ifdef SLAPD_OVER_CLOAK + +#include <stdio.h> + +#include "ac/string.h" +#include "ac/socket.h" + +#include "lutil.h" +#include "slap.h" +#include "config.h" + +enum { CLOAK_ATTR = 1 }; + +typedef struct cloak_info_t { + ObjectClass *ci_oc; + AttributeDescription *ci_ad; + struct cloak_info_t *ci_next; +} cloak_info_t; + +#define CLOAK_USAGE "\"cloak-attr <attr> [<class>]\": " + +static int +cloak_cfgen( ConfigArgs *c ) +{ + slap_overinst *on = (slap_overinst *)c->bi; + cloak_info_t *ci = (cloak_info_t *)on->on_bi.bi_private; + + int rc = 0, i; + + if ( c->op == SLAP_CONFIG_EMIT ) { + switch( c->type ) { + case CLOAK_ATTR: + for ( i = 0; ci; i++, ci = ci->ci_next ) { + struct berval bv; + int len; + + assert( ci->ci_ad != NULL ); + + if ( ci->ci_oc != NULL ) + len = snprintf( c->cr_msg, + sizeof( c->cr_msg ), + SLAP_X_ORDERED_FMT "%s %s", i, + ci->ci_ad->ad_cname.bv_val, + ci->ci_oc->soc_cname.bv_val ); + else + len = snprintf( c->cr_msg, + sizeof( c->cr_msg ), + SLAP_X_ORDERED_FMT "%s", i, + ci->ci_ad->ad_cname.bv_val ); + + bv.bv_val = c->cr_msg; + bv.bv_len = len; + value_add_one( &c->rvalue_vals, &bv ); + } + break; + + default: + rc = 1; + break; + } + + return rc; + + } else if ( c->op == LDAP_MOD_DELETE ) { + cloak_info_t *ci_next; + + switch( c->type ) { + case CLOAK_ATTR: + for ( ci_next = ci, i = 0; + ci_next, c->valx < 0 || i < c->valx; + ci = ci_next, i++ ){ + + ci_next = ci->ci_next; + + ch_free ( ci->ci_ad ); + if ( ci->ci_oc != NULL ) + ch_free ( ci->ci_oc ); + + ch_free( ci ); + } + ci = (cloak_info_t *)on->on_bi.bi_private; + break; + + default: + rc = 1; + break; + } + + return rc; + } + + switch( c->type ) { + case CLOAK_ATTR: { + ObjectClass *oc = NULL; + AttributeDescription *ad = NULL; + const char *text; + cloak_info_t **cip = NULL; + cloak_info_t *ci_next = NULL; + + if ( c->argc == 3 ) { + oc = oc_find( c->argv[ 2 ] ); + if ( oc == NULL ) { + snprintf( c->cr_msg, + sizeof( c->cr_msg ), + CLOAK_USAGE + "unable to find ObjectClass \"%s\"", + c->argv[ 2 ] ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", + c->log, c->cr_msg, 0 ); + return 1; + } + } + + rc = slap_str2ad( c->argv[ 1 ], &ad, &text ); + if ( rc != LDAP_SUCCESS ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), CLOAK_USAGE + "unable to find AttributeDescription \"%s\"", + c->argv[ 1 ] ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", + c->log, c->cr_msg, 0 ); + return 1; + } + + for ( i = 0, cip = (cloak_info_t **)&on->on_bi.bi_private; + c->valx < 0 || i < c->valx, *cip; + i++, cip = &(*cip)->ci_next ) { + if ( c->valx >= 0 && *cip == NULL ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), + CLOAK_USAGE + "invalid index {%d}\n", + c->valx ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", + c->log, c->cr_msg, 0 ); + return 1; + } + ci_next = *cip; + } + + *cip = (cloak_info_t *)SLAP_CALLOC( 1, sizeof( cloak_info_t ) ); + (*cip)->ci_oc = oc; + (*cip)->ci_ad = ad; + (*cip)->ci_next = ci_next; + + rc = 0; + break; + } + + default: + rc = 1; + break; + } + + return rc; +} + +static int +cloak_search_response_cb( Operation *op, SlapReply *rs ) +{ + slap_callback *sc; + cloak_info_t *ci; + Entry *e = NULL; + Entry *me = NULL; + + assert( op && op->o_callback && rs ); + + if ( rs->sr_type != REP_SEARCH || !rs->sr_entry ) { + return ( SLAP_CB_CONTINUE ); + } + + sc = op->o_callback; + e = rs->sr_entry; + + /* + * First perform a quick scan for an attribute to cloak + */ + for ( ci = (cloak_info_t *)sc->sc_private; ci; ci = ci->ci_next ) { + Attribute *a; + + if ( ci->ci_oc != NULL && + !is_entry_objectclass_or_sub( e, ci->ci_oc ) ) + continue; + + for ( a = e->e_attrs; a; a = a->a_next ) + if ( a->a_desc == ci->ci_ad ) + break; + + if ( a != NULL ) + break; + } + + /* + * Nothing found to cloak + */ + if ( ci == NULL ) + return ( SLAP_CB_CONTINUE ); + + /* + * We are now committed to cloak an attribute. + */ + rs_entry2modifiable( op, rs, (slap_overinst *) op->o_bd->bd_info ); + me = rs->sr_entry; + + for ( ci = (cloak_info_t *)sc->sc_private; ci; ci = ci->ci_next ) { + Attribute *a; + Attribute *pa; + + for ( pa = NULL, a = me->e_attrs; + a; + pa = a, a = a->a_next ) { + + if ( a->a_desc != ci->ci_ad ) + continue; + + Debug( LDAP_DEBUG_TRACE, "cloak_search_response_cb: cloak %s\n", + a->a_desc->ad_cname.bv_val, + 0, 0 ); + + if ( pa != NULL ) + pa->a_next = a->a_next; + else + me->e_attrs = a->a_next; + + attr_clean( a ); + } + + } + + return ( SLAP_CB_CONTINUE ); +} + +static int +cloak_search_cleanup_cb( Operation *op, SlapReply *rs ) +{ + if ( rs->sr_type == REP_RESULT || rs->sr_err != LDAP_SUCCESS ) { + slap_freeself_cb( op, rs ); + } + + return SLAP_CB_CONTINUE; +} + +static int +cloak_search( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + cloak_info_t *ci = (cloak_info_t *)on->on_bi.bi_private; + slap_callback *sc; + + if ( op->ors_attrsonly || + op->ors_attrs || + get_manageDSAit( op ) ) + return SLAP_CB_CONTINUE; + + sc = op->o_tmpcalloc( 1, sizeof( *sc ), op->o_tmpmemctx ); + sc->sc_response = cloak_search_response_cb; + sc->sc_cleanup = cloak_search_cleanup_cb; + sc->sc_next = op->o_callback; + sc->sc_private = ci; + op->o_callback = sc; + + return SLAP_CB_CONTINUE; +} + +static slap_overinst cloak_ovl; + +static ConfigTable cloakcfg[] = { + { "cloak-attr", "attribute [class]", + 2, 3, 0, ARG_MAGIC|CLOAK_ATTR, cloak_cfgen, + "( OLcfgCtAt:4.1 NAME 'olcCloakAttribute' " + "DESC 'Cloaked attribute: attribute [class]' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString " + "X-ORDERED 'VALUES' )", + NULL, NULL }, + { NULL, NULL, 0, 0, 0, ARG_IGNORED } +}; + +static int +cloak_db_destroy( + BackendDB *be, + ConfigReply *cr ) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + cloak_info_t *ci = (cloak_info_t *)on->on_bi.bi_private; + + for ( ; ci; ) { + cloak_info_t *tmp = ci; + ci = ci->ci_next; + SLAP_FREE( tmp ); + } + + on->on_bi.bi_private = NULL; + + return 0; +} + +static ConfigOCs cloakocs[] = { + { "( OLcfgCtOc:4.1 " + "NAME 'olcCloakConfig' " + "DESC 'Attribute cloak configuration' " + "SUP olcOverlayConfig " + "MAY ( olcCloakAttribute ) )", + Cft_Overlay, cloakcfg }, + { NULL, 0, NULL } +}; + +#if SLAPD_OVER_CLOAK == SLAPD_MOD_DYNAMIC +static +#endif +int +cloak_initialize( void ) { + int rc; + cloak_ovl.on_bi.bi_type = "cloak"; + cloak_ovl.on_bi.bi_db_destroy = cloak_db_destroy; + cloak_ovl.on_bi.bi_op_search = cloak_search; + cloak_ovl.on_bi.bi_cf_ocs = cloakocs; + + rc = config_register_schema ( cloakcfg, cloakocs ); + if ( rc ) + return rc; + + return overlay_register( &cloak_ovl ); +} + +#if SLAPD_OVER_CLOAK == SLAPD_MOD_DYNAMIC +int init_module(int argc, char *argv[]) { + return cloak_initialize(); +} +#endif + +#endif /* defined(SLAPD_OVER_CLOAK) */ + diff --git a/contrib/slapd-modules/cloak/slapo-cloak.5 b/contrib/slapd-modules/cloak/slapo-cloak.5 new file mode 100644 index 0000000..3d4c992 --- /dev/null +++ b/contrib/slapd-modules/cloak/slapo-cloak.5 @@ -0,0 +1,82 @@ +.TH SLAPO-CLOAK 5 "RELEASEDATE" "OpenLDAP LDVERSION" +.\" Copyright 1998-2021 The OpenLDAP Foundation, All Rights Reserved. +.\" Copying restrictions apply. See the COPYRIGHT file. +.\" $OpenLDAP$ +.SH NAME +slapo-cloak \- Attribute cloak overlay to slapd +.SH SYNOPSIS +ETCDIR/slapd.conf +.SH DESCRIPTION +The +.B cloak +overlay to +.BR slapd (8) +allows the server to hide specific attributes, unless explicitely requested +by the client. This improve performance when a client requests all attributes +and get a huge binary attribute that is of no interest for it. +This behavior is disabled when the \fImanageDSAit\fP +control (RFC 3296) is used. + +.SH CONFIGURATION +The config directives that are specific to the +.B cloak +overlay must be prefixed by +.BR cloak\- , +to avoid potential conflicts with directives specific to the underlying +database or to other stacked overlays. + +.TP +.B overlay cloak +This directive adds the cloak overlay to the current database, +or to the frontend, if used before any database instantiation; see +.BR slapd.conf (5) +for details. + +.LP +This +.B slapd.conf +configuration option is defined for the cloak overlay. It may have multiple +occurrences, and it must appear after the +.B overlay +directive: +.TP +.B cloak-attr <attribute> [<class>] +The value +.B <attribute> +is the name of the attribute that will be cloaked. + +The optional +.B <class> +restricts cloaking only to entries of the named +.B <class>. + +.SH EXAMPLE +This example hide the +.B jpegPhoto +attribute. Add the following to slapd.conf: + +.LP +.nf + database <database> + # ... + + overlay cloak + cloak-attr jpegPhoto +.fi +.LP +and that slapd loads cloak.la, if compiled as a run-time module; + +.SH FILES +.TP +ETCDIR/slapd.conf +default slapd configuration file +.SH SEE ALSO +.BR slapd.conf (5), +.BR slapd (8). +The +.BR slapo-cloak (5) +overlay supports dynamic configuration via +.BR back-config . +.SH ACKNOWLEDGEMENTS +.P +This module was originally written in 2008 by Emmanuel Dreyfus. diff --git a/contrib/slapd-modules/comp_match/Makefile b/contrib/slapd-modules/comp_match/Makefile new file mode 100644 index 0000000..f34f579 --- /dev/null +++ b/contrib/slapd-modules/comp_match/Makefile @@ -0,0 +1,69 @@ +# $OpenLDAP$ +# This work is part of OpenLDAP Software <http://www.openldap.org/>. +# +# Copyright 2003-2021 The OpenLDAP Foundation. +# Portions Copyright 2004 by IBM Corporation. +# All rights reserved. + +# Copyright 2004 Sang Seok Lim, IBM Corp. All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted only as authorized by the OpenLDAP +# Public License. +# +# A copy of this license is available in the file LICENSE in the +# top-level directory of the distribution or, alternatively, at +# <http://www.OpenLDAP.org/license.html>. + +LDAP_SRC = ../../.. +LDAP_BUILD = $(LDAP_SRC) +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +SNACC_DIR = ../$(LDAP_SRC)/snacc +SNACC_INC = -I$(SNACC_DIR) -I$(SNACC_DIR)/c-lib/inc +SNACC_LIB = $(SNACC_DIR)/c-lib/libcasn1.a + +SSL_DIR = /usr/local +SSL_INC = -I$(SSL_DIR)/include/openssl +SSL_LIB = -lcrypto -L$(SSL_DIR)/lib + +LIBTOOL = $(LDAP_BUILD)/libtool +CC = gcc +OPT = -g -O2 -Wall +DEFS = -DLDAP_COMPONENT +INCS = $(LDAP_INC) $(SNACC_INC) $(SSL_INC) +LIBS = $(LDAP_LIB) $(SNACC_LIB) $(SSL_LIB) + +PROGRAMS = compmatch.la +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +compmatch.la: componentlib.lo init.lo certificate.lo asn_to_syn_mr.lo authorityKeyIdentifier.lo crl.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + diff --git a/contrib/slapd-modules/comp_match/README b/contrib/slapd-modules/comp_match/README new file mode 100644 index 0000000..133757c --- /dev/null +++ b/contrib/slapd-modules/comp_match/README @@ -0,0 +1,127 @@ +Copyright 2004 Sang Seok Lim, IBM . All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted only as authorized +by the OpenLDAP Public License. + +A copy of this license is available in the file LICENSE in +the top-level directory of the distribution or, alternatively, +at <http://www.OpenLDAP.org/license.html>. + +This directory contains a Component Matching module and +a X.509 Certificate example. In order to understand Component +Matching, see RFC 3687 and +http://www.openldap.org/conf/odd-sandiego-2004/Sangseok.pdf + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +A) Brief introduction about files in this directory +%%%%%%%%%%55%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +1) init.c +module_init() and functions which are dynamically linked +into the main slapd codes. + +2) componentlib.c and componentlib.h +GSER and BER decoder library of each primitive ASN.1 type. +They use component representation to store ASN.1 values. + +3) certificate.c/.h authorityKeyIdentifier.c/.h +eSNACC generated BER and GSER decoder routines of the X.509 +certificate specification and one of its extensions, +authorityKeyIdentifier. + +4) asn_to_syn_mr.c asn.h +An mapping table from ASN.1 types to corresponding Syntaxes, +matching rules, and component description in slapd. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +B) How to use Component Matching on X.509 certificates +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +1) be sure to configure slapd with enable-modules on. +2) install the GSER-support eSNACC compiler. You can find +only in www.openldap.org. At least, you need the library +(libcasn1.a) and header files for compiling this module. +3) modify Makefile accordingly. then run make. +you will get compmatch.la and other necessary files in ./libs +4) modify slapd.conf to include the following module command + moduleload <path to>compmatch.la +5) run slapd and perform search operations against +the attribute, userCertificate. You need to read through +RFC 3687 in order to understand how to compose component +filters. +Ex) component search filter examples +"(userCertificate:componentFilterMatch:=item:{ component +\"toBeSigned.serialNumber\", rule integerMatch, value 2 })" +You can find more examples in "test031-component-filter" +in the OpenLDAP source directory. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +C) How to add a new ASN.1 syntax +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +1) download and install the eSNACC compiler supporting +Component Matching. You can find the compiler only in +www.openldap.org. Before compiling, be sure to define +the "LDAP_COMPONENT" macro to obtain component +supported version of C library and back-ends of eSNACC. +Otherwise compiled library will fail to be linked to +the module. +2) using eSNACC, compile your ASN.1 specifications and +copy the generated .c and .h files to this directory +Ex) +$ esnacc -E BER_COMP -E GSER -t -d -f example.asn +For Component Matching, set BOTH BER_COMP and GSER on. +After compiling, you will get example.c and example.h +3) modify example.c accordingly, seeing certificate.c +and certificate.asn as a reference. +- add init_module_xxx() located in generated .c file +into init_module() in init.c. +- modify the arguments of InstallOidDecoderMapping(...) +accordingly +- in the generated .c file, you need to write +"DecComponentxxxTop(...)" function for yourself. +You can copy BDecComponentCertificateTop in the +generated .c file and modify it accordingly. +4) register a new attribute syntax with a new OID +in a schema file +5) then goto 3) of B) section. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +D) How to configure Component Indexing +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +You can generate indices on each component of +a given attribute whose values are in either GSER or +BER. Currently primitive ASN.1 types, DN, and RDN +can be indexed for equality matching in BDB. +In order to generate indices, put following line +in the slapd configuration file, slapd.conf. + +index [attribute name].[component reference] eq + +Ex) +index userCertificate eq +index userCertificate.toBeSigned.issuer.rdnSequence eq +index userCertificate.toBeSigned.serialNumber eq +index userCertificate.toBeSigned.version eq + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +D) How to configure Attribute Alias +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +If your client is unable to use component filters, +attribute aliasing can be used instead. Attribute +Alias maps a virtual attribute type to an attribute +component and a component matching rule. +You can create your own aliases by following steps. + +1) register aliasing attributes in the schema file. +Sample aliasing attributes are in test.schema. +2) compose component filters for aliasing attributes +and put them in "preprocessed_comp_filter" array +in "init.c". +3) add "add_aa_entry" function calls in +"init_attribute_aliasing_table()" in "init.c" +4) perform searching against the aliasing attribute +Ex) +"(x509CertificateIssuer:distinguishedNameMatch= +cn=ray,L=yorktown,o=ibm,c=us)" diff --git a/contrib/slapd-modules/comp_match/asn.h b/contrib/slapd-modules/comp_match/asn.h new file mode 100644 index 0000000..de63c0a --- /dev/null +++ b/contrib/slapd-modules/comp_match/asn.h @@ -0,0 +1,57 @@ +/* Copyright 2004 IBM Corporation + * All rights reserved. + * Redisribution and use in source and binary forms, with or without + * modification, are permitted only as authorizd by the OpenLADP + * Public License. + */ +/* ACKNOWLEDGEMENTS + * This work originally developed by Sang Seok Lim + * 2004/06/18 03:20:00 slim@OpenLDAP.org + */ +#ifndef _H_ASN_MODULE +#define _H_ASN_MODULE + +typedef enum { BER, GSER } EncRulesType; + +typedef enum AsnTypeId { + BASICTYPE_BOOLEAN = 0, + BASICTYPE_INTEGER, + BASICTYPE_BITSTRING, + BASICTYPE_OCTETSTRING, + BASICTYPE_NULL, + BASICTYPE_OID, + BASICTYPE_REAL, + BASICTYPE_ENUMERATED, + BASICTYPE_NUMERIC_STR, + BASICTYPE_PRINTABLE_STR, + BASICTYPE_UNIVERSAL_STR, + BASICTYPE_IA5_STR, + BASICTYPE_BMP_STR, + BASICTYPE_UTF8_STR, + BASICTYPE_UTCTIME, + BASICTYPE_GENERALIZEDTIME, + BASICTYPE_GRAPHIC_STR, + BASICTYPE_VISIBLE_STR, + BASICTYPE_GENERAL_STR, + BASICTYPE_OBJECTDESCRIPTOR, + BASICTYPE_VIDEOTEX_STR, + BASICTYPE_T61_STR, + BASICTYPE_OCTETCONTAINING, + BASICTYPE_BITCONTAINING, + BASICTYPE_RELATIVE_OID, /* 25 */ + BASICTYPE_ANY, + /* Embedded Composite Types*/ + COMPOSITE_ASN1_TYPE, + /* A New ASN.1 types including type reference */ + RDNSequence, + RelativeDistinguishedName, + TelephoneNumber, + FacsimileTelephoneNumber__telephoneNumber, + DirectoryString, + /* Newly Defined ASN.1 Type, Manually registered */ + ASN_COMP_CERTIFICATE, + /* ASN.1 Type End */ + ASNTYPE_END +} AsnTypeId; + +#endif diff --git a/contrib/slapd-modules/comp_match/asn_to_syn_mr.c b/contrib/slapd-modules/comp_match/asn_to_syn_mr.c new file mode 100644 index 0000000..e7e1ee7 --- /dev/null +++ b/contrib/slapd-modules/comp_match/asn_to_syn_mr.c @@ -0,0 +1,282 @@ +#include <component.h> +#include "asn.h" +#include "componentlib.h" +#include "certificate.h" + +AsnTypetoMatchingRuleTable directory_component_matching_table[] = { + "1.2.36.79672281.1.13.7", +{ + { BASICTYPE_BOOLEAN,NULL,"1.3.6.1.4.1.1466.115.121.1.7", NULL }, + { BASICTYPE_INTEGER,NULL ,"1.3.6.1.4.1.1466.115.121.1.27", NULL }, + { BASICTYPE_BITSTRING,NULL ,"1.3.6.1.4.1.1466.115.121.1.6", NULL }, + { BASICTYPE_OCTETSTRING,NULL , "1.3.6.1.4.1.1466.115.121.1.40", NULL }, + { BASICTYPE_NULL,NULL , NULL, NULL }, + { BASICTYPE_OID,NULL ,"1.3.6.1.4.1.1466.115.121.1.38", NULL }, + { BASICTYPE_REAL,NULL , NULL, NULL }, + { BASICTYPE_ENUMERATED,NULL , NULL, NULL }, + { BASICTYPE_NUMERIC_STR, "numericStringMatch", "1.3.6.1.4.1.1466.115.121.1.36", NULL }, + { BASICTYPE_PRINTABLE_STR, "caseIgnoreMatch", "1.3.6.1.4.1.1466.115.121.1.44", NULL }, + { BASICTYPE_UNIVERSAL_STR, "caseIgnoreMatch" , NULL, NULL }, + { BASICTYPE_IA5_STR, "caseIgnoreMatch", "1.3.6.1.4.1.1466.115.121.1.26", NULL }, + { BASICTYPE_BMP_STR, "caseIgnoreMatch" , NULL, NULL }, + { BASICTYPE_UTF8_STR, "caseIgnoreMatch" , NULL, NULL }, + { BASICTYPE_UTCTIME, "uTCTimeMatch" , "1.3.6.1.4.1.1466.115.121.1.53", NULL }, + { BASICTYPE_GENERALIZEDTIME, "generalizedTimeMatch" ,"1.3.6.1.4.1.1466.115.121.1.24", NULL }, + { BASICTYPE_GRAPHIC_STR, "caseIgnoreMatch", NULL, NULL }, + { BASICTYPE_VISIBLE_STR, "caseIgnoreMatch", NULL, NULL }, + { BASICTYPE_GENERAL_STR, "caseIgnoreMatch", NULL, NULL }, + { BASICTYPE_OBJECTDESCRIPTOR, NULL , NULL, NULL }, + { BASICTYPE_VIDEOTEX_STR, "caseIgnoreMatch", NULL, NULL }, + { BASICTYPE_T61_STR, "caseIgnoreMatch", NULL, NULL }, + { BASICTYPE_OCTETCONTAINING, NULL , NULL, NULL }, + { BASICTYPE_BITCONTAINING, NULL , NULL, NULL }, + { BASICTYPE_RELATIVE_OID, NULL, "1.2.36.79672281.1.5.0", NULL }, + { RDNSequence, "distinguishedNameMatch" , NULL, NULL }, + { RelativeDistinguishedName, NULL , NULL, NULL }, + { TelephoneNumber, "telephoneNumberMatch" , "1.3.6.1.4.1.1466.115.121.1.50", NULL }, + { FacsimileTelephoneNumber__telephoneNumber, "telephoneNumberMatch","1.3.6.1.4.1.1466.115.121.1.22", NULL }, + { DirectoryString, "caseIgnoreMatch" ,"1.3.6.1.4.1.1466.115.121.1.15", NULL }, + { ASN_COMP_CERTIFICATE, NULL , "1.2.36.79672281.1.5.2" , NULL }, + { ASNTYPE_END , NULL , NULL, NULL } +}, + NULL +}; + +AsnTypetoSyntax asn_to_syntax_mapping_tbl[] = { +{ BASICTYPE_BOOLEAN,"Boolean","1.3.6.1.4.1.1466.115.121.1.7", NULL }, +{ BASICTYPE_INTEGER,"Integer","1.3.6.1.4.1.1466.115.121.1.27", NULL }, +{ BASICTYPE_BITSTRING,"Bit String","1.3.6.1.4.1.1466.115.121.1.6", NULL }, +{ BASICTYPE_OCTETSTRING,"Octet String", "1.3.6.1.4.1.1466.115.121.1.40", NULL }, +{ BASICTYPE_NULL,NULL, NULL, NULL }, +{ BASICTYPE_OID,"OID","1.3.6.1.4.1.1466.115.121.1.38", NULL }, +{ BASICTYPE_REAL,NULL, NULL, NULL }, +{ BASICTYPE_ENUMERATED,"Integer", "1.3.6.1.4.1.1466.115.121.1.27", NULL }, +{ BASICTYPE_NUMERIC_STR, "Numeric String", "1.3.6.1.4.1.1466.115.121.1.36", NULL }, +{ BASICTYPE_PRINTABLE_STR, "Printable String", "1.3.6.1.4.1.1466.115.121.1.44", NULL }, +{ BASICTYPE_UNIVERSAL_STR, NULL , NULL, NULL }, +{ BASICTYPE_IA5_STR, "IA5 String", "1.3.6.1.4.1.1466.115.121.1.26", NULL }, +{ BASICTYPE_BMP_STR, NULL , NULL, NULL }, +{ BASICTYPE_UTF8_STR, "Directory String" , "1.3.6.1.4.1.1466.115.121.1.15", NULL }, +{ BASICTYPE_UTCTIME, "UTC Time" , "1.3.6.1.4.1.1466.115.121.1.53", NULL }, +{ BASICTYPE_GENERALIZEDTIME, "Generalized Time" ,"1.3.6.1.4.1.1466.115.121.1.24", NULL }, +{ BASICTYPE_GRAPHIC_STR, NULL, NULL, NULL }, +{ BASICTYPE_VISIBLE_STR, "Directory String", "1.3.6.1.4.1.1466.115.121.1.15", NULL }, +{ BASICTYPE_GENERAL_STR, NULL, NULL, NULL }, +{ BASICTYPE_OBJECTDESCRIPTOR, "Object Class Description", "1.3.6.1.4.1.1466.115.121.1.37", NULL }, +{ BASICTYPE_VIDEOTEX_STR, NULL, NULL, NULL }, +{ BASICTYPE_T61_STR, NULL, NULL, NULL }, +{ BASICTYPE_OCTETCONTAINING, NULL , NULL, NULL }, +{ BASICTYPE_BITCONTAINING, NULL , NULL, NULL }, +{ BASICTYPE_RELATIVE_OID, "OID", "1.3.6.1.4.1.1466.115.121.1.38", NULL }, +{ BASICTYPE_ANY, NULL, NULL, NULL }, +{ COMPOSITE_ASN1_TYPE, NULL , NULL, NULL }, +{ RDNSequence, "Distinguished Name" , "1.3.6.1.4.1.1466.115.121.1.12", NULL }, +{ RelativeDistinguishedName, "RDN", "1.2.36.79672281.1.5.0", NULL }, +{ TelephoneNumber, "Telephone Number" , "1.3.6.1.4.1.1466.115.121.1.50", NULL }, +{ FacsimileTelephoneNumber__telephoneNumber, "Facsimile Telephone Number","1.3.6.1.4.1.1466.115.121.1.22", NULL }, +{ DirectoryString, "Directory String" ,"1.3.6.1.4.1.1466.115.121.1.15", NULL }, +{ ASN_COMP_CERTIFICATE, "componentCertificate", "1.2.36.79672281.1.5.2" , NULL }, +{ ASNTYPE_END , NULL , NULL, NULL } +}; + +/* + * This table describes relationship between an ASN.1 type and its + * potential matching rules such as equality, approx, ordering, and substring + * Based on the description of this table, the following ComponentType + * table is initialized + */ +AsnTypetoCompMatchingRule asntype_to_compMR_mapping_tbl[] = { +{ BASICTYPE_BOOLEAN, "booleanMatch", NULL, NULL, NULL }, +{ BASICTYPE_INTEGER, "integerMatch", NULL, "integerOrderingMatch", NULL }, +{ BASICTYPE_BITSTRING, "bitStringMatch", NULL, NULL, NULL }, +{ BASICTYPE_OCTETSTRING, "octetStringMatch", NULL, "octetStringOrderingMatch", NULL }, +{ BASICTYPE_NULL, NULL, NULL, NULL, NULL }, +{ BASICTYPE_OID, "objectIdentifierMatch", NULL, NULL, NULL }, +{ BASICTYPE_REAL, NULL, NULL, NULL, NULL }, +{ BASICTYPE_ENUMERATED, "integerMatch", NULL, "integerOrderingMatch", NULL }, +{ BASICTYPE_NUMERIC_STR, "numericStringMatch", NULL, "numericStringOrderingMatch", "numericStringSubstringsMatch"}, +{ BASICTYPE_PRINTABLE_STR, "caseIgnoreMatch", "directoryStringApproxMatch", "caseIgnoreOrderingMatch", "caseIgnoreSubstringsMatch" }, +{ BASICTYPE_UNIVERSAL_STR, "caseIgnoreMatch", "directoryStringApproxMatch", "caseIgnoreOrderingMatch", "caseIgnoreSubstringsMatch" }, +{ BASICTYPE_IA5_STR, "caseIgnoreMatch", "IA5StringApproxMatch", "caseIgnoreOrderingMatch", "caseIgnoreSubstringsMatch" }, +{ BASICTYPE_BMP_STR, "caseIgnoreMatch", "directoryStringApproxMatch", "caseIgnoreOrderingMatch", "caseIgnoreSubstringsMatch" }, +{ BASICTYPE_UTF8_STR, "caseIgnoreMatch", "directoryStringApproxMatch", "caseIgnoreOrderingMatch", "caseIgnoreSubstringsMatch" }, +{ BASICTYPE_UTCTIME, NULL, NULL, NULL, NULL }, +{ BASICTYPE_GENERALIZEDTIME, NULL, NULL, NULL, NULL }, +{ BASICTYPE_GRAPHIC_STR, NULL, NULL, NULL, NULL }, +{ BASICTYPE_VISIBLE_STR, "caseIgnoreMatch", "directoryStringApproxMatch", "caseIgnoreOrderingMatch", "caseIgnoreSubstringsMatch" }, +{ BASICTYPE_GENERAL_STR, NULL, NULL, NULL, NULL }, +{ BASICTYPE_OBJECTDESCRIPTOR, "objectIdentifierFirstComponentMatch", NULL, NULL, NULL }, +{ BASICTYPE_VIDEOTEX_STR, NULL, NULL, NULL, NULL }, +{ BASICTYPE_T61_STR, NULL, NULL, NULL, NULL }, +{ BASICTYPE_OCTETCONTAINING, NULL, NULL, NULL, NULL }, +{ BASICTYPE_BITCONTAINING, NULL, NULL, NULL, NULL }, +{ BASICTYPE_RELATIVE_OID, "objectIdentifierFirstComponentMatch", NULL, NULL, NULL }, +{ BASICTYPE_ANY, NULL, NULL, NULL, NULL }, +{ COMPOSITE_ASN1_TYPE, NULL, NULL, NULL, NULL }, +{ RDNSequence, "distinguishedNameMatch", NULL, NULL, NULL }, +{ RelativeDistinguishedName, "rdnMatch" , NULL, NULL, NULL }, +{ TelephoneNumber, NULL, NULL, NULL, NULL }, +{ FacsimileTelephoneNumber__telephoneNumber, "caseIgnoreMatch", "directoryStringApproxMatch", "caseIgnoreOrderingMatch", "caseIgnoreSubstringsMatch" }, +{ DirectoryString, "caseIgnoreMatch", "directoryStringApproxMatch", "caseIgnoreOrderingMatch", "caseIgnoreSubstringsMatch"}, +{ ASN_COMP_CERTIFICATE, "componentFilterMatch", NULL, NULL, NULL }, +{ ASNTYPE_END, NULL, NULL, NULL, NULL } +}; + +/* + * This table mapps an ASN type to a corresponding ComponentType which has + * equivalent contents of an existing AttributeType + */ +AsnTypetoCompType asntype_to_compType_mapping_tbl[] = { +{ BASICTYPE_BOOLEAN,{}}, +{ BASICTYPE_INTEGER, {}}, +{ BASICTYPE_BITSTRING, {}}, +{ BASICTYPE_OCTETSTRING, {}}, +{ BASICTYPE_NULL, {}}, +{ BASICTYPE_OID, {}}, +{ BASICTYPE_REAL, {}}, +{ BASICTYPE_ENUMERATED, {}}, +{ BASICTYPE_NUMERIC_STR, {}}, +{ BASICTYPE_PRINTABLE_STR, {}}, +{ BASICTYPE_UNIVERSAL_STR, {}}, +{ BASICTYPE_IA5_STR, {}}, +{ BASICTYPE_BMP_STR, {}}, +{ BASICTYPE_UTF8_STR, {}}, +{ BASICTYPE_UTCTIME, {}}, +{ BASICTYPE_GENERALIZEDTIME, {}}, +{ BASICTYPE_GRAPHIC_STR, {}}, +{ BASICTYPE_VISIBLE_STR, {}}, +{ BASICTYPE_GENERAL_STR,{}}, +{ BASICTYPE_OBJECTDESCRIPTOR, {}}, +{ BASICTYPE_VIDEOTEX_STR, {}}, +{ BASICTYPE_T61_STR, {}}, +{ BASICTYPE_OCTETCONTAINING, {}}, +{ BASICTYPE_BITCONTAINING, {}}, +{ BASICTYPE_RELATIVE_OID, {}}, +{ BASICTYPE_ANY, {}}, +{ COMPOSITE_ASN1_TYPE, {}}, +{ RDNSequence, {}}, +{ RelativeDistinguishedName, {}}, +{ TelephoneNumber, {}}, +{ FacsimileTelephoneNumber__telephoneNumber, {}}, +{ DirectoryString, {}}, +{ ASN_COMP_CERTIFICATE, {}}, +{ ASNTYPE_END , {}} +}; + +AsnTypetoCompDesc asntype_to_compdesc_mapping_tbl[] = { +{ BASICTYPE_BOOLEAN, { -1, NULL, {},{},0,ASN_BASIC,BASICTYPE_BOOLEAN, + (encoder_func*)NULL,(encoder_func*)GEncComponentBool,(encoder_func*)NULL, + (gser_decoder_func*)GDecComponentBool,(ber_decoder_func*)BDecComponentBool, + (comp_free_func*)NULL,(extract_component_from_id_func*)NULL,MatchingComponentBool}}, +{ BASICTYPE_INTEGER, { -1, NULL, {},{},0,ASN_BASIC,BASICTYPE_INTEGER, + (encoder_func*)NULL,(encoder_func*)GEncComponentInt,(encoder_func*)NULL, + (gser_decoder_func*)GDecComponentInt,(ber_decoder_func*)BDecComponentInt, + (comp_free_func*)NULL,(extract_component_from_id_func*)NULL,MatchingComponentInt}}, +{ BASICTYPE_BITSTRING, { -1, NULL, {},{},0,ASN_BASIC,BASICTYPE_BITSTRING, + (encoder_func*)NULL,(encoder_func*)GEncComponentBits,(encoder_func*)NULL, + (gser_decoder_func*)GDecComponentBits,(ber_decoder_func*)BDecComponentBits, + (comp_free_func*)NULL,(extract_component_from_id_func*)NULL,MatchingComponentBits}}, +{ BASICTYPE_OCTETSTRING, { -1, NULL, {},{},0,ASN_BASIC,BASICTYPE_OCTETSTRING, + (encoder_func*)NULL,(encoder_func*)GEncComponentOcts,(encoder_func*)NULL, + (gser_decoder_func*)GDecComponentOcts,(ber_decoder_func*)BDecComponentOcts, + (comp_free_func*)NULL,(extract_component_from_id_func*)NULL,MatchingComponentOcts}}, +{ BASICTYPE_NULL, { -1, NULL, {},{},0,ASN_BASIC,BASICTYPE_NULL, + (encoder_func*)NULL,(encoder_func*)GEncComponentNull,(encoder_func*)NULL, + (gser_decoder_func*)GDecComponentNull,(ber_decoder_func*)BDecComponentNull, + (comp_free_func*)NULL,(extract_component_from_id_func*)NULL,MatchingComponentNull}}, +{ BASICTYPE_OID, { -1, NULL, {},{},0,ASN_BASIC,BASICTYPE_OID, + (encoder_func*)NULL,(encoder_func*)GEncComponentOid,(encoder_func*)NULL, + (gser_decoder_func*)GDecComponentOid,(ber_decoder_func*)BDecComponentOid, + (comp_free_func*)NULL,(extract_component_from_id_func*)NULL,MatchingComponentOid}}, +{ BASICTYPE_REAL, { -1, NULL, {},{},0,ASN_BASIC,BASICTYPE_REAL, + (encoder_func*)NULL,(encoder_func*)GEncComponentReal,(encoder_func*)NULL, + (gser_decoder_func*)GDecComponentReal,(ber_decoder_func*)BDecComponentReal, + (comp_free_func*)NULL,(extract_component_from_id_func*)NULL,MatchingComponentReal}}, +{ BASICTYPE_ENUMERATED, { -1, NULL, {},{},0,ASN_BASIC,BASICTYPE_ENUMERATED, + (encoder_func*)NULL,(encoder_func*)GEncComponentEnum,(encoder_func*)NULL, + (gser_decoder_func*)GDecComponentEnum,(ber_decoder_func*)BDecComponentEnum, + (comp_free_func*)NULL,(extract_component_from_id_func*)NULL,MatchingComponentEnum}}, +{ BASICTYPE_NUMERIC_STR, { -1, NULL, {},{},0,ASN_BASIC,BASICTYPE_NUMERIC_STR, + (encoder_func*)NULL,(encoder_func*)GEncComponentNumericString,(encoder_func*)NULL, + (gser_decoder_func*)GDecComponentNumericString,(ber_decoder_func*)BDecComponentNumericString, + (comp_free_func*)NULL,(extract_component_from_id_func*)NULL,MatchingComponentNumericString}}, +{ BASICTYPE_PRINTABLE_STR, { -1, NULL, {},{},0,ASN_BASIC,BASICTYPE_PRINTABLE_STR, + (encoder_func*)NULL,(encoder_func*)GEncComponentPrintableString,(encoder_func*)NULL, + (gser_decoder_func*)GDecComponentPrintableString,(ber_decoder_func*)BDecComponentPrintableString, + (comp_free_func*)NULL,(extract_component_from_id_func*)NULL,MatchingComponentPrintableString}}, +{ BASICTYPE_UNIVERSAL_STR, { -1, NULL, {},{},0,ASN_BASIC,BASICTYPE_UNIVERSAL_STR, + (encoder_func*)NULL,(encoder_func*)GEncComponentUniversalString,(encoder_func*)NULL, + (gser_decoder_func*)GDecComponentUniversalString,(ber_decoder_func*)BDecComponentUniversalString, + (comp_free_func*)NULL,(extract_component_from_id_func*)NULL,MatchingComponentUniversalString}}, +{ BASICTYPE_IA5_STR, { -1, NULL, {},{},0,ASN_BASIC,BASICTYPE_IA5_STR, + (encoder_func*)NULL,(encoder_func*)GEncComponentIA5String,(encoder_func*)NULL, + (gser_decoder_func*)GDecComponentIA5String,(ber_decoder_func*)BDecComponentIA5String, + (comp_free_func*)NULL,(extract_component_from_id_func*)NULL,MatchingComponentIA5String}}, +{ BASICTYPE_BMP_STR, { -1, NULL, {},{},0,ASN_BASIC,BASICTYPE_BMP_STR, + (encoder_func*)NULL,(encoder_func*)GEncComponentBMPString,(encoder_func*)NULL, + (gser_decoder_func*)GDecComponentBMPString,(ber_decoder_func*)BDecComponentBMPString, + (comp_free_func*)NULL,(extract_component_from_id_func*)NULL,MatchingComponentBMPString}}, +{ BASICTYPE_UTF8_STR, { -1, NULL, {},{},0,ASN_BASIC,BASICTYPE_UTF8_STR, + (encoder_func*)NULL,(encoder_func*)GEncComponentUTF8String,(encoder_func*)NULL, + (gser_decoder_func*)GDecComponentUTF8String,(ber_decoder_func*)BDecComponentUTF8String, + (comp_free_func*)NULL,(extract_component_from_id_func*)NULL,MatchingComponentUTF8String}}, +{ BASICTYPE_UTCTIME, { -1, NULL, {},{},0,ASN_BASIC,BASICTYPE_UTCTIME, + (encoder_func*)NULL,(encoder_func*)GEncComponentUTCTime,(encoder_func*)NULL, + (gser_decoder_func*)GDecComponentUTCTime,(ber_decoder_func*)BDecComponentUTCTime, + (comp_free_func*)NULL,(extract_component_from_id_func*)NULL,MatchingComponentUTCTime}}, +{ BASICTYPE_GENERALIZEDTIME, { -1, NULL, {},{},0,ASN_BASIC,BASICTYPE_GENERALIZEDTIME, + (encoder_func*)NULL,(encoder_func*)GEncComponentUTCTime,(encoder_func*)NULL, + (gser_decoder_func*)GDecComponentUTCTime,(ber_decoder_func*)BDecComponentUTCTime, + (comp_free_func*)NULL,(extract_component_from_id_func*)NULL,MatchingComponentUTCTime}}, +{ BASICTYPE_GRAPHIC_STR, { -1, NULL, {},{},0,ASN_BASIC,BASICTYPE_GRAPHIC_STR, + (encoder_func*)NULL,(encoder_func*)GEncComponentPrintableString,(encoder_func*)NULL, + (gser_decoder_func*)GDecComponentPrintableString,(ber_decoder_func*)BDecComponentPrintableString, + (comp_free_func*)NULL,(extract_component_from_id_func*)NULL,MatchingComponentPrintableString}}, +{ BASICTYPE_VISIBLE_STR, { -1, NULL, {},{},0,ASN_BASIC,BASICTYPE_VISIBLE_STR, + (encoder_func*)NULL,(encoder_func*)GEncComponentVisibleString,(encoder_func*)NULL, + (gser_decoder_func*)GDecComponentVisibleString,(ber_decoder_func*)BDecComponentVisibleString, + (comp_free_func*)NULL,(extract_component_from_id_func*)NULL,MatchingComponentVisibleString}}, +{ BASICTYPE_GENERAL_STR,{ -1, NULL, {},{},0,ASN_BASIC,BASICTYPE_GENERAL_STR, + (encoder_func*)NULL,(encoder_func*)GEncComponentUTF8String,(encoder_func*)NULL, + (gser_decoder_func*)GDecComponentUTF8String,(ber_decoder_func*)BDecComponentUTF8String, + (comp_free_func*)NULL,(extract_component_from_id_func*)NULL,MatchingComponentUTF8String}}, +{ BASICTYPE_OBJECTDESCRIPTOR, { -1, NULL, {},{},0,ASN_BASIC,BASICTYPE_OBJECTDESCRIPTOR, + (encoder_func*)NULL,(encoder_func*)GEncComponentUTF8String,(encoder_func*)NULL, + (gser_decoder_func*)GDecComponentUTF8String,(ber_decoder_func*)BDecComponentUTF8String, + (comp_free_func*)NULL,(extract_component_from_id_func*)NULL,MatchingComponentUTF8String}}, +{ BASICTYPE_VIDEOTEX_STR, { -1, NULL, {},{},0,ASN_BASIC,BASICTYPE_VIDEOTEX_STR, + (encoder_func*)NULL,(encoder_func*)GEncComponentTeletexString,(encoder_func*)NULL, + (gser_decoder_func*)GDecComponentTeletexString,(ber_decoder_func*)BDecComponentTeletexString, + (comp_free_func*)NULL,(extract_component_from_id_func*)NULL,MatchingComponentTeletexString}}, +{ BASICTYPE_T61_STR, { -1, NULL, {},{},0,ASN_BASIC,BASICTYPE_T61_STR, + (encoder_func*)NULL,(encoder_func*)GEncComponentUTF8String,(encoder_func*)NULL, + (gser_decoder_func*)GDecComponentUTF8String,(ber_decoder_func*)BDecComponentUTF8String, + (comp_free_func*)NULL,(extract_component_from_id_func*)NULL,MatchingComponentUTF8String}}, +{ BASICTYPE_OCTETCONTAINING, { -1, NULL, {},{},0,ASN_BASIC,BASICTYPE_OCTETCONTAINING, + (encoder_func*)NULL,(encoder_func*)NULL,(encoder_func*)NULL, + (gser_decoder_func*)NULL,(ber_decoder_func*)NULL, + (comp_free_func*)NULL,(extract_component_from_id_func*)NULL,NULL}}, +{ BASICTYPE_BITCONTAINING, { -1, NULL, {},{},0,ASN_BASIC,BASICTYPE_BITCONTAINING, + (encoder_func*)NULL,(encoder_func*)NULL,(encoder_func*)NULL, + (gser_decoder_func*)NULL,(ber_decoder_func*)NULL, + (comp_free_func*)NULL,(extract_component_from_id_func*)NULL,NULL}}, +{ BASICTYPE_RELATIVE_OID, { -1, NULL, {},{},0,ASN_BASIC,BASICTYPE_RELATIVE_OID, + (encoder_func*)NULL,(encoder_func*)GEncComponentRelativeOid,(encoder_func*)NULL, + (gser_decoder_func*)GDecComponentRelativeOid,(ber_decoder_func*)BDecComponentRelativeOid, + (comp_free_func*)NULL,(extract_component_from_id_func*)NULL,MatchingComponentRelativeOid}}, +{ BASICTYPE_ANY, {}}, +{ COMPOSITE_ASN1_TYPE, {}}, +{ RDNSequence, { -1, NULL, {},{},0,ASN_COMPOSITE,RDNSequence, + (encoder_func*)ConvertRDNSequence2RFC2253,(encoder_func*)NULL,(encoder_func*)NULL, + (gser_decoder_func*)GDecComponentRDNSequence,(ber_decoder_func*)BDecComponentRDNSequence, + (comp_free_func*)NULL,(extract_component_from_id_func*)NULL,MatchingComponentRDNSequence}}, +{ RelativeDistinguishedName, { -1, NULL, {},{},0,ASN_COMPOSITE,RDNSequence, + (encoder_func*)ConvertRDNSequence2RFC2253,(encoder_func*)NULL,(encoder_func*)NULL, + (gser_decoder_func*)GDecComponentRDNSequence,(ber_decoder_func*)BDecComponentRDNSequence, + (comp_free_func*)NULL,(extract_component_from_id_func*)NULL,MatchingComponentRDNSequence}}, +{ TelephoneNumber, {}}, +{ FacsimileTelephoneNumber__telephoneNumber, {}}, +{ DirectoryString, {}}, +{ ASN_COMP_CERTIFICATE, {}}, +{ ASNTYPE_END , {}} +}; diff --git a/contrib/slapd-modules/comp_match/authorityKeyIdentifier.asn b/contrib/slapd-modules/comp_match/authorityKeyIdentifier.asn new file mode 100644 index 0000000..85ac92d --- /dev/null +++ b/contrib/slapd-modules/comp_match/authorityKeyIdentifier.asn @@ -0,0 +1,65 @@ +AuthorityKeyIdentifierDefinition DEFINITIONS ::=
+BEGIN
+AuthorityKeyIdentifier ::= SEQUENCE {
+ keyIdentifier [0] IMPLICIT KeyIdentifier OPTIONAL,
+ authorityCertIssuer [1] IMPLICIT GeneralNames OPTIONAL,
+ authorityCertSerialNumber [2] IMPLICIT CertificateSerialNumber OPTIONAL }
+ -- authorityCertIssuer and authorityCertSerialNumber MUST both
+ -- be present or both be absent
+
+KeyIdentifier ::= OCTET STRING
+
+CertificateSerialNumber ::= INTEGER
+
+GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
+
+GeneralName ::= CHOICE {
+ otherName [0] OtherName,
+ rfc822Name [1] IA5String,
+ dNSName [2] IA5String,
+ x400Address [3] ORAddress,
+ directoryName [4] Name,
+ ediPartyName [5] EDIPartyName,
+ uniformResourceIdentifier [6] IA5String,
+ iPAddress [7] OCTET STRING,
+ registeredID [8] OBJECT IDENTIFIER }
+
+OtherName ::= SEQUENCE {
+ type-id OBJECT IDENTIFIER,
+ value [0] EXPLICIT ANY DEFINED BY type-id }
+
+EDIPartyName ::= SEQUENCE {
+ nameAssigner [0] DirectoryString OPTIONAL,
+ partyName [1] DirectoryString }
+
+-- following ORAddress may not conform original def. in ASN.1
+ORAddress ::= SEQUENCE {
+-- built-in-standard-attributes BuiltInStandardAttributes,
+ type-id OBJECT IDENTIFIER,
+-- built-in-domain-defined-attributes
+ value ANY DEFINED BY type-id,
+-- BuiltInDomainDefinedAttributes OPTIONAL,
+-- see also teletex-domain-defined-attributes
+--extension-attributes ExtensionAttributes OPTIONAL }
+ extension OCTET STRING OPTIONAL }
+
+
+Name ::= CHOICE {
+ rdnSequence RDNSequence }
+
+RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+
+RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
+
+AttributeTypeAndValue ::= SEQUENCE {
+ type OBJECT IDENTIFIER,
+ value ANY DEFINED BY type}
+
+DirectoryString ::= CHOICE {
+ teletexString TeletexString (SIZE (1..MAX)),
+ printableString PrintableString (SIZE (1..MAX)),
+ universalString UniversalString (SIZE (1..MAX)),
+ utf8String UTF8String (SIZE (1..MAX)),
+ bmpString BMPString (SIZE (1..MAX)) }
+
+END
diff --git a/contrib/slapd-modules/comp_match/authorityKeyIdentifier.c b/contrib/slapd-modules/comp_match/authorityKeyIdentifier.c new file mode 100644 index 0000000..84e83b8 --- /dev/null +++ b/contrib/slapd-modules/comp_match/authorityKeyIdentifier.c @@ -0,0 +1,2058 @@ +/* + * authorityKeyIdentifier.c + * "AuthorityKeyIdentifierDefinition" ASN.1 module encode/decode/extracting/matching/free C src. + * This file was generated by modified eSMACC compiler Wed Dec 8 22:22:49 2004 + * The generated files are supposed to be compiled as a module for OpenLDAP Software + */ + +#include "authorityKeyIdentifier.h" + +BDecComponentAuthorityKeyIdentifierTop( void* mem_op, GenBuf* b, void *v, AsnLen* bytesDecoded,int mode) { + AsnTag tag; + AsnLen elmtLen; + + tag = BDecTag ( b, bytesDecoded ); + elmtLen = BDecLen ( b, bytesDecoded ); + if ( elmtLen <= 0 ) return (-1); + if ( tag != MAKE_TAG_ID (UNIV, CONS, SEQ_TAG_CODE) ) { + return (-1); + } + + return BDecComponentAuthorityKeyIdentifier( mem_op, b, tag, elmtLen, ( ComponentAuthorityKeyIdentifier**)v, (AsnLen*)bytesDecoded, mode ); +} + + +void init_module_AuthorityKeyIdentifierDefinition() { + InstallOidDecoderMapping( "2.5.29.35", NULL, + GDecComponentAuthorityKeyIdentifier, + BDecComponentAuthorityKeyIdentifierTop, + ExtractingComponentAuthorityKeyIdentifier, + MatchingComponentAuthorityKeyIdentifier ); +} + +int +MatchingComponentOtherName ( char* oid, ComponentSyntaxInfo* csi_attr, ComponentSyntaxInfo* csi_assert ) { + int rc; + MatchingRule* mr; + + if ( oid ) { + mr = retrieve_matching_rule( oid, csi_attr->csi_comp_desc->cd_type_id); + if ( mr ) return component_value_match( mr, csi_attr, csi_assert ); + } + + rc = 1; + rc = MatchingComponentOid ( oid, (ComponentSyntaxInfo*)&((ComponentOtherName*)csi_attr)->type_id, (ComponentSyntaxInfo*)&((ComponentOtherName*)csi_assert)->type_id ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + rc = SetAnyTypeByComponentOid ((ComponentSyntaxInfo*)&((ComponentOtherName*)csi_attr)->value, (&((ComponentOtherName*)csi_attr)->type_id)); + rc = MatchingComponentAnyDefinedBy ( oid, (ComponentAny*)&((ComponentOtherName*)csi_attr)->value, (ComponentAny*)&((ComponentOtherName*)csi_assert)->value); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + return LDAP_COMPARE_TRUE; +} /* BMatchingComponentOtherName */ + +void* +ExtractingComponentOtherName ( void* mem_op, ComponentReference* cr, ComponentOtherName *comp ) +{ + + if ( ( comp->type_id.identifier.bv_val && strncmp(comp->type_id.identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->type_id.id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return &comp->type_id; + else + return NULL; + } + if ( ( comp->value.identifier.bv_val && strncmp(comp->value.identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->value.id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return &comp->value; + else + return NULL; + } + return NULL; +} /* ExtractingComponentOtherName */ + +int +BDecComponentOtherName PARAMS ((b, tagId0, elmtLen0, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +AsnTag tagId0 _AND_ +AsnLen elmtLen0 _AND_ +ComponentOtherName **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + int seqDone = FALSE; + AsnLen totalElmtsLen1 = 0; + AsnLen elmtLen1; + AsnTag tagId1; + int mandatoryElmtCount1 = 0; + AsnLen totalElmtsLen2 = 0; + AsnLen elmtLen2; + AsnTag tagId2; + int old_mode = mode; + int rc; + ComponentOtherName *k, *t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + tagId1 = BDecTag (b, &totalElmtsLen1 ); + + if (((tagId1 == MAKE_TAG_ID (UNIV, PRIM, OID_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentOid (mem_op, b, tagId1, elmtLen1, (&k->type_id), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->type_id)->identifier.bv_val = (&k->type_id)->id_buf; + (&k->type_id)->identifier.bv_len = strlen("type_id"); + strcpy( (&k->type_id)->identifier.bv_val, "type_id"); + tagId1 = BDecTag (b, &totalElmtsLen1); + } + else + return -1; + + + + if (((tagId1 == MAKE_TAG_ID (CNTX, CONS, 0)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = SetAnyTypeByComponentOid ((&k->value), (&k->type_id)); + rc = BDecComponentAnyDefinedBy (mem_op,b, (&k->value), &totalElmtsLen1, mode ); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->value)->identifier.bv_val = (&k->value)->id_buf; + (&k->value)->identifier.bv_len = strlen("value"); + strcpy( (&k->value)->identifier.bv_val, "value"); + if (elmtLen1 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + seqDone = TRUE; + if (elmtLen0 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + else if (totalElmtsLen1 != elmtLen0) + return -1; + + } + else + return -1; + + + + if (!seqDone) + return -1; + + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentOtherName*) CompAlloc( mem_op, sizeof(ComponentOtherName) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentOtherName ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentOtherName ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentOtherName; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentOtherName; + (*bytesDecoded) += totalElmtsLen1; + return LDAP_SUCCESS; +} /* BDecOtherName*/ + +int +GDecComponentOtherName PARAMS (( mem_op,b, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +ComponentOtherName **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + char* peek_head,*peek_head2; + int i, strLen,strLen2, rc, old_mode = mode; + ComponentOtherName *k,*t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + *bytesDecoded = 0; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '{'){ + Asn1Error("Missing { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + if ( strncmp( peek_head, "type_id", strlen("type_id") ) == 0 ) { + rc = GDecComponentOid (mem_op, b, (&k->type_id), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->type_id)->identifier.bv_val = peek_head; + (&k->type_id)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "value", strlen("value") ) == 0 ) { + rc = SetAnyTypeByComponentOid ((&k->value), (&k->type_id)); + rc = GDecComponentAnyDefinedBy (mem_op, b, (&k->value), bytesDecoded, mode ); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->value)->identifier.bv_val = peek_head; + (&k->value)->identifier.bv_len = strLen; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ) { + Asn1Error("Error during Reading } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '}'){ + Asn1Error("Missing } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentOtherName*) CompAlloc( mem_op, sizeof(ComponentOtherName) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentOtherName ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentOtherName ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentOtherName; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentOtherName; + return LDAP_SUCCESS; +} /* GDecOtherName*/ + + +int +MatchingComponentORAddress ( char* oid, ComponentSyntaxInfo* csi_attr, ComponentSyntaxInfo* csi_assert ) { + int rc; + MatchingRule* mr; + + if ( oid ) { + mr = retrieve_matching_rule( oid, csi_attr->csi_comp_desc->cd_type_id); + if ( mr ) return component_value_match( mr, csi_attr, csi_assert ); + } + + rc = 1; + rc = MatchingComponentOid ( oid, (ComponentSyntaxInfo*)&((ComponentORAddress*)csi_attr)->type_id, (ComponentSyntaxInfo*)&((ComponentORAddress*)csi_assert)->type_id ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + rc = SetAnyTypeByComponentOid ((ComponentSyntaxInfo*)&((ComponentORAddress*)csi_attr)->value, (&((ComponentORAddress*)csi_attr)->type_id)); + rc = MatchingComponentAnyDefinedBy ( oid, (ComponentAny*)&((ComponentORAddress*)csi_attr)->value, (ComponentAny*)&((ComponentORAddress*)csi_assert)->value); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + rc = MatchingComponentOcts ( oid, (ComponentSyntaxInfo*)&((ComponentORAddress*)csi_attr)->extension, (ComponentSyntaxInfo*)&((ComponentORAddress*)csi_assert)->extension ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + return LDAP_COMPARE_TRUE; +} /* BMatchingComponentORAddress */ + +void* +ExtractingComponentORAddress ( void* mem_op, ComponentReference* cr, ComponentORAddress *comp ) +{ + + if ( ( comp->type_id.identifier.bv_val && strncmp(comp->type_id.identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->type_id.id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return &comp->type_id; + else + return NULL; + } + if ( ( comp->value.identifier.bv_val && strncmp(comp->value.identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->value.id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return &comp->value; + else + return NULL; + } + if ( ( comp->extension.identifier.bv_val && strncmp(comp->extension.identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->extension.id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return &comp->extension; + else + return NULL; + } + return NULL; +} /* ExtractingComponentORAddress */ + +int +BDecComponentORAddress PARAMS ((b, tagId0, elmtLen0, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +AsnTag tagId0 _AND_ +AsnLen elmtLen0 _AND_ +ComponentORAddress **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + int seqDone = FALSE; + AsnLen totalElmtsLen1 = 0; + AsnLen elmtLen1; + AsnTag tagId1; + int mandatoryElmtCount1 = 0; + int old_mode = mode; + int rc; + ComponentORAddress *k, *t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + tagId1 = BDecTag (b, &totalElmtsLen1 ); + + if (((tagId1 == MAKE_TAG_ID (UNIV, PRIM, OID_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentOid (mem_op, b, tagId1, elmtLen1, (&k->type_id), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->type_id)->identifier.bv_val = (&k->type_id)->id_buf; + (&k->type_id)->identifier.bv_len = strlen("type_id"); + strcpy( (&k->type_id)->identifier.bv_val, "type_id"); + } + else + return -1; + + + + { + rc = SetAnyTypeByComponentOid ((&k->value), (&k->type_id)); + rc = BDecComponentAnyDefinedBy (mem_op,b, (&k->value), &totalElmtsLen1, mode ); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->value)->identifier.bv_val = (&k->value)->id_buf; + (&k->value)->identifier.bv_len = strlen("value"); + strcpy( (&k->value)->identifier.bv_val, "value"); + if ((elmtLen0 != INDEFINITE_LEN) && (totalElmtsLen1 == elmtLen0)) + seqDone = TRUE; + else + { + tagId1 = BDecTag (b, &totalElmtsLen1 ); + + if ((elmtLen0 == INDEFINITE_LEN) && (tagId1 == EOC_TAG_ID)) + { + BDEC_2ND_EOC_OCTET (b, &totalElmtsLen1 ) + seqDone = TRUE; + } + } + } + + + if ((!seqDone) && ((tagId1 == MAKE_TAG_ID (UNIV, PRIM, OCTETSTRING_TAG_CODE)) || +(tagId1 == MAKE_TAG_ID (UNIV, CONS, OCTETSTRING_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentOcts (mem_op, b, tagId1, elmtLen1, (&k->extension), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->extension)->identifier.bv_val = (&k->extension)->id_buf; + (&k->extension)->identifier.bv_len = strlen("extension"); + strcpy( (&k->extension)->identifier.bv_val, "extension"); + seqDone = TRUE; + if (elmtLen0 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + else if (totalElmtsLen1 != elmtLen0) + return -1; + + } + + + if (!seqDone) + return -1; + + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentORAddress*) CompAlloc( mem_op, sizeof(ComponentORAddress) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentORAddress ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentORAddress ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentORAddress; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentORAddress; + (*bytesDecoded) += totalElmtsLen1; + return LDAP_SUCCESS; +} /* BDecORAddress*/ + +int +GDecComponentORAddress PARAMS (( mem_op,b, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +ComponentORAddress **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + char* peek_head,*peek_head2; + int i, strLen,strLen2, rc, old_mode = mode; + ComponentORAddress *k,*t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + *bytesDecoded = 0; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '{'){ + Asn1Error("Missing { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + if ( strncmp( peek_head, "type_id", strlen("type_id") ) == 0 ) { + rc = GDecComponentOid (mem_op, b, (&k->type_id), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->type_id)->identifier.bv_val = peek_head; + (&k->type_id)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "value", strlen("value") ) == 0 ) { + rc = SetAnyTypeByComponentOid ((&k->value), (&k->type_id)); + rc = GDecComponentAnyDefinedBy (mem_op, b, (&k->value), bytesDecoded, mode ); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->value)->identifier.bv_val = peek_head; + (&k->value)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "extension", strlen("extension") ) == 0 ) { + rc = GDecComponentOcts (mem_op, b, (&k->extension), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->extension)->identifier.bv_val = peek_head; + (&k->extension)->identifier.bv_len = strLen; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ) { + Asn1Error("Error during Reading } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '}'){ + Asn1Error("Missing } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentORAddress*) CompAlloc( mem_op, sizeof(ComponentORAddress) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentORAddress ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentORAddress ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentORAddress; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentORAddress; + return LDAP_SUCCESS; +} /* GDecORAddress*/ + + +int +MatchingComponentDirectoryString ( char* oid, ComponentSyntaxInfo* csi_attr, ComponentSyntaxInfo* csi_assert ) { + int rc; + MatchingRule* mr; + ComponentDirectoryString *v1, *v2; + + + v1 = (ComponentDirectoryString*)csi_attr; + v2 = (ComponentDirectoryString*)csi_assert; + if ( oid ) { + mr = retrieve_matching_rule( oid, csi_attr->csi_comp_desc->cd_type_id); + if ( mr ) return component_value_match( mr, csi_attr, csi_assert ); + } + + if( (v1->choiceId != v2->choiceId ) ) + return LDAP_COMPARE_FALSE; + switch( v1->choiceId ) + { + case DIRECTORYSTRING_TELETEXSTRING : + rc = MatchingComponentTeletexString ( oid, (ComponentSyntaxInfo*)(v1->a.teletexString), (ComponentSyntaxInfo*)(v2->a.teletexString) ); + break; + case DIRECTORYSTRING_PRINTABLESTRING : + rc = MatchingComponentPrintableString ( oid, (ComponentSyntaxInfo*)(v1->a.printableString), (ComponentSyntaxInfo*)(v2->a.printableString) ); + break; + case DIRECTORYSTRING_UNIVERSALSTRING : + rc = MatchingComponentUniversalString ( oid, (ComponentSyntaxInfo*)(v1->a.universalString), (ComponentSyntaxInfo*)(v2->a.universalString) ); + break; + case DIRECTORYSTRING_UTF8STRING : + rc = MatchingComponentUTF8String ( oid, (ComponentSyntaxInfo*)(v1->a.utf8String), (ComponentSyntaxInfo*)(v2->a.utf8String) ); + break; + case DIRECTORYSTRING_BMPSTRING : + rc = MatchingComponentBMPString ( oid, (ComponentSyntaxInfo*)(v1->a.bmpString), (ComponentSyntaxInfo*)(v2->a.bmpString) ); + break; + default : + return LDAP_PROTOCOL_ERROR; + } + return rc; +} /* BMatchingComponentDirectoryStringContent */ + +void* +ExtractingComponentDirectoryString ( void* mem_op, ComponentReference* cr, ComponentDirectoryString *comp ) +{ + + + if( (comp->choiceId) == DIRECTORYSTRING_TELETEXSTRING && + (( comp->a.teletexString->identifier.bv_val && strncmp(comp->a.teletexString->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0) || + ( strncmp(comp->a.teletexString->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0))) { + if ( cr->cr_curr->ci_next == NULL ) + return (comp->a.teletexString); + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentTeletexString ( mem_op, cr, (comp->a.teletexString) ); + }; + } + if( (comp->choiceId) == DIRECTORYSTRING_PRINTABLESTRING && + (( comp->a.printableString->identifier.bv_val && strncmp(comp->a.printableString->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0) || + ( strncmp(comp->a.printableString->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0))) { + if ( cr->cr_curr->ci_next == NULL ) + return (comp->a.printableString); + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentPrintableString ( mem_op, cr, (comp->a.printableString) ); + }; + } + if( (comp->choiceId) == DIRECTORYSTRING_UNIVERSALSTRING && + (( comp->a.universalString->identifier.bv_val && strncmp(comp->a.universalString->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0) || + ( strncmp(comp->a.universalString->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0))) { + if ( cr->cr_curr->ci_next == NULL ) + return (comp->a.universalString); + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentUniversalString ( mem_op, cr, (comp->a.universalString) ); + }; + } + if( (comp->choiceId) == DIRECTORYSTRING_UTF8STRING && + (( comp->a.utf8String->identifier.bv_val && strncmp(comp->a.utf8String->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0) || + ( strncmp(comp->a.utf8String->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0))) { + if ( cr->cr_curr->ci_next == NULL ) + return (comp->a.utf8String); + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentUTF8String ( mem_op, cr, (comp->a.utf8String) ); + }; + } + if( (comp->choiceId) == DIRECTORYSTRING_BMPSTRING && + (( comp->a.bmpString->identifier.bv_val && strncmp(comp->a.bmpString->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0) || + ( strncmp(comp->a.bmpString->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0))) { + if ( cr->cr_curr->ci_next == NULL ) + return (comp->a.bmpString); + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentBMPString ( mem_op, cr, (comp->a.bmpString) ); + }; + } + return NULL; +} /* ExtractingComponentDirectoryString */ + +int +BDecComponentDirectoryString PARAMS ((b, tagId0, elmtLen0, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +AsnTag tagId0 _AND_ +AsnLen elmtLen0 _AND_ +ComponentDirectoryString **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + int seqDone = FALSE; + AsnLen totalElmtsLen1 = 0; + AsnLen elmtLen1; + AsnTag tagId1; + int mandatoryElmtCount1 = 0; + int old_mode = mode; + int rc; + ComponentDirectoryString *k, *t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + switch (tagId0) + { + case MAKE_TAG_ID (UNIV, PRIM, TELETEXSTRING_TAG_CODE): + case MAKE_TAG_ID (UNIV, CONS, TELETEXSTRING_TAG_CODE): + (k->choiceId) = DIRECTORYSTRING_TELETEXSTRING; + rc = BDecComponentTeletexString (mem_op, b, tagId0, elmtLen0, (&k->a.teletexString), &totalElmtsLen1, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.teletexString)->identifier.bv_val = (k->a.teletexString)->id_buf; + (k->a.teletexString)->identifier.bv_len = strlen("teletexString"); + strcpy( (k->a.teletexString)->identifier.bv_val, "teletexString"); + break; + + case MAKE_TAG_ID (UNIV, PRIM, PRINTABLESTRING_TAG_CODE): + case MAKE_TAG_ID (UNIV, CONS, PRINTABLESTRING_TAG_CODE): + (k->choiceId) = DIRECTORYSTRING_PRINTABLESTRING; + rc = BDecComponentPrintableString (mem_op, b, tagId0, elmtLen0, (&k->a.printableString), &totalElmtsLen1, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.printableString)->identifier.bv_val = (k->a.printableString)->id_buf; + (k->a.printableString)->identifier.bv_len = strlen("printableString"); + strcpy( (k->a.printableString)->identifier.bv_val, "printableString"); + break; + + case MAKE_TAG_ID (UNIV, PRIM, UNIVERSALSTRING_TAG_CODE): + case MAKE_TAG_ID (UNIV, CONS, UNIVERSALSTRING_TAG_CODE): + (k->choiceId) = DIRECTORYSTRING_UNIVERSALSTRING; + rc = BDecComponentUniversalString (mem_op, b, tagId0, elmtLen0, (&k->a.universalString), &totalElmtsLen1, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.universalString)->identifier.bv_val = (k->a.universalString)->id_buf; + (k->a.universalString)->identifier.bv_len = strlen("universalString"); + strcpy( (k->a.universalString)->identifier.bv_val, "universalString"); + break; + + case MAKE_TAG_ID (UNIV, PRIM, UTF8STRING_TAG_CODE): + case MAKE_TAG_ID (UNIV, CONS, UTF8STRING_TAG_CODE): + (k->choiceId) = DIRECTORYSTRING_UTF8STRING; + rc = BDecComponentUTF8String (mem_op, b, tagId0, elmtLen0, (&k->a.utf8String), &totalElmtsLen1, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.utf8String)->identifier.bv_val = (k->a.utf8String)->id_buf; + (k->a.utf8String)->identifier.bv_len = strlen("utf8String"); + strcpy( (k->a.utf8String)->identifier.bv_val, "utf8String"); + break; + + case MAKE_TAG_ID (UNIV, PRIM, BMPSTRING_TAG_CODE): + case MAKE_TAG_ID (UNIV, CONS, BMPSTRING_TAG_CODE): + (k->choiceId) = DIRECTORYSTRING_BMPSTRING; + rc = BDecComponentBMPString (mem_op, b, tagId0, elmtLen0, (&k->a.bmpString), &totalElmtsLen1, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.bmpString)->identifier.bv_val = (k->a.bmpString)->id_buf; + (k->a.bmpString)->identifier.bv_len = strlen("bmpString"); + strcpy( (k->a.bmpString)->identifier.bv_val, "bmpString"); + break; + + default: + Asn1Error ("ERROR - unexpected tag in CHOICE\n"); + return -1; + break; + } /* end switch */ + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentDirectoryString*) CompAlloc( mem_op, sizeof(ComponentDirectoryString) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentDirectoryString ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentDirectoryString ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentDirectoryString; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentDirectoryString; + (*bytesDecoded) += totalElmtsLen1; + return LDAP_SUCCESS; +} /* BDecDirectoryStringContent */ + +int +GDecComponentDirectoryString PARAMS (( mem_op,b, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +ComponentDirectoryString **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + char* peek_head,*peek_head2; + int i, strLen,strLen2, rc, old_mode = mode; + ComponentDirectoryString *k,*t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen2 = LocateNextGSERToken(mem_op,b,&peek_head2,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head2 != ':'){ + Asn1Error("Missing : in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + if( strncmp("teletexString",peek_head, strlen("teletexString")) == 0){ + (k->choiceId) = DIRECTORYSTRING_TELETEXSTRING; + rc = GDecComponentTeletexString (mem_op, b, (&k->a.teletexString), bytesDecoded, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.teletexString)->identifier.bv_val = peek_head; + (k->a.teletexString)->identifier.bv_len = strLen; + } + else if( strncmp("printableString",peek_head,strlen("printableString")) == 0){ + (k->choiceId) = DIRECTORYSTRING_PRINTABLESTRING; + rc = GDecComponentPrintableString (mem_op, b, (&k->a.printableString), bytesDecoded, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.printableString)->identifier.bv_val = peek_head; + (k->a.printableString)->identifier.bv_len = strLen; + } + else if( strncmp("universalString",peek_head,strlen("universalString")) == 0){ + (k->choiceId) = DIRECTORYSTRING_UNIVERSALSTRING; + rc = GDecComponentUniversalString (mem_op, b, (&k->a.universalString), bytesDecoded, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.universalString)->identifier.bv_val = peek_head; + (k->a.universalString)->identifier.bv_len = strLen; + } + else if( strncmp("utf8String",peek_head,strlen("utf8String")) == 0){ + (k->choiceId) = DIRECTORYSTRING_UTF8STRING; + rc = GDecComponentUTF8String (mem_op, b, (&k->a.utf8String), bytesDecoded, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.utf8String)->identifier.bv_val = peek_head; + (k->a.utf8String)->identifier.bv_len = strLen; + } + else if( strncmp("bmpString",peek_head,strlen("bmpString")) == 0){ + (k->choiceId) = DIRECTORYSTRING_BMPSTRING; + rc = GDecComponentBMPString (mem_op, b, (&k->a.bmpString), bytesDecoded, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.bmpString)->identifier.bv_val = peek_head; + (k->a.bmpString)->identifier.bv_len = strLen; + } + else { + Asn1Error("Undefined Identifier"); + return LDAP_PROTOCOL_ERROR; + } + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentDirectoryString*) CompAlloc( mem_op, sizeof(ComponentDirectoryString) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentDirectoryString ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentDirectoryString ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentDirectoryString; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentDirectoryString; + return LDAP_SUCCESS; +} /* GDecDirectoryStringContent */ + + +int +MatchingComponentEDIPartyName ( char* oid, ComponentSyntaxInfo* csi_attr, ComponentSyntaxInfo* csi_assert ) { + int rc; + MatchingRule* mr; + + if ( oid ) { + mr = retrieve_matching_rule( oid, csi_attr->csi_comp_desc->cd_type_id); + if ( mr ) return component_value_match( mr, csi_attr, csi_assert ); + } + + rc = 1; + if(COMPONENTNOT_NULL( ((ComponentEDIPartyName*)csi_attr)->nameAssigner ) ) { + rc = MatchingComponentDirectoryString ( oid, (ComponentSyntaxInfo*)((ComponentEDIPartyName*)csi_attr)->nameAssigner, (ComponentSyntaxInfo*)((ComponentEDIPartyName*)csi_assert)->nameAssigner ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + } + rc = MatchingComponentDirectoryString ( oid, (ComponentSyntaxInfo*)((ComponentEDIPartyName*)csi_attr)->partyName, (ComponentSyntaxInfo*)((ComponentEDIPartyName*)csi_assert)->partyName ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + return LDAP_COMPARE_TRUE; +} /* BMatchingComponentEDIPartyName */ + +void* +ExtractingComponentEDIPartyName ( void* mem_op, ComponentReference* cr, ComponentEDIPartyName *comp ) +{ + + if ( ( comp->nameAssigner->identifier.bv_val && strncmp(comp->nameAssigner->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->nameAssigner->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->nameAssigner; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentDirectoryString ( mem_op, cr, comp->nameAssigner ); + } + } + if ( ( comp->partyName->identifier.bv_val && strncmp(comp->partyName->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->partyName->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->partyName; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentDirectoryString ( mem_op, cr, comp->partyName ); + } + } + return NULL; +} /* ExtractingComponentEDIPartyName */ + +int +BDecComponentEDIPartyName PARAMS ((b, tagId0, elmtLen0, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +AsnTag tagId0 _AND_ +AsnLen elmtLen0 _AND_ +ComponentEDIPartyName **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + int seqDone = FALSE; + AsnLen totalElmtsLen1 = 0; + AsnLen elmtLen1; + AsnTag tagId1; + int mandatoryElmtCount1 = 0; + AsnLen totalElmtsLen2 = 0; + AsnLen elmtLen2; + AsnTag tagId2; + AsnLen totalElmtsLen3 = 0; + AsnLen elmtLen3; + AsnTag tagId3; + int old_mode = mode; + int rc; + ComponentEDIPartyName *k, *t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + tagId1 = BDecTag (b, &totalElmtsLen1 ); + + if (((tagId1 == MAKE_TAG_ID (CNTX, CONS, 0)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = tagId2 = BDecTag (b, &totalElmtsLen1 ); + elmtLen2 = BDecLen (b, &totalElmtsLen1 ); + BDecComponentDirectoryString (mem_op, b, tagId2, elmtLen2, (&k->nameAssigner), &totalElmtsLen1, mode); + if (elmtLen1 == INDEFINITE_LEN) + BDecEoc(b, &totalElmtsLen1 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->nameAssigner)->identifier.bv_val = (k->nameAssigner)->id_buf; + (k->nameAssigner)->identifier.bv_len = strlen("nameAssigner"); + strcpy( (k->nameAssigner)->identifier.bv_val, "nameAssigner"); + if (elmtLen1 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + tagId1 = BDecTag (b, &totalElmtsLen1); + } + + + if (((tagId1 == MAKE_TAG_ID (CNTX, CONS, 1)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = tagId2 = BDecTag (b, &totalElmtsLen1 ); + elmtLen2 = BDecLen (b, &totalElmtsLen1 ); + BDecComponentDirectoryString (mem_op, b, tagId2, elmtLen2, (&k->partyName), &totalElmtsLen1, mode); + if (elmtLen1 == INDEFINITE_LEN) + BDecEoc(b, &totalElmtsLen1 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->partyName)->identifier.bv_val = (k->partyName)->id_buf; + (k->partyName)->identifier.bv_len = strlen("partyName"); + strcpy( (k->partyName)->identifier.bv_val, "partyName"); + if (elmtLen1 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + seqDone = TRUE; + if (elmtLen0 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + else if (totalElmtsLen1 != elmtLen0) + return -1; + + } + else + return -1; + + + + if (!seqDone) + return -1; + + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentEDIPartyName*) CompAlloc( mem_op, sizeof(ComponentEDIPartyName) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentEDIPartyName ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentEDIPartyName ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentEDIPartyName; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentEDIPartyName; + (*bytesDecoded) += totalElmtsLen1; + return LDAP_SUCCESS; +} /* BDecEDIPartyName*/ + +int +GDecComponentEDIPartyName PARAMS (( mem_op,b, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +ComponentEDIPartyName **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + char* peek_head,*peek_head2; + int i, strLen,strLen2, rc, old_mode = mode; + ComponentEDIPartyName *k,*t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + *bytesDecoded = 0; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '{'){ + Asn1Error("Missing { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + if ( strncmp( peek_head, "nameAssigner", strlen("nameAssigner") ) == 0 ) { + rc = GDecComponentDirectoryString (mem_op, b, (&k->nameAssigner), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->nameAssigner)->identifier.bv_val = peek_head; + ( k->nameAssigner)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "partyName", strlen("partyName") ) == 0 ) { + rc = GDecComponentDirectoryString (mem_op, b, (&k->partyName), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->partyName)->identifier.bv_val = peek_head; + ( k->partyName)->identifier.bv_len = strLen; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ) { + Asn1Error("Error during Reading } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '}'){ + Asn1Error("Missing } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentEDIPartyName*) CompAlloc( mem_op, sizeof(ComponentEDIPartyName) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentEDIPartyName ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentEDIPartyName ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentEDIPartyName; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentEDIPartyName; + return LDAP_SUCCESS; +} /* GDecEDIPartyName*/ + + + +int +MatchingComponentGeneralName ( char* oid, ComponentSyntaxInfo* csi_attr, ComponentSyntaxInfo* csi_assert ) { + int rc; + MatchingRule* mr; + ComponentGeneralName *v1, *v2; + + + v1 = (ComponentGeneralName*)csi_attr; + v2 = (ComponentGeneralName*)csi_assert; + if ( oid ) { + mr = retrieve_matching_rule( oid, csi_attr->csi_comp_desc->cd_type_id); + if ( mr ) return component_value_match( mr, csi_attr, csi_assert ); + } + + if( (v1->choiceId != v2->choiceId ) ) + return LDAP_COMPARE_FALSE; + switch( v1->choiceId ) + { + case GENERALNAME_OTHERNAME : + rc = MatchingComponentOtherName ( oid, (ComponentSyntaxInfo*)(v1->a.otherName), (ComponentSyntaxInfo*)(v2->a.otherName) ); + break; + case GENERALNAME_RFC822NAME : + rc = MatchingComponentIA5String ( oid, (ComponentSyntaxInfo*)(v1->a.rfc822Name), (ComponentSyntaxInfo*)(v2->a.rfc822Name) ); + break; + case GENERALNAME_DNSNAME : + rc = MatchingComponentIA5String ( oid, (ComponentSyntaxInfo*)(v1->a.dNSName), (ComponentSyntaxInfo*)(v2->a.dNSName) ); + break; + case GENERALNAME_X400ADDRESS : + rc = MatchingComponentORAddress ( oid, (ComponentSyntaxInfo*)(v1->a.x400Address), (ComponentSyntaxInfo*)(v2->a.x400Address) ); + break; + case GENERALNAME_DIRECTORYNAME : + rc = MatchingComponentName ( oid, (ComponentSyntaxInfo*)(v1->a.directoryName), (ComponentSyntaxInfo*)(v2->a.directoryName) ); + break; + case GENERALNAME_EDIPARTYNAME : + rc = MatchingComponentEDIPartyName ( oid, (ComponentSyntaxInfo*)(v1->a.ediPartyName), (ComponentSyntaxInfo*)(v2->a.ediPartyName) ); + break; + case GENERALNAME_UNIFORMRESOURCEIDENTIFIER : + rc = MatchingComponentIA5String ( oid, (ComponentSyntaxInfo*)(v1->a.uniformResourceIdentifier), (ComponentSyntaxInfo*)(v2->a.uniformResourceIdentifier) ); + break; + case GENERALNAME_IPADDRESS : + rc = MatchingComponentOcts ( oid, (ComponentSyntaxInfo*)(v1->a.iPAddress), (ComponentSyntaxInfo*)(v2->a.iPAddress) ); + break; + case GENERALNAME_REGISTEREDID : + rc = MatchingComponentOid ( oid, (ComponentSyntaxInfo*)(v1->a.registeredID), (ComponentSyntaxInfo*)(v2->a.registeredID) ); + break; + default : + return LDAP_PROTOCOL_ERROR; + } + return rc; +} /* BMatchingComponentGeneralNameContent */ + +void* +ExtractingComponentGeneralName ( void* mem_op, ComponentReference* cr, ComponentGeneralName *comp ) +{ + + + if( (comp->choiceId) == GENERALNAME_OTHERNAME && + (( comp->a.otherName->identifier.bv_val && strncmp(comp->a.otherName->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0) || + ( strncmp(comp->a.otherName->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0))) { + if ( cr->cr_curr->ci_next == NULL ) + return (comp->a.otherName); + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentOtherName ( mem_op, cr, (comp->a.otherName) ); + }; + } + if( (comp->choiceId) == GENERALNAME_RFC822NAME && + (( comp->a.rfc822Name->identifier.bv_val && strncmp(comp->a.rfc822Name->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0) || + ( strncmp(comp->a.rfc822Name->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0))) { + if ( cr->cr_curr->ci_next == NULL ) + return (comp->a.rfc822Name); + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentIA5String ( mem_op, cr, (comp->a.rfc822Name) ); + }; + } + if( (comp->choiceId) == GENERALNAME_DNSNAME && + (( comp->a.dNSName->identifier.bv_val && strncmp(comp->a.dNSName->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0) || + ( strncmp(comp->a.dNSName->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0))) { + if ( cr->cr_curr->ci_next == NULL ) + return (comp->a.dNSName); + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentIA5String ( mem_op, cr, (comp->a.dNSName) ); + }; + } + if( (comp->choiceId) == GENERALNAME_X400ADDRESS && + (( comp->a.x400Address->identifier.bv_val && strncmp(comp->a.x400Address->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0) || + ( strncmp(comp->a.x400Address->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0))) { + if ( cr->cr_curr->ci_next == NULL ) + return (comp->a.x400Address); + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentORAddress ( mem_op, cr, (comp->a.x400Address) ); + }; + } + if( (comp->choiceId) == GENERALNAME_DIRECTORYNAME && + (( comp->a.directoryName->identifier.bv_val && strncmp(comp->a.directoryName->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0) || + ( strncmp(comp->a.directoryName->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0))) { + if ( cr->cr_curr->ci_next == NULL ) + return (comp->a.directoryName); + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentName ( mem_op, cr, (comp->a.directoryName) ); + }; + } + if( (comp->choiceId) == GENERALNAME_EDIPARTYNAME && + (( comp->a.ediPartyName->identifier.bv_val && strncmp(comp->a.ediPartyName->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0) || + ( strncmp(comp->a.ediPartyName->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0))) { + if ( cr->cr_curr->ci_next == NULL ) + return (comp->a.ediPartyName); + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentEDIPartyName ( mem_op, cr, (comp->a.ediPartyName) ); + }; + } + if( (comp->choiceId) == GENERALNAME_UNIFORMRESOURCEIDENTIFIER && + (( comp->a.uniformResourceIdentifier->identifier.bv_val && strncmp(comp->a.uniformResourceIdentifier->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0) || + ( strncmp(comp->a.uniformResourceIdentifier->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0))) { + if ( cr->cr_curr->ci_next == NULL ) + return (comp->a.uniformResourceIdentifier); + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentIA5String ( mem_op, cr, (comp->a.uniformResourceIdentifier) ); + }; + } + if( (comp->choiceId) == GENERALNAME_IPADDRESS && + (( comp->a.iPAddress->identifier.bv_val && strncmp(comp->a.iPAddress->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0) || + ( strncmp(comp->a.iPAddress->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0))) { + if ( cr->cr_curr->ci_next == NULL ) + return (comp->a.iPAddress); + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentOcts ( mem_op, cr, (comp->a.iPAddress) ); + }; + } + if( (comp->choiceId) == GENERALNAME_REGISTEREDID && + (( comp->a.registeredID->identifier.bv_val && strncmp(comp->a.registeredID->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0) || + ( strncmp(comp->a.registeredID->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0))) { + if ( cr->cr_curr->ci_next == NULL ) + return (comp->a.registeredID); + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentOid ( mem_op, cr, (comp->a.registeredID) ); + }; + } + return NULL; +} /* ExtractingComponentGeneralName */ + +int +BDecComponentGeneralName PARAMS ((b, tagId0, elmtLen0, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +AsnTag tagId0 _AND_ +AsnLen elmtLen0 _AND_ +ComponentGeneralName **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + int seqDone = FALSE; + AsnLen totalElmtsLen1 = 0; + AsnLen elmtLen1; + AsnTag tagId1; + int mandatoryElmtCount1 = 0; + AsnLen totalElmtsLen2 = 0; + AsnLen elmtLen2; + AsnTag tagId2; + AsnLen totalElmtsLen3 = 0; + AsnLen elmtLen3; + AsnTag tagId3; + int old_mode = mode; + int rc; + ComponentGeneralName *k, *t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + switch (tagId0) + { + case MAKE_TAG_ID (CNTX, CONS, 0): +if (BDecTag (b, &totalElmtsLen1 ) != MAKE_TAG_ID (UNIV, CONS, SEQ_TAG_CODE)) + { + Asn1Error ("Unexpected Tag\n"); + return -1; + } + + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + (k->choiceId) = GENERALNAME_OTHERNAME; + rc = BDecComponentOtherName (mem_op, b, tagId1, elmtLen1, (&k->a.otherName), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.otherName)->identifier.bv_val = (k->a.otherName)->id_buf; + (k->a.otherName)->identifier.bv_len = strlen("otherName"); + strcpy( (k->a.otherName)->identifier.bv_val, "otherName"); + if (elmtLen0 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + break; + + case MAKE_TAG_ID (CNTX, CONS, 1): + tagId1 = BDecTag (b, &totalElmtsLen1 ); +if ((tagId1 != MAKE_TAG_ID (UNIV, PRIM, IA5STRING_TAG_CODE)) && + (tagId1 != MAKE_TAG_ID (UNIV, CONS, IA5STRING_TAG_CODE))) + { + Asn1Error ("Unexpected Tag\n"); + return -1; + } + + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + (k->choiceId) = GENERALNAME_RFC822NAME; + rc = BDecComponentIA5String (mem_op, b, tagId1, elmtLen1, (&k->a.rfc822Name), &totalElmtsLen1, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.rfc822Name)->identifier.bv_val = (k->a.rfc822Name)->id_buf; + (k->a.rfc822Name)->identifier.bv_len = strlen("rfc822Name"); + strcpy( (k->a.rfc822Name)->identifier.bv_val, "rfc822Name"); + if (elmtLen0 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + break; + + case MAKE_TAG_ID (CNTX, CONS, 2): + tagId1 = BDecTag (b, &totalElmtsLen1 ); +if ((tagId1 != MAKE_TAG_ID (UNIV, PRIM, IA5STRING_TAG_CODE)) && + (tagId1 != MAKE_TAG_ID (UNIV, CONS, IA5STRING_TAG_CODE))) + { + Asn1Error ("Unexpected Tag\n"); + return -1; + } + + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + (k->choiceId) = GENERALNAME_DNSNAME; + rc = BDecComponentIA5String (mem_op, b, tagId1, elmtLen1, (&k->a.dNSName), &totalElmtsLen1, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.dNSName)->identifier.bv_val = (k->a.dNSName)->id_buf; + (k->a.dNSName)->identifier.bv_len = strlen("dNSName"); + strcpy( (k->a.dNSName)->identifier.bv_val, "dNSName"); + if (elmtLen0 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + break; + + case MAKE_TAG_ID (CNTX, CONS, 3): +if (BDecTag (b, &totalElmtsLen1 ) != MAKE_TAG_ID (UNIV, CONS, SEQ_TAG_CODE)) + { + Asn1Error ("Unexpected Tag\n"); + return -1; + } + + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + (k->choiceId) = GENERALNAME_X400ADDRESS; + rc = BDecComponentORAddress (mem_op, b, tagId1, elmtLen1, (&k->a.x400Address), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.x400Address)->identifier.bv_val = (k->a.x400Address)->id_buf; + (k->a.x400Address)->identifier.bv_len = strlen("x400Address"); + strcpy( (k->a.x400Address)->identifier.bv_val, "x400Address"); + if (elmtLen0 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + break; + + case MAKE_TAG_ID (CNTX, CONS, 4): + (k->choiceId) = GENERALNAME_DIRECTORYNAME; + tagId1 = BDecTag (b, &totalElmtsLen1 ); + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentName (mem_op, b, tagId1, elmtLen1, (&k->a.directoryName), &totalElmtsLen1, mode); + if (elmtLen0 == INDEFINITE_LEN) + BDecEoc(b, &totalElmtsLen1 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.directoryName)->identifier.bv_val = (k->a.directoryName)->id_buf; + (k->a.directoryName)->identifier.bv_len = strlen("directoryName"); + strcpy( (k->a.directoryName)->identifier.bv_val, "directoryName"); + if (elmtLen0 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + break; + + case MAKE_TAG_ID (CNTX, CONS, 5): +if (BDecTag (b, &totalElmtsLen1 ) != MAKE_TAG_ID (UNIV, CONS, SEQ_TAG_CODE)) + { + Asn1Error ("Unexpected Tag\n"); + return -1; + } + + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + (k->choiceId) = GENERALNAME_EDIPARTYNAME; + rc = BDecComponentEDIPartyName (mem_op, b, tagId1, elmtLen1, (&k->a.ediPartyName), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.ediPartyName)->identifier.bv_val = (k->a.ediPartyName)->id_buf; + (k->a.ediPartyName)->identifier.bv_len = strlen("ediPartyName"); + strcpy( (k->a.ediPartyName)->identifier.bv_val, "ediPartyName"); + if (elmtLen0 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + break; + + case MAKE_TAG_ID (CNTX, CONS, 6): + tagId1 = BDecTag (b, &totalElmtsLen1 ); +if ((tagId1 != MAKE_TAG_ID (UNIV, PRIM, IA5STRING_TAG_CODE)) && + (tagId1 != MAKE_TAG_ID (UNIV, CONS, IA5STRING_TAG_CODE))) + { + Asn1Error ("Unexpected Tag\n"); + return -1; + } + + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + (k->choiceId) = GENERALNAME_UNIFORMRESOURCEIDENTIFIER; + rc = BDecComponentIA5String (mem_op, b, tagId1, elmtLen1, (&k->a.uniformResourceIdentifier), &totalElmtsLen1, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.uniformResourceIdentifier)->identifier.bv_val = (k->a.uniformResourceIdentifier)->id_buf; + (k->a.uniformResourceIdentifier)->identifier.bv_len = strlen("uniformResourceIdentifier"); + strcpy( (k->a.uniformResourceIdentifier)->identifier.bv_val, "uniformResourceIdentifier"); + if (elmtLen0 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + break; + + case MAKE_TAG_ID (CNTX, CONS, 7): + tagId1 = BDecTag (b, &totalElmtsLen1 ); +if ((tagId1 != MAKE_TAG_ID (UNIV, PRIM, OCTETSTRING_TAG_CODE)) && + (tagId1 != MAKE_TAG_ID (UNIV, CONS, OCTETSTRING_TAG_CODE))) + { + Asn1Error ("Unexpected Tag\n"); + return -1; + } + + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + (k->choiceId) = GENERALNAME_IPADDRESS; + rc = BDecComponentOcts (mem_op, b, tagId1, elmtLen1, (&k->a.iPAddress), &totalElmtsLen1, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.iPAddress)->identifier.bv_val = (k->a.iPAddress)->id_buf; + (k->a.iPAddress)->identifier.bv_len = strlen("iPAddress"); + strcpy( (k->a.iPAddress)->identifier.bv_val, "iPAddress"); + if (elmtLen0 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + break; + + case MAKE_TAG_ID (CNTX, CONS, 8): +if (BDecTag (b, &totalElmtsLen1 ) != MAKE_TAG_ID (UNIV, PRIM, OID_TAG_CODE)) + { + Asn1Error ("Unexpected Tag\n"); + return -1; + } + + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + (k->choiceId) = GENERALNAME_REGISTEREDID; + rc = BDecComponentOid (mem_op, b, tagId1, elmtLen1, (&k->a.registeredID), &totalElmtsLen1, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.registeredID)->identifier.bv_val = (k->a.registeredID)->id_buf; + (k->a.registeredID)->identifier.bv_len = strlen("registeredID"); + strcpy( (k->a.registeredID)->identifier.bv_val, "registeredID"); + if (elmtLen0 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + break; + + default: + Asn1Error ("ERROR - unexpected tag in CHOICE\n"); + return -1; + break; + } /* end switch */ + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentGeneralName*) CompAlloc( mem_op, sizeof(ComponentGeneralName) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentGeneralName ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentGeneralName ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentGeneralName; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentGeneralName; + (*bytesDecoded) += totalElmtsLen1; + return LDAP_SUCCESS; +} /* BDecGeneralNameContent */ + +int +GDecComponentGeneralName PARAMS (( mem_op,b, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +ComponentGeneralName **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + char* peek_head,*peek_head2; + int i, strLen,strLen2, rc, old_mode = mode; + ComponentGeneralName *k,*t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen2 = LocateNextGSERToken(mem_op,b,&peek_head2,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head2 != ':'){ + Asn1Error("Missing : in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + if( strncmp("otherName",peek_head, strlen("otherName")) == 0){ + (k->choiceId) = GENERALNAME_OTHERNAME; + rc = GDecComponentOtherName (mem_op, b, (&k->a.otherName), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.otherName)->identifier.bv_val = peek_head; + (k->a.otherName)->identifier.bv_len = strLen; + } + else if( strncmp("rfc822Name",peek_head,strlen("rfc822Name")) == 0){ + (k->choiceId) = GENERALNAME_RFC822NAME; + rc = GDecComponentIA5String (mem_op, b, (&k->a.rfc822Name), bytesDecoded, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.rfc822Name)->identifier.bv_val = peek_head; + (k->a.rfc822Name)->identifier.bv_len = strLen; + } + else if( strncmp("dNSName",peek_head,strlen("dNSName")) == 0){ + (k->choiceId) = GENERALNAME_DNSNAME; + rc = GDecComponentIA5String (mem_op, b, (&k->a.dNSName), bytesDecoded, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.dNSName)->identifier.bv_val = peek_head; + (k->a.dNSName)->identifier.bv_len = strLen; + } + else if( strncmp("x400Address",peek_head,strlen("x400Address")) == 0){ + (k->choiceId) = GENERALNAME_X400ADDRESS; + rc = GDecComponentORAddress (mem_op, b, (&k->a.x400Address), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.x400Address)->identifier.bv_val = peek_head; + (k->a.x400Address)->identifier.bv_len = strLen; + } + else if( strncmp("directoryName",peek_head,strlen("directoryName")) == 0){ + (k->choiceId) = GENERALNAME_DIRECTORYNAME; + rc = GDecComponentName (mem_op, b, (&k->a.directoryName), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.directoryName)->identifier.bv_val = peek_head; + (k->a.directoryName)->identifier.bv_len = strLen; + } + else if( strncmp("ediPartyName",peek_head,strlen("ediPartyName")) == 0){ + (k->choiceId) = GENERALNAME_EDIPARTYNAME; + rc = GDecComponentEDIPartyName (mem_op, b, (&k->a.ediPartyName), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.ediPartyName)->identifier.bv_val = peek_head; + (k->a.ediPartyName)->identifier.bv_len = strLen; + } + else if( strncmp("uniformResourceIdentifier",peek_head,strlen("uniformResourceIdentifier")) == 0){ + (k->choiceId) = GENERALNAME_UNIFORMRESOURCEIDENTIFIER; + rc = GDecComponentIA5String (mem_op, b, (&k->a.uniformResourceIdentifier), bytesDecoded, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.uniformResourceIdentifier)->identifier.bv_val = peek_head; + (k->a.uniformResourceIdentifier)->identifier.bv_len = strLen; + } + else if( strncmp("iPAddress",peek_head,strlen("iPAddress")) == 0){ + (k->choiceId) = GENERALNAME_IPADDRESS; + rc = GDecComponentOcts (mem_op, b, (&k->a.iPAddress), bytesDecoded, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.iPAddress)->identifier.bv_val = peek_head; + (k->a.iPAddress)->identifier.bv_len = strLen; + } + else if( strncmp("registeredID",peek_head,strlen("registeredID")) == 0){ + (k->choiceId) = GENERALNAME_REGISTEREDID; + rc = GDecComponentOid (mem_op, b, (&k->a.registeredID), bytesDecoded, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.registeredID)->identifier.bv_val = peek_head; + (k->a.registeredID)->identifier.bv_len = strLen; + } + else { + Asn1Error("Undefined Identifier"); + return LDAP_PROTOCOL_ERROR; + } + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentGeneralName*) CompAlloc( mem_op, sizeof(ComponentGeneralName) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentGeneralName ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentGeneralName ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentGeneralName; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentGeneralName; + return LDAP_SUCCESS; +} /* GDecGeneralNameContent */ + + +int +MatchingComponentGeneralNames ( char* oid, ComponentSyntaxInfo* csi_attr, ComponentSyntaxInfo* csi_assert ) { + int rc; + MatchingRule* mr; + void* component1, *component2; + AsnList *v1, *v2, t_list; + + + if ( oid ) { + mr = retrieve_matching_rule( oid, csi_attr->csi_comp_desc->cd_type_id); + if ( mr ) return component_value_match( mr, csi_attr, csi_assert ); + } + + v1 = &((ComponentGeneralNames*)csi_attr)->comp_list; + v2 = &((ComponentGeneralNames*)csi_assert)->comp_list; + FOR_EACH_LIST_PAIR_ELMT(component1, component2, v1, v2) + { + if( MatchingComponentGeneralName(oid, (ComponentSyntaxInfo*)component1, (ComponentSyntaxInfo*)component2) == LDAP_COMPARE_FALSE) { + return LDAP_COMPARE_FALSE; + } + } /* end of for */ + + AsnListFirst( v1 ); + AsnListFirst( v2 ); + if( (!component1 && component2) || (component1 && !component2)) + return LDAP_COMPARE_FALSE; + else + return LDAP_COMPARE_TRUE; +} /* BMatchingComponentGeneralNamesContent */ + +void* +ExtractingComponentGeneralNames ( void* mem_op, ComponentReference* cr, ComponentGeneralNames *comp ) +{ + int count = 0; + int total; + AsnList *v = &comp->comp_list; + ComponentInt *k; + ComponentGeneralName *component; + + + switch ( cr->cr_curr->ci_type ) { + case LDAP_COMPREF_FROM_BEGINNING : + count = cr->cr_curr->ci_val.ci_from_beginning; + FOR_EACH_LIST_ELMT( component , v ) { + if( --count == 0 ) { + if( cr->cr_curr->ci_next == NULL ) + return component; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentGeneralName ( mem_op, cr, component ); + } + } + } + break; + case LDAP_COMPREF_FROM_END : + total = AsnListCount ( v ); + count = cr->cr_curr->ci_val.ci_from_end; + count = total + count +1; + FOR_EACH_LIST_ELMT ( component, v ) { + if( --count == 0 ) { + if( cr->cr_curr->ci_next == NULL ) + return component; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentGeneralName ( mem_op, cr, component ); + } + } + } + break; + case LDAP_COMPREF_ALL : + return comp; + case LDAP_COMPREF_COUNT : + k = (ComponentInt*)CompAlloc( mem_op, sizeof(ComponentInt)); + k->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + k->comp_desc->cd_tag = (-1); + k->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentInt; + k->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentInt; + k->comp_desc->cd_extract_i = (extract_component_from_id_func*)NULL; + k->comp_desc->cd_type = ASN_BASIC; + k->comp_desc->cd_type_id = BASICTYPE_INTEGER; + k->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentInt; + k->value = AsnListCount(v); + return k; + default : + return NULL; + } +} /* ExtractingComponentGeneralNames */ + +int +BDecComponentGeneralNames PARAMS ((b, tagId0, elmtLen0, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +AsnTag tagId0 _AND_ +AsnLen elmtLen0 _AND_ +ComponentGeneralNames **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + int seqDone = FALSE; + AsnLen totalElmtsLen1 = 0; + AsnLen elmtLen1; + AsnTag tagId1; + int mandatoryElmtCount1 = 0; + int old_mode = mode; + int rc; + ComponentGeneralNames *k, *t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + AsnListInit(&k->comp_list,sizeof(ComponentGeneralName)); + for (totalElmtsLen1 = 0; (totalElmtsLen1 < elmtLen0) || (elmtLen0 == INDEFINITE_LEN);) + { + ComponentGeneralName **tmpVar; + tagId1 = BDecTag (b, &totalElmtsLen1 ); + + if ((tagId1 == EOC_TAG_ID) && (elmtLen0 == INDEFINITE_LEN)) + { + BDEC_2ND_EOC_OCTET (b, &totalElmtsLen1 ) + break; /* got EOC so can exit this SET OF/SEQ OF's for loop*/ + } + elmtLen1 = BDecLen (b, &totalElmtsLen1); + tmpVar = (ComponentGeneralName**) CompAsnListAppend (mem_op,&k->comp_list); + rc = BDecComponentGeneralName (mem_op, b, tagId1, elmtLen1, tmpVar, &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + } /* end of for */ + + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentGeneralNames*) CompAlloc( mem_op, sizeof(ComponentGeneralNames) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentGeneralNames ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentGeneralNames ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentGeneralNames; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentGeneralNames; + (*bytesDecoded) += totalElmtsLen1; + return LDAP_SUCCESS; +} /* BDecGeneralNamesContent */ + +int +GDecComponentGeneralNames PARAMS (( mem_op,b, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +ComponentGeneralNames **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + char* peek_head,*peek_head2; + int i, strLen,strLen2, rc, old_mode = mode; + ComponentGeneralNames *k,*t, c_temp; + + + int ElmtsLen1; + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + AsnListInit( &k->comp_list, sizeof( ComponentGeneralName ) ); + *bytesDecoded = 0; + if( !(strLen = LocateNextGSERToken(mem_op,b, &peek_head, GSER_PEEK)) ){ + Asn1Error("Error during Reading { in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '{'){ + Asn1Error("Missing { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + + for (ElmtsLen1 = 0; ElmtsLen1 >= INDEFINITE_LEN; ElmtsLen1++) + { + ComponentGeneralName **tmpVar; + if( !(strLen = LocateNextGSERToken(mem_op,b, &peek_head, GSER_NO_COPY)) ){ + Asn1Error("Error during Reading{ in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head == '}') break; + if( !(*peek_head == '{' || *peek_head ==',') ) { + return LDAP_PROTOCOL_ERROR; + } + tmpVar = (ComponentGeneralName**) CompAsnListAppend (mem_op, &k->comp_list); + if ( tmpVar == NULL ) { + Asn1Error("Error during Reading{ in encoding"); + return LDAP_PROTOCOL_ERROR; + } + rc = GDecComponentGeneralName (mem_op, b, tmpVar, bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + } /* end of for */ + + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentGeneralNames*) CompAlloc( mem_op, sizeof(ComponentGeneralNames) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentGeneralNames ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentGeneralNames ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentGeneralNames; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentGeneralNames; + return LDAP_SUCCESS; +} /* GDecGeneralNamesContent */ + + +int +MatchingComponentAuthorityKeyIdentifier ( char* oid, ComponentSyntaxInfo* csi_attr, ComponentSyntaxInfo* csi_assert ) { + int rc; + MatchingRule* mr; + + if ( oid ) { + mr = retrieve_matching_rule( oid, csi_attr->csi_comp_desc->cd_type_id); + if ( mr ) return component_value_match( mr, csi_attr, csi_assert ); + } + + rc = 1; + rc = MatchingComponentKeyIdentifier ( oid, (ComponentSyntaxInfo*)&((ComponentAuthorityKeyIdentifier*)csi_attr)->keyIdentifier, (ComponentSyntaxInfo*)&((ComponentAuthorityKeyIdentifier*)csi_assert)->keyIdentifier ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + if(COMPONENTNOT_NULL( ((ComponentAuthorityKeyIdentifier*)csi_attr)->authorityCertIssuer ) ) { + rc = MatchingComponentGeneralNames ( oid, (ComponentSyntaxInfo*)((ComponentAuthorityKeyIdentifier*)csi_attr)->authorityCertIssuer, (ComponentSyntaxInfo*)((ComponentAuthorityKeyIdentifier*)csi_assert)->authorityCertIssuer ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + } + if(COMPONENTNOT_NULL( ((ComponentAuthorityKeyIdentifier*)csi_attr)->authorityCertSerialNumber ) ) { + rc = MatchingComponentCertificateSerialNumber ( oid, (ComponentSyntaxInfo*)((ComponentAuthorityKeyIdentifier*)csi_attr)->authorityCertSerialNumber, (ComponentSyntaxInfo*)((ComponentAuthorityKeyIdentifier*)csi_assert)->authorityCertSerialNumber ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + } + return LDAP_COMPARE_TRUE; +} /* BMatchingComponentAuthorityKeyIdentifier */ + +void* +ExtractingComponentAuthorityKeyIdentifier ( void* mem_op, ComponentReference* cr, ComponentAuthorityKeyIdentifier *comp ) +{ + + if ( ( comp->keyIdentifier.identifier.bv_val && strncmp(comp->keyIdentifier.identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->keyIdentifier.id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return &comp->keyIdentifier; + else + return NULL; + } + if ( ( comp->authorityCertIssuer->identifier.bv_val && strncmp(comp->authorityCertIssuer->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->authorityCertIssuer->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->authorityCertIssuer; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentGeneralNames ( mem_op, cr, comp->authorityCertIssuer ); + } + } + if ( ( comp->authorityCertSerialNumber->identifier.bv_val && strncmp(comp->authorityCertSerialNumber->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->authorityCertSerialNumber->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->authorityCertSerialNumber; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentCertificateSerialNumber ( mem_op, cr, comp->authorityCertSerialNumber ); + } + } + return NULL; +} /* ExtractingComponentAuthorityKeyIdentifier */ + +int +BDecComponentAuthorityKeyIdentifier PARAMS ((b, tagId0, elmtLen0, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +AsnTag tagId0 _AND_ +AsnLen elmtLen0 _AND_ +ComponentAuthorityKeyIdentifier **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + int seqDone = FALSE; + AsnLen totalElmtsLen1 = 0; + AsnLen elmtLen1; + AsnTag tagId1; + int mandatoryElmtCount1 = 0; + AsnLen totalElmtsLen2 = 0; + AsnLen elmtLen2; + AsnTag tagId2; + int old_mode = mode; + int rc; + ComponentAuthorityKeyIdentifier *k, *t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + if ((elmtLen0 != INDEFINITE_LEN) && (totalElmtsLen1 == elmtLen0)) + seqDone = TRUE; + else + { + tagId1 = BDecTag (b, &totalElmtsLen1 ); + + if ((elmtLen0 == INDEFINITE_LEN) && (tagId1 == EOC_TAG_ID)) + { + BDEC_2ND_EOC_OCTET (b, &totalElmtsLen1 ) + seqDone = TRUE; + } + } + + if ((!seqDone) && ((tagId1 == MAKE_TAG_ID (CNTX, PRIM, 0)) || +(tagId1 == MAKE_TAG_ID (CNTX, CONS, 0)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentKeyIdentifier (mem_op, b, tagId1, elmtLen1, (&k->keyIdentifier), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->keyIdentifier)->identifier.bv_val = (&k->keyIdentifier)->id_buf; + (&k->keyIdentifier)->identifier.bv_len = strlen("keyIdentifier"); + strcpy( (&k->keyIdentifier)->identifier.bv_val, "keyIdentifier"); + if ((elmtLen0 != INDEFINITE_LEN) && (totalElmtsLen1 == elmtLen0)) + seqDone = TRUE; + else + { + tagId1 = BDecTag (b, &totalElmtsLen1 ); + + if ((elmtLen0 == INDEFINITE_LEN) && (tagId1 == EOC_TAG_ID)) + { + BDEC_2ND_EOC_OCTET (b, &totalElmtsLen1 ) + seqDone = TRUE; + } + } + } + + if ((!seqDone) && ((tagId1 == MAKE_TAG_ID (CNTX, CONS, 1)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentGeneralNames (mem_op, b, tagId1, elmtLen1, +(&k->authorityCertIssuer), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->authorityCertIssuer)->identifier.bv_val = (k->authorityCertIssuer)->id_buf; + (k->authorityCertIssuer)->identifier.bv_len = strlen("authorityCertIssuer"); + strcpy( (k->authorityCertIssuer)->identifier.bv_val, "authorityCertIssuer"); + if ((elmtLen0 != INDEFINITE_LEN) && (totalElmtsLen1 == elmtLen0)) + seqDone = TRUE; + else + { + tagId1 = BDecTag (b, &totalElmtsLen1 ); + + if ((elmtLen0 == INDEFINITE_LEN) && (tagId1 == EOC_TAG_ID)) + { + BDEC_2ND_EOC_OCTET (b, &totalElmtsLen1 ) + seqDone = TRUE; + } + } + } + + if ((!seqDone) && ((tagId1 == MAKE_TAG_ID (CNTX, PRIM, 2)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentCertificateSerialNumber (mem_op, b, tagId1, elmtLen1, (&k->authorityCertSerialNumber), &totalElmtsLen1, DEC_ALLOC_MODE_0 ); if ( rc != LDAP_SUCCESS ) return rc; + (k->authorityCertSerialNumber)->identifier.bv_val = (k->authorityCertSerialNumber)->id_buf; + (k->authorityCertSerialNumber)->identifier.bv_len = strlen("authorityCertSerialNumber"); + strcpy( (k->authorityCertSerialNumber)->identifier.bv_val, "authorityCertSerialNumber"); + seqDone = TRUE; + if (elmtLen0 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + else if (totalElmtsLen1 != elmtLen0) + return -1; + + } + + if (!seqDone) + return -1; + + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentAuthorityKeyIdentifier*) CompAlloc( mem_op, sizeof(ComponentAuthorityKeyIdentifier) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentAuthorityKeyIdentifier ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentAuthorityKeyIdentifier ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentAuthorityKeyIdentifier; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentAuthorityKeyIdentifier; + (*bytesDecoded) += totalElmtsLen1; + return LDAP_SUCCESS; +} /* BDecAuthorityKeyIdentifier*/ + +int +GDecComponentAuthorityKeyIdentifier PARAMS (( mem_op,b, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +ComponentAuthorityKeyIdentifier **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + char* peek_head,*peek_head2; + int i, strLen,strLen2, rc, old_mode = mode; + ComponentAuthorityKeyIdentifier *k,*t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + *bytesDecoded = 0; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '{'){ + Asn1Error("Missing { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + if ( strncmp( peek_head, "keyIdentifier", strlen("keyIdentifier") ) == 0 ) { + rc = GDecComponentKeyIdentifier (mem_op, b, (&k->keyIdentifier), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->keyIdentifier)->identifier.bv_val = peek_head; + (&k->keyIdentifier)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "authorityCertIssuer", strlen("authorityCertIssuer") ) == 0 ) { + rc = GDecComponentGeneralNames (mem_op, b, (&k->authorityCertIssuer), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->authorityCertIssuer)->identifier.bv_val = peek_head; + ( k->authorityCertIssuer)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "authorityCertSerialNumber", strlen("authorityCertSerialNumber") ) == 0 ) { + rc = GDecComponentCertificateSerialNumber (mem_op, b, (&k->authorityCertSerialNumber), bytesDecoded, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->authorityCertSerialNumber)->identifier.bv_val = peek_head; + ( k->authorityCertSerialNumber)->identifier.bv_len = strLen; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ) { + Asn1Error("Error during Reading } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '}'){ + Asn1Error("Missing } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentAuthorityKeyIdentifier*) CompAlloc( mem_op, sizeof(ComponentAuthorityKeyIdentifier) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentAuthorityKeyIdentifier ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentAuthorityKeyIdentifier ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentAuthorityKeyIdentifier; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentAuthorityKeyIdentifier; + return LDAP_SUCCESS; +} /* GDecAuthorityKeyIdentifier*/ + + diff --git a/contrib/slapd-modules/comp_match/authorityKeyIdentifier.h b/contrib/slapd-modules/comp_match/authorityKeyIdentifier.h new file mode 100644 index 0000000..5fa4ab5 --- /dev/null +++ b/contrib/slapd-modules/comp_match/authorityKeyIdentifier.h @@ -0,0 +1,327 @@ + +#include "asn-incl.h" +/* + * authorityKeyIdentifier.h + * "AuthorityKeyIdentifierDefinition" ASN.1 module encode/decode/extracting/matching/free C src. + * This file was generated by modified eSMACC compiler Sat Dec 11 10:15:39 2004 + * The generated files are strongly encouraged to be + * compiled as a module for OpenLDAP Software + */ + +#ifndef _authorityKeyIdentifier_h_ +#define _authorityKeyIdentifier_h_ + + + + +#ifdef __cplusplus +extern "C" { +#endif +#ifdef _WIN32 +#pragma warning( disable : 4101 ) +#endif +#include "componentlib.h" +typedef ComponentOcts ComponentKeyIdentifier; /* OCTET STRING */ + +#define MatchingComponentKeyIdentifier MatchingComponentOcts + +#define ExtractingComponentKeyIdentifier ExtractingComponentOcts + +#define BDecComponentKeyIdentifier BDecComponentOcts + +#define GDecComponentKeyIdentifier GDecComponentOcts + + +typedef ComponentInt ComponentCertificateSerialNumber; /* INTEGER */ + +#define MatchingComponentCertificateSerialNumber MatchingComponentInt + +#define ExtractingComponentCertificateSerialNumber ExtractingComponentInt + +#define BDecComponentCertificateSerialNumber BDecComponentInt + +#define GDecComponentCertificateSerialNumber GDecComponentInt + + +typedef struct OtherName /* SEQUENCE */ +{ + Syntax* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + ComponentOid type_id; /* OBJECT IDENTIFIER */ + ComponentAnyDefinedBy value; /* [0] EXPLICIT ANY DEFINED BY type-id */ +} ComponentOtherName; + +int MatchingComponentOtherName PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentOtherName PROTO (( void* mem_op, ComponentReference *cr, ComponentOtherName *comp )); + + +int BDecComponentOtherName PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentOtherName **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentOtherName PROTO (( void* mem_op, GenBuf * b, ComponentOtherName **v, AsnLen *bytesDecoded, int mode)); + + + +typedef struct ORAddress /* SEQUENCE */ +{ + Syntax* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + ComponentOid type_id; /* OBJECT IDENTIFIER */ + ComponentAnyDefinedBy value; /* ANY DEFINED BY type-id */ + ComponentOcts extension; /* OCTET STRING OPTIONAL */ +} ComponentORAddress; + +int MatchingComponentORAddress PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentORAddress PROTO (( void* mem_op, ComponentReference *cr, ComponentORAddress *comp )); + + +int BDecComponentORAddress PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentORAddress **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentORAddress PROTO (( void* mem_op, GenBuf * b, ComponentORAddress **v, AsnLen *bytesDecoded, int mode)); + + + +typedef struct AttributeTypeAndValue /* SEQUENCE */ +{ + Syntax* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + ComponentOid type; /* OBJECT IDENTIFIER */ + ComponentAnyDefinedBy value; /* ANY DEFINED BY type */ +} ComponentAttributeTypeAndValue; + +int MatchingComponentAttributeTypeAndValue PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentAttributeTypeAndValue PROTO (( void* mem_op, ComponentReference *cr, ComponentAttributeTypeAndValue *comp )); + + +int BDecComponentAttributeTypeAndValue PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentAttributeTypeAndValue **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentAttributeTypeAndValue PROTO (( void* mem_op, GenBuf * b, ComponentAttributeTypeAndValue **v, AsnLen *bytesDecoded, int mode)); + + + +typedef struct DirectoryString /* CHOICE */ +{ + Syntax* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + enum DirectoryStringChoiceId + { + DIRECTORYSTRING_TELETEXSTRING, + DIRECTORYSTRING_PRINTABLESTRING, + DIRECTORYSTRING_UNIVERSALSTRING, + DIRECTORYSTRING_UTF8STRING, + DIRECTORYSTRING_BMPSTRING + } choiceId; + union DirectoryStringChoiceUnion + { + ComponentTeletexString* teletexString; /* TeletexString SIZE 1..MAX */ + ComponentPrintableString* printableString; /* PrintableString SIZE 1..MAX */ + ComponentUniversalString* universalString; /* UniversalString SIZE 1..MAX */ + ComponentUTF8String* utf8String; /* UTF8String SIZE 1..MAX */ + ComponentBMPString* bmpString; /* BMPString SIZE 1..MAX */ + } a; +} ComponentDirectoryString; + +int MatchingComponentDirectoryString PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentDirectoryString PROTO (( void* mem_op, ComponentReference *cr, ComponentDirectoryString *comp )); + + +int BDecComponentDirectoryString PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentDirectoryString **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentDirectoryString PROTO (( void* mem_op, GenBuf * b, ComponentDirectoryString **v, AsnLen *bytesDecoded, int mode)); + + + +typedef struct EDIPartyName /* SEQUENCE */ +{ + Syntax* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + ComponentDirectoryString* nameAssigner; /* [0] DirectoryString OPTIONAL */ + ComponentDirectoryString* partyName; /* [1] DirectoryString */ +} ComponentEDIPartyName; + +int MatchingComponentEDIPartyName PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentEDIPartyName PROTO (( void* mem_op, ComponentReference *cr, ComponentEDIPartyName *comp )); + + +int BDecComponentEDIPartyName PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentEDIPartyName **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentEDIPartyName PROTO (( void* mem_op, GenBuf * b, ComponentEDIPartyName **v, AsnLen *bytesDecoded, int mode)); + + + +typedef ComponentList ComponentRelativeDistinguishedName; /* SET OF AttributeTypeAndValue */ + +int MatchingComponentRelativeDistinguishedName PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentRelativeDistinguishedName PROTO (( void* mem_op, ComponentReference *cr, ComponentRelativeDistinguishedName *comp )); + + +int BDecComponentRelativeDistinguishedName PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentRelativeDistinguishedName **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentRelativeDistinguishedName PROTO (( void* mem_op, GenBuf * b, ComponentRelativeDistinguishedName **v, AsnLen *bytesDecoded, int mode)); + + + +typedef ComponentList ComponentRDNSequence; /* SEQUENCE OF RelativeDistinguishedName */ + +int MatchingComponentRDNSequence PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentRDNSequence PROTO (( void* mem_op, ComponentReference *cr, ComponentRDNSequence *comp )); + + +int BDecComponentRDNSequence PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentRDNSequence **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentRDNSequence PROTO (( void* mem_op, GenBuf * b, ComponentRDNSequence **v, AsnLen *bytesDecoded, int mode)); + + + +typedef struct Name /* CHOICE */ +{ + Syntax* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + enum NameChoiceId + { + NAME_RDNSEQUENCE + } choiceId; + union NameChoiceUnion + { + ComponentRDNSequence* rdnSequence; /* RDNSequence */ + } a; +} ComponentName; + +int MatchingComponentName PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentName PROTO (( void* mem_op, ComponentReference *cr, ComponentName *comp )); + + +int BDecComponentName PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentName **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentName PROTO (( void* mem_op, GenBuf * b, ComponentName **v, AsnLen *bytesDecoded, int mode)); + + + +typedef struct GeneralName /* CHOICE */ +{ + Syntax* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + enum GeneralNameChoiceId + { + GENERALNAME_OTHERNAME, + GENERALNAME_RFC822NAME, + GENERALNAME_DNSNAME, + GENERALNAME_X400ADDRESS, + GENERALNAME_DIRECTORYNAME, + GENERALNAME_EDIPARTYNAME, + GENERALNAME_UNIFORMRESOURCEIDENTIFIER, + GENERALNAME_IPADDRESS, + GENERALNAME_REGISTEREDID + } choiceId; + union GeneralNameChoiceUnion + { + ComponentOtherName* otherName; /* [0] OtherName */ + ComponentIA5String* rfc822Name; /* [1] IA5String */ + ComponentIA5String* dNSName; /* [2] IA5String */ + ComponentORAddress* x400Address; /* [3] ORAddress */ + ComponentName* directoryName; /* [4] Name */ + ComponentEDIPartyName* ediPartyName; /* [5] EDIPartyName */ + ComponentIA5String* uniformResourceIdentifier; /* [6] IA5String */ + ComponentOcts* iPAddress; /* [7] OCTET STRING */ + ComponentOid* registeredID; /* [8] OBJECT IDENTIFIER */ + } a; +} ComponentGeneralName; + +int MatchingComponentGeneralName PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentGeneralName PROTO (( void* mem_op, ComponentReference *cr, ComponentGeneralName *comp )); + + +int BDecComponentGeneralName PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentGeneralName **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentGeneralName PROTO (( void* mem_op, GenBuf * b, ComponentGeneralName **v, AsnLen *bytesDecoded, int mode)); + + + +typedef ComponentList ComponentGeneralNames; /* SEQUENCE SIZE 1..MAX OF GeneralName */ + +int MatchingComponentGeneralNames PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentGeneralNames PROTO (( void* mem_op, ComponentReference *cr, ComponentGeneralNames *comp )); + + +int BDecComponentGeneralNames PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentGeneralNames **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentGeneralNames PROTO (( void* mem_op, GenBuf * b, ComponentGeneralNames **v, AsnLen *bytesDecoded, int mode)); + + + +typedef struct AuthorityKeyIdentifier /* SEQUENCE */ +{ + Syntax* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + ComponentKeyIdentifier keyIdentifier; /* [0] KeyIdentifier OPTIONAL */ + ComponentGeneralNames* authorityCertIssuer; /* [1] GeneralNames OPTIONAL */ + ComponentCertificateSerialNumber* authorityCertSerialNumber; /* [2] CertificateSerialNumber OPTIONAL */ +} ComponentAuthorityKeyIdentifier; + +int MatchingComponentAuthorityKeyIdentifier PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentAuthorityKeyIdentifier PROTO (( void* mem_op, ComponentReference *cr, ComponentAuthorityKeyIdentifier *comp )); + + +int BDecComponentAuthorityKeyIdentifier PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentAuthorityKeyIdentifier **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentAuthorityKeyIdentifier PROTO (( void* mem_op, GenBuf * b, ComponentAuthorityKeyIdentifier **v, AsnLen *bytesDecoded, int mode)); + + + +/* ========== Object Declarations ========== */ + + +/* ========== Object Set Declarations ========== */ +#ifdef __cplusplus +extern "C" { +#endif + +#endif /* conditional include of authorityKeyIdentifier.h */ diff --git a/contrib/slapd-modules/comp_match/certificate.asn1 b/contrib/slapd-modules/comp_match/certificate.asn1 new file mode 100644 index 0000000..db81897 --- /dev/null +++ b/contrib/slapd-modules/comp_match/certificate.asn1 @@ -0,0 +1,175 @@ +AuthenticationFramework {joint-iso-itu-t ds(5) module(1) authenticationFramework(7) 4} DEFINITIONS ::= +BEGIN +-- based on RFC 3280 and X.509 + +Certificate ::= SEQUENCE { + toBeSigned TBSCertificate, + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING +} + +TBSCertificate ::= SEQUENCE { + version [0] Version DEFAULT v1, + serialNumber CertificateSerialNumber, + signature AlgorithmIdentifier, + issuer Name, + validity Validity, + subject Name, + subjectPublicKeyInfo SubjectPublicKeyInfo, + issuerUniqueIdentifier [1] IMPLICIT UniqueIdentifier OPTIONAL, + -- if present, version shall be v2 or v3 + subjectUniqueIdentifier [2] IMPLICIT UniqueIdentifier OPTIONAL, + -- if present, version shall be v2 or v3 + extensions [3] Extensions OPTIONAL + -- If present, version shall be v3 -- } + +Version ::= INTEGER { v1(0), v2(1), v3(2) } + +CertificateSerialNumber ::= INTEGER + +AlgorithmIdentifier ::= SEQUENCE { + algorithm OBJECT IDENTIFIER, + parameters ANY DEFINED BY algorithm OPTIONAL -- DSA, SHA-1-- +} + +Name ::= CHOICE { + rdnSequence RDNSequence } + +RDNSequence ::= SEQUENCE OF RelativeDistinguishedName + +RelativeDistinguishedName ::= SET OF AttributeTypeAndValue + +AttributeTypeAndValue ::= SEQUENCE { + type AttributeType, + value ANY DEFINED BY type} + +AttributeType ::= OBJECT IDENTIFIER + +Validity ::= SEQUENCE { + notBefore Time, + notAfter Time } + +UniqueIdentifier ::= BIT STRING + +SubjectPublicKeyInfo ::= SEQUENCE { + algorithm AlgorithmIdentifier, + subjectPublicKey BIT STRING } + +Time ::= CHOICE { + utcTime UTCTime, + generalizedTime GeneralizedTime } + +Extensions ::= SEQUENCE SIZE(1..MAX) OF Extension + +Extension ::= SEQUENCE { + extnID OBJECT IDENTIFIER, + critical BOOLEAN DEFAULT FALSE, + extnValue OCTET STRING +-- contains a DER encoding of a value of type &ExtnType +-- for the extension object identified by extnId -- +} + +nullOid OBJECT-TYPE + SYNTAX NULL + ACCESS read-write + STATUS mandatory + ::= { 1 2 840 113549 1 1 4 } + +nullOid2 OBJECT-TYPE + SYNTAX NULL + ACCESS read-write + STATUS mandatory + ::= { 1 2 840 113549 1 1 1 } + +nullOid3 OBJECT-TYPE + SYNTAX NULL + ACCESS read-write + STATUS mandatory + ::= { 1 2 840 113549 1 1 5 } + +printableStringOid OBJECT-TYPE + SYNTAX PrintableString + ACCESS read-write + STATUS mandatory + ::= { 2 5 4 3 } + +printableStringOid2 OBJECT-TYPE + SYNTAX PrintableString + ACCESS read-write + STATUS mandatory + ::= { 2 5 4 6 } + +printableStringOid3 OBJECT-TYPE + SYNTAX PrintableString + ACCESS read-write + STATUS mandatory + ::= { 2 5 4 7 } + +printableStringOid4 OBJECT-TYPE + SYNTAX PrintableString + ACCESS read-write + STATUS mandatory + ::= { 2 5 4 8 } + +printableStringOid5 OBJECT-TYPE + SYNTAX PrintableString + ACCESS read-write + STATUS mandatory + ::= { 2 5 4 10 } + +printableStringOid6 OBJECT-TYPE + SYNTAX PrintableString + ACCESS read-write + STATUS mandatory + ::= { 2 5 4 11 } + +printableStringOid7 OBJECT-TYPE + SYNTAX PrintableString + ACCESS read-write + STATUS mandatory + ::= { 0 9 2342 19200300 100 1 3 } + + +iA5StringOid OBJECT-TYPE + SYNTAX IA5String + ACCESS read-write + STATUS mandatory + ::= { 1 2 840 113549 1 9 1 } + +octetStringOid OBJECT-TYPE + SYNTAX OCTET STRING + ACCESS read-write + STATUS mandatory + ::= { 2 5 29 19 } + +octetStringOid2 OBJECT-TYPE + SYNTAX OCTET STRING + ACCESS read-write + STATUS mandatory + ::= { 2 16 840 1 113730 1 13 } + +octetStringOid3 OBJECT-TYPE + SYNTAX OCTET STRING + ACCESS read-write + STATUS mandatory + ::= { 2 5 29 14 } + +octetStringOid4 OBJECT-TYPE + SYNTAX OCTET STRING + ACCESS read-write + STATUS mandatory + ::= { 2 5 29 21 } + +octetStringOid5 OBJECT-TYPE + SYNTAX OCTET STRING + ACCESS read-write + STATUS mandatory + ::= { 2 5 29 20 } + +octetStringOid7 OBJECT-TYPE + SYNTAX OCTET STRING + ACCESS read-write + STATUS mandatory + ::= { 2 5 29 28 } + +END diff --git a/contrib/slapd-modules/comp_match/certificate.c b/contrib/slapd-modules/comp_match/certificate.c new file mode 100644 index 0000000..8b58bdb --- /dev/null +++ b/contrib/slapd-modules/comp_match/certificate.c @@ -0,0 +1,3249 @@ +/* + * certificate.c + * "AuthenticationFramework" ASN.1 module encode/decode/extracting/matching/free C src. + * This file was generated by modified eSMACC compiler Sat Dec 11 11:22:49 2004 + * The generated files are supposed to be compiled as a module for OpenLDAP Software + */ + +#include "certificate.h" + +BDecComponentCertificateTop( void* mem_op, GenBuf* b, void **v, AsnLen* bytesDecoded,int mode) { + AsnTag tag; + AsnLen elmtLen; + + tag = BDecTag ( b, bytesDecoded ); + elmtLen = BDecLen ( b, bytesDecoded ); + if ( elmtLen <= 0 ) return (-1); + if ( tag != MAKE_TAG_ID (UNIV, CONS, SEQ_TAG_CODE) ) { + return (-1); + } + + return BDecComponentCertificate( mem_op, b, tag, elmtLen, (ComponentCertificate**)v,(AsnLen*)bytesDecoded, mode ); +} + +void init_module_AuthenticationFramework() { + /* Register Certificate OID and its decoder */ + InstallOidDecoderMapping( "2.5.4.36", NULL, + GDecComponentCertificate, + BDecComponentCertificateTop, + ExtractingComponentCertificate, + MatchingComponentCertificate ); + InitAnyAuthenticationFramework(); +} + +void InitAnyAuthenticationFramework() +{ + AsnOid oid0 ={ 9, "\52\206\110\206\367\15\1\1\4" }; + AsnOid oid1 ={ 9, "\52\206\110\206\367\15\1\1\1" }; + AsnOid oid2 ={ 9, "\52\206\110\206\367\15\1\1\5" }; + AsnOid oid3 ={ 3, "\125\4\3" }; + AsnOid oid4 ={ 3, "\125\4\6" }; + AsnOid oid5 ={ 3, "\125\4\7" }; + AsnOid oid6 ={ 3, "\125\4\10" }; + AsnOid oid7 ={ 3, "\125\4\12" }; + AsnOid oid8 ={ 3, "\125\4\13" }; + AsnOid oid9 ={ 10, "\11\222\46\211\223\362\54\144\1\3" }; + AsnOid oid10 ={ 9, "\52\206\110\206\367\15\1\11\1" }; + AsnOid oid11 ={ 3, "\125\35\23" }; + AsnOid oid12 ={ 9, "\140\206\110\1\206\370\102\1\15" }; + AsnOid oid13 ={ 3, "\125\35\16" }; + AsnOid oid14 ={ 3, "\125\35\25" }; + AsnOid oid15 ={ 3, "\125\35\24" }; + AsnOid oid17 ={ 3, "\125\35\34" }; + + + InstallAnyByComponentOid (nullOid_ANY_ID, &oid0, sizeof (ComponentNull), (EncodeFcn)BEncAsnNull, (gser_decoder_func*)GDecComponentNull, (ber_tag_decoder_func*)BDecComponentNullTag, (ExtractFcn)NULL,(MatchFcn)MatchingComponentNull,(FreeFcn)FreeComponentNull, (PrintFcn)NULL); + + InstallAnyByComponentOid (nullOid2_ANY_ID, &oid1, sizeof (ComponentNull), (EncodeFcn)BEncAsnNull, (gser_decoder_func*)GDecComponentNull, (ber_tag_decoder_func*)BDecComponentNullTag, (ExtractFcn)NULL,(MatchFcn)MatchingComponentNull,(FreeFcn)FreeComponentNull, (PrintFcn)NULL); + + InstallAnyByComponentOid (nullOid3_ANY_ID, &oid2, sizeof (ComponentNull), (EncodeFcn)BEncAsnNull, (gser_decoder_func*)GDecComponentNull, (ber_tag_decoder_func*)BDecComponentNullTag, (ExtractFcn)NULL,(MatchFcn)MatchingComponentNull,(FreeFcn)FreeComponentNull, (PrintFcn)NULL); + + InstallAnyByComponentOid (printableStringOid_ANY_ID, &oid3, sizeof (ComponentPrintableString), (EncodeFcn)BEncPrintableString, (gser_decoder_func*)GDecComponentPrintableString, (ber_tag_decoder_func*)BDecComponentPrintableStringTag, (ExtractFcn)NULL,(MatchFcn)MatchingComponentPrintableString,(FreeFcn)FreeComponentPrintableString, (PrintFcn)NULL); + + InstallAnyByComponentOid (printableStringOid2_ANY_ID, &oid4, sizeof (ComponentPrintableString), (EncodeFcn)BEncPrintableString, (gser_decoder_func*)GDecComponentPrintableString, (ber_tag_decoder_func*)BDecComponentPrintableStringTag, (ExtractFcn)NULL,(MatchFcn)MatchingComponentPrintableString,(FreeFcn)FreeComponentPrintableString, (PrintFcn)NULL); + + InstallAnyByComponentOid (printableStringOid3_ANY_ID, &oid5, sizeof (ComponentPrintableString), (EncodeFcn)BEncPrintableString, (gser_decoder_func*)GDecComponentPrintableString, (ber_tag_decoder_func*)BDecComponentPrintableStringTag, (ExtractFcn)NULL,(MatchFcn)MatchingComponentPrintableString,(FreeFcn)FreeComponentPrintableString, (PrintFcn)NULL); + + InstallAnyByComponentOid (printableStringOid4_ANY_ID, &oid6, sizeof (ComponentPrintableString), (EncodeFcn)BEncPrintableString, (gser_decoder_func*)GDecComponentPrintableString, (ber_tag_decoder_func*)BDecComponentPrintableStringTag, (ExtractFcn)NULL,(MatchFcn)MatchingComponentPrintableString,(FreeFcn)FreeComponentPrintableString, (PrintFcn)NULL); + + InstallAnyByComponentOid (printableStringOid5_ANY_ID, &oid7, sizeof (ComponentPrintableString), (EncodeFcn)BEncPrintableString, (gser_decoder_func*)GDecComponentPrintableString, (ber_tag_decoder_func*)BDecComponentPrintableStringTag, (ExtractFcn)NULL,(MatchFcn)MatchingComponentPrintableString,(FreeFcn)FreeComponentPrintableString, (PrintFcn)NULL); + + InstallAnyByComponentOid (printableStringOid6_ANY_ID, &oid8, sizeof (ComponentPrintableString), (EncodeFcn)BEncPrintableString, (gser_decoder_func*)GDecComponentPrintableString, (ber_tag_decoder_func*)BDecComponentPrintableStringTag, (ExtractFcn)NULL,(MatchFcn)MatchingComponentPrintableString,(FreeFcn)FreeComponentPrintableString, (PrintFcn)NULL); + + InstallAnyByComponentOid (printableStringOid7_ANY_ID, &oid9, sizeof (ComponentTeletexString), (EncodeFcn)BEncTeletexString, (gser_decoder_func*)GDecComponentTeletexString, (ber_tag_decoder_func*)BDecComponentTeletexStringTag, (ExtractFcn)NULL,(MatchFcn)MatchingComponentTeletexString,(FreeFcn)FreeComponentTeletexString, (PrintFcn)NULL); + + InstallAnyByComponentOid (iA5StringOid_ANY_ID, &oid10, sizeof (ComponentIA5String), (EncodeFcn)BEncIA5String, (gser_decoder_func*)GDecComponentIA5String, (ber_tag_decoder_func*)BDecComponentIA5StringTag, (ExtractFcn)NULL,(MatchFcn)MatchingComponentIA5String,(FreeFcn)FreeComponentIA5String, (PrintFcn)NULL); + + InstallAnyByComponentOid (octetStringOid_ANY_ID, &oid11, sizeof (ComponentOcts), (EncodeFcn)BEncAsnOcts, (gser_decoder_func*)GDecComponentOcts, (ber_tag_decoder_func*)BDecComponentOctsTag, (ExtractFcn)NULL,(MatchFcn)MatchingComponentOcts,(FreeFcn)FreeComponentOcts, (PrintFcn)NULL); + + InstallAnyByComponentOid (octetStringOid2_ANY_ID, &oid12, sizeof (ComponentOcts), (EncodeFcn)BEncAsnOcts, (gser_decoder_func*)GDecComponentOcts, (ber_tag_decoder_func*)BDecComponentOctsTag, (ExtractFcn)NULL,(MatchFcn)MatchingComponentOcts,(FreeFcn)FreeComponentOcts, (PrintFcn)NULL); + + InstallAnyByComponentOid (octetStringOid3_ANY_ID, &oid13, sizeof (ComponentOcts), (EncodeFcn)BEncAsnOcts, (gser_decoder_func*)GDecComponentOcts, (ber_tag_decoder_func*)BDecComponentOctsTag, (ExtractFcn)NULL,(MatchFcn)MatchingComponentOcts,(FreeFcn)FreeComponentOcts, (PrintFcn)NULL); + + InstallAnyByComponentOid (octetStringOid4_ANY_ID, &oid14, sizeof (ComponentOcts), (EncodeFcn)BEncAsnOcts, (gser_decoder_func*)GDecComponentOcts, (ber_tag_decoder_func*)BDecComponentOctsTag, (ExtractFcn)NULL,(MatchFcn)MatchingComponentOcts,(FreeFcn)FreeComponentOcts, (PrintFcn)NULL); + + InstallAnyByComponentOid (octetStringOid5_ANY_ID, &oid15, sizeof (ComponentOcts), (EncodeFcn)BEncAsnOcts, (gser_decoder_func*)GDecComponentOcts, (ber_tag_decoder_func*)BDecComponentOctsTag, (ExtractFcn)NULL,(MatchFcn)MatchingComponentOcts,(FreeFcn)FreeComponentOcts, (PrintFcn)NULL); + + InstallAnyByComponentOid (octetStringOid7_ANY_ID, &oid17, sizeof (ComponentOcts), (EncodeFcn)BEncAsnOcts, (gser_decoder_func*)GDecComponentOcts, (ber_tag_decoder_func*)BDecComponentOctsTag, (ExtractFcn)NULL,(MatchFcn)MatchingComponentOcts,(FreeFcn)FreeComponentOcts, (PrintFcn)NULL); + +} /* InitAnyAuthenticationFramework */ + +int +MatchingComponentAlgorithmIdentifier ( char* oid, ComponentSyntaxInfo* csi_attr, ComponentSyntaxInfo* csi_assert ) { + int rc; + MatchingRule* mr; + + if ( oid ) { + mr = retrieve_matching_rule( oid, csi_attr->csi_comp_desc->cd_type_id); + if ( mr ) return component_value_match( mr, csi_attr, csi_assert ); + } + + rc = 1; + rc = MatchingComponentOid ( oid, (ComponentSyntaxInfo*)&((ComponentAlgorithmIdentifier*)csi_attr)->algorithm, (ComponentSyntaxInfo*)&((ComponentAlgorithmIdentifier*)csi_assert)->algorithm ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + rc = SetAnyTypeByComponentOid ((ComponentSyntaxInfo*)&((ComponentAlgorithmIdentifier*)csi_attr)->parameters, (&((ComponentAlgorithmIdentifier*)csi_attr)->algorithm)); + rc = MatchingComponentAnyDefinedBy ( oid, (ComponentAny*)&((ComponentAlgorithmIdentifier*)csi_attr)->parameters, (ComponentAny*)&((ComponentAlgorithmIdentifier*)csi_assert)->parameters); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + return LDAP_COMPARE_TRUE; +} /* BMatchingComponentAlgorithmIdentifier */ + +void* +ExtractingComponentAlgorithmIdentifier ( void* mem_op, ComponentReference* cr, ComponentAlgorithmIdentifier *comp ) +{ + + if ( ( comp->algorithm.identifier.bv_val && strncmp(comp->algorithm.identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->algorithm.id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return &comp->algorithm; + else + return NULL; + } + if ( ( comp->parameters.identifier.bv_val && strncmp(comp->parameters.identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->parameters.id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return &comp->parameters; + else if ( cr->cr_curr->ci_next->ci_type == LDAP_COMPREF_CONTENT) { + cr->cr_curr = cr->cr_curr->ci_next; + return &comp->parameters; + } else { + return NULL; + } + } + return NULL; +} /* ExtractingComponentAlgorithmIdentifier */ + +int +BDecComponentAlgorithmIdentifier PARAMS ((b, tagId0, elmtLen0, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +AsnTag tagId0 _AND_ +AsnLen elmtLen0 _AND_ +ComponentAlgorithmIdentifier **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + int seqDone = FALSE; + AsnLen totalElmtsLen1 = 0; + AsnLen elmtLen1; + AsnTag tagId1; + int mandatoryElmtCount1 = 0; + int old_mode = mode; + int rc; + ComponentAlgorithmIdentifier *k, *t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + tagId1 = BDecTag (b, &totalElmtsLen1 ); + + if (((tagId1 == MAKE_TAG_ID (UNIV, PRIM, OID_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentOid (mem_op, b, tagId1, elmtLen1, (&k->algorithm), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->algorithm)->identifier.bv_val = (&k->algorithm)->id_buf; + (&k->algorithm)->identifier.bv_len = strlen("algorithm"); + strcpy( (&k->algorithm)->identifier.bv_val, "algorithm"); + if ((elmtLen0 != INDEFINITE_LEN) && (totalElmtsLen1 == elmtLen0)) + seqDone = TRUE; + else + { + tagId1 = BufPeekByte (b); + if ((elmtLen0 == INDEFINITE_LEN) && (tagId1 == EOC_TAG_ID)) + { + BDecEoc (b, &totalElmtsLen1 ); + seqDone = TRUE; + } + } + } + else + return -1; + + + + if (!seqDone) { + rc = SetAnyTypeByComponentOid ((&k->parameters), (&k->algorithm)); + rc = BDecComponentAnyDefinedBy (mem_op,b, (&k->parameters), &totalElmtsLen1, mode ); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->parameters)->identifier.bv_val = (&k->parameters)->id_buf; + (&k->parameters)->identifier.bv_len = strlen("parameters"); + strcpy( (&k->parameters)->identifier.bv_val, "parameters"); + seqDone = TRUE; + if (elmtLen0 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + else if (totalElmtsLen1 != elmtLen0) + return -1; + + } + + + if (!seqDone) + return -1; + + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentAlgorithmIdentifier*) CompAlloc( mem_op, sizeof(ComponentAlgorithmIdentifier) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentAlgorithmIdentifier ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentAlgorithmIdentifier ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentAlgorithmIdentifier; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentAlgorithmIdentifier; + (*bytesDecoded) += totalElmtsLen1; + return LDAP_SUCCESS; +} /* BDecAlgorithmIdentifier*/ + +int +GDecComponentAlgorithmIdentifier PARAMS (( mem_op,b, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +ComponentAlgorithmIdentifier **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + char* peek_head,*peek_head2; + int i, strLen,strLen2, rc, old_mode = mode; + ComponentAlgorithmIdentifier *k,*t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + *bytesDecoded = 0; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '{'){ + Asn1Error("Missing { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + if ( strncmp( peek_head, "algorithm", strlen("algorithm") ) == 0 ) { + rc = GDecComponentOid (mem_op, b, (&k->algorithm), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->algorithm)->identifier.bv_val = peek_head; + (&k->algorithm)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "parameters", strlen("parameters") ) == 0 ) { + rc = rc = SetAnyTypeByComponentOid ((&k->parameters), (&k->algorithm)); + rc = GDecComponentAnyDefinedBy (mem_op, b, (&k->parameters), bytesDecoded, mode ); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->parameters)->identifier.bv_val = peek_head; + (&k->parameters)->identifier.bv_len = strLen; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ) { + Asn1Error("Error during Reading } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '}'){ + Asn1Error("Missing } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentAlgorithmIdentifier*) CompAlloc( mem_op, sizeof(ComponentAlgorithmIdentifier) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentAlgorithmIdentifier ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentAlgorithmIdentifier ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentAlgorithmIdentifier; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentAlgorithmIdentifier; + return LDAP_SUCCESS; +} /* GDecAlgorithmIdentifier*/ + + +int +MatchingComponentTime ( char* oid, ComponentSyntaxInfo* csi_attr, ComponentSyntaxInfo* csi_assert ) { + int rc; + MatchingRule* mr; + ComponentTime *v1, *v2; + + + v1 = (ComponentTime*)csi_attr; + v2 = (ComponentTime*)csi_assert; + if ( oid ) { + mr = retrieve_matching_rule( oid, csi_attr->csi_comp_desc->cd_type_id); + if ( mr ) return component_value_match( mr, csi_attr, csi_assert ); + } + + if( (v1->choiceId != v2->choiceId ) ) + return LDAP_COMPARE_FALSE; + switch( v1->choiceId ) + { + case TIME_UTCTIME : + rc = MatchingComponentUTCTime ( oid, (ComponentSyntaxInfo*)(v1->a.utcTime), (ComponentSyntaxInfo*)(v2->a.utcTime) ); + break; + case TIME_GENERALIZEDTIME : + rc = MatchingComponentGeneralizedTime ( oid, (ComponentSyntaxInfo*)(v1->a.generalizedTime), (ComponentSyntaxInfo*)(v2->a.generalizedTime) ); + break; + default : + return LDAP_PROTOCOL_ERROR; + } + return rc; +} /* BMatchingComponentTimeContent */ + +void* +ExtractingComponentTime ( void* mem_op, ComponentReference* cr, ComponentTime *comp ) +{ + + + if( (comp->choiceId) == TIME_UTCTIME && + (( comp->a.utcTime->identifier.bv_val && strncmp(comp->a.utcTime->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0) || + ( strncmp(comp->a.utcTime->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0))) { + if ( cr->cr_curr->ci_next == NULL ) + return (comp->a.utcTime); + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentUTCTime ( mem_op, cr, (comp->a.utcTime) ); + }; + } + if( (comp->choiceId) == TIME_GENERALIZEDTIME && + (( comp->a.generalizedTime->identifier.bv_val && strncmp(comp->a.generalizedTime->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0) || + ( strncmp(comp->a.generalizedTime->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0))) { + if ( cr->cr_curr->ci_next == NULL ) + return (comp->a.generalizedTime); + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentGeneralizedTime ( mem_op, cr, (comp->a.generalizedTime) ); + }; + } + return NULL; +} /* ExtractingComponentTime */ + +int +BDecComponentTime PARAMS ((b, tagId0, elmtLen0, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +AsnTag tagId0 _AND_ +AsnLen elmtLen0 _AND_ +ComponentTime **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + int seqDone = FALSE; + AsnLen totalElmtsLen1 = 0; + AsnLen elmtLen1; + AsnTag tagId1; + int mandatoryElmtCount1 = 0; + int old_mode = mode; + int rc; + ComponentTime *k, *t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + switch (tagId0) + { + case MAKE_TAG_ID (UNIV, PRIM, UTCTIME_TAG_CODE): + case MAKE_TAG_ID (UNIV, CONS, UTCTIME_TAG_CODE): + (k->choiceId) = TIME_UTCTIME; + rc = BDecComponentUTCTime (mem_op, b, tagId0, elmtLen0, (&k->a.utcTime), &totalElmtsLen1, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.utcTime)->identifier.bv_val = (k->a.utcTime)->id_buf; + (k->a.utcTime)->identifier.bv_len = strlen("utcTime"); + strcpy( (k->a.utcTime)->identifier.bv_val, "utcTime"); + break; + + case MAKE_TAG_ID (UNIV, PRIM, GENERALIZEDTIME_TAG_CODE): + case MAKE_TAG_ID (UNIV, CONS, GENERALIZEDTIME_TAG_CODE): + (k->choiceId) = TIME_GENERALIZEDTIME; + rc = BDecComponentGeneralizedTime (mem_op, b, tagId0, elmtLen0, (&k->a.generalizedTime), &totalElmtsLen1, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.generalizedTime)->identifier.bv_val = (k->a.generalizedTime)->id_buf; + (k->a.generalizedTime)->identifier.bv_len = strlen("generalizedTime"); + strcpy( (k->a.generalizedTime)->identifier.bv_val, "generalizedTime"); + break; + + default: + Asn1Error ("ERROR - unexpected tag in CHOICE\n"); + return -1; + break; + } /* end switch */ + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentTime*) CompAlloc( mem_op, sizeof(ComponentTime) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentTime ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentTime ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentTime; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentTime; + (*bytesDecoded) += totalElmtsLen1; + return LDAP_SUCCESS; +} /* BDecTimeContent */ + +int +GDecComponentTime PARAMS (( mem_op,b, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +ComponentTime **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + char* peek_head,*peek_head2; + int i, strLen,strLen2, rc, old_mode = mode; + ComponentTime *k,*t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen2 = LocateNextGSERToken(mem_op,b,&peek_head2,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head2 != ':'){ + Asn1Error("Missing : in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + if( strncmp("utcTime",peek_head, strlen("utcTime")) == 0){ + (k->choiceId) = TIME_UTCTIME; + rc = GDecComponentUTCTime (mem_op, b, (&k->a.utcTime), bytesDecoded, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.utcTime)->identifier.bv_val = peek_head; + (k->a.utcTime)->identifier.bv_len = strLen; + } + else if( strncmp("generalizedTime",peek_head,strlen("generalizedTime")) == 0){ + (k->choiceId) = TIME_GENERALIZEDTIME; + rc = GDecComponentGeneralizedTime (mem_op, b, (&k->a.generalizedTime), bytesDecoded, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.generalizedTime)->identifier.bv_val = peek_head; + (k->a.generalizedTime)->identifier.bv_len = strLen; + } + else { + Asn1Error("Undefined Identifier"); + return LDAP_PROTOCOL_ERROR; + } + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentTime*) CompAlloc( mem_op, sizeof(ComponentTime) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentTime ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentTime ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentTime; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentTime; + return LDAP_SUCCESS; +} /* GDecTimeContent */ + + +int +MatchingComponentExtension ( char* oid, ComponentSyntaxInfo* csi_attr, ComponentSyntaxInfo* csi_assert ) { + int rc; + MatchingRule* mr; + + if ( oid ) { + mr = retrieve_matching_rule( oid, csi_attr->csi_comp_desc->cd_type_id); + if ( mr ) return component_value_match( mr, csi_attr, csi_assert ); + } + + rc = 1; + rc = MatchingComponentOid ( oid, (ComponentSyntaxInfo*)&((ComponentExtension*)csi_attr)->extnID, (ComponentSyntaxInfo*)&((ComponentExtension*)csi_assert)->extnID ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + rc = MatchingComponentBool ( oid, (ComponentSyntaxInfo*)((ComponentExtension*)csi_attr)->critical, (ComponentSyntaxInfo*)((ComponentExtension*)csi_assert)->critical ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + rc = MatchingComponentOcts ( oid, (ComponentSyntaxInfo*)&((ComponentExtension*)csi_attr)->extnValue, (ComponentSyntaxInfo*)&((ComponentExtension*)csi_assert)->extnValue ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + return LDAP_COMPARE_TRUE; +} /* BMatchingComponentExtension */ + +void* +ExtractingComponentExtension ( void* mem_op, ComponentReference* cr, ComponentExtension *comp ) +{ + + if ( ( comp->extnID.identifier.bv_val && strncmp(comp->extnID.identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->extnID.id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return &comp->extnID; + else + return NULL; + } + if ( ( comp->critical->identifier.bv_val && strncmp(comp->critical->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->critical->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->critical; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentBool ( mem_op, cr, comp->critical ); + } + } + if ( ( comp->extnValue.identifier.bv_val && strncmp(comp->extnValue.identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->extnValue.id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return &comp->extnValue; + else if ( cr->cr_curr->ci_next->ci_type == LDAP_COMPREF_CONTENT) { + cr->cr_curr = cr->cr_curr->ci_next; + return &comp->extnValue; + } else { + return NULL; + } + } + return NULL; +} /* ExtractingComponentExtension */ + +int +BDecComponentExtension PARAMS ((b, tagId0, elmtLen0, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +AsnTag tagId0 _AND_ +AsnLen elmtLen0 _AND_ +ComponentExtension **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + int seqDone = FALSE; + AsnLen totalElmtsLen1 = 0; + AsnLen elmtLen1; + AsnTag tagId1; + int mandatoryElmtCount1 = 0; + int old_mode = mode; + int rc; + ComponentExtension *k, *t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + tagId1 = BDecTag (b, &totalElmtsLen1 ); + + if (((tagId1 == MAKE_TAG_ID (UNIV, PRIM, OID_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentOid (mem_op, b, tagId1, elmtLen1, (&k->extnID), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->extnID)->identifier.bv_val = (&k->extnID)->id_buf; + (&k->extnID)->identifier.bv_len = strlen("extnID"); + strcpy( (&k->extnID)->identifier.bv_val, "extnID"); + tagId1 = BDecTag (b, &totalElmtsLen1); + } + else + return -1; + + + + if (((tagId1 == MAKE_TAG_ID (UNIV, PRIM, BOOLEAN_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentBool (mem_op, b, tagId1, elmtLen1, (&k->critical), &totalElmtsLen1, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->critical)->identifier.bv_val = (k->critical)->id_buf; + (k->critical)->identifier.bv_len = strlen("critical"); + strcpy( (k->critical)->identifier.bv_val, "critical"); + tagId1 = BDecTag (b, &totalElmtsLen1); + } + + + if (((tagId1 == MAKE_TAG_ID (UNIV, PRIM, OCTETSTRING_TAG_CODE)) || +(tagId1 == MAKE_TAG_ID (UNIV, CONS, OCTETSTRING_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentOcts (mem_op, b, tagId1, elmtLen1, (&k->extnValue), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->extnValue)->identifier.bv_val = (&k->extnValue)->id_buf; + (&k->extnValue)->identifier.bv_len = strlen("extnValue"); + strcpy( (&k->extnValue)->identifier.bv_val, "extnValue"); + seqDone = TRUE; + if (elmtLen0 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + else if (totalElmtsLen1 != elmtLen0) + return -1; + + } + else + return -1; + + + + if (!seqDone) + return -1; + + if(!COMPONENTNOT_NULL ((k->critical))) + { +(k->critical) = CompAlloc( mem_op, sizeof(ComponentBool)); + (k->critical)->identifier.bv_val = (k->critical)->id_buf; + (k->critical)->identifier.bv_len = strlen("critical"); + strcpy( (k->critical)->identifier.bv_val, "critical"); + (k->critical)->value = 0; + } + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentExtension*) CompAlloc( mem_op, sizeof(ComponentExtension) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentExtension ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentExtension ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentExtension; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentExtension; + (*bytesDecoded) += totalElmtsLen1; + return LDAP_SUCCESS; +} /* BDecExtension*/ + +int +GDecComponentExtension PARAMS (( mem_op,b, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +ComponentExtension **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + char* peek_head,*peek_head2; + int i, strLen,strLen2, rc, old_mode = mode; + ComponentExtension *k,*t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + *bytesDecoded = 0; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '{'){ + Asn1Error("Missing { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + if ( strncmp( peek_head, "extnID", strlen("extnID") ) == 0 ) { + rc = GDecComponentOid (mem_op, b, (&k->extnID), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->extnID)->identifier.bv_val = peek_head; + (&k->extnID)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "critical", strlen("critical") ) == 0 ) { + rc = GDecComponentBool (mem_op, b, (&k->critical), bytesDecoded, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->critical)->identifier.bv_val = peek_head; + ( k->critical)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + else { +(k->critical) = CompAlloc( mem_op, sizeof(ComponentBool)); + (k->critical)->value = 0; + } + if ( strncmp( peek_head, "extnValue", strlen("extnValue") ) == 0 ) { + rc = GDecComponentOcts (mem_op, b, (&k->extnValue), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->extnValue)->identifier.bv_val = peek_head; + (&k->extnValue)->identifier.bv_len = strLen; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ) { + Asn1Error("Error during Reading } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '}'){ + Asn1Error("Missing } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentExtension*) CompAlloc( mem_op, sizeof(ComponentExtension) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentExtension ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentExtension ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentExtension; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentExtension; + return LDAP_SUCCESS; +} /* GDecExtension*/ + + +int +MatchingComponentAttributeTypeAndValue ( char* oid, ComponentSyntaxInfo* csi_attr, ComponentSyntaxInfo* csi_assert ) { + int rc; + MatchingRule* mr; + + if ( oid ) { + mr = retrieve_matching_rule( oid, csi_attr->csi_comp_desc->cd_type_id); + if ( mr ) return component_value_match( mr, csi_attr, csi_assert ); + } + + rc = 1; + rc = MatchingComponentAttributeType ( oid, (ComponentSyntaxInfo*)&((ComponentAttributeTypeAndValue*)csi_attr)->type, (ComponentSyntaxInfo*)&((ComponentAttributeTypeAndValue*)csi_assert)->type ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + rc = SetAnyTypeByComponentOid ((ComponentSyntaxInfo*)&((ComponentAttributeTypeAndValue*)csi_attr)->value, (&((ComponentAttributeTypeAndValue*)csi_attr)->type)); + rc = MatchingComponentAnyDefinedBy ( oid, (ComponentAny*)&((ComponentAttributeTypeAndValue*)csi_attr)->value, (ComponentAny*)&((ComponentAttributeTypeAndValue*)csi_assert)->value); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + return LDAP_COMPARE_TRUE; +} /* BMatchingComponentAttributeTypeAndValue */ + +void* +ExtractingComponentAttributeTypeAndValue ( void* mem_op, ComponentReference* cr, ComponentAttributeTypeAndValue *comp ) +{ + + if ( ( comp->type.identifier.bv_val && strncmp(comp->type.identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->type.id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return &comp->type; + else + return NULL; + } + if ( ( comp->value.identifier.bv_val && strncmp(comp->value.identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->value.id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return &comp->value; + else if ( cr->cr_curr->ci_next->ci_type == LDAP_COMPREF_SELECT ) { + cr->cr_curr = cr->cr_curr->ci_next; + return &comp->value; + } else { + return NULL; + } + } + return NULL; +} /* ExtractingComponentAttributeTypeAndValue */ + +int +BDecComponentAttributeTypeAndValue PARAMS ((b, tagId0, elmtLen0, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +AsnTag tagId0 _AND_ +AsnLen elmtLen0 _AND_ +ComponentAttributeTypeAndValue **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + int seqDone = FALSE; + AsnLen totalElmtsLen1 = 0; + AsnLen elmtLen1; + AsnTag tagId1; + int mandatoryElmtCount1 = 0; + int old_mode = mode; + int rc; + ComponentAttributeTypeAndValue *k, *t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + tagId1 = BDecTag (b, &totalElmtsLen1 ); + + if (((tagId1 == MAKE_TAG_ID (UNIV, PRIM, OID_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentAttributeType (mem_op, b, tagId1, elmtLen1, (&k->type), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->type)->identifier.bv_val = (&k->type)->id_buf; + (&k->type)->identifier.bv_len = strlen("type"); + strcpy( (&k->type)->identifier.bv_val, "type"); + } + else + return -1; + + + + { + rc = SetAnyTypeByComponentOid ((&k->value), (&k->type)); + rc = BDecComponentAnyDefinedBy (mem_op,b, (&k->value), &totalElmtsLen1, mode ); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->value)->identifier.bv_val = (&k->value)->id_buf; + (&k->value)->identifier.bv_len = strlen("value"); + strcpy( (&k->value)->identifier.bv_val, "value"); + seqDone = TRUE; + if (elmtLen0 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + else if (totalElmtsLen1 != elmtLen0) + return -1; + + } + + + if (!seqDone) + return -1; + + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentAttributeTypeAndValue*) CompAlloc( mem_op, sizeof(ComponentAttributeTypeAndValue) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentAttributeTypeAndValue ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentAttributeTypeAndValue ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentAttributeTypeAndValue; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentAttributeTypeAndValue; + (*bytesDecoded) += totalElmtsLen1; + return LDAP_SUCCESS; +} /* BDecAttributeTypeAndValue*/ + +int +GDecComponentAttributeTypeAndValue PARAMS (( mem_op,b, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +ComponentAttributeTypeAndValue **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + char* peek_head,*peek_head2; + int i, strLen,strLen2, rc, old_mode = mode; + ComponentAttributeTypeAndValue *k,*t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + *bytesDecoded = 0; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '{'){ + Asn1Error("Missing { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + if ( strncmp( peek_head, "type", strlen("type") ) == 0 ) { + rc = GDecComponentAttributeType (mem_op, b, (&k->type), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->type)->identifier.bv_val = peek_head; + (&k->type)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "value", strlen("value") ) == 0 ) { + rc = rc = SetAnyTypeByComponentOid ((&k->value), (&k->type)); + rc = GDecComponentAnyDefinedBy (mem_op, b, (&k->value), bytesDecoded, mode ); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->value)->identifier.bv_val = peek_head; + (&k->value)->identifier.bv_len = strLen; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ) { + Asn1Error("Error during Reading } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '}'){ + Asn1Error("Missing } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentAttributeTypeAndValue*) CompAlloc( mem_op, sizeof(ComponentAttributeTypeAndValue) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentAttributeTypeAndValue ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentAttributeTypeAndValue ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentAttributeTypeAndValue; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentAttributeTypeAndValue; + return LDAP_SUCCESS; +} /* GDecAttributeTypeAndValue*/ + + +int +MatchingComponentValidity ( char* oid, ComponentSyntaxInfo* csi_attr, ComponentSyntaxInfo* csi_assert ) { + int rc; + MatchingRule* mr; + + if ( oid ) { + mr = retrieve_matching_rule( oid, csi_attr->csi_comp_desc->cd_type_id); + if ( mr ) return component_value_match( mr, csi_attr, csi_assert ); + } + + rc = 1; + rc = MatchingComponentTime ( oid, (ComponentSyntaxInfo*)((ComponentValidity*)csi_attr)->notBefore, (ComponentSyntaxInfo*)((ComponentValidity*)csi_assert)->notBefore ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + rc = MatchingComponentTime ( oid, (ComponentSyntaxInfo*)((ComponentValidity*)csi_attr)->notAfter, (ComponentSyntaxInfo*)((ComponentValidity*)csi_assert)->notAfter ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + return LDAP_COMPARE_TRUE; +} /* BMatchingComponentValidity */ + +void* +ExtractingComponentValidity ( void* mem_op, ComponentReference* cr, ComponentValidity *comp ) +{ + + if ( ( comp->notBefore->identifier.bv_val && strncmp(comp->notBefore->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->notBefore->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->notBefore; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentTime ( mem_op, cr, comp->notBefore ); + } + } + if ( ( comp->notAfter->identifier.bv_val && strncmp(comp->notAfter->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->notAfter->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->notAfter; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentTime ( mem_op, cr, comp->notAfter ); + } + } + return NULL; +} /* ExtractingComponentValidity */ + +int +BDecComponentValidity PARAMS ((b, tagId0, elmtLen0, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +AsnTag tagId0 _AND_ +AsnLen elmtLen0 _AND_ +ComponentValidity **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + int seqDone = FALSE; + AsnLen totalElmtsLen1 = 0; + AsnLen elmtLen1; + AsnTag tagId1; + int mandatoryElmtCount1 = 0; + AsnLen totalElmtsLen2 = 0; + AsnLen elmtLen2; + AsnTag tagId2; + int old_mode = mode; + int rc; + ComponentValidity *k, *t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + tagId1 = BDecTag (b, &totalElmtsLen1 ); + + if (((tagId1 == MAKE_TAG_ID (UNIV, PRIM, UTCTIME_TAG_CODE)) || +(tagId1 == MAKE_TAG_ID (UNIV, CONS, UTCTIME_TAG_CODE)) || + (tagId1 ==MAKE_TAG_ID (UNIV, PRIM, GENERALIZEDTIME_TAG_CODE))|| + (tagId1 == MAKE_TAG_ID (UNIV, CONS, GENERALIZEDTIME_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentTime (mem_op, b, tagId1, elmtLen1, (&k->notBefore), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->notBefore)->identifier.bv_val = (k->notBefore)->id_buf; + (k->notBefore)->identifier.bv_len = strlen("notBefore"); + strcpy( (k->notBefore)->identifier.bv_val, "notBefore"); + tagId1 = BDecTag (b, &totalElmtsLen1); + } + else + return -1; + + + + if (((tagId1 == MAKE_TAG_ID (UNIV, PRIM, UTCTIME_TAG_CODE)) || +(tagId1 == MAKE_TAG_ID (UNIV, CONS, UTCTIME_TAG_CODE)) || + (tagId1 ==MAKE_TAG_ID (UNIV, PRIM, GENERALIZEDTIME_TAG_CODE))|| + (tagId1 == MAKE_TAG_ID (UNIV, CONS, GENERALIZEDTIME_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentTime (mem_op, b, tagId1, elmtLen1, (&k->notAfter), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->notAfter)->identifier.bv_val = (k->notAfter)->id_buf; + (k->notAfter)->identifier.bv_len = strlen("notAfter"); + strcpy( (k->notAfter)->identifier.bv_val, "notAfter"); + seqDone = TRUE; + if (elmtLen0 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + else if (totalElmtsLen1 != elmtLen0) + return -1; + + } + else + return -1; + + + + if (!seqDone) + return -1; + + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentValidity*) CompAlloc( mem_op, sizeof(ComponentValidity) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentValidity ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentValidity ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentValidity; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentValidity; + (*bytesDecoded) += totalElmtsLen1; + return LDAP_SUCCESS; +} /* BDecValidity*/ + +int +GDecComponentValidity PARAMS (( mem_op,b, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +ComponentValidity **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + char* peek_head,*peek_head2; + int i, strLen,strLen2, rc, old_mode = mode; + ComponentValidity *k,*t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + *bytesDecoded = 0; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '{'){ + Asn1Error("Missing { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + if ( strncmp( peek_head, "notBefore", strlen("notBefore") ) == 0 ) { + rc = GDecComponentTime (mem_op, b, (&k->notBefore), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->notBefore)->identifier.bv_val = peek_head; + ( k->notBefore)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "notAfter", strlen("notAfter") ) == 0 ) { + rc = GDecComponentTime (mem_op, b, (&k->notAfter), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->notAfter)->identifier.bv_val = peek_head; + ( k->notAfter)->identifier.bv_len = strLen; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ) { + Asn1Error("Error during Reading } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '}'){ + Asn1Error("Missing } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentValidity*) CompAlloc( mem_op, sizeof(ComponentValidity) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentValidity ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentValidity ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentValidity; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentValidity; + return LDAP_SUCCESS; +} /* GDecValidity*/ + + +int +MatchingComponentSubjectPublicKeyInfo ( char* oid, ComponentSyntaxInfo* csi_attr, ComponentSyntaxInfo* csi_assert ) { + int rc; + MatchingRule* mr; + + if ( oid ) { + mr = retrieve_matching_rule( oid, csi_attr->csi_comp_desc->cd_type_id); + if ( mr ) return component_value_match( mr, csi_attr, csi_assert ); + } + + rc = 1; + rc = MatchingComponentAlgorithmIdentifier ( oid, (ComponentSyntaxInfo*)((ComponentSubjectPublicKeyInfo*)csi_attr)->algorithm, (ComponentSyntaxInfo*)((ComponentSubjectPublicKeyInfo*)csi_assert)->algorithm ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + rc = MatchingComponentBits ( oid, (ComponentSyntaxInfo*)&((ComponentSubjectPublicKeyInfo*)csi_attr)->subjectPublicKey, (ComponentSyntaxInfo*)&((ComponentSubjectPublicKeyInfo*)csi_assert)->subjectPublicKey ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + return LDAP_COMPARE_TRUE; +} /* BMatchingComponentSubjectPublicKeyInfo */ + +void* +ExtractingComponentSubjectPublicKeyInfo ( void* mem_op, ComponentReference* cr, ComponentSubjectPublicKeyInfo *comp ) +{ + + if ( ( comp->algorithm->identifier.bv_val && strncmp(comp->algorithm->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->algorithm->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->algorithm; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentAlgorithmIdentifier ( mem_op, cr, comp->algorithm ); + } + } + if ( ( comp->subjectPublicKey.identifier.bv_val && strncmp(comp->subjectPublicKey.identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->subjectPublicKey.id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return &comp->subjectPublicKey; + else if ( cr->cr_curr->ci_next->ci_type == LDAP_COMPREF_CONTENT) { + cr->cr_curr = cr->cr_curr->ci_next; + return &comp->subjectPublicKey; + } else { + return NULL; + } + } + return NULL; +} /* ExtractingComponentSubjectPublicKeyInfo */ + +int +BDecComponentSubjectPublicKeyInfo PARAMS ((b, tagId0, elmtLen0, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +AsnTag tagId0 _AND_ +AsnLen elmtLen0 _AND_ +ComponentSubjectPublicKeyInfo **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + int seqDone = FALSE; + AsnLen totalElmtsLen1 = 0; + AsnLen elmtLen1; + AsnTag tagId1; + int mandatoryElmtCount1 = 0; + int old_mode = mode; + int rc; + ComponentSubjectPublicKeyInfo *k, *t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + tagId1 = BDecTag (b, &totalElmtsLen1 ); + + if (((tagId1 == MAKE_TAG_ID (UNIV, CONS, SEQ_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentAlgorithmIdentifier (mem_op, b, tagId1, elmtLen1, (&k->algorithm), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->algorithm)->identifier.bv_val = (k->algorithm)->id_buf; + (k->algorithm)->identifier.bv_len = strlen("algorithm"); + strcpy( (k->algorithm)->identifier.bv_val, "algorithm"); + tagId1 = BDecTag (b, &totalElmtsLen1); + } + else + return -1; + + + + if (((tagId1 == MAKE_TAG_ID (UNIV, PRIM, BITSTRING_TAG_CODE)) || +(tagId1 == MAKE_TAG_ID (UNIV, CONS, BITSTRING_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentBits (mem_op, b, tagId1, elmtLen1, (&k->subjectPublicKey), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->subjectPublicKey)->identifier.bv_val = (&k->subjectPublicKey)->id_buf; + (&k->subjectPublicKey)->identifier.bv_len = strlen("subjectPublicKey"); + strcpy( (&k->subjectPublicKey)->identifier.bv_val, "subjectPublicKey"); + seqDone = TRUE; + if (elmtLen0 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + else if (totalElmtsLen1 != elmtLen0) + return -1; + + } + else + return -1; + + + + if (!seqDone) + return -1; + + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentSubjectPublicKeyInfo*) CompAlloc( mem_op, sizeof(ComponentSubjectPublicKeyInfo) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentSubjectPublicKeyInfo ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentSubjectPublicKeyInfo ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentSubjectPublicKeyInfo; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentSubjectPublicKeyInfo; + (*bytesDecoded) += totalElmtsLen1; + return LDAP_SUCCESS; +} /* BDecSubjectPublicKeyInfo*/ + +int +GDecComponentSubjectPublicKeyInfo PARAMS (( mem_op,b, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +ComponentSubjectPublicKeyInfo **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + char* peek_head,*peek_head2; + int i, strLen,strLen2, rc, old_mode = mode; + ComponentSubjectPublicKeyInfo *k,*t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + *bytesDecoded = 0; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '{'){ + Asn1Error("Missing { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + if ( strncmp( peek_head, "algorithm", strlen("algorithm") ) == 0 ) { + rc = GDecComponentAlgorithmIdentifier (mem_op, b, (&k->algorithm), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->algorithm)->identifier.bv_val = peek_head; + ( k->algorithm)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "subjectPublicKey", strlen("subjectPublicKey") ) == 0 ) { + rc = GDecComponentBits (mem_op, b, (&k->subjectPublicKey), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->subjectPublicKey)->identifier.bv_val = peek_head; + (&k->subjectPublicKey)->identifier.bv_len = strLen; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ) { + Asn1Error("Error during Reading } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '}'){ + Asn1Error("Missing } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentSubjectPublicKeyInfo*) CompAlloc( mem_op, sizeof(ComponentSubjectPublicKeyInfo) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentSubjectPublicKeyInfo ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentSubjectPublicKeyInfo ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentSubjectPublicKeyInfo; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentSubjectPublicKeyInfo; + return LDAP_SUCCESS; +} /* GDecSubjectPublicKeyInfo*/ + + +int +MatchingComponentExtensions ( char* oid, ComponentSyntaxInfo* csi_attr, ComponentSyntaxInfo* csi_assert ) { + int rc; + MatchingRule* mr; + void* component1, *component2; + AsnList *v1, *v2, t_list; + + + if ( oid ) { + mr = retrieve_matching_rule( oid, csi_attr->csi_comp_desc->cd_type_id); + if ( mr ) return component_value_match( mr, csi_attr, csi_assert ); + } + + v1 = &((ComponentExtensions*)csi_attr)->comp_list; + v2 = &((ComponentExtensions*)csi_assert)->comp_list; + FOR_EACH_LIST_PAIR_ELMT(component1, component2, v1, v2) + { + if( MatchingComponentExtension(oid, (ComponentSyntaxInfo*)component1, (ComponentSyntaxInfo*)component2) == LDAP_COMPARE_FALSE) { + return LDAP_COMPARE_FALSE; + } + } /* end of for */ + + AsnListFirst( v1 ); + AsnListFirst( v2 ); + if( (!component1 && component2) || (component1 && !component2)) + return LDAP_COMPARE_FALSE; + else + return LDAP_COMPARE_TRUE; +} /* BMatchingComponentExtensionsContent */ + +void* +ExtractingComponentExtensions ( void* mem_op, ComponentReference* cr, ComponentExtensions *comp ) +{ + int count = 0; + int total; + AsnList *v = &comp->comp_list; + ComponentInt *k; + ComponentExtension *component; + + + switch ( cr->cr_curr->ci_type ) { + case LDAP_COMPREF_FROM_BEGINNING : + count = cr->cr_curr->ci_val.ci_from_beginning; + FOR_EACH_LIST_ELMT( component , v ) { + if( --count == 0 ) { + if( cr->cr_curr->ci_next == NULL ) + return component; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentExtension ( mem_op, cr, component ); + } + } + } + break; + case LDAP_COMPREF_FROM_END : + total = AsnListCount ( v ); + count = cr->cr_curr->ci_val.ci_from_end; + count = total + count +1; + FOR_EACH_LIST_ELMT ( component, v ) { + if( --count == 0 ) { + if( cr->cr_curr->ci_next == NULL ) + return component; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentExtension ( mem_op, cr, component ); + } + } + } + break; + case LDAP_COMPREF_ALL : + return comp; + case LDAP_COMPREF_COUNT : + k = (ComponentInt*)CompAlloc( mem_op, sizeof(ComponentInt)); + k->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + k->comp_desc->cd_tag = (-1); + k->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentInt; + k->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentInt; + k->comp_desc->cd_extract_i = (extract_component_from_id_func*)NULL; + k->comp_desc->cd_type = ASN_BASIC; + k->comp_desc->cd_type_id = BASICTYPE_INTEGER; + k->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentInt; + k->value = AsnListCount(v); + return k; + default : + return NULL; + } +} /* ExtractingComponentExtensions */ + +int +BDecComponentExtensions PARAMS ((b, tagId0, elmtLen0, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +AsnTag tagId0 _AND_ +AsnLen elmtLen0 _AND_ +ComponentExtensions **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + int seqDone = FALSE; + AsnLen totalElmtsLen1 = 0; + AsnLen elmtLen1; + AsnTag tagId1; + int mandatoryElmtCount1 = 0; + int old_mode = mode; + int rc; + ComponentExtensions *k, *t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + AsnListInit(&k->comp_list,sizeof(ComponentExtension)); + for (totalElmtsLen1 = 0; (totalElmtsLen1 < elmtLen0) || (elmtLen0 == INDEFINITE_LEN);) + { + ComponentExtension **tmpVar; + tagId1 = BDecTag (b, &totalElmtsLen1 ); + + if ((tagId1 == EOC_TAG_ID) && (elmtLen0 == INDEFINITE_LEN)) + { + BDEC_2ND_EOC_OCTET (b, &totalElmtsLen1 ) + break; /* got EOC so can exit this SET OF/SEQ OF's for loop*/ + } + if ((tagId1 == MAKE_TAG_ID (UNIV, CONS, SEQ_TAG_CODE))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + tmpVar = (ComponentExtension**) CompAsnListAppend (mem_op,&k->comp_list); + rc = BDecComponentExtension (mem_op, b, tagId1, elmtLen1, tmpVar, &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + } /* end of tag check if */ + else /* wrong tag */ + { + Asn1Error ("Unexpected Tag\n"); + return -1; + } + } /* end of for */ + + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentExtensions*) CompAlloc( mem_op, sizeof(ComponentExtensions) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentExtensions ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentExtensions ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentExtensions; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentExtensions; + (*bytesDecoded) += totalElmtsLen1; + return LDAP_SUCCESS; +} /* BDecExtensionsContent */ + +int +GDecComponentExtensions PARAMS (( mem_op,b, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +ComponentExtensions **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + char* peek_head,*peek_head2; + int i, strLen,strLen2, rc, old_mode = mode; + ComponentExtensions *k,*t, c_temp; + + + int ElmtsLen1; + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + AsnListInit( &k->comp_list, sizeof( ComponentExtension ) ); + *bytesDecoded = 0; + if( !(strLen = LocateNextGSERToken(mem_op,b, &peek_head, GSER_PEEK)) ){ + Asn1Error("Error during Reading { in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '{'){ + Asn1Error("Missing { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + + for (ElmtsLen1 = 0; ElmtsLen1 >= INDEFINITE_LEN; ElmtsLen1++) + { + ComponentExtension **tmpVar; + if( !(strLen = LocateNextGSERToken(mem_op,b, &peek_head, GSER_NO_COPY)) ){ + Asn1Error("Error during Reading{ in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head == '}') break; + if( !(*peek_head == '{' || *peek_head ==',') ) { + return LDAP_PROTOCOL_ERROR; + } + tmpVar = (ComponentExtension**) CompAsnListAppend (mem_op, &k->comp_list); + if ( tmpVar == NULL ) { + Asn1Error("Error during Reading{ in encoding"); + return LDAP_PROTOCOL_ERROR; + } + rc = GDecComponentExtension (mem_op, b, tmpVar, bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + } /* end of for */ + + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentExtensions*) CompAlloc( mem_op, sizeof(ComponentExtensions) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentExtensions ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentExtensions ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentExtensions; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentExtensions; + return LDAP_SUCCESS; +} /* GDecExtensionsContent */ + + +int +MatchingComponentRelativeDistinguishedName ( char* oid, ComponentSyntaxInfo* csi_attr, ComponentSyntaxInfo* csi_assert ) { + int rc; + MatchingRule* mr; + void* component1, *component2; + AsnList *v1, *v2, t_list; + + + if ( oid ) { + mr = retrieve_matching_rule( oid, csi_attr->csi_comp_desc->cd_type_id); + if ( mr ) return component_value_match( mr, csi_attr, csi_assert ); + } + + v1 = &((ComponentRelativeDistinguishedName*)csi_attr)->comp_list; + v2 = &((ComponentRelativeDistinguishedName*)csi_assert)->comp_list; + AsnListInit( &t_list, 0 ); + if( AsnListCount( v1 ) != AsnListCount( v2 ) ) + return LDAP_COMPARE_FALSE; + FOR_EACH_LIST_ELMT (component1, v1) + { + FOR_EACH_LIST_ELMT(component2, v2) + { + if( MatchingComponentAttributeTypeAndValue(oid, (ComponentSyntaxInfo*)component1,(ComponentSyntaxInfo*)component2) == LDAP_COMPARE_TRUE ) { + AsnElmtMove( v2, &t_list ); + break; + } + } /* end of inner for */ + } /* end of outer for */ + + if( AsnListCount( v2 ) == 0 ) + rc = LDAP_COMPARE_TRUE; + else + rc = LDAP_COMPARE_FALSE; + AsnListMove( &t_list, v2 ); + AsnListFirst( v1 ); + AsnListFirst( v2 ); + return rc; +} /* BMatchingComponentRelativeDistinguishedNameContent */ + +void* +ExtractingComponentRelativeDistinguishedName ( void* mem_op, ComponentReference* cr, ComponentRelativeDistinguishedName *comp ) +{ + int count = 0; + int total; + AsnList *v = &comp->comp_list; + ComponentInt *k; + ComponentAttributeTypeAndValue *component; + + + switch ( cr->cr_curr->ci_type ) { + case LDAP_COMPREF_FROM_BEGINNING : + count = cr->cr_curr->ci_val.ci_from_beginning; + FOR_EACH_LIST_ELMT( component , v ) { + if( --count == 0 ) { + if( cr->cr_curr->ci_next == NULL ) + return component; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentAttributeTypeAndValue ( mem_op, cr, component ); + } + } + } + break; + case LDAP_COMPREF_FROM_END : + total = AsnListCount ( v ); + count = cr->cr_curr->ci_val.ci_from_end; + count = total + count +1; + FOR_EACH_LIST_ELMT ( component, v ) { + if( --count == 0 ) { + if( cr->cr_curr->ci_next == NULL ) + return component; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentAttributeTypeAndValue ( mem_op, cr, component ); + } + } + } + break; + case LDAP_COMPREF_ALL : + return comp; + case LDAP_COMPREF_COUNT : + k = (ComponentInt*)CompAlloc( mem_op, sizeof(ComponentInt)); + k->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + k->comp_desc->cd_tag = (-1); + k->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentInt; + k->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentInt; + k->comp_desc->cd_extract_i = (extract_component_from_id_func*)NULL; + k->comp_desc->cd_type = ASN_BASIC; + k->comp_desc->cd_type_id = BASICTYPE_INTEGER; + k->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentInt; + k->value = AsnListCount(v); + return k; + default : + return NULL; + } +} /* ExtractingComponentRelativeDistinguishedName */ + +int +BDecComponentRelativeDistinguishedName PARAMS ((b, tagId0, elmtLen0, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +AsnTag tagId0 _AND_ +AsnLen elmtLen0 _AND_ +ComponentRelativeDistinguishedName **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + int seqDone = FALSE; + AsnLen totalElmtsLen1 = 0; + AsnLen elmtLen1; + AsnTag tagId1; + int mandatoryElmtCount1 = 0; + int old_mode = mode; + int rc; + ComponentRelativeDistinguishedName *k, *t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + AsnListInit(&k->comp_list,sizeof(ComponentAttributeTypeAndValue)); + for (totalElmtsLen1 = 0; (totalElmtsLen1 < elmtLen0) || (elmtLen0 == INDEFINITE_LEN);) + { + ComponentAttributeTypeAndValue **tmpVar; + tagId1 = BDecTag (b, &totalElmtsLen1 ); + + if ((tagId1 == EOC_TAG_ID) && (elmtLen0 == INDEFINITE_LEN)) + { + BDEC_2ND_EOC_OCTET (b, &totalElmtsLen1 ) + break; /* got EOC so can exit this SET OF/SEQ OF's for loop*/ + } + if ((tagId1 == MAKE_TAG_ID (UNIV, CONS, SEQ_TAG_CODE))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + tmpVar = (ComponentAttributeTypeAndValue**) CompAsnListAppend (mem_op,&k->comp_list); + rc = BDecComponentAttributeTypeAndValue (mem_op, b, tagId1, elmtLen1, tmpVar, &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + } /* end of tag check if */ + else /* wrong tag */ + { + Asn1Error ("Unexpected Tag\n"); + return -1; + } + } /* end of for */ + + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentRelativeDistinguishedName*) CompAlloc( mem_op, sizeof(ComponentRelativeDistinguishedName) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + + t->comp_desc->cd_gser_encoder = (encoder_func*)NULL; + t->comp_desc->cd_ber_encoder = (encoder_func*)NULL; + t->comp_desc->cd_ldap_encoder = (encoder_func*)ConvertRDN2RFC2253; + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentRelativeDistinguishedName ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentRelativeDistinguishedName ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentRelativeDistinguishedName; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = RelativeDistinguishedName; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentRelativeDistinguishedName; + (*bytesDecoded) += totalElmtsLen1; + return LDAP_SUCCESS; +} /* BDecRelativeDistinguishedNameContent */ + +int +GDecComponentRelativeDistinguishedName PARAMS (( mem_op,b, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +ComponentRelativeDistinguishedName **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + char* peek_head,*peek_head2; + int i, strLen,strLen2, rc, old_mode = mode; + ComponentRelativeDistinguishedName *k,*t, c_temp; + + + int ElmtsLen1; + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + AsnListInit( &k->comp_list, sizeof( ComponentAttributeTypeAndValue ) ); + *bytesDecoded = 0; + if( !(strLen = LocateNextGSERToken(mem_op,b, &peek_head, GSER_PEEK)) ){ + Asn1Error("Error during Reading { in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '{'){ + Asn1Error("Missing { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + + for (ElmtsLen1 = 0; ElmtsLen1 >= INDEFINITE_LEN; ElmtsLen1++) + { + ComponentAttributeTypeAndValue **tmpVar; + if( !(strLen = LocateNextGSERToken(mem_op,b, &peek_head, GSER_NO_COPY)) ){ + Asn1Error("Error during Reading{ in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head == '}') break; + if( !(*peek_head == '{' || *peek_head ==',') ) { + return LDAP_PROTOCOL_ERROR; + } + tmpVar = (ComponentAttributeTypeAndValue**) CompAsnListAppend (mem_op, &k->comp_list); + if ( tmpVar == NULL ) { + Asn1Error("Error during Reading{ in encoding"); + return LDAP_PROTOCOL_ERROR; + } + rc = GDecComponentAttributeTypeAndValue (mem_op, b, tmpVar, bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + } /* end of for */ + + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentRelativeDistinguishedName*) CompAlloc( mem_op, sizeof(ComponentRelativeDistinguishedName) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentRelativeDistinguishedName ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentRelativeDistinguishedName ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentRelativeDistinguishedName; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = RelativeDistinguishedName; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentRelativeDistinguishedName; + return LDAP_SUCCESS; +} /* GDecRelativeDistinguishedNameContent */ + + +int +MatchingComponentRDNSequence ( char* oid, ComponentSyntaxInfo* csi_attr, ComponentSyntaxInfo* csi_assert ) { + int rc; + MatchingRule* mr; + void* component1, *component2; + AsnList *v1, *v2, t_list; + + + if ( oid ) { + mr = retrieve_matching_rule( oid, csi_attr->csi_comp_desc->cd_type_id); + if ( mr ) return component_value_match( mr, csi_attr, csi_assert ); + } + + v1 = &((ComponentRDNSequence*)csi_attr)->comp_list; + v2 = &((ComponentRDNSequence*)csi_assert)->comp_list; + FOR_EACH_LIST_PAIR_ELMT(component1, component2, v1, v2) + { + if( MatchingComponentRelativeDistinguishedName(oid, (ComponentSyntaxInfo*)component1, (ComponentSyntaxInfo*)component2) == LDAP_COMPARE_FALSE) { + return LDAP_COMPARE_FALSE; + } + } /* end of for */ + + AsnListFirst( v1 ); + AsnListFirst( v2 ); + if( (!component1 && component2) || (component1 && !component2)) + return LDAP_COMPARE_FALSE; + else + return LDAP_COMPARE_TRUE; +} /* BMatchingComponentRDNSequenceContent */ + +void* +ExtractingComponentRDNSequence ( void* mem_op, ComponentReference* cr, ComponentRDNSequence *comp ) +{ + int count = 0; + int total; + AsnList *v = &comp->comp_list; + ComponentInt *k; + ComponentRelativeDistinguishedName *component; + + + switch ( cr->cr_curr->ci_type ) { + case LDAP_COMPREF_FROM_BEGINNING : + count = cr->cr_curr->ci_val.ci_from_beginning; + FOR_EACH_LIST_ELMT( component , v ) { + if( --count == 0 ) { + if( cr->cr_curr->ci_next == NULL ) + return component; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentRelativeDistinguishedName ( mem_op, cr, component ); + } + } + } + break; + case LDAP_COMPREF_FROM_END : + total = AsnListCount ( v ); + count = cr->cr_curr->ci_val.ci_from_end; + count = total + count +1; + FOR_EACH_LIST_ELMT ( component, v ) { + if( --count == 0 ) { + if( cr->cr_curr->ci_next == NULL ) + return component; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentRelativeDistinguishedName ( mem_op, cr, component ); + } + } + } + break; + case LDAP_COMPREF_ALL : + return comp; + case LDAP_COMPREF_COUNT : + k = (ComponentInt*)CompAlloc( mem_op, sizeof(ComponentInt)); + k->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + k->comp_desc->cd_tag = (-1); + k->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentInt; + k->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentInt; + k->comp_desc->cd_extract_i = (extract_component_from_id_func*)NULL; + k->comp_desc->cd_type = ASN_BASIC; + k->comp_desc->cd_type_id = BASICTYPE_INTEGER; + k->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentInt; + k->value = AsnListCount(v); + return k; + default : + return NULL; + } +} /* ExtractingComponentRDNSequence */ + +int +BDecComponentRDNSequence PARAMS ((b, tagId0, elmtLen0, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +AsnTag tagId0 _AND_ +AsnLen elmtLen0 _AND_ +ComponentRDNSequence **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + int seqDone = FALSE; + AsnLen totalElmtsLen1 = 0; + AsnLen elmtLen1; + AsnTag tagId1; + int mandatoryElmtCount1 = 0; + int old_mode = mode; + int rc; + ComponentRDNSequence *k, *t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + AsnListInit(&k->comp_list,sizeof(ComponentRelativeDistinguishedName)); + for (totalElmtsLen1 = 0; (totalElmtsLen1 < elmtLen0) || (elmtLen0 == INDEFINITE_LEN);) + { + ComponentRelativeDistinguishedName **tmpVar; + tagId1 = BDecTag (b, &totalElmtsLen1 ); + + if ((tagId1 == EOC_TAG_ID) && (elmtLen0 == INDEFINITE_LEN)) + { + BDEC_2ND_EOC_OCTET (b, &totalElmtsLen1 ) + break; /* got EOC so can exit this SET OF/SEQ OF's for loop*/ + } + if ((tagId1 == MAKE_TAG_ID (UNIV, CONS, SET_TAG_CODE))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + tmpVar = (ComponentRelativeDistinguishedName**) CompAsnListAppend (mem_op,&k->comp_list); + rc = BDecComponentRelativeDistinguishedName (mem_op, b, tagId1, elmtLen1, tmpVar, &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + } /* end of tag check if */ + else /* wrong tag */ + { + Asn1Error ("Unexpected Tag\n"); + return -1; + } + } /* end of for */ + + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentRDNSequence*) CompAlloc( mem_op, sizeof(ComponentRDNSequence) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + + t->comp_desc->cd_gser_encoder = (encoder_func*)NULL; + t->comp_desc->cd_ber_encoder = (encoder_func*)NULL; + t->comp_desc->cd_ldap_encoder = (encoder_func*) ConvertRDNSequence2RFC2253; + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentRDNSequence ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentRDNSequence ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentRDNSequence; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = RDNSequence; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentRDNSequence; + (*bytesDecoded) += totalElmtsLen1; + return LDAP_SUCCESS; +} /* BDecRDNSequenceContent */ + +int +GDecComponentRDNSequence PARAMS (( mem_op,b, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +ComponentRDNSequence **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + char* peek_head,*peek_head2; + int i, strLen,strLen2, rc, old_mode = mode; + ComponentRDNSequence *k,*t, c_temp; + + + int ElmtsLen1; + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + AsnListInit( &k->comp_list, sizeof( ComponentRelativeDistinguishedName ) ); + *bytesDecoded = 0; + if( !(strLen = LocateNextGSERToken(mem_op,b, &peek_head, GSER_PEEK)) ){ + Asn1Error("Error during Reading { in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '{'){ + Asn1Error("Missing { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + + for (ElmtsLen1 = 0; ElmtsLen1 >= INDEFINITE_LEN; ElmtsLen1++) + { + ComponentRelativeDistinguishedName **tmpVar; + if( !(strLen = LocateNextGSERToken(mem_op,b, &peek_head, GSER_NO_COPY)) ){ + Asn1Error("Error during Reading{ in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head == '}') break; + if( !(*peek_head == '{' || *peek_head ==',') ) { + return LDAP_PROTOCOL_ERROR; + } + tmpVar = (ComponentRelativeDistinguishedName**) CompAsnListAppend (mem_op, &k->comp_list); + if ( tmpVar == NULL ) { + Asn1Error("Error during Reading{ in encoding"); + return LDAP_PROTOCOL_ERROR; + } + rc = GDecComponentRelativeDistinguishedName (mem_op, b, tmpVar, bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + } /* end of for */ + + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentRDNSequence*) CompAlloc( mem_op, sizeof(ComponentRDNSequence) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_encoder = (encoder_func*)NULL; + t->comp_desc->cd_ber_encoder = (encoder_func*)NULL; + t->comp_desc->cd_ldap_encoder = (encoder_func*)ConvertRDNSequence2RFC2253; + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentRDNSequence ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentRDNSequence ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentRDNSequence; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = RDNSequence ; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentRDNSequence; + return LDAP_SUCCESS; +} /* GDecRDNSequenceContent */ + + +int +MatchingComponentName ( char* oid, ComponentSyntaxInfo* csi_attr, ComponentSyntaxInfo* csi_assert ) { + int rc; + MatchingRule* mr; + ComponentName *v1, *v2; + + + v1 = (ComponentName*)csi_attr; + v2 = (ComponentName*)csi_assert; + if ( oid ) { + mr = retrieve_matching_rule( oid, csi_attr->csi_comp_desc->cd_type_id); + if ( mr ) return component_value_match( mr, csi_attr, csi_assert ); + } + + if( (v1->choiceId != v2->choiceId ) ) + return LDAP_COMPARE_FALSE; + switch( v1->choiceId ) + { + case NAME_RDNSEQUENCE : + rc = MatchingComponentRDNSequence ( oid, (ComponentSyntaxInfo*)(v1->a.rdnSequence), (ComponentSyntaxInfo*)(v2->a.rdnSequence) ); + break; + default : + return LDAP_PROTOCOL_ERROR; + } + return rc; +} /* BMatchingComponentNameContent */ + +void* +ExtractingComponentName ( void* mem_op, ComponentReference* cr, ComponentName *comp ) +{ + + + if( (comp->choiceId) == NAME_RDNSEQUENCE && + (( comp->a.rdnSequence->identifier.bv_val && strncmp(comp->a.rdnSequence->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0) || + ( strncmp(comp->a.rdnSequence->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0))) { + if ( cr->cr_curr->ci_next == NULL ) + return (comp->a.rdnSequence); + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentRDNSequence ( mem_op, cr, (comp->a.rdnSequence) ); + }; + } + return NULL; +} /* ExtractingComponentName */ + +int +BDecComponentName PARAMS ((b, tagId0, elmtLen0, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +AsnTag tagId0 _AND_ +AsnLen elmtLen0 _AND_ +ComponentName **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + int seqDone = FALSE; + AsnLen totalElmtsLen1 = 0; + AsnLen elmtLen1; + AsnTag tagId1; + int mandatoryElmtCount1 = 0; + int old_mode = mode; + int rc; + ComponentName *k, *t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + switch (tagId0) + { + case MAKE_TAG_ID (UNIV, CONS, SEQ_TAG_CODE): + (k->choiceId) = NAME_RDNSEQUENCE; + rc = BDecComponentRDNSequence (mem_op, b, tagId0, elmtLen0, (&k->a.rdnSequence), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.rdnSequence)->identifier.bv_val = (k->a.rdnSequence)->id_buf; + (k->a.rdnSequence)->identifier.bv_len = strlen("rdnSequence"); + strcpy( (k->a.rdnSequence)->identifier.bv_val, "rdnSequence"); + break; + + default: + Asn1Error ("ERROR - unexpected tag in CHOICE\n"); + return -1; + break; + } /* end switch */ + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentName*) CompAlloc( mem_op, sizeof(ComponentName) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentName ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentName ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentName; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentName; + (*bytesDecoded) += totalElmtsLen1; + return LDAP_SUCCESS; +} /* BDecNameContent */ + +int +GDecComponentName PARAMS (( mem_op,b, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +ComponentName **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + char* peek_head,*peek_head2; + int i, strLen,strLen2, rc, old_mode = mode; + ComponentName *k,*t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen2 = LocateNextGSERToken(mem_op,b,&peek_head2,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head2 != ':'){ + Asn1Error("Missing : in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + if( strncmp("rdnSequence",peek_head, strlen("rdnSequence")) == 0){ + (k->choiceId) = NAME_RDNSEQUENCE; + rc = GDecComponentRDNSequence (mem_op, b, (&k->a.rdnSequence), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->a.rdnSequence)->identifier.bv_val = peek_head; + (k->a.rdnSequence)->identifier.bv_len = strLen; + } + else { + Asn1Error("Undefined Identifier"); + return LDAP_PROTOCOL_ERROR; + } + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentName*) CompAlloc( mem_op, sizeof(ComponentName) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentName ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentName ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentName; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentName; + return LDAP_SUCCESS; +} /* GDecNameContent */ + + +int +MatchingComponentTBSCertificate ( char* oid, ComponentSyntaxInfo* csi_attr, ComponentSyntaxInfo* csi_assert ) { + int rc; + MatchingRule* mr; + + if ( oid ) { + mr = retrieve_matching_rule( oid, csi_attr->csi_comp_desc->cd_type_id); + if ( mr ) return component_value_match( mr, csi_attr, csi_assert ); + } + + rc = 1; + rc = MatchingComponentVersion ( oid, (ComponentSyntaxInfo*)((ComponentTBSCertificate*)csi_attr)->version, (ComponentSyntaxInfo*)((ComponentTBSCertificate*)csi_assert)->version ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + rc = MatchingComponentCertificateSerialNumber ( oid, (ComponentSyntaxInfo*)&((ComponentTBSCertificate*)csi_attr)->serialNumber, (ComponentSyntaxInfo*)&((ComponentTBSCertificate*)csi_assert)->serialNumber ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + rc = MatchingComponentAlgorithmIdentifier ( oid, (ComponentSyntaxInfo*)((ComponentTBSCertificate*)csi_attr)->signature, (ComponentSyntaxInfo*)((ComponentTBSCertificate*)csi_assert)->signature ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + rc = MatchingComponentName ( oid, (ComponentSyntaxInfo*)((ComponentTBSCertificate*)csi_attr)->issuer, (ComponentSyntaxInfo*)((ComponentTBSCertificate*)csi_assert)->issuer ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + rc = MatchingComponentValidity ( oid, (ComponentSyntaxInfo*)((ComponentTBSCertificate*)csi_attr)->validity, (ComponentSyntaxInfo*)((ComponentTBSCertificate*)csi_assert)->validity ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + rc = MatchingComponentName ( oid, (ComponentSyntaxInfo*)((ComponentTBSCertificate*)csi_attr)->subject, (ComponentSyntaxInfo*)((ComponentTBSCertificate*)csi_assert)->subject ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + rc = MatchingComponentSubjectPublicKeyInfo ( oid, (ComponentSyntaxInfo*)((ComponentTBSCertificate*)csi_attr)->subjectPublicKeyInfo, (ComponentSyntaxInfo*)((ComponentTBSCertificate*)csi_assert)->subjectPublicKeyInfo ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + rc = MatchingComponentUniqueIdentifier ( oid, (ComponentSyntaxInfo*)&((ComponentTBSCertificate*)csi_attr)->issuerUniqueIdentifier, (ComponentSyntaxInfo*)&((ComponentTBSCertificate*)csi_assert)->issuerUniqueIdentifier ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + rc = MatchingComponentUniqueIdentifier ( oid, (ComponentSyntaxInfo*)&((ComponentTBSCertificate*)csi_attr)->subjectUniqueIdentifier, (ComponentSyntaxInfo*)&((ComponentTBSCertificate*)csi_assert)->subjectUniqueIdentifier ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + if(COMPONENTNOT_NULL( ((ComponentTBSCertificate*)csi_attr)->extensions ) ) { + rc = MatchingComponentExtensions ( oid, (ComponentSyntaxInfo*)((ComponentTBSCertificate*)csi_attr)->extensions, (ComponentSyntaxInfo*)((ComponentTBSCertificate*)csi_assert)->extensions ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + } + return LDAP_COMPARE_TRUE; +} /* BMatchingComponentTBSCertificate */ + +void* +ExtractingComponentTBSCertificate ( void* mem_op, ComponentReference* cr, ComponentTBSCertificate *comp ) +{ + + if ( ( comp->version->identifier.bv_val && strncmp(comp->version->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->version->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->version; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentVersion ( mem_op, cr, comp->version ); + } + } + if ( ( comp->serialNumber.identifier.bv_val && strncmp(comp->serialNumber.identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->serialNumber.id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return &comp->serialNumber; + else + return NULL; + } + if ( ( comp->signature->identifier.bv_val && strncmp(comp->signature->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->signature->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->signature; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentAlgorithmIdentifier ( mem_op, cr, comp->signature ); + } + } + if ( ( comp->issuer->identifier.bv_val && strncmp(comp->issuer->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->issuer->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->issuer; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentName ( mem_op, cr, comp->issuer ); + } + } + if ( ( comp->validity->identifier.bv_val && strncmp(comp->validity->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->validity->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->validity; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentValidity ( mem_op, cr, comp->validity ); + } + } + if ( ( comp->subject->identifier.bv_val && strncmp(comp->subject->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->subject->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->subject; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentName ( mem_op, cr, comp->subject ); + } + } + if ( ( comp->subjectPublicKeyInfo->identifier.bv_val && strncmp(comp->subjectPublicKeyInfo->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->subjectPublicKeyInfo->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->subjectPublicKeyInfo; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentSubjectPublicKeyInfo ( mem_op, cr, comp->subjectPublicKeyInfo ); + } + } + if ( ( comp->issuerUniqueIdentifier.identifier.bv_val && strncmp(comp->issuerUniqueIdentifier.identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->issuerUniqueIdentifier.id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return &comp->issuerUniqueIdentifier; + else if ( cr->cr_curr->ci_next->ci_type == LDAP_COMPREF_CONTENT) { + cr->cr_curr = cr->cr_curr->ci_next; + return &comp->issuerUniqueIdentifier; + } else { + return NULL; + } + } + if ( ( comp->subjectUniqueIdentifier.identifier.bv_val && strncmp(comp->subjectUniqueIdentifier.identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->subjectUniqueIdentifier.id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return &comp->subjectUniqueIdentifier; + else if ( cr->cr_curr->ci_next->ci_type == LDAP_COMPREF_CONTENT) { + cr->cr_curr = cr->cr_curr->ci_next; + return &comp->subjectUniqueIdentifier; + } else { + return NULL; + } + } + if ( ( comp->extensions->identifier.bv_val && strncmp(comp->extensions->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->extensions->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->extensions; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentExtensions ( mem_op, cr, comp->extensions ); + } + } + return NULL; +} /* ExtractingComponentTBSCertificate */ + +int +BDecComponentTBSCertificate PARAMS ((b, tagId0, elmtLen0, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +AsnTag tagId0 _AND_ +AsnLen elmtLen0 _AND_ +ComponentTBSCertificate **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + int seqDone = FALSE; + AsnLen totalElmtsLen1 = 0; + AsnLen elmtLen1; + AsnTag tagId1; + int mandatoryElmtCount1 = 0; + AsnLen totalElmtsLen2 = 0; + AsnLen elmtLen2; + AsnTag tagId2; + int old_mode = mode; + int rc; + ComponentTBSCertificate *k, *t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + tagId1 = BDecTag (b, &totalElmtsLen1 ); + + if (((tagId1 == MAKE_TAG_ID (CNTX, CONS, 0)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + tagId2 = BDecTag (b, &totalElmtsLen1 ); + + if (tagId2 != MAKE_TAG_ID (UNIV, PRIM, INTEGER_TAG_CODE)) + { + Asn1Error ("Unexpected Tag\n"); + return -1; + } + + elmtLen2 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentVersion (mem_op, b, tagId2, elmtLen2, (&k->version), &totalElmtsLen1, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->version)->identifier.bv_val = (k->version)->id_buf; + (k->version)->identifier.bv_len = strlen("version"); + strcpy( (k->version)->identifier.bv_val, "version"); + if (elmtLen1 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + tagId1 = BDecTag (b, &totalElmtsLen1); + } + + + if (((tagId1 == MAKE_TAG_ID (UNIV, PRIM, INTEGER_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentCertificateSerialNumber (mem_op, b, tagId1, elmtLen1, (&k->serialNumber), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->serialNumber)->identifier.bv_val = (&k->serialNumber)->id_buf; + (&k->serialNumber)->identifier.bv_len = strlen("serialNumber"); + strcpy( (&k->serialNumber)->identifier.bv_val, "serialNumber"); + tagId1 = BDecTag (b, &totalElmtsLen1); + } + else + return -1; + + + + if (((tagId1 == MAKE_TAG_ID (UNIV, CONS, SEQ_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentAlgorithmIdentifier (mem_op, b, tagId1, elmtLen1, (&k->signature), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->signature)->identifier.bv_val = (k->signature)->id_buf; + (k->signature)->identifier.bv_len = strlen("signature"); + strcpy( (k->signature)->identifier.bv_val, "signature"); + tagId1 = BDecTag (b, &totalElmtsLen1); + } + else + return -1; + + + + if (((tagId1 == MAKE_TAG_ID (UNIV, CONS, SEQ_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentName (mem_op, b, tagId1, elmtLen1, (&k->issuer), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->issuer)->identifier.bv_val = (k->issuer)->id_buf; + (k->issuer)->identifier.bv_len = strlen("issuer"); + strcpy( (k->issuer)->identifier.bv_val, "issuer"); + tagId1 = BDecTag (b, &totalElmtsLen1); + } + else + return -1; + + + + if (((tagId1 == MAKE_TAG_ID (UNIV, CONS, SEQ_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentValidity (mem_op, b, tagId1, elmtLen1, (&k->validity), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->validity)->identifier.bv_val = (k->validity)->id_buf; + (k->validity)->identifier.bv_len = strlen("validity"); + strcpy( (k->validity)->identifier.bv_val, "validity"); + tagId1 = BDecTag (b, &totalElmtsLen1); + } + else + return -1; + + + + if (((tagId1 == MAKE_TAG_ID (UNIV, CONS, SEQ_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentName (mem_op, b, tagId1, elmtLen1, (&k->subject), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->subject)->identifier.bv_val = (k->subject)->id_buf; + (k->subject)->identifier.bv_len = strlen("subject"); + strcpy( (k->subject)->identifier.bv_val, "subject"); + tagId1 = BDecTag (b, &totalElmtsLen1); + } + else + return -1; + + + + if (((tagId1 == MAKE_TAG_ID (UNIV, CONS, SEQ_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentSubjectPublicKeyInfo (mem_op, b, tagId1, elmtLen1, (&k->subjectPublicKeyInfo), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->subjectPublicKeyInfo)->identifier.bv_val = (k->subjectPublicKeyInfo)->id_buf; + (k->subjectPublicKeyInfo)->identifier.bv_len = strlen("subjectPublicKeyInfo"); + strcpy( (k->subjectPublicKeyInfo)->identifier.bv_val, "subjectPublicKeyInfo"); + if ((elmtLen0 != INDEFINITE_LEN) && (totalElmtsLen1 == elmtLen0)) + seqDone = TRUE; + else + { + tagId1 = BDecTag (b, &totalElmtsLen1 ); + + if ((elmtLen0 == INDEFINITE_LEN) && (tagId1 == EOC_TAG_ID)) + { + BDEC_2ND_EOC_OCTET (b, &totalElmtsLen1 ) + seqDone = TRUE; + } + } + } + else + return -1; + + + + if ((!seqDone) && ((tagId1 == MAKE_TAG_ID (CNTX, PRIM, 1)) || +(tagId1 == MAKE_TAG_ID (CNTX, CONS, 1)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentUniqueIdentifier (mem_op, b, tagId1, elmtLen1, (&k->issuerUniqueIdentifier), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->issuerUniqueIdentifier)->identifier.bv_val = (&k->issuerUniqueIdentifier)->id_buf; + (&k->issuerUniqueIdentifier)->identifier.bv_len = strlen("issuerUniqueIdentifier"); + strcpy( (&k->issuerUniqueIdentifier)->identifier.bv_val, "issuerUniqueIdentifier"); + if ((elmtLen0 != INDEFINITE_LEN) && (totalElmtsLen1 == elmtLen0)) + seqDone = TRUE; + else + { + tagId1 = BDecTag (b, &totalElmtsLen1 ); + + if ((elmtLen0 == INDEFINITE_LEN) && (tagId1 == EOC_TAG_ID)) + { + BDEC_2ND_EOC_OCTET (b, &totalElmtsLen1 ) + seqDone = TRUE; + } + } + } + + + if ((!seqDone) && ((tagId1 == MAKE_TAG_ID (CNTX, PRIM, 2)) || +(tagId1 == MAKE_TAG_ID (CNTX, CONS, 2)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentUniqueIdentifier (mem_op, b, tagId1, elmtLen1, (&k->subjectUniqueIdentifier), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->subjectUniqueIdentifier)->identifier.bv_val = (&k->subjectUniqueIdentifier)->id_buf; + (&k->subjectUniqueIdentifier)->identifier.bv_len = strlen("subjectUniqueIdentifier"); + strcpy( (&k->subjectUniqueIdentifier)->identifier.bv_val, "subjectUniqueIdentifier"); + if ((elmtLen0 != INDEFINITE_LEN) && (totalElmtsLen1 == elmtLen0)) + seqDone = TRUE; + else + { + tagId1 = BDecTag (b, &totalElmtsLen1 ); + + if ((elmtLen0 == INDEFINITE_LEN) && (tagId1 == EOC_TAG_ID)) + { + BDEC_2ND_EOC_OCTET (b, &totalElmtsLen1 ) + seqDone = TRUE; + } + } + } + + + if ((!seqDone) && ((tagId1 == MAKE_TAG_ID (CNTX, CONS, 3)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + tagId2 = BDecTag (b, &totalElmtsLen1 ); + + if (tagId2 != MAKE_TAG_ID (UNIV, CONS, SEQ_TAG_CODE)) + { + Asn1Error ("Unexpected Tag\n"); + return -1; + } + + elmtLen2 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentExtensions (mem_op, b, tagId2, elmtLen2, (&k->extensions), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->extensions)->identifier.bv_val = (k->extensions)->id_buf; + (k->extensions)->identifier.bv_len = strlen("extensions"); + strcpy( (k->extensions)->identifier.bv_val, "extensions"); + if (elmtLen1 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + seqDone = TRUE; + if (elmtLen0 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + else if (totalElmtsLen1 != elmtLen0) + return -1; + + } + + + if (!seqDone) + return -1; + + if(!COMPONENTNOT_NULL ((k->version))) + { +(k->version) = CompAlloc( mem_op, sizeof(ComponentVersion)); + (k->version)->identifier.bv_val = (k->version)->id_buf; + (k->version)->identifier.bv_len = strlen("version"); + strcpy( (k->version)->identifier.bv_val, "version"); + (k->version)->value = 0; + } + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentTBSCertificate*) CompAlloc( mem_op, sizeof(ComponentTBSCertificate) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentTBSCertificate ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentTBSCertificate ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentTBSCertificate; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentTBSCertificate; + (*bytesDecoded) += totalElmtsLen1; + return LDAP_SUCCESS; +} /* BDecTBSCertificate*/ + +int +GDecComponentTBSCertificate PARAMS (( mem_op,b, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +ComponentTBSCertificate **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + char* peek_head,*peek_head2; + int i, strLen,strLen2, rc, old_mode = mode; + ComponentTBSCertificate *k,*t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + *bytesDecoded = 0; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '{'){ + Asn1Error("Missing { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + if ( strncmp( peek_head, "version", strlen("version") ) == 0 ) { + rc = GDecComponentVersion (mem_op, b, (&k->version), bytesDecoded, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->version)->identifier.bv_val = peek_head; + ( k->version)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + else { +(k->version) = CompAlloc( mem_op, sizeof(ComponentVersion)); + (k->version)->value = 0; + } + if ( strncmp( peek_head, "serialNumber", strlen("serialNumber") ) == 0 ) { + rc = GDecComponentCertificateSerialNumber (mem_op, b, (&k->serialNumber), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->serialNumber)->identifier.bv_val = peek_head; + (&k->serialNumber)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "signature", strlen("signature") ) == 0 ) { + rc = GDecComponentAlgorithmIdentifier (mem_op, b, (&k->signature), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->signature)->identifier.bv_val = peek_head; + ( k->signature)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "issuer", strlen("issuer") ) == 0 ) { + rc = GDecComponentName (mem_op, b, (&k->issuer), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->issuer)->identifier.bv_val = peek_head; + ( k->issuer)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "validity", strlen("validity") ) == 0 ) { + rc = GDecComponentValidity (mem_op, b, (&k->validity), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->validity)->identifier.bv_val = peek_head; + ( k->validity)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "subject", strlen("subject") ) == 0 ) { + rc = GDecComponentName (mem_op, b, (&k->subject), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->subject)->identifier.bv_val = peek_head; + ( k->subject)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "subjectPublicKeyInfo", strlen("subjectPublicKeyInfo") ) == 0 ) { + rc = GDecComponentSubjectPublicKeyInfo (mem_op, b, (&k->subjectPublicKeyInfo), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->subjectPublicKeyInfo)->identifier.bv_val = peek_head; + ( k->subjectPublicKeyInfo)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "issuerUniqueIdentifier", strlen("issuerUniqueIdentifier") ) == 0 ) { + rc = GDecComponentUniqueIdentifier (mem_op, b, (&k->issuerUniqueIdentifier), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->issuerUniqueIdentifier)->identifier.bv_val = peek_head; + (&k->issuerUniqueIdentifier)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "subjectUniqueIdentifier", strlen("subjectUniqueIdentifier") ) == 0 ) { + rc = GDecComponentUniqueIdentifier (mem_op, b, (&k->subjectUniqueIdentifier), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->subjectUniqueIdentifier)->identifier.bv_val = peek_head; + (&k->subjectUniqueIdentifier)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "extensions", strlen("extensions") ) == 0 ) { + rc = GDecComponentExtensions (mem_op, b, (&k->extensions), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->extensions)->identifier.bv_val = peek_head; + ( k->extensions)->identifier.bv_len = strLen; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ) { + Asn1Error("Error during Reading } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '}'){ + Asn1Error("Missing } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentTBSCertificate*) CompAlloc( mem_op, sizeof(ComponentTBSCertificate) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentTBSCertificate ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentTBSCertificate ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentTBSCertificate; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentTBSCertificate; + return LDAP_SUCCESS; +} /* GDecTBSCertificate*/ + + +int +MatchingComponentCertificate ( char* oid, ComponentSyntaxInfo* csi_attr, ComponentSyntaxInfo* csi_assert ) { + int rc; + MatchingRule* mr; + + if ( oid ) { + mr = retrieve_matching_rule( oid, csi_attr->csi_comp_desc->cd_type_id); + if ( mr ) return component_value_match( mr, csi_attr, csi_assert ); + } + + rc = 1; + rc = MatchingComponentTBSCertificate ( oid, (ComponentSyntaxInfo*)((ComponentCertificate*)csi_attr)->toBeSigned, (ComponentSyntaxInfo*)((ComponentCertificate*)csi_assert)->toBeSigned ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + rc = MatchingComponentAlgorithmIdentifier ( oid, (ComponentSyntaxInfo*)((ComponentCertificate*)csi_attr)->signatureAlgorithm, (ComponentSyntaxInfo*)((ComponentCertificate*)csi_assert)->signatureAlgorithm ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + rc = MatchingComponentBits ( oid, (ComponentSyntaxInfo*)&((ComponentCertificate*)csi_attr)->signature, (ComponentSyntaxInfo*)&((ComponentCertificate*)csi_assert)->signature ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + return LDAP_COMPARE_TRUE; +} /* BMatchingComponentCertificate */ + +void* +ExtractingComponentCertificate ( void* mem_op, ComponentReference* cr, ComponentCertificate *comp ) +{ + + if ( ( comp->toBeSigned->identifier.bv_val && strncmp(comp->toBeSigned->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->toBeSigned->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->toBeSigned; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentTBSCertificate ( mem_op, cr, comp->toBeSigned ); + } + } + if ( ( comp->signatureAlgorithm->identifier.bv_val && strncmp(comp->signatureAlgorithm->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->signatureAlgorithm->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->signatureAlgorithm; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentAlgorithmIdentifier ( mem_op, cr, comp->signatureAlgorithm ); + } + } + if ( ( comp->signature.identifier.bv_val && strncmp(comp->signature.identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->signature.id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return &comp->signature; + else if ( cr->cr_curr->ci_next->ci_type == LDAP_COMPREF_CONTENT) { + cr->cr_curr = cr->cr_curr->ci_next; + return &comp->signature; + } else { + return NULL; + } + } + return NULL; +} /* ExtractingComponentCertificate */ + +int +BDecComponentCertificate PARAMS ((b, tagId0, elmtLen0, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +AsnTag tagId0 _AND_ +AsnLen elmtLen0 _AND_ +ComponentCertificate **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + int seqDone = FALSE; + AsnLen totalElmtsLen1 = 0; + AsnLen elmtLen1; + AsnTag tagId1; + int mandatoryElmtCount1 = 0; + int old_mode = mode; + int rc; + ComponentCertificate *k, *t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + tagId1 = BDecTag (b, &totalElmtsLen1 ); + + if (((tagId1 == MAKE_TAG_ID (UNIV, CONS, SEQ_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentTBSCertificate (mem_op, b, tagId1, elmtLen1, (&k->toBeSigned), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->toBeSigned)->identifier.bv_val = (k->toBeSigned)->id_buf; + (k->toBeSigned)->identifier.bv_len = strlen("toBeSigned"); + strcpy( (k->toBeSigned)->identifier.bv_val, "toBeSigned"); + tagId1 = BDecTag (b, &totalElmtsLen1); + } + else + return -1; + + + + if (((tagId1 == MAKE_TAG_ID (UNIV, CONS, SEQ_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentAlgorithmIdentifier (mem_op, b, tagId1, elmtLen1, (&k->signatureAlgorithm), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->signatureAlgorithm)->identifier.bv_val = (k->signatureAlgorithm)->id_buf; + (k->signatureAlgorithm)->identifier.bv_len = strlen("signatureAlgorithm"); + strcpy( (k->signatureAlgorithm)->identifier.bv_val, "signatureAlgorithm"); + tagId1 = BDecTag (b, &totalElmtsLen1); + } + else + return -1; + + + + if (((tagId1 == MAKE_TAG_ID (UNIV, PRIM, BITSTRING_TAG_CODE)) || +(tagId1 == MAKE_TAG_ID (UNIV, CONS, BITSTRING_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentBits (mem_op, b, tagId1, elmtLen1, (&k->signature), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->signature)->identifier.bv_val = (&k->signature)->id_buf; + (&k->signature)->identifier.bv_len = strlen("signature"); + strcpy( (&k->signature)->identifier.bv_val, "signature"); + seqDone = TRUE; + if (elmtLen0 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + else if (totalElmtsLen1 != elmtLen0) + return -1; + + } + else + return -1; + + + + if (!seqDone) + return -1; + + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentCertificate*) CompAlloc( mem_op, sizeof(ComponentCertificate) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentCertificate ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentCertificate ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentCertificate; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentCertificate; + (*bytesDecoded) += totalElmtsLen1; + return LDAP_SUCCESS; +} /* BDecCertificate*/ + +int +GDecComponentCertificate PARAMS (( mem_op,b, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +ComponentCertificate **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + char* peek_head,*peek_head2; + int i, strLen,strLen2, rc, old_mode = mode; + ComponentCertificate *k,*t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + *bytesDecoded = 0; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '{'){ + Asn1Error("Missing { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + if ( strncmp( peek_head, "toBeSigned", strlen("toBeSigned") ) == 0 ) { + rc = GDecComponentTBSCertificate (mem_op, b, (&k->toBeSigned), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->toBeSigned)->identifier.bv_val = peek_head; + ( k->toBeSigned)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "signatureAlgorithm", strlen("signatureAlgorithm") ) == 0 ) { + rc = GDecComponentAlgorithmIdentifier (mem_op, b, (&k->signatureAlgorithm), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->signatureAlgorithm)->identifier.bv_val = peek_head; + ( k->signatureAlgorithm)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "signature", strlen("signature") ) == 0 ) { + rc = GDecComponentBits (mem_op, b, (&k->signature), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->signature)->identifier.bv_val = peek_head; + (&k->signature)->identifier.bv_len = strLen; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ) { + Asn1Error("Error during Reading } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '}'){ + Asn1Error("Missing } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentCertificate*) CompAlloc( mem_op, sizeof(ComponentCertificate) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentCertificate ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentCertificate ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentCertificate; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentCertificate; + return LDAP_SUCCESS; +} /* GDecCertificate*/ + + diff --git a/contrib/slapd-modules/comp_match/certificate.h b/contrib/slapd-modules/comp_match/certificate.h new file mode 100644 index 0000000..d1df75f --- /dev/null +++ b/contrib/slapd-modules/comp_match/certificate.h @@ -0,0 +1,379 @@ + +#include "asn-incl.h" +/* + * certificate.h + * "AuthenticationFramework" ASN.1 module encode/decode/extracting/matching/free C src. + * This file was generated by modified eSMACC compiler Sat Dec 11 11:22:49 2004 + * The generated files are strongly encouraged to be + * compiled as a module for OpenLDAP Software + */ + +#ifndef _certificate_h_ +#define _certificate_h_ + + + + +#ifdef __cplusplus +extern "C" { +#endif +#ifdef _WIN32 +#pragma warning( disable : 4101 ) +#endif +#include "componentlib.h" +typedef enum AuthenticationFrameworkAnyId +{ + nullOid_ANY_ID = 0, + nullOid2_ANY_ID = 1, + nullOid3_ANY_ID = 2, + printableStringOid_ANY_ID = 3, + printableStringOid2_ANY_ID = 4, + printableStringOid3_ANY_ID = 5, + printableStringOid4_ANY_ID = 6, + printableStringOid5_ANY_ID = 7, + printableStringOid6_ANY_ID = 8, + printableStringOid7_ANY_ID = 9, + iA5StringOid_ANY_ID = 10, + octetStringOid_ANY_ID = 11, + octetStringOid2_ANY_ID = 12, + octetStringOid3_ANY_ID = 13, + octetStringOid4_ANY_ID = 14, + octetStringOid5_ANY_ID = 15, + octetStringOid7_ANY_ID = 17} AuthenticationFrameworkAnyId; + +void InitAnyAuthenticationFramework(); + + +#define V1 0 +#define V2 1 +#define V3 2 + +typedef ComponentInt ComponentVersion; /* INTEGER { V1 (0), V2 (1), V3 (2) } */ + +#define MatchingComponentVersion MatchingComponentInt + +#define ExtractingComponentVersion ExtractingComponentInt + +#define BDecComponentVersion BDecComponentInt + +#define GDecComponentVersion GDecComponentInt + + +typedef ComponentInt ComponentCertificateSerialNumber; /* INTEGER */ + +#define MatchingComponentCertificateSerialNumber MatchingComponentInt + +#define ExtractingComponentCertificateSerialNumber ExtractingComponentInt + +#define BDecComponentCertificateSerialNumber BDecComponentInt + +#define GDecComponentCertificateSerialNumber GDecComponentInt + + +typedef ComponentOid ComponentAttributeType; /* OBJECT IDENTIFIER */ + +#define MatchingComponentAttributeType MatchingComponentOid + +#define ExtractingComponentAttributeType ExtractingComponentOid + +#define BDecComponentAttributeType BDecComponentOid + +#define GDecComponentAttributeType GDecComponentOid + + +typedef ComponentBits ComponentUniqueIdentifier; /* BIT STRING */ + +#define MatchingComponentUniqueIdentifier MatchingComponentBits + +#define ExtractingComponentUniqueIdentifier ExtractingComponentBits + +#define BDecComponentUniqueIdentifier BDecComponentBits + +#define GDecComponentUniqueIdentifier GDecComponentBits + + +typedef struct AlgorithmIdentifier /* SEQUENCE */ +{ + Syntax* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + ComponentOid algorithm; /* OBJECT IDENTIFIER */ + ComponentAnyDefinedBy parameters; /* ANY DEFINED BY algorithm OPTIONAL */ +} ComponentAlgorithmIdentifier; + +int MatchingComponentAlgorithmIdentifier PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentAlgorithmIdentifier PROTO (( void* mem_op, ComponentReference *cr, ComponentAlgorithmIdentifier *comp )); + + +int BDecComponentAlgorithmIdentifier PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentAlgorithmIdentifier **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentAlgorithmIdentifier PROTO (( void* mem_op, GenBuf * b, ComponentAlgorithmIdentifier **v, AsnLen *bytesDecoded, int mode)); + + + +typedef struct Time /* CHOICE */ +{ + Syntax* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + enum TimeChoiceId + { + TIME_UTCTIME, + TIME_GENERALIZEDTIME + } choiceId; + union TimeChoiceUnion + { + ComponentUTCTime* utcTime; /* < unknown type id ?! > */ + ComponentGeneralizedTime* generalizedTime; /* < unknown type id ?! > */ + } a; +} ComponentTime; + +int MatchingComponentTime PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentTime PROTO (( void* mem_op, ComponentReference *cr, ComponentTime *comp )); + + +int BDecComponentTime PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentTime **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentTime PROTO (( void* mem_op, GenBuf * b, ComponentTime **v, AsnLen *bytesDecoded, int mode)); + + + +typedef struct Extension /* SEQUENCE */ +{ + Syntax* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + ComponentOid extnID; /* OBJECT IDENTIFIER */ + ComponentBool* critical; /* BOOLEAN DEFAULT FALSE */ + ComponentOcts extnValue; /* OCTET STRING */ +} ComponentExtension; + +int MatchingComponentExtension PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentExtension PROTO (( void* mem_op, ComponentReference *cr, ComponentExtension *comp )); + + +int BDecComponentExtension PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentExtension **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentExtension PROTO (( void* mem_op, GenBuf * b, ComponentExtension **v, AsnLen *bytesDecoded, int mode)); + + + +typedef struct AttributeTypeAndValue /* SEQUENCE */ +{ + Syntax* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + ComponentAttributeType type; /* AttributeType */ + ComponentAnyDefinedBy value; /* ANY DEFINED BY type */ +} ComponentAttributeTypeAndValue; + +int MatchingComponentAttributeTypeAndValue PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentAttributeTypeAndValue PROTO (( void* mem_op, ComponentReference *cr, ComponentAttributeTypeAndValue *comp )); + + +int BDecComponentAttributeTypeAndValue PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentAttributeTypeAndValue **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentAttributeTypeAndValue PROTO (( void* mem_op, GenBuf * b, ComponentAttributeTypeAndValue **v, AsnLen *bytesDecoded, int mode)); + + + +typedef struct Validity /* SEQUENCE */ +{ + Syntax* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + ComponentTime* notBefore; /* Time */ + ComponentTime* notAfter; /* Time */ +} ComponentValidity; + +int MatchingComponentValidity PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentValidity PROTO (( void* mem_op, ComponentReference *cr, ComponentValidity *comp )); + + +int BDecComponentValidity PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentValidity **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentValidity PROTO (( void* mem_op, GenBuf * b, ComponentValidity **v, AsnLen *bytesDecoded, int mode)); + + + +typedef struct SubjectPublicKeyInfo /* SEQUENCE */ +{ + Syntax* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + ComponentAlgorithmIdentifier* algorithm; /* AlgorithmIdentifier */ + ComponentBits subjectPublicKey; /* BIT STRING */ +} ComponentSubjectPublicKeyInfo; + +int MatchingComponentSubjectPublicKeyInfo PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentSubjectPublicKeyInfo PROTO (( void* mem_op, ComponentReference *cr, ComponentSubjectPublicKeyInfo *comp )); + + +int BDecComponentSubjectPublicKeyInfo PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentSubjectPublicKeyInfo **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentSubjectPublicKeyInfo PROTO (( void* mem_op, GenBuf * b, ComponentSubjectPublicKeyInfo **v, AsnLen *bytesDecoded, int mode)); + + + +typedef ComponentList ComponentExtensions; /* SEQUENCE SIZE 1..MAX OF Extension */ + +int MatchingComponentExtensions PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentExtensions PROTO (( void* mem_op, ComponentReference *cr, ComponentExtensions *comp )); + + +int BDecComponentExtensions PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentExtensions **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentExtensions PROTO (( void* mem_op, GenBuf * b, ComponentExtensions **v, AsnLen *bytesDecoded, int mode)); + + + +typedef ComponentList ComponentRelativeDistinguishedName; /* SET OF AttributeTypeAndValue */ + +int MatchingComponentRelativeDistinguishedName PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentRelativeDistinguishedName PROTO (( void* mem_op, ComponentReference *cr, ComponentRelativeDistinguishedName *comp )); + + +int BDecComponentRelativeDistinguishedName PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentRelativeDistinguishedName **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentRelativeDistinguishedName PROTO (( void* mem_op, GenBuf * b, ComponentRelativeDistinguishedName **v, AsnLen *bytesDecoded, int mode)); + + + +typedef ComponentList ComponentRDNSequence; /* SEQUENCE OF RelativeDistinguishedName */ + +int MatchingComponentRDNSequence PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentRDNSequence PROTO (( void* mem_op, ComponentReference *cr, ComponentRDNSequence *comp )); + + +int BDecComponentRDNSequence PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentRDNSequence **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentRDNSequence PROTO (( void* mem_op, GenBuf * b, ComponentRDNSequence **v, AsnLen *bytesDecoded, int mode)); + + + +typedef struct Name /* CHOICE */ +{ + Syntax* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + enum NameChoiceId + { + NAME_RDNSEQUENCE + } choiceId; + union NameChoiceUnion + { + ComponentRDNSequence* rdnSequence; /* RDNSequence */ + } a; +} ComponentName; + +int MatchingComponentName PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentName PROTO (( void* mem_op, ComponentReference *cr, ComponentName *comp )); + + +int BDecComponentName PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentName **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentName PROTO (( void* mem_op, GenBuf * b, ComponentName **v, AsnLen *bytesDecoded, int mode)); + + + +typedef struct TBSCertificate /* SEQUENCE */ +{ + Syntax* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + ComponentVersion* version; /* [0] Version DEFAULT v1 */ + ComponentCertificateSerialNumber serialNumber; /* CertificateSerialNumber */ + ComponentAlgorithmIdentifier* signature; /* AlgorithmIdentifier */ + ComponentName* issuer; /* Name */ + ComponentValidity* validity; /* Validity */ + ComponentName* subject; /* Name */ + ComponentSubjectPublicKeyInfo* subjectPublicKeyInfo; /* SubjectPublicKeyInfo */ + ComponentUniqueIdentifier issuerUniqueIdentifier; /* [1] IMPLICIT UniqueIdentifier OPTIONAL */ + ComponentUniqueIdentifier subjectUniqueIdentifier; /* [2] IMPLICIT UniqueIdentifier OPTIONAL */ + ComponentExtensions* extensions; /* [3] Extensions OPTIONAL */ +} ComponentTBSCertificate; + +int MatchingComponentTBSCertificate PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentTBSCertificate PROTO (( void* mem_op, ComponentReference *cr, ComponentTBSCertificate *comp )); + + +int BDecComponentTBSCertificate PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentTBSCertificate **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentTBSCertificate PROTO (( void* mem_op, GenBuf * b, ComponentTBSCertificate **v, AsnLen *bytesDecoded, int mode)); + + + +typedef struct Certificate /* SEQUENCE */ +{ + Syntax* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + ComponentTBSCertificate* toBeSigned; /* TBSCertificate */ + ComponentAlgorithmIdentifier* signatureAlgorithm; /* AlgorithmIdentifier */ + ComponentBits signature; /* BIT STRING */ +} ComponentCertificate; + +int MatchingComponentCertificate PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentCertificate PROTO (( void* mem_op, ComponentReference *cr, ComponentCertificate *comp )); + + +int BDecComponentCertificate PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentCertificate **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentCertificate PROTO (( void* mem_op, GenBuf * b, ComponentCertificate **v, AsnLen *bytesDecoded, int mode)); + + + +/* ========== Object Declarations ========== */ + + +/* ========== Object Set Declarations ========== */ +#ifdef __cplusplus +extern "C" { +#endif + +#endif /* conditional include of certificate.h */ diff --git a/contrib/slapd-modules/comp_match/componentlib.c b/contrib/slapd-modules/comp_match/componentlib.c new file mode 100644 index 0000000..93141b3 --- /dev/null +++ b/contrib/slapd-modules/comp_match/componentlib.c @@ -0,0 +1,2370 @@ +/* Copyright 2004 IBM Corporation + * All rights reserved. + * Redisribution and use in source and binary forms, with or without + * modification, are permitted only as authorizd by the OpenLADP + * Public License. + */ +/* ACKNOWLEDGEMENTS + * This work originally developed by Sang Seok Lim + * 2004/06/18 03:20:00 slim@OpenLDAP.org + */ + +#include "portable.h" +#include <ac/string.h> +#include <ac/socket.h> +#include <ldap_pvt.h> +#include "lutil.h" +#include <ldap.h> +#include "slap.h" +#include "component.h" + +#include "componentlib.h" +#include "asn.h" +#include <asn-gser.h> +#include <stdlib.h> + +#include <string.h> + +#ifndef SLAPD_COMP_MATCH +#define SLAPD_COMP_MATCH SLAPD_MOD_DYNAMIC +#endif + +#ifdef SLAPD_COMP_MATCH +/* + * Matching function : BIT STRING + */ +int +MatchingComponentBits ( char* oid, ComponentSyntaxInfo *csi_attr, + ComponentSyntaxInfo *csi_assert ) +{ + int rc; + MatchingRule* mr; + ComponentBits *a, *b; + + if ( oid ) { + mr = retrieve_matching_rule(oid, (AsnTypeId)csi_attr->csi_comp_desc->cd_type_id ); + if ( mr ) + return component_value_match( mr, csi_attr , csi_assert ); + } + a = ((ComponentBits*)csi_attr); + b = ((ComponentBits*)csi_assert); + rc = ( a->value.bitLen == b->value.bitLen && + strncmp( a->value.bits,b->value.bits,a->value.bitLen ) == 0 ); + return rc ? LDAP_COMPARE_TRUE:LDAP_COMPARE_FALSE; +} + +/* + * Free function: BIT STRING + */ +void +FreeComponentBits ( ComponentBits* v ) { + FreeAsnBits( &v->value ); +} + +/* + * GSER Encoder : BIT STRING + */ +int +GEncComponentBits ( GenBuf *b, ComponentBits *in ) +{ + GAsnBits bits = {0}; + + bits.value = in->value; + if ( !in ) + return (-1); + return GEncAsnBitsContent ( b, &bits); +} + + +/* + * GSER Decoder : BIT STRING + */ +int +GDecComponentBits ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ) +{ + char* peek_head; + int i, strLen; + void* component_values; + ComponentBits* k, **k2; + GAsnBits result; + + k = (ComponentBits*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentBits**) v; + *k2 = (ComponentBits*) CompAlloc( mem_op, sizeof( ComponentBits ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + if ( GDecAsnBitsContent ( mem_op, b, &result, bytesDecoded ) < 0 ) { + if ( k ) CompFree( mem_op, k ); + return LDAP_DECODING_ERROR; + } + k->value = result.value; + k->comp_desc = get_component_description (BASICTYPE_BITSTRING); + + return LDAP_SUCCESS; +} + +/* + * Component BER Decoder : BIT STRING + */ +int +BDecComponentBitsTag ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ) { + return BDecComponentBits ( mem_op, b, 0, 0, v, bytesDecoded, mode|CALL_TAG_DECODER ); +} + +int +BDecComponentBits ( void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *v, + AsnLen *bytesDecoded, int mode ) +{ + char* peek_head; + int i, strLen, rc; + void* component_values; + ComponentBits* k, **k2; + AsnBits result; + + k = (ComponentBits*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentBits**) v; + *k2 = (ComponentBits*) CompAlloc( mem_op, sizeof( ComponentBits ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + if ( mode & CALL_TAG_DECODER ){ + mode = mode & CALL_CONTENT_DECODER; + rc = BDecAsnBits ( mem_op, b, &result, bytesDecoded ); + } else { + rc = BDecAsnBitsContent ( mem_op, b, tagId, len, &result, bytesDecoded ); + } + + if ( rc < 0 ) { + if ( k ) CompFree( mem_op, k ); + return LDAP_DECODING_ERROR; + } + + k->value = result; + k->comp_desc = get_component_description (BASICTYPE_BITSTRING); + + return LDAP_SUCCESS; +} + +/* + * Component GSER BMPString Encoder + */ +int +GEncComponentBMPString ( GenBuf *b, ComponentBMPString *in ) +{ + GBMPString t = {0}; + + if ( !in || in->value.octetLen <= 0 ) + return (-1); + t.value = in->value; + return GEncBMPStringContent ( b, &t ); +} + +/* + * Component GSER BMPString Decoder + */ +int +GDecComponentBMPString ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode) +{ + char* peek_head; + int i, strLen; + void* component_values; + ComponentBMPString* k, **k2; + GBMPString result; + + k = (ComponentBMPString*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentBMPString**) v; + *k2 = (ComponentBMPString*) CompAlloc( mem_op, sizeof( ComponentBMPString ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + *bytesDecoded = 0; + + if ( GDecBMPStringContent ( mem_op, b, &result, bytesDecoded ) < 0 ) { + if ( k ) CompFree( mem_op, k ); + return LDAP_DECODING_ERROR; + } + + k->value = result.value; + k->comp_desc = get_component_description (BASICTYPE_BMP_STR); + + return LDAP_SUCCESS; + +} + +/* + * Component BER BMPString Decoder + */ +int +BDecComponentBMPStringTag ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ) { + return BDecComponentBMPString ( mem_op, b, 0, 0, v, bytesDecoded, mode|CALL_TAG_DECODER ); +} + +int +BDecComponentBMPString ( void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *v, + AsnLen *bytesDecoded, int mode ) +{ + char* peek_head; + int i, strLen, rc; + void* component_values; + ComponentBMPString* k, **k2; + BMPString result; + + k = (ComponentBMPString*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentBMPString**) v; + *k2 = (ComponentBMPString*) CompAlloc( mem_op, sizeof( ComponentBMPString ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + if ( mode & CALL_TAG_DECODER ){ + mode = mode & CALL_CONTENT_DECODER; + rc = BDecBMPString ( mem_op, b, &result, bytesDecoded ); + } else { + rc = BDecBMPStringContent ( mem_op, b, tagId, len, &result, bytesDecoded ); + } + + if ( rc < 0 ) { + if ( k ) CompFree( mem_op, k ); + return LDAP_DECODING_ERROR; + } + + k->value = result; + k->comp_desc = get_component_description (BASICTYPE_BMP_STR); + + return LDAP_SUCCESS; + +} + +/* + * Component GSER Encoder : UTF8 String + */ +int +GEncComponentUTF8String ( GenBuf *b, ComponentUTF8String *in ) +{ + GUTF8String t = {0}; + if ( !in || in->value.octetLen <= 0 ) + return (-1); + t.value = in->value; + return GEncUTF8StringContent ( b, &t ); +} + +/* + * Component GSER Decoder : UTF8 String + */ +int +GDecComponentUTF8String ( void* mem_op, GenBuf *b, void *v, + AsnLen *bytesDecoded, int mode) { + char* peek_head; + int i, strLen; + void* component_values; + ComponentUTF8String* k, **k2; + GUTF8String result; + + k = (ComponentUTF8String*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentUTF8String**) v; + *k2 = (ComponentUTF8String*)CompAlloc( mem_op, sizeof( ComponentUTF8String ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + *bytesDecoded = 0; + + if ( GDecUTF8StringContent ( mem_op, b, &result, bytesDecoded ) < 0 ) { + if ( k ) CompFree( mem_op, k ); + return LDAP_DECODING_ERROR; + } + + k->value = result.value; + k->comp_desc = get_component_description (BASICTYPE_UTF8_STR); + + return LDAP_SUCCESS; +} + +/* + * Component BER Decoder : UTF8String + */ +int +BDecComponentUTF8StringTag ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ) { + return BDecComponentUTF8String ( mem_op, b, 0, 0, v, bytesDecoded, mode|CALL_TAG_DECODER ); +} + +int +BDecComponentUTF8String ( void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, + void *v, AsnLen *bytesDecoded, int mode ) +{ + char* peek_head; + int i, strLen, rc; + void* component_values; + ComponentUTF8String* k, **k2; + UTF8String result; + + k = (ComponentUTF8String*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentUTF8String**) v; + *k2 = (ComponentUTF8String*) CompAlloc( mem_op, sizeof( ComponentUTF8String ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + if ( mode & CALL_TAG_DECODER ){ + mode = mode & CALL_CONTENT_DECODER; + rc = BDecUTF8String ( mem_op, b, &result, bytesDecoded ); + } else { + rc = BDecUTF8StringContent ( mem_op, b, tagId, len, &result, bytesDecoded ); + } + if ( rc < 0 ) { + if ( k ) CompFree( mem_op, k ); + return LDAP_DECODING_ERROR; + } + + k->value = result; + k->comp_desc = get_component_description (BASICTYPE_UTF8_STR); + + return LDAP_SUCCESS; +} + +/* + * Component GSER Encoder : Teletex String + */ +int +GEncComponentTeletexString ( GenBuf *b, ComponentTeletexString *in ) +{ + GTeletexString t = {0}; + + if ( !in || in->value.octetLen <= 0 ) + return (-1); + t.value = in->value; + return GEncTeletexStringContent ( b, &t ); +} + +/* + * Component GSER Decoder : Teletex String + */ +int +GDecComponentTeletexString ( void* mem_op, GenBuf *b, void *v, + AsnLen *bytesDecoded, int mode) { + char* peek_head; + int i, strLen; + void* component_values; + ComponentTeletexString* k, **k2; + GTeletexString result; + + k = (ComponentTeletexString*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentTeletexString**) v; + *k2 = (ComponentTeletexString*)CompAlloc( mem_op, sizeof( ComponentTeletexString ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + *bytesDecoded = 0; + + if ( GDecTeletexStringContent ( mem_op, b, &result, bytesDecoded ) < 0 ) { + if ( k ) CompFree( mem_op, k ); + return LDAP_DECODING_ERROR; + } + + k->value = result.value; + k->comp_desc = get_component_description (BASICTYPE_VIDEOTEX_STR); + + return LDAP_SUCCESS; +} + + +/* + * Matching function : BOOLEAN + */ +int +MatchingComponentBool(char* oid, ComponentSyntaxInfo* csi_attr, + ComponentSyntaxInfo* csi_assert ) +{ + MatchingRule* mr; + ComponentBool *a, *b; + + if( oid ) { + mr = retrieve_matching_rule(oid, csi_attr->csi_comp_desc->cd_type_id ); + if ( mr ) + return component_value_match( mr, csi_attr , csi_assert ); + } + + a = ((ComponentBool*)csi_attr); + b = ((ComponentBool*)csi_assert); + + return (a->value == b->value) ? LDAP_COMPARE_TRUE:LDAP_COMPARE_FALSE; +} + +/* + * GSER Encoder : BOOLEAN + */ +int +GEncComponentBool ( GenBuf *b, ComponentBool *in ) +{ + GAsnBool t = {0}; + + if ( !in ) + return (-1); + t.value = in->value; + return GEncAsnBoolContent ( b, &t ); +} + +/* + * GSER Decoder : BOOLEAN + */ +int +GDecComponentBool ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ) +{ + char* peek_head; + int i, strLen; + ComponentBool* k, **k2; + GAsnBool result; + + k = (ComponentBool*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentBool**) v; + *k2 = (ComponentBool*) CompAlloc( mem_op, sizeof( ComponentBool ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + if ( GDecAsnBoolContent( mem_op, b, &result, bytesDecoded ) < 0 ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + + k->value = result.value; + k->comp_desc = get_component_description (BASICTYPE_BOOLEAN); + + return LDAP_SUCCESS; +} + +/* + * Component BER Decoder : BOOLEAN + */ +int +BDecComponentBoolTag ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ) { + return BDecComponentBool ( mem_op, b, 0, 0, v, bytesDecoded, mode|CALL_TAG_DECODER ); +} + +int +BDecComponentBool ( void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *v, + AsnLen *bytesDecoded, int mode ) +{ + char* peek_head; + int i, strLen, rc; + ComponentBool* k, **k2; + AsnBool result; + + k = (ComponentBool*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentBool**) v; + *k2 = (ComponentBool*) CompAlloc( mem_op, sizeof( ComponentBool ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + if ( mode & CALL_TAG_DECODER ){ + mode = mode & CALL_CONTENT_DECODER; + rc = BDecAsnBool ( mem_op, b, &result, bytesDecoded ); + } else { + rc = BDecAsnBoolContent( mem_op, b, tagId, len, &result, bytesDecoded ); + } + if ( rc < 0 ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + + k->value = result; + k->comp_desc = get_component_description (BASICTYPE_BOOLEAN); + + return LDAP_SUCCESS; +} + +/* + * Matching function : ENUMERATE + */ +int +MatchingComponentEnum ( char* oid, ComponentSyntaxInfo *csi_attr, + ComponentSyntaxInfo *csi_assert ) +{ + int rc; + MatchingRule* mr; + ComponentEnum *a, *b; + + if( oid ) { + mr = retrieve_matching_rule(oid, csi_attr->csi_comp_desc->cd_type_id ); + if ( mr ) + return component_value_match( mr, csi_attr , csi_assert ); + } + a = ((ComponentEnum*)csi_attr); + b = ((ComponentEnum*)csi_assert); + rc = (a->value == b->value); + + return rc ? LDAP_COMPARE_TRUE:LDAP_COMPARE_FALSE; +} + +/* + * GSER Encoder : ENUMERATE + */ +int +GEncComponentEnum ( GenBuf *b, ComponentEnum *in ) +{ + GAsnEnum t = {0}; + + if ( !in ) + return (-1); + t.value = in->value; + return GEncAsnEnumContent ( b, &t ); +} + +/* + * GSER Decoder : ENUMERATE + */ +int +GDecComponentEnum ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ) +{ + char* peek_head; + int i, strLen; + void* component_values; + ComponentEnum* k, **k2; + GAsnEnum result; + + k = (ComponentEnum*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentEnum**) v; + *k2 = (ComponentEnum*) CompAlloc( mem_op, sizeof( ComponentEnum ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + if ( GDecAsnEnumContent ( mem_op, b, &result, bytesDecoded ) < 0 ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + + k->value_identifier.bv_val = result.value_identifier; + k->value_identifier.bv_len = result.len; + + k->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !k->comp_desc ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + k->comp_desc->cd_gser_encoder = (encoder_func*)GEncComponentEnum; + k->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentEnum; + k->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentEnum; + k->comp_desc->cd_free = (comp_free_func*)NULL; + k->comp_desc->cd_extract_i = NULL; + k->comp_desc->cd_type = ASN_BASIC; + k->comp_desc->cd_type_id = BASICTYPE_ENUMERATED; + k->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentEnum; + + return LDAP_SUCCESS; +} + +/* + * Component BER Decoder : ENUMERATE + */ +int +BDecComponentEnumTag ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ) { + return BDecComponentEnum ( mem_op, b, 0, 0, v, bytesDecoded, mode|CALL_TAG_DECODER ); +} + +int +BDecComponentEnum ( void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *v, + AsnLen *bytesDecoded, int mode ) +{ + char* peek_head; + int i, strLen, rc; + void* component_values; + ComponentEnum* k, **k2; + AsnEnum result; + + k = (ComponentEnum*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentEnum**) v; + *k2 = (ComponentEnum*) CompAlloc( mem_op, sizeof( ComponentEnum ) ); + if ( k ) return LDAP_DECODING_ERROR; + k = *k2; + } + + if ( mode & CALL_TAG_DECODER ){ + mode = mode & CALL_CONTENT_DECODER; + rc = BDecAsnEnum ( mem_op, b, &result, bytesDecoded ); + } else { + rc = BDecAsnEnumContent ( mem_op, b, tagId, len, &result, bytesDecoded ); + } + if ( rc < 0 ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + + k->value = result; + + k->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !k->comp_desc ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + k->comp_desc->cd_gser_encoder = (encoder_func*)GEncComponentEnum; + k->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentEnum; + k->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentEnum; + k->comp_desc->cd_free = (comp_free_func*)NULL; + k->comp_desc->cd_extract_i = NULL; + k->comp_desc->cd_type = ASN_BASIC; + k->comp_desc->cd_type_id = BASICTYPE_ENUMERATED; + k->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentEnum; + + return LDAP_SUCCESS; +} + +/* + * Component GSER Encoder : IA5String + */ +int +GEncComponentIA5Stirng ( GenBuf *b, ComponentIA5String* in ) +{ + GIA5String t = {0}; + t.value = in->value; + if ( !in || in->value.octetLen <= 0 ) return (-1); + return GEncIA5StringContent( b, &t ); +} + +/* + * Component BER Decoder : IA5String + */ +int +BDecComponentIA5StringTag ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ) { + return BDecComponentIA5String ( mem_op, b, 0, 0, v, bytesDecoded, mode|CALL_TAG_DECODER ); +} + +int +BDecComponentIA5String ( void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *v, + AsnLen *bytesDecoded, int mode ) +{ + char* peek_head; + int i, strLen, rc; + void* component_values; + ComponentIA5String* k, **k2; + IA5String result; + + k = (ComponentIA5String*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentIA5String**) v; + *k2 = (ComponentIA5String*) CompAlloc( mem_op, sizeof( ComponentIA5String ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + if ( mode & CALL_TAG_DECODER ){ + mode = mode & CALL_CONTENT_DECODER; + rc = BDecIA5String ( mem_op, b, &result, bytesDecoded ); + } else { + rc = BDecIA5StringContent ( mem_op, b, tagId, len, &result, bytesDecoded ); + } + if ( rc < 0 ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + + k->value = result; + + k->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !k->comp_desc ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + k->comp_desc->cd_gser_encoder = (encoder_func*)GEncComponentIA5String; + k->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentIA5String; + k->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentIA5String; + k->comp_desc->cd_free = (comp_free_func*)FreeComponentIA5String; + k->comp_desc->cd_extract_i = NULL; + k->comp_desc->cd_type = ASN_BASIC; + k->comp_desc->cd_type_id = BASICTYPE_IA5_STR; + k->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentIA5String; + + return LDAP_SUCCESS; +} + +/* + * Matching function : INTEGER + */ +int +MatchingComponentInt(char* oid, ComponentSyntaxInfo* csi_attr, + ComponentSyntaxInfo* csi_assert ) +{ + MatchingRule* mr; + ComponentInt *a, *b; + + if( oid ) { + /* check if this ASN type's matching rule is overrided */ + mr = retrieve_matching_rule(oid, csi_attr->csi_comp_desc->cd_type_id ); + /* if existing function is overrided, call the overriding +function*/ + if ( mr ) + return component_value_match( mr, csi_attr , csi_assert ); + } + a = ((ComponentInt*)csi_attr); + b = ((ComponentInt*)csi_assert); + + return ( a->value == b->value ) ? LDAP_COMPARE_TRUE:LDAP_COMPARE_FALSE; +} + +/* + * GSER Encoder : INTEGER + */ +int +GEncComponentInt ( GenBuf *b, ComponentInt* in ) +{ + GAsnInt t = {0}; + + if ( !in ) + return (-1); + t.value = in->value; + return GEncAsnIntContent ( b, &t ); +} + +/* + * GSER Decoder : INTEGER + */ +int +GDecComponentInt( void* mem_op, GenBuf * b, void *v, AsnLen *bytesDecoded, int mode) +{ + char* peek_head; + int i, strLen; + void* component_values; + ComponentInt* k, **k2; + GAsnInt result; + + k = (ComponentInt*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentInt**) v; + *k2 = (ComponentInt*) CompAlloc( mem_op, sizeof( ComponentInt ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + if ( GDecAsnIntContent ( mem_op, b, &result, bytesDecoded ) < 0 ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + k->value = result.value; + k->comp_desc = get_component_description (BASICTYPE_INTEGER ); + + return LDAP_SUCCESS; +} + +/* + * Component BER Decoder : INTEGER + */ +int +BDecComponentIntTag ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ) { + return BDecComponentInt ( mem_op, b, 0, 0, v, bytesDecoded, mode|CALL_TAG_DECODER ); +} + +int +BDecComponentInt ( void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *v, + AsnLen *bytesDecoded, int mode ) +{ + char* peek_head; + int i, strLen, rc; + void* component_values; + ComponentInt* k, **k2; + AsnInt result; + + k = (ComponentInt*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentInt**) v; + *k2 = (ComponentInt*) CompAlloc( mem_op, sizeof( ComponentInt ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + if ( mode & CALL_TAG_DECODER ){ + mode = mode & CALL_CONTENT_DECODER; + rc = BDecAsnInt ( mem_op, b, &result, bytesDecoded ); + } else { + rc = BDecAsnIntContent ( mem_op, b, tagId, len, &result, bytesDecoded ); + } + k->value = result; + + k->comp_desc = get_component_description (BASICTYPE_INTEGER ); + + return LDAP_SUCCESS; +} + +/* + * Matching function : NULL + */ +int +MatchingComponentNull ( char *oid, ComponentSyntaxInfo *csi_attr, + ComponentSyntaxInfo *csi_assert ) +{ + MatchingRule* mr; + ComponentNull *a, *b; + + if( oid ) { + mr = retrieve_matching_rule(oid, csi_attr->csi_comp_desc->cd_type_id ); + if ( mr ) + return component_value_match( mr, csi_attr , csi_assert ); + } + a = ((ComponentNull*)csi_attr); + b = ((ComponentNull*)csi_assert); + + return (a->value == b->value) ? LDAP_COMPARE_TRUE:LDAP_COMPARE_FALSE; +} + +/* + * GSER Encoder : NULL + */ +int +GEncComponentNull ( GenBuf *b, ComponentNull *in ) +{ + GAsnNull t = {0}; + + if ( !in ) + return (-1); + t.value = in->value; + return GEncAsnNullContent ( b, &t ); +} + +/* + * GSER Decoder : NULL + */ +int +GDecComponentNull ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ) +{ + char* peek_head; + int i, strLen; + void* component_values; + ComponentNull* k, **k2; + GAsnNull result; + + k = (ComponentNull*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentNull**) v; + *k2 = (ComponentNull*) CompAlloc( mem_op, sizeof( ComponentNull ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + if ( GDecAsnNullContent ( mem_op, b, &result, bytesDecoded ) < 0 ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + k->value = result.value; + + k->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !k->comp_desc ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + k->comp_desc->cd_gser_encoder = (encoder_func*)GEncComponentNull; + k->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentNull; + k->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentNull; + k->comp_desc->cd_free = (comp_free_func*)FreeComponentNull; + k->comp_desc->cd_extract_i = NULL; + k->comp_desc->cd_type = ASN_BASIC; + k->comp_desc->cd_type_id = BASICTYPE_NULL; + k->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentNull; + + return LDAP_SUCCESS; +} + +/* + * Component BER Decoder : NULL + */ +int +BDecComponentNullTag ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ) +{ + return BDecComponentNull ( mem_op, b, 0, 0, v,bytesDecoded, mode|CALL_TAG_DECODER ); +} + +int +BDecComponentNull ( void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *v, + AsnLen *bytesDecoded, int mode ) +{ + char* peek_head; + int i, strLen, rc; + void* component_values; + ComponentNull* k, **k2; + AsnNull result; + + k = (ComponentNull*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentNull**) v; + *k2 = (ComponentNull*) CompAlloc( mem_op, sizeof( ComponentNull ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + if ( mode & CALL_TAG_DECODER ){ + mode = mode & CALL_CONTENT_DECODER; + rc = BDecAsnNull ( mem_op, b, &result, bytesDecoded ); + } + else { + rc = BDecAsnNullContent ( mem_op, b, tagId, len, &result, bytesDecoded); + } + if ( rc < 0 ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + k->value = result; + + k->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !k->comp_desc ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + k->comp_desc->cd_gser_encoder = (encoder_func*)GEncComponentNull; + k->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentNull; + k->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentNull; + k->comp_desc->cd_free = (comp_free_func*)FreeComponentNull; + k->comp_desc->cd_extract_i = NULL; + k->comp_desc->cd_type = ASN_BASIC; + k->comp_desc->cd_type_id = BASICTYPE_NULL; + k->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentNull; + return LDAP_SUCCESS; +} + +/* + * Component BER Decoder : NumericString + */ +int +BDecComponentNumericStringTag ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ) { + return BDecComponentNumericString ( mem_op, b, 0, 0, v, bytesDecoded, mode|CALL_TAG_DECODER ); +} + +int +BDecComponentNumericString ( void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *v, AsnLen *bytesDecoded, int mode ) +{ + char* peek_head; + int i, strLen, rc; + void* component_values; + ComponentNumericString* k, **k2; + NumericString result; + + k = (ComponentNumericString*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentNumericString**) v; + *k2 = (ComponentNumericString*) CompAlloc( mem_op, sizeof( ComponentNumericString ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + if ( mode & CALL_TAG_DECODER ){ + mode = mode & CALL_CONTENT_DECODER; + rc = BDecNumericString ( mem_op, b, &result, bytesDecoded ); + } else { + rc = BDecNumericStringContent ( mem_op, b, tagId, len, &result, bytesDecoded); + } + if ( rc < 0 ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + k->value = result; + + k->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !k->comp_desc ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + k->comp_desc->cd_gser_encoder = (encoder_func*)GEncComponentNumericString; + k->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentNumericString; + k->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentNumericString; + k->comp_desc->cd_free = (comp_free_func*)FreeComponentNumericString; + k->comp_desc->cd_extract_i = NULL; + k->comp_desc->cd_type = ASN_BASIC; + k->comp_desc->cd_type_id = BASICTYPE_NUMERIC_STR; + k->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentNumericString; + + return LDAP_SUCCESS; +} + + +/* + * Free function : OCTET STRING + */ +void +FreeComponentOcts ( ComponentOcts* v) { + FreeAsnOcts( &v->value ); +} + +/* + * Matching function : OCTET STRING + */ +int +MatchingComponentOcts ( char* oid, ComponentSyntaxInfo* csi_attr, + ComponentSyntaxInfo* csi_assert ) +{ + int rc; + MatchingRule* mr; + ComponentOcts *a, *b; + + if( oid ) { + mr = retrieve_matching_rule(oid, csi_attr->csi_comp_desc->cd_type_id ); + if ( mr ) + return component_value_match( mr, csi_attr , csi_assert ); + } + a = (ComponentOcts*) csi_attr; + b = (ComponentOcts*) csi_assert; + /* Assume that both of OCTET string has end of string character */ + if ( (a->value.octetLen == b->value.octetLen) && + strncmp ( a->value.octs, b->value.octs, a->value.octetLen ) == 0 ) + return LDAP_COMPARE_TRUE; + else + return LDAP_COMPARE_FALSE; +} + +/* + * GSER Encoder : OCTET STRING + */ +int +GEncComponentOcts ( GenBuf* b, ComponentOcts *in ) +{ + GAsnOcts t = {0}; + if ( !in || in->value.octetLen <= 0 ) + return (-1); + + t.value = in->value; + return GEncAsnOctsContent ( b, &t ); +} + +/* + * GSER Decoder : OCTET STRING + */ +int +GDecComponentOcts ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ) +{ + char *peek_head, *data; + int i, j, strLen; + void* component_values; + ComponentOcts* k, **k2; + GAsnOcts result; + + k = (ComponentOcts*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentOcts**) v; + *k2 = (ComponentOcts*) CompAlloc( mem_op, sizeof( ComponentOcts ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + if ( GDecAsnOctsContent ( mem_op, b, &result, bytesDecoded ) < 0 ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + k->value = result.value; + + k->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !k->comp_desc ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + k->comp_desc->cd_gser_encoder = (encoder_func*)GEncComponentOcts; + k->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentOcts; + k->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentOcts; + k->comp_desc->cd_free = (comp_free_func*)FreeComponentOcts; + k->comp_desc->cd_extract_i = NULL; + k->comp_desc->cd_type = ASN_BASIC; + k->comp_desc->cd_type_id = BASICTYPE_OCTETSTRING; + k->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentOcts; + + return LDAP_SUCCESS; +} + +/* + * Component BER Decoder : OCTET STRING + */ +int +BDecComponentOctsTag ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ) { + return BDecComponentOcts ( mem_op, b, 0, 0, v, bytesDecoded, mode|CALL_TAG_DECODER ); +} + +int +BDecComponentOcts ( void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *v, + AsnLen *bytesDecoded, int mode ) +{ + char *peek_head, *data; + int i, strLen, rc; + void* component_values; + ComponentOcts* k, **k2; + AsnOcts result; + + k = (ComponentOcts*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentOcts**) v; + *k2 = (ComponentOcts*) CompAlloc( mem_op, sizeof( ComponentOcts ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + if ( mode & CALL_TAG_DECODER ){ + mode = mode & CALL_CONTENT_DECODER; + rc = BDecAsnOcts ( mem_op, b, &result, bytesDecoded ); + } else { + rc = BDecAsnOctsContent ( mem_op, b, tagId, len, &result, bytesDecoded ); + } + if ( rc < 0 ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + k->value = result; + + k->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !k->comp_desc ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + k->comp_desc->cd_gser_encoder = (encoder_func*)GEncComponentOcts; + k->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentOcts; + k->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentOcts; + k->comp_desc->cd_free = (comp_free_func*)FreeComponentOcts; + k->comp_desc->cd_extract_i = NULL; + k->comp_desc->cd_type = ASN_BASIC; + k->comp_desc->cd_type_id = BASICTYPE_OCTETSTRING; + k->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentOcts; + return LDAP_SUCCESS; +} + +/* + * Matching function : OBJECT IDENTIFIER + */ +int +MatchingComponentOid ( char *oid, ComponentSyntaxInfo *csi_attr , + ComponentSyntaxInfo *csi_assert ) +{ + int rc; + MatchingRule* mr; + ComponentOid *a, *b; + + if( oid ) { + mr = retrieve_matching_rule(oid, csi_attr->csi_comp_desc->cd_type_id ); + if ( mr ) + return component_value_match( mr, csi_attr , csi_assert ); + } + + a = (ComponentOid*)csi_attr; + b = (ComponentOid*)csi_assert; + if ( a->value.octetLen != b->value.octetLen ) + return LDAP_COMPARE_FALSE; + rc = ( strncmp( a->value.octs, b->value.octs, a->value.octetLen ) == 0 ); + + return rc ? LDAP_COMPARE_TRUE:LDAP_COMPARE_FALSE; +} + +/* + * GSER Encoder : OID + */ +GEncComponentOid ( GenBuf *b, ComponentOid *in ) +{ + GAsnOid t = {0}; + + if ( !in || in->value.octetLen <= 0 ) + return (-1); + t.value = in->value; + return GEncAsnOidContent( b, (GAsnOcts*)&t ); +} + +/* + * GSER Decoder : OID + */ +int +GDecAsnDescOidContent ( void* mem_op, GenBuf *b, GAsnOid *result, AsnLen *bytesDecoded ){ + AttributeType *ad_type; + struct berval name; + char* peek_head; + int strLen; + + strLen = LocateNextGSERToken ( mem_op, b, &peek_head, GSER_NO_COPY ); + name.bv_val = peek_head; + name.bv_len = strLen; + + ad_type = at_bvfind( &name ); + + if ( !ad_type ) + return LDAP_DECODING_ERROR; + + peek_head = ad_type->sat_atype.at_oid; + strLen = strlen ( peek_head ); + + result->value.octs = (char*)EncodeComponentOid ( mem_op, peek_head , &strLen ); + result->value.octetLen = strLen; + return LDAP_SUCCESS; +} + +int +IsNumericOid ( char* peek_head , int strLen ) { + int i; + int num_dot; + for ( i = 0, num_dot = 0 ; i < strLen ; i++ ) { + if ( peek_head[i] == '.' ) num_dot++; + else if ( peek_head[i] > '9' || peek_head[i] < '0' ) + return (-1); + } + if ( num_dot ) + return (1); + else + return (-1); +} + +int +GDecComponentOid ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ) +{ + char* peek_head; + int i, strLen, rc; + void* component_values; + ComponentOid* k, **k2; + GAsnOid result; + + k = (ComponentOid*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentOid**) v; + *k2 = (ComponentOid*) CompAlloc( mem_op, sizeof( ComponentOid ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + strLen = LocateNextGSERToken ( mem_op, b, &peek_head, GSER_PEEK ); + if ( IsNumericOid ( peek_head , strLen ) >= 1 ) { + /* numeric-oid */ + if ( GDecAsnOidContent ( mem_op, b, &result, bytesDecoded ) < 0 ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + } + else { + /*descr*/ + if ( GDecAsnDescOidContent ( mem_op, b, &result, bytesDecoded ) < 0 ){ + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + } + k->value = result.value; + k->comp_desc = get_component_description (BASICTYPE_OID); + + return LDAP_SUCCESS; +} + +/* + * Component BER Decoder : OID + */ +int +BDecComponentOidTag ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ) { + return BDecComponentOid ( mem_op, b, 0, 0, v, bytesDecoded, mode|CALL_TAG_DECODER ); +} + +int +BDecComponentOid ( void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *v, + AsnLen *bytesDecoded, int mode ) +{ + char* peek_head; + int i, strLen, rc; + void* component_values; + ComponentOid* k, **k2; + AsnOid result; + + k = (ComponentOid*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentOid**) v; + *k2 = (ComponentOid*) CompAlloc( mem_op, sizeof( ComponentOid ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + if ( mode & CALL_TAG_DECODER ){ + mode = mode & CALL_CONTENT_DECODER; + rc = BDecAsnOid ( mem_op, b, &result, bytesDecoded ); + } else { + rc = BDecAsnOidContent ( mem_op, b, tagId, len, &result, bytesDecoded ); + } + if ( rc < 0 ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + k->value = result; + + k->comp_desc = get_component_description (BASICTYPE_OID); + + return LDAP_SUCCESS; +} + +/* + * Component BER Decoder : PrintiableString + */ + +int +BDecComponentPrintableStringTag ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ) +{ + return BDecComponentPrintableString ( mem_op, b, 0, 0, v, bytesDecoded, mode|CALL_TAG_DECODER ); +} + +int +BDecComponentPrintableString( void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *v, AsnLen *bytesDecoded, int mode ) +{ + char* peek_head; + int i, strLen, rc; + void* component_values; + ComponentPrintableString* k, **k2; + AsnOid result; + + k = (ComponentPrintableString*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentPrintableString**) v; + *k2 = (ComponentPrintableString*) CompAlloc( mem_op, sizeof( ComponentPrintableString ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + if ( mode & CALL_TAG_DECODER ) { + mode = mode & CALL_CONTENT_DECODER; + rc = BDecPrintableString ( mem_op, b, &result, bytesDecoded ); + } else { + rc = BDecPrintableStringContent ( mem_op, b, tagId, len, &result, bytesDecoded ); + } + if ( rc < 0 ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + k->value = result; + + k->comp_desc = get_component_description (BASICTYPE_PRINTABLE_STR); + + return LDAP_SUCCESS; +} + +/* + * Component BER Decoder : TeletexString + */ + +int +BDecComponentTeletexStringTag ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ) +{ + return BDecComponentTeletexString ( mem_op, b, 0, 0, v, bytesDecoded, mode|CALL_TAG_DECODER ); +} + +int +BDecComponentTeletexString( void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *v, AsnLen *bytesDecoded, int mode ) +{ + char* peek_head; + int i, strLen, rc; + void* component_values; + ComponentTeletexString* k, **k2; + AsnOid result; + + k = (ComponentTeletexString*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentTeletexString**) v; + *k2 = (ComponentTeletexString*) CompAlloc( mem_op, sizeof( ComponentTeletexString ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + if ( mode & CALL_TAG_DECODER ) { + mode = mode & CALL_CONTENT_DECODER; + rc = BDecTeletexString ( mem_op, b, &result, bytesDecoded ); + } else { + rc = BDecTeletexStringContent ( mem_op, b, tagId, len, &result, bytesDecoded ); + } + if ( rc < 0 ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + k->value = result; + + k->comp_desc = get_component_description (BASICTYPE_T61_STR); + + return LDAP_SUCCESS; +} + + +/* + * Matching function : Real + */ +int +MatchingComponentReal (char* oid, ComponentSyntaxInfo *csi_attr, + ComponentSyntaxInfo *csi_assert ) +{ + int rc; + MatchingRule* mr; + ComponentReal *a, *b; + + if( oid ) { + mr = retrieve_matching_rule(oid, csi_attr->csi_comp_desc->cd_type_id ); + if ( mr ) + return component_value_match( mr, csi_attr , csi_assert ); + } + a = (ComponentReal*)csi_attr; + b = (ComponentReal*)csi_assert; + rc = (a->value == b->value); + + return rc ? LDAP_COMPARE_TRUE:LDAP_COMPARE_FALSE; +} + +/* + * GSER Encoder : Real + */ +int +GEncComponentReal ( GenBuf *b, ComponentReal *in ) +{ + GAsnReal t = {0}; + if ( !in ) + return (-1); + t.value = in->value; + return GEncAsnRealContent ( b, &t ); +} + +/* + * GSER Decoder : Real + */ +int +GDecComponentReal ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ) +{ + char* peek_head; + int i, strLen; + void* component_values; + ComponentReal* k, **k2; + GAsnReal result; + + k = (ComponentReal*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentReal**) v; + *k2 = (ComponentReal*) CompAlloc( mem_op, sizeof( ComponentReal ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + if ( GDecAsnRealContent ( mem_op, b, &result, bytesDecoded ) < 0 ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + k->value = result.value; + k->comp_desc = get_component_description (BASICTYPE_REAL); + + return LDAP_SUCCESS; +} + +/* + * Component BER Decoder : Real + */ +int +BDecComponentRealTag ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ) { + return BDecComponentReal ( mem_op, b, 0, 0, v, bytesDecoded, mode|CALL_TAG_DECODER ); +} + +int +BDecComponentReal ( void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *v, AsnLen *bytesDecoded, int mode ) +{ + char* peek_head; + int i, strLen, rc; + void* component_values; + ComponentReal* k, **k2; + AsnReal result; + + k = (ComponentReal*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentReal**) v; + *k2 = (ComponentReal*) CompAlloc( mem_op, sizeof( ComponentReal ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + if ( mode & CALL_TAG_DECODER ){ + mode = mode & CALL_CONTENT_DECODER; + rc = BDecAsnReal ( mem_op, b, &result, bytesDecoded ); + } else { + rc = BDecAsnRealContent ( mem_op, b, tagId, len, &result, bytesDecoded ); + } + if ( rc < 0 ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + k->value = result; + k->comp_desc = get_component_description (BASICTYPE_REAL); + + return LDAP_SUCCESS; +} + +/* + * Matching function : Relative OID + */ +int +MatchingComponentRelativeOid ( char* oid, ComponentSyntaxInfo *csi_attr, + ComponentSyntaxInfo *csi_assert ) +{ + int rc; + MatchingRule* mr; + ComponentRelativeOid *a, *b; + + if( oid ) { + mr = retrieve_matching_rule(oid, csi_attr->csi_comp_desc->cd_type_id ); + if ( mr ) + return component_value_match( mr, csi_attr , csi_assert ); + } + + a = (ComponentRelativeOid*)csi_attr; + b = (ComponentRelativeOid*)csi_assert; + + if ( a->value.octetLen != b->value.octetLen ) + return LDAP_COMPARE_FALSE; + rc = ( strncmp( a->value.octs, b->value.octs, a->value.octetLen ) == 0 ); + + return rc ? LDAP_COMPARE_TRUE:LDAP_COMPARE_FALSE; +} + +/* + * GSER Encoder : RELATIVE_OID. + */ +int +GEncComponentRelativeOid ( GenBuf *b, ComponentRelativeOid *in ) +{ + GAsnRelativeOid t = {0}; + + if ( !in || in->value.octetLen <= 0 ) + return (-1); + t.value = in->value; + return GEncAsnRelativeOidContent ( b , (GAsnOcts*)&t ); +} + +/* + * GSER Decoder : RELATIVE_OID. + */ +int +GDecComponentRelativeOid ( void* mem_op, GenBuf *b,void *v, AsnLen *bytesDecoded, int mode ) +{ + char* peek_head; + int i, strLen; + void* component_values; + ComponentRelativeOid* k, **k2; + GAsnRelativeOid result; + + k = (ComponentRelativeOid*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentRelativeOid**) v; + *k2 = (ComponentRelativeOid*) CompAlloc( mem_op, sizeof( ComponentRelativeOid ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + if ( GDecAsnRelativeOidContent ( mem_op, b, &result, bytesDecoded ) < 0 ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + k->value = result.value; + k->comp_desc = get_component_description (BASICTYPE_OID); + + return LDAP_SUCCESS; +} + +/* + * Component BER Decoder : RELATIVE_OID. + */ +int +BDecComponentRelativeOidTag ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ) { + return BDecComponentRelativeOid ( mem_op, b, 0, 0, v, bytesDecoded, mode|CALL_TAG_DECODER ); +} + +int +BDecComponentRelativeOid ( void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *v, AsnLen *bytesDecoded, int mode ) +{ + char* peek_head; + int i, strLen, rc; + void* component_values; + ComponentRelativeOid* k, **k2; + AsnRelativeOid result; + + k = (ComponentRelativeOid*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentRelativeOid**) v; + *k2 = (ComponentRelativeOid*) CompAlloc( mem_op, sizeof( ComponentRelativeOid ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + if ( mode & CALL_TAG_DECODER ){ + mode = mode & CALL_CONTENT_DECODER; + rc = BDecAsnRelativeOid ( mem_op, b, &result, bytesDecoded ); + } else { + rc = BDecAsnRelativeOidContent ( mem_op, b, tagId, len, &result, bytesDecoded ); + } + if ( rc < 0 ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + k->value = result; + k->comp_desc = get_component_description (BASICTYPE_OID); + + return LDAP_SUCCESS; +} + +/* + * GSER Encoder : UniversalString + */ +int +GEncComponentUniversalString ( GenBuf *b, ComponentUniversalString *in ) +{ + GUniversalString t = {0}; + if ( !in || in->value.octetLen <= 0 ) + return (-1); + t.value = in->value; + return GEncUniversalStringContent( b, &t ); +} + +/* + * GSER Decoder : UniversalString + */ +static int +UTF8toUniversalString( char* octs, int len){ + /* Need to be Implemented */ + return LDAP_SUCCESS; +} + +int +GDecComponentUniversalString ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ) +{ + if ( GDecComponentUTF8String ( mem_op, b, v, bytesDecoded, mode) < 0 ) + UTF8toUniversalString( ((ComponentUniversalString*)v)->value.octs, ((ComponentUniversalString*)v)->value.octetLen ); + return LDAP_DECODING_ERROR; +} + +/* + * Component BER Decoder : UniverseString + */ +int +BDecComponentUniversalStringTag ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ) { + return BDecComponentUniversalString ( mem_op, b, 0, 0, v, bytesDecoded, mode|CALL_TAG_DECODER ); +} + +int +BDecComponentUniversalString ( void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *v, AsnLen *bytesDecoded, int mode ) +{ + char* peek_head; + int i, strLen, rc; + void* component_values; + ComponentUniversalString* k, **k2; + UniversalString result; + + k = (ComponentUniversalString*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentUniversalString**) v; + *k2 = (ComponentUniversalString*) CompAlloc( mem_op, sizeof( ComponentUniversalString ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + if ( mode & CALL_TAG_DECODER ){ + mode = mode & CALL_CONTENT_DECODER; + rc = BDecUniversalString ( mem_op, b, &result, bytesDecoded ); + } else { + rc = BDecUniversalStringContent ( mem_op, b, tagId, len, &result, bytesDecoded ); + } + if ( rc < 0 ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + k->value = result; + k->comp_desc = get_component_description (BASICTYPE_UNIVERSAL_STR); + + return LDAP_SUCCESS; +} + +/* + * Component BER Decoder : VisibleString + */ +int +BDecComponentVisibleStringTag ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ) { + return BDecComponentVisibleString ( mem_op, b, 0, 0, v, bytesDecoded, mode|CALL_TAG_DECODER ); +} + +int +BDecComponentVisibleString ( void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *v, AsnLen *bytesDecoded, int mode ) +{ + char* peek_head; + int i, strLen, rc; + void* component_values; + ComponentVisibleString* k, **k2; + VisibleString result; + + k = (ComponentVisibleString*) v; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentVisibleString**) v; + *k2 = (ComponentVisibleString*) CompAlloc( mem_op, sizeof( ComponentVisibleString ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + if ( mode & CALL_TAG_DECODER ){ + mode = mode & CALL_CONTENT_DECODER; + rc = BDecVisibleString ( mem_op, b, &result, bytesDecoded ); + } else { + rc = BDecVisibleStringContent ( mem_op, b, tagId, len, &result, bytesDecoded ); + } + k->value = result; + k->comp_desc = get_component_description (BASICTYPE_VISIBLE_STR); + + return LDAP_SUCCESS; +} + +/* + * Routines for handling an ANY DEFINED Type + */ + +/* Check if the <select> type CR and the OID of the given ANY type */ +int +CheckSelectTypeCorrect ( void* mem_op, ComponentAnyInfo* cai, struct berval* select ) { + int strLen; + AttributeType* ad_type; + char* oid; + char* result; + + if ( IsNumericOid ( select->bv_val , select->bv_len ) ) { + oid = select->bv_val; + strLen = select->bv_len; + } else { + ad_type = at_bvfind( select ); + + if ( !ad_type ) + return LDAP_DECODING_ERROR; + + oid = ad_type->sat_atype.at_oid; + strLen = strlen ( oid ); + } + result = EncodeComponentOid ( mem_op, oid , &strLen ); + if ( !result || strLen <= 0 ) return (-1); + + if ( cai->oid.octetLen == strLen && + strncmp ( cai->oid.octs, result, strLen ) == 0 ) + return (1); + else + return (-1); +} + +int +SetAnyTypeByComponentOid ( ComponentAny *v, ComponentOid *id ) { + Hash hash; + void *anyInfo; + + /* use encoded oid as hash string */ + hash = MakeHash (id->value.octs, id->value.octetLen); + if (CheckForAndReturnValue (anyOidHashTblG, hash, &anyInfo)) + v->cai = (ComponentAnyInfo*) anyInfo; + else + v->cai = NULL; + + if ( !v->cai ) { + /* + * If not found, the data considered as octet chunk + * Yet-to-be-Implemented + */ + } + return LDAP_SUCCESS; +} + +void +SetAnyTypeByComponentInt( ComponentAny *v, ComponentInt id) { + Hash hash; + void *anyInfo; + + hash = MakeHash ((char*)&id, sizeof (id)); + if (CheckForAndReturnValue (anyIntHashTblG, hash, &anyInfo)) + v->cai = (ComponentAnyInfo*) anyInfo; + else + v->cai = NULL; +} + +int +GEncComponentAny ( GenBuf *b, ComponentAny *in ) +{ + if ( in->cai != NULL && in->cai->Encode != NULL ) + return in->cai->Encode(b, &in->value ); + else + return (-1); +} + +int +BEncComponentAny ( void* mem_op, GenBuf *b, ComponentAny *result, AsnLen *bytesDecoded, int mode) +{ + ComponentAny *k, **k2; + + k = (ComponentAny*) result; + + if ( !k ) return (-1); + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentAny**) result; + *k2 = (ComponentAny*) CompAlloc( mem_op, sizeof( ComponentAny ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + if ((result->cai != NULL) && (result->cai->BER_Decode != NULL)) { + result->value = (void*) CompAlloc ( mem_op, result->cai->size ); + if ( !result->value ) return 0; + result->cai->BER_Decode ( mem_op, b, result->value, (int*)bytesDecoded, DEC_ALLOC_MODE_1); + + k->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !k->comp_desc ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + k->comp_desc->cd_gser_encoder = (encoder_func*)GEncComponentAny; + k->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentAny; + k->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentAny; + k->comp_desc->cd_free = (comp_free_func*)FreeComponentAny; + k->comp_desc->cd_extract_i = NULL; + k->comp_desc->cd_type = ASN_BASIC; + k->comp_desc->cd_type_id = BASICTYPE_ANY; + k->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentAny; + return LDAP_SUCCESS; + } + else { + Asn1Error ("ERROR - Component ANY Decode routine is NULL\n"); + return 0; + } +} + +int +BDecComponentAny ( void* mem_op, GenBuf *b, ComponentAny *result, AsnLen *bytesDecoded, int mode) { + int rc; + ComponentAny *k, **k2; + + k = (ComponentAny*) result; + + if ( !k ) return (-1); + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentAny**) result; + *k2 = (ComponentAny*) CompAlloc( mem_op, sizeof( ComponentAny ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + + if ((result->cai != NULL) && (result->cai->BER_Decode != NULL)) { + result->cai->BER_Decode ( mem_op, b, (ComponentSyntaxInfo*)&result->value, (int*)bytesDecoded, DEC_ALLOC_MODE_0 ); + + k->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !k->comp_desc ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + k->comp_desc->cd_gser_encoder = (encoder_func*)GEncComponentAny; + k->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentAny; + k->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentAny; + k->comp_desc->cd_free = (comp_free_func*)FreeComponentAny; + k->comp_desc->cd_extract_i = NULL; + k->comp_desc->cd_type = ASN_BASIC; + k->comp_desc->cd_type_id = BASICTYPE_ANY; + k->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentAny; + return LDAP_SUCCESS; + } + else { + Asn1Error ("ERROR - Component ANY Decode routine is NULL\n"); + return 0; + } +} + +int +GDecComponentAny ( void* mem_op, GenBuf *b, ComponentAny *result, AsnLen *bytesDecoded, int mode) { + ComponentAny *k, **k2; + + k = (ComponentAny*) result; + + if ( mode & DEC_ALLOC_MODE_0 ) { + k2 = (ComponentAny**) result; + *k2 = (ComponentAny*) CompAlloc( mem_op, sizeof( ComponentAny ) ); + if ( !*k2 ) return LDAP_DECODING_ERROR; + k = *k2; + } + if ((result->cai != NULL) && (result->cai->GSER_Decode != NULL)) { + result->value = (void*) CompAlloc ( mem_op, result->cai->size ); + if ( !result->value ) return 0; + result->cai->GSER_Decode ( mem_op, b, result->value, (int*)bytesDecoded, DEC_ALLOC_MODE_1); + k->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !k->comp_desc ) { + if ( k ) CompFree ( mem_op, k ); + return LDAP_DECODING_ERROR; + } + k->comp_desc->cd_gser_encoder = (encoder_func*)GEncComponentAny; + k->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentAny; + k->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentAny; + k->comp_desc->cd_free = (comp_free_func*)FreeComponentAny; + k->comp_desc->cd_type = ASN_BASIC; + k->comp_desc->cd_extract_i = NULL; + k->comp_desc->cd_type_id = BASICTYPE_ANY; + k->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentAny; + return LDAP_SUCCESS; + } + else { + Asn1Error ("ERROR - ANY Decode routine is NULL\n"); + return 0; + } +} + +int +MatchingComponentAny (char* oid, ComponentAny *result, ComponentAny *result2) { + void *comp1, *comp2; + + if ( result->comp_desc->cd_type_id == BASICTYPE_ANY ) + comp1 = result->value; + else + comp1 = result; + + if ( result2->comp_desc->cd_type_id == BASICTYPE_ANY ) + comp2 = result2->value; + else + comp2 = result2; + + if ((result->cai != NULL) && (result->cai->Match != NULL)) { + if ( result->comp_desc->cd_type_id == BASICTYPE_ANY ) + return result->cai->Match(oid, comp1, comp2 ); + else if ( result2->comp_desc->cd_type_id == BASICTYPE_ANY ) + return result2->cai->Match(oid, comp1, comp2); + else + return LDAP_INVALID_SYNTAX; + } + else { + Asn1Error ("ERROR - ANY Matching routine is NULL\n"); + return LDAP_INVALID_SYNTAX; + } +} + +void* +ExtractingComponentAny ( void* mem_op, ComponentReference* cr, ComponentAny *result ) { + if ((result->cai != NULL) && (result->cai->Extract != NULL)) { + return (void*) result->cai->Extract( mem_op, cr , result->value ); + } + else { + Asn1Error ("ERROR - ANY Extracting routine is NULL\n"); + return (void*)NULL; + } +} + +void +FreeComponentAny (ComponentAny* any) { + if ( any->cai != NULL && any->cai->Free != NULL ) { + any->cai->Free( any->value ); + free ( ((ComponentSyntaxInfo*)any->value)->csi_comp_desc ); + free ( any->value ); + } + else + Asn1Error ("ERROR - ANY Free routine is NULL\n"); +} + +void +InstallAnyByComponentInt (int anyId, ComponentInt intId, unsigned int size, + EncodeFcn encode, gser_decoder_func* G_decode, + ber_tag_decoder_func* B_decode, ExtractFcn extract, + MatchFcn match, FreeFcn free, + PrintFcn print) +{ + ComponentAnyInfo *a; + Hash h; + + a = (ComponentAnyInfo*) malloc(sizeof (ComponentAnyInfo)); + a->anyId = anyId; + a->oid.octs = NULL; + a->oid.octetLen = 0; + a->intId = intId; + a->size = size; + a->Encode = encode; + a->GSER_Decode = G_decode; + a->BER_Decode = B_decode; + a->Match = match; + a->Extract = extract; + a->Free = free; + a->Print = print; + + if (anyIntHashTblG == NULL) + anyIntHashTblG = InitHash(); + + h = MakeHash ((char*)&intId, sizeof (intId)); + + if(anyIntHashTblG != NULL) + Insert(anyIntHashTblG, a, h); +} + + +/* + * OID and its corresponding decoder can be registerd with this func. + * If contained types constrained by <select> are used, + * their OID and decoder MUST be registered, otherwise it will return no entry. + * An open type(ANY type) also need be registered. + */ +void +InstallOidDecoderMapping ( char* ch_oid, EncodeFcn encode, gser_decoder_func* G_decode, ber_tag_decoder_func* B_decode, ExtractFcn extract, MatchFcn match ) { + AsnOid oid; + int strLen; + void* mem_op; + + strLen = strlen( ch_oid ); + if( strLen <= 0 ) return; + mem_op = comp_nibble_memory_allocator ( 128, 16 ); + oid.octs = EncodeComponentOid ( mem_op, ch_oid, &strLen ); + oid.octetLen = strLen; + if( strLen <= 0 ) return; + + + InstallAnyByComponentOid ( 0, &oid, 0, encode, G_decode, B_decode, + extract, match, NULL, NULL); + comp_nibble_memory_free(mem_op); +} + +/* + * Look up Oid-decoder mapping table by berval have either + * oid or description + */ +OidDecoderMapping* +RetrieveOidDecoderMappingbyBV( struct berval* in ) { + if ( IsNumericOid ( in->bv_val, in->bv_len ) ) + return RetrieveOidDecoderMappingbyOid( in->bv_val, in->bv_len ); + else + return RetrieveOidDecoderMappingbyDesc( in->bv_val, in->bv_len ); +} + +/* + * Look up Oid-decoder mapping table by dotted OID + */ +OidDecoderMapping* +RetrieveOidDecoderMappingbyOid( char* ch_oid, int oid_len ) { + Hash hash; + void *anyInfo; + AsnOid oid; + int strLen; + void* mem_op; + + mem_op = comp_nibble_memory_allocator ( 128, 16 ); + oid.octs = EncodeComponentOid ( mem_op, ch_oid, &oid_len); + oid.octetLen = oid_len; + if( oid_len <= 0 ) { + comp_nibble_memory_free( mem_op ); + return NULL; + } + + /* use encoded oid as hash string */ + hash = MakeHash ( oid.octs, oid.octetLen); + comp_nibble_memory_free( mem_op ); + if (CheckForAndReturnValue (anyOidHashTblG, hash, &anyInfo)) + return (OidDecoderMapping*) anyInfo; + else + return (OidDecoderMapping*) NULL; + +} + +/* + * Look up Oid-decoder mapping table by description + */ +OidDecoderMapping* +RetrieveOidDecoderMappingbyDesc( char* desc, int desc_len ) { + Hash hash; + void *anyInfo; + AsnOid oid; + AttributeType* ad_type; + struct berval bv; + void* mem_op; + + bv.bv_val = desc; + bv.bv_len = desc_len; + ad_type = at_bvfind( &bv ); + + oid.octs = ad_type->sat_atype.at_oid; + oid.octetLen = strlen ( oid.octs ); + + if ( !ad_type ) + return (OidDecoderMapping*) NULL; + + mem_op = comp_nibble_memory_allocator ( 128, 16 ); + + oid.octs = EncodeComponentOid ( mem_op, oid.octs , (int*)&oid.octetLen ); + if( oid.octetLen <= 0 ) { + comp_nibble_memory_free( mem_op ); + return (OidDecoderMapping*) NULL; + } + + /* use encoded oid as hash string */ + hash = MakeHash ( oid.octs, oid.octetLen); + comp_nibble_memory_free( mem_op ); + if (CheckForAndReturnValue (anyOidHashTblG, hash, &anyInfo)) + return (OidDecoderMapping*) anyInfo; + else + return (OidDecoderMapping*) NULL; + +} +void +InstallAnyByComponentOid (int anyId, AsnOid *oid, unsigned int size, + EncodeFcn encode, gser_decoder_func* G_decode, + ber_tag_decoder_func* B_decode, ExtractFcn extract, + MatchFcn match, FreeFcn free, PrintFcn print) +{ + ComponentAnyInfo *a; + Hash h; + + a = (ComponentAnyInfo*) malloc (sizeof (ComponentAnyInfo)); + a->anyId = anyId; + if ( oid ) { + a->oid.octs = malloc( oid->octetLen ); + memcpy ( a->oid.octs, oid->octs, oid->octetLen ); + a->oid.octetLen = oid->octetLen; + } + a->size = size; + a->Encode = encode; + a->GSER_Decode = G_decode; + a->BER_Decode = B_decode; + a->Match = match; + a->Extract = extract; + a->Free = free; + a->Print = print; + + h = MakeHash (oid->octs, oid->octetLen); + + if (anyOidHashTblG == NULL) + anyOidHashTblG = InitHash(); + + if(anyOidHashTblG != NULL) + Insert(anyOidHashTblG, a, h); +} + +int +BDecComponentTop ( +ber_decoder_func *decoder _AND_ +void* mem_op _AND_ +GenBuf *b _AND_ +AsnTag tag _AND_ +AsnLen elmtLen _AND_ +void **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) { + tag = BDecTag ( b, bytesDecoded ); + elmtLen = BDecLen ( b, bytesDecoded ); + if ( elmtLen <= 0 ) return (-1); + if ( tag != MAKE_TAG_ID (UNIV, CONS, SEQ_TAG_CODE) ) { + return (-1); + } + + return (*decoder)( mem_op, b, tag, elmtLen, (ComponentSyntaxInfo*)v,(int*)bytesDecoded, mode ); +} + +/* + * ASN.1 specification of a distinguished name + * DistinguishedName ::= RDNSequence + * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName + * RelativeDistinguishedName ::= SET SIZE(1..MAX) OF AttributeTypeandValue + * AttributeTypeandValue ::= SEQUENCE { + * type AttributeType + * value AttributeValue + * } + * When dnMatch/rdnMatch is used in a component assertion value + * the component in DistinguishedName/RelativeDistinguishedName + * need to be converted to the LDAP encodings in RFC2253 + * in order to be matched against the assertion value + * If allComponentMatch is used, the assertion value may be + * decoded into the Internal Representation(Component Tree) + * by the corresponding GSER or BER decoder + * Following routine converts a component tree(DistinguishedName) into + * LDAP encodings in RFC2253 + * Example) + * IR : ComponentRDNSequence + * GSER : { { type cn, value sang },{ type o, value ibm}, {type c, value us} } + * LDAP Encodings : cn=sang,o=ibm,c=us + */ + +increment_bv_mem_by_size ( struct berval* in, int size ) { + int new_size = in->bv_len + size; + in->bv_val = realloc( in->bv_val, new_size ); + in->bv_len = new_size; +} + +int +ConvertBER2Desc( char* in, int size, struct berval* out, int* pos ) { + int desc_size; + char* desc_ptr; + unsigned int firstArcNum; + unsigned int arcNum; + int i, rc, start_pos = *pos; + char buf[MAX_OID_LEN]; + AttributeType *at; + struct berval bv_name; + + /*convert BER oid to desc*/ + for ( i = 0, arcNum = 0; (i < size) && (in[i] & 0x80 ); i++ ) + arcNum = (arcNum << 7) + (in[i] & 0x7f); + arcNum = (arcNum << 7) + (in[i] & 0x7f); + i++; + firstArcNum = (unsigned short)(arcNum/40); + if ( firstArcNum > 2 ) + firstArcNum = 2; + + arcNum = arcNum - (firstArcNum * 40 ); + + rc = intToAscii ( arcNum, buf ); + + /*check if the buffer can store the first/second arc and two dots*/ + if ( out->bv_len < *pos + 2 + 1 + rc ) + increment_bv_mem_by_size ( out, INCREMENT_SIZE ); + + if ( firstArcNum == 1) + out->bv_val[*pos] = '1'; + else + out->bv_val[*pos] = '2'; + (*pos)++; + out->bv_val[*pos] = '.'; + (*pos)++; + + memcpy( out->bv_val + *pos, buf, rc ); + *pos += rc; + out->bv_val[*pos] = '.'; + (*pos)++; + + for ( ; i < size ; ) { + for ( arcNum=0; (i < size) && (in[i] & 0x80) ; i++ ) + arcNum = (arcNum << 7) + (in[i] & 0x7f); + arcNum = (arcNum << 7) + (in[i] & 0x7f); + i++; + + rc = intToAscii ( arcNum, buf ); + + if ( out->bv_len < *pos + rc + 1 ) + increment_bv_mem_by_size ( out, INCREMENT_SIZE ); + + memcpy( out->bv_val + *pos, buf, rc ); + *pos += rc; + out->bv_val[*pos] = '.'; + (*pos)++; + } + (*pos)--;/*remove the last '.'*/ + + /* + * lookup OID database to locate desc + * then overwrite OID with desc in *out + * If failed to look up desc, OID form is used + */ + bv_name.bv_val = out->bv_val + start_pos; + bv_name.bv_len = *pos - start_pos; + at = at_bvfind( &bv_name ); + if ( !at ) + return LDAP_SUCCESS; + desc_size = at->sat_cname.bv_len; + memcpy( out->bv_val + start_pos, at->sat_cname.bv_val, desc_size ); + *pos = start_pos + desc_size; + return LDAP_SUCCESS; +} + +int +ConvertComponentAttributeTypeAndValue2RFC2253 ( irAttributeTypeAndValue* in, struct berval* out, int *pos ) { + int rc; + int value_size = ((ComponentUTF8String*)in->value.value)->value.octetLen; + char* value_ptr = ((ComponentUTF8String*)in->value.value)->value.octs; + + rc = ConvertBER2Desc( in->type.value.octs, in->type.value.octetLen, out, pos ); + if ( rc != LDAP_SUCCESS ) return rc; + if ( out->bv_len < *pos + 1/*for '='*/ ) + increment_bv_mem_by_size ( out, INCREMENT_SIZE ); + /*Between type and value, put '='*/ + out->bv_val[*pos] = '='; + (*pos)++; + + /*Assume it is string*/ + if ( out->bv_len < *pos + value_size ) + increment_bv_mem_by_size ( out, INCREMENT_SIZE ); + memcpy( out->bv_val + *pos, value_ptr, value_size ); + out->bv_len += value_size; + *pos += value_size; + + return LDAP_SUCCESS; +} + +int +ConvertRelativeDistinguishedName2RFC2253 ( irRelativeDistinguishedName* in, struct berval *out , int* pos) { + irAttributeTypeAndValue* attr_typeNvalue; + int rc; + + + FOR_EACH_LIST_ELMT( attr_typeNvalue, &in->comp_list) + { + rc = ConvertComponentAttributeTypeAndValue2RFC2253( attr_typeNvalue, out, pos ); + if ( rc != LDAP_SUCCESS ) return LDAP_INVALID_SYNTAX; + + if ( out->bv_len < *pos + 1/*for '+'*/ ) + increment_bv_mem_by_size ( out, INCREMENT_SIZE ); + /*between multivalued RDNs, put comma*/ + out->bv_val[(*pos)++] = '+'; + } + (*pos)--;/*remove the last '+'*/ + return LDAP_SUCCESS; +} + +int +ConvertRDN2RFC2253 ( irRelativeDistinguishedName* in, struct berval *out ) { + int rc, pos = 0; + out->bv_val = (char*)malloc( INITIAL_DN_SIZE ); + out->bv_len = INITIAL_DN_SIZE; + + rc = ConvertRelativeDistinguishedName2RFC2253 ( in, out , &pos); + if ( rc != LDAP_SUCCESS ) return rc; + out->bv_val[pos] = '\0'; + out->bv_len = pos; + return LDAP_SUCCESS; +} + +int +ConvertRDNSequence2RFC2253( irRDNSequence *in, struct berval* out ) { + irRelativeDistinguishedName* rdn_seq; + AsnList* seq = &in->comp_list; + int pos = 0, rc ; + + out->bv_val = (char*)malloc( INITIAL_DN_SIZE ); + out->bv_len = INITIAL_DN_SIZE; + + FOR_EACH_LIST_ELMT( rdn_seq, seq ) + { + rc = ConvertRelativeDistinguishedName2RFC2253( rdn_seq, out, &pos ); + if ( rc != LDAP_SUCCESS ) return LDAP_INVALID_SYNTAX; + + if ( out->bv_len < pos + 1/*for ','*/ ) + increment_bv_mem_by_size ( out, INCREMENT_SIZE ); + /*Between RDN, put comma*/ + out->bv_val[pos++] = ','; + } + pos--;/*remove the last '+'*/ + out->bv_val[pos] = '\0'; + out->bv_len =pos; + return LDAP_SUCCESS; +} + +#endif diff --git a/contrib/slapd-modules/comp_match/componentlib.h b/contrib/slapd-modules/comp_match/componentlib.h new file mode 100644 index 0000000..31bf375 --- /dev/null +++ b/contrib/slapd-modules/comp_match/componentlib.h @@ -0,0 +1,593 @@ +/* Copyright 2004 IBM Corporation + * All rights reserved. + * Redisribution and use in source and binary forms, with or without + * modification, are permitted only as authorizd by the OpenLADP + * Public License. + */ +/* ACKNOWLEDGEMENTS + * This work originally developed by Sang Seok Lim + * 2004/06/18 03:20:00 slim@OpenLDAP.org + */ + +#ifndef _H_COMPONENT_MODULE +#define _H_COMPONENT_MODULE + +#include "portable.h" +#include <ac/string.h> +#include <ac/socket.h> +#include <ldap_pvt.h> +#include "lutil.h" +#include <ldap.h> +#include <slap.h> +#include <component.h> + +#include <asn-incl.h> +#include "asn.h" +#include <asn-gser.h> +#include <string.h> + +#define MAX_IDENTIFIER_LEN 32 +#define COMPONENTNOT_NULL(ptr) ((ptr) != NULL) + +typedef struct slap_component_type { + /* + * Don't change the order of following fields + * They are identical the first 9 fields of + * AttributeType + */ + LDAPAttributeType ct_atype; + struct berval ct_cname; + struct slap_attribute_type *ct_sup; + struct slap_attribute_type **ct_subtypes; + MatchingRule *ct_equality; + MatchingRule *ct_approx; + MatchingRule *ct_ordering; + MatchingRule *ct_substr; + Syntax *ct_syntax; +} ComponentType; + + +/* + * BIT STRING + */ +typedef struct ComponentBits { + void* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + AsnBits value; +} ComponentBits; + +#define GASNBITS_PRESENT(abits) ((abits)->value.bits != NULL) +#define COMPONENTBITS_PRESENT(abits) ((abits)->value.bits != NULL) +int GEncComponentBits (GenBuf *b, ComponentBits* bits); +int GDecComponentBits (void* mem_op, GenBuf *b, void *result, AsnLen *bytesDecoded, int mode); +int BDecComponentBits (void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *result, AsnLen *bytesDecoded, int mode); +int MatchingComponentBits (char* oid, ComponentSyntaxInfo *bits1 , ComponentSyntaxInfo* bits2); +#define ExtractingComponentBits( mem_op, cr,data ) NULL + +/* + * BMP String + */ +typedef struct ComponentBMPString { + void* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + BMPString value; +} ComponentBMPString; + +int GEncComponentBMPString (GenBuf *b, ComponentBMPString* bmp); +int GDecComponentBMPString (void* mem_op, GenBuf *b, void *result, AsnLen *bytesDecoded, int mode); +int BDecComponentBMPString (void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *result, AsnLen *bytesDecoded, int mode); +#define MatchingComponentBMPString MatchingComponentOcts +#define ExtractingComponentBMPString( mem_op, cr, data ) NULL +#define FreeComponentBMPString FreeComponentOcts + +/* + * BOOLEAN + */ +typedef struct ComponentBool { + void* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + AsnBool value; +} ComponentBool; + +int GEncComponentBool (GenBuf *b, ComponentBool * bool ); +int GDecComponentBool ( void* mem_op, GenBuf *b, void *result, AsnLen *bytesDecoded, int mode); +int BDecComponentBool ( void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *result, AsnLen *bytesDecoded, int mode); +int MatchingComponentBool (char* oid, ComponentSyntaxInfo *a, ComponentSyntaxInfo *b); +#define ExtractingComponentBool( mem_op, cr, data ) NULL +#define FreeComponentBool(v) NULL + +/* + * ENUMERTED + */ +typedef struct ComponentEnum { + void* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + AsnEnum value; + struct berval value_identifier;/*Why this value is defined here?*/ +} ComponentEnum; + +int GEncComponentEnum (GenBuf *b, ComponentEnum* comp_enum); +int GDecComponentEnum ( void* mem_op, GenBuf *a, void *result, AsnLen *bytesDecoded,int mode); +int BDecComponentEnum ( void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *result, AsnLen *bytesDecoded, int mode); +int MatchingComponentEnum (char *oid, ComponentSyntaxInfo *a, ComponentSyntaxInfo * b); +#define ExtractingComponentEnum( mem_op, cr, data ) NULL +#define FreeComponentEnum FreeComponentInt + +/* + * IA5 String + */ +typedef struct ComponentIA5String { + void* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + IA5String value; +} ComponentIA5String; + +#define GEncComponentIA5String GEncComponentUTF8String +#define GDecComponentIA5String GDecComponentUTF8String +int +BDecComponentIA5StringTag ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ); +int BDecComponentIA5String ( void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *result, AsnLen *bytesDecoded, int mode); +#define MatchingComponentIA5String MatchingComponentOcts +#define ExtractingComponentIA5String(mem_op, cr,data) NULL +#define FreeComponentIA5String FreeComponentOcts + + +/* + * INTEGER + */ +typedef struct ComponentInt { + void* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + int value; +} ComponentInt; + +#define GNOT_NULL(ptr) ((ptr) != NULL) +int GEncComponentInt (GenBuf *b, ComponentInt *comp_int); +int GDecComponentInt ( void* mem_op, GenBuf *b, void *result, AsnLen *bytesDecoded, int mode ); +int BDecComponentInt ( void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *result, AsnLen *bytesDecoded, int mode); +int MatchingComponentInt (char* oid, ComponentSyntaxInfo *a, ComponentSyntaxInfo *b); +#define ExtractingComponentInt(mem_op, cr,data) NULL +#define FreeComponentInt(v) NULL + +/* + * LIST Data Structure for C_LIST + */ +typedef struct ComponentList { + void* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + AsnList comp_list; +} ComponentList; + +/* + * NULL + */ +typedef struct ComponentNull { + void* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + AsnNull value; +} ComponentNull; + +int GEncComponentNull (GenBuf *b, ComponentNull* comp_null); +int GDecComponentNull ( void* mem_op, GenBuf *b, void *result, AsnLen *bytesDecoded, int mode); +int BDecComponentNull ( void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *result, AsnLen *bytesDecoded, int mode); +int BDecComponentNullTag ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ); +int MatchingComponentNull (char* oid, ComponentSyntaxInfo *a, ComponentSyntaxInfo *b); +#define ExtractingComponentNull(mem_op, cr, data) NULL +#define FreeComponentNull NULL + +/* + * Numeric String + */ +typedef struct ComponentNumericString { + void* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + NumericString value; +} ComponentNumericString; + +#define GEncComponentNumericString GEncComponentUTF8String +#define GDecComponentNumericString GDecComponentUTF8String +int BDecComponentNumericString ( void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *result, AsnLen *bytesDecoded, int mode); +#define MatchingComponentNumericString MatchingComponentOcts +#define ExtractingComponentNumericString(mem_op, cr,data) NULL +#define FreeComponentNumericString FreeComponentOcts + +/* + * OCTETS STRING + */ +typedef struct ComponentOcts { + void* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + AsnOcts value; +} ComponentOcts; + +#define GASNOCTS_PRESENT(aocts) ((aocts)->value.octs != NULL) +int GEncComponentOcts (GenBuf *b, ComponentOcts *octs); +int GDecComponentOcts (void* mem_op, GenBuf *b, void *result, AsnLen *bytesDecoded, int mode); +int BDecComponentOctsTag ( void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ); +int BDecComponentOcts (void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *result, AsnLen *bytesDecoded, int mode); +int MatchingComponentOcts (char* oid, ComponentSyntaxInfo *a, ComponentSyntaxInfo *b); +#define ExtractingComponentOcts(mem_op,cr,data) NULL +void FreeComponentOcts( ComponentOcts* octs ); + +/* + * OID (Object Identifier) + */ +typedef struct ComponentOid { + void* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + AsnOid value; +} ComponentOid; + +#define GASNOID_PRESENT(aoid) ASNOCTS_PRESENT(aoid) +int GEncComponentOid (GenBuf *b, ComponentOid *oid); +int GDecComponentOid (void* mem_op, GenBuf *b, void *result, AsnLen *bytesDecoded, int mode); +int BDecComponentOid (void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *result, AsnLen *bytesDecoded, int mode); +int MatchingComponentOid (char* oid, ComponentSyntaxInfo *a, ComponentSyntaxInfo *b); +#define ExtractingComponentOid(mem_op, cr, data) NULL +#define FreeComponentOid FreeComponentOcts + +/* + * Printable String + */ +typedef struct ComponentPrintableString{ + void* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + PrintableString value; +} ComponentPrintableString; +#define GEncComponentPrintableString GEncComponentUTF8String +#define GDecComponentPrintableString GDecComponentUTF8String +int BDecComponentPrintableString (void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *result, AsnLen *bytesDecoded, int mode); +int BDecComponentPrintableStringTag (void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ); +#define MatchingComponentPrintableString MatchingComponentOcts +#define ExtractingComponentPrintableString(mem_op, cr, data) NULL +#define FreeComponentPrintableString FreeComponentOcts + +/* + * REAL + */ +typedef struct ComponentReal{ + void* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + AsnReal value; +} ComponentReal; + +int GEncComponentReal (GenBuf *b, ComponentReal* comp_real); +int GDecComponentReal (void* mem_op, GenBuf *b, void *result, AsnLen *bytesDecoded, int mode); +int BDecComponentReal (void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *result, AsnLen *bytesDecoded, int mode); +int MatchingComponentReal (char* oid, ComponentSyntaxInfo *a, ComponentSyntaxInfo *b); +#define ExtractingComponentReal( mem_op, cr, data ) NULL +#define FreeComponentReal(v) NULL + +/* + * Relative OID + */ + +typedef struct ComponentRelativeOid { + void* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + AsnRelativeOid value; +} ComponentRelativeOid; + +int GEncComponentRelativeOid (GenBuf *b, ComponentRelativeOid *r_oid); +int GDecComponentRelativeOid ( void* mem_op, GenBuf *b, void *result, AsnLen *bytesDecoded, int mode); +int BDecComponentRelativeOid ( void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *result, AsnLen *bytesDecoded, int mode); +int MatchingComponentRelativeOid (char* oid, ComponentSyntaxInfo *a, ComponentSyntaxInfo *b); +#define ExtractingComponentRelativeOid( mem_op, cr, data ) NULL +#define FreeComponentRelativeOid FreeComponentOid + +/* + * Teletex String + */ +typedef struct ComponentTeletexString { + void* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + TeletexString value; +} ComponentTeletexString; + +int GEncComponentTeletexString (GenBuf *b, ComponentTeletexString * tel_str); +int GDecComponentTeletexString ( void* mem_op, GenBuf *b, void *result, AsnLen *bytesDecoded, int mode ); +int BDecComponentTeletexStringTag (void* mem_op, GenBuf *b, void *v, AsnLen *bytesDecoded, int mode ); +int BDecComponentTeletexString( void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *v, AsnLen *bytesDecoded, int mode ); +#define MatchingComponentTeletexString MatchingComponentOcts +#define ExtractingComponentTeletexString(mem_op,cr,data) +#define FreeComponentTeletexString FreeComponentOcts + + +/* + * Universal String + */ +typedef struct ComponentUniversalString{ + void* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + UniversalString value; +} ComponentUniversalString; + +int GEncComponentUniversalString (GenBuf *b, ComponentUniversalString* uni_str); +int GDecComponentUniversalString ( void* mem_op, GenBuf *b, void *result, AsnLen *bytesDecoded, int mode); +int BDecComponentUniversalString ( void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *result, AsnLen *bytesDecoded, int mode); +#define MatchingComponentUniversalString MatchingComponentOcts +#define ExtractingComponentUniversalString(mem_op,cr,data) +#define FreeComponentUniversalString FreeComponentOcts + +/* + * UTF8 String + */ +typedef struct ComponentUTF8String{ + void* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + UTF8String value; +} ComponentUTF8String; + +int GEncComponentUTF8String (GenBuf *b, ComponentUTF8String * utf_str); +int GDecComponentUTF8String (void* mem_op, GenBuf *b, void *result, AsnLen *bytesDecoded, int mode); +int BDecComponentUTF8String (void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *result, AsnLen *bytesDecoded, int mode); +#define MatchingComponentUTF8String MatchingComponentOcts +#define ExtractingComponentUTF8String(mem_op,cr,data) +#define FreeComponentUTF8String FreeComponentOcts + +/* + * Visible String + */ +typedef struct ComponentVisibleString{ + void* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + VisibleString value; +} ComponentVisibleString; + +#define GEncComponentVisibleString GEncComponentUTF8String +#define GDecComponentVisibleString GDecComponentUTF8String +int BDecComponentVisibleString (void* mem_op, GenBuf *b, AsnTag tagId, AsnLen len, void *result, AsnLen *bytesDecoded, int mode); +#define MatchingComponentVisibleString MatchingComponentOcts +#define ExtractingComponentVisibleString(mem_op,cr,data) +#define FreeComponentVisibleString FreeComponentOcts + +/* + * ANY and ANY DEFINED BY + */ + +typedef int (*MatchFcn) (char*, void*, void*); +typedef void* (*ExtractFcn) (void*, ComponentReference*, void * ); + +typedef struct ComponentAnyInfo +{ + int anyId; + AsnOid oid; + ComponentInt intId; + unsigned int size; + EncodeFcn Encode; + gser_decoder_func* GSER_Decode; + ber_tag_decoder_func* BER_Decode; + ExtractFcn Extract; + MatchFcn Match; + FreeFcn Free; + PrintFcn Print; +} ComponentAnyInfo; + +typedef struct ComponentAnyInfo OidDecoderMapping ; + +typedef struct ComponentAny{ + void* syntax; + ComponentDesc *comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + ComponentAnyInfo *cai; + void *value; +} ComponentAny; + +typedef ComponentAny ComponentAnyDefinedBy; + +#define BDecComponentAnyDefinedBy BDecComponentAny +#define GDecComponentAnyDefinedBy GDecComponentAny +#define MatchingComponentAnyDefinedBy MatchingComponentAny +#define FreeComponentAnyDefinedBy FreeComponentAny + +int GEncComponentAny (GenBuf *b, ComponentAny *comp_any); +int BDecComponentAny ( void* mem_op, GenBuf *b, ComponentAny *result, AsnLen *bytesDecoded, int mode); +int GDecComponentAny ( void* mem_op, GenBuf *b, ComponentAny *result, AsnLen *bytesDecoded, int mode); +int MatchingComponentAny (char* oid, ComponentAny *a, ComponentAny *b); +void FreeComponentAny ( ComponentAny*); + +void InstallAnyByComponentInt (int anyId, ComponentInt intId, unsigned int size, EncodeFcn encode, gser_decoder_func* G_decode, ber_tag_decoder_func B_decode, ExtractFcn extract, MatchFcn match, FreeFcn free, PrintFcn print); + +void InstallAnyByComponentOid (int anyId, AsnOid *oid, unsigned int size, EncodeFcn encode, gser_decoder_func* G_decode, ber_tag_decoder_func* B_decode, ExtractFcn extract, MatchFcn match, FreeFcn free, PrintFcn print); + +int CheckSelectTypeCorrect ( void* mem_op, ComponentAnyInfo *v, struct berval* select ); + +OidDecoderMapping* RetrieveOidDecoderMappingbyBV( struct berval* in ); +OidDecoderMapping* RetrieveOidDecoderMappingbyOid( char* ch_oid, int oid_len ); +OidDecoderMapping* RetrieveOidDecoderMappingbyDesc( char* desc, int desc_len ); +/* + * UTCTime + */ +typedef ComponentVisibleString ComponentUTCTime; +#define GEncComponentUTCTime GEncComponentUTF8String +#define GDecComponentUTCTime GDecComponentVisibleString +#define BDecComponentUTCTime BDecComponentOcts +#define MatchingComponentUTCTime MatchingComponentOcts +#define ExtractingComponentUTCTime(mem_op,cr,data) NULL +#define FreeComponentUTCTime FreeComponentOcts + +/* + * GeneralizedTime + */ +typedef ComponentVisibleString ComponentGeneralizedTime; +int GEncComponentGeneralizedTime (GenBuf *b, ComponentGeneralizedTime *gen_time); +#define GDecComponentGeneralizedTime GDecComponentVisibleString +#define BDecComponentGeneralizedTime BDecComponentOcts +#define MatchingComponentGeneralizedTime MatchingComponentOcts +#define ExtractingComponentGeneralizedTime(mem_op,cr,data) NULL +#define FreeComponentGeneralizedTime FreeComponentOcts + +typedef int converter_func LDAP_P (( + struct berval* in )); + +typedef struct asntype_to_syntax { + AsnTypeId ats_typeId; + /* Syntax Descriptor */ + char *ats_syn_name; + /* Syntax OID */ + char *ats_syn_oid; + Syntax *ats_syn; +} AsnTypetoSyntax; + +typedef struct asntype_to_comp_matchingrule { + AsnTypeId atc_typeId; + char* atc_equality; + char* atc_approx; + char* atc_ordering; + char* atc_substr; +} AsnTypetoCompMatchingRule; + +typedef struct asntype_to_comp_desc { + AsnTypeId atcd_typeId; + ComponentDesc atcd_cd; +} AsnTypetoCompDesc; + +typedef struct asntype_to_comp_type { + AsnTypeId ac_asn_id; + ComponentType ac_comp_type; +} AsnTypetoCompType; + +/* refined matching purpose */ +typedef struct asntype_to_matchingrule { + AsnTypeId atmr_typeId; + char* atmr_mr_name; + /*Implicitly corresponding LDAP syntax OID*/ + char* atmr_syn_oid; + MatchingRule *atmr_mr; +} AsnTypetoMatchingRule; + +typedef struct asntype_to_matchingrule_table { + char* atmr_oid; + struct asntype_to_matchingrule atmr_table[ASNTYPE_END]; + struct asntype_to_matchingrule_table* atmr_table_next; +} AsnTypetoMatchingRuleTable; + +#define MAX_OID_LEN 256 +#define MAX_OD_ENTRY 8 + +/* + * Object Identifier and corresponding Syntax Decoder Table + */ +typedef struct OID_Decoder_entry { + char oe_oid[MAX_OID_LEN]; + gser_decoder_func* oe_gser_decoder; + ber_decoder_func* oe_ber_decoder; + converter_func* oe_converter; + struct OID_Decoder_entry* oe_next; + struct OID_Decoder_entry* oe_prev; +} OD_entry; + +void +m_convert_asn_to_ldap ( ComponentSyntaxInfo* csi, struct berval* bv); +int +m_convert_assert_to_comp ( gser_decoder_func* decoder, struct berval* bv, + ComponentSyntaxInfo** csi, int len, int mode ); +void* +m_convert_attr_to_comp ( Attribute* a, struct berval* bv ); + +/* + * Decoder Modes + * Different operation is required to handle Decoding(2), Extracted Component + * decoding(0), ANY DEFINED TYPe(2) + * b0 : Component Alloc(yes) + * Constructed type : Component Alloc (Yes) + * Primitive type : Component Alloc (Yes) + * set to mode 2 in inner decoders + * b1 : Component Alloc (No) + * Constructed type : Component Alloc (No) + * Primitive type : Component Alloc (No) + * set to mode 2 in inner decoders + * b2 : Default Mode + * Constructed type : Component Alloc (Yes) + * Primitive type : Component Alloc (No) + * in addition to above modes, the 4th bit has special meaning, + * b4 : if the 4th bit is clear, DecxxxContent is called + * b4 : if the 4th bit is set, Decxxx is called, then it is cleared. + */ +#define DEC_ALLOC_MODE_0 0x01 +#define DEC_ALLOC_MODE_1 0x02 +#define DEC_ALLOC_MODE_2 0x04 +#define CALL_TAG_DECODER 0x08 +#define CALL_CONTENT_DECODER ~0x08 + +#define OID_ALL_COMP_MATCH "1.2.36.79672281.1.13.6" +#define OID_COMP_FILTER_MATCH "1.2.36.79672281.1.13.2" +#define MAX_LDAP_STR_LEN 128 + +MatchingRule* +retrieve_matching_rule( char* mr_oid, AsnTypeId type ); + +#define INITIAL_DN_SIZE 128 +#define INITIAL_ATTR_SIZE 256 +#define INCREMENT_SIZE 32 +/* + * Followings are for conversion from ASN.1 RDN and DN to + * LDAP encodings + */ +#define MAX_ALIASING_ENTRY 128 +int increment_bv_mem ( struct berval* in ); +int intToAscii ( int value, char* buf ); +typedef ComponentList irRDNSequence; +typedef ComponentList irRelativeDistinguishedName; +typedef ComponentOid irAttributeType; +typedef struct comp_irAttributeTypeAndValue /* SEQUENCE */ +{ + Syntax* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + irAttributeType type; /* AttributeType */ + ComponentAnyDefinedBy value; /* ANY DEFINED BY type */ +} irAttributeTypeAndValue; +#define RDN_MATCH_OID "1.2.36.79672281.1.13.3" +#define DN_MATCH_OID "2.5.13.1" + +extern AsnTypetoSyntax asn_to_syntax_mapping_tbl[]; +extern AsnTypetoCompMatchingRule asntype_to_compMR_mapping_tbl[]; +extern AsnTypetoCompType asntype_to_compType_mapping_tbl[]; +extern AsnTypetoCompDesc asntype_to_compdesc_mapping_tbl[]; + +int ConvertRDN2RFC2253 ( irRelativeDistinguishedName* in, struct berval *out ); +int ConvertRDNSequence2RFC2253( irRDNSequence *in, struct berval* out ); + +void* comp_nibble_memory_allocator ( int init_mem, int inc_mem ); + +ComponentDesc* get_ComponentDesc( int id ); +#endif diff --git a/contrib/slapd-modules/comp_match/crl.c b/contrib/slapd-modules/comp_match/crl.c new file mode 100644 index 0000000..abd82cd --- /dev/null +++ b/contrib/slapd-modules/comp_match/crl.c @@ -0,0 +1,1294 @@ +/* + * crl.c + * "CertificateRevokationList" ASN.1 module encode/decode/extracting/matching/free C src. + * This file was generated by modified eSMACC compiler Fri Jan 21 11:25:24 2005 + * The generated files are supposed to be compiled as a module for OpenLDAP Software + */ + +#include "crl.h" + +BDecComponentCertificateListTop( void* mem_op, GenBuf* b, void *v, AsnLen* bytesDecoded,int mode) { + AsnTag tag; + AsnLen elmtLen; + + tag = BDecTag ( b, bytesDecoded ); + elmtLen = BDecLen ( b, bytesDecoded ); + if ( elmtLen <= 0 ) return (-1); + if ( tag != MAKE_TAG_ID (UNIV, CONS, SEQ_TAG_CODE) ) { + return (-1); + } + + return BDecComponentCertificateList( mem_op, b, tag, elmtLen, ( ComponentCertificateList**)v, (AsnLen*)bytesDecoded, mode ); +} + + +void init_module_CertificateRevokationList() { + InstallOidDecoderMapping( "2.5.4.39", NULL, + GDecComponentCertificateList, + BDecComponentCertificateListTop, + ExtractingComponentCertificateList, + MatchingComponentCertificateList); +} + +int +MatchingComponentTBSCertListSeqOfSeq ( char* oid, ComponentSyntaxInfo* csi_attr, ComponentSyntaxInfo* csi_assert ) { + int rc; + MatchingRule* mr; + + if ( oid ) { + mr = retrieve_matching_rule( oid, csi_attr->csi_comp_desc->cd_type_id); + if ( mr ) return component_value_match( mr, csi_attr, csi_assert ); + } + + rc = 1; + rc = MatchingComponentCertificateSerialNumber ( oid, (ComponentSyntaxInfo*)&((ComponentTBSCertListSeqOfSeq*)csi_attr)->userCertificate, (ComponentSyntaxInfo*)&((ComponentTBSCertListSeqOfSeq*)csi_assert)->userCertificate ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + rc = MatchingComponentTime ( oid, (ComponentSyntaxInfo*)((ComponentTBSCertListSeqOfSeq*)csi_attr)->revocationDate, (ComponentSyntaxInfo*)((ComponentTBSCertListSeqOfSeq*)csi_assert)->revocationDate ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + if(COMPONENTNOT_NULL( ((ComponentTBSCertListSeqOfSeq*)csi_attr)->crlEntryExtensions ) ) { + rc = MatchingComponentExtensions ( oid, (ComponentSyntaxInfo*)((ComponentTBSCertListSeqOfSeq*)csi_attr)->crlEntryExtensions, (ComponentSyntaxInfo*)((ComponentTBSCertListSeqOfSeq*)csi_assert)->crlEntryExtensions ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + } + return LDAP_COMPARE_TRUE; +} /* BMatchingComponentTBSCertListSeqOfSeq */ + +void* +ExtractingComponentTBSCertListSeqOfSeq ( void* mem_op, ComponentReference* cr, ComponentTBSCertListSeqOfSeq *comp ) +{ + + if ( ( comp->userCertificate.identifier.bv_val && strncmp(comp->userCertificate.identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->userCertificate.id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return &comp->userCertificate; + else + return NULL; + } + if ( ( comp->revocationDate->identifier.bv_val && strncmp(comp->revocationDate->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->revocationDate->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->revocationDate; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentTime ( mem_op, cr, comp->revocationDate ); + } + } + if ( ( comp->crlEntryExtensions->identifier.bv_val && strncmp(comp->crlEntryExtensions->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->crlEntryExtensions->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->crlEntryExtensions; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentExtensions ( mem_op, cr, comp->crlEntryExtensions ); + } + } + return NULL; +} /* ExtractingComponentTBSCertListSeqOfSeq */ + +int +BDecComponentTBSCertListSeqOfSeq PARAMS ((b, tagId0, elmtLen0, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +AsnTag tagId0 _AND_ +AsnLen elmtLen0 _AND_ +ComponentTBSCertListSeqOfSeq **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + int seqDone = FALSE; + AsnLen totalElmtsLen1 = 0; + AsnLen elmtLen1; + AsnTag tagId1; + int mandatoryElmtCount1 = 0; + AsnLen totalElmtsLen2 = 0; + AsnLen elmtLen2; + AsnTag tagId2; + int old_mode = mode; + int rc; + ComponentTBSCertListSeqOfSeq *k, *t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + tagId1 = BDecTag (b, &totalElmtsLen1 ); + + if (((tagId1 == MAKE_TAG_ID (UNIV, PRIM, INTEGER_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentCertificateSerialNumber (mem_op, b, tagId1, elmtLen1, (&k->userCertificate), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->userCertificate)->identifier.bv_val = (&k->userCertificate)->id_buf; + (&k->userCertificate)->identifier.bv_len = strlen("userCertificate"); + strcpy( (&k->userCertificate)->identifier.bv_val, "userCertificate"); + tagId1 = BDecTag (b, &totalElmtsLen1); + } + else + return -1; + + + + if (((tagId1 == MAKE_TAG_ID (UNIV, PRIM, UTCTIME_TAG_CODE)) || +(tagId1 == MAKE_TAG_ID (UNIV, CONS, UTCTIME_TAG_CODE)) || + (tagId1 ==MAKE_TAG_ID (UNIV, PRIM, GENERALIZEDTIME_TAG_CODE))|| + (tagId1 == MAKE_TAG_ID (UNIV, CONS, GENERALIZEDTIME_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentTime (mem_op, b, tagId1, elmtLen1, (&k->revocationDate), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->revocationDate)->identifier.bv_val = (k->revocationDate)->id_buf; + (k->revocationDate)->identifier.bv_len = strlen("revocationDate"); + strcpy( (k->revocationDate)->identifier.bv_val, "revocationDate"); + if ((elmtLen0 != INDEFINITE_LEN) && (totalElmtsLen1 == elmtLen0)) + seqDone = TRUE; + else + { + tagId1 = BDecTag (b, &totalElmtsLen1 ); + + if ((elmtLen0 == INDEFINITE_LEN) && (tagId1 == EOC_TAG_ID)) + { + BDEC_2ND_EOC_OCTET (b, &totalElmtsLen1 ) + seqDone = TRUE; + } + } + } + else + return -1; + + + + if ((!seqDone) && ((tagId1 == MAKE_TAG_ID (UNIV, CONS, SEQ_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentExtensions (mem_op, b, tagId1, elmtLen1, (&k->crlEntryExtensions), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->crlEntryExtensions)->identifier.bv_val = (k->crlEntryExtensions)->id_buf; + (k->crlEntryExtensions)->identifier.bv_len = strlen("crlEntryExtensions"); + strcpy( (k->crlEntryExtensions)->identifier.bv_val, "crlEntryExtensions"); + seqDone = TRUE; + if (elmtLen0 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + else if (totalElmtsLen1 != elmtLen0) + return -1; + + } + + + if (!seqDone) + return -1; + + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentTBSCertListSeqOfSeq*) CompAlloc( mem_op, sizeof(ComponentTBSCertListSeqOfSeq) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_ldap_encoder = (encoder_func*)NULL; + t->comp_desc->cd_gser_encoder = (encoder_func*)NULL; + t->comp_desc->cd_ber_encoder = (encoder_func*)NULL; + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentTBSCertListSeqOfSeq ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentTBSCertListSeqOfSeq ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentTBSCertListSeqOfSeq; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentTBSCertListSeqOfSeq; + (*bytesDecoded) += totalElmtsLen1; + return LDAP_SUCCESS; +} /* BDecTBSCertListSeqOfSeq*/ + +int +GDecComponentTBSCertListSeqOfSeq PARAMS (( mem_op,b, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +ComponentTBSCertListSeqOfSeq **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + char* peek_head,*peek_head2; + int i, strLen,strLen2, rc, old_mode = mode; + ComponentTBSCertListSeqOfSeq *k,*t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + *bytesDecoded = 0; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '{'){ + Asn1Error("Missing { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + if ( strncmp( peek_head, "userCertificate", strlen("userCertificate") ) == 0 ) { + rc = GDecComponentCertificateSerialNumber (mem_op, b, (&k->userCertificate), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->userCertificate)->identifier.bv_val = peek_head; + (&k->userCertificate)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "revocationDate", strlen("revocationDate") ) == 0 ) { + rc = GDecComponentTime (mem_op, b, (&k->revocationDate), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->revocationDate)->identifier.bv_val = peek_head; + ( k->revocationDate)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "crlEntryExtensions", strlen("crlEntryExtensions") ) == 0 ) { + rc = GDecComponentExtensions (mem_op, b, (&k->crlEntryExtensions), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->crlEntryExtensions)->identifier.bv_val = peek_head; + ( k->crlEntryExtensions)->identifier.bv_len = strLen; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ) { + Asn1Error("Error during Reading } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '}'){ + Asn1Error("Missing } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentTBSCertListSeqOfSeq*) CompAlloc( mem_op, sizeof(ComponentTBSCertListSeqOfSeq) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_ldap_encoder = (encoder_func*)NULL; + t->comp_desc->cd_gser_encoder = (encoder_func*)NULL; + t->comp_desc->cd_ber_encoder = (encoder_func*)NULL; + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentTBSCertListSeqOfSeq ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentTBSCertListSeqOfSeq ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentTBSCertListSeqOfSeq; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentTBSCertListSeqOfSeq; + return LDAP_SUCCESS; +} /* GDecTBSCertListSeqOfSeq*/ + + +int +MatchingComponentTBSCertListSeqOf ( char* oid, ComponentSyntaxInfo* csi_attr, ComponentSyntaxInfo* csi_assert ) { + int rc; + MatchingRule* mr; + void* component1, *component2; + AsnList *v1, *v2, t_list; + + + if ( oid ) { + mr = retrieve_matching_rule( oid, csi_attr->csi_comp_desc->cd_type_id); + if ( mr ) return component_value_match( mr, csi_attr, csi_assert ); + } + + v1 = &((ComponentTBSCertListSeqOf*)csi_attr)->comp_list; + v2 = &((ComponentTBSCertListSeqOf*)csi_assert)->comp_list; + FOR_EACH_LIST_PAIR_ELMT(component1, component2, v1, v2) + { + if( MatchingComponentTBSCertListSeqOfSeq(oid, (ComponentSyntaxInfo*)component1, (ComponentSyntaxInfo*)component2) == LDAP_COMPARE_FALSE) { + return LDAP_COMPARE_FALSE; + } + } /* end of for */ + + AsnListFirst( v1 ); + AsnListFirst( v2 ); + if( (!component1 && component2) || (component1 && !component2)) + return LDAP_COMPARE_FALSE; + else + return LDAP_COMPARE_TRUE; +} /* BMatchingComponentTBSCertListSeqOfContent */ + +void* +ExtractingComponentTBSCertListSeqOf ( void* mem_op, ComponentReference* cr, ComponentTBSCertListSeqOf *comp ) +{ + int count = 0; + int total; + AsnList *v = &comp->comp_list; + ComponentInt *k; + ComponentTBSCertListSeqOfSeq *component; + + + switch ( cr->cr_curr->ci_type ) { + case LDAP_COMPREF_FROM_BEGINNING : + count = cr->cr_curr->ci_val.ci_from_beginning; + FOR_EACH_LIST_ELMT( component , v ) { + if( --count == 0 ) { + if( cr->cr_curr->ci_next == NULL ) + return component; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentTBSCertListSeqOfSeq ( mem_op, cr, component ); + } + } + } + break; + case LDAP_COMPREF_FROM_END : + total = AsnListCount ( v ); + count = cr->cr_curr->ci_val.ci_from_end; + count = total + count +1; + FOR_EACH_LIST_ELMT ( component, v ) { + if( --count == 0 ) { + if( cr->cr_curr->ci_next == NULL ) + return component; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentTBSCertListSeqOfSeq ( mem_op, cr, component ); + } + } + } + break; + case LDAP_COMPREF_ALL : + return comp; + case LDAP_COMPREF_COUNT : + k = (ComponentInt*)CompAlloc( mem_op, sizeof(ComponentInt)); + k->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + k->comp_desc->cd_tag = (-1); + k->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentInt; + k->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentInt; + k->comp_desc->cd_extract_i = (extract_component_from_id_func*)NULL; + k->comp_desc->cd_type = ASN_BASIC; + k->comp_desc->cd_type_id = BASICTYPE_INTEGER; + k->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentInt; + k->value = AsnListCount(v); + return k; + default : + return NULL; + } +} /* ExtractingComponentTBSCertListSeqOf */ + +int +BDecComponentTBSCertListSeqOf PARAMS ((b, tagId0, elmtLen0, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +AsnTag tagId0 _AND_ +AsnLen elmtLen0 _AND_ +ComponentTBSCertListSeqOf **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + int seqDone = FALSE; + AsnLen totalElmtsLen1 = 0; + AsnLen elmtLen1; + AsnTag tagId1; + int mandatoryElmtCount1 = 0; + int old_mode = mode; + int rc; + ComponentTBSCertListSeqOf *k, *t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + AsnListInit(&k->comp_list,sizeof(ComponentTBSCertListSeqOfSeq)); + for (totalElmtsLen1 = 0; (totalElmtsLen1 < elmtLen0) || (elmtLen0 == INDEFINITE_LEN);) + { + ComponentTBSCertListSeqOfSeq **tmpVar; + tagId1 = BDecTag (b, &totalElmtsLen1 ); + + if ((tagId1 == EOC_TAG_ID) && (elmtLen0 == INDEFINITE_LEN)) + { + BDEC_2ND_EOC_OCTET (b, &totalElmtsLen1 ) + break; /* got EOC so can exit this SET OF/SEQ OF's for loop*/ + } + if ((tagId1 == MAKE_TAG_ID (UNIV, CONS, SEQ_TAG_CODE))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + tmpVar = (ComponentTBSCertListSeqOfSeq**) CompAsnListAppend (mem_op,&k->comp_list); + rc = BDecComponentTBSCertListSeqOfSeq (mem_op, b, tagId1, elmtLen1, tmpVar, &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + } /* end of tag check if */ + else /* wrong tag */ + { + Asn1Error ("Unexpected Tag\n"); + return -1; + } + } /* end of for */ + + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentTBSCertListSeqOf*) CompAlloc( mem_op, sizeof(ComponentTBSCertListSeqOf) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_ldap_encoder = (encoder_func*)NULL; + t->comp_desc->cd_gser_encoder = (encoder_func*)NULL; + t->comp_desc->cd_ber_encoder = (encoder_func*)NULL; + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentTBSCertListSeqOf ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentTBSCertListSeqOf ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentTBSCertListSeqOf; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentTBSCertListSeqOf; + (*bytesDecoded) += totalElmtsLen1; + return LDAP_SUCCESS; +} /* BDecTBSCertListSeqOfContent */ + +int +GDecComponentTBSCertListSeqOf PARAMS (( mem_op,b, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +ComponentTBSCertListSeqOf **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + char* peek_head,*peek_head2; + int i, strLen,strLen2, rc, old_mode = mode; + ComponentTBSCertListSeqOf *k,*t, c_temp; + + + int ElmtsLen1; + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + AsnListInit( &k->comp_list, sizeof( ComponentTBSCertListSeqOfSeq ) ); + *bytesDecoded = 0; + if( !(strLen = LocateNextGSERToken(mem_op,b, &peek_head, GSER_PEEK)) ){ + Asn1Error("Error during Reading { in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '{'){ + Asn1Error("Missing { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + + for (ElmtsLen1 = 0; ElmtsLen1 >= INDEFINITE_LEN; ElmtsLen1++) + { + ComponentTBSCertListSeqOfSeq **tmpVar; + if( !(strLen = LocateNextGSERToken(mem_op,b, &peek_head, GSER_NO_COPY)) ){ + Asn1Error("Error during Reading{ in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head == '}') break; + if( !(*peek_head == '{' || *peek_head ==',') ) { + return LDAP_PROTOCOL_ERROR; + } + tmpVar = (ComponentTBSCertListSeqOfSeq**) CompAsnListAppend (mem_op, &k->comp_list); + if ( tmpVar == NULL ) { + Asn1Error("Error during Reading{ in encoding"); + return LDAP_PROTOCOL_ERROR; + } + rc = GDecComponentTBSCertListSeqOfSeq (mem_op, b, tmpVar, bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + } /* end of for */ + + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentTBSCertListSeqOf*) CompAlloc( mem_op, sizeof(ComponentTBSCertListSeqOf) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_ldap_encoder = (encoder_func*)NULL; + t->comp_desc->cd_gser_encoder = (encoder_func*)NULL; + t->comp_desc->cd_ber_encoder = (encoder_func*)NULL; + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentTBSCertListSeqOf ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentTBSCertListSeqOf ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentTBSCertListSeqOf; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentTBSCertListSeqOf; + return LDAP_SUCCESS; +} /* GDecTBSCertListSeqOfContent */ + +int +MatchingComponentTBSCertList ( char* oid, ComponentSyntaxInfo* csi_attr, ComponentSyntaxInfo* csi_assert ) { + int rc; + MatchingRule* mr; + + if ( oid ) { + mr = retrieve_matching_rule( oid, csi_attr->csi_comp_desc->cd_type_id); + if ( mr ) return component_value_match( mr, csi_attr, csi_assert ); + } + + rc = 1; + if(COMPONENTNOT_NULL( ((ComponentTBSCertList*)csi_attr)->version ) ) { + rc = MatchingComponentVersion ( oid, (ComponentSyntaxInfo*)((ComponentTBSCertList*)csi_attr)->version, (ComponentSyntaxInfo*)((ComponentTBSCertList*)csi_assert)->version ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + } + rc = MatchingComponentAlgorithmIdentifier ( oid, (ComponentSyntaxInfo*)((ComponentTBSCertList*)csi_attr)->signature, (ComponentSyntaxInfo*)((ComponentTBSCertList*)csi_assert)->signature ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + rc = MatchingComponentName ( oid, (ComponentSyntaxInfo*)((ComponentTBSCertList*)csi_attr)->issuer, (ComponentSyntaxInfo*)((ComponentTBSCertList*)csi_assert)->issuer ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + rc = MatchingComponentTime ( oid, (ComponentSyntaxInfo*)((ComponentTBSCertList*)csi_attr)->thisUpdate, (ComponentSyntaxInfo*)((ComponentTBSCertList*)csi_assert)->thisUpdate ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + if(COMPONENTNOT_NULL( ((ComponentTBSCertList*)csi_attr)->nextUpdate ) ) { + rc = MatchingComponentTime ( oid, (ComponentSyntaxInfo*)((ComponentTBSCertList*)csi_attr)->nextUpdate, (ComponentSyntaxInfo*)((ComponentTBSCertList*)csi_assert)->nextUpdate ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + } + rc = MatchingComponentTBSCertListSeqOf ( oid, (ComponentSyntaxInfo*)((ComponentTBSCertList*)csi_attr)->revokedCertificates, (ComponentSyntaxInfo*)((ComponentTBSCertList*)csi_assert)->revokedCertificates ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + if(COMPONENTNOT_NULL( ((ComponentTBSCertList*)csi_attr)->crlExtensions ) ) { + rc = MatchingComponentExtensions ( oid, (ComponentSyntaxInfo*)((ComponentTBSCertList*)csi_attr)->crlExtensions, (ComponentSyntaxInfo*)((ComponentTBSCertList*)csi_assert)->crlExtensions ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + } + return LDAP_COMPARE_TRUE; +} /* BMatchingComponentTBSCertList */ + +void* +ExtractingComponentTBSCertList ( void* mem_op, ComponentReference* cr, ComponentTBSCertList *comp ) +{ + + if ( ( comp->version->identifier.bv_val && strncmp(comp->version->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->version->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->version; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentVersion ( mem_op, cr, comp->version ); + } + } + if ( ( comp->signature->identifier.bv_val && strncmp(comp->signature->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->signature->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->signature; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentAlgorithmIdentifier ( mem_op, cr, comp->signature ); + } + } + if ( ( comp->issuer->identifier.bv_val && strncmp(comp->issuer->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->issuer->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->issuer; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentName ( mem_op, cr, comp->issuer ); + } + } + if ( ( comp->thisUpdate->identifier.bv_val && strncmp(comp->thisUpdate->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->thisUpdate->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->thisUpdate; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentTime ( mem_op, cr, comp->thisUpdate ); + } + } + if ( ( comp->nextUpdate->identifier.bv_val && strncmp(comp->nextUpdate->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->nextUpdate->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->nextUpdate; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentTime ( mem_op, cr, comp->nextUpdate ); + } + } + if ( ( comp->revokedCertificates->identifier.bv_val && strncmp(comp->revokedCertificates->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->revokedCertificates->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->revokedCertificates; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentTBSCertListSeqOf ( mem_op, cr, comp->revokedCertificates ); + } + } + if ( ( comp->crlExtensions->identifier.bv_val && strncmp(comp->crlExtensions->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->crlExtensions->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->crlExtensions; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentExtensions ( mem_op, cr, comp->crlExtensions ); + } + } + return NULL; +} /* ExtractingComponentTBSCertList */ + +int +BDecComponentTBSCertList PARAMS ((b, tagId0, elmtLen0, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +AsnTag tagId0 _AND_ +AsnLen elmtLen0 _AND_ +ComponentTBSCertList **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + int seqDone = FALSE; + AsnLen totalElmtsLen1 = 0; + AsnLen elmtLen1; + AsnTag tagId1; + int mandatoryElmtCount1 = 0; + AsnLen totalElmtsLen2 = 0; + AsnLen elmtLen2; + AsnTag tagId2; + int old_mode = mode; + int rc; + ComponentTBSCertList *k, *t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + tagId1 = BDecTag (b, &totalElmtsLen1 ); + + if (((tagId1 == MAKE_TAG_ID (UNIV, PRIM, INTEGER_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentVersion (mem_op, b, tagId1, elmtLen1, (&k->version), &totalElmtsLen1, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + (k->version)->identifier.bv_val = (k->version)->id_buf; + (k->version)->identifier.bv_len = strlen("version"); + strcpy( (k->version)->identifier.bv_val, "version"); + tagId1 = BDecTag (b, &totalElmtsLen1); + } + + + if (((tagId1 == MAKE_TAG_ID (UNIV, CONS, SEQ_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentAlgorithmIdentifier (mem_op, b, tagId1, elmtLen1, (&k->signature), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->signature)->identifier.bv_val = (k->signature)->id_buf; + (k->signature)->identifier.bv_len = strlen("signature"); + strcpy( (k->signature)->identifier.bv_val, "signature"); + tagId1 = BDecTag (b, &totalElmtsLen1); + } + else + return -1; + + + + if (((tagId1 == MAKE_TAG_ID (UNIV, CONS, SEQ_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentName (mem_op, b, tagId1, elmtLen1, (&k->issuer), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->issuer)->identifier.bv_val = (k->issuer)->id_buf; + (k->issuer)->identifier.bv_len = strlen("issuer"); + strcpy( (k->issuer)->identifier.bv_val, "issuer"); + tagId1 = BDecTag (b, &totalElmtsLen1); + } + else + return -1; + + + + if (((tagId1 == MAKE_TAG_ID (UNIV, PRIM, UTCTIME_TAG_CODE)) || +(tagId1 == MAKE_TAG_ID (UNIV, CONS, UTCTIME_TAG_CODE)) || + (tagId1 ==MAKE_TAG_ID (UNIV, PRIM, GENERALIZEDTIME_TAG_CODE))|| + (tagId1 == MAKE_TAG_ID (UNIV, CONS, GENERALIZEDTIME_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentTime (mem_op, b, tagId1, elmtLen1, (&k->thisUpdate), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->thisUpdate)->identifier.bv_val = (k->thisUpdate)->id_buf; + (k->thisUpdate)->identifier.bv_len = strlen("thisUpdate"); + strcpy( (k->thisUpdate)->identifier.bv_val, "thisUpdate"); + tagId1 = BDecTag (b, &totalElmtsLen1); + } + else + return -1; + + + + if (((tagId1 == MAKE_TAG_ID (UNIV, PRIM, UTCTIME_TAG_CODE)) || +(tagId1 == MAKE_TAG_ID (UNIV, CONS, UTCTIME_TAG_CODE)) || + (tagId1 ==MAKE_TAG_ID (UNIV, PRIM, GENERALIZEDTIME_TAG_CODE))|| + (tagId1 == MAKE_TAG_ID (UNIV, CONS, GENERALIZEDTIME_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentTime (mem_op, b, tagId1, elmtLen1, (&k->nextUpdate), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->nextUpdate)->identifier.bv_val = (k->nextUpdate)->id_buf; + (k->nextUpdate)->identifier.bv_len = strlen("nextUpdate"); + strcpy( (k->nextUpdate)->identifier.bv_val, "nextUpdate"); + tagId1 = BDecTag (b, &totalElmtsLen1); + } + + + if (((tagId1 == MAKE_TAG_ID (UNIV, CONS, SEQ_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentTBSCertListSeqOf (mem_op, b, tagId1, elmtLen1, (&k->revokedCertificates), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->revokedCertificates)->identifier.bv_val = (k->revokedCertificates)->id_buf; + (k->revokedCertificates)->identifier.bv_len = strlen("revokedCertificates"); + strcpy( (k->revokedCertificates)->identifier.bv_val, "revokedCertificates"); + if ((elmtLen0 != INDEFINITE_LEN) && (totalElmtsLen1 == elmtLen0)) + seqDone = TRUE; + else + { + tagId1 = BDecTag (b, &totalElmtsLen1 ); + + if ((elmtLen0 == INDEFINITE_LEN) && (tagId1 == EOC_TAG_ID)) + { + BDEC_2ND_EOC_OCTET (b, &totalElmtsLen1 ) + seqDone = TRUE; + } + } + } + else + return -1; + + + + if ((!seqDone) && ((tagId1 == MAKE_TAG_ID (CNTX, CONS, 0)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + tagId2 = BDecTag (b, &totalElmtsLen1 ); + + if (tagId2 != MAKE_TAG_ID (UNIV, CONS, SEQ_TAG_CODE)) + { + Asn1Error ("Unexpected Tag\n"); + return -1; + } + + elmtLen2 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentExtensions (mem_op, b, tagId2, elmtLen2, (&k->crlExtensions), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->crlExtensions)->identifier.bv_val = (k->crlExtensions)->id_buf; + (k->crlExtensions)->identifier.bv_len = strlen("crlExtensions"); + strcpy( (k->crlExtensions)->identifier.bv_val, "crlExtensions"); + if (elmtLen1 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + seqDone = TRUE; + if (elmtLen0 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + else if (totalElmtsLen1 != elmtLen0) + return -1; + + } + + + if (!seqDone) + return -1; + + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentTBSCertList*) CompAlloc( mem_op, sizeof(ComponentTBSCertList) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_ldap_encoder = (encoder_func*)NULL; + t->comp_desc->cd_gser_encoder = (encoder_func*)NULL; + t->comp_desc->cd_ber_encoder = (encoder_func*)NULL; + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentTBSCertList ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentTBSCertList ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentTBSCertList; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentTBSCertList; + (*bytesDecoded) += totalElmtsLen1; + return LDAP_SUCCESS; +} /* BDecTBSCertList*/ + +int +GDecComponentTBSCertList PARAMS (( mem_op,b, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +ComponentTBSCertList **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + char* peek_head,*peek_head2; + int i, strLen,strLen2, rc, old_mode = mode; + ComponentTBSCertList *k,*t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + *bytesDecoded = 0; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '{'){ + Asn1Error("Missing { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + if ( strncmp( peek_head, "version", strlen("version") ) == 0 ) { + rc = GDecComponentVersion (mem_op, b, (&k->version), bytesDecoded, DEC_ALLOC_MODE_0 ); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->version)->identifier.bv_val = peek_head; + ( k->version)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "signature", strlen("signature") ) == 0 ) { + rc = GDecComponentAlgorithmIdentifier (mem_op, b, (&k->signature), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->signature)->identifier.bv_val = peek_head; + ( k->signature)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "issuer", strlen("issuer") ) == 0 ) { + rc = GDecComponentName (mem_op, b, (&k->issuer), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->issuer)->identifier.bv_val = peek_head; + ( k->issuer)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "thisUpdate", strlen("thisUpdate") ) == 0 ) { + rc = GDecComponentTime (mem_op, b, (&k->thisUpdate), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->thisUpdate)->identifier.bv_val = peek_head; + ( k->thisUpdate)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "nextUpdate", strlen("nextUpdate") ) == 0 ) { + rc = GDecComponentTime (mem_op, b, (&k->nextUpdate), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->nextUpdate)->identifier.bv_val = peek_head; + ( k->nextUpdate)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "revokedCertificates", strlen("revokedCertificates") ) == 0 ) { + rc = GDecComponentTBSCertListSeqOf (mem_op, b, (&k->revokedCertificates), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->revokedCertificates)->identifier.bv_val = peek_head; + ( k->revokedCertificates)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "crlExtensions", strlen("crlExtensions") ) == 0 ) { + rc = GDecComponentExtensions (mem_op, b, (&k->crlExtensions), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->crlExtensions)->identifier.bv_val = peek_head; + ( k->crlExtensions)->identifier.bv_len = strLen; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ) { + Asn1Error("Error during Reading } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '}'){ + Asn1Error("Missing } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentTBSCertList*) CompAlloc( mem_op, sizeof(ComponentTBSCertList) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_ldap_encoder = (encoder_func*)NULL; + t->comp_desc->cd_gser_encoder = (encoder_func*)NULL; + t->comp_desc->cd_ber_encoder = (encoder_func*)NULL; + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentTBSCertList ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentTBSCertList ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentTBSCertList; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentTBSCertList; + return LDAP_SUCCESS; +} /* GDecTBSCertList*/ + + +int +MatchingComponentCertificateList ( char* oid, ComponentSyntaxInfo* csi_attr, ComponentSyntaxInfo* csi_assert ) { + int rc; + MatchingRule* mr; + + if ( oid ) { + mr = retrieve_matching_rule( oid, csi_attr->csi_comp_desc->cd_type_id); + if ( mr ) return component_value_match( mr, csi_attr, csi_assert ); + } + + rc = 1; + rc = MatchingComponentTBSCertList ( oid, (ComponentSyntaxInfo*)((ComponentCertificateList*)csi_attr)->tbsCertList, (ComponentSyntaxInfo*)((ComponentCertificateList*)csi_assert)->tbsCertList ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + rc = MatchingComponentAlgorithmIdentifier ( oid, (ComponentSyntaxInfo*)((ComponentCertificateList*)csi_attr)->signatureAlgorithm, (ComponentSyntaxInfo*)((ComponentCertificateList*)csi_assert)->signatureAlgorithm ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + rc = MatchingComponentBits ( oid, (ComponentSyntaxInfo*)&((ComponentCertificateList*)csi_attr)->signature, (ComponentSyntaxInfo*)&((ComponentCertificateList*)csi_assert)->signature ); + if ( rc != LDAP_COMPARE_TRUE ) + return rc; + return LDAP_COMPARE_TRUE; +} /* BMatchingComponentCertificateList */ + +void* +ExtractingComponentCertificateList ( void* mem_op, ComponentReference* cr, ComponentCertificateList *comp ) +{ + + if ( ( comp->tbsCertList->identifier.bv_val && strncmp(comp->tbsCertList->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->tbsCertList->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->tbsCertList; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentTBSCertList ( mem_op, cr, comp->tbsCertList ); + } + } + if ( ( comp->signatureAlgorithm->identifier.bv_val && strncmp(comp->signatureAlgorithm->identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->signatureAlgorithm->id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return comp->signatureAlgorithm; + else { + cr->cr_curr = cr->cr_curr->ci_next; + return ExtractingComponentAlgorithmIdentifier ( mem_op, cr, comp->signatureAlgorithm ); + } + } + if ( ( comp->signature.identifier.bv_val && strncmp(comp->signature.identifier.bv_val, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) || ( strncmp(comp->signature.id_buf, cr->cr_curr->ci_val.ci_identifier.bv_val,cr->cr_curr->ci_val.ci_identifier.bv_len) == 0 ) ) { + if ( cr->cr_curr->ci_next == NULL ) + return &comp->signature; + else if ( cr->cr_curr->ci_next->ci_type == LDAP_COMPREF_CONTENT) { + cr->cr_curr = cr->cr_curr->ci_next; + return &comp->signature; + } else { + return NULL; + } + } + return NULL; +} /* ExtractingComponentCertificateList */ + +int +BDecComponentCertificateList PARAMS ((b, tagId0, elmtLen0, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +AsnTag tagId0 _AND_ +AsnLen elmtLen0 _AND_ +ComponentCertificateList **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + int seqDone = FALSE; + AsnLen totalElmtsLen1 = 0; + AsnLen elmtLen1; + AsnTag tagId1; + int mandatoryElmtCount1 = 0; + int old_mode = mode; + int rc; + ComponentCertificateList *k, *t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + tagId1 = BDecTag (b, &totalElmtsLen1 ); + + if (((tagId1 == MAKE_TAG_ID (UNIV, CONS, SEQ_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentTBSCertList (mem_op, b, tagId1, elmtLen1, (&k->tbsCertList), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->tbsCertList)->identifier.bv_val = (k->tbsCertList)->id_buf; + (k->tbsCertList)->identifier.bv_len = strlen("tbsCertList"); + strcpy( (k->tbsCertList)->identifier.bv_val, "tbsCertList"); + tagId1 = BDecTag (b, &totalElmtsLen1); + } + else + return -1; + + + + if (((tagId1 == MAKE_TAG_ID (UNIV, CONS, SEQ_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentAlgorithmIdentifier (mem_op, b, tagId1, elmtLen1, (&k->signatureAlgorithm), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (k->signatureAlgorithm)->identifier.bv_val = (k->signatureAlgorithm)->id_buf; + (k->signatureAlgorithm)->identifier.bv_len = strlen("signatureAlgorithm"); + strcpy( (k->signatureAlgorithm)->identifier.bv_val, "signatureAlgorithm"); + tagId1 = BDecTag (b, &totalElmtsLen1); + } + else + return -1; + + + + if (((tagId1 == MAKE_TAG_ID (UNIV, PRIM, BITSTRING_TAG_CODE)) || +(tagId1 == MAKE_TAG_ID (UNIV, CONS, BITSTRING_TAG_CODE)))) + { + elmtLen1 = BDecLen (b, &totalElmtsLen1 ); + rc = BDecComponentBits (mem_op, b, tagId1, elmtLen1, (&k->signature), &totalElmtsLen1, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->signature)->identifier.bv_val = (&k->signature)->id_buf; + (&k->signature)->identifier.bv_len = strlen("signature"); + strcpy( (&k->signature)->identifier.bv_val, "signature"); + seqDone = TRUE; + if (elmtLen0 == INDEFINITE_LEN) + BDecEoc (b, &totalElmtsLen1 ); + else if (totalElmtsLen1 != elmtLen0) + return -1; + + } + else + return -1; + + + + if (!seqDone) + return -1; + + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentCertificateList*) CompAlloc( mem_op, sizeof(ComponentCertificateList) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_ldap_encoder = (encoder_func*)NULL; + t->comp_desc->cd_gser_encoder = (encoder_func*)NULL; + t->comp_desc->cd_ber_encoder = (encoder_func*)NULL; + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentCertificateList ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentCertificateList ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentCertificateList; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentCertificateList; + (*bytesDecoded) += totalElmtsLen1; + return LDAP_SUCCESS; +} /* BDecCertificateList*/ + +int +GDecComponentCertificateList PARAMS (( mem_op,b, v, bytesDecoded, mode), +void* mem_op _AND_ +GenBuf * b _AND_ +ComponentCertificateList **v _AND_ +AsnLen *bytesDecoded _AND_ +int mode) +{ + char* peek_head,*peek_head2; + int i, strLen,strLen2, rc, old_mode = mode; + ComponentCertificateList *k,*t, c_temp; + + + if ( !(mode & DEC_ALLOC_MODE_1) ) { + memset(&c_temp,0,sizeof(c_temp)); + k = &c_temp; + } else + k = t = *v; + mode = DEC_ALLOC_MODE_2; + *bytesDecoded = 0; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '{'){ + Asn1Error("Missing { in encoded data"); + return LDAP_PROTOCOL_ERROR; + } + + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + if ( strncmp( peek_head, "tbsCertList", strlen("tbsCertList") ) == 0 ) { + rc = GDecComponentTBSCertList (mem_op, b, (&k->tbsCertList), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->tbsCertList)->identifier.bv_val = peek_head; + ( k->tbsCertList)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "signatureAlgorithm", strlen("signatureAlgorithm") ) == 0 ) { + rc = GDecComponentAlgorithmIdentifier (mem_op, b, (&k->signatureAlgorithm), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + ( k->signatureAlgorithm)->identifier.bv_val = peek_head; + ( k->signatureAlgorithm)->identifier.bv_len = strLen; + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading , "); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != ','){ + Asn1Error("Missing , in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ){ + Asn1Error("Error during Reading identifier"); + return LDAP_PROTOCOL_ERROR; + } + } + if ( strncmp( peek_head, "signature", strlen("signature") ) == 0 ) { + rc = GDecComponentBits (mem_op, b, (&k->signature), bytesDecoded, mode); + if ( rc != LDAP_SUCCESS ) return rc; + (&k->signature)->identifier.bv_val = peek_head; + (&k->signature)->identifier.bv_len = strLen; + } + if( !(strLen = LocateNextGSERToken(mem_op,b,&peek_head,GSER_NO_COPY)) ) { + Asn1Error("Error during Reading } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if(*peek_head != '}'){ + Asn1Error("Missing } in encoding"); + return LDAP_PROTOCOL_ERROR; + } + if( !(old_mode & DEC_ALLOC_MODE_1) ) { + *v = t = (ComponentCertificateList*) CompAlloc( mem_op, sizeof(ComponentCertificateList) ); + if ( !t ) return -1; + *t = *k; + } + t->syntax = (Syntax*)NULL; + t->comp_desc = CompAlloc( mem_op, sizeof( ComponentDesc ) ); + if ( !t->comp_desc ) { + free ( t ); + return -1; + } + t->comp_desc->cd_ldap_encoder = (encoder_func*)NULL; + t->comp_desc->cd_gser_encoder = (encoder_func*)NULL; + t->comp_desc->cd_ber_encoder = (encoder_func*)NULL; + t->comp_desc->cd_gser_decoder = (gser_decoder_func*)GDecComponentCertificateList ; + t->comp_desc->cd_ber_decoder = (ber_decoder_func*)BDecComponentCertificateList ; + t->comp_desc->cd_free = (comp_free_func*)NULL; + t->comp_desc->cd_extract_i = (extract_component_from_id_func*)ExtractingComponentCertificateList; + t->comp_desc->cd_type = ASN_COMPOSITE; + t->comp_desc->cd_type_id = COMPOSITE_ASN1_TYPE; + t->comp_desc->cd_all_match = (allcomponent_matching_func*)MatchingComponentCertificateList; + return LDAP_SUCCESS; +} /* GDecCertificateList*/ diff --git a/contrib/slapd-modules/comp_match/crl.h b/contrib/slapd-modules/comp_match/crl.h new file mode 100644 index 0000000..f2b4a24 --- /dev/null +++ b/contrib/slapd-modules/comp_match/crl.h @@ -0,0 +1,359 @@ + +#include "asn-incl.h" +/* + * crl.h + * "CertificateRevokationList" ASN.1 module encode/decode/extracting/matching/free C src. + * This file was generated by modified eSMACC compiler Fri Jan 21 11:25:24 2005 + * The generated files are strongly encouraged to be + * compiled as a module for OpenLDAP Software + */ + +#ifndef _crl_h_ +#define _crl_h_ + + + + +#ifdef __cplusplus +extern "C" { +#endif +#ifdef _WIN32 +#pragma warning( disable : 4101 ) +#endif +#include "componentlib.h" + +#define V1 0 +#define V2 1 +#define V3 2 + +typedef ComponentInt ComponentVersion; /* INTEGER { V1 (0), V2 (1), V3 (2) } */ + +#define MatchingComponentVersion MatchingComponentInt + +#define ExtractingComponentVersion ExtractingComponentInt + +#define BDecComponentVersion BDecComponentInt + +#define GDecComponentVersion GDecComponentInt + + +typedef ComponentInt ComponentCertificateSerialNumber; /* INTEGER */ + +#define MatchingComponentCertificateSerialNumber MatchingComponentInt + +#define ExtractingComponentCertificateSerialNumber ExtractingComponentInt + +#define BDecComponentCertificateSerialNumber BDecComponentInt + +#define GDecComponentCertificateSerialNumber GDecComponentInt + + +typedef ComponentOid ComponentAttributeType; /* OBJECT IDENTIFIER */ + +#define MatchingComponentAttributeType MatchingComponentOid + +#define ExtractingComponentAttributeType ExtractingComponentOid + +#define BDecComponentAttributeType BDecComponentOid + +#define GDecComponentAttributeType GDecComponentOid + + +typedef struct AlgorithmIdentifier /* SEQUENCE */ +{ + Syntax* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + ComponentOid algorithm; /* OBJECT IDENTIFIER */ + ComponentAnyDefinedBy parameters; /* ANY DEFINED BY algorithm OPTIONAL */ +} ComponentAlgorithmIdentifier; + +int MatchingComponentAlgorithmIdentifier PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentAlgorithmIdentifier PROTO (( void* mem_op, ComponentReference *cr, ComponentAlgorithmIdentifier *comp )); + + +int BDecComponentAlgorithmIdentifier PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentAlgorithmIdentifier **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentAlgorithmIdentifier PROTO (( void* mem_op, GenBuf * b, ComponentAlgorithmIdentifier **v, AsnLen *bytesDecoded, int mode)); + + + +typedef struct Time /* CHOICE */ +{ + Syntax* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + enum TimeChoiceId + { + TIME_UTCTIME, + TIME_GENERALIZEDTIME + } choiceId; + union TimeChoiceUnion + { + ComponentUTCTime* utcTime; /* < unknown type id ?! > */ + ComponentGeneralizedTime* generalizedTime; /* < unknown type id ?! > */ + } a; +} ComponentTime; + +int MatchingComponentTime PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentTime PROTO (( void* mem_op, ComponentReference *cr, ComponentTime *comp )); + + +int BDecComponentTime PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentTime **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentTime PROTO (( void* mem_op, GenBuf * b, ComponentTime **v, AsnLen *bytesDecoded, int mode)); + + + +typedef struct Extension /* SEQUENCE */ +{ + Syntax* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + ComponentOid extnID; /* OBJECT IDENTIFIER */ + ComponentBool* critical; /* BOOLEAN DEFAULT FALSE */ + ComponentOcts extnValue; /* OCTET STRING */ +} ComponentExtension; + +int MatchingComponentExtension PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentExtension PROTO (( void* mem_op, ComponentReference *cr, ComponentExtension *comp )); + + +int BDecComponentExtension PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentExtension **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentExtension PROTO (( void* mem_op, GenBuf * b, ComponentExtension **v, AsnLen *bytesDecoded, int mode)); + + + +typedef struct AttributeTypeAndValue /* SEQUENCE */ +{ + Syntax* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + ComponentAttributeType type; /* AttributeType */ + ComponentAnyDefinedBy value; /* ANY DEFINED BY type */ +} ComponentAttributeTypeAndValue; + +int MatchingComponentAttributeTypeAndValue PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentAttributeTypeAndValue PROTO (( void* mem_op, ComponentReference *cr, ComponentAttributeTypeAndValue *comp )); + + +int BDecComponentAttributeTypeAndValue PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentAttributeTypeAndValue **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentAttributeTypeAndValue PROTO (( void* mem_op, GenBuf * b, ComponentAttributeTypeAndValue **v, AsnLen *bytesDecoded, int mode)); + + + +typedef ComponentList ComponentExtensions; /* SEQUENCE SIZE 1..MAX OF Extension */ + +int MatchingComponentExtensions PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentExtensions PROTO (( void* mem_op, ComponentReference *cr, ComponentExtensions *comp )); + + +int BDecComponentExtensions PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentExtensions **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentExtensions PROTO (( void* mem_op, GenBuf * b, ComponentExtensions **v, AsnLen *bytesDecoded, int mode)); + + + +typedef struct TBSCertListSeqOfSeq /* SEQUENCE */ +{ + Syntax* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + ComponentCertificateSerialNumber userCertificate; /* CertificateSerialNumber */ + ComponentTime* revocationDate; /* Time */ + ComponentExtensions* crlEntryExtensions; /* Extensions OPTIONAL */ +} ComponentTBSCertListSeqOfSeq; + +int MatchingComponentTBSCertListSeqOfSeq PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentTBSCertListSeqOfSeq PROTO (( void* mem_op, ComponentReference *cr, ComponentTBSCertListSeqOfSeq *comp )); + + +int BDecComponentTBSCertListSeqOfSeq PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentTBSCertListSeqOfSeq **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentTBSCertListSeqOfSeq PROTO (( void* mem_op, GenBuf * b, ComponentTBSCertListSeqOfSeq **v, AsnLen *bytesDecoded, int mode)); + + + +typedef ComponentList ComponentTBSCertListSeqOf; /* SEQUENCE OF TBSCertListSeqOfSeq */ + +int MatchingComponentTBSCertListSeqOf PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentTBSCertListSeqOf PROTO (( void* mem_op, ComponentReference *cr, ComponentTBSCertListSeqOf *comp )); + + +int BDecComponentTBSCertListSeqOf PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentTBSCertListSeqOf **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentTBSCertListSeqOf PROTO (( void* mem_op, GenBuf * b, ComponentTBSCertListSeqOf **v, AsnLen *bytesDecoded, int mode)); + + + +typedef ComponentList ComponentRelativeDistinguishedName; /* SET OF AttributeTypeAndValue */ + +int MatchingComponentRelativeDistinguishedName PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentRelativeDistinguishedName PROTO (( void* mem_op, ComponentReference *cr, ComponentRelativeDistinguishedName *comp )); + + +int BDecComponentRelativeDistinguishedName PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentRelativeDistinguishedName **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentRelativeDistinguishedName PROTO (( void* mem_op, GenBuf * b, ComponentRelativeDistinguishedName **v, AsnLen *bytesDecoded, int mode)); + + + +typedef ComponentList ComponentRDNSequence; /* SEQUENCE OF RelativeDistinguishedName */ + +int MatchingComponentRDNSequence PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentRDNSequence PROTO (( void* mem_op, ComponentReference *cr, ComponentRDNSequence *comp )); + + +int BDecComponentRDNSequence PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentRDNSequence **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentRDNSequence PROTO (( void* mem_op, GenBuf * b, ComponentRDNSequence **v, AsnLen *bytesDecoded, int mode)); + + + +typedef struct Name /* CHOICE */ +{ + Syntax* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + enum NameChoiceId + { + NAME_RDNSEQUENCE + } choiceId; + union NameChoiceUnion + { + ComponentRDNSequence* rdnSequence; /* RDNSequence */ + } a; +} ComponentName; + +int MatchingComponentName PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentName PROTO (( void* mem_op, ComponentReference *cr, ComponentName *comp )); + + +int BDecComponentName PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentName **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentName PROTO (( void* mem_op, GenBuf * b, ComponentName **v, AsnLen *bytesDecoded, int mode)); + + + +typedef struct TBSCertList /* SEQUENCE */ +{ + Syntax* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + ComponentVersion* version; /* Version OPTIONAL */ + ComponentAlgorithmIdentifier* signature; /* AlgorithmIdentifier */ + ComponentName* issuer; /* Name */ + ComponentTime* thisUpdate; /* Time */ + ComponentTime* nextUpdate; /* Time OPTIONAL */ + ComponentTBSCertListSeqOf* revokedCertificates; /* TBSCertListSeqOf */ + ComponentExtensions* crlExtensions; /* [0] EXPLICIT Extensions OPTIONAL */ +} ComponentTBSCertList; + +int MatchingComponentTBSCertList PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentTBSCertList PROTO (( void* mem_op, ComponentReference *cr, ComponentTBSCertList *comp )); + + +int BDecComponentTBSCertList PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentTBSCertList **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentTBSCertList PROTO (( void* mem_op, GenBuf * b, ComponentTBSCertList **v, AsnLen *bytesDecoded, int mode)); + + + +typedef struct CertificateList /* SEQUENCE */ +{ + Syntax* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + ComponentTBSCertList* tbsCertList; /* TBSCertList */ + ComponentAlgorithmIdentifier* signatureAlgorithm; /* AlgorithmIdentifier */ + ComponentBits signature; /* BIT STRING */ +} ComponentCertificateList; + +int MatchingComponentCertificateList PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentCertificateList PROTO (( void* mem_op, ComponentReference *cr, ComponentCertificateList *comp )); + + +int BDecComponentCertificateList PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentCertificateList **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentCertificateList PROTO (( void* mem_op, GenBuf * b, ComponentCertificateList **v, AsnLen *bytesDecoded, int mode)); + + + +typedef struct Validity /* SEQUENCE */ +{ + Syntax* syntax; + ComponentDesc* comp_desc; + struct berval identifier; + char id_buf[MAX_IDENTIFIER_LEN]; + ComponentTime* notBefore; /* Time */ + ComponentTime* notAfter; /* Time */ +} ComponentValidity; + +int MatchingComponentValidity PROTO (( char *oid, ComponentSyntaxInfo *, ComponentSyntaxInfo *v2 )); + + +void* ExtractingComponentValidity PROTO (( void* mem_op, ComponentReference *cr, ComponentValidity *comp )); + + +int BDecComponentValidity PROTO ((void* mem_op, GenBuf * b, AsnTag tagId0, AsnLen elmtLen0, ComponentValidity **v, AsnLen *bytesDecoded, int mode)); + + +int GDecComponentValidity PROTO (( void* mem_op, GenBuf * b, ComponentValidity **v, AsnLen *bytesDecoded, int mode)); + + + +/* ========== Object Declarations ========== */ + + +/* ========== Object Set Declarations ========== */ +#ifdef __cplusplus +extern "C" { +#endif + +#endif /* conditional include of crl.h */ diff --git a/contrib/slapd-modules/comp_match/init.c b/contrib/slapd-modules/comp_match/init.c new file mode 100644 index 0000000..5f0d86d --- /dev/null +++ b/contrib/slapd-modules/comp_match/init.c @@ -0,0 +1,839 @@ +/* Copyright 2004 IBM Corporation + * All rights reserved. + * Redisribution and use in source and binary forms, with or without + * modification, are permitted only as authorizd by the OpenLADP + * Public License. + */ +/* ACKNOWLEDGEMENTS + * This work originally developed by Sang Seok Lim + * 2004/06/18 03:20:00 slim@OpenLDAP.org + */ + +#include "portable.h" +#include <ac/string.h> +#include <ac/socket.h> +#include <ldap_pvt.h> +#include "lutil.h" +#include <ldap.h> +#include "slap.h" +#include "component.h" + +#include "componentlib.h" +#include "asn.h" +#include <asn-gser.h> + +#include <string.h> + +#ifndef SLAPD_COMP_MATCH +#define SLAPD_COMP_MATCH SLAPD_MOD_DYNAMIC +#endif + +/* + * Attribute and MatchingRule aliasing table + */ +AttributeAliasing aa_table [ MAX_ALIASING_ENTRY ]; +MatchingRuleAliasing mra_table [ MAX_ALIASING_ENTRY ]; + +OD_entry* gOD_table = NULL; +AsnTypetoMatchingRuleTable* gATMR_table = NULL; + +int +load_derived_matching_rule ( char* cfg_path ){ +} + +AttributeAliasing* +comp_is_aliased_attribute( void *in ) +{ + AttributeAliasing* curr_aa; + int i; + AttributeDescription *ad = (AttributeDescription*)in; + + for ( i = 0; aa_table[i].aa_aliasing_ad && i < MAX_ALIASING_ENTRY; i++ ) { + if ( strncmp(aa_table[i].aa_aliasing_ad->ad_cname.bv_val , ad->ad_cname.bv_val, ad->ad_cname.bv_len) == 0 ) + return &aa_table[i]; + } + return NULL; +} + +static int +add_aa_entry( int index, char* aliasing_at_name, char* aliased_at_name, char* mr_name, char* component_filter ) +{ + char text[1][128]; + int rc; + struct berval type; + + /* get and store aliasing AttributeDescription */ + type.bv_val = aliasing_at_name; + type.bv_len = strlen ( aliasing_at_name ); + rc = slap_bv2ad ( &type, &aa_table[index].aa_aliasing_ad,(const char**)text ); + if ( rc != LDAP_SUCCESS ) return rc; + + /* get and store aliased AttributeDescription */ + type.bv_val = aliased_at_name; + type.bv_len = strlen ( aliased_at_name ); + rc = slap_bv2ad ( &type, &aa_table[index].aa_aliased_ad,(const char**)text ); + if ( rc != LDAP_SUCCESS ) return rc; + + /* get and store componentFilterMatch */ + type.bv_val = mr_name; + type.bv_len = strlen ( mr_name); + aa_table[index].aa_mr = mr_bvfind ( &type ); + + /* get and store a component filter */ + type.bv_val = component_filter; + type.bv_len = strlen ( component_filter ); + rc = get_comp_filter( NULL, &type, &aa_table[index].aa_cf,(const char**)text); + + aa_table[index].aa_cf_str = component_filter; + + return rc; +} + +/* + * Initialize attribute aliasing table when this module is loaded + * add_aa_entry ( index for the global table, + * name of the aliasing attribute, + * component filter with filling value parts "xxx" + * ) + * "xxx" will be replaced with effective values later. + * See RFC3687 to understand the content of a component filter. + */ +char* pre_processed_comp_filter[] = { +/*1*/"item:{ component \"toBeSigned.issuer.rdnSequence\", rule distinguishedNameMatch, value xxx }", +/*2*/"item:{ component \"toBeSigned.serialNumber\", rule integerMatch, value xxx }", +/*3*/"and:{ item:{ component \"toBeSigned.serialNumber\", rule integerMatch, value xxx }, item:{ component \"toBeSigned.issuer.rdnSequence\", rule distinguishedNameMatch, value xxx } }" +}; + +static int +init_attribute_aliasing_table () +{ + int rc; + int index = 0 ; + + rc = add_aa_entry ( index, "x509CertificateIssuer", "userCertificate","componentFilterMatch", pre_processed_comp_filter[index] ); + if ( rc != LDAP_SUCCESS ) return LDAP_PARAM_ERROR; + index++; + + rc = add_aa_entry ( index, "x509CertificateSerial","userCertificate", "componentFilterMatch", pre_processed_comp_filter[index] ); + if ( rc != LDAP_SUCCESS ) return LDAP_PARAM_ERROR; + index++; + + rc = add_aa_entry ( index, "x509CertificateSerialAndIssuer", "userCertificate", "componentFilterMatch", pre_processed_comp_filter[index] ); + if ( rc != LDAP_SUCCESS ) return LDAP_PARAM_ERROR; + index++; + + return LDAP_SUCCESS; +} + +void +init_component_description_table () { + AsnTypeId id; + struct berval mr; + AsnTypetoSyntax* asn_to_syn; + Syntax* syn; + + for ( id = BASICTYPE_BOOLEAN; id != ASNTYPE_END ; id++ ) { + asntype_to_compType_mapping_tbl[id].ac_comp_type.ct_subtypes = NULL; + asntype_to_compType_mapping_tbl[id].ac_comp_type.ct_syntax = NULL; + + /* Equality Matching Rule */ + if ( asntype_to_compMR_mapping_tbl[id].atc_equality ) { + mr.bv_val = asntype_to_compMR_mapping_tbl[id].atc_equality; + mr.bv_len = strlen(asntype_to_compMR_mapping_tbl[id].atc_equality); + asntype_to_compType_mapping_tbl[id].ac_comp_type.ct_equality = mr_bvfind( &mr ); + } + /* Approx Matching Rule */ + if ( asntype_to_compMR_mapping_tbl[id].atc_approx ) { + mr.bv_val = asntype_to_compMR_mapping_tbl[id].atc_approx; + mr.bv_len = strlen(asntype_to_compMR_mapping_tbl[id].atc_approx); + asntype_to_compType_mapping_tbl[id].ac_comp_type.ct_approx = mr_bvfind( &mr ); + } + + /* Ordering Matching Rule */ + if ( asntype_to_compMR_mapping_tbl[id].atc_ordering ) { + mr.bv_val = asntype_to_compMR_mapping_tbl[id].atc_ordering; + mr.bv_len = strlen(asntype_to_compMR_mapping_tbl[id].atc_ordering); + asntype_to_compType_mapping_tbl[id].ac_comp_type.ct_ordering= mr_bvfind( &mr ); + } + + /* Substr Matching Rule */ + if ( asntype_to_compMR_mapping_tbl[id].atc_substr ) { + mr.bv_val = asntype_to_compMR_mapping_tbl[id].atc_substr; + mr.bv_len = strlen(asntype_to_compMR_mapping_tbl[id].atc_substr); + asntype_to_compType_mapping_tbl[id].ac_comp_type.ct_substr = mr_bvfind( &mr ); + } + /* Syntax */ + + asn_to_syn = &asn_to_syntax_mapping_tbl[ id ]; + if ( asn_to_syn->ats_syn_oid ) + syn = syn_find ( asn_to_syn->ats_syn_oid ); + else + syn = NULL; + asntype_to_compType_mapping_tbl[id].ac_comp_type.ct_syntax = syn; + + /* Initialize Component Descriptions of primitive ASN.1 types */ + asntype_to_compdesc_mapping_tbl[id].atcd_cd.cd_comp_type = (AttributeType*)&asntype_to_compType_mapping_tbl[id].ac_comp_type; + } +} + +MatchingRule* +retrieve_matching_rule( char* mr_oid, AsnTypeId type ) { + char* tmp; + struct berval mr_name = BER_BVNULL; + AsnTypetoMatchingRuleTable* atmr; + + for ( atmr = gATMR_table ; atmr ; atmr = atmr->atmr_table_next ) { + if ( strcmp( atmr->atmr_oid, mr_oid ) == 0 ) { + tmp = atmr->atmr_table[type].atmr_mr_name; + if ( tmp ) { + mr_name.bv_val = tmp; + mr_name.bv_len = strlen( tmp ); + return mr_bvfind ( &mr_name ); + } + } + } + return (MatchingRule*)NULL; +} + +void* +comp_convert_attr_to_comp LDAP_P (( Attribute* a, Syntax *syn, struct berval* bv )) +{ + char* peek_head; + int mode, bytesDecoded, size, rc; + void* component; + char* oid = a->a_desc->ad_type->sat_atype.at_oid ; + GenBuf* b = NULL; + ExpBuf* buf = NULL; + OidDecoderMapping* odm; + + /* look for the decoder registered for the given attribute */ + odm = RetrieveOidDecoderMappingbyOid( oid, strlen(oid) ); + + if ( !odm || (!odm->BER_Decode && !odm->GSER_Decode) ) + return (void*)NULL; + + buf = ExpBufAllocBuf(); + ExpBuftoGenBuf( buf, &b ); + ExpBufInstallDataInBuf ( buf, bv->bv_val, bv->bv_len ); + BufResetInReadMode( b ); + + mode = DEC_ALLOC_MODE_2; + /* + * How can we decide which decoder will be called, GSER or BER? + * Currently BER decoder is called for a certificate. + * The flag of Attribute will say something about it in the future + */ + if ( syn && slap_syntax_is_ber ( syn ) ) { +#if 0 + rc =BDecComponentTop(odm->BER_Decode, a->a_comp_data->cd_mem_op, b, 0,0, &component,&bytesDecoded,mode ) ; +#endif + rc = odm->BER_Decode ( a->a_comp_data->cd_mem_op, b, (ComponentSyntaxInfo*)&component, &bytesDecoded, mode ); + } + else { + rc = odm->GSER_Decode( a->a_comp_data->cd_mem_op, b, (ComponentSyntaxInfo**)component, &bytesDecoded, mode); + } + + ExpBufFreeBuf( buf ); + GenBufFreeBuf( b ); + if ( rc == -1 ) { +#if 0 + ShutdownNibbleMemLocal ( a->a_comp_data->cd_mem_op ); + free ( a->a_comp_data ); + a->a_comp_data = NULL; +#endif + return (void*)NULL; + } + else { + return component; + } +} + +#include <nibble-alloc.h> +void +comp_free_component ( void* mem_op ) { + ShutdownNibbleMemLocal( (NibbleMem*)mem_op ); + return; +} + +void +comp_convert_assert_to_comp ( + void* mem_op, + ComponentSyntaxInfo *csi_attr, + struct berval* bv, + ComponentSyntaxInfo** csi, int* len, int mode ) +{ + int rc; + GenBuf* genBuf; + ExpBuf* buf; + gser_decoder_func *decoder = csi_attr->csi_comp_desc->cd_gser_decoder; + + buf = ExpBufAllocBuf(); + ExpBuftoGenBuf( buf, &genBuf ); + ExpBufInstallDataInBuf ( buf, bv->bv_val, bv->bv_len ); + BufResetInReadMode( genBuf ); + + if ( csi_attr->csi_comp_desc->cd_type_id == BASICTYPE_ANY ) + decoder = ((ComponentAny*)csi_attr)->cai->GSER_Decode; + + rc = (*decoder)( mem_op, genBuf, csi, len, mode ); + ExpBufFreeBuf ( buf ); + GenBufFreeBuf( genBuf ); +} + +int intToAscii( int value, char* buf ) { + int minus=0,i,temp; + int total_num_digits; + + if ( value == 0 ){ + buf[0] = '0'; + return 1; + } + + if ( value < 0 ){ + minus = 1; + value = value*(-1); + buf[0] = '-'; + } + + /* How many digits */ + for ( temp = value, total_num_digits=0 ; temp ; total_num_digits++ ) + temp = temp/10; + + total_num_digits += minus; + + for ( i = minus ; value ; i++ ) { + buf[ total_num_digits - i - 1 ]= (char)(value%10 + '0'); + value = value/10; + } + return i; +} + +int +comp_convert_asn_to_ldap ( MatchingRule* mr, ComponentSyntaxInfo* csi, struct berval* bv, int *allocated ) +{ + int rc; + struct berval prettied; + Syntax* syn; + + AsnTypetoSyntax* asn_to_syn = + &asn_to_syntax_mapping_tbl[csi->csi_comp_desc->cd_type_id]; + if ( asn_to_syn->ats_syn_oid ) + csi->csi_syntax = syn_find ( asn_to_syn->ats_syn_oid ); + else + csi->csi_syntax = NULL; + + + switch ( csi->csi_comp_desc->cd_type_id ) { + case BASICTYPE_BOOLEAN : + bv->bv_val = (char*)malloc( 5 ); + *allocated = 1; + bv->bv_len = 5; + if ( ((ComponentBool*)csi)->value > 0 ) { + strcpy ( bv->bv_val , "TRUE" ); + bv->bv_len = 4; + } + else { + strcpy ( bv->bv_val , "FALSE" ); + bv->bv_len = 5; + } + break ; + case BASICTYPE_NULL : + bv->bv_len = 0; + break; + case BASICTYPE_INTEGER : + bv->bv_val = (char*)malloc( INITIAL_ATTR_SIZE ); + *allocated = 1; + bv->bv_len = INITIAL_ATTR_SIZE; + bv->bv_len = intToAscii(((ComponentInt*)csi)->value, bv->bv_val ); + if ( bv->bv_len <= 0 ) + return LDAP_INVALID_SYNTAX; + break; + case BASICTYPE_REAL : + return LDAP_INVALID_SYNTAX; + case BASICTYPE_ENUMERATED : + bv->bv_val = (char*)malloc( INITIAL_ATTR_SIZE ); + *allocated = 1; + bv->bv_len = INITIAL_ATTR_SIZE; + bv->bv_len = intToAscii(((ComponentEnum*)csi)->value, bv->bv_val ); + if ( bv->bv_len <= 0 ) + return LDAP_INVALID_SYNTAX; + break; + case BASICTYPE_OID : + case BASICTYPE_OCTETSTRING : + case BASICTYPE_BITSTRING : + case BASICTYPE_NUMERIC_STR : + case BASICTYPE_PRINTABLE_STR : + case BASICTYPE_UNIVERSAL_STR : + case BASICTYPE_IA5_STR : + case BASICTYPE_BMP_STR : + case BASICTYPE_UTF8_STR : + case BASICTYPE_UTCTIME : + case BASICTYPE_GENERALIZEDTIME : + case BASICTYPE_GRAPHIC_STR : + case BASICTYPE_VISIBLE_STR : + case BASICTYPE_GENERAL_STR : + case BASICTYPE_OBJECTDESCRIPTOR : + case BASICTYPE_VIDEOTEX_STR : + case BASICTYPE_T61_STR : + case BASICTYPE_OCTETCONTAINING : + case BASICTYPE_BITCONTAINING : + case BASICTYPE_RELATIVE_OID : + bv->bv_val = ((ComponentOcts*)csi)->value.octs; + bv->bv_len = ((ComponentOcts*)csi)->value.octetLen; + break; + case BASICTYPE_ANY : + csi = ((ComponentAny*)csi)->value; + if ( csi->csi_comp_desc->cd_type != ASN_BASIC || + csi->csi_comp_desc->cd_type_id == BASICTYPE_ANY ) + return LDAP_INVALID_SYNTAX; + return comp_convert_asn_to_ldap( mr, csi, bv, allocated ); + case COMPOSITE_ASN1_TYPE : + break; + case RDNSequence : + /*dnMatch*/ + if( strncmp( mr->smr_mrule.mr_oid, DN_MATCH_OID, strlen(DN_MATCH_OID) ) != 0 ) + return LDAP_INVALID_SYNTAX; + *allocated = 1; + rc = ConvertRDNSequence2RFC2253( (irRDNSequence*)csi, bv ); + if ( rc != LDAP_SUCCESS ) return rc; + break; + case RelativeDistinguishedName : + /*rdnMatch*/ + if( strncmp( mr->smr_mrule.mr_oid, RDN_MATCH_OID, strlen(RDN_MATCH_OID) ) != 0 ) + return LDAP_INVALID_SYNTAX; + *allocated = 1; + rc = ConvertRDN2RFC2253((irRelativeDistinguishedName*)csi,bv); + if ( rc != LDAP_SUCCESS ) return rc; + break; + case TelephoneNumber : + case FacsimileTelephoneNumber__telephoneNumber : + break; + case DirectoryString : + return LDAP_INVALID_SYNTAX; + case ASN_COMP_CERTIFICATE : + case ASNTYPE_END : + break; + default : + /*Only ASN Basic Type can be converted into LDAP string*/ + return LDAP_INVALID_SYNTAX; + } + + if ( csi->csi_syntax ) { + if ( csi->csi_syntax->ssyn_validate ) { + rc = csi->csi_syntax->ssyn_validate(csi->csi_syntax, bv); + if ( rc != LDAP_SUCCESS ) + return LDAP_INVALID_SYNTAX; + } + if ( csi->csi_syntax->ssyn_pretty ) { + rc = csi->csi_syntax->ssyn_pretty(csi->csi_syntax, bv, &prettied , NULL ); + if ( rc != LDAP_SUCCESS ) + return LDAP_INVALID_SYNTAX; +#if 0 + free ( bv->bv_val );/*potential memory leak?*/ +#endif + bv->bv_val = prettied.bv_val; + bv->bv_len = prettied.bv_len; + } + } + + return LDAP_SUCCESS; +} + +/* + * If <all> type component referenced is used + * more than one component will be tested + */ +#define IS_TERMINAL_COMPREF(cr) (cr->cr_curr->ci_next == NULL) +int +comp_test_all_components ( + void* attr_mem_op, + void* assert_mem_op, + ComponentSyntaxInfo *csi_attr, + ComponentAssertion* ca ) +{ + int rc; + ComponentSyntaxInfo *csi_temp = NULL, *csi_assert = NULL, *comp_elmt = NULL; + ComponentReference *cr = ca->ca_comp_ref; + struct berval *ca_val = &ca->ca_ma_value; + + switch ( cr->cr_curr->ci_type ) { + case LDAP_COMPREF_ALL: + if ( IS_TERMINAL_COMPREF(cr) ) { + FOR_EACH_LIST_ELMT( comp_elmt, &((ComponentList*)csi_attr)->comp_list ) + { + rc = comp_test_one_component( attr_mem_op, assert_mem_op, comp_elmt, ca ); + if ( rc == LDAP_COMPARE_TRUE ) { + break; + } + } + } else { + ComponentId *start_compid = ca->ca_comp_ref->cr_curr->ci_next; + FOR_EACH_LIST_ELMT( comp_elmt, &((ComponentList*)csi_attr)->comp_list ) + { + cr->cr_curr = start_compid; + rc = comp_test_components ( attr_mem_op, assert_mem_op, comp_elmt, ca ); + if ( rc != LDAP_COMPARE_FALSE ) { + break; + } +#if 0 + if ( rc == LDAP_COMPARE_TRUE ) { + break; + } +#endif + } + } + break; + case LDAP_COMPREF_CONTENT: + case LDAP_COMPREF_SELECT: + case LDAP_COMPREF_DEFINED: + case LDAP_COMPREF_UNDEFINED: + case LDAP_COMPREF_IDENTIFIER: + case LDAP_COMPREF_FROM_BEGINNING: + case LDAP_COMPREF_FROM_END: + case LDAP_COMPREF_COUNT: + rc = LDAP_OPERATIONS_ERROR; + break; + default: + rc = LDAP_OPERATIONS_ERROR; + } + return rc; +} + +void +eat_bv_whsp ( struct berval* in ) +{ + char* end = in->bv_val + in->bv_len; + for ( ; ( *in->bv_val == ' ' ) && ( in->bv_val < end ) ; ) { + in->bv_val++; + } +} + +/* + * Perform matching one referenced component against assertion + * If the matching rule in a component filter is allComponentsMatch + * or its derivatives the extracted component's ASN.1 specification + * is applied to the assertion value as its syntax + * Otherwise, the matching rule's syntax is applied to the assertion value + * By RFC 3687 + */ +int +comp_test_one_component ( + void* attr_mem_op, + void* assert_mem_op, + ComponentSyntaxInfo *csi_attr, + ComponentAssertion *ca ) +{ + int len, rc; + ComponentSyntaxInfo *csi_assert = NULL; + char* oid = NULL; + MatchingRule* mr = ca->ca_ma_rule; + + if ( mr->smr_usage & SLAP_MR_COMPONENT ) { + /* If allComponentsMatch or its derivatives */ + if ( !ca->ca_comp_data.cd_tree ) { + comp_convert_assert_to_comp( assert_mem_op, csi_attr, &ca->ca_ma_value, &csi_assert, &len, DEC_ALLOC_MODE_0 ); + ca->ca_comp_data.cd_tree = (void*)csi_assert; + } else { + csi_assert = ca->ca_comp_data.cd_tree; + } + + if ( !csi_assert ) + return LDAP_PROTOCOL_ERROR; + + if ( strcmp( mr->smr_mrule.mr_oid, OID_ALL_COMP_MATCH ) != 0 ) + { + /* allComponentMatch's derivatives */ + oid = mr->smr_mrule.mr_oid; + } + return csi_attr->csi_comp_desc->cd_all_match( + oid, csi_attr, csi_assert ); + + } else { + /* LDAP existing matching rules */ + struct berval attr_bv = BER_BVNULL; + struct berval n_attr_bv = BER_BVNULL; + struct berval* assert_bv = &ca->ca_ma_value; + int allocated = 0; + /*Attribute is converted to compatible LDAP encodings*/ + if ( comp_convert_asn_to_ldap( mr, csi_attr, &attr_bv, &allocated ) != LDAP_SUCCESS ) + return LDAP_INAPPROPRIATE_MATCHING; + /* extracted component value is not normalized */ + if ( ca->ca_ma_rule->smr_normalize ) { + rc = ca->ca_ma_rule->smr_normalize ( + SLAP_MR_VALUE_OF_ASSERTION_SYNTAX, + NULL, ca->ca_ma_rule, + &attr_bv, &n_attr_bv, NULL ); + if ( rc != LDAP_SUCCESS ) + return rc; + if ( allocated && attr_bv.bv_val ) + free (attr_bv.bv_val); + } else { + n_attr_bv = attr_bv; + } +#if 0 + /*Assertion value is validated by MR's syntax*/ + if ( !ca->ca_comp_data.cd_tree ) { + ca->ca_comp_data.cd_tree = assert_bv; + } + else { + assert_bv = ca->ca_comp_data.cd_tree; + } +#endif + if ( !n_attr_bv.bv_val ) + return LDAP_COMPARE_FALSE; + rc = csi_value_match( mr, &n_attr_bv, assert_bv ); + if ( n_attr_bv.bv_val ) + free ( n_attr_bv.bv_val ); + return rc; + } +} + +int +comp_test_components( void* attr_nm, void* assert_nm, ComponentSyntaxInfo* csi_attr, ComponentAssertion* ca) { + char* peek_head; + int mode, bytesDecoded = 0, rc; + GenBuf* b; + ExpBuf* buf; + OidDecoderMapping* odm; + struct berval bv; + char oid[MAX_OID_LEN]; + void* contained_comp, *anytype_comp; + ComponentReference* cr = ca->ca_comp_ref; + + if ( !cr ) + return comp_test_one_component ( attr_nm, assert_nm, csi_attr, ca ); + /* Extracting the component refrenced by ca->ca_comp_ref */ + csi_attr = (ComponentSyntaxInfo*)csi_attr->csi_comp_desc->cd_extract_i( attr_nm, cr, csi_attr ); + if ( !csi_attr ) return LDAP_INVALID_SYNTAX; + /* perform matching, considering the type of a Component Reference(CR)*/ + switch( cr->cr_curr->ci_type ) { + case LDAP_COMPREF_IDENTIFIER: + case LDAP_COMPREF_FROM_BEGINNING: + case LDAP_COMPREF_FROM_END: + case LDAP_COMPREF_COUNT: + /* + * Exactly one component is referenced + * Fast Path for matching for this case + */ + rc = comp_test_one_component ( attr_nm, assert_nm, csi_attr, ca ); + break; + case LDAP_COMPREF_ALL: + /* + * If <all> type CR is used + * more than one component will be tested + */ + rc = comp_test_all_components ( attr_nm, assert_nm, csi_attr, ca ); + break; + + case LDAP_COMPREF_CONTENT: + /* + * <content> type CR is used + * check if it is followed by <select> type CR. + * 1) If so, look up the corresponding decoder in the mapping + * table(OID to decoder) by <select> + * and then decode the OCTET/BIT STRING with the decoder + * Finially, extreact the target component with the remaining CR. + * 2) If not, just return the current component, It SHOULD not be + * extracted further, because the component MUST be BIT/OCTET + * string. + */ + + cr->cr_curr = cr->cr_curr->ci_next; + if ( !cr->cr_curr ) { + /* case 2) in above description */ + rc = comp_test_one_component ( attr_nm, assert_nm, csi_attr, ca ); + break; + } + + if ( cr->cr_curr->ci_type == LDAP_COMPREF_SELECT ) { + /* Look up OID mapping table */ + odm = RetrieveOidDecoderMappingbyBV( &cr->cr_curr->ci_val.ci_select_value ); + + if ( !odm || !odm->BER_Decode ) + return LDAP_PROTOCOL_ERROR; + + /* current componet MUST be either BIT or OCTET STRING */ + if ( csi_attr->csi_comp_desc->cd_type_id != BASICTYPE_BITSTRING ) { + bv.bv_val = ((ComponentBits*)csi_attr)->value.bits; + bv.bv_len = ((ComponentBits*)csi_attr)->value.bitLen; + } + else if ( csi_attr->csi_comp_desc->cd_type_id != BASICTYPE_BITSTRING ) { + bv.bv_val = ((ComponentOcts*)csi_attr)->value.octs; + bv.bv_len = ((ComponentOcts*)csi_attr)->value.octetLen; + } + else + return LDAP_PROTOCOL_ERROR; + + buf = ExpBufAllocBuf(); + ExpBuftoGenBuf( buf, &b ); + ExpBufInstallDataInBuf ( buf, bv.bv_val, bv.bv_len ); + BufResetInReadMode( b ); + mode = DEC_ALLOC_MODE_2; + + /* Try to decode with BER/DER decoder */ + rc = odm->BER_Decode ( attr_nm, b, (ComponentSyntaxInfo*)&contained_comp, &bytesDecoded, mode ); + + ExpBufFreeBuf( buf ); + GenBufFreeBuf( b ); + + if ( rc != LDAP_SUCCESS ) return LDAP_PROTOCOL_ERROR; + + /* xxx.content.(x.xy.xyz).rfc822Name */ + /* In the aboe Ex. move CR to the right to (x.xy.xyz)*/ + cr->cr_curr = cr->cr_curr->ci_next; + if (!cr->cr_curr ) + rc = comp_test_one_component ( attr_nm, assert_nm, csi_attr, ca ); + else + rc = comp_test_components( attr_nm, assert_nm, contained_comp, ca ); + } + else { + /* Ivalid Component reference */ + rc = LDAP_PROTOCOL_ERROR; + } + break; + case LDAP_COMPREF_SELECT: + if (csi_attr->csi_comp_desc->cd_type_id != BASICTYPE_ANY ) + return LDAP_INVALID_SYNTAX; + rc = CheckSelectTypeCorrect( attr_nm, ((ComponentAny*)csi_attr)->cai, &cr->cr_curr->ci_val.ci_select_value ); + if ( rc < 0 ) return LDAP_INVALID_SYNTAX; + + /* point to the real component, not any type component */ + csi_attr = ((ComponentAny*)csi_attr)->value; + cr->cr_curr = cr->cr_curr->ci_next; + if ( cr->cr_curr ) + rc = comp_test_components( attr_nm, assert_nm, csi_attr, ca); + else + rc = comp_test_one_component( attr_nm, assert_nm, csi_attr, ca); + break; + default: + rc = LDAP_INVALID_SYNTAX; + } + return rc; +} + + +void* +comp_nibble_memory_allocator ( int init_mem, int inc_mem ) { + void* nm; + nm = (void*)InitNibbleMemLocal( (unsigned long)init_mem, (unsigned long)inc_mem ); + if ( !nm ) return NULL; + else return (void*)nm; +} + +void +comp_nibble_memory_free ( void* nm ) { + ShutdownNibbleMemLocal( nm ); +} + +void* +comp_get_component_description ( int id ) { + if ( asntype_to_compdesc_mapping_tbl[id].atcd_typeId == id ) + return &asntype_to_compdesc_mapping_tbl[id].atcd_cd; + else + return NULL; +} + +int +comp_component_encoder ( void* mem_op, ComponentSyntaxInfo* csi , struct berval* nval ) { + int size, rc; + GenBuf* b; + ExpBuf* buf; + struct berval bv; + + buf = ExpBufAllocBufAndData(); + ExpBufResetInWriteRvsMode(buf); + ExpBuftoGenBuf( buf, &b ); + + if ( !csi->csi_comp_desc->cd_gser_encoder && !csi->csi_comp_desc->cd_ldap_encoder ) + return (-1); + + /* + * if an LDAP specific encoder is provided : + * dn and rdn have their LDAP specific encoder + */ + if ( csi->csi_comp_desc->cd_ldap_encoder ) { + rc = csi->csi_comp_desc->cd_ldap_encoder( csi, &bv ); + if ( rc != LDAP_SUCCESS ) + return rc; + if ( mem_op ) + nval->bv_val = CompAlloc( mem_op, bv.bv_len ); + else + nval->bv_val = malloc( size ); + memcpy( nval->bv_val, bv.bv_val, bv.bv_len ); + nval->bv_len = bv.bv_len; + /* + * This free will be eliminated by making ldap_encoder + * use nibble memory in it + */ + free ( bv.bv_val ); + GenBufFreeBuf( b ); + BufFreeBuf( buf ); + return LDAP_SUCCESS; + } + + rc = csi->csi_comp_desc->cd_gser_encoder( b, csi ); + if ( rc < 0 ) { + GenBufFreeBuf( b ); + BufFreeBuf( buf ); + return rc; + } + + size = ExpBufDataSize( buf ); + if ( size > 0 ) { + if ( mem_op ) + nval->bv_val = CompAlloc ( mem_op, size ); + else + nval->bv_val = malloc( size ); + nval->bv_len = size; + BufResetInReadMode(b); + BufCopy( nval->bv_val, b, size ); + } + ExpBufFreeBuf( buf ); + GenBufFreeBuf( b ); + + return LDAP_SUCCESS; +} + +#if SLAPD_COMP_MATCH == SLAPD_MOD_DYNAMIC + +#include "certificate.h" + +extern convert_attr_to_comp_func* attr_converter; +extern convert_assert_to_comp_func* assert_converter; +extern convert_asn_to_ldap_func* csi_converter; +extern free_component_func* component_destructor; +extern test_component_func* test_components; +extern alloc_nibble_func* nibble_mem_allocator; +extern free_nibble_func* nibble_mem_free; +extern test_membership_func* is_aliased_attribute; +extern get_component_info_func* get_component_description; +extern component_encoder_func* component_encoder; + + +int init_module(int argc, char *argv[]) { + /* + * Initialize function pointers in slapd + */ + attr_converter = (convert_attr_to_comp_func*)comp_convert_attr_to_comp; + assert_converter = (convert_assert_to_comp_func*)comp_convert_assert_to_comp; + component_destructor = (free_component_func*)comp_free_component; + test_components = (test_component_func*)comp_test_components; + nibble_mem_allocator = (free_nibble_func*)comp_nibble_memory_allocator; + nibble_mem_free = (free_nibble_func*)comp_nibble_memory_free; + is_aliased_attribute = (test_membership_func*)comp_is_aliased_attribute; + get_component_description = (get_component_info_func*)comp_get_component_description; + component_encoder = (component_encoder_func*)comp_component_encoder; + + /* file path needs to be */ + load_derived_matching_rule ("derived_mr.cfg"); + + /* the initialization for example X.509 certificate */ + init_module_AuthenticationFramework(); + init_module_AuthorityKeyIdentifierDefinition(); + init_module_CertificateRevokationList(); + init_attribute_aliasing_table (); + init_component_description_table (); + return 0; +} + +#endif /* SLAPD_PASSWD */ diff --git a/contrib/slapd-modules/denyop/Makefile b/contrib/slapd-modules/denyop/Makefile new file mode 100644 index 0000000..c837762 --- /dev/null +++ b/contrib/slapd-modules/denyop/Makefile @@ -0,0 +1,46 @@ +# $OpenLDAP$ + +LDAP_SRC = ../../.. +LDAP_BUILD = $(LDAP_SRC) +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +CC = gcc +OPT = -g -O2 -Wall +DEFS = -DSLAPD_OVER_DENYOP=SLAPD_MOD_DYNAMIC +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) + +PROGRAMS = denyop.la +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +denyop.la: denyop.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + diff --git a/contrib/slapd-modules/denyop/denyop.c b/contrib/slapd-modules/denyop/denyop.c new file mode 100644 index 0000000..d75a0aa --- /dev/null +++ b/contrib/slapd-modules/denyop/denyop.c @@ -0,0 +1,259 @@ +/* denyop.c - Denies operations */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2004-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by Pierangelo Masarati for inclusion in + * OpenLDAP Software. + */ + +#include "portable.h" + +#ifdef SLAPD_OVER_DENYOP + +#include <stdio.h> + +#include <ac/string.h> +#include <ac/socket.h> + +#include "slap.h" + +/* This overlay provides a quick'n'easy way to deny selected operations + * for a database whose backend implements the operations. It is intended + * to be less expensive than ACLs because its evaluation occurs before + * any backend specific operation is actually even initiated. + */ + +enum { + denyop_add = 0, + denyop_bind, + denyop_compare, + denyop_delete, + denyop_extended, + denyop_modify, + denyop_modrdn, + denyop_search, + denyop_unbind +} denyop_e; + +typedef struct denyop_info { + int do_op[denyop_unbind + 1]; +} denyop_info; + +static int +denyop_func( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; + denyop_info *oi = (denyop_info *)on->on_bi.bi_private; + int deny = 0; + + switch( op->o_tag ) { + case LDAP_REQ_BIND: + deny = oi->do_op[denyop_bind]; + break; + + case LDAP_REQ_ADD: + deny = oi->do_op[denyop_add]; + break; + + case LDAP_REQ_DELETE: + deny = oi->do_op[denyop_delete]; + break; + + case LDAP_REQ_MODRDN: + deny = oi->do_op[denyop_modrdn]; + break; + + case LDAP_REQ_MODIFY: + deny = oi->do_op[denyop_modify]; + break; + + case LDAP_REQ_COMPARE: + deny = oi->do_op[denyop_compare]; + break; + + case LDAP_REQ_SEARCH: + deny = oi->do_op[denyop_search]; + break; + + case LDAP_REQ_EXTENDED: + deny = oi->do_op[denyop_extended]; + break; + + case LDAP_REQ_UNBIND: + deny = oi->do_op[denyop_unbind]; + break; + } + + if ( !deny ) { + return SLAP_CB_CONTINUE; + } + + op->o_bd->bd_info = (BackendInfo *)on->on_info; + send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, + "operation not allowed within namingContext" ); + + return 0; +} + +static int +denyop_over_init( + BackendDB *be, ConfigReply *cr +) +{ + slap_overinst *on = (slap_overinst *) be->bd_info; + denyop_info *oi; + + oi = (denyop_info *)ch_malloc(sizeof(denyop_info)); + memset(oi, 0, sizeof(denyop_info)); + on->on_bi.bi_private = oi; + + return 0; +} + +static int +denyop_config( + BackendDB *be, + const char *fname, + int lineno, + int argc, + char **argv +) +{ + slap_overinst *on = (slap_overinst *) be->bd_info; + denyop_info *oi = (denyop_info *)on->on_bi.bi_private; + + if ( strcasecmp( argv[0], "denyop" ) == 0 ) { + char *op; + + if ( argc != 2 ) { + Debug( LDAP_DEBUG_ANY, "%s: line %d: " + "operation list missing in " + "\"denyop <op-list>\" line.\n", + fname, lineno, 0 ); + return( 1 ); + } + + /* The on->on_bi.bi_private pointer can be used for + * anything this instance of the overlay needs. + */ + + op = argv[1]; + do { + char *next = strchr( op, ',' ); + + if ( next ) { + next[0] = '\0'; + next++; + } + + if ( strcmp( op, "add" ) == 0 ) { + oi->do_op[denyop_add] = 1; + + } else if ( strcmp( op, "bind" ) == 0 ) { + oi->do_op[denyop_bind] = 1; + + } else if ( strcmp( op, "compare" ) == 0 ) { + oi->do_op[denyop_compare] = 1; + + } else if ( strcmp( op, "delete" ) == 0 ) { + oi->do_op[denyop_delete] = 1; + + } else if ( strcmp( op, "extended" ) == 0 ) { + oi->do_op[denyop_extended] = 1; + + } else if ( strcmp( op, "modify" ) == 0 ) { + oi->do_op[denyop_modify] = 1; + + } else if ( strcmp( op, "modrdn" ) == 0 ) { + oi->do_op[denyop_modrdn] = 1; + + } else if ( strcmp( op, "search" ) == 0 ) { + oi->do_op[denyop_search] = 1; + + } else if ( strcmp( op, "unbind" ) == 0 ) { + oi->do_op[denyop_unbind] = 1; + + } else { + Debug( LDAP_DEBUG_ANY, "%s: line %d: " + "unknown operation \"%s\" at " + "\"denyop <op-list>\" line.\n", + fname, lineno, op ); + return( 1 ); + } + + op = next; + } while ( op ); + + } else { + return SLAP_CONF_UNKNOWN; + } + return 0; +} + +static int +denyop_destroy( + BackendDB *be, ConfigReply *cr +) +{ + slap_overinst *on = (slap_overinst *) be->bd_info; + denyop_info *oi = (denyop_info *)on->on_bi.bi_private; + + if ( oi ) { + ch_free( oi ); + } + + return 0; +} + +/* This overlay is set up for dynamic loading via moduleload. For static + * configuration, you'll need to arrange for the slap_overinst to be + * initialized and registered by some other function inside slapd. + */ + +static slap_overinst denyop; + +int +denyop_initialize( void ) +{ + memset( &denyop, 0, sizeof( slap_overinst ) ); + denyop.on_bi.bi_type = "denyop"; + denyop.on_bi.bi_db_init = denyop_over_init; + denyop.on_bi.bi_db_config = denyop_config; + denyop.on_bi.bi_db_destroy = denyop_destroy; + + denyop.on_bi.bi_op_bind = denyop_func; + denyop.on_bi.bi_op_search = denyop_func; + denyop.on_bi.bi_op_compare = denyop_func; + denyop.on_bi.bi_op_modify = denyop_func; + denyop.on_bi.bi_op_modrdn = denyop_func; + denyop.on_bi.bi_op_add = denyop_func; + denyop.on_bi.bi_op_delete = denyop_func; + denyop.on_bi.bi_extended = denyop_func; + denyop.on_bi.bi_op_unbind = denyop_func; + + denyop.on_response = NULL /* denyop_response */ ; + + return overlay_register( &denyop ); +} + +#if SLAPD_OVER_DENYOP == SLAPD_MOD_DYNAMIC +int +init_module( int argc, char *argv[] ) +{ + return denyop_initialize(); +} +#endif /* SLAPD_OVER_DENYOP == SLAPD_MOD_DYNAMIC */ + +#endif /* defined(SLAPD_OVER_DENYOP) */ diff --git a/contrib/slapd-modules/dsaschema/Makefile b/contrib/slapd-modules/dsaschema/Makefile new file mode 100644 index 0000000..5ca4b4f --- /dev/null +++ b/contrib/slapd-modules/dsaschema/Makefile @@ -0,0 +1,46 @@ +# $OpenLDAP$ + +LDAP_SRC = ../../.. +LDAP_BUILD = $(LDAP_SRC) +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +CC = gcc +OPT = -g -O2 -Wall +DEFS = +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) + +PROGRAMS = dsaschema.la +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +dsaschema.la: dsaschema.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + diff --git a/contrib/slapd-modules/dsaschema/README b/contrib/slapd-modules/dsaschema/README new file mode 100644 index 0000000..f102bb9 --- /dev/null +++ b/contrib/slapd-modules/dsaschema/README @@ -0,0 +1,23 @@ +Copyright 2004-2021 The OpenLDAP Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted only as authorized by the OpenLDAP +Public License. + +This directory contains a native slapd plugin, dsaschema, that permits the +loading of DSA-specific schema from configuration files (including operational +attributes). + +To use the plugin, add: + +moduleload dsaschema.so + /etc/openldap/schema/foo1.schema + ...etc... + /etc/openldap/schema/fooN.schema + +to your slapd configuration file. + +Use Makefile to compile this plugin or use a command line similar to: + +gcc -shared -I../../../include -Wall -g -o dsaschema.so dsaschema.c + diff --git a/contrib/slapd-modules/dsaschema/dsaschema.c b/contrib/slapd-modules/dsaschema/dsaschema.c new file mode 100644 index 0000000..fa8d07c --- /dev/null +++ b/contrib/slapd-modules/dsaschema/dsaschema.c @@ -0,0 +1,438 @@ +/* dsaschema.c */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2004-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ + +#include <portable.h> + +#include <ac/string.h> +#include <ac/ctype.h> +#include <ac/signal.h> +#include <ac/errno.h> +#include <ac/stdlib.h> +#include <ac/ctype.h> +#include <ac/time.h> +#include <ac/unistd.h> + +#include <stdio.h> + +/* + * Schema reader that allows us to define DSA schema (including + * operational attributes and non-user object classes) + * + * A kludge, at best, and in order to avoid including slapd + * headers we use fprintf() rather than slapd's native logging, + * which may confuse users... + * + */ + +#include <ldap.h> +#include <ldap_schema.h> + +extern int at_add(LDAPAttributeType *at, const char **err); +extern int oc_add(LDAPObjectClass *oc, int user, const char **err); +extern int cr_add(LDAPContentRule *cr, int user, const char **err); + +#define ARGS_STEP 512 + +static char *fp_getline(FILE *fp, int *lineno); +static void fp_getline_init(int *lineno); +static int fp_parse_line(int lineno, char *line); +static char *strtok_quote( char *line, char *sep ); + +static char **cargv = NULL; +static int cargv_size = 0; +static int cargc = 0; +static char *strtok_quote_ptr; + +int init_module(int argc, char *argv[]); + +static int dsaschema_parse_at(const char *fname, int lineno, char *line, char **argv) +{ + LDAPAttributeType *at; + int code; + const char *err; + + at = ldap_str2attributetype(line, &code, &err, LDAP_SCHEMA_ALLOW_ALL); + if (!at) { + fprintf(stderr, "%s: line %d: %s before %s\n", + fname, lineno, ldap_scherr2str(code), err); + return 1; + } + + if (at->at_oid == NULL) { + fprintf(stderr, "%s: line %d: attributeType has no OID\n", + fname, lineno); + return 1; + } + + code = at_add(at, &err); + if (code) { + fprintf(stderr, "%s: line %d: %s: \"%s\"\n", + fname, lineno, ldap_scherr2str(code), err); + return 1; + } + + ldap_memfree(at); + + return 0; +} + +static int dsaschema_parse_oc(const char *fname, int lineno, char *line, char **argv) +{ + LDAPObjectClass *oc; + int code; + const char *err; + + oc = ldap_str2objectclass(line, &code, &err, LDAP_SCHEMA_ALLOW_ALL); + if (!oc) { + fprintf(stderr, "%s: line %d: %s before %s\n", + fname, lineno, ldap_scherr2str(code), err); + return 1; + } + + if (oc->oc_oid == NULL) { + fprintf(stderr, + "%s: line %d: objectclass has no OID\n", + fname, lineno); + return 1; + } + + code = oc_add(oc, 0, &err); + if (code) { + fprintf(stderr, "%s: line %d: %s: \"%s\"\n", + fname, lineno, ldap_scherr2str(code), err); + return 1; + } + + ldap_memfree(oc); + return 0; +} + +static int dsaschema_parse_cr(const char *fname, int lineno, char *line, char **argv) +{ + LDAPContentRule *cr; + int code; + const char *err; + + cr = ldap_str2contentrule(line, &code, &err, LDAP_SCHEMA_ALLOW_ALL); + if (!cr) { + fprintf(stderr, "%s: line %d: %s before %s\n", + fname, lineno, ldap_scherr2str(code), err); + return 1; + } + + if (cr->cr_oid == NULL) { + fprintf(stderr, + "%s: line %d: objectclass has no OID\n", + fname, lineno); + return 1; + } + + code = cr_add(cr, 0, &err); + if (code) { + fprintf(stderr, "%s: line %d: %s: \"%s\"\n", + fname, lineno, ldap_scherr2str(code), err); + return 1; + } + + ldap_memfree(cr); + return 0; +} + +static int dsaschema_read_config(const char *fname, int depth) +{ + FILE *fp; + char *line, *savefname, *saveline; + int savelineno, lineno; + int rc; + + if (depth == 0) { + cargv = calloc(ARGS_STEP + 1, sizeof(*cargv)); + if (cargv == NULL) { + return 1; + } + cargv_size = ARGS_STEP + 1; + } + + fp = fopen(fname, "r"); + if (fp == NULL) { + fprintf(stderr, "could not open config file \"%s\": %s (%d)\n", + fname, strerror(errno), errno); + return 1; + } + fp_getline_init(&lineno); + + while ((line = fp_getline(fp, &lineno)) != NULL) { + /* skip comments and blank lines */ + if (line[0] == '#' || line[0] == '\0') { + continue; + } + + saveline = strdup(line); + if (saveline == NULL) { + return 1; + } + + if (fp_parse_line(lineno, line) != 0) { + return 1; + } + + if (cargc < 1) { + continue; + } + + if (strcasecmp(cargv[0], "attributetype") == 0 || + strcasecmp(cargv[0], "attribute") == 0) { + if (cargc < 2) { + fprintf(stderr, "%s: line %d: illegal attribute type format\n", + fname, lineno); + return 1; + } else if (*cargv[1] == '(' /*')'*/) { + char *p; + + p = strchr(saveline, '(' /*')'*/); + rc = dsaschema_parse_at(fname, lineno, p, cargv); + if (rc != 0) + return rc; + } else { + fprintf(stderr, "%s: line %d: old attribute type format not supported\n", + fname, lineno); + } + } else if (strcasecmp(cargv[0], "ditcontentrule") == 0) { + char *p; + p = strchr(saveline, '(' /*')'*/); + rc = dsaschema_parse_cr(fname, lineno, p, cargv); + if (rc != 0) + return rc; + } else if (strcasecmp(cargv[0], "objectclass") == 0) { + if (cargc < 2) { + fprintf(stderr, "%s: line %d: illegal objectclass format\n", + fname, lineno); + return 1; + } else if (*cargv[1] == '(' /*')'*/) { + char *p; + + p = strchr(saveline, '(' /*')'*/); + rc = dsaschema_parse_oc(fname, lineno, p, cargv); + if (rc != 0) + return rc; + } else { + fprintf(stderr, "%s: line %d: object class format not supported\n", + fname, lineno); + } + } else if (strcasecmp(cargv[0], "include") == 0) { + if (cargc < 2) { + fprintf(stderr, "%s: line %d: missing file name in \"include <filename>\" line", + fname, lineno); + return 1; + } + savefname = strdup(cargv[1]); + if (savefname == NULL) { + return 1; + } + if (dsaschema_read_config(savefname, depth + 1) != 0) { + return 1; + } + free(savefname); + lineno = savelineno - 1; + } else { + fprintf(stderr, "%s: line %d: unknown directive \"%s\" (ignored)\n", + fname, lineno, cargv[0]); + } + } + + fclose(fp); + + if (depth == 0) + free(cargv); + + return 0; +} + +int init_module(int argc, char *argv[]) +{ + int i; + int rc; + + for (i = 0; i < argc; i++) { + rc = dsaschema_read_config(argv[i], 0); + if (rc != 0) { + break; + } + } + + return rc; +} + + +static int +fp_parse_line( + int lineno, + char *line +) +{ + char * token; + + cargc = 0; + token = strtok_quote( line, " \t" ); + + if ( strtok_quote_ptr ) { + *strtok_quote_ptr = ' '; + } + + if ( strtok_quote_ptr ) { + *strtok_quote_ptr = '\0'; + } + + for ( ; token != NULL; token = strtok_quote( NULL, " \t" ) ) { + if ( cargc == cargv_size - 1 ) { + char **tmp; + tmp = realloc( cargv, (cargv_size + ARGS_STEP) * + sizeof(*cargv) ); + if ( tmp == NULL ) { + return -1; + } + cargv = tmp; + cargv_size += ARGS_STEP; + } + cargv[cargc++] = token; + } + cargv[cargc] = NULL; + return 0; +} + +static char * +strtok_quote( char *line, char *sep ) +{ + int inquote; + char *tmp; + static char *next; + + strtok_quote_ptr = NULL; + if ( line != NULL ) { + next = line; + } + while ( *next && strchr( sep, *next ) ) { + next++; + } + + if ( *next == '\0' ) { + next = NULL; + return( NULL ); + } + tmp = next; + + for ( inquote = 0; *next; ) { + switch ( *next ) { + case '"': + if ( inquote ) { + inquote = 0; + } else { + inquote = 1; + } + AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 ); + break; + + case '\\': + if ( next[1] ) + AC_MEMCPY( next, + next + 1, strlen( next + 1 ) + 1 ); + next++; /* dont parse the escaped character */ + break; + + default: + if ( ! inquote ) { + if ( strchr( sep, *next ) != NULL ) { + strtok_quote_ptr = next; + *next++ = '\0'; + return( tmp ); + } + } + next++; + break; + } + } + + return( tmp ); +} + +static char buf[BUFSIZ]; +static char *line; +static size_t lmax, lcur; + +#define CATLINE( buf ) \ + do { \ + size_t len = strlen( buf ); \ + while ( lcur + len + 1 > lmax ) { \ + lmax += BUFSIZ; \ + line = (char *) realloc( line, lmax ); \ + } \ + strcpy( line + lcur, buf ); \ + lcur += len; \ + } while( 0 ) + +static char * +fp_getline( FILE *fp, int *lineno ) +{ + char *p; + + lcur = 0; + CATLINE( buf ); + (*lineno)++; + + /* hack attack - keeps us from having to keep a stack of bufs... */ + if ( strncasecmp( line, "include", 7 ) == 0 ) { + buf[0] = '\0'; + return( line ); + } + + while ( fgets( buf, sizeof(buf), fp ) != NULL ) { + /* trim off \r\n or \n */ + if ( (p = strchr( buf, '\n' )) != NULL ) { + if( p > buf && p[-1] == '\r' ) --p; + *p = '\0'; + } + + /* trim off trailing \ and append the next line */ + if ( line[ 0 ] != '\0' + && (p = line + strlen( line ) - 1)[ 0 ] == '\\' + && p[ -1 ] != '\\' ) { + p[ 0 ] = '\0'; + lcur--; + + } else { + if ( ! isspace( (unsigned char) buf[0] ) ) { + return( line ); + } + + /* change leading whitespace to a space */ + buf[0] = ' '; + } + + CATLINE( buf ); + (*lineno)++; + } + buf[0] = '\0'; + + return( line[0] ? line : NULL ); +} + +static void +fp_getline_init( int *lineno ) +{ + *lineno = -1; + buf[0] = '\0'; +} + diff --git a/contrib/slapd-modules/dupent/Makefile b/contrib/slapd-modules/dupent/Makefile new file mode 100644 index 0000000..b771015 --- /dev/null +++ b/contrib/slapd-modules/dupent/Makefile @@ -0,0 +1,58 @@ +# $OpenLDAP$ +# This work is part of OpenLDAP Software <http://www.openldap.org/>. +# +# Copyright 1998-2021 The OpenLDAP Foundation. +# Copyright 2004 Howard Chu, Symas Corp. All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted only as authorized by the OpenLDAP +# Public License. +# +# A copy of this license is available in the file LICENSE in the +# top-level directory of the distribution or, alternatively, at +# <http://www.OpenLDAP.org/license.html>. + +LDAP_SRC = ../../.. +LDAP_BUILD = $(LDAP_SRC) +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +CC = gcc +OPT = -g -O2 -Wall +DEFS = -DSLAPD_OVER_DUPENT=SLAPD_MOD_DYNAMIC +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) + +PROGRAMS = dupent.la +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +dupent.la: dupent.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + diff --git a/contrib/slapd-modules/dupent/dupent.c b/contrib/slapd-modules/dupent/dupent.c new file mode 100644 index 0000000..3c53c21 --- /dev/null +++ b/contrib/slapd-modules/dupent/dupent.c @@ -0,0 +1,557 @@ +/* dupent.c - LDAP Control for a Duplicate Entry Representation of Search Results */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2006-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by Pierangelo Masarati for inclusion + * in OpenLDAP Software. + */ + +/* + * LDAP Control for a Duplicate Entry Representation of Search Results + * <draft-ietf-ldapext-ldapv3-dupent-08.txt> (EXPIRED) + * <http://tools.ietf.org/id/draft-ietf-ldapext-ldapv3-dupent-08.txt> + */ + +#include "portable.h" + +/* define SLAPD_OVER_DUPENT=2 to build as run-time loadable module */ +#ifdef SLAPD_OVER_DUPENT + +/* + * The macros + * + * LDAP_CONTROL_DUPENT_REQUEST "2.16.840.1.113719.1.27.101.1" + * LDAP_CONTROL_DUPENT_RESPONSE "2.16.840.1.113719.1.27.101.2" + * LDAP_CONTROL_DUPENT_ENTRY "2.16.840.1.113719.1.27.101.3" + * + * are already defined in <ldap.h> + */ + +/* + * support for no attrs and "*" in AttributeDescriptionList is missing + */ + +#include "slap.h" +#include "ac/string.h" + +#define o_dupent o_ctrlflag[dupent_cid] +#define o_ctrldupent o_controls[dupent_cid] + +static int dupent_cid; +static slap_overinst dupent; + +typedef struct dupent_t { + AttributeName *ds_an; + ber_len_t ds_nattrs; + slap_mask_t ds_flags; + ber_int_t ds_paa; +} dupent_t; + +static int +dupent_parseCtrl ( + Operation *op, + SlapReply *rs, + LDAPControl *ctrl ) +{ + ber_tag_t tag; + BerElementBuffer berbuf; + BerElement *ber = (BerElement *)&berbuf; + ber_len_t len; + BerVarray AttributeDescriptionList = NULL; + ber_len_t cnt = sizeof(struct berval); + ber_len_t off = 0; + ber_int_t PartialApplicationAllowed = 1; + dupent_t *ds = NULL; + int i; + + if ( op->o_dupent != SLAP_CONTROL_NONE ) { + rs->sr_text = "Dupent control specified multiple times"; + return LDAP_PROTOCOL_ERROR; + } + + if ( BER_BVISNULL( &ctrl->ldctl_value ) ) { + rs->sr_text = "Dupent control value is absent"; + return LDAP_PROTOCOL_ERROR; + } + + if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) { + rs->sr_text = "Dupent control value is empty"; + return LDAP_PROTOCOL_ERROR; + } + + ber_init2( ber, &ctrl->ldctl_value, 0 ); + + /* + + DuplicateEntryRequest ::= SEQUENCE { + AttributeDescriptionList, -- from [RFC2251] + PartialApplicationAllowed BOOLEAN DEFAULT TRUE } + + AttributeDescriptionList ::= SEQUENCE OF + AttributeDescription + + AttributeDescription ::= LDAPString + + attributeDescription = AttributeType [ ";" <options> ] + + */ + + tag = ber_skip_tag( ber, &len ); + if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX; + if ( ber_scanf( ber, "{M}", &AttributeDescriptionList, &cnt, off ) + == LBER_ERROR ) + { + rs->sr_text = "Dupent control: dupentSpec decoding error"; + rs->sr_err = LDAP_PROTOCOL_ERROR; + goto done; + } + tag = ber_skip_tag( ber, &len ); + if ( tag == LBER_BOOLEAN ) { + /* NOTE: PartialApplicationAllowed is ignored, since the control + * can always be honored + */ + if ( ber_scanf( ber, "b", &PartialApplicationAllowed ) == LBER_ERROR ) + { + rs->sr_text = "Dupent control: dupentSpec decoding error"; + rs->sr_err = LDAP_PROTOCOL_ERROR; + goto done; + } + tag = ber_skip_tag( ber, &len ); + } + if ( len || tag != LBER_DEFAULT ) { + rs->sr_text = "Dupent control: dupentSpec decoding error"; + rs->sr_err = LDAP_PROTOCOL_ERROR; + goto done; + } + + ds = (dupent_t *)op->o_tmpcalloc( 1, + sizeof(dupent_t) + sizeof(AttributeName)*cnt, + op->o_tmpmemctx ); + + ds->ds_paa = PartialApplicationAllowed; + + if ( cnt == 0 ) { + ds->ds_flags |= SLAP_USERATTRS_YES; + + } else { + int c; + + ds->ds_an = (AttributeName *)&ds[ 1 ]; + + for ( i = 0, c = 0; i < cnt; i++ ) { + const char *text; + int j; + int rc; + AttributeDescription *ad = NULL; + + if ( bvmatch( &AttributeDescriptionList[i], + slap_bv_all_user_attrs ) ) + { + if ( ds->ds_flags & SLAP_USERATTRS_YES ) { + rs->sr_text = "Dupent control: AttributeDescription decoding error"; + rs->sr_err = LDAP_PROTOCOL_ERROR; + goto done; + } + + ds->ds_flags |= SLAP_USERATTRS_YES; + continue; + } + + rc = slap_bv2ad( &AttributeDescriptionList[i], &ad, &text ); + if ( rc != LDAP_SUCCESS ) { + continue; + } + + ds->ds_an[c].an_desc = ad; + ds->ds_an[c].an_name = ad->ad_cname; + + /* FIXME: not specified; consider this an error, just in case */ + for ( j = 0; j < c; j++ ) { + if ( ds->ds_an[c].an_desc == ds->ds_an[j].an_desc ) { + rs->sr_text = "Dupent control: AttributeDescription must be unique within AttributeDescriptionList"; + rs->sr_err = LDAP_PROTOCOL_ERROR; + goto done; + } + } + + c++; + } + + ds->ds_nattrs = c; + + if ( ds->ds_flags & SLAP_USERATTRS_YES ) { + /* purge user attrs */ + for ( i = 0; i < ds->ds_nattrs; ) { + if ( is_at_operational( ds->ds_an[i].an_desc->ad_type ) ) { + i++; + continue; + } + + ds->ds_nattrs--; + if ( i < ds->ds_nattrs ) { + ds->ds_an[i] = ds->ds_an[ds->ds_nattrs]; + } + } + } + } + + op->o_ctrldupent = (void *)ds; + + op->o_dupent = ctrl->ldctl_iscritical + ? SLAP_CONTROL_CRITICAL + : SLAP_CONTROL_NONCRITICAL; + + rs->sr_err = LDAP_SUCCESS; + +done:; + if ( rs->sr_err != LDAP_SUCCESS ) { + op->o_tmpfree( ds, op->o_tmpmemctx ); + } + + if ( AttributeDescriptionList != NULL ) { + ber_memfree_x( AttributeDescriptionList, op->o_tmpmemctx ); + } + + return rs->sr_err; +} + +typedef struct dupent_cb_t { + slap_overinst *dc_on; + dupent_t *dc_ds; + int dc_skip; +} dupent_cb_t; + +typedef struct valnum_t { + Attribute *ap; + Attribute a; + struct berval vals[2]; + struct berval nvals[2]; + int cnt; +} valnum_t; + +static int +dupent_response_done( Operation *op, SlapReply *rs ) +{ + BerElementBuffer berbuf; + BerElement *ber = (BerElement *) &berbuf; + struct berval ctrlval; + LDAPControl *ctrl, *ctrlsp[2]; + + ber_init2( ber, NULL, LBER_USE_DER ); + + /* + + DuplicateEntryResponseDone ::= SEQUENCE { + resultCode, -- From [RFC2251] + errorMessage [0] LDAPString OPTIONAL, + attribute [1] AttributeDescription OPTIONAL } + + */ + + ber_printf( ber, "{i}", rs->sr_err ); + if ( ber_flatten2( ber, &ctrlval, 0 ) == -1 ) { + ber_free_buf( ber ); + if ( op->o_dupent == SLAP_CONTROL_CRITICAL ) { + return LDAP_CONSTRAINT_VIOLATION; + } + return SLAP_CB_CONTINUE; + } + + ctrl = op->o_tmpcalloc( 1, + sizeof( LDAPControl ) + ctrlval.bv_len + 1, + op->o_tmpmemctx ); + ctrl->ldctl_value.bv_val = (char *)&ctrl[ 1 ]; + ctrl->ldctl_oid = LDAP_CONTROL_DUPENT_RESPONSE; + ctrl->ldctl_iscritical = 0; + ctrl->ldctl_value.bv_len = ctrlval.bv_len; + AC_MEMCPY( ctrl->ldctl_value.bv_val, ctrlval.bv_val, ctrlval.bv_len ); + ctrl->ldctl_value.bv_val[ ctrl->ldctl_value.bv_len ] = '\0'; + + ber_free_buf( ber ); + + ctrlsp[0] = ctrl; + ctrlsp[1] = NULL; + slap_add_ctrls( op, rs, ctrlsp ); + + return SLAP_CB_CONTINUE; +} + +static int +dupent_response_entry_1level( + Operation *op, + SlapReply *rs, + Entry *e, + valnum_t *valnum, + int nattrs, + int level ) +{ + int i, rc = LDAP_SUCCESS; + + for ( i = 0; i < valnum[level].ap->a_numvals; i++ ) { + LDAPControl *ctrl = NULL, *ctrlsp[2]; + + valnum[level].a.a_vals[0] = valnum[level].ap->a_vals[i]; + if ( valnum[level].ap->a_nvals != valnum[level].ap->a_vals ) { + valnum[level].a.a_nvals[0] = valnum[level].ap->a_nvals[i]; + } + + if ( level < nattrs - 1 ) { + rc = dupent_response_entry_1level( op, rs, + e, valnum, nattrs, level + 1 ); + if ( rc != LDAP_SUCCESS ) { + break; + } + + continue; + } + + /* NOTE: add the control all times, under the assumption + * send_search_entry() honors the REP_CTRLS_MUSTBEFREED + * set by slap_add_ctrls(); this is not true (ITS#6629) + */ + ctrl = op->o_tmpcalloc( 1, sizeof( LDAPControl ), op->o_tmpmemctx ); + ctrl->ldctl_oid = LDAP_CONTROL_DUPENT_ENTRY; + ctrl->ldctl_iscritical = 0; + + ctrlsp[0] = ctrl; + ctrlsp[1] = NULL; + slap_add_ctrls( op, rs, ctrlsp ); + + /* do the real send */ + rs->sr_entry = e; + rc = send_search_entry( op, rs ); + if ( rc != LDAP_SUCCESS ) { + break; + } + } + + return rc; +} + +static void +dupent_attr_prepare( dupent_t *ds, Entry *e, valnum_t *valnum, int nattrs, int c, Attribute **app, Attribute **ap_listp ) +{ + valnum[c].ap = *app; + *app = (*app)->a_next; + + valnum[c].ap->a_next = *ap_listp; + *ap_listp = valnum[c].ap; + + valnum[c].a = *valnum[c].ap; + if ( c < nattrs - 1 ) { + valnum[c].a.a_next = &valnum[c + 1].a; + } else { + valnum[c].a.a_next = NULL; + } + valnum[c].a.a_numvals = 1; + valnum[c].a.a_vals = valnum[c].vals; + BER_BVZERO( &valnum[c].vals[1] ); + if ( valnum[c].ap->a_nvals != valnum[c].ap->a_vals ) { + valnum[c].a.a_nvals = valnum[c].nvals; + BER_BVZERO( &valnum[c].nvals[1] ); + } else { + valnum[c].a.a_nvals = valnum[c].a.a_vals; + } +} + +static int +dupent_response_entry( Operation *op, SlapReply *rs ) +{ + dupent_cb_t *dc = (dupent_cb_t *)op->o_callback->sc_private; + int nattrs = 0; + valnum_t *valnum = NULL; + Attribute **app, *ap_list = NULL; + int i, c; + Entry *e = NULL; + int rc; + + assert( rs->sr_type == REP_SEARCH ); + + for ( i = 0; i < dc->dc_ds->ds_nattrs; i++ ) { + Attribute *ap; + + ap = attr_find( rs->sr_entry->e_attrs, + dc->dc_ds->ds_an[ i ].an_desc ); + if ( ap && ap->a_numvals > 1 ) { + nattrs++; + } + } + + if ( dc->dc_ds->ds_flags & SLAP_USERATTRS_YES ) { + Attribute *ap; + + for ( ap = rs->sr_entry->e_attrs; ap != NULL; ap = ap->a_next ) { + if ( !is_at_operational( ap->a_desc->ad_type ) && ap->a_numvals > 1 ) { + nattrs++; + } + } + } + + if ( !nattrs ) { + return SLAP_CB_CONTINUE; + } + + rs_entry2modifiable( op, rs, dc->dc_on ); + rs->sr_flags &= ~(REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED); + e = rs->sr_entry; + + valnum = op->o_tmpcalloc( sizeof(valnum_t), nattrs, op->o_tmpmemctx ); + + for ( c = 0, i = 0; i < dc->dc_ds->ds_nattrs; i++ ) { + for ( app = &e->e_attrs; *app != NULL; app = &(*app)->a_next ) { + if ( (*app)->a_desc == dc->dc_ds->ds_an[ i ].an_desc ) { + break; + } + } + + if ( *app != NULL && (*app)->a_numvals > 1 ) { + assert( c < nattrs ); + dupent_attr_prepare( dc->dc_ds, e, valnum, nattrs, c, app, &ap_list ); + c++; + } + } + + if ( dc->dc_ds->ds_flags & SLAP_USERATTRS_YES ) { + for ( app = &e->e_attrs; *app != NULL; app = &(*app)->a_next ) { + if ( !is_at_operational( (*app)->a_desc->ad_type ) && (*app)->a_numvals > 1 ) { + assert( c < nattrs ); + dupent_attr_prepare( dc->dc_ds, e, valnum, nattrs, c, app, &ap_list ); + c++; + } + } + } + + for ( app = &e->e_attrs; *app != NULL; app = &(*app)->a_next ) + /* goto tail */ ; + + *app = &valnum[0].a; + + /* NOTE: since send_search_entry() does not honor the + * REP_CTRLS_MUSTBEFREED flag set by slap_add_ctrls(), + * the control could be added here once for all (ITS#6629) + */ + + dc->dc_skip = 1; + rc = dupent_response_entry_1level( op, rs, e, valnum, nattrs, 0 ); + dc->dc_skip = 0; + + *app = ap_list; + + entry_free( e ); + + op->o_tmpfree( valnum, op->o_tmpmemctx ); + + return rc; +} + +static int +dupent_response( Operation *op, SlapReply *rs ) +{ + dupent_cb_t *dc = (dupent_cb_t *)op->o_callback->sc_private; + + if ( dc->dc_skip ) { + return SLAP_CB_CONTINUE; + } + + switch ( rs->sr_type ) { + case REP_RESULT: + return dupent_response_done( op, rs ); + + case REP_SEARCH: + return dupent_response_entry( op, rs ); + + case REP_SEARCHREF: + break; + + default: + assert( 0 ); + } + + return SLAP_CB_CONTINUE; +} + +static int +dupent_cleanup( Operation *op, SlapReply *rs ) +{ + if ( rs->sr_type == REP_RESULT || rs->sr_err == SLAPD_ABANDON ) { + op->o_tmpfree( op->o_callback, op->o_tmpmemctx ); + op->o_callback = NULL; + + op->o_tmpfree( op->o_ctrldupent, op->o_tmpmemctx ); + op->o_ctrldupent = NULL; + } + + return SLAP_CB_CONTINUE; +} + +static int +dupent_op_search( Operation *op, SlapReply *rs ) +{ + if ( op->o_dupent != SLAP_CONTROL_NONE ) { + slap_callback *sc; + dupent_cb_t *dc; + + sc = op->o_tmpcalloc( 1, sizeof( slap_callback ) + sizeof( dupent_cb_t ), op->o_tmpmemctx ); + + dc = (dupent_cb_t *)&sc[ 1 ]; + dc->dc_on = (slap_overinst *)op->o_bd->bd_info; + dc->dc_ds = (dupent_t *)op->o_ctrldupent; + dc->dc_skip = 0; + + sc->sc_response = dupent_response; + sc->sc_cleanup = dupent_cleanup; + sc->sc_private = (void *)dc; + + sc->sc_next = op->o_callback->sc_next; + op->o_callback->sc_next = sc; + } + + return SLAP_CB_CONTINUE; +} + +#if SLAPD_OVER_DUPENT == SLAPD_MOD_DYNAMIC +static +#endif /* SLAPD_OVER_DUPENT == SLAPD_MOD_DYNAMIC */ +int +dupent_initialize( void ) +{ + int rc; + + rc = register_supported_control( LDAP_CONTROL_DUPENT, + SLAP_CTRL_SEARCH, NULL, + dupent_parseCtrl, &dupent_cid ); + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, + "dupent_initialize: Failed to register control (%d)\n", + rc, 0, 0 ); + return -1; + } + + dupent.on_bi.bi_type = "dupent"; + + dupent.on_bi.bi_op_search = dupent_op_search; + + return overlay_register( &dupent ); +} + +#if SLAPD_OVER_DUPENT == SLAPD_MOD_DYNAMIC +int +init_module( int argc, char *argv[] ) +{ + return dupent_initialize(); +} +#endif /* SLAPD_OVER_DUPENT == SLAPD_MOD_DYNAMIC */ + +#endif /* SLAPD_OVER_DUPENT */ diff --git a/contrib/slapd-modules/kinit/Makefile b/contrib/slapd-modules/kinit/Makefile new file mode 100644 index 0000000..2a925ed --- /dev/null +++ b/contrib/slapd-modules/kinit/Makefile @@ -0,0 +1,46 @@ +# $OpenLDAP$ + +LDAP_SRC = ../../.. +LDAP_BUILD = $(LDAP_SRC) +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +CC = gcc +OPT = -g -O2 -Wall +DEFS = +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) -lkrb5 + +PROGRAMS = kinit.la +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +kinit.la: kinit.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + diff --git a/contrib/slapd-modules/kinit/README b/contrib/slapd-modules/kinit/README new file mode 100644 index 0000000..d6f73bb --- /dev/null +++ b/contrib/slapd-modules/kinit/README @@ -0,0 +1,36 @@ +This directory contains the "kinit" slapd module. It is a simple plugin to +have slapd request a Kerberos TGT and keep it renewed as long as slapd is +running. + +The current implementation has only been tested against the MIT variant of +the Kerberos libraries. (Heimdal support might come later) + +To use the overlay just load it into the slapd process: + + moduleload </path/to>/kinit.so <principal> </path/to/key.tab> + +The module accepts two arguments. The first one being the principal for which +to request the TGT (it defaults to "ldap/<your hostname>@<DEFAULTREALM>") +and the second one is the path to the keytab file to use for +authentication, defaulting to whatever your system wide kerberos settings +default to). + +Use Makefile or the following commands should work to +build it from inside the unpacked slapd sources, provided the required KRB5 +header files and libaries are installed on your system: + + gcc -fPIC -c -I ../../../include/ -I ../../../servers/slapd kinit.c + gcc -shared -o kinit.so kinit.o -lkrb5 + +--- +This work is part of OpenLDAP Software <http://www.openldap.org/>. + +Copyright 2010-2021 The OpenLDAP Foundation. + +Redistribution and use in source and binary forms, with or without +modification, are permitted only as authorized by the OpenLDAP +Public License. + +A copy of this license is available in the file LICENSE in the +top-level directory of the distribution or, alternatively, at +<http://www.OpenLDAP.org/license.html>. diff --git a/contrib/slapd-modules/kinit/kinit.c b/contrib/slapd-modules/kinit/kinit.c new file mode 100644 index 0000000..7a83d38 --- /dev/null +++ b/contrib/slapd-modules/kinit/kinit.c @@ -0,0 +1,295 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2010-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ + +#include <portable.h> + +#ifndef SLAPD_MOD_KINIT +#define SLAPD_MOD_KINIT SLAPD_MOD_DYNAMIC +#endif + +#ifdef SLAPD_MOD_KINIT + +#include <slap.h> +#include "ldap_rq.h" +#include <ac/errno.h> +#include <ac/string.h> +#include <krb5/krb5.h> + +typedef struct kinit_data { + krb5_context ctx; + krb5_ccache ccache; + krb5_keytab keytab; + krb5_principal princ; + krb5_get_init_creds_opt *opts; +} kinit_data; + +static char* principal; +static char* kt_name; +static kinit_data *kid; + +static void +log_krb5_errmsg( krb5_context ctx, const char* func, krb5_error_code rc ) +{ + const char* errmsg = krb5_get_error_message(ctx, rc); + Log2(LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, "slapd-kinit: %s: %s\n", func, errmsg); + krb5_free_error_message(ctx, errmsg); + return; +} + +static int +kinit_check_tgt(kinit_data *kid, int *remaining) +{ + int ret=3; + krb5_principal princ; + krb5_error_code rc; + krb5_cc_cursor cursor; + krb5_creds creds; + char *name; + time_t now=time(NULL); + + rc = krb5_cc_get_principal(kid->ctx, kid->ccache, &princ); + if (rc) { + log_krb5_errmsg(kid->ctx, "krb5_cc_get_principal", rc); + return 2; + } else { + if (!krb5_principal_compare(kid->ctx, kid->princ, princ)) { + Log0(LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, + "Principal in ccache does not match requested principal\n"); + krb5_free_principal(kid->ctx, princ); + return 2; + } + } + + rc = krb5_cc_start_seq_get(kid->ctx, kid->ccache, &cursor); + if (rc) { + log_krb5_errmsg(kid->ctx, "krb5_cc_start_seq_get", rc); + krb5_free_principal(kid->ctx, princ); + return -1; + } + + while (!(rc = krb5_cc_next_cred(kid->ctx, kid->ccache, &cursor, &creds))) { + if (krb5_is_config_principal(kid->ctx, creds.server)) { + krb5_free_cred_contents(kid->ctx, &creds); + continue; + } + + if (creds.server->length==2 && + (!strcmp(creds.server->data[0].data, "krbtgt")) && + (!strcmp(creds.server->data[1].data, princ->realm.data))) { + + krb5_unparse_name(kid->ctx, creds.server, &name); + + *remaining = (time_t)creds.times.endtime-now; + if ( *remaining <= 0) { + Log1(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, + "kinit_qtask: TGT (%s) expired\n", name); + } else { + Log4(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, + "kinit_qtask: TGT (%s) expires in %dh:%02dm:%02ds\n", + name, *remaining/3600, (*remaining%3600)/60, *remaining%60); + } + free(name); + + if (*remaining <= 30) { + if (creds.times.renew_till-60 > now) { + int renewal=creds.times.renew_till-now; + Log3(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, + "kinit_qtask: Time remaining for renewal: %dh:%02dm:%02ds\n", + renewal/3600, (renewal%3600)/60, renewal%60); + ret = 1; + } else { + Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, + "kinit_qtask: Only short time left for renewal. " + "Trying to re-init.\n"); + ret = 2; + } + } else { + ret=0; + } + krb5_free_cred_contents(kid->ctx, &creds); + break; + } + krb5_free_cred_contents(kid->ctx, &creds); + + } + krb5_cc_end_seq_get(kid->ctx, kid->ccache, &cursor); + krb5_free_principal(kid->ctx, princ); + return ret; +} + +void* +kinit_qtask( void *ctx, void *arg ) +{ + struct re_s *rtask = arg; + kinit_data *kid = (kinit_data*)rtask->arg; + krb5_error_code rc; + krb5_creds creds; + int nextcheck, remaining, renew=0; + Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "kinit_qtask: running TGT check\n"); + + memset(&creds, 0, sizeof(creds)); + + renew = kinit_check_tgt(kid, &remaining); + + if (renew > 0) { + if (renew==1) { + Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, + "kinit_qtask: Trying to renew TGT: "); + rc = krb5_get_renewed_creds(kid->ctx, &creds, kid->princ, kid->ccache, NULL); + if (rc!=0) { + Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "Failed\n"); + log_krb5_errmsg( kid->ctx, + "kinit_qtask, Renewal failed: krb5_get_renewed_creds", rc ); + renew++; + } else { + Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "Success\n"); + krb5_cc_initialize(kid->ctx, kid->ccache, creds.client); + krb5_cc_store_cred(kid->ctx, kid->ccache, &creds); + krb5_free_cred_contents(kid->ctx, &creds); + renew=kinit_check_tgt(kid, &remaining); + } + } + if (renew > 1) { + Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, + "kinit_qtask: Trying to get new TGT: "); + rc = krb5_get_init_creds_keytab( kid->ctx, &creds, kid->princ, + kid->keytab, 0, NULL, kid->opts); + if (rc) { + Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "Failed\n"); + log_krb5_errmsg(kid->ctx, "krb5_get_init_creds_keytab", rc); + } else { + Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "Success\n"); + renew=kinit_check_tgt(kid, &remaining); + } + krb5_free_cred_contents(kid->ctx, &creds); + } + } + if (renew == 0) { + nextcheck = remaining-30; + } else { + nextcheck = 60; + } + + ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); + if ( ldap_pvt_runqueue_isrunning( &slapd_rq, rtask )) { + ldap_pvt_runqueue_stoptask( &slapd_rq, rtask ); + } + Log3(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, + "kinit_qtask: Next TGT check in %dh:%02dm:%02ds\n", + nextcheck/3600, (nextcheck%3600)/60, nextcheck%60); + rtask->interval.tv_sec = nextcheck; + ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 ); + slap_wake_listener(); + ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); + return NULL; +} + +int +kinit_initialize(void) +{ + Log0( LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "kinit_initialize\n" ); + krb5_error_code rc; + struct re_s *task = NULL; + + kid = ch_calloc(1, sizeof(kinit_data) ); + + rc = krb5_init_context( &kid->ctx ); + if ( !rc ) + rc = krb5_cc_default(kid->ctx, &kid->ccache ); + + if ( !rc ) { + if (!principal) { + int len=STRLENOF("ldap/")+global_host_bv.bv_len+1; + principal=ch_calloc(len, 1); + snprintf(principal, len, "ldap/%s", global_host_bv.bv_val); + Log1(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "Principal <%s>\n", principal); + + } + rc = krb5_parse_name(kid->ctx, principal, &kid->princ); + } + + if ( !rc && kt_name) { + rc = krb5_kt_resolve(kid->ctx, kt_name, &kid->keytab); + } + + if ( !rc ) + rc = krb5_get_init_creds_opt_alloc(kid->ctx, &kid->opts); + + if ( !rc ) + rc = krb5_get_init_creds_opt_set_out_ccache( kid->ctx, kid->opts, kid->ccache); + + if ( !rc ) { + ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); + task = ldap_pvt_runqueue_insert( &slapd_rq, 10, kinit_qtask, (void*)kid, + "kinit_qtask", "ldap/bronsted.g17.lan@G17.LAN" ); + ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); + } + + if (rc) { + log_krb5_errmsg(kid->ctx, "kinit_initialize", rc); + rc = -1; + } + return rc; +} + +#if SLAPD_MOD_KINIT == SLAPD_MOD_DYNAMIC +int init_module(int argc, char *argv[]) { + if (argc > 0) { + principal = ch_strdup(argv[0]); + } + if (argc > 1) { + kt_name = ch_strdup(argv[1]); + } + if (argc > 2) { + return -1; + } + return kinit_initialize(); +} + +int +term_module() { + if (principal) + ch_free(principal); + if (kt_name) + ch_free(kt_name); + if (kid) { + struct re_s *task; + + task=ldap_pvt_runqueue_find( &slapd_rq, kinit_qtask, (void*)kid); + if (task) { + if ( ldap_pvt_runqueue_isrunning(&slapd_rq, task) ) { + ldap_pvt_runqueue_stoptask(&slapd_rq, task); + } + ldap_pvt_runqueue_remove(&slapd_rq, task); + } + if ( kid->ctx ) { + if ( kid->princ ) + krb5_free_principal(kid->ctx, kid->princ); + if ( kid->ccache ) + krb5_cc_close(kid->ctx, kid->ccache); + if ( kid->keytab ) + krb5_kt_close(kid->ctx, kid->keytab); + if ( kid->opts ) + krb5_get_init_creds_opt_free(kid->ctx, kid->opts); + krb5_free_context(kid->ctx); + } + ch_free(kid); + } + return 0; +} +#endif + +#endif /* SLAPD_MOD_KINIT */ + diff --git a/contrib/slapd-modules/lastbind/Makefile b/contrib/slapd-modules/lastbind/Makefile new file mode 100644 index 0000000..1745aa8 --- /dev/null +++ b/contrib/slapd-modules/lastbind/Makefile @@ -0,0 +1,56 @@ +# $OpenLDAP$ +# Copyright 2009 Jonathan Clarke <jonathan@phillipoux.net>. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted only as authorized by the OpenLDAP +# Public License. +# +# A copy of this license is available in the file LICENSE in the +# top-level directory of the distribution or, alternatively, at +# <http://www.OpenLDAP.org/license.html>. + +LDAP_SRC = ../../.. +LDAP_BUILD = $(LDAP_SRC) +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +CC = gcc +OPT = -g -O2 -Wall +DEFS = -DSLAPD_OVER_LASTBIND=SLAPD_MOD_DYNAMIC +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) + +PROGRAMS = lastbind.la +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +lastbind.la: lastbind.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + diff --git a/contrib/slapd-modules/lastbind/lastbind.c b/contrib/slapd-modules/lastbind/lastbind.c new file mode 100644 index 0000000..311be04 --- /dev/null +++ b/contrib/slapd-modules/lastbind/lastbind.c @@ -0,0 +1,317 @@ +/* lastbind.c - Record timestamp of the last successful bind to entries */ +/* $OpenLDAP$ */ +/* + * Copyright 2009 Jonathan Clarke <jonathan@phillipoux.net>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This work is loosely derived from the ppolicy overlay. + */ + +#include "portable.h" + +/* + * This file implements an overlay that stores the timestamp of the + * last successful bind operation in a directory entry. + * + * Optimization: to avoid performing a write on each bind, + * a precision for this timestamp may be configured, causing it to + * only be updated if it is older than a given number of seconds. + */ + +#ifdef SLAPD_OVER_LASTBIND + +#include <ldap.h> +#include "lutil.h" +#include "slap.h" +#include <ac/errno.h> +#include <ac/time.h> +#include <ac/string.h> +#include <ac/ctype.h> +#include "config.h" + +/* Per-instance configuration information */ +typedef struct lastbind_info { + /* precision to update timestamp in authTimestamp attribute */ + int timestamp_precision; + int forward_updates; /* use frontend for authTimestamp updates */ +} lastbind_info; + +/* Operational attributes */ +static AttributeDescription *ad_authTimestamp; + +/* This is the definition used by ISODE, as supplied to us in + * ITS#6238 Followup #9 + */ +static struct schema_info { + char *def; + AttributeDescription **ad; +} lastBind_OpSchema[] = { + { "( 1.3.6.1.4.1.453.16.2.188 " + "NAME 'authTimestamp' " + "DESC 'last successful authentication using any method/mech' " + "EQUALITY generalizedTimeMatch " + "ORDERING generalizedTimeOrderingMatch " + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 " + "SINGLE-VALUE NO-USER-MODIFICATION USAGE dsaOperation )", + &ad_authTimestamp}, + { NULL, NULL } +}; + +/* configuration attribute and objectclass */ +static ConfigTable lastbindcfg[] = { + { "lastbind-precision", "seconds", 2, 2, 0, + ARG_INT|ARG_OFFSET, + (void *)offsetof(lastbind_info, timestamp_precision), + "( OLcfgCtAt:5.1 " + "NAME 'olcLastBindPrecision' " + "DESC 'Precision of authTimestamp attribute' " + "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, + { "lastbind_forward_updates", "on|off", 1, 2, 0, + ARG_ON_OFF|ARG_OFFSET, + (void *)offsetof(lastbind_info,forward_updates), + "( OLcfgAt:5.2 NAME 'olcLastBindForwardUpdates' " + "DESC 'Allow authTimestamp updates to be forwarded via updateref' " + "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, + { NULL, NULL, 0, 0, 0, ARG_IGNORED } +}; + +static ConfigOCs lastbindocs[] = { + { "( OLcfgCtOc:5.1 " + "NAME 'olcLastBindConfig' " + "DESC 'Last Bind configuration' " + "SUP olcOverlayConfig " + "MAY ( olcLastBindPrecision $ olcLastBindForwardUpdates) )", + Cft_Overlay, lastbindcfg, NULL, NULL }, + { NULL, 0, NULL } +}; + +static time_t +parse_time( char *atm ) +{ + struct lutil_tm tm; + struct lutil_timet tt; + time_t ret = (time_t)-1; + + if ( lutil_parsetime( atm, &tm ) == 0) { + lutil_tm2time( &tm, &tt ); + ret = tt.tt_sec; + } + return ret; +} + +static int +lastbind_bind_response( Operation *op, SlapReply *rs ) +{ + Modifications *mod = NULL; + BackendInfo *bi = op->o_bd->bd_info; + Entry *e; + int rc; + + /* we're only interested if the bind was successful */ + if ( rs->sr_err != LDAP_SUCCESS ) + return SLAP_CB_CONTINUE; + + rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e ); + op->o_bd->bd_info = bi; + + if ( rc != LDAP_SUCCESS ) { + return SLAP_CB_CONTINUE; + } + + { + lastbind_info *lbi = (lastbind_info *) op->o_callback->sc_private; + + time_t now, bindtime = (time_t)-1; + Attribute *a; + Modifications *m; + char nowstr[ LDAP_LUTIL_GENTIME_BUFSIZE ]; + struct berval timestamp; + + /* get the current time */ + now = slap_get_time(); + + /* get authTimestamp attribute, if it exists */ + if ((a = attr_find( e->e_attrs, ad_authTimestamp)) != NULL) { + bindtime = parse_time( a->a_nvals[0].bv_val ); + + if (bindtime != (time_t)-1) { + /* if the recorded bind time is within our precision, we're done + * it doesn't need to be updated (save a write for nothing) */ + if ((now - bindtime) < lbi->timestamp_precision) { + goto done; + } + } + } + + /* update the authTimestamp in the user's entry with the current time */ + timestamp.bv_val = nowstr; + timestamp.bv_len = sizeof(nowstr); + slap_timestamp( &now, ×tamp ); + + m = ch_calloc( sizeof(Modifications), 1 ); + m->sml_op = LDAP_MOD_REPLACE; + m->sml_flags = 0; + m->sml_type = ad_authTimestamp->ad_cname; + m->sml_desc = ad_authTimestamp; + m->sml_numvals = 1; + m->sml_values = ch_calloc( sizeof(struct berval), 2 ); + m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 ); + + ber_dupbv( &m->sml_values[0], ×tamp ); + ber_dupbv( &m->sml_nvalues[0], ×tamp ); + m->sml_next = mod; + mod = m; + } + +done: + be_entry_release_r( op, e ); + + /* perform the update, if necessary */ + if ( mod ) { + Operation op2 = *op; + SlapReply r2 = { REP_RESULT }; + slap_callback cb = { NULL, slap_null_cb, NULL, NULL }; + LDAPControl c, *ca[2]; + lastbind_info *lbi = (lastbind_info *) op->o_callback->sc_private; + + /* This is a DSA-specific opattr, it never gets replicated. */ + op2.o_tag = LDAP_REQ_MODIFY; + op2.o_callback = &cb; + op2.orm_modlist = mod; + op2.orm_no_opattrs = 0; + op2.o_dn = op->o_bd->be_rootdn; + op2.o_ndn = op->o_bd->be_rootndn; + + /* + * Code for forwarding of updates adapted from ppolicy.c of slapo-ppolicy + * + * If this server is a shadow and forward_updates is true, + * use the frontend to perform this modify. That will trigger + * the update referral, which can then be forwarded by the + * chain overlay. Obviously the updateref and chain overlay + * must be configured appropriately for this to be useful. + */ + if ( SLAP_SHADOW( op->o_bd ) && lbi->forward_updates ) { + op2.o_bd = frontendDB; + + /* Must use Relax control since these are no-user-mod */ + op2.o_relax = SLAP_CONTROL_CRITICAL; + op2.o_ctrls = ca; + ca[0] = &c; + ca[1] = NULL; + BER_BVZERO( &c.ldctl_value ); + c.ldctl_iscritical = 1; + c.ldctl_oid = LDAP_CONTROL_RELAX; + } else { + /* If not forwarding, don't update opattrs and don't replicate */ + if ( SLAP_SINGLE_SHADOW( op->o_bd )) { + op2.orm_no_opattrs = 1; + op2.o_dont_replicate = 1; + } + /* TODO: not sure what this does in slapo-ppolicy */ + /* + op2.o_bd->bd_info = (BackendInfo *)on->on_info; + */ + } + + rc = op->o_bd->be_modify( &op2, &r2 ); + slap_mods_free( mod, 1 ); + } + + op->o_bd->bd_info = bi; + return SLAP_CB_CONTINUE; +} + +static int +lastbind_bind( Operation *op, SlapReply *rs ) +{ + slap_callback *cb; + slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; + + /* setup a callback to intercept result of this bind operation + * and pass along the lastbind_info struct */ + cb = op->o_tmpcalloc( sizeof(slap_callback), 1, op->o_tmpmemctx ); + cb->sc_response = lastbind_bind_response; + cb->sc_next = op->o_callback->sc_next; + cb->sc_private = on->on_bi.bi_private; + op->o_callback->sc_next = cb; + + return SLAP_CB_CONTINUE; +} + +static int +lastbind_db_init( + BackendDB *be, + ConfigReply *cr +) +{ + slap_overinst *on = (slap_overinst *) be->bd_info; + + /* initialize private structure to store configuration */ + on->on_bi.bi_private = ch_calloc( 1, sizeof(lastbind_info) ); + + return 0; +} + +static int +lastbind_db_close( + BackendDB *be, + ConfigReply *cr +) +{ + slap_overinst *on = (slap_overinst *) be->bd_info; + lastbind_info *lbi = (lastbind_info *) on->on_bi.bi_private; + + /* free private structure to store configuration */ + free( lbi ); + + return 0; +} + +static slap_overinst lastbind; + +int lastbind_initialize() +{ + int i, code; + + /* register operational schema for this overlay (authTimestamp attribute) */ + for (i=0; lastBind_OpSchema[i].def; i++) { + code = register_at( lastBind_OpSchema[i].def, lastBind_OpSchema[i].ad, 0 ); + if ( code ) { + Debug( LDAP_DEBUG_ANY, + "lastbind_initialize: register_at failed\n", 0, 0, 0 ); + return code; + } + } + + ad_authTimestamp->ad_type->sat_flags |= SLAP_AT_MANAGEABLE; + + lastbind.on_bi.bi_type = "lastbind"; + lastbind.on_bi.bi_db_init = lastbind_db_init; + lastbind.on_bi.bi_db_close = lastbind_db_close; + lastbind.on_bi.bi_op_bind = lastbind_bind; + + /* register configuration directives */ + lastbind.on_bi.bi_cf_ocs = lastbindocs; + code = config_register_schema( lastbindcfg, lastbindocs ); + if ( code ) return code; + + return overlay_register( &lastbind ); +} + +#if SLAPD_OVER_LASTBIND == SLAPD_MOD_DYNAMIC +int init_module(int argc, char *argv[]) { + return lastbind_initialize(); +} +#endif + +#endif /* defined(SLAPD_OVER_LASTBIND) */ diff --git a/contrib/slapd-modules/lastbind/slapo-lastbind.5 b/contrib/slapd-modules/lastbind/slapo-lastbind.5 new file mode 100644 index 0000000..d0da8b8 --- /dev/null +++ b/contrib/slapd-modules/lastbind/slapo-lastbind.5 @@ -0,0 +1,108 @@ +.TH SLAPO-LASTBIND 5 "RELEASEDATE" "OpenLDAP LDVERSION" +.\" Copyright 2009 Jonathan Clarke, All Rights Reserved. +.\" $OpenLDAP$ +.SH NAME +slapo-lastbind \- lastbind overlay to slapd +.SH SYNOPSIS +ETCDIR/slapd.conf +.SH DESCRIPTION +The +.B lastbind +overlay to +.BR slapd (8) +allows recording the timestamp of the last successful bind to entries +in the directory, in the +.B authTimestamp +attribute. +The overlay can be configured to update this timestamp only if it is +older than a given value, thus avoiding large numbers of write +operations penalizing performance. +One sample use for this overlay would be to detect unused accounts. + +.SH CONFIGURATION +The config directives that are specific to the +.B lastbind +overlay must be prefixed by +.BR lastbind\- , +to avoid potential conflicts with directives specific to the underlying +database or to other stacked overlays. + +.TP +.B overlay lastbind +This directive adds the +.B lastbind +overlay to the current database, see +.BR slapd.conf (5) +for details. + +.LP +This +.B slapd.conf +configuration option is defined for the lastbind overlay. It must +appear after the +.B overlay +directive: +.TP +.B lastbind-precision <seconds> +The value +.B <seconds> +is the number of seconds after which to update the +.B authTimestamp +attribute in an entry. If the existing value of +.B authTimestamp +is less than +.B <seconds> +old, it will not be changed. +If this configuration option is omitted, the +.B authTimestamp +attribute is updated on each successful bind operation. +.TP +.B lastbind_forward_updates +Specify that updates of the authTimestamp attribute +on a consumer should be forwarded +to a provider instead of being written directly into the consumer's local +database. This setting is only useful on a replication consumer, and +also requires the +.B updateref +setting and +.B chain +overlay to be appropriately configured. + +.SH EXAMPLE +This example configures the +.B lastbind +overlay to store +.B authTimestamp +in all entries in a database, with a 1 week precision. +Add the following to +.BR slapd.conf (5): + +.LP +.nf + database <database> + # ... + + overlay lastbind + lastbind-precision 604800 +.fi +.LP +.B slapd +must also load +.B lastbind.la, +if compiled as a run-time module; + +.SH FILES +.TP +ETCDIR/slapd.conf +default slapd configuration file +.SH SEE ALSO +.BR slapd.conf (5), +.BR slapd (8). +The +.BR slapo-lastbind (5) +overlay supports dynamic configuration via +.BR back-config. +.SH ACKNOWLEDGEMENTS +.P +This module was written in 2009 by Jonathan Clarke. It is loosely +derived from the password policy overlay. diff --git a/contrib/slapd-modules/lastmod/Makefile b/contrib/slapd-modules/lastmod/Makefile new file mode 100644 index 0000000..098984e --- /dev/null +++ b/contrib/slapd-modules/lastmod/Makefile @@ -0,0 +1,47 @@ +# $OpenLDAP$ + +LDAP_SRC = ../../.. +LDAP_BUILD = $(LDAP_SRC) +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +CC = gcc +OPT = -g -O2 -Wall +DEFS = -DSLAPD_OVER_LASTMOD=SLAPD_MOD_DYNAMIC +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) + +PROGRAMS = lastmod.la +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +lastmod.la: lastmod.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + + diff --git a/contrib/slapd-modules/lastmod/lastmod.c b/contrib/slapd-modules/lastmod/lastmod.c new file mode 100644 index 0000000..2df3be5 --- /dev/null +++ b/contrib/slapd-modules/lastmod/lastmod.c @@ -0,0 +1,962 @@ +/* lastmod.c - returns last modification info */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2004-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by Pierangelo Masarati for inclusion in + * OpenLDAP Software. + */ + +#include "portable.h" + +#ifdef SLAPD_OVER_LASTMOD + +#include <stdio.h> + +#include <ac/string.h> +#include <ac/socket.h> + +#include "slap.h" +#include "lutil.h" + +typedef struct lastmod_info_t { + struct berval lmi_rdnvalue; + Entry *lmi_e; + ldap_pvt_thread_mutex_t lmi_entry_mutex; + int lmi_enabled; +} lastmod_info_t; + +struct lastmod_schema_t { + ObjectClass *lms_oc_lastmod; + AttributeDescription *lms_ad_lastmodDN; + AttributeDescription *lms_ad_lastmodType; + AttributeDescription *lms_ad_lastmodEnabled; +} lastmod_schema; + +enum lastmodType_e { + LASTMOD_ADD = 0, + LASTMOD_DELETE, + LASTMOD_EXOP, + LASTMOD_MODIFY, + LASTMOD_MODRDN, + LASTMOD_UNKNOWN +}; + +struct berval lastmodType[] = { + BER_BVC( "add" ), + BER_BVC( "delete" ), + BER_BVC( "exop" ), + BER_BVC( "modify" ), + BER_BVC( "modrdn" ), + BER_BVC( "unknown" ), + BER_BVNULL +}; + +static struct m_s { + char *schema; + slap_mask_t flags; + int offset; +} moc[] = { + { "( 1.3.6.1.4.1.4203.666.3.13" + "NAME 'lastmod' " + "DESC 'OpenLDAP per-database last modification monitoring' " + "STRUCTURAL " + "SUP top " + "MUST cn " + "MAY ( " + "lastmodDN " + "$ lastmodType " + "$ description " + "$ seeAlso " + ") )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE, + offsetof( struct lastmod_schema_t, lms_oc_lastmod ) }, + { NULL } +}, mat[] = { + { "( 1.3.6.1.4.1.4203.666.1.28" + "NAME 'lastmodDN' " + "DESC 'DN of last modification' " + "EQUALITY distinguishedNameMatch " + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 " + "NO-USER-MODIFICATION " + "USAGE directoryOperation )", SLAP_AT_HIDE, + offsetof( struct lastmod_schema_t, lms_ad_lastmodDN ) }, + { "( 1.3.6.1.4.1.4203.666.1.29" + "NAME 'lastmodType' " + "DESC 'Type of last modification' " + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 " + "EQUALITY caseIgnoreMatch " + "SINGLE-VALUE " + "NO-USER-MODIFICATION " + "USAGE directoryOperation )", SLAP_AT_HIDE, + offsetof( struct lastmod_schema_t, lms_ad_lastmodType ) }, + { "( 1.3.6.1.4.1.4203.666.1.30" + "NAME 'lastmodEnabled' " + "DESC 'Lastmod overlay state' " + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 " + "EQUALITY booleanMatch " + "SINGLE-VALUE )", 0, + offsetof( struct lastmod_schema_t, lms_ad_lastmodEnabled ) }, + { NULL } + + /* FIXME: what about UUID of last modified entry? */ +}; + +static int +lastmod_search( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + lastmod_info_t *lmi = (lastmod_info_t *)on->on_bi.bi_private; + int rc; + + /* if we get here, it must be a success */ + rs->sr_err = LDAP_SUCCESS; + + ldap_pvt_thread_mutex_lock( &lmi->lmi_entry_mutex ); + + rc = test_filter( op, lmi->lmi_e, op->oq_search.rs_filter ); + if ( rc == LDAP_COMPARE_TRUE ) { + rs->sr_attrs = op->ors_attrs; + rs->sr_flags = 0; + rs->sr_entry = lmi->lmi_e; + rs->sr_err = send_search_entry( op, rs ); + rs->sr_entry = NULL; + rs->sr_flags = 0; + rs->sr_attrs = NULL; + } + + ldap_pvt_thread_mutex_unlock( &lmi->lmi_entry_mutex ); + + send_ldap_result( op, rs ); + + return 0; +} + +static int +lastmod_compare( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + lastmod_info_t *lmi = (lastmod_info_t *)on->on_bi.bi_private; + Attribute *a; + + ldap_pvt_thread_mutex_lock( &lmi->lmi_entry_mutex ); + + if ( get_assert( op ) && + ( test_filter( op, lmi->lmi_e, get_assertion( op ) ) != LDAP_COMPARE_TRUE ) ) + { + rs->sr_err = LDAP_ASSERTION_FAILED; + goto return_results; + } + + rs->sr_err = access_allowed( op, lmi->lmi_e, op->oq_compare.rs_ava->aa_desc, + &op->oq_compare.rs_ava->aa_value, ACL_COMPARE, NULL ); + if ( ! rs->sr_err ) { + rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + goto return_results; + } + + rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE; + + for ( a = attr_find( lmi->lmi_e->e_attrs, op->oq_compare.rs_ava->aa_desc ); + a != NULL; + a = attr_find( a->a_next, op->oq_compare.rs_ava->aa_desc ) ) + { + rs->sr_err = LDAP_COMPARE_FALSE; + + if ( value_find_ex( op->oq_compare.rs_ava->aa_desc, + SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | + SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, + a->a_nvals, &op->oq_compare.rs_ava->aa_value, op->o_tmpmemctx ) == 0 ) + { + rs->sr_err = LDAP_COMPARE_TRUE; + break; + } + } + +return_results:; + + ldap_pvt_thread_mutex_unlock( &lmi->lmi_entry_mutex ); + + send_ldap_result( op, rs ); + + if( rs->sr_err == LDAP_COMPARE_FALSE || rs->sr_err == LDAP_COMPARE_TRUE ) { + rs->sr_err = LDAP_SUCCESS; + } + + return rs->sr_err; +} + +static int +lastmod_exop( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + + /* Temporary */ + + op->o_bd->bd_info = (BackendInfo *)on->on_info; + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "not allowed within namingContext"; + send_ldap_result( op, rs ); + rs->sr_text = NULL; + + return -1; +} + +static int +lastmod_modify( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + lastmod_info_t *lmi = (lastmod_info_t *)on->on_bi.bi_private; + Modifications *ml; + + ldap_pvt_thread_mutex_lock( &lmi->lmi_entry_mutex ); + + if ( !acl_check_modlist( op, lmi->lmi_e, op->orm_modlist ) ) { + rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + goto cleanup; + } + + for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) { + Attribute *a; + + if ( ml->sml_desc != lastmod_schema.lms_ad_lastmodEnabled ) { + continue; + } + + if ( ml->sml_op != LDAP_MOD_REPLACE ) { + rs->sr_text = "unsupported mod type"; + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + goto cleanup; + } + + a = attr_find( lmi->lmi_e->e_attrs, ml->sml_desc ); + + if ( a == NULL ) { + rs->sr_text = "lastmod overlay internal error"; + rs->sr_err = LDAP_OTHER; + goto cleanup; + } + + ch_free( a->a_vals[ 0 ].bv_val ); + ber_dupbv( &a->a_vals[ 0 ], &ml->sml_values[ 0 ] ); + if ( a->a_nvals ) { + ch_free( a->a_nvals[ 0 ].bv_val ); + if ( ml->sml_nvalues && !BER_BVISNULL( &ml->sml_nvalues[ 0 ] ) ) { + ber_dupbv( &a->a_nvals[ 0 ], &ml->sml_nvalues[ 0 ] ); + } else { + ber_dupbv( &a->a_nvals[ 0 ], &ml->sml_values[ 0 ] ); + } + } + + if ( strcmp( ml->sml_values[ 0 ].bv_val, "TRUE" ) == 0 ) { + lmi->lmi_enabled = 1; + } else if ( strcmp( ml->sml_values[ 0 ].bv_val, "FALSE" ) == 0 ) { + lmi->lmi_enabled = 0; + } else { + assert( 0 ); + } + } + + rs->sr_err = LDAP_SUCCESS; + +cleanup:; + ldap_pvt_thread_mutex_unlock( &lmi->lmi_entry_mutex ); + + send_ldap_result( op, rs ); + rs->sr_text = NULL; + + return rs->sr_err; +} + +static int +lastmod_op_func( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + lastmod_info_t *lmi = (lastmod_info_t *)on->on_bi.bi_private; + Modifications *ml; + + if ( dn_match( &op->o_req_ndn, &lmi->lmi_e->e_nname ) ) { + switch ( op->o_tag ) { + case LDAP_REQ_SEARCH: + if ( op->ors_scope != LDAP_SCOPE_BASE ) { + goto return_referral; + } + /* process */ + return lastmod_search( op, rs ); + + case LDAP_REQ_COMPARE: + return lastmod_compare( op, rs ); + + case LDAP_REQ_EXTENDED: + /* if write, reject; otherwise process */ + if ( exop_is_write( op )) { + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "not allowed within namingContext"; + goto return_error; + } + return lastmod_exop( op, rs ); + + case LDAP_REQ_MODIFY: + /* allow only changes to overlay status */ + for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) { + if ( ad_cmp( ml->sml_desc, slap_schema.si_ad_modifiersName ) != 0 + && ad_cmp( ml->sml_desc, slap_schema.si_ad_modifyTimestamp ) != 0 + && ad_cmp( ml->sml_desc, slap_schema.si_ad_entryCSN ) != 0 + && ad_cmp( ml->sml_desc, lastmod_schema.lms_ad_lastmodEnabled ) != 0 ) + { + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "not allowed within namingContext"; + goto return_error; + } + } + return lastmod_modify( op, rs ); + + default: + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "not allowed within namingContext"; + goto return_error; + } + } + + if ( dnIsSuffix( &op->o_req_ndn, &lmi->lmi_e->e_nname ) ) { + goto return_referral; + } + + return SLAP_CB_CONTINUE; + +return_referral:; + op->o_bd->bd_info = (BackendInfo *)on->on_info; + rs->sr_ref = referral_rewrite( default_referral, + NULL, &op->o_req_dn, op->ors_scope ); + + if ( !rs->sr_ref ) { + rs->sr_ref = default_referral; + } + rs->sr_err = LDAP_REFERRAL; + send_ldap_result( op, rs ); + + if ( rs->sr_ref != default_referral ) { + ber_bvarray_free( rs->sr_ref ); + } + rs->sr_ref = NULL; + + return -1; + +return_error:; + op->o_bd->bd_info = (BackendInfo *)on->on_info; + send_ldap_result( op, rs ); + rs->sr_text = NULL; + + return -1; +} + +static int +best_guess( Operation *op, + struct berval *bv_entryCSN, struct berval *bv_nentryCSN, + struct berval *bv_modifyTimestamp, struct berval *bv_nmodifyTimestamp, + struct berval *bv_modifiersName, struct berval *bv_nmodifiersName ) +{ + if ( bv_entryCSN ) { + char csnbuf[ LDAP_PVT_CSNSTR_BUFSIZE ]; + struct berval entryCSN; + + entryCSN.bv_val = csnbuf; + entryCSN.bv_len = sizeof( csnbuf ); + slap_get_csn( NULL, &entryCSN, 0 ); + + ber_dupbv( bv_entryCSN, &entryCSN ); + ber_dupbv( bv_nentryCSN, &entryCSN ); + } + + if ( bv_modifyTimestamp ) { + char tmbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; + struct berval timestamp; + time_t currtime; + + /* best guess */ +#if 0 + currtime = slap_get_time(); +#endif + /* maybe we better use the time the operation was initiated */ + currtime = op->o_time; + + timestamp.bv_val = tmbuf; + timestamp.bv_len = sizeof(tmbuf); + slap_timestamp( &currtime, ×tamp ); + + ber_dupbv( bv_modifyTimestamp, ×tamp ); + ber_dupbv( bv_nmodifyTimestamp, bv_modifyTimestamp ); + } + + if ( bv_modifiersName ) { + /* best guess */ + ber_dupbv( bv_modifiersName, &op->o_dn ); + ber_dupbv( bv_nmodifiersName, &op->o_ndn ); + } + + return 0; +} + +static int +lastmod_update( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + lastmod_info_t *lmi = (lastmod_info_t *)on->on_bi.bi_private; + Attribute *a; + Modifications *ml = NULL; + struct berval bv_entryCSN = BER_BVNULL, + bv_nentryCSN = BER_BVNULL, + bv_modifyTimestamp = BER_BVNULL, + bv_nmodifyTimestamp = BER_BVNULL, + bv_modifiersName = BER_BVNULL, + bv_nmodifiersName = BER_BVNULL, + bv_name = BER_BVNULL, + bv_nname = BER_BVNULL; + enum lastmodType_e lmt = LASTMOD_UNKNOWN; + Entry *e = NULL; + int rc = -1; + + /* FIXME: timestamp? modifier? */ + switch ( op->o_tag ) { + case LDAP_REQ_ADD: + lmt = LASTMOD_ADD; + e = op->ora_e; + a = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN ); + if ( a != NULL ) { + ber_dupbv( &bv_entryCSN, &a->a_vals[0] ); + if ( a->a_nvals && !BER_BVISNULL( &a->a_nvals[0] ) ) { + ber_dupbv( &bv_nentryCSN, &a->a_nvals[0] ); + } else { + ber_dupbv( &bv_nentryCSN, &a->a_vals[0] ); + } + } + a = attr_find( e->e_attrs, slap_schema.si_ad_modifyTimestamp ); + if ( a != NULL ) { + ber_dupbv( &bv_modifyTimestamp, &a->a_vals[0] ); + if ( a->a_nvals && !BER_BVISNULL( &a->a_nvals[0] ) ) { + ber_dupbv( &bv_nmodifyTimestamp, &a->a_nvals[0] ); + } else { + ber_dupbv( &bv_nmodifyTimestamp, &a->a_vals[0] ); + } + } + a = attr_find( e->e_attrs, slap_schema.si_ad_modifiersName ); + if ( a != NULL ) { + ber_dupbv( &bv_modifiersName, &a->a_vals[0] ); + ber_dupbv( &bv_nmodifiersName, &a->a_nvals[0] ); + } + ber_dupbv( &bv_name, &e->e_name ); + ber_dupbv( &bv_nname, &e->e_nname ); + break; + + case LDAP_REQ_DELETE: + lmt = LASTMOD_DELETE; + + best_guess( op, &bv_entryCSN, &bv_nentryCSN, + &bv_modifyTimestamp, &bv_nmodifyTimestamp, + &bv_modifiersName, &bv_nmodifiersName ); + + ber_dupbv( &bv_name, &op->o_req_dn ); + ber_dupbv( &bv_nname, &op->o_req_ndn ); + break; + + case LDAP_REQ_EXTENDED: + lmt = LASTMOD_EXOP; + + /* actually, password change is wrapped around a backend + * call to modify, so it never shows up as an exop... */ + best_guess( op, &bv_entryCSN, &bv_nentryCSN, + &bv_modifyTimestamp, &bv_nmodifyTimestamp, + &bv_modifiersName, &bv_nmodifiersName ); + + ber_dupbv( &bv_name, &op->o_req_dn ); + ber_dupbv( &bv_nname, &op->o_req_ndn ); + break; + + case LDAP_REQ_MODIFY: + lmt = LASTMOD_MODIFY; + rc = 3; + + for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) { + if ( ad_cmp( ml->sml_desc , slap_schema.si_ad_modifiersName ) == 0 ) { + ber_dupbv( &bv_modifiersName, &ml->sml_values[0] ); + ber_dupbv( &bv_nmodifiersName, &ml->sml_nvalues[0] ); + + rc--; + if ( !rc ) { + break; + } + + } else if ( ad_cmp( ml->sml_desc, slap_schema.si_ad_entryCSN ) == 0 ) { + ber_dupbv( &bv_entryCSN, &ml->sml_values[0] ); + if ( ml->sml_nvalues && !BER_BVISNULL( &ml->sml_nvalues[0] ) ) { + ber_dupbv( &bv_nentryCSN, &ml->sml_nvalues[0] ); + } else { + ber_dupbv( &bv_nentryCSN, &ml->sml_values[0] ); + } + + rc --; + if ( !rc ) { + break; + } + + } else if ( ad_cmp( ml->sml_desc, slap_schema.si_ad_modifyTimestamp ) == 0 ) { + ber_dupbv( &bv_modifyTimestamp, &ml->sml_values[0] ); + if ( ml->sml_nvalues && !BER_BVISNULL( &ml->sml_nvalues[0] ) ) { + ber_dupbv( &bv_nmodifyTimestamp, &ml->sml_nvalues[0] ); + } else { + ber_dupbv( &bv_nmodifyTimestamp, &ml->sml_values[0] ); + } + + rc --; + if ( !rc ) { + break; + } + } + } + + /* if rooted at global overlay, opattrs are not yet in place */ + if ( BER_BVISNULL( &bv_modifiersName ) ) { + best_guess( op, NULL, NULL, NULL, NULL, &bv_modifiersName, &bv_nmodifiersName ); + } + + if ( BER_BVISNULL( &bv_entryCSN ) ) { + best_guess( op, &bv_entryCSN, &bv_nentryCSN, NULL, NULL, NULL, NULL ); + } + + if ( BER_BVISNULL( &bv_modifyTimestamp ) ) { + best_guess( op, NULL, NULL, &bv_modifyTimestamp, &bv_nmodifyTimestamp, NULL, NULL ); + } + + ber_dupbv( &bv_name, &op->o_req_dn ); + ber_dupbv( &bv_nname, &op->o_req_ndn ); + break; + + case LDAP_REQ_MODRDN: + lmt = LASTMOD_MODRDN; + e = NULL; + + if ( op->orr_newSup && !BER_BVISNULL( op->orr_newSup ) ) { + build_new_dn( &bv_name, op->orr_newSup, &op->orr_newrdn, NULL ); + build_new_dn( &bv_nname, op->orr_nnewSup, &op->orr_nnewrdn, NULL ); + + } else { + struct berval pdn; + + dnParent( &op->o_req_dn, &pdn ); + build_new_dn( &bv_name, &pdn, &op->orr_newrdn, NULL ); + + dnParent( &op->o_req_ndn, &pdn ); + build_new_dn( &bv_nname, &pdn, &op->orr_nnewrdn, NULL ); + } + + if ( on->on_info->oi_orig->bi_entry_get_rw ) { + BackendInfo *bi = op->o_bd->bd_info; + int rc; + + op->o_bd->bd_info = (BackendInfo *)on->on_info->oi_orig; + rc = op->o_bd->bd_info->bi_entry_get_rw( op, &bv_name, NULL, NULL, 0, &e ); + if ( rc == LDAP_SUCCESS ) { + a = attr_find( e->e_attrs, slap_schema.si_ad_modifiersName ); + if ( a != NULL ) { + ber_dupbv( &bv_modifiersName, &a->a_vals[0] ); + ber_dupbv( &bv_nmodifiersName, &a->a_nvals[0] ); + } + a = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN ); + if ( a != NULL ) { + ber_dupbv( &bv_entryCSN, &a->a_vals[0] ); + if ( a->a_nvals && !BER_BVISNULL( &a->a_nvals[0] ) ) { + ber_dupbv( &bv_nentryCSN, &a->a_nvals[0] ); + } else { + ber_dupbv( &bv_nentryCSN, &a->a_vals[0] ); + } + } + a = attr_find( e->e_attrs, slap_schema.si_ad_modifyTimestamp ); + if ( a != NULL ) { + ber_dupbv( &bv_modifyTimestamp, &a->a_vals[0] ); + if ( a->a_nvals && !BER_BVISNULL( &a->a_nvals[0] ) ) { + ber_dupbv( &bv_nmodifyTimestamp, &a->a_nvals[0] ); + } else { + ber_dupbv( &bv_nmodifyTimestamp, &a->a_vals[0] ); + } + } + + assert( dn_match( &bv_name, &e->e_name ) ); + assert( dn_match( &bv_nname, &e->e_nname ) ); + + op->o_bd->bd_info->bi_entry_release_rw( op, e, 0 ); + } + + op->o_bd->bd_info = bi; + + } + + /* if !bi_entry_get_rw || bi_entry_get_rw failed for any reason... */ + if ( e == NULL ) { + best_guess( op, &bv_entryCSN, &bv_nentryCSN, + &bv_modifyTimestamp, &bv_nmodifyTimestamp, + &bv_modifiersName, &bv_nmodifiersName ); + } + + break; + + default: + return -1; + } + + ldap_pvt_thread_mutex_lock( &lmi->lmi_entry_mutex ); + +#if 0 + fprintf( stderr, "### lastmodDN: %s %s\n", bv_name.bv_val, bv_nname.bv_val ); +#endif + + a = attr_find( lmi->lmi_e->e_attrs, lastmod_schema.lms_ad_lastmodDN ); + if ( a == NULL ) { + goto error_return; + } + ch_free( a->a_vals[0].bv_val ); + a->a_vals[0] = bv_name; + ch_free( a->a_nvals[0].bv_val ); + a->a_nvals[0] = bv_nname; + +#if 0 + fprintf( stderr, "### lastmodType: %s %s\n", lastmodType[ lmt ].bv_val, lastmodType[ lmt ].bv_val ); +#endif + + a = attr_find( lmi->lmi_e->e_attrs, lastmod_schema.lms_ad_lastmodType ); + if ( a == NULL ) { + goto error_return; + } + ch_free( a->a_vals[0].bv_val ); + ber_dupbv( &a->a_vals[0], &lastmodType[ lmt ] ); + ch_free( a->a_nvals[0].bv_val ); + ber_dupbv( &a->a_nvals[0], &lastmodType[ lmt ] ); + +#if 0 + fprintf( stderr, "### modifiersName: %s %s\n", bv_modifiersName.bv_val, bv_nmodifiersName.bv_val ); +#endif + + a = attr_find( lmi->lmi_e->e_attrs, slap_schema.si_ad_modifiersName ); + if ( a == NULL ) { + goto error_return; + } + ch_free( a->a_vals[0].bv_val ); + a->a_vals[0] = bv_modifiersName; + ch_free( a->a_nvals[0].bv_val ); + a->a_nvals[0] = bv_nmodifiersName; + +#if 0 + fprintf( stderr, "### modifyTimestamp: %s %s\n", bv_nmodifyTimestamp.bv_val, bv_modifyTimestamp.bv_val ); +#endif + + a = attr_find( lmi->lmi_e->e_attrs, slap_schema.si_ad_modifyTimestamp ); + if ( a == NULL ) { + goto error_return; + } + ch_free( a->a_vals[0].bv_val ); + a->a_vals[0] = bv_modifyTimestamp; + ch_free( a->a_nvals[0].bv_val ); + a->a_nvals[0] = bv_nmodifyTimestamp; + +#if 0 + fprintf( stderr, "### entryCSN: %s %s\n", bv_nentryCSN.bv_val, bv_entryCSN.bv_val ); +#endif + + a = attr_find( lmi->lmi_e->e_attrs, slap_schema.si_ad_entryCSN ); + if ( a == NULL ) { + goto error_return; + } + ch_free( a->a_vals[0].bv_val ); + a->a_vals[0] = bv_entryCSN; + ch_free( a->a_nvals[0].bv_val ); + a->a_nvals[0] = bv_nentryCSN; + + rc = 0; + +error_return:; + ldap_pvt_thread_mutex_unlock( &lmi->lmi_entry_mutex ); + + return rc; +} + +static int +lastmod_response( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + lastmod_info_t *lmi = (lastmod_info_t *)on->on_bi.bi_private; + + /* don't record failed operations */ + switch ( rs->sr_err ) { + case LDAP_SUCCESS: + /* FIXME: other cases? */ + break; + + default: + return SLAP_CB_CONTINUE; + } + + /* record only write operations */ + switch ( op->o_tag ) { + case LDAP_REQ_ADD: + case LDAP_REQ_MODIFY: + case LDAP_REQ_MODRDN: + case LDAP_REQ_DELETE: + break; + + case LDAP_REQ_EXTENDED: + /* if write, process */ + if ( exop_is_write( op )) + break; + + /* fall thru */ + default: + return SLAP_CB_CONTINUE; + } + + /* skip if disabled */ + ldap_pvt_thread_mutex_lock( &lmi->lmi_entry_mutex ); + if ( !lmi->lmi_enabled ) { + ldap_pvt_thread_mutex_unlock( &lmi->lmi_entry_mutex ); + return SLAP_CB_CONTINUE; + } + ldap_pvt_thread_mutex_unlock( &lmi->lmi_entry_mutex ); + + (void)lastmod_update( op, rs ); + + return SLAP_CB_CONTINUE; +} + +static int +lastmod_db_init( BackendDB *be, ConfigReply *cr ) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + lastmod_info_t *lmi; + + if ( lastmod_schema.lms_oc_lastmod == NULL ) { + int i; + const char *text; + + /* schema integration */ + for ( i = 0; mat[i].schema; i++ ) { + int code; + AttributeDescription **ad = + ((AttributeDescription **)&(((char *)&lastmod_schema)[mat[i].offset])); + ad[0] = NULL; + + code = register_at( mat[i].schema, ad, 0 ); + if ( code ) { + Debug( LDAP_DEBUG_ANY, + "lastmod_init: register_at failed\n", 0, 0, 0 ); + return -1; + } + (*ad)->ad_type->sat_flags |= mat[i].flags; + } + + for ( i = 0; moc[i].schema; i++ ) { + int code; + ObjectClass **Oc = + ((ObjectClass **)&(((char *)&lastmod_schema)[moc[i].offset])); + + code = register_oc( moc[i].schema, Oc, 0 ); + if ( code ) { + Debug( LDAP_DEBUG_ANY, + "lastmod_init: register_oc failed\n", 0, 0, 0 ); + return -1; + } + (*Oc)->soc_flags |= moc[i].flags; + } + } + + lmi = (lastmod_info_t *)ch_malloc( sizeof( lastmod_info_t ) ); + + memset( lmi, 0, sizeof( lastmod_info_t ) ); + lmi->lmi_enabled = 1; + + on->on_bi.bi_private = lmi; + + return 0; +} + +static int +lastmod_db_config( + BackendDB *be, + const char *fname, + int lineno, + int argc, + char **argv +) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + lastmod_info_t *lmi = (lastmod_info_t *)on->on_bi.bi_private; + + if ( strcasecmp( argv[ 0 ], "lastmod-rdnvalue" ) == 0 ) { + if ( lmi->lmi_rdnvalue.bv_val ) { + /* already defined! */ + ch_free( lmi->lmi_rdnvalue.bv_val ); + } + + ber_str2bv( argv[ 1 ], 0, 1, &lmi->lmi_rdnvalue ); + + } else if ( strcasecmp( argv[ 0 ], "lastmod-enabled" ) == 0 ) { + if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) { + lmi->lmi_enabled = 1; + + } else if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) { + lmi->lmi_enabled = 0; + + } else { + return -1; + } + + } else { + return SLAP_CONF_UNKNOWN; + } + + return 0; +} + +static int +lastmod_db_open( BackendDB *be, ConfigReply *cr ) +{ + slap_overinst *on = (slap_overinst *) be->bd_info; + lastmod_info_t *lmi = (lastmod_info_t *)on->on_bi.bi_private; + char buf[ 8192 ]; + static char tmbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; + + char csnbuf[ LDAP_PVT_CSNSTR_BUFSIZE ]; + struct berval entryCSN; + struct berval timestamp; + + if ( !SLAP_LASTMOD( be ) ) { + fprintf( stderr, "set \"lastmod on\" to make this overlay effective\n" ); + return -1; + } + + /* + * Start + */ + timestamp.bv_val = tmbuf; + timestamp.bv_len = sizeof(tmbuf); + slap_timestamp( &starttime, ×tamp ); + + entryCSN.bv_val = csnbuf; + entryCSN.bv_len = sizeof( csnbuf ); + slap_get_csn( NULL, &entryCSN, 0 ); + + if ( BER_BVISNULL( &lmi->lmi_rdnvalue ) ) { + ber_str2bv( "Lastmod", 0, 1, &lmi->lmi_rdnvalue ); + } + + snprintf( buf, sizeof( buf ), + "dn: cn=%s%s%s\n" + "objectClass: %s\n" + "structuralObjectClass: %s\n" + "cn: %s\n" + "description: This object contains the last modification to this database\n" + "%s: cn=%s%s%s\n" + "%s: %s\n" + "%s: %s\n" + "createTimestamp: %s\n" + "creatorsName: %s\n" + "entryCSN: %s\n" + "modifyTimestamp: %s\n" + "modifiersName: %s\n" + "hasSubordinates: FALSE\n", + lmi->lmi_rdnvalue.bv_val, BER_BVISEMPTY( &be->be_suffix[ 0 ] ) ? "" : ",", be->be_suffix[ 0 ].bv_val, + lastmod_schema.lms_oc_lastmod->soc_cname.bv_val, + lastmod_schema.lms_oc_lastmod->soc_cname.bv_val, + lmi->lmi_rdnvalue.bv_val, + lastmod_schema.lms_ad_lastmodDN->ad_cname.bv_val, + lmi->lmi_rdnvalue.bv_val, BER_BVISEMPTY( &be->be_suffix[ 0 ] ) ? "" : ",", be->be_suffix[ 0 ].bv_val, + lastmod_schema.lms_ad_lastmodType->ad_cname.bv_val, lastmodType[ LASTMOD_ADD ].bv_val, + lastmod_schema.lms_ad_lastmodEnabled->ad_cname.bv_val, lmi->lmi_enabled ? "TRUE" : "FALSE", + tmbuf, + BER_BVISNULL( &be->be_rootdn ) ? SLAPD_ANONYMOUS : be->be_rootdn.bv_val, + entryCSN.bv_val, + tmbuf, + BER_BVISNULL( &be->be_rootdn ) ? SLAPD_ANONYMOUS : be->be_rootdn.bv_val ); + +#if 0 + fprintf( stderr, "# entry:\n%s\n", buf ); +#endif + + lmi->lmi_e = str2entry( buf ); + if ( lmi->lmi_e == NULL ) { + return -1; + } + + ldap_pvt_thread_mutex_init( &lmi->lmi_entry_mutex ); + + return 0; +} + +static int +lastmod_db_destroy( BackendDB *be, ConfigReply *cr ) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + lastmod_info_t *lmi = (lastmod_info_t *)on->on_bi.bi_private; + + if ( lmi ) { + if ( !BER_BVISNULL( &lmi->lmi_rdnvalue ) ) { + ch_free( lmi->lmi_rdnvalue.bv_val ); + } + + if ( lmi->lmi_e ) { + entry_free( lmi->lmi_e ); + + ldap_pvt_thread_mutex_destroy( &lmi->lmi_entry_mutex ); + } + + ch_free( lmi ); + } + + return 0; +} + +/* This overlay is set up for dynamic loading via moduleload. For static + * configuration, you'll need to arrange for the slap_overinst to be + * initialized and registered by some other function inside slapd. + */ + +static slap_overinst lastmod; + +int +lastmod_initialize() +{ + lastmod.on_bi.bi_type = "lastmod"; + lastmod.on_bi.bi_db_init = lastmod_db_init; + lastmod.on_bi.bi_db_config = lastmod_db_config; + lastmod.on_bi.bi_db_destroy = lastmod_db_destroy; + lastmod.on_bi.bi_db_open = lastmod_db_open; + + lastmod.on_bi.bi_op_add = lastmod_op_func; + lastmod.on_bi.bi_op_compare = lastmod_op_func; + lastmod.on_bi.bi_op_delete = lastmod_op_func; + lastmod.on_bi.bi_op_modify = lastmod_op_func; + lastmod.on_bi.bi_op_modrdn = lastmod_op_func; + lastmod.on_bi.bi_op_search = lastmod_op_func; + lastmod.on_bi.bi_extended = lastmod_op_func; + + lastmod.on_response = lastmod_response; + + return overlay_register( &lastmod ); +} + +#if SLAPD_OVER_LASTMOD == SLAPD_MOD_DYNAMIC +int +init_module( int argc, char *argv[] ) +{ + return lastmod_initialize(); +} +#endif /* SLAPD_OVER_LASTMOD == SLAPD_MOD_DYNAMIC */ + +#endif /* defined(SLAPD_OVER_LASTMOD) */ diff --git a/contrib/slapd-modules/lastmod/slapo-lastmod.5 b/contrib/slapd-modules/lastmod/slapo-lastmod.5 new file mode 100644 index 0000000..88a19cf --- /dev/null +++ b/contrib/slapd-modules/lastmod/slapo-lastmod.5 @@ -0,0 +1,185 @@ +.\" Copyright 2004-2021 The OpenLDAP Foundation All Rights Reserved. +.\" Copying restrictions apply. See COPYRIGHT/LICENSE. +.TH SLAPO_LASTMOD 5 "RELEASEDATE" "OpenLDAP LDVERSION" +.SH NAME +slapo-lastmod \- Last Modification overlay +.SH SYNOPSIS +ETCDIR/slapd.conf +.SH DESCRIPTION +.LP +The +.B lastmod +overlay creates a service entry rooted at the suffix of the database +it's stacked onto, which holds the DN, the modification type, +the modifiersName and the modifyTimestamp of the last write operation +performed on that database. +The lastmod overlay cannot be used when the "lastmod" feature +is disabled, i.e. "lastmod off" is used. +.P +All operations targeted at the DN of the lastmod entry are rejected, +except reads, i.e. searches with +.B base +scope. +Regular operations are ignored, unless they result in writing; then, +in case of success, the lastmod entry is updated accordingly, +if possible. + +.SH CONFIGURATION +These +.B slapd.conf +configuration options apply to the lastmod overlay. They must appear +after the +.B overlay +directive. +.TP +.B lastmod-rdnvalue <RDN value> +Specify the value of the RDN used for the service entry. By default +.I Lastmod +is used. +.TP +.B lastmod-enabled {yes|no} +Specify whether the overlay must be enabled or not at startup. +By default, the overlay is enabled; however, by changing the boolean +value of the attribute +.IR lastmodEnabled , +one can affect the status of the overlay. +This is useful, for instance, to inhibit the overlay from keeping track +of large bulk loads or deletions. + +.SH OBJECT CLASS +The +.B lastmod +overlay depends on the +.B lastmod +objectClass. The definition of that class is as follows: +.LP +.RS 4 +( 1.3.6.1.4.1.4203.666.3.13 " + NAME 'lastmod' + DESC 'OpenLDAP per-database last modification monitoring' + STRUCTURAL + SUP top + MUST ( cn $ lastmodDN $ lastmodType ) + MAY ( description $ seeAlso ) ) +.RE + +.SH ATTRIBUTES +.P +Each one of the sections below details the meaning and use of a particular +attribute of this +.B lastmod +objectClass. +Most of the attributes that are specific to the lastmod objectClass are +operational, since they can logically be altered only by the DSA. +The most notable exception is the +.I lastmodEnabled +attributeType, which can be altered via protocol to change the status +of the overlay. +.P + +.B lastmodEnabled +.P +This attribute contains a boolean flag that determines the status +of the overlay. It can be altered via protocol by issuing a modify +operation that replaces the value of the attribute. +.LP +.RS 4 +( 1.3.6.1.4.1.4203.666.1.30 + NAME 'lastmodEnabled' + DESC 'Lastmod overlay state' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 + EQUALITY booleanMatch + SINGLE-VALUE ) +.RE + +.SH OPERATIONAL ATTRIBUTES +.P +Each one of the sections below details the meaning and use of a particular +attribute of this +.B lastmod +objectClass. +Most of the attributes that are specific to the lastmod objectClass are +operational, since they can logically be altered only by the DSA. +.P + +.B lastmodDN +.P +This attribute contains the distinguished name of the entry +that was last modified within the naming context of a database. +.LP +.RS 4 +( 1.3.6.1.4.1.4203.666.1.28 + NAME 'lastmodDN' + DESC 'DN of last modification' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + NO-USER-MODIFICATION + USAGE directoryOperation ) +.RE + +.B lastmodType +.P +This attribute contains the type of the modification that occurred +to the last modified entry. Legal values are +.BR add , +.BR delete , +.BR exop , +.BR modify , +.B modrdn +and +.BR unknown . +The latter should only be used as a fall-thru in case of unhandled +request types that are considered equivalent to a write operation. +.LP +.RS 4 +( 1.3.6.1.4.1.4203.666.1.29 + NAME 'lastmodType' + DESC 'Type of last modification' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + EQUALITY caseIgnoreMatch + SINGLE-VALUE + NO-USER-MODIFICATION + USAGE directoryOperation ) +.RE + + +.SH EXAMPLES +.LP +.RS +.nf +database bdb +suffix dc=example,dc=com +\... +overlay lastmod +lastmod-rdnvalue "Last Modification" +.fi +.RE + +.SH SEE ALSO +.BR ldap (3), +.BR slapd.conf (5), +.LP +"OpenLDAP Administrator's Guide" (http://www.OpenLDAP.org/doc/admin/) +.LP + +.SH BUGS +It is unclear whether this overlay can safely interoperate +with other overlays. +If the underlying backend does not implement entry_get/entry_release +handlers, modrdn update can become tricky. +The code needs some cleanup and more consistent error handling. +So far, the OIDs for the schema haven't been assigned yet. + +.SH ACKNOWLEDGEMENTS +.P +This module was written in 2004 by Pierangelo Masarati in fulfillment +of requirements from SysNet s.n.c.; this man page has been copied +from +.BR slapo-ppolicy (5), +and most of the overlays ever written are copied from Howard Chu's +first overlays. +.P +.B OpenLDAP +is developed and maintained by The OpenLDAP Project (http://www.openldap.org/). +.B OpenLDAP +is derived from University of Michigan LDAP 3.3 Release. diff --git a/contrib/slapd-modules/noopsrch/Makefile b/contrib/slapd-modules/noopsrch/Makefile new file mode 100644 index 0000000..ab1babe --- /dev/null +++ b/contrib/slapd-modules/noopsrch/Makefile @@ -0,0 +1,58 @@ +# $OpenLDAP$ +# This work is part of OpenLDAP Software <http://www.openldap.org/>. +# +# Copyright 1998-2021 The OpenLDAP Foundation. +# Copyright 2004 Howard Chu, Symas Corp. All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted only as authorized by the OpenLDAP +# Public License. +# +# A copy of this license is available in the file LICENSE in the +# top-level directory of the distribution or, alternatively, at +# <http://www.OpenLDAP.org/license.html>. + +LDAP_SRC = ../../.. +LDAP_BUILD = $(LDAP_SRC) +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +CC = gcc +OPT = -g -O2 -Wall +DEFS = -DSLAPD_OVER_NOOPSRCH=SLAPD_MOD_DYNAMIC +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) + +PROGRAMS = noopsrch.la +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +noopsrch.la: noopsrch.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + diff --git a/contrib/slapd-modules/noopsrch/noopsrch.c b/contrib/slapd-modules/noopsrch/noopsrch.c new file mode 100644 index 0000000..57522ac --- /dev/null +++ b/contrib/slapd-modules/noopsrch/noopsrch.c @@ -0,0 +1,254 @@ +/* noopsrch.c - LDAP Control that counts entries a search would return */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2010-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by Pierangelo Masarati for inclusion + * in OpenLDAP Software. + */ + +#include "portable.h" + +/* define SLAPD_OVER_NOOPSRCH=2 to build as run-time loadable module */ +#ifdef SLAPD_OVER_NOOPSRCH + +/* + * Control OID + */ +#define LDAP_CONTROL_X_NOOPSRCH "1.3.6.1.4.1.4203.666.5.18" + +#include "slap.h" +#include "ac/string.h" + +#define o_noopsrch o_ctrlflag[noopsrch_cid] +#define o_ctrlnoopsrch o_controls[noopsrch_cid] + +static int noopsrch_cid; +static slap_overinst noopsrch; + +static int +noopsrch_parseCtrl ( + Operation *op, + SlapReply *rs, + LDAPControl *ctrl ) +{ + if ( op->o_noopsrch != SLAP_CONTROL_NONE ) { + rs->sr_text = "No-op Search control specified multiple times"; + return LDAP_PROTOCOL_ERROR; + } + + if ( !BER_BVISNULL( &ctrl->ldctl_value ) ) { + rs->sr_text = "No-op Search control value is present"; + return LDAP_PROTOCOL_ERROR; + } + + op->o_ctrlnoopsrch = (void *)NULL; + + op->o_noopsrch = ctrl->ldctl_iscritical + ? SLAP_CONTROL_CRITICAL + : SLAP_CONTROL_NONCRITICAL; + + rs->sr_err = LDAP_SUCCESS; + + return rs->sr_err; +} + +int dummy; + +typedef struct noopsrch_cb_t { + slap_overinst *nc_on; + ber_int_t nc_nentries; + ber_int_t nc_nsearchref; + AttributeName *nc_save_attrs; + int *nc_pdummy; + int nc_save_slimit; +} noopsrch_cb_t; + +static int +noopsrch_response( Operation *op, SlapReply *rs ) +{ + noopsrch_cb_t *nc = (noopsrch_cb_t *)op->o_callback->sc_private; + + /* if the control is global, limits are not computed yet */ + if ( nc->nc_pdummy == &dummy ) { + nc->nc_save_slimit = op->ors_slimit; + op->ors_slimit = SLAP_NO_LIMIT; + nc->nc_pdummy = NULL; + } + + if ( rs->sr_type == REP_SEARCH ) { + nc->nc_nentries++; +#ifdef NOOPSRCH_DEBUG + Debug( LDAP_DEBUG_TRACE, "noopsrch_response(REP_SEARCH): nentries=%d\n", nc->nc_nentries, 0, 0 ); +#endif + return 0; + + } else if ( rs->sr_type == REP_SEARCHREF ) { + nc->nc_nsearchref++; + return 0; + + } else if ( rs->sr_type == REP_RESULT ) { + BerElementBuffer berbuf; + BerElement *ber = (BerElement *) &berbuf; + struct berval ctrlval; + LDAPControl *ctrl, *ctrlsp[2]; + int rc = rs->sr_err; + + if ( nc->nc_save_slimit >= 0 && nc->nc_nentries >= nc->nc_save_slimit ) { + rc = LDAP_SIZELIMIT_EXCEEDED; + } + +#ifdef NOOPSRCH_DEBUG + Debug( LDAP_DEBUG_TRACE, "noopsrch_response(REP_RESULT): err=%d nentries=%d nref=%d\n", rc, nc->nc_nentries, nc->nc_nsearchref ); +#endif + + ber_init2( ber, NULL, LBER_USE_DER ); + + ber_printf( ber, "{iii}", rc, nc->nc_nentries, nc->nc_nsearchref ); + if ( ber_flatten2( ber, &ctrlval, 0 ) == -1 ) { + ber_free_buf( ber ); + if ( op->o_noopsrch == SLAP_CONTROL_CRITICAL ) { + return LDAP_CONSTRAINT_VIOLATION; + } + return SLAP_CB_CONTINUE; + } + + ctrl = op->o_tmpcalloc( 1, + sizeof( LDAPControl ) + ctrlval.bv_len + 1, + op->o_tmpmemctx ); + ctrl->ldctl_value.bv_val = (char *)&ctrl[ 1 ]; + ctrl->ldctl_oid = LDAP_CONTROL_X_NOOPSRCH; + ctrl->ldctl_iscritical = 0; + ctrl->ldctl_value.bv_len = ctrlval.bv_len; + AC_MEMCPY( ctrl->ldctl_value.bv_val, ctrlval.bv_val, ctrlval.bv_len ); + ctrl->ldctl_value.bv_val[ ctrl->ldctl_value.bv_len ] = '\0'; + + ber_free_buf( ber ); + + ctrlsp[0] = ctrl; + ctrlsp[1] = NULL; + slap_add_ctrls( op, rs, ctrlsp ); + } + return SLAP_CB_CONTINUE; +} + +static int +noopsrch_cleanup( Operation *op, SlapReply *rs ) +{ + if ( rs->sr_type == REP_RESULT || rs->sr_err == SLAPD_ABANDON ) { + noopsrch_cb_t *nc = (noopsrch_cb_t *)op->o_callback->sc_private; + op->ors_attrs = nc->nc_save_attrs; + if ( nc->nc_pdummy == NULL ) { + op->ors_slimit = nc->nc_save_slimit; + } + + op->o_tmpfree( op->o_callback, op->o_tmpmemctx ); + op->o_callback = NULL; + } + + return SLAP_CB_CONTINUE; +} + +static int +noopsrch_op_search( Operation *op, SlapReply *rs ) +{ + if ( op->o_noopsrch != SLAP_CONTROL_NONE ) { + slap_callback *sc; + noopsrch_cb_t *nc; + + sc = op->o_tmpcalloc( 1, sizeof( slap_callback ) + sizeof( noopsrch_cb_t ), op->o_tmpmemctx ); + + nc = (noopsrch_cb_t *)&sc[ 1 ]; + nc->nc_on = (slap_overinst *)op->o_bd->bd_info; + nc->nc_nentries = 0; + nc->nc_nsearchref = 0; + nc->nc_save_attrs = op->ors_attrs; + nc->nc_pdummy = &dummy; + + sc->sc_response = noopsrch_response; + sc->sc_cleanup = noopsrch_cleanup; + sc->sc_private = (void *)nc; + + op->ors_attrs = slap_anlist_no_attrs; + + sc->sc_next = op->o_callback->sc_next; + op->o_callback->sc_next = sc; + } + + return SLAP_CB_CONTINUE; +} + +static int noopsrch_cnt; + +static int +noopsrch_db_init( BackendDB *be, ConfigReply *cr) +{ + if ( noopsrch_cnt++ == 0 ) { + int rc; + + rc = register_supported_control( LDAP_CONTROL_X_NOOPSRCH, + SLAP_CTRL_SEARCH | SLAP_CTRL_GLOBAL_SEARCH, NULL, + noopsrch_parseCtrl, &noopsrch_cid ); + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, + "noopsrch_initialize: Failed to register control '%s' (%d)\n", + LDAP_CONTROL_X_NOOPSRCH, rc, 0 ); + return rc; + } + } + + return LDAP_SUCCESS; +} + +static int +noopsrch_db_destroy( BackendDB *be, ConfigReply *cr ) +{ + assert( noopsrch_cnt > 0 ); + +#ifdef SLAP_CONFIG_DELETE + overlay_unregister_control( be, LDAP_CONTROL_X_NOOPSRCH ); + if ( --noopsrch_cnt == 0 ) { + unregister_supported_control( LDAP_CONTROL_X_NOOPSRCH ); + } + +#endif /* SLAP_CONFIG_DELETE */ + + return 0; +} + +#if SLAPD_OVER_NOOPSRCH == SLAPD_MOD_DYNAMIC +static +#endif /* SLAPD_OVER_NOOPSRCH == SLAPD_MOD_DYNAMIC */ +int +noopsrch_initialize( void ) +{ + + noopsrch.on_bi.bi_type = "noopsrch"; + + noopsrch.on_bi.bi_db_init = noopsrch_db_init; + noopsrch.on_bi.bi_db_destroy = noopsrch_db_destroy; + noopsrch.on_bi.bi_op_search = noopsrch_op_search; + + return overlay_register( &noopsrch ); +} + +#if SLAPD_OVER_NOOPSRCH == SLAPD_MOD_DYNAMIC +int +init_module( int argc, char *argv[] ) +{ + return noopsrch_initialize(); +} +#endif /* SLAPD_OVER_NOOPSRCH == SLAPD_MOD_DYNAMIC */ + +#endif /* SLAPD_OVER_NOOPSRCH */ diff --git a/contrib/slapd-modules/nops/Makefile b/contrib/slapd-modules/nops/Makefile new file mode 100644 index 0000000..eda7b47 --- /dev/null +++ b/contrib/slapd-modules/nops/Makefile @@ -0,0 +1,46 @@ +# $OpenLDAP$ + +LDAP_SRC = ../../.. +LDAP_BUILD = $(LDAP_SRC) +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +CC = gcc +OPT = -g -O2 -Wall +DEFS = -DSLAPD_OVER_NOPS=SLAPD_MOD_DYNAMIC +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) + +PROGRAMS = nops.la +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +nops.la: nops.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + diff --git a/contrib/slapd-modules/nops/nops.c b/contrib/slapd-modules/nops/nops.c new file mode 100644 index 0000000..c0d5088 --- /dev/null +++ b/contrib/slapd-modules/nops/nops.c @@ -0,0 +1,177 @@ +/* nops.c - Overlay to filter idempotent operations */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2008-2021 The OpenLDAP Foundation. + * Copyright 2008 Emmanuel Dreyfus. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This work was originally developed by the Emmanuel Dreyfus for + * inclusion in OpenLDAP Software. + */ +#include "portable.h" + +#ifdef SLAPD_OVER_NOPS + +#include <stdio.h> + +#include <ac/string.h> +#include <ac/socket.h> + +#include "lutil.h" +#include "slap.h" +#include "config.h" + +static ConfigDriver nops_cf_gen; + +static int nops_cf_gen( ConfigArgs *c ) { return 0; } + +static void +nops_rm_mod( Modifications **mods, Modifications *mod ) { + Modifications *next, *m; + + next = mod->sml_next; + if (*mods == mod) { + *mods = next; + } else { + Modifications *m; + + for (m = *mods; m; m = m->sml_next) { + if (m->sml_next == mod) { + m->sml_next = next; + break; + } + } + } + + mod->sml_next = NULL; + slap_mods_free(mod, 1); + + return; +} + +static int +nops_modify( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; + Backend *be = op->o_bd; + Entry *target_entry = NULL; + Modifications *m; + int rc; + + if ((m = op->orm_modlist) == NULL) { + op->o_bd->bd_info = (BackendInfo *)(on->on_info); + send_ldap_error(op, rs, LDAP_INVALID_SYNTAX, + "nops() got null orm_modlist"); + return(rs->sr_err); + } + + op->o_bd = on->on_info->oi_origdb; + rc = be_entry_get_rw(op, &op->o_req_ndn, NULL, NULL, 0, &target_entry); + op->o_bd = be; + + if (rc != 0 || target_entry == NULL) + return 0; + + /* + * For each attribute modification, check if the + * modification and the old entry are the same. + */ + while (m) { + int i, j; + int found; + Attribute *a; + BerVarray bm; + BerVarray bt; + Modifications *mc; + + mc = m; + m = m->sml_next; + + /* Check only replace sub-operations */ + if ((mc->sml_op & LDAP_MOD_OP) != LDAP_MOD_REPLACE) + continue; + + /* If there is no values, skip */ + if (((bm = mc->sml_values ) == NULL ) || (bm[0].bv_val == NULL)) + continue; + + /* If the attribute does not exist in old entry, skip */ + if ((a = attr_find(target_entry->e_attrs, mc->sml_desc)) == NULL) + continue; + if ((bt = a->a_vals) == NULL) + continue; + + /* For each value replaced, do we find it in old entry? */ + found = 0; + for (i = 0; bm[i].bv_val; i++) { + for (j = 0; bt[j].bv_val; j++) { + if (bm[i].bv_len != bt[j].bv_len) + continue; + if (memcmp(bm[i].bv_val, bt[j].bv_val, bt[j].bv_len) != 0) + continue; + + found++; + break; + } + } + + /* Did we find as many values as we had in old entry? */ + if (i != a->a_numvals || found != a->a_numvals) + continue; + + /* This is a nop, remove it */ + Debug(LDAP_DEBUG_TRACE, "removing nop on %s%s%s", + a->a_desc->ad_cname.bv_val, "", ""); + + nops_rm_mod(&op->orm_modlist, mc); + } + if (target_entry) { + op->o_bd = on->on_info->oi_origdb; + be_entry_release_r(op, target_entry); + op->o_bd = be; + } + + if ((m = op->orm_modlist) == NULL) { + slap_callback *cb = op->o_callback; + + op->o_bd->bd_info = (BackendInfo *)(on->on_info); + op->o_callback = NULL; + send_ldap_error(op, rs, LDAP_SUCCESS, ""); + op->o_callback = cb; + + return (rs->sr_err); + } + + return SLAP_CB_CONTINUE; +} + +static slap_overinst nops_ovl; + +#if SLAPD_OVER_NOPS == SLAPD_MOD_DYNAMIC +static +#endif +int +nops_initialize( void ) { + nops_ovl.on_bi.bi_type = "nops"; + nops_ovl.on_bi.bi_op_modify = nops_modify; + return overlay_register( &nops_ovl ); +} + +#if SLAPD_OVER_NOPS == SLAPD_MOD_DYNAMIC +int init_module(int argc, char *argv[]) { + return nops_initialize(); +} +#endif + +#endif /* defined(SLAPD_OVER_NOPS) */ + diff --git a/contrib/slapd-modules/nops/slapo-nops.5 b/contrib/slapd-modules/nops/slapo-nops.5 new file mode 100644 index 0000000..ac8f19d --- /dev/null +++ b/contrib/slapd-modules/nops/slapo-nops.5 @@ -0,0 +1,32 @@ +.TH SLAPO-NOPS 5 "RELEASEDATE" "OpenLDAP LDVERSION" +.\" Copyright 2008 Emmanuel Dreyfus +.\" Copying restrictions apply. See COPYRIGHT/LICENSE. +.\" $OpenLDAP$ +.SH NAME +slapo-nops \- Remove Null Operations Overlay to slapd +.SH SYNOPSIS +ETCDIR/slapd.conf +.SH DESCRIPTION +Some broken client tend to implement modifications as replace operations +where all attributes are replaced, most of the time by the same values +they had before. This can cause undesirable load on logs, ACL evaluation, +or replication trafic. + +This overlay detects idempotent replace operations and filter them out. +.SH CONFIGURATION +This overlay had no specific configuration. +.SH EXAMPLES +.LP +.RS +.nf +overlay nops +.RE +.SH FILES +.TP +ETCDIR/slapd.conf +default slapd configuration file +.SH SEE ALSO +.BR slapd.conf (5). +.SH ACKNOWLEDGEMENTS +This module was written in 2008 by Emmanuel Dreyfus. +.so ../Project diff --git a/contrib/slapd-modules/nssov/Makefile b/contrib/slapd-modules/nssov/Makefile new file mode 100644 index 0000000..a69ec4d --- /dev/null +++ b/contrib/slapd-modules/nssov/Makefile @@ -0,0 +1,73 @@ +# $OpenLDAP$ +# This work is part of OpenLDAP Software <http://www.openldap.org/>. +# +# Copyright 2008-2021 The OpenLDAP Foundation. +# Portions Copyright 2008 Howard Chu, Symas Corp. All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted only as authorized by the OpenLDAP +# Public License. +# +# A copy of this license is available in the file LICENSE in the +# top-level directory of the distribution or, alternatively, at +# <http://www.OpenLDAP.org/license.html>. + +# Path to the OpenLDAP source tree +LDAP_SRC=../../.. + +# Path to the OpenLDAP object tree - same as above unless +# you're doing out-of-tree builds. +LDAP_BUILD=$(LDAP_SRC) + +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +NLDAPD_INC=-Inss-pam-ldapd + +LIBTOOL = $(LDAP_BUILD)/libtool +OPT = -g -O2 -Wall +CC = gcc +DEFS = +INCS = $(LDAP_INC) $(NLDAPD_INC) +LIBS = $(LDAP_LIB) + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) +sysconfdir = $(prefix)/etc$(ldap_subdir) +schemadir = $(sysconfdir)/schema + +all: nssov.la + +XOBJS = tio.lo + +OBJS = alias.lo ether.lo group.lo host.lo netgroup.lo network.lo \ + nssov.lo passwd.lo protocol.lo rpc.lo service.lo shadow.lo pam.lo + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +tio.lo: nss-pam-ldapd/tio.c + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $? + +$(OBJS): nssov.h + +nssov.la: $(OBJS) $(XOBJS) + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info 0:0:0 \ + -rpath $(moduledir) -module -o $@ $(OBJS) $(XOBJS) $(LIBS) + +install: nssov.la + mkdir -p $(DESTDIR)$(moduledir) + $(LIBTOOL) --mode=install cp nssov.la $(DESTDIR)$(moduledir) + cp ldapns.schema $(DESTDIR)$(schemadir) + +clean: + rm -f *.*o *.la .libs/* + rm -rf .libs diff --git a/contrib/slapd-modules/nssov/README b/contrib/slapd-modules/nssov/README new file mode 100644 index 0000000..28d6286 --- /dev/null +++ b/contrib/slapd-modules/nssov/README @@ -0,0 +1,134 @@ +This directory contains a slapd overlay, nssov, that handles +NSS lookup requests through a local Unix Domain socket. It uses the +same IPC protocol as Arthur de Jong's nss-ldapd, and a complete +copy of the nss-ldapd source is included here. It also handles +PAM requests. + +To use this code, you will need the client-side stuf library from +nss-pam-ldapd. You can get it from: +http://arthurdejong.org/nss-pam-ldapd +You will not need the nslcd daemon; this overlay replaces that part. +To disable building of the nslcd daemon in nss-pam-ldapd, add the +--disable-nslcd option to the nss-pam-ldapd configure script. You +should already be familiar with the RFC2307 and RFC2307bis schema +to use this overlay. See the nss-pam-ldapd README for more information +on the schema and which features are supported. + +To use the overlay, add: + + include <path to>nis.schema + + moduleload <path to>nssov.so + ... + + database hdb + ... + overlay nssov + +to your slapd configuration file. (The nis.schema file contains +the original RFC2307 schema. Some modifications will be needed to +use RFC2307bis.) + +The overlay may be configured with Service Search Descriptors (SSDs) +for each NSS service that will be used. SSDs are configured using + + nssov-ssd <service> <url> + +where the <service> may be one of + aliases + ethers + group + hosts + netgroup + networks + passwd + protocols + rpc + services + shadow + +and the <url> must be of the form + ldap:///[<basedn>][??[<scope>][?<filter>]] + +The <basedn> will default to the first suffix of the current database. +The <scope> defaults to "subtree". The default <filter> depends on which +service is being used. + +If the local database is actually a proxy to a foreign LDAP server, some +mapping of schema may be needed. Some simple attribute substitutions may +be performed using + + nssov-map <service> <orig> <new> + +See the nss-ldapd/README for the original attribute names used in this code. + +The overlay also supports dynamic configuration in cn=config. The layout +of the config entry is + + dn: olcOverlay={0}nssov,ocDatabase={1}hdb,cn=config + objectClass: olcOverlayConfig + objectClass: olcNssOvConfig + olcOverlay: {0}nssov + olcNssSsd: passwd ldap:///ou=users,dc=example,dc=com??one + olcNssMap: passwd uid accountName + +which enables the passwd service, and uses the accountName attribute to +fetch what is usually retrieved from the uid attribute. + +PAM authentication, account management, session management, and password +management are supported. + +Authentication is performed using Simple Binds. Since all operations occur +inside the slapd overlay, "fake" connections are used and they are +inherently secure. Two methods of mapping the PAM username to an LDAP DN +are provided: + the mapping can be accomplished using slapd's authz-regexp facility. In +this case, a DN of the form + cn=<service>+uid=<user>,cn=<hostname>,cn=pam,cn=auth +is fed into the regexp matcher. If a match is produced, the resulting DN +is used. + otherwise, the NSS passwd map is invoked (which means it must already +be configured). + +If no DN is found, the overlay returns PAM_USER_UNKNOWN. If the DN is +found, and Password Policy is supported, then the Bind will use the +Password Policy control and return expiration information to PAM. + +Account management also uses two methods. These methods depend on the +ldapns.schema included with the nssov source. + The first is identical to the method used in PADL's pam_ldap module: +host and authorizedService attributes may be looked up in the user's entry, +and checked to determine access. Also a check may be performed to see if +the user is a member of a particular group. This method is pretty +inflexible and doesn't scale well to large networks of users, hosts, +and services. + The second uses slapd's ACL engine to check if the user has "compare" +privilege on an ipHost object whose name matches the current hostname, and +whose authorizedService attribute matches the current service name. This +method is preferred, since it allows authorization to be centralized in +the ipHost entries instead of scattered across the entire user population. +The ipHost entries must have an authorizedService attribute (e.g. by way +of the authorizedServiceObject auxiliary class) to use this method. + +Session management: the overlay may optionally add a "logged in" attribute +to a user's entry for successful logins, and delete the corresponding +value upon logout. The attribute value is of the form + <generalizedTime> <host> <service> <tty> (<ruser@rhost>) + +Password management: the overlay will perform a PasswordModify exop +in the server for the given user. + +--- +This work is part of OpenLDAP Software <http://www.openldap.org/>. + +Copyright 1998-2021 The OpenLDAP Foundation. +Portions Copyright 2008-2009 Howard Chu, Symas Corp. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted only as authorized by the OpenLDAP +Public License. + +A copy of this license is available in the file LICENSE in the +top-level directory of the distribution or, alternatively, at +<http://www.OpenLDAP.org/license.html>. + diff --git a/contrib/slapd-modules/nssov/alias.c b/contrib/slapd-modules/nssov/alias.c new file mode 100644 index 0000000..92d6f13 --- /dev/null +++ b/contrib/slapd-modules/nssov/alias.c @@ -0,0 +1,116 @@ +/* alias.c - mail alias lookup routines */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2008-2021 The OpenLDAP Foundation. + * Portions Copyright 2008 by Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This code references portions of the nss-ldapd package + * written by Arthur de Jong. The nss-ldapd code was forked + * from the nss-ldap library written by Luke Howard. + */ + +#include "nssov.h" + +/* Vendor-specific attributes and object classes. + * (Mainly from Sun.) + * ( 1.3.6.1.4.1.42.2.27.1.2.5 NAME 'nisMailAlias' SUP top STRUCTURAL + * DESC 'NIS mail alias' + * MUST cn + * MAY rfc822MailMember ) + */ + +/* the basic search filter for searches */ +static struct berval alias_filter = BER_BVC("(objectClass=nisMailAlias)"); + +/* the attributes to request with searches */ +static struct berval alias_keys[] = { + BER_BVC("cn"), + BER_BVC("rfc822MailMember"), + BER_BVNULL +}; + +NSSOV_INIT(alias) + +NSSOV_CBPRIV(alias, + struct berval name; + char buf[256];); + +static int write_alias(nssov_alias_cbp *cbp,Entry *entry) +{ + int32_t tmpint32,tmp2int32,tmp3int32; + struct berval tmparr[2], empty; + struct berval *names, *members; + Attribute *a; + int i; + + /* get the name of the alias */ + if (BER_BVISNULL(&cbp->name)) + { + a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[0].an_desc); + if ( !a ) + { + Debug(LDAP_DEBUG_ANY,"alias entry %s does not contain %s value\n", + entry->e_name.bv_val,cbp->mi->mi_attrs[0].an_desc->ad_cname.bv_val,0 ); + return 0; + } + names = a->a_vals; + } + else + { + names=tmparr; + names[0]=cbp->name; + BER_BVZERO(&names[1]); + } + /* get the members of the alias */ + a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[1].an_desc); + if ( !a ) { + BER_BVZERO( &empty ); + members = ∅ + } else { + members = a->a_vals; + } + /* for each name, write an entry */ + for (i=0;!BER_BVISNULL(&names[i]);i++) + { + WRITE_INT32(cbp->fp,NSLCD_RESULT_BEGIN); + WRITE_BERVAL(cbp->fp,&names[i]); + WRITE_BVARRAY(cbp->fp,members); + } + return 0; +} + +NSSOV_CB(alias) + +NSSOV_HANDLE( + alias,byname, + char fbuf[1024]; + struct berval filter = {sizeof(fbuf)}; + filter.bv_val = fbuf; + READ_STRING(fp,cbp.buf); + cbp.name.bv_len = tmpint32; + cbp.name.bv_val = cbp.buf;, + Debug(LDAP_DEBUG_TRACE,"nssov_alias_byname(%s)\n",cbp.name.bv_val,0,0);, + NSLCD_ACTION_ALIAS_BYNAME, + nssov_filter_byname(cbp.mi,0,&cbp.name,&filter) +) + +NSSOV_HANDLE( + alias,all, + struct berval filter; + /* no parameters to read */ + BER_BVZERO(&cbp.name);, + Debug(LDAP_DEBUG,"nssov_alias_all()\n",0,0,0);, + NSLCD_ACTION_ALIAS_ALL, + (filter=cbp.mi->mi_filter,0) +) diff --git a/contrib/slapd-modules/nssov/ether.c b/contrib/slapd-modules/nssov/ether.c new file mode 100644 index 0000000..e96a815 --- /dev/null +++ b/contrib/slapd-modules/nssov/ether.c @@ -0,0 +1,167 @@ +/* ether.c - ethernet address lookup routines */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2008-2021 The OpenLDAP Foundation. + * Copyright 2008 by Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This code references portions of the nss-ldapd package + * written by Arthur de Jong. The nss-ldapd code was forked + * from the nss-ldap library written by Luke Howard. + */ + +#include "nssov.h" + +struct ether_addr { + uint8_t ether_addr_octet[6]; +}; + +/* ( nisSchema.2.11 NAME 'ieee802Device' SUP top AUXILIARY + * DESC 'A device with a MAC address; device SHOULD be + * used as a structural class' + * MAY macAddress ) + */ + +/* the basic search filter for searches */ +static struct berval ether_filter = BER_BVC("(objectClass=ieee802Device)"); + +/* the attributes to request with searches */ +static struct berval ether_keys[] = { + BER_BVC("cn"), + BER_BVC("macAddress"), + BER_BVNULL +}; + +NSSOV_INIT(ether) + +NSSOV_CBPRIV(ether, + char buf[256]; + struct berval name; + struct berval addr;); + +#define WRITE_ETHER(fp,addr) \ + {int ao[6]; \ + sscanf(addr.bv_val,"%02x:%02x:%02x:%02x:%02x:%02x", \ + &ao[0], &ao[1], &ao[2], &ao[3], &ao[4], &ao[5] );\ + tmpaddr.ether_addr_octet[0] = ao[0]; \ + tmpaddr.ether_addr_octet[1] = ao[1]; \ + tmpaddr.ether_addr_octet[2] = ao[2]; \ + tmpaddr.ether_addr_octet[3] = ao[3]; \ + tmpaddr.ether_addr_octet[4] = ao[4]; \ + tmpaddr.ether_addr_octet[5] = ao[5]; } \ + WRITE(fp,&tmpaddr,sizeof(uint8_t[6])); + +static int write_ether(nssov_ether_cbp *cbp,Entry *entry) +{ + int32_t tmpint32; + struct ether_addr tmpaddr; + struct berval tmparr[2]; + struct berval *names,*ethers; + Attribute *a; + int i,j; + + /* get the name of the ether entry */ + if (BER_BVISNULL(&cbp->name)) + { + a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[0].an_desc); + if ( !a ) + { + Debug(LDAP_DEBUG_ANY,"ether entry %s does not contain %s value\n", + entry->e_name.bv_val,cbp->mi->mi_attrs[0].an_desc->ad_cname.bv_val,0 ); + return 0; + } + names = a->a_vals; + } + else + { + names=tmparr; + names[0]=cbp->name; + BER_BVZERO(&names[1]); + } + /* get the addresses */ + if (BER_BVISNULL(&cbp->addr)) + { + a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[1].an_desc); + if ( !a ) + { + Debug(LDAP_DEBUG_ANY,"ether entry %s does not contain %s value\n", + entry->e_name.bv_val,cbp->mi->mi_attrs[1].an_desc->ad_cname.bv_val,0 ); + return 0; + } + ethers = a->a_vals; + /* TODO: move parsing of addresses up here */ + } + else + { + ethers=tmparr; + ethers[0]=cbp->addr; + BER_BVZERO(ðers[1]); + } + /* write entries for all names and addresses */ + for (i=0;!BER_BVISNULL(&names[i]);i++) + for (j=0;!BER_BVISNULL(ðers[j]);j++) + { + WRITE_INT32(cbp->fp,NSLCD_RESULT_BEGIN); + WRITE_BERVAL(cbp->fp,&names[i]); + WRITE_ETHER(cbp->fp,ethers[j]); + } + return 0; +} + +NSSOV_CB(ether) + +NSSOV_HANDLE( + ether,byname, + char fbuf[1024]; + struct berval filter = {sizeof(fbuf)}; + filter.bv_val = fbuf; + BER_BVZERO(&cbp.addr); + READ_STRING(fp,cbp.buf); + cbp.name.bv_len = tmpint32; + cbp.name.bv_val = cbp.buf;, + Debug(LDAP_DEBUG_TRACE,"nssov_ether_byname(%s)\n",cbp.name.bv_val,0,0);, + NSLCD_ACTION_ETHER_BYNAME, + nssov_filter_byname(cbp.mi,0,&cbp.name,&filter) +) + +NSSOV_HANDLE( + ether,byether, + struct ether_addr addr; + char fbuf[1024]; + struct berval filter = {sizeof(fbuf)}; + filter.bv_val = fbuf; + BER_BVZERO(&cbp.name); + READ(fp,&addr,sizeof(uint8_t[6])); + cbp.addr.bv_len = snprintf(cbp.buf,sizeof(cbp.buf), "%x:%x:%x:%x:%x:%x", + addr.ether_addr_octet[0], + addr.ether_addr_octet[1], + addr.ether_addr_octet[2], + addr.ether_addr_octet[3], + addr.ether_addr_octet[4], + addr.ether_addr_octet[5]); + cbp.addr.bv_val = cbp.buf;, + Debug(LDAP_DEBUG_TRACE,"nssov_ether_byether(%s)\n",cbp.addr.bv_val,0,0);, + NSLCD_ACTION_ETHER_BYETHER, + nssov_filter_byid(cbp.mi,1,&cbp.addr,&filter) +) + +NSSOV_HANDLE( + ether,all, + struct berval filter; + /* no parameters to read */ + BER_BVZERO(&cbp.name); + BER_BVZERO(&cbp.addr);, + Debug(LDAP_DEBUG_TRACE,"nssov_ether_all()\n",0,0,0);, + NSLCD_ACTION_ETHER_ALL, + (filter=cbp.mi->mi_filter,0) +) diff --git a/contrib/slapd-modules/nssov/group.c b/contrib/slapd-modules/nssov/group.c new file mode 100644 index 0000000..f6d2dd2 --- /dev/null +++ b/contrib/slapd-modules/nssov/group.c @@ -0,0 +1,346 @@ +/* group.c - group lookup routines */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2008-2021 The OpenLDAP Foundation. + * Portions Copyright 2008-2009 by Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This code references portions of the nss-ldapd package + * written by Arthur de Jong. The nss-ldapd code was forked + * from the nss-ldap library written by Luke Howard. + */ + +#include "nssov.h" + +/* for gid_t */ +#include <grp.h> + +/* ( nisSchema.2.2 NAME 'posixGroup' SUP top STRUCTURAL + * DESC 'Abstraction of a group of accounts' + * MUST ( cn $ gidNumber ) + * MAY ( userPassword $ memberUid $ description ) ) + * + * apart from that the above the uniqueMember attributes may be + * supported in a coming release (they map to DNs, which is an extra + * lookup step) + * + * using nested groups (groups that are member of a group) is currently + * not supported, this may be added in a later release + */ + +/* the basic search filter for searches */ +static struct berval group_filter = BER_BVC("(objectClass=posixGroup)"); + +/* the attributes to request with searches */ +static struct berval group_keys[] = { + BER_BVC("cn"), + BER_BVC("userPassword"), + BER_BVC("gidNumber"), + BER_BVC("memberUid"), + BER_BVC("uniqueMember"), + BER_BVNULL +}; + +#define CN_KEY 0 +#define PWD_KEY 1 +#define GID_KEY 2 +#define UID_KEY 3 +#define MEM_KEY 4 + +/* default values for attributes */ +static struct berval default_group_userPassword = BER_BVC("*"); /* unmatchable */ + +NSSOV_CBPRIV(group, + nssov_info *ni; + char buf[256]; + struct berval name; + struct berval gidnum; + struct berval user; + int wantmembers;); + +/* create a search filter for searching a group entry + by member uid, return -1 on errors */ +static int mkfilter_group_bymember(nssov_group_cbp *cbp,struct berval *buf) +{ + struct berval dn; + /* try to translate uid to DN */ + nssov_uid2dn(cbp->op,cbp->ni,&cbp->user,&dn); + if (BER_BVISNULL(&dn)) { + if (cbp->user.bv_len + cbp->mi->mi_filter.bv_len + cbp->mi->mi_attrs[UID_KEY].an_desc->ad_cname.bv_len + 6 > + buf->bv_len ) + return -1; + buf->bv_len = snprintf(buf->bv_val, buf->bv_len, "(&%s(%s=%s))", + cbp->mi->mi_filter.bv_val, cbp->mi->mi_attrs[UID_KEY].an_desc->ad_cname.bv_val, + cbp->user.bv_val ); + } else { /* also lookup using user DN */ + if (cbp->user.bv_len + cbp->mi->mi_filter.bv_len + cbp->mi->mi_attrs[UID_KEY].an_desc->ad_cname.bv_len + + dn.bv_len + cbp->mi->mi_attrs[MEM_KEY].an_desc->ad_cname.bv_len + 12 > buf->bv_len ) + return -1; + buf->bv_len = snprintf(buf->bv_val, buf->bv_len, "(&%s(|(%s=%s)(%s=%s)))", + cbp->mi->mi_filter.bv_val, + cbp->mi->mi_attrs[UID_KEY].an_desc->ad_cname.bv_val, cbp->user.bv_val, + cbp->mi->mi_attrs[MEM_KEY].an_desc->ad_cname.bv_val, dn.bv_val ); + } + return 0; +} + +NSSOV_INIT(group) + +/* + Checks to see if the specified name is a valid group name. + + This test is based on the definition from POSIX (IEEE Std 1003.1, 2004, + 3.189 Group Name and 3.276 Portable Filename Character Set): + http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_189 + http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_276 + + The standard defines group names valid if they only contain characters from + the set [A-Za-z0-9._-] where the hyphen should not be used as first + character. +*/ +static int isvalidgroupname(struct berval *name) +{ + int i; + + if ( !name->bv_val || !name->bv_len ) + return 0; + /* check first character */ + if ( ! ( (name->bv_val[0]>='A' && name->bv_val[0] <= 'Z') || + (name->bv_val[0]>='a' && name->bv_val[0] <= 'z') || + (name->bv_val[0]>='0' && name->bv_val[0] <= '9') || + name->bv_val[0]=='.' || name->bv_val[0]=='_' ) ) + return 0; + /* check other characters */ + for (i=1;i<name->bv_len;i++) + { +#ifndef STRICT_GROUPS + /* allow spaces too */ + if (name->bv_val[i] == ' ') continue; +#endif + if ( ! ( (name->bv_val[i]>='A' && name->bv_val[i] <= 'Z') || + (name->bv_val[i]>='a' && name->bv_val[i] <= 'z') || + (name->bv_val[i]>='0' && name->bv_val[i] <= '9') || + name->bv_val[i]=='.' || name->bv_val[i]=='_' || name->bv_val[i]=='-') ) + return 0; + } + /* no test failed so it must be good */ + return -1; +} + +static int write_group(nssov_group_cbp *cbp,Entry *entry) +{ + struct berval tmparr[2], tmpgid[2]; + struct berval *names,*gids,*members; + struct berval passwd = {0}; + Attribute *a; + int i,j,nummembers,rc = 0; + + /* get group name (cn) */ + if (BER_BVISNULL(&cbp->name)) + { + a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[CN_KEY].an_desc); + if ( !a ) + { + Debug(LDAP_DEBUG_ANY,"group entry %s does not contain %s value\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[CN_KEY].an_desc->ad_cname.bv_val,0); + return 0; + } + names = a->a_vals; + } + else + { + names=tmparr; + names[0]=cbp->name; + BER_BVZERO(&names[1]); + } + /* get the group id(s) */ + if (BER_BVISNULL(&cbp->gidnum)) + { + a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[GID_KEY].an_desc); + if ( !a ) + { + Debug(LDAP_DEBUG_ANY,"group entry %s does not contain %s value\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[GID_KEY].an_desc->ad_cname.bv_val,0); + return 0; + } + gids = a->a_vals; + } + else + { + gids=tmpgid; + gids[0]=cbp->gidnum; + BER_BVZERO(&gids[1]); + } + /* get group passwd (userPassword) (use only first entry) */ + a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[PWD_KEY].an_desc); + if (a) + get_userpassword(&a->a_vals[0], &passwd); + if (BER_BVISNULL(&passwd)) + passwd=default_group_userPassword; + /* get group members (memberUid&uniqueMember) */ + if (cbp->wantmembers) { + Attribute *b; + i = 0; j = 0; + a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[UID_KEY].an_desc); + b = attr_find(entry->e_attrs, cbp->mi->mi_attrs[MEM_KEY].an_desc); + if ( a ) + i += a->a_numvals; + if ( b ) + i += b->a_numvals; + if ( i ) { + members = cbp->op->o_tmpalloc( (i+1) * sizeof(struct berval), cbp->op->o_tmpmemctx ); + + if ( a ) { + for (i=0; i<a->a_numvals; i++) { + if (isvalidusername(&a->a_vals[i])) { + ber_dupbv_x(&members[j],&a->a_vals[i],cbp->op->o_tmpmemctx); + j++; + } + } + } + a = b; + if ( a ) { + for (i=0; i<a->a_numvals; i++) { + if (nssov_dn2uid(cbp->op,cbp->ni,&a->a_nvals[i],&members[j])) + j++; + } + } + nummembers = j; + BER_BVZERO(&members[j]); + } else { + members=NULL; + nummembers = 0; + } + + } else { + members=NULL; + nummembers = 0; + } + /* write entries for all names and gids */ + for (i=0;!BER_BVISNULL(&names[i]);i++) + { + if (!isvalidgroupname(&names[i])) + { + Debug(LDAP_DEBUG_ANY,"nssov: group entry %s contains invalid group name: \"%s\"\n", + entry->e_name.bv_val,names[i].bv_val,0); + } + else + { + for (j=0;!BER_BVISNULL(&gids[j]);j++) + { + char *tmp; + int tmpint32; + gid_t gid; + gid = strtol(gids[j].bv_val, &tmp, 0); + if ( *tmp ) { + Debug(LDAP_DEBUG_ANY,"nssov: group entry %s contains non-numeric %s value: \"%s\"\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[GID_KEY].an_desc->ad_cname.bv_val, + names[i].bv_val); + continue; + } + WRITE_INT32(cbp->fp,NSLCD_RESULT_BEGIN); + WRITE_BERVAL(cbp->fp,&names[i]); + WRITE_BERVAL(cbp->fp,&passwd); + WRITE_INT32(cbp->fp,gid); + /* write a list of values */ + WRITE_INT32(cbp->fp,nummembers); + if (nummembers) + { + int k; + for (k=0;k<nummembers;k++) { + WRITE_BERVAL(cbp->fp,&members[k]); + } + } + } + } + } + /* free and return */ + if (members!=NULL) + ber_bvarray_free_x( members, cbp->op->o_tmpmemctx ); + return rc; +} + +NSSOV_CB(group) + +NSSOV_HANDLE( + group,byname, + char fbuf[1024]; + struct berval filter = {sizeof(fbuf)}; + filter.bv_val = fbuf; + READ_STRING(fp,cbp.buf); + cbp.name.bv_len = tmpint32; + cbp.name.bv_val = cbp.buf; + if (!isvalidgroupname(&cbp.name)) { + Debug(LDAP_DEBUG_ANY,"nssov_group_byname(%s): invalid group name\n",cbp.name.bv_val,0,0); + return -1; + } + cbp.wantmembers = 1; + cbp.ni = ni; + BER_BVZERO(&cbp.gidnum); + BER_BVZERO(&cbp.user);, + Debug(LDAP_DEBUG_TRACE,"nslcd_group_byname(%s)\n",cbp.name.bv_val,0,0);, + NSLCD_ACTION_GROUP_BYNAME, + nssov_filter_byname(cbp.mi,CN_KEY,&cbp.name,&filter) +) + +NSSOV_HANDLE( + group,bygid, + gid_t gid; + char fbuf[1024]; + struct berval filter = {sizeof(fbuf)}; + filter.bv_val = fbuf; + READ_INT32(fp,gid); + cbp.gidnum.bv_val = cbp.buf; + cbp.gidnum.bv_len = snprintf(cbp.buf,sizeof(cbp.buf),"%d",gid); + cbp.wantmembers = 1; + cbp.ni = ni; + BER_BVZERO(&cbp.name); + BER_BVZERO(&cbp.user);, + Debug(LDAP_DEBUG_TRACE,"nssov_group_bygid(%s)\n",cbp.gidnum.bv_val,0,0);, + NSLCD_ACTION_GROUP_BYGID, + nssov_filter_byid(cbp.mi,GID_KEY,&cbp.gidnum,&filter) +) + +NSSOV_HANDLE( + group,bymember, + char fbuf[1024]; + struct berval filter = {sizeof(fbuf)}; + filter.bv_val = fbuf; + READ_STRING(fp,cbp.buf); + cbp.user.bv_len = tmpint32; + cbp.user.bv_val = cbp.buf; + if (!isvalidusername(&cbp.user)) { + Debug(LDAP_DEBUG_ANY,"nssov_group_bymember(%s): invalid user name\n",cbp.user.bv_val,0,0); + return -1; + } + cbp.wantmembers = 0; + cbp.ni = ni; + BER_BVZERO(&cbp.name); + BER_BVZERO(&cbp.gidnum);, + Debug(LDAP_DEBUG_TRACE,"nssov_group_bymember(%s)\n",cbp.user.bv_val,0,0);, + NSLCD_ACTION_GROUP_BYMEMBER, + mkfilter_group_bymember(&cbp,&filter) +) + +NSSOV_HANDLE( + group,all, + struct berval filter; + /* no parameters to read */ + cbp.wantmembers = 1; + cbp.ni = ni; + BER_BVZERO(&cbp.name); + BER_BVZERO(&cbp.gidnum);, + Debug(LDAP_DEBUG_TRACE,"nssov_group_all()\n",0,0,0);, + NSLCD_ACTION_GROUP_ALL, + (filter=cbp.mi->mi_filter,0) +) diff --git a/contrib/slapd-modules/nssov/host.c b/contrib/slapd-modules/nssov/host.c new file mode 100644 index 0000000..0fea935 --- /dev/null +++ b/contrib/slapd-modules/nssov/host.c @@ -0,0 +1,161 @@ +/* host.c - host lookup routines */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2008-2021 The OpenLDAP Foundation. + * Portions Copyright 2008 by Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This code references portions of the nss-ldapd package + * written by Arthur de Jong. The nss-ldapd code was forked + * from the nss-ldap library written by Luke Howard. + */ + +#include "nssov.h" + +/* ( nisSchema.2.6 NAME 'ipHost' SUP top AUXILIARY + * DESC 'Abstraction of a host, an IP device. The distinguished + * value of the cn attribute denotes the host's canonical + * name. Device SHOULD be used as a structural class' + * MUST ( cn $ ipHostNumber ) + * MAY ( l $ description $ manager ) ) + */ + +/* the basic search filter for searches */ +static struct berval host_filter = BER_BVC("(objectClass=ipHost)"); + +/* the attributes to request with searches */ +static struct berval host_keys[] = { + BER_BVC("cn"), + BER_BVC("ipHostNumber"), + BER_BVNULL +}; + +NSSOV_INIT(host) + +NSSOV_CBPRIV(host, + char buf[1024]; + struct berval name; + struct berval addr;); + +/* write a single host entry to the stream */ +static int write_host(nssov_host_cbp *cbp,Entry *entry) +{ + int32_t tmpint32; + int numaddr,i,numname,dupname; + struct berval name,*names,*addrs; + Attribute *a; + + /* get the most canonical name */ + nssov_find_rdnval( &entry->e_nname, cbp->mi->mi_attrs[0].an_desc, &name ); + /* get the other names for the host */ + a = attr_find( entry->e_attrs, cbp->mi->mi_attrs[0].an_desc ); + if ( !a || !a->a_vals ) + { + Debug(LDAP_DEBUG_ANY,"host entry %s does not contain %s value\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[0].an_desc->ad_cname.bv_val, 0 ); + return 0; + } + names = a->a_vals; + numname = a->a_numvals; + /* if the name is not yet found, get the first entry from names */ + if (BER_BVISNULL(&name)) { + name=names[0]; + dupname = 0; + } else { + dupname = -1; + for (i=0; i<numname; i++) { + if ( bvmatch(&name, &a->a_nvals[i])) { + dupname = i; + break; + } + } + } + /* get the addresses */ + a = attr_find( entry->e_attrs, cbp->mi->mi_attrs[1].an_desc ); + if ( !a || !a->a_vals ) + { + Debug(LDAP_DEBUG_ANY,"host entry %s does not contain %s value\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[1].an_desc->ad_cname.bv_val, 0 ); + return 0; + } + addrs = a->a_vals; + numaddr = a->a_numvals; + /* write the entry */ + WRITE_INT32(cbp->fp,NSLCD_RESULT_BEGIN); + WRITE_BERVAL(cbp->fp,&name); + if ( dupname >= 0 ) { + WRITE_INT32(cbp->fp,numname-1); + } else { + WRITE_INT32(cbp->fp,numname); + } + for (i=0;i<numname;i++) { + if (i == dupname) continue; + WRITE_BERVAL(cbp->fp,&names[i]); + } + WRITE_INT32(cbp->fp,numaddr); + for (i=0;i<numaddr;i++) + { + WRITE_ADDRESS(cbp->fp,&addrs[i]); + } + return 0; +} + +NSSOV_CB(host) + +NSSOV_HANDLE( + host,byname, + char fbuf[1024]; + struct berval filter = {sizeof(fbuf)}; + filter.bv_val = fbuf; + BER_BVZERO(&cbp.addr); + READ_STRING(fp,cbp.buf); + cbp.name.bv_len = tmpint32; + cbp.name.bv_val = cbp.buf;, + Debug(LDAP_DEBUG_TRACE,"nssov_host_byname(%s)\n",cbp.name.bv_val,0,0);, + NSLCD_ACTION_HOST_BYNAME, + nssov_filter_byname(cbp.mi,0,&cbp.name,&filter) +) + +NSSOV_HANDLE( + host,byaddr, + int af; + char addr[64]; + int len=sizeof(addr); + char fbuf[1024]; + struct berval filter = {sizeof(fbuf)}; + filter.bv_val = fbuf; + BER_BVZERO(&cbp.name); + READ_ADDRESS(fp,addr,len,af); + /* translate the address to a string */ + if (inet_ntop(af,addr,cbp.buf,sizeof(cbp.buf))==NULL) + { + Debug(LDAP_DEBUG_ANY,"nssov: unable to convert address to string\n",0,0,0); + return -1; + } + cbp.addr.bv_val = cbp.buf; + cbp.addr.bv_len = strlen(cbp.buf);, + Debug(LDAP_DEBUG_TRACE,"nssov_host_byaddr(%s)\n",cbp.addr.bv_val,0,0);, + NSLCD_ACTION_HOST_BYADDR, + nssov_filter_byid(cbp.mi,1,&cbp.addr,&filter) +) + +NSSOV_HANDLE( + host,all, + struct berval filter; + /* no parameters to read */ + BER_BVZERO(&cbp.name); + BER_BVZERO(&cbp.addr);, + Debug(LDAP_DEBUG_TRACE,"nssov_host_all()\n",0,0,0);, + NSLCD_ACTION_HOST_ALL, + (filter=cbp.mi->mi_filter,0) +) diff --git a/contrib/slapd-modules/nssov/ldapns.schema b/contrib/slapd-modules/nssov/ldapns.schema new file mode 100644 index 0000000..f6f7c9f --- /dev/null +++ b/contrib/slapd-modules/nssov/ldapns.schema @@ -0,0 +1,38 @@ +# $OpenLDAP$ +# $Id: ldapns.schema,v 1.3 2009-10-01 19:17:20 tedcheng Exp $ +# LDAP Name Service Additional Schema +# http://www.iana.org/assignments/gssapi-service-names + +# +# Not part of the distribution: this is a workaround! +# + +attributetype ( 1.3.6.1.4.1.5322.17.2.1 NAME 'authorizedService' + DESC 'IANA GSS-API authorized service name' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} ) + +attributetype ( 1.3.6.1.4.1.5322.17.2.2 NAME 'loginStatus' + DESC 'Currently logged in sessions for a user' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + ORDERING caseIgnoreOrderingMatch + SYNTAX OMsDirectoryString ) + +objectclass ( 1.3.6.1.4.1.5322.17.1.1 NAME 'authorizedServiceObject' + DESC 'Auxiliary object class for adding authorizedService attribute' + SUP top + AUXILIARY + MAY authorizedService ) + +objectclass ( 1.3.6.1.4.1.5322.17.1.2 NAME 'hostObject' + DESC 'Auxiliary object class for adding host attribute' + SUP top + AUXILIARY + MAY host ) + +objectclass ( 1.3.6.1.4.1.5322.17.1.3 NAME 'loginStatusObject' + DESC 'Auxiliary object class for login status attribute' + SUP top + AUXILIARY + MAY loginStatus ) diff --git a/contrib/slapd-modules/nssov/netgroup.c b/contrib/slapd-modules/nssov/netgroup.c new file mode 100644 index 0000000..18694b6 --- /dev/null +++ b/contrib/slapd-modules/nssov/netgroup.c @@ -0,0 +1,199 @@ +/* netgroup.c - netgroup lookup routines */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2008-2021 The OpenLDAP Foundation. + * Portions Copyright 2008 by Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This code references portions of the nss-ldapd package + * written by Arthur de Jong. The nss-ldapd code was forked + * from the nss-ldap library written by Luke Howard. + */ + +#include "nssov.h" +#include <ac/ctype.h> + +/* ( nisSchema.2.8 NAME 'nisNetgroup' SUP top STRUCTURAL + * DESC 'Abstraction of a netgroup. May refer to other netgroups' + * MUST cn + * MAY ( nisNetgroupTriple $ memberNisNetgroup $ description ) ) + */ + +/* the basic search filter for searches */ +static struct berval netgroup_filter = BER_BVC("(objectClass=nisNetgroup)"); + +/* the attributes to request with searches */ +static struct berval netgroup_keys[] = { + BER_BVC("cn"), + BER_BVC("nisNetgroupTriple"), + BER_BVC("memberNisNetgroup"), + BER_BVNULL +}; + +NSSOV_INIT(netgroup) + +NSSOV_CBPRIV(netgroup, + char buf[256]; + struct berval name;); + +static int write_string_stripspace_len(TFILE *fp,const char *str,int len) +{ + int32_t tmpint32; + int i,j; + DEBUG_PRINT("WRITE_STRING: var="__STRING(str)" string=\"%s\"",str); + if (str==NULL) + { + WRITE_INT32(fp,0); + } + else + { + /* skip leading spaces */ + for (i=0;(str[i]!='\0')&&(isspace(str[i]));i++) + /* nothing else to do */ ; + /* skip trailing spaces */ + for (j=len;(j>i)&&(isspace(str[j-1]));j--) + /* nothing else to do */ ; + /* write length of string */ + WRITE_INT32(fp,j-i); + /* write string itself */ + if (j>i) + { + WRITE(fp,str+i,j-i); + } + } + /* we're done */ + return 0; +} + +#define WRITE_STRING_STRIPSPACE_LEN(fp,str,len) \ + if (write_string_stripspace_len(fp,str,len)) \ + return -1; + +#define WRITE_STRING_STRIPSPACE(fp,str) \ + WRITE_STRING_STRIPSPACE_LEN(fp,str,strlen(str)) + +static int write_netgroup_triple(TFILE *fp,const char *triple) +{ + int32_t tmpint32; + int i; + int hostb,hoste,userb,usere,domainb,domaine; + /* skip leading spaces */ + for (i=0;(triple[i]!='\0')&&(isspace(triple[i]));i++) + /* nothing else to do */ ; + /* we should have a bracket now */ + if (triple[i]!='(') + { + Debug(LDAP_DEBUG_ANY,"write_netgroup_triple(): entry does not begin with '(' (entry skipped)\n",0,0,0); + return 0; + } + i++; + hostb=i; + /* find comma (end of host string) */ + for (;(triple[i]!='\0')&&(triple[i]!=',');i++) + /* nothing else to do */ ; + if (triple[i]!=',') + { + Debug(LDAP_DEBUG_ANY,"write_netgroup_triple(): missing ',' (entry skipped)\n",0,0,0); + return 0; + } + hoste=i; + i++; + userb=i; + /* find comma (end of user string) */ + for (;(triple[i]!='\0')&&(triple[i]!=',');i++) + /* nothing else to do */ ; + if (triple[i]!=',') + { + Debug(LDAP_DEBUG_ANY,"write_netgroup_triple(): missing ',' (entry skipped)\n",0,0,0); + return 0; + } + usere=i; + i++; + domainb=i; + /* find closing bracket (end of domain string) */ + for (;(triple[i]!='\0')&&(triple[i]!=')');i++) + /* nothing else to do */ ; + if (triple[i]!=')') + { + Debug(LDAP_DEBUG_ANY,"write_netgroup_triple(): missing ')' (entry skipped)\n",0,0,0); + return 0; + } + domaine=i; + i++; + /* skip trailing spaces */ + for (;(triple[i]!='\0')&&(isspace(triple[i]));i++) + /* nothing else to do */ ; + /* if anything is left in the string we have a problem */ + if (triple[i]!='\0') + { + Debug(LDAP_DEBUG_ANY,"write_netgroup_triple(): string contains trailing data (entry skipped)\n",0,0,0); + return 0; + } + /* write strings */ + WRITE_INT32(fp,NSLCD_RESULT_BEGIN); + WRITE_INT32(fp,NSLCD_NETGROUP_TYPE_TRIPLE); + WRITE_STRING_STRIPSPACE_LEN(fp,triple+hostb,hoste-hostb) + WRITE_STRING_STRIPSPACE_LEN(fp,triple+userb,usere-userb) + WRITE_STRING_STRIPSPACE_LEN(fp,triple+domainb,domaine-domainb) + /* we're done */ + return 0; +} + +static int write_netgroup(nssov_netgroup_cbp *cbp,Entry *entry) +{ + int32_t tmpint32; + int i; + Attribute *a; + + /* get the netgroup triples and member */ + a = attr_find(entry->e_attrs,cbp->mi->mi_attrs[1].an_desc); + if ( a ) { + /* write the netgroup triples */ + for (i=0;i<a->a_numvals;i++) + { + if (write_netgroup_triple(cbp->fp, a->a_vals[i].bv_val)) + return -1; + } + } + a = attr_find(entry->e_attrs,cbp->mi->mi_attrs[2].an_desc); + if ( a ) { + /* write netgroup members */ + for (i=0;i<a->a_numvals;i++) + { + /* write the result code */ + WRITE_INT32(cbp->fp,NSLCD_RESULT_BEGIN); + /* write triple indicator */ + WRITE_INT32(cbp->fp,NSLCD_NETGROUP_TYPE_NETGROUP); + /* write netgroup name */ + if (write_string_stripspace_len(cbp->fp,a->a_vals[i].bv_val,a->a_vals[i].bv_len)) + return -1; + } + } + /* we're done */ + return 0; +} + +NSSOV_CB(netgroup) + +NSSOV_HANDLE( + netgroup,byname, + char fbuf[1024]; + struct berval filter = {sizeof(fbuf)}; + filter.bv_val = fbuf; + READ_STRING(fp,cbp.buf);, + cbp.name.bv_len = tmpint32; + cbp.name.bv_val = cbp.buf; + Debug(LDAP_DEBUG_TRACE,"nssov_netgroup_byname(%s)\n",cbp.name.bv_val,0,0);, + NSLCD_ACTION_NETGROUP_BYNAME, + nssov_filter_byname(cbp.mi,0,&cbp.name,&filter) +) diff --git a/contrib/slapd-modules/nssov/network.c b/contrib/slapd-modules/nssov/network.c new file mode 100644 index 0000000..3098f36 --- /dev/null +++ b/contrib/slapd-modules/nssov/network.c @@ -0,0 +1,161 @@ +/* network.c - network address lookup routines */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2008-2021 The OpenLDAP Foundation. + * Portions Copyright 2008 by Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This code references portions of the nss-ldapd package + * written by Arthur de Jong. The nss-ldapd code was forked + * from the nss-ldap library written by Luke Howard. + */ + +#include "nssov.h" + +#include <ac/socket.h> + +/* ( nisSchema.2.7 NAME 'ipNetwork' SUP top STRUCTURAL + * DESC 'Abstraction of a network. The distinguished value of + * MUST ( cn $ ipNetworkNumber ) + * MAY ( ipNetmaskNumber $ l $ description $ manager ) ) + */ + +/* the basic search filter for searches */ +static struct berval network_filter = BER_BVC("(objectClass=ipNetwork)"); + +/* the attributes used in searches */ +static struct berval network_keys[] = { + BER_BVC("cn"), + BER_BVC("ipNetworkNumber"), + BER_BVNULL +}; + +NSSOV_INIT(network) + +NSSOV_CBPRIV(network, + char buf[1024]; + struct berval name; + struct berval addr;); + +/* write a single network entry to the stream */ +static int write_network(nssov_network_cbp *cbp,Entry *entry) +{ + int32_t tmpint32; + int numaddr,i,numname,dupname; + struct berval name, *names, *addrs; + Attribute *a; + + /* get the most canonical name */ + nssov_find_rdnval( &entry->e_nname, cbp->mi->mi_attrs[0].an_desc, &name); + /* get the other names for the network */ + a = attr_find( entry->e_attrs, cbp->mi->mi_attrs[0].an_desc ); + if ( !a || !a->a_vals ) + { + Debug(LDAP_DEBUG_ANY,"network entry %s does not contain %s value\n", + entry->e_name.bv_val,cbp->mi->mi_attrs[0].an_desc->ad_cname.bv_val,0); + return 0; + } + names = a->a_vals; + numname = a->a_numvals; + /* if the name is not yet found, get the first entry from names */ + if (BER_BVISNULL(&name)) { + name=names[0]; + dupname = 0; + } else { + dupname = -1; + for (i=0; i<numname; i++) { + if ( bvmatch(&name, &a->a_nvals[i])) { + dupname = i; + break; + } + } + } + /* get the addresses */ + a = attr_find( entry->e_attrs, cbp->mi->mi_attrs[1].an_desc ); + if ( !a || !a->a_vals ) + { + Debug(LDAP_DEBUG_ANY,"network entry %s does not contain %s value\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[1].an_desc->ad_cname.bv_val, 0 ); + return 0; + } + addrs = a->a_vals; + numaddr = a->a_numvals; + /* write the entry */ + WRITE_INT32(cbp->fp,NSLCD_RESULT_BEGIN); + WRITE_BERVAL(cbp->fp,&name); + if ( dupname >= 0 ) { + WRITE_INT32(cbp->fp,numname-1); + } else { + WRITE_INT32(cbp->fp,numname); + } + for (i=0;i<numname;i++) { + if (i == dupname) continue; + WRITE_BERVAL(cbp->fp,&names[i]); + } + WRITE_INT32(cbp->fp,numaddr); + for (i=0;i<numaddr;i++) + { + WRITE_ADDRESS(cbp->fp,&addrs[i]); + } + return 0; +} + +NSSOV_CB(network) + +NSSOV_HANDLE( + network,byname, + char fbuf[1024]; + struct berval filter = {sizeof(fbuf)}; + filter.bv_val = fbuf; + BER_BVZERO(&cbp.addr); + READ_STRING(fp,cbp.buf); + cbp.name.bv_len = tmpint32; + cbp.name.bv_val = cbp.buf;, + Debug(LDAP_DEBUG_TRACE,"nssov_network_byname(%s)\n",cbp.name.bv_val,0,0);, + NSLCD_ACTION_NETWORK_BYNAME, + nssov_filter_byname(cbp.mi,0,&cbp.name,&filter) +) + +NSSOV_HANDLE( + network,byaddr, + int af; + char addr[64]; + int len=sizeof(addr); + char fbuf[1024]; + struct berval filter = {sizeof(fbuf)}; + filter.bv_val = fbuf; + BER_BVZERO(&cbp.name); + READ_ADDRESS(fp,addr,len,af); + /* translate the address to a string */ + if (inet_ntop(af,addr,cbp.buf,sizeof(cbp.buf))==NULL) + { + Debug(LDAP_DEBUG_ANY,"nssov: unable to convert address to string\n",0,0,0); + return -1; + } + cbp.addr.bv_val = cbp.buf; + cbp.addr.bv_len = strlen(cbp.buf);, + Debug(LDAP_DEBUG_TRACE,"nslcd_network_byaddr(%s)\n",cbp.addr.bv_val,0,0);, + NSLCD_ACTION_NETWORK_BYADDR, + nssov_filter_byid(cbp.mi,1,&cbp.addr,&filter) +) + +NSSOV_HANDLE( + network,all, + struct berval filter; + /* no parameters to read */ + BER_BVZERO(&cbp.name); + BER_BVZERO(&cbp.addr);, + Debug(LDAP_DEBUG_TRACE,"nssov_network_all()\n",0,0,0);, + NSLCD_ACTION_NETWORK_ALL, + (filter=cbp.mi->mi_filter,0) +) diff --git a/contrib/slapd-modules/nssov/nss-pam-ldapd/README b/contrib/slapd-modules/nssov/nss-pam-ldapd/README new file mode 100644 index 0000000..4176ad7 --- /dev/null +++ b/contrib/slapd-modules/nssov/nss-pam-ldapd/README @@ -0,0 +1,15 @@ +These files were pulled from the nss-pam-ldapd project version 0.9.4. +Copyright notices are in the individual files. + +This is not the full distribution of nss-pam-ldapd, and does not +include the client-side stub libraries. Get the latest release of +nss-pam-ldapd from http://arthurdejong.org/nss-pam-ldapd/ to use +this overlay. + +If your system already has the nss-pam-ldapd stub libraries +installed, make sure the versions match the version number +shown above. Otherwise, there may be incompatible differences in +the protocols being used. Currently nssov requires at least +version 0.9.0. If your system's version is older, you will need +to install the client-side stubs from source. + diff --git a/contrib/slapd-modules/nssov/nss-pam-ldapd/attrs.h b/contrib/slapd-modules/nssov/nss-pam-ldapd/attrs.h new file mode 100644 index 0000000..83f1777 --- /dev/null +++ b/contrib/slapd-modules/nssov/nss-pam-ldapd/attrs.h @@ -0,0 +1,91 @@ +/* + attrs.h - wrapper macros for the gcc __attribute__(()) directive + + Copyright (C) 2007, 2008, 2012 Arthur de Jong + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA +*/ + +#ifndef COMPAT__ATTRS_H +#define COMPAT__ATTRS_H 1 + +/* macro for testing the version of GCC */ +#define GCC_VERSION(major, minor) \ + ((__GNUC__ > (major)) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor))) + +/* These are macros to use some gcc-specific flags in case the're available + and otherwise define them to empty strings. This allows us to give + the compiler some extra information. + See http://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html + for a list of attributes supported by gcc */ + +/* this is used to flag function parameters that are not used in the function + body. */ +#if GCC_VERSION(3, 0) +#define UNUSED(x) x __attribute__((__unused__)) +#else +#define UNUSED(x) x +#endif + +/* this is used to add extra format checking to the function calls as if this + was a printf()-like function */ +#if GCC_VERSION(3, 0) +#define LIKE_PRINTF(format_idx, arg_idx) \ + __attribute__((__format__(__printf__, format_idx, arg_idx))) +#else +#define LIKE_PRINTF(format_idx, arg_idx) /* no attribute */ +#endif + +/* indicates that the function is "pure": its result is purely based on + the parameters and has no side effects or used static data */ +#if GCC_VERSION(3, 0) +#define PURE __attribute__((__pure__)) +#else +#define PURE /* no attribute */ +#endif + +/* the function returns a new data structure that has been freshly + allocated */ +#if GCC_VERSION(3, 0) +#define LIKE_MALLOC __attribute__((__malloc__)) +#else +#define LIKE_MALLOC /* no attribute */ +#endif + +/* the function's return value should be used by the caller */ +#if GCC_VERSION(3, 4) +#define MUST_USE __attribute__((__warn_unused_result__)) +#else +#define MUST_USE /* no attribute */ +#endif + +/* the function's return value should be used by the caller */ +#if GCC_VERSION(2, 5) +#define NORETURN __attribute__((__noreturn__)) +#else +#define NORETURN /* no attribute */ +#endif + +/* define __STRING if it's not yet defined */ +#ifndef __STRING +#ifdef __STDC__ +#define __STRING(x) #x +#else /* __STDC__ */ +#define __STRING(x) "x" +#endif /* not __STDC__ */ +#endif /* not __STRING */ + +#endif /* not COMPAT__ATTRS_H */ diff --git a/contrib/slapd-modules/nssov/nss-pam-ldapd/nslcd-prot.h b/contrib/slapd-modules/nssov/nss-pam-ldapd/nslcd-prot.h new file mode 100644 index 0000000..649be89 --- /dev/null +++ b/contrib/slapd-modules/nssov/nss-pam-ldapd/nslcd-prot.h @@ -0,0 +1,381 @@ +/* + nslcd-prot.h - helper macros for reading and writing in protocol streams + + Copyright (C) 2006 West Consulting + Copyright (C) 2006-2014 Arthur de Jong + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA +*/ + +#ifndef COMMON__NSLCD_PROT_H +#define COMMON__NSLCD_PROT_H 1 + +#include <arpa/inet.h> +#include <netinet/in.h> + +#include "tio.h" + +/* If you use these macros you should define the following macros to + handle error conditions (these marcos should clean up and return from the + function): + ERROR_OUT_WRITEERROR(fp) + ERROR_OUT_READERROR(fp) + ERROR_OUT_BUFERROR(fp) + ERROR_OUT_NOSUCCESS(fp) */ + + +/* Debugging marcos that can be used to enable detailed protocol logging, + pass -DDEBUG_PROT to do overall protocol debugging, and -DDEBUG_PROT_DUMP + to dump the actual bytestream. */ + +#ifdef DEBUG_PROT +/* define a debugging macro to output logging */ +#include <string.h> +#include <errno.h> +#define DEBUG_PRINT(fmt, arg) \ + fprintf(stderr, "%s:%d:%s: " fmt "\n", __FILE__, __LINE__, \ + __PRETTY_FUNCTION__, arg); +#else /* DEBUG_PROT */ +/* define an empty debug macro to disable logging */ +#define DEBUG_PRINT(fmt, arg) +#endif /* not DEBUG_PROT */ + +#ifdef DEBUG_PROT_DUMP +/* define a debugging macro to output detailed logging */ +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif /* HAVE_STDINT_H */ +static void debug_dump(const void *ptr, size_t size) +{ + int i; + for (i = 0; i < size; i++) + fprintf(stderr, " %02x", ((const uint8_t *)ptr)[i]); + fprintf(stderr, "\n"); +} +#define DEBUG_DUMP(ptr, size) \ + fprintf(stderr, "%s:%d:%s:", __FILE__, __LINE__, __PRETTY_FUNCTION__); \ + debug_dump(ptr, size); +#else /* DEBUG_PROT_DUMP */ +/* define an empty debug macro to disable logging */ +#define DEBUG_DUMP(ptr, size) +#endif /* not DEBUG_PROT_DUMP */ + + +/* WRITE marcos, used for writing data, on write error they will + call the ERROR_OUT_WRITEERROR macro + these macros may require the availability of the following + variables: + int32_t tmpint32; - temporary variable + */ + +#define WRITE(fp, ptr, size) \ + DEBUG_PRINT("WRITE : var="__STRING(ptr)" size=%d", (int)size); \ + DEBUG_DUMP(ptr, size); \ + if (tio_write(fp, ptr, (size_t)size)) \ + { \ + DEBUG_PRINT("WRITE : var="__STRING(ptr)" error: %s", \ + strerror(errno)); \ + ERROR_OUT_WRITEERROR(fp); \ + } + +#define WRITE_INT32(fp, i) \ + DEBUG_PRINT("WRITE_INT32 : var="__STRING(i)" int32=%08x", (int)i); \ + tmpint32 = htonl((int32_t)(i)); \ + WRITE(fp, &tmpint32, sizeof(int32_t)) + +#define WRITE_STRING(fp, str) \ + DEBUG_PRINT("WRITE_STRING: var="__STRING(str)" string=\"%s\"", (str)); \ + if ((str) == NULL) \ + { \ + WRITE_INT32(fp, 0); \ + } \ + else \ + { \ + WRITE_INT32(fp, strlen(str)); \ + tmpint32 = ntohl(tmpint32); \ + if (tmpint32 > 0) \ + { \ + WRITE(fp, (str), tmpint32); \ + } \ + } + +#define WRITE_STRINGLIST(fp, arr) \ + if ((arr) == NULL) \ + { \ + DEBUG_PRINT("WRITE_STRLST: var="__STRING(arr)" num=%d", 0); \ + WRITE_INT32(fp, 0); \ + } \ + else \ + { \ + /* first determine length of array */ \ + for (tmp3int32 = 0; (arr)[tmp3int32] != NULL; tmp3int32++) \ + /* noting */ ; \ + /* write number of strings */ \ + DEBUG_PRINT("WRITE_STRLST: var="__STRING(arr)" num=%d", (int)tmp3int32); \ + WRITE_INT32(fp, tmp3int32); \ + /* write strings */ \ + for (tmp2int32 = 0; tmp2int32 < tmp3int32; tmp2int32++) \ + { \ + WRITE_STRING(fp, (arr)[tmp2int32]); \ + } \ + } + +#define WRITE_STRINGLIST_EXCEPT(fp, arr, not) \ + /* first determine length of array */ \ + tmp3int32 = 0; \ + for (tmp2int32 = 0; (arr)[tmp2int32] != NULL; tmp2int32++) \ + if (strcmp((arr)[tmp2int32], (not)) != 0) \ + tmp3int32++; \ + /* write number of strings (mius one because we intend to skip one) */ \ + DEBUG_PRINT("WRITE_STRLST: var="__STRING(arr)" num=%d", (int)tmp3int32); \ + WRITE_INT32(fp, tmp3int32); \ + /* write strings */ \ + for (tmp2int32 = 0; (arr)[tmp2int32] != NULL; tmp2int32++) \ + { \ + if (strcmp((arr)[tmp2int32], (not)) != 0) \ + { \ + WRITE_STRING(fp, (arr)[tmp2int32]); \ + } \ + } + +/* READ macros, used for reading data, on read error they will + call the ERROR_OUT_READERROR or ERROR_OUT_BUFERROR macro + these macros may require the availability of the following + variables: + int32_t tmpint32; - temporary variable + */ + +#define READ(fp, ptr, size) \ + if (tio_read(fp, ptr, (size_t)size)) \ + { \ + DEBUG_PRINT("READ : var="__STRING(ptr)" error: %s", \ + strerror(errno)); \ + ERROR_OUT_READERROR(fp); \ + } \ + DEBUG_PRINT("READ : var="__STRING(ptr)" size=%d", (int)(size)); \ + DEBUG_DUMP(ptr, size); + +#define READ_INT32(fp, i) \ + READ(fp, &tmpint32, sizeof(int32_t)); \ + (i) = (int32_t)ntohl(tmpint32); \ + DEBUG_PRINT("READ_INT32 : var="__STRING(i)" int32==%08x", (int)(i)); + +/* read a string in a fixed-size "normal" buffer */ +#define READ_STRING(fp, buffer) \ + /* read the size of the string */ \ + READ(fp, &tmpint32, sizeof(int32_t)); \ + tmpint32 = ntohl(tmpint32); \ + DEBUG_PRINT("READ_STRING: var="__STRING(buffer)" strlen=%d", tmpint32); \ + /* check if read would fit */ \ + if (((size_t)tmpint32) >= sizeof(buffer)) \ + { \ + /* will not fit */ \ + tmpint32 = (tmpint32 - sizeof(buffer)) + 1; \ + DEBUG_PRINT("READ : buffer %d bytes too small", tmpint32); \ + ERROR_OUT_BUFERROR(fp); \ + } \ + /* read string from the stream */ \ + if (tmpint32 > 0) \ + { \ + READ(fp, buffer, (size_t)tmpint32); \ + } \ + /* null-terminate string in buffer */ \ + buffer[tmpint32] = '\0'; \ + DEBUG_PRINT("READ_STRING: var="__STRING(buffer)" string=\"%s\"", buffer); + + +/* READ BUF macros that read data into a pre-allocated buffer. + these macros may require the availability of the following + variables: + int32_t tmpint32; - temporary variable + char *buffer; - pointer to a buffer for reading strings + size_t buflen; - the size of the buffer + size_t bufptr; - the current position in the buffer + */ + +/* current position in the buffer */ +#define BUF_CUR \ + (buffer + bufptr) + +/* check that the buffer has sz bytes left in it */ +#define BUF_CHECK(fp, sz) \ + if ((bufptr + (size_t)(sz)) > buflen) \ + { \ + /* will not fit */ \ + tmpint32 = bufptr + (sz) - (buflen); \ + DEBUG_PRINT("READ : buffer %d bytes too small", tmpint32); \ + ERROR_OUT_BUFERROR(fp); \ + } + +/* move the buffer pointer */ +#define BUF_SKIP(sz) \ + bufptr += (size_t)(sz); + +/* move BUF_CUR foreward so that it is aligned to the specified + type width */ +#define BUF_ALIGN(fp, type) \ + /* figure out number of bytes to skip foreward */ \ + tmp2int32 = (sizeof(type) - ((BUF_CUR - (char *)NULL) % sizeof(type))) \ + % sizeof(type); \ + /* check and skip */ \ + BUF_CHECK(fp, tmp2int32); \ + BUF_SKIP(tmp2int32); + +/* allocate a piece of the buffer to store an array in */ +#define BUF_ALLOC(fp, ptr, type, num) \ + /* align to the specified type width */ \ + BUF_ALIGN(fp, type); \ + /* check that we have enough room */ \ + BUF_CHECK(fp, (size_t)(num) * sizeof(type)); \ + /* store the pointer */ \ + (ptr) = (type *)BUF_CUR; \ + /* reserve the space */ \ + BUF_SKIP((size_t)(num) * sizeof(type)); + +/* read a binary blob into the buffer */ +#define READ_BUF(fp, ptr, sz) \ + /* check that there is enough room and read */ \ + BUF_CHECK(fp, sz); \ + READ(fp, BUF_CUR, (size_t)sz); \ + /* store pointer and skip */ \ + (ptr) = BUF_CUR; \ + BUF_SKIP(sz); + +/* read string in the buffer (using buffer, buflen and bufptr) + and store the actual location of the string in field */ +#define READ_BUF_STRING(fp, field) \ + /* read the size of the string */ \ + READ(fp, &tmpint32, sizeof(int32_t)); \ + tmpint32 = ntohl(tmpint32); \ + DEBUG_PRINT("READ_BUF_STRING: var="__STRING(field)" strlen=%d", tmpint32); \ + /* check if read would fit */ \ + BUF_CHECK(fp, tmpint32 + 1); \ + /* read string from the stream */ \ + if (tmpint32 > 0) \ + { \ + READ(fp, BUF_CUR, (size_t)tmpint32); \ + } \ + /* null-terminate string in buffer */ \ + BUF_CUR[tmpint32] = '\0'; \ + DEBUG_PRINT("READ_BUF_STRING: var="__STRING(field)" string=\"%s\"", BUF_CUR); \ + /* prepare result */ \ + (field) = BUF_CUR; \ + BUF_SKIP(tmpint32 + 1); + +/* read an array from a stram and store it as a null-terminated + array list (size for the array is allocated) */ +#define READ_BUF_STRINGLIST(fp, arr) \ + /* read the number of entries */ \ + READ(fp, &tmp3int32, sizeof(int32_t)); \ + tmp3int32 = ntohl(tmp3int32); \ + DEBUG_PRINT("READ_STRLST: var="__STRING(arr)" num=%d", (int)tmp3int32); \ + /* allocate room for *char[num + 1] */ \ + BUF_ALLOC(fp, arr, char *, tmp3int32 + 1); \ + /* read all entries */ \ + for (tmp2int32 = 0; tmp2int32 < tmp3int32; tmp2int32++) \ + { \ + READ_BUF_STRING(fp, (arr)[tmp2int32]); \ + } \ + /* set last entry to NULL */ \ + (arr)[tmp2int32] = NULL; + + +/* SKIP macros for skipping over certain parts of the protocol stream. */ + +/* skip a number of bytes foreward */ +#define SKIP(fp, sz) \ + DEBUG_PRINT("READ : skip %d bytes", (int)(sz)); \ + /* read (skip) the specified number of bytes */ \ + if (tio_skip(fp, sz)) \ + { \ + DEBUG_PRINT("READ : skip error: %s", strerror(errno)); \ + ERROR_OUT_READERROR(fp); \ + } + +/* read a string from the stream but don't do anything with the result */ +#define SKIP_STRING(fp) \ + /* read the size of the string */ \ + READ(fp, &tmpint32, sizeof(int32_t)); \ + tmpint32 = ntohl(tmpint32); \ + DEBUG_PRINT("READ_STRING: skip %d bytes", (int)tmpint32); \ + /* read (skip) the specified number of bytes */ \ + SKIP(fp, tmpint32); + +/* skip a list of strings */ +#define SKIP_STRINGLIST(fp) \ + /* read the number of entries */ \ + READ(fp, &tmp3int32, sizeof(int32_t)); \ + tmp3int32 = ntohl(tmp3int32); \ + DEBUG_PRINT("READ_STRLST: skip %d strings", (int)tmp3int32); \ + /* read all entries */ \ + for (tmp2int32 = 0; tmp2int32 < tmp3int32; tmp2int32++) \ + { \ + SKIP_STRING(fp); \ + } + + +/* These are functions and macors for performing common operations in + the nslcd request/response protocol. */ + +/* returns a socket to the server or NULL on error (see errno), + socket should be closed with tio_close() */ +TFILE *nslcd_client_open(void) + MUST_USE; + +/* generic request code */ +#define NSLCD_REQUEST(fp, action, writefn) \ + /* open a client socket */ \ + if ((fp = nslcd_client_open()) == NULL) \ + { \ + ERROR_OUT_OPENERROR; \ + } \ + /* write a request header with a request code */ \ + WRITE_INT32(fp, (int32_t)NSLCD_VERSION) \ + WRITE_INT32(fp, (int32_t)action) \ + /* write the request parameters (if any) */ \ + writefn; \ + /* flush the stream */ \ + if (tio_flush(fp) < 0) \ + { \ + DEBUG_PRINT("WRITE_FLUSH : error: %s", strerror(errno)); \ + ERROR_OUT_WRITEERROR(fp); \ + } \ + /* read and check response version number */ \ + READ(fp, &tmpint32, sizeof(int32_t)); \ + tmpint32 = ntohl(tmpint32); \ + if (tmpint32 != (int32_t)NSLCD_VERSION) \ + { \ + ERROR_OUT_READERROR(fp); \ + } \ + /* read and check response request number */ \ + READ(fp, &tmpint32, sizeof(int32_t)); \ + tmpint32 = ntohl(tmpint32); \ + if (tmpint32 != (int32_t)(action)) \ + { \ + ERROR_OUT_READERROR(fp); \ + } + +/* Read the response code (the result code of the query) from + the stream. */ +#define READ_RESPONSE_CODE(fp) \ + READ(fp, &tmpint32, sizeof(int32_t)); \ + tmpint32 = ntohl(tmpint32); \ + if (tmpint32 != (int32_t)NSLCD_RESULT_BEGIN) \ + { \ + ERROR_OUT_NOSUCCESS(fp); \ + } + +#endif /* not COMMON__NSLCD_PROT_H */ diff --git a/contrib/slapd-modules/nssov/nss-pam-ldapd/nslcd.h b/contrib/slapd-modules/nssov/nss-pam-ldapd/nslcd.h new file mode 100644 index 0000000..9884733 --- /dev/null +++ b/contrib/slapd-modules/nssov/nss-pam-ldapd/nslcd.h @@ -0,0 +1,305 @@ +/* + nslcd.h - file describing client/server protocol + + Copyright (C) 2006 West Consulting + Copyright (C) 2006, 2007, 2009, 2010, 2011, 2012, 2013 Arthur de Jong + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA +*/ + +#ifndef _NSLCD_H +#define _NSLCD_H 1 + +/* + The protocol used between the nslcd client and server is a simple binary + protocol. It is request/response based where the client initiates a + connection, does a single request and closes the connection again. Any + mangled or not understood messages will be silently ignored by the server. + + A request looks like: + INT32 NSLCD_VERSION + INT32 NSLCD_ACTION_* + [request parameters if any] + A response looks like: + INT32 NSLCD_VERSION + INT32 NSLCD_ACTION_* (the original request type) + [result(s)] + INT32 NSLCD_RESULT_END + A single result entry looks like: + INT32 NSLCD_RESULT_BEGIN + [result value(s)] + If a response would return multiple values (e.g. for NSLCD_ACTION_*_ALL + functions) each return value will be preceded by a NSLCD_RESULT_BEGIN + value. After the last returned result the server sends + NSLCD_RESULT_END. If some error occurs (e.g. LDAP server unavailable, + error in the request, etc) the server terminates the connection to signal + an error condition (breaking the protocol). + + These are the available basic data types: + INT32 - 32-bit integer value + TYPE - a typed field that is transferred using sizeof() + STRING - a string length (32bit) followed by the string value (not + null-terminted) the string itself is assumed to be UTF-8 + STRINGLIST - a 32-bit number noting the number of strings followed by + the strings one at a time + + Furthermore the ADDRESS compound data type is defined as: + INT32 type of address: e.g. AF_INET or AF_INET6 + INT32 lenght of address + RAW the address itself + With the ADDRESSLIST using the same construct as with STRINGLIST. + + The protocol uses network byte order for all types. +*/ + +/* The current version of the protocol. This protocol should only be + updated with major backwards-incompatible changes. */ +#define NSLCD_VERSION 0x00000002 + +/* Get a NSLCD configuration option. There is one request parameter: + INT32 NSLCD_CONFIG_* + the result value is: + STRING value, interpretation depending on request */ +#define NSLCD_ACTION_CONFIG_GET 0x00010001 + +/* return the message, if any, that is presented to the user when password + modification through PAM is prohibited */ +#define NSLCD_CONFIG_PAM_PASSWORD_PROHIBIT_MESSAGE 1 + +/* Email alias (/etc/aliases) NSS requests. The result values for a + single entry are: + STRING alias name + STRINGLIST alias rcpts */ +#define NSLCD_ACTION_ALIAS_BYNAME 0x00020001 +#define NSLCD_ACTION_ALIAS_ALL 0x00020008 + +/* Ethernet address/name mapping NSS requests. The result values for a + single entry are: + STRING ether name + TYPE(uint8_t[6]) ether address */ +#define NSLCD_ACTION_ETHER_BYNAME 0x00030001 +#define NSLCD_ACTION_ETHER_BYETHER 0x00030002 +#define NSLCD_ACTION_ETHER_ALL 0x00030008 + +/* Group and group membership related NSS requests. The result values + for a single entry are: + STRING group name + STRING group password + INT32 group id + STRINGLIST members (usernames) of the group + (not that the BYMEMER call returns an empty members list) */ +#define NSLCD_ACTION_GROUP_BYNAME 0x00040001 +#define NSLCD_ACTION_GROUP_BYGID 0x00040002 +#define NSLCD_ACTION_GROUP_BYMEMBER 0x00040006 +#define NSLCD_ACTION_GROUP_ALL 0x00040008 + +/* Hostname (/etc/hosts) lookup NSS requests. The result values + for an entry are: + STRING host name + STRINGLIST host aliases + ADDRESSLIST host addresses */ +#define NSLCD_ACTION_HOST_BYNAME 0x00050001 +#define NSLCD_ACTION_HOST_BYADDR 0x00050002 +#define NSLCD_ACTION_HOST_ALL 0x00050008 + +/* Netgroup NSS result entries contain a number of parts. A result entry + starts with: + STRING netgroup name + followed by zero or more references to other netgroups or netgroup + triples. A reference to another netgroup looks like: + INT32 NSLCD_NETGROUP_TYPE_NETGROUP + STRING other netgroup name + A a netgroup triple looks like: + INT32 NSLCD_NETGROUP_TYPE_TRIPLE + STRING host + STRING user + STRING domain + A netgroup result entry is terminated by: + INT32 NSLCD_NETGROUP_TYPE_END + */ +#define NSLCD_ACTION_NETGROUP_BYNAME 0x00060001 +#define NSLCD_ACTION_NETGROUP_ALL 0x00060008 +#define NSLCD_NETGROUP_TYPE_NETGROUP 1 +#define NSLCD_NETGROUP_TYPE_TRIPLE 2 +#define NSLCD_NETGROUP_TYPE_END 3 + +/* Network name (/etc/networks) NSS requests. Result values for a single + entry are: + STRING network name + STRINGLIST network aliases + ADDRESSLIST network addresses */ +#define NSLCD_ACTION_NETWORK_BYNAME 0x00070001 +#define NSLCD_ACTION_NETWORK_BYADDR 0x00070002 +#define NSLCD_ACTION_NETWORK_ALL 0x00070008 + +/* User account (/etc/passwd) NSS requests. Result values are: + STRING user name + STRING user password + INT32 user id + INT32 group id + STRING gecos information + STRING home directory + STRING login shell */ +#define NSLCD_ACTION_PASSWD_BYNAME 0x00080001 +#define NSLCD_ACTION_PASSWD_BYUID 0x00080002 +#define NSLCD_ACTION_PASSWD_ALL 0x00080008 + +/* Protocol information requests. Result values are: + STRING protocol name + STRINGLIST protocol aliases + INT32 protocol number */ +#define NSLCD_ACTION_PROTOCOL_BYNAME 0x00090001 +#define NSLCD_ACTION_PROTOCOL_BYNUMBER 0x00090002 +#define NSLCD_ACTION_PROTOCOL_ALL 0x00090008 + +/* RPC information requests. Result values are: + STRING rpc name + STRINGLIST rpc aliases + INT32 rpc number */ +#define NSLCD_ACTION_RPC_BYNAME 0x000a0001 +#define NSLCD_ACTION_RPC_BYNUMBER 0x000a0002 +#define NSLCD_ACTION_RPC_ALL 0x000a0008 + +/* Service (/etc/services) information requests. The BYNAME and BYNUMBER + requests contain an extra protocol string in the request which, if not + blank, will filter the services by this protocol. Result values are: + STRING service name + STRINGLIST service aliases + INT32 service (port) number + STRING service protocol */ +#define NSLCD_ACTION_SERVICE_BYNAME 0x000b0001 +#define NSLCD_ACTION_SERVICE_BYNUMBER 0x000b0002 +#define NSLCD_ACTION_SERVICE_ALL 0x000b0008 + +/* Extended user account (/etc/shadow) information requests. Result + values for a single entry are: + STRING user name + STRING user password + INT32 last password change + INT32 mindays + INT32 maxdays + INT32 warn + INT32 inact + INT32 expire + INT32 flag */ +#define NSLCD_ACTION_SHADOW_BYNAME 0x000c0001 +#define NSLCD_ACTION_SHADOW_ALL 0x000c0008 + +/* PAM-related requests. The request parameters for all these requests + begin with: + STRING user name + STRING service name + STRING ruser + STRING rhost + STRING tty + If the user is not known in LDAP no result may be returned (immediately + return NSLCD_RESULT_END instead of a PAM error code). */ + +/* PAM authentication check request. The extra request values are: + STRING password + and the result value consists of: + INT32 authc NSLCD_PAM_* result code + STRING user name (the cannonical user name) + INT32 authz NSLCD_PAM_* result code + STRING authorisation error message + If the username is empty in this request an attempt is made to + authenticate as the administrator (set using rootpwmoddn). + Some authorisation checks are already done during authentication so the + response also includes authorisation information. */ +#define NSLCD_ACTION_PAM_AUTHC 0x000d0001 + +/* PAM authorisation check request. The result value consists of: + INT32 authz NSLCD_PAM_* result code + STRING authorisation error message + The authentication check may have already returned some authorisation + information. The authorisation error message, if supplied, will be used + by the PAM module instead of a message that is generated by the PAM + module itself. */ +#define NSLCD_ACTION_PAM_AUTHZ 0x000d0002 + +/* PAM session open request. The result value consists of: + STRING session id + This session id may be used to close this session with. */ +#define NSLCD_ACTION_PAM_SESS_O 0x000d0003 + +/* PAM session close request. This request has the following + extra request value: + STRING session id + and this calls only returns an empty response value. */ +#define NSLCD_ACTION_PAM_SESS_C 0x000d0004 + +/* PAM password modification request. This requests has the following extra + request values: + INT32 asroot: 0=oldpasswd is user passwd, 1=oldpasswd is root passwd + STRING old password + STRING new password + and returns there extra result values: + INT32 NSLCD_PAM_* result code + STRING error message */ +#define NSLCD_ACTION_PAM_PWMOD 0x000d0005 + +/* User information change request. This request allows one to change + their full name and other information. The request parameters for this + request are: + STRING user name + INT32 asroot: 0=passwd is user passwd, 1=passwd is root passwd + STRING password + followed by one or more of the below, terminated by NSLCD_USERMOD_END + INT32 NSLCD_USERMOD_* + STRING new value + the response consists of one or more of the entries below, terminated + by NSLCD_USERMOD_END: + INT32 NSLCD_USERMOD_* + STRING response + (if the response is blank, the change went OK, otherwise the string + contains an error message) + */ +#define NSLCD_ACTION_USERMOD 0x000e0001 + +/* These are the possible values for the NSLCD_ACTION_USERMOD operation + above. */ +#define NSLCD_USERMOD_END 0 /* end of change values */ +#define NSLCD_USERMOD_RESULT 1 /* global result value */ +#define NSLCD_USERMOD_FULLNAME 2 /* full name */ +#define NSLCD_USERMOD_ROOMNUMBER 3 /* room number */ +#define NSLCD_USERMOD_WORKPHONE 4 /* office phone number */ +#define NSLCD_USERMOD_HOMEPHONE 5 /* home phone number */ +#define NSLCD_USERMOD_OTHER 6 /* other info */ +#define NSLCD_USERMOD_HOMEDIR 7 /* home directory */ +#define NSLCD_USERMOD_SHELL 8 /* login shell */ + +/* Request result codes. */ +#define NSLCD_RESULT_BEGIN 1 +#define NSLCD_RESULT_END 2 + +/* Partial list of PAM result codes. */ +#define NSLCD_PAM_SUCCESS 0 /* everything ok */ +#define NSLCD_PAM_PERM_DENIED 6 /* Permission denied */ +#define NSLCD_PAM_AUTH_ERR 7 /* Authc failure */ +#define NSLCD_PAM_CRED_INSUFFICIENT 8 /* Cannot access authc data */ +#define NSLCD_PAM_AUTHINFO_UNAVAIL 9 /* Cannot retrieve authc info */ +#define NSLCD_PAM_USER_UNKNOWN 10 /* User not known */ +#define NSLCD_PAM_MAXTRIES 11 /* Retry limit reached */ +#define NSLCD_PAM_NEW_AUTHTOK_REQD 12 /* Password expired */ +#define NSLCD_PAM_ACCT_EXPIRED 13 /* Account expired */ +#define NSLCD_PAM_SESSION_ERR 14 /* Cannot make/remove session record */ +#define NSLCD_PAM_AUTHTOK_ERR 20 /* Authentication token manipulation error */ +#define NSLCD_PAM_AUTHTOK_DISABLE_AGING 23 /* Password aging disabled */ +#define NSLCD_PAM_IGNORE 25 /* Ignore module */ +#define NSLCD_PAM_ABORT 26 /* Fatal error */ +#define NSLCD_PAM_AUTHTOK_EXPIRED 27 /* authentication token has expired */ + +#endif /* not _NSLCD_H */ diff --git a/contrib/slapd-modules/nssov/nss-pam-ldapd/tio.c b/contrib/slapd-modules/nssov/nss-pam-ldapd/tio.c new file mode 100644 index 0000000..11ad4f7 --- /dev/null +++ b/contrib/slapd-modules/nssov/nss-pam-ldapd/tio.c @@ -0,0 +1,520 @@ +/* + tio.c - timed io functions + This file is part of the nss-pam-ldapd library. + + Copyright (C) 2007-2014 Arthur de Jong + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA +*/ + +#include "portable.h" + +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif /* HAVE_STDINT_H */ +#include <stdlib.h> +#include <unistd.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <errno.h> +#include <string.h> +#include <signal.h> +#include <stdio.h> +#include <limits.h> +#include <poll.h> +#include <time.h> + +#include "tio.h" + +/* for platforms that don't have ETIME use ETIMEDOUT */ +#ifndef ETIME +#define ETIME ETIMEDOUT +#endif /* ETIME */ + +/* structure that holds a buffer + the buffer contains the data that is between the application and the + file descriptor that is used for efficient transfer + the buffer is built up as follows: + |.....********......| + ^start ^size + ^--len--^ */ +struct tio_buffer { + uint8_t *buffer; + size_t size; /* the size of the buffer */ + size_t maxsize; /* the maximum size of the buffer */ + size_t start; /* the start of the data (before start is unused) */ + size_t len; /* size of the data (from the start) */ +}; + +/* structure that holds all the state for files */ +struct tio_fileinfo { + int fd; + struct tio_buffer readbuffer; + struct tio_buffer writebuffer; + int readtimeout; + int writetimeout; + int read_resettable; /* whether the tio_reset() function can be called */ +#ifdef DEBUG_TIO_STATS + /* this is used to collect statistics on the use of the streams + and can be used to tune the buffer sizes */ + size_t byteswritten; + size_t bytesread; +#endif /* DEBUG_TIO_STATS */ +}; + +/* some older versions of Solaris don't provide CLOCK_MONOTONIC but do have + a CLOCK_HIGHRES that has the same properties we need */ +#ifndef CLOCK_MONOTONIC +#ifdef CLOCK_HIGHRES +#define CLOCK_MONOTONIC CLOCK_HIGHRES +#endif /* CLOCK_HIGHRES */ +#endif /* not CLOCK_MONOTONIC */ + +/* update the timeout to the value that is remaining before the deadline + returns the number of milliseconds before the deadline (or a negative + value of the deadline has expired) */ +static inline int tio_time_remaining(struct timespec *deadline, int timeout) +{ + struct timespec tv; + /* if this is the first call, set the deadline and return the full time */ + if ((deadline->tv_sec == 0) && (deadline->tv_nsec == 0)) + { + if (clock_gettime(CLOCK_MONOTONIC, deadline) == 0) + { + deadline->tv_sec += timeout / 1000; + deadline->tv_nsec += (timeout % 1000) * 1000000; + } + return timeout; + } + /* get the current time (fall back to full time on error) */ + if (clock_gettime(CLOCK_MONOTONIC, &tv)) + return timeout; + /* calculate time remaining in milliseconds */ + return (deadline->tv_sec - tv.tv_sec) * 1000 + + (deadline->tv_nsec - tv.tv_nsec) / 1000000; +} + +/* open a new TFILE based on the file descriptor */ +TFILE *tio_fdopen(int fd, int readtimeout, int writetimeout, + size_t initreadsize, size_t maxreadsize, + size_t initwritesize, size_t maxwritesize) +{ + struct tio_fileinfo *fp; + fp = (struct tio_fileinfo *)malloc(sizeof(struct tio_fileinfo)); + if (fp == NULL) + return NULL; + fp->fd = fd; + /* initialize read buffer */ + fp->readbuffer.buffer = (uint8_t *)malloc(initreadsize); + if (fp->readbuffer.buffer == NULL) + { + free(fp); + return NULL; + } + fp->readbuffer.size = initreadsize; + fp->readbuffer.maxsize = maxreadsize; + fp->readbuffer.start = 0; + fp->readbuffer.len = 0; + /* initialize write buffer */ + fp->writebuffer.buffer = (uint8_t *)malloc(initwritesize); + if (fp->writebuffer.buffer == NULL) + { + free(fp->readbuffer.buffer); + free(fp); + return NULL; + } + fp->writebuffer.size = initwritesize; + fp->writebuffer.maxsize = maxwritesize; + fp->writebuffer.start = 0; + fp->writebuffer.len = 0; + /* initialize other attributes */ + fp->readtimeout = readtimeout; + fp->writetimeout = writetimeout; + fp->read_resettable = 0; +#ifdef DEBUG_TIO_STATS + fp->byteswritten = 0; + fp->bytesread = 0; +#endif /* DEBUG_TIO_STATS */ + return fp; +} + +/* wait for any activity on the specified file descriptor using + the specified deadline */ +static int tio_wait(int fd, short events, int timeout, + struct timespec *deadline) +{ + int t; + struct pollfd fds[1]; + int rv; + while (1) + { + fds[0].fd = fd; + fds[0].events = events; + /* figure out the time we need to wait */ + if ((t = tio_time_remaining(deadline, timeout)) < 0) + { + errno = ETIME; + return -1; + } + /* sanitiy check for moving clock */ + if (t > timeout) + t = timeout; + /* wait for activity */ + rv = poll(fds, 1, t); + if (rv > 0) + return 0; /* we have activity */ + else if (rv == 0) + { + /* no file descriptors were available within the specified time */ + errno = ETIME; + return -1; + } + else if ((errno != EINTR) && (errno != EAGAIN)) + /* some error ocurred */ + return -1; + /* we just try again on EINTR or EAGAIN */ + } +} + +/* do a read on the file descriptor, returning the data in the buffer + if no data was read in the specified time an error is returned */ +int tio_read(TFILE *fp, void *buf, size_t count) +{ + struct timespec deadline = {0, 0}; + int rv; + uint8_t *tmp; + size_t newsz; + size_t len; + /* have a more convenient storage type for the buffer */ + uint8_t *ptr = (uint8_t *)buf; + /* loop until we have returned all the needed data */ + while (1) + { + /* check if we have enough data in the buffer */ + if (fp->readbuffer.len >= count) + { + if (count > 0) + { + if (ptr != NULL) + memcpy(ptr, fp->readbuffer.buffer + fp->readbuffer.start, count); + /* adjust buffer position */ + fp->readbuffer.start += count; + fp->readbuffer.len -= count; + } + return 0; + } + /* empty what we have and continue from there */ + if (fp->readbuffer.len > 0) + { + if (ptr != NULL) + { + memcpy(ptr, fp->readbuffer.buffer + fp->readbuffer.start, + fp->readbuffer.len); + ptr += fp->readbuffer.len; + } + count -= fp->readbuffer.len; + fp->readbuffer.start += fp->readbuffer.len; + fp->readbuffer.len = 0; + } + /* after this point until the read fp->readbuffer.len is 0 */ + if (!fp->read_resettable) + { + /* the stream is not resettable, re-use the buffer */ + fp->readbuffer.start = 0; + } + else if (fp->readbuffer.start >= (fp->readbuffer.size - 4)) + { + /* buffer is running empty, try to grow buffer */ + if (fp->readbuffer.size < fp->readbuffer.maxsize) + { + newsz = fp->readbuffer.size * 2; + if (newsz > fp->readbuffer.maxsize) + newsz = fp->readbuffer.maxsize; + tmp = realloc(fp->readbuffer.buffer, newsz); + if (tmp != NULL) + { + fp->readbuffer.buffer = tmp; + fp->readbuffer.size = newsz; + } + } + /* if buffer still does not contain enough room, clear resettable */ + if (fp->readbuffer.start >= (fp->readbuffer.size - 4)) + { + fp->readbuffer.start = 0; + fp->read_resettable = 0; + } + } + /* wait until we have input */ + if (tio_wait(fp->fd, POLLIN, fp->readtimeout, &deadline)) + return -1; + /* read the input in the buffer */ + len = fp->readbuffer.size - fp->readbuffer.start; +#ifdef SSIZE_MAX + if (len > SSIZE_MAX) + len = SSIZE_MAX; +#endif /* SSIZE_MAX */ + rv = read(fp->fd, fp->readbuffer.buffer + fp->readbuffer.start, len); + /* check for errors */ + if (rv == 0) + { + errno = ECONNRESET; + return -1; + } + else if ((rv < 0) && (errno != EINTR) && (errno != EAGAIN)) + return -1; /* something went wrong with the read */ + else if (rv > 0) + fp->readbuffer.len = rv; /* skip the read part in the buffer */ +#ifdef DEBUG_TIO_STATS + fp->bytesread += rv; +#endif /* DEBUG_TIO_STATS */ + } +} + +/* Read and discard the specified number of bytes from the stream. */ +int tio_skip(TFILE *fp, size_t count) +{ + return tio_read(fp, NULL, count); +} + +/* Read all available data from the stream and empty the read buffer. */ +int tio_skipall(TFILE *fp, int timeout) +{ + struct timespec deadline = {0, 0}; + int rv; + size_t len; + /* clear the read buffer */ + fp->readbuffer.start = 0; + fp->readbuffer.len = 0; + fp->read_resettable = 0; + /* read until we can't read no more */ + len = fp->readbuffer.size; +#ifdef SSIZE_MAX + if (len > SSIZE_MAX) + len = SSIZE_MAX; +#endif /* SSIZE_MAX */ + while (1) + { + /* wait until we have input */ + if (tio_wait(fp->fd, POLLIN, timeout, &deadline)) + return -1; + /* read data from the stream */ + rv = read(fp->fd, fp->readbuffer.buffer, len); + if (rv == 0) + return 0; /* end-of-file */ + if ((rv < 0) && (errno == EWOULDBLOCK)) + return 0; /* we've ready everything we can without blocking */ + if ((rv < 0) && (errno != EINTR) && (errno != EAGAIN)) + return -1; /* something went wrong with the read */ + } +} + +/* the caller has assured us that we can write to the file descriptor + and we give it a shot */ +static int tio_writebuf(TFILE *fp) +{ + int rv; + /* write the buffer */ +#ifdef MSG_NOSIGNAL + rv = send(fp->fd, fp->writebuffer.buffer + fp->writebuffer.start, + fp->writebuffer.len, MSG_NOSIGNAL); +#else /* not MSG_NOSIGNAL */ + /* on platforms that cannot use send() with masked signals, we change the + signal mask and change it back after the write (note that there is a + race condition here) */ + struct sigaction act, oldact; + /* set up sigaction */ + memset(&act, 0, sizeof(struct sigaction)); + act.sa_sigaction = NULL; + act.sa_handler = SIG_IGN; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_RESTART; + /* ignore SIGPIPE */ + if (sigaction(SIGPIPE, &act, &oldact) != 0) + return -1; /* error setting signal handler */ + /* write the buffer */ + rv = write(fp->fd, fp->writebuffer.buffer + fp->writebuffer.start, + fp->writebuffer.len); + /* restore the old handler for SIGPIPE */ + if (sigaction(SIGPIPE, &oldact, NULL) != 0) + return -1; /* error restoring signal handler */ +#endif + /* check for errors */ + if ((rv == 0) || ((rv < 0) && (errno != EINTR) && (errno != EAGAIN))) + return -1; /* something went wrong with the write */ + /* skip the written part in the buffer */ + if (rv > 0) + { + fp->writebuffer.start += rv; + fp->writebuffer.len -= rv; +#ifdef DEBUG_TIO_STATS + fp->byteswritten += rv; +#endif /* DEBUG_TIO_STATS */ + /* reset start if len is 0 */ + if (fp->writebuffer.len == 0) + fp->writebuffer.start = 0; + /* move contents of the buffer to the front if it will save enough room */ + if (fp->writebuffer.start >= (fp->writebuffer.size / 4)) + { + memmove(fp->writebuffer.buffer, + fp->writebuffer.buffer + fp->writebuffer.start, + fp->writebuffer.len); + fp->writebuffer.start = 0; + } + } + return 0; +} + +/* write all the data in the buffer to the stream */ +int tio_flush(TFILE *fp) +{ + struct timespec deadline = {0, 0}; + /* loop until we have written our buffer */ + while (fp->writebuffer.len > 0) + { + /* wait until we can write */ + if (tio_wait(fp->fd, POLLOUT, fp->writetimeout, &deadline)) + return -1; + /* write one block */ + if (tio_writebuf(fp)) + return -1; + } + return 0; +} + +/* try a single write of data in the buffer if the file descriptor + will accept data */ +static int tio_flush_nonblock(TFILE *fp) +{ + struct pollfd fds[1]; + int rv; + /* see if we can write without blocking */ + fds[0].fd = fp->fd; + fds[0].events = POLLOUT; + rv = poll(fds, 1, 0); + /* check if any file descriptors were ready (timeout) or we were + interrupted */ + if ((rv == 0) || ((rv < 0) && ((errno == EINTR) || (errno == EAGAIN)))) + return 0; + /* any other errors? */ + if (rv < 0) + return -1; + /* so file descriptor will accept writes */ + return tio_writebuf(fp); +} + +int tio_write(TFILE *fp, const void *buf, size_t count) +{ + size_t fr; + uint8_t *tmp; + size_t newsz; + const uint8_t *ptr = (const uint8_t *)buf; + /* keep filling the buffer until we have bufferred everything */ + while (count > 0) + { + /* figure out free size in buffer */ + fr = fp->writebuffer.size - (fp->writebuffer.start + fp->writebuffer.len); + if (count <= fr) + { + /* the data fits in the buffer */ + memcpy(fp->writebuffer.buffer + fp->writebuffer.start + + fp->writebuffer.len, ptr, count); + fp->writebuffer.len += count; + return 0; + } + else if (fr > 0) + { + /* fill the buffer with data that will fit */ + memcpy(fp->writebuffer.buffer + fp->writebuffer.start + + fp->writebuffer.len, ptr, fr); + fp->writebuffer.len += fr; + ptr += fr; + count -= fr; + } + /* try to flush some of the data that is in the buffer */ + if (tio_flush_nonblock(fp)) + return -1; + /* if we have room now, try again */ + if (fp->writebuffer.size > (fp->writebuffer.start + fp->writebuffer.len)) + continue; + /* try to grow the buffer */ + if (fp->writebuffer.size < fp->writebuffer.maxsize) + { + newsz = fp->writebuffer.size * 2; + if (newsz > fp->writebuffer.maxsize) + newsz = fp->writebuffer.maxsize; + tmp = realloc(fp->writebuffer.buffer, newsz); + if (tmp != NULL) + { + fp->writebuffer.buffer = tmp; + fp->writebuffer.size = newsz; + continue; /* try again */ + } + } + /* write the buffer to the stream */ + if (tio_flush(fp)) + return -1; + } + return 0; +} + +int tio_close(TFILE *fp) +{ + int retv; + /* write any buffered data */ + retv = tio_flush(fp); +#ifdef DEBUG_TIO_STATS + /* dump statistics to stderr */ + fprintf(stderr, "DEBUG_TIO_STATS READ=%d WRITTEN=%d\n", fp->bytesread, + fp->byteswritten); +#endif /* DEBUG_TIO_STATS */ + /* close file descriptor */ + if (close(fp->fd)) + retv = -1; + /* free any allocated buffers */ + memset(fp->readbuffer.buffer, 0, fp->readbuffer.size); + memset(fp->writebuffer.buffer, 0, fp->writebuffer.size); + free(fp->readbuffer.buffer); + free(fp->writebuffer.buffer); + /* free the tio struct itself */ + free(fp); + /* return the result of the earlier operations */ + return retv; +} + +void tio_mark(TFILE *fp) +{ + /* move any data in the buffer to the start of the buffer */ + if ((fp->readbuffer.start > 0) && (fp->readbuffer.len > 0)) + { + memmove(fp->readbuffer.buffer, + fp->readbuffer.buffer + fp->readbuffer.start, fp->readbuffer.len); + fp->readbuffer.start = 0; + } + /* mark the stream as resettable */ + fp->read_resettable = 1; +} + +int tio_reset(TFILE *fp) +{ + /* check if the stream is (still) resettable */ + if (!fp->read_resettable) + return -1; + /* reset the buffer */ + fp->readbuffer.len += fp->readbuffer.start; + fp->readbuffer.start = 0; + return 0; +} diff --git a/contrib/slapd-modules/nssov/nss-pam-ldapd/tio.h b/contrib/slapd-modules/nssov/nss-pam-ldapd/tio.h new file mode 100644 index 0000000..95f9812 --- /dev/null +++ b/contrib/slapd-modules/nssov/nss-pam-ldapd/tio.h @@ -0,0 +1,83 @@ +/* + tio.h - timed io functions + This file is part of the nss-pam-ldapd library. + + Copyright (C) 2007, 2008, 2010, 2012, 2013 Arthur de Jong + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA +*/ + +/* + + TODO: Add some documentation here. + + the SIGPIPE signal should be ignored (is ignored in this code) + + This library is not thread safe. You cannot share TFILE objects between + threads and expect to be able to read and write from them in different + threads. All the state is in the TFILE object so calls to this library on + different objects can be done in parallel. + +*/ + +#ifndef COMMON__TIO_H +#define COMMON__TIO_H + +#include <sys/time.h> +#include <sys/types.h> + +#include "attrs.h" + +/* This is a generic file handle used for reading and writing + (something like FILE from stdio.h). */ +typedef struct tio_fileinfo TFILE; + +/* Open a new TFILE based on the file descriptor. The timeout is set for any + operation (value in milliseconds). */ +TFILE *tio_fdopen(int fd, int readtimeout, int writetimeout, + size_t initreadsize, size_t maxreadsize, + size_t initwritesize, size_t maxwritesize) + LIKE_MALLOC MUST_USE; + +/* Read the specified number of bytes from the stream. */ +int tio_read(TFILE *fp, void *buf, size_t count); + +/* Read and discard the specified number of bytes from the stream. */ +int tio_skip(TFILE *fp, size_t count); + +/* Read all available data from the stream and empty the read buffer. */ +int tio_skipall(TFILE *fp, int timeout); + +/* Write the specified buffer to the stream. */ +int tio_write(TFILE *fp, const void *buf, size_t count); + +/* Write out all buffered data to the stream. */ +int tio_flush(TFILE *fp); + +/* Flush the streams and closes the underlying file descriptor. */ +int tio_close(TFILE *fp); + +/* Store the current position in the stream so that we can jump back to it + with the tio_reset() function. */ +void tio_mark(TFILE *fp); + +/* Rewinds the stream to the point set by tio_mark(). Note that this only + resets the read stream and not the write stream. This function returns + whether the reset was successful (this function may fail if the buffers + were full). */ +int tio_reset(TFILE *fp); + +#endif /* COMMON__TIO_H */ diff --git a/contrib/slapd-modules/nssov/nssov.c b/contrib/slapd-modules/nssov/nssov.c new file mode 100644 index 0000000..7a542e5 --- /dev/null +++ b/contrib/slapd-modules/nssov/nssov.c @@ -0,0 +1,993 @@ +/* nssov.c - nss-ldap overlay for slapd */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2008-2021 The OpenLDAP Foundation. + * Portions Copyright 2008 by Howard Chu, Symas Corp. + * Portions Copyright 2013 by Ted C. Cheng, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This code references portions of the nss-ldapd package + * written by Arthur de Jong. The nss-ldapd code was forked + * from the nss-ldap library written by Luke Howard. + */ + +#include "nssov.h" + +#ifndef SLAPD_OVER_NSSOV +#define SLAPD_OVER_NSSOV SLAPD_MOD_DYNAMIC +#endif + +#include "../slapd/config.h" /* not nss-ldapd config.h */ + +#include "lutil.h" + +#include <ac/errno.h> +#include <ac/unistd.h> +#include <fcntl.h> +#include <sys/stat.h> + +AttributeDescription *nssov_pam_host_ad; +AttributeDescription *nssov_pam_svc_ad; + +/* buffer sizes for I/O */ +#define READBUFFER_MINSIZE 32 +#define READBUFFER_MAXSIZE 64 +#define WRITEBUFFER_MINSIZE 64 +#define WRITEBUFFER_MAXSIZE 64*1024 + +/* Find the given attribute's value in the RDN of the DN */ +void nssov_find_rdnval(struct berval *dn, AttributeDescription *ad, struct berval *value) +{ + struct berval rdn; + char *next; + + BER_BVZERO(value); + dnRdn( dn, &rdn ); + do { + next = ber_bvchr( &rdn, '+' ); + if ( rdn.bv_val[ad->ad_cname.bv_len] == '=' && + !ber_bvcmp( &rdn, &ad->ad_cname )) { + if ( next ) + rdn.bv_len = next - rdn.bv_val; + value->bv_val = rdn.bv_val + ad->ad_cname.bv_len + 1; + value->bv_len = rdn.bv_len - ad->ad_cname.bv_len - 1; + break; + } + if ( !next ) + break; + next++; + rdn.bv_len -= next - rdn.bv_val; + rdn.bv_val = next; + } while (1); +} + +/* create a search filter using a name that requires escaping */ +int nssov_filter_byname(nssov_mapinfo *mi,int key,struct berval *name,struct berval *buf) +{ + char buf2[1024]; + struct berval bv2 = {sizeof(buf2),buf2}; + + /* escape attribute */ + if (nssov_escape(name,&bv2)) + return -1; + /* build filter */ + if (bv2.bv_len + mi->mi_filter.bv_len + mi->mi_attrs[key].an_desc->ad_cname.bv_len + 6 > + buf->bv_len ) + return -1; + buf->bv_len = snprintf(buf->bv_val, buf->bv_len, "(&%s(%s=%s))", + mi->mi_filter.bv_val, mi->mi_attrs[key].an_desc->ad_cname.bv_val, + bv2.bv_val ); + return 0; +} + +/* create a search filter using a string converted from an int */ +int nssov_filter_byid(nssov_mapinfo *mi,int key,struct berval *id,struct berval *buf) +{ + /* build filter */ + if (id->bv_len + mi->mi_filter.bv_len + mi->mi_attrs[key].an_desc->ad_cname.bv_len + 6 > + buf->bv_len ) + return -1; + buf->bv_len = snprintf(buf->bv_val, buf->bv_len, "(&%s(%s=%s))", + mi->mi_filter.bv_val, mi->mi_attrs[key].an_desc->ad_cname.bv_val, + id->bv_val ); + return 0; +} + +void get_userpassword(struct berval *attr,struct berval *pw) +{ + int i; + /* go over the entries and return the remainder of the value if it + starts with {crypt} or crypt$ */ + for (i=0;!BER_BVISNULL(&attr[i]);i++) + { + if (strncasecmp(attr[i].bv_val,"{crypt}",7)==0) { + pw->bv_val = attr[i].bv_val + 7; + pw->bv_len = attr[i].bv_len - 7; + return; + } + if (strncasecmp(attr[i].bv_val,"crypt$",6)==0) { + pw->bv_val = attr[i].bv_val + 6; + pw->bv_len = attr[i].bv_len - 6; + return; + } + } + /* just return the first value completely */ + *pw = *attr; + /* TODO: support more password formats e.g. SMD5 + (which is $1$ but in a different format) + (any code for this is more than welcome) */ +} + +/* this writes a single address to the stream */ +int write_address(TFILE *fp,struct berval *addr) +{ + int32_t tmpint32; + struct in_addr ipv4addr; + struct in6_addr ipv6addr; + /* try to parse the address as IPv4 first, fall back to IPv6 */ + if (inet_pton(AF_INET,addr->bv_val,&ipv4addr)>0) + { + /* write address type */ + WRITE_INT32(fp,AF_INET); + /* write the address length */ + WRITE_INT32(fp,sizeof(struct in_addr)); + /* write the address itself (in network byte order) */ + WRITE(fp,&ipv4addr,sizeof(struct in_addr)); + } + else if (inet_pton(AF_INET6,addr->bv_val,&ipv6addr)>0) + { + /* write address type */ + WRITE_INT32(fp,AF_INET6); + /* write the address length */ + WRITE_INT32(fp,sizeof(struct in6_addr)); + /* write the address itself (in network byte order) */ + WRITE(fp,&ipv6addr,sizeof(struct in6_addr)); + } + else + { + /* failure, log but write simple invalid address + (otherwise the address list is messed up) */ + /* TODO: have error message in correct format */ + Debug(LDAP_DEBUG_ANY,"nssov: unparseable address: %s\n",addr->bv_val,0,0); + /* write an illegal address type */ + WRITE_INT32(fp,-1); + /* write an empty address */ + WRITE_INT32(fp,0); + } + /* we're done */ + return 0; +} + +int read_address(TFILE *fp,char *addr,int *addrlen,int *af) +{ + int32_t tmpint32; + int len; + /* read address family */ + READ_INT32(fp,*af); + if ((*af!=AF_INET)&&(*af!=AF_INET6)) + { + Debug(LDAP_DEBUG_ANY,"nssov: incorrect address family specified: %d\n",*af,0,0); + return -1; + } + /* read address length */ + READ_INT32(fp,len); + if ((len>*addrlen)||(len<=0)) + { + Debug(LDAP_DEBUG_ANY,"nssov: address length incorrect: %d\n",len,0,0); + return -1; + } + *addrlen=len; + /* read address */ + READ(fp,addr,len); + /* we're done */ + return 0; +} + +int nssov_escape(struct berval *src,struct berval *dst) +{ + size_t pos=0; + int i; + /* go over all characters in source string */ + for (i=0;i<src->bv_len;i++) + { + /* check if char will fit */ + if (pos>=(dst->bv_len-4)) + return -1; + /* do escaping for some characters */ + switch (src->bv_val[i]) + { + case '*': + strcpy(dst->bv_val+pos,"\\2a"); + pos+=3; + break; + case '(': + strcpy(dst->bv_val+pos,"\\28"); + pos+=3; + break; + case ')': + strcpy(dst->bv_val+pos,"\\29"); + pos+=3; + break; + case '\\': + strcpy(dst->bv_val+pos,"\\5c"); + pos+=3; + break; + default: + /* just copy character */ + dst->bv_val[pos++]=src->bv_val[i]; + break; + } + } + /* terminate destination string */ + dst->bv_val[pos]='\0'; + dst->bv_len = pos; + return 0; +} + +/* read the version information and action from the stream + this function returns the read action in location pointer to by action */ +static int read_header(TFILE *fp,int32_t *action) +{ + int32_t tmpint32; + /* read the protocol version */ + READ_INT32(fp,tmpint32); + if (tmpint32 != (int32_t)NSLCD_VERSION) + { + Debug( LDAP_DEBUG_TRACE,"nssov: wrong nslcd version id (%d)\n",(int)tmpint32,0,0); + return -1; + } + /* read the request type */ + READ_INT32(fp,*action); + return 0; +} + +int nssov_config(nssov_info *ni,TFILE *fp,Operation *op) +{ + int opt; + int32_t tmpint32; + + READ_INT32(fp,opt); + + Debug(LDAP_DEBUG_TRACE, "nssov_config (%d)\n",opt,0,0); + + WRITE_INT32(fp,NSLCD_VERSION); + WRITE_INT32(fp,NSLCD_ACTION_CONFIG_GET); + WRITE_INT32(fp,NSLCD_RESULT_BEGIN); + + switch (opt) { + case NSLCD_CONFIG_PAM_PASSWORD_PROHIBIT_MESSAGE: + /* request for pam password_prohibit_message */ + /* nssov_pam prohibits password */ + if (!BER_BVISEMPTY(&ni->ni_pam_password_prohibit_message)) { + Debug(LDAP_DEBUG_TRACE,"nssov_config(): %s (%s)\n", + "password_prohibit_message", + ni->ni_pam_password_prohibit_message.bv_val,0); + WRITE_STRING(fp,ni->ni_pam_password_prohibit_message.bv_val); + } + default: + /* all other config options are ignored */ + break; + } + + WRITE_INT32(fp,NSLCD_RESULT_END); + return 0; +} + + +/* read a request message, returns <0 in case of errors, + this function closes the socket */ +static void handleconnection(nssov_info *ni,int sock,Operation *op) +{ + TFILE *fp; + int32_t action; + int readtimeout,writetimeout; + uid_t uid; + gid_t gid; + char authid[sizeof("gidNumber=4294967295+uidNumber=424967295,cn=peercred,cn=external,cn=auth")]; + char peerbuf[8]; + struct berval peerbv = { sizeof(peerbuf), peerbuf }; + + /* log connection */ + if (LUTIL_GETPEEREID(sock,&uid,&gid,&peerbv)) + Debug( LDAP_DEBUG_TRACE,"nssov: connection from unknown client: %s\n",strerror(errno),0,0); + else + Debug( LDAP_DEBUG_TRACE,"nssov: connection from uid=%d gid=%d\n", + (int)uid,(int)gid,0); + + /* Should do authid mapping too */ + op->o_dn.bv_len = sprintf(authid,"gidNumber=%d+uidNumber=%d,cn=peercred,cn=external,cn=auth", + (int)gid, (int)uid ); + op->o_dn.bv_val = authid; + op->o_ndn = op->o_dn; + + /* set the timeouts: + * read timeout is half a second because clients should send their request + * quickly, write timeout is 60 seconds because clients could be taking some + * time to process the results + */ + readtimeout = 500; + writetimeout = 60000; + /* create a stream object */ + if ((fp=tio_fdopen(sock,readtimeout,writetimeout, + READBUFFER_MINSIZE,READBUFFER_MAXSIZE, + WRITEBUFFER_MINSIZE,WRITEBUFFER_MAXSIZE))==NULL) + { + Debug( LDAP_DEBUG_ANY,"nssov: cannot create stream for writing: %s",strerror(errno),0,0); + (void)close(sock); + return; + } + /* read request */ + if (read_header(fp,&action)) + { + (void)tio_close(fp); + return; + } + /* handle request */ + switch (action) + { + case NSLCD_ACTION_ALIAS_BYNAME: (void)nssov_alias_byname(ni,fp,op); break; + case NSLCD_ACTION_ALIAS_ALL: (void)nssov_alias_all(ni,fp,op); break; + case NSLCD_ACTION_ETHER_BYNAME: (void)nssov_ether_byname(ni,fp,op); break; + case NSLCD_ACTION_ETHER_BYETHER: (void)nssov_ether_byether(ni,fp,op); break; + case NSLCD_ACTION_ETHER_ALL: (void)nssov_ether_all(ni,fp,op); break; + case NSLCD_ACTION_GROUP_BYNAME: (void)nssov_group_byname(ni,fp,op); break; + case NSLCD_ACTION_GROUP_BYGID: (void)nssov_group_bygid(ni,fp,op); break; + case NSLCD_ACTION_GROUP_BYMEMBER: (void)nssov_group_bymember(ni,fp,op); break; + case NSLCD_ACTION_GROUP_ALL: (void)nssov_group_all(ni,fp,op); break; + case NSLCD_ACTION_HOST_BYNAME: (void)nssov_host_byname(ni,fp,op); break; + case NSLCD_ACTION_HOST_BYADDR: (void)nssov_host_byaddr(ni,fp,op); break; + case NSLCD_ACTION_HOST_ALL: (void)nssov_host_all(ni,fp,op); break; + case NSLCD_ACTION_NETGROUP_BYNAME: (void)nssov_netgroup_byname(ni,fp,op); break; + case NSLCD_ACTION_NETWORK_BYNAME: (void)nssov_network_byname(ni,fp,op); break; + case NSLCD_ACTION_NETWORK_BYADDR: (void)nssov_network_byaddr(ni,fp,op); break; + case NSLCD_ACTION_NETWORK_ALL: (void)nssov_network_all(ni,fp,op); break; + case NSLCD_ACTION_PASSWD_BYNAME: (void)nssov_passwd_byname(ni,fp,op); break; + case NSLCD_ACTION_PASSWD_BYUID: (void)nssov_passwd_byuid(ni,fp,op); break; + case NSLCD_ACTION_PASSWD_ALL: (void)nssov_passwd_all(ni,fp,op); break; + case NSLCD_ACTION_PROTOCOL_BYNAME: (void)nssov_protocol_byname(ni,fp,op); break; + case NSLCD_ACTION_PROTOCOL_BYNUMBER:(void)nssov_protocol_bynumber(ni,fp,op); break; + case NSLCD_ACTION_PROTOCOL_ALL: (void)nssov_protocol_all(ni,fp,op); break; + case NSLCD_ACTION_RPC_BYNAME: (void)nssov_rpc_byname(ni,fp,op); break; + case NSLCD_ACTION_RPC_BYNUMBER: (void)nssov_rpc_bynumber(ni,fp,op); break; + case NSLCD_ACTION_RPC_ALL: (void)nssov_rpc_all(ni,fp,op); break; + case NSLCD_ACTION_SERVICE_BYNAME: (void)nssov_service_byname(ni,fp,op); break; + case NSLCD_ACTION_SERVICE_BYNUMBER: (void)nssov_service_bynumber(ni,fp,op); break; + case NSLCD_ACTION_SERVICE_ALL: (void)nssov_service_all(ni,fp,op); break; + case NSLCD_ACTION_SHADOW_BYNAME: if (uid==0) (void)nssov_shadow_byname(ni,fp,op); break; + case NSLCD_ACTION_SHADOW_ALL: if (uid==0) (void)nssov_shadow_all(ni,fp,op); break; + case NSLCD_ACTION_PAM_AUTHC: (void)pam_authc(ni,fp,op,uid); break; + case NSLCD_ACTION_PAM_AUTHZ: (void)pam_authz(ni,fp,op); break; + case NSLCD_ACTION_PAM_SESS_O: if (uid==0) (void)pam_sess_o(ni,fp,op); break; + case NSLCD_ACTION_PAM_SESS_C: if (uid==0) (void)pam_sess_c(ni,fp,op); break; + case NSLCD_ACTION_PAM_PWMOD: (void)pam_pwmod(ni,fp,op,uid); break; + case NSLCD_ACTION_CONFIG_GET: (void)nssov_config(ni,fp,op); break; + default: + Debug( LDAP_DEBUG_ANY,"nssov: invalid request id: %d",(int)action,0,0); + break; + } + /* we're done with the request */ + (void)tio_close(fp); + return; +} + +/* accept a connection on the socket */ +static void *acceptconn(void *ctx, void *arg) +{ + nssov_info *ni = arg; + Connection conn = {0}; + OperationBuffer opbuf; + Operation *op; + int csock; + + if ( slapd_shutdown ) + return NULL; + + { + struct sockaddr_storage addr; + socklen_t alen; + int j; + + /* accept a new connection */ + alen=(socklen_t)sizeof(struct sockaddr_storage); + csock=accept(ni->ni_socket,(struct sockaddr *)&addr,&alen); + connection_client_enable(ni->ni_conn); + if (csock<0) + { + if ((errno==EINTR)||(errno==EAGAIN)||(errno==EWOULDBLOCK)) + { + Debug( LDAP_DEBUG_TRACE,"nssov: accept() failed (ignored): %s",strerror(errno),0,0); + return NULL; + } + Debug( LDAP_DEBUG_ANY,"nssov: accept() failed: %s",strerror(errno),0,0); + return NULL; + } + /* make sure O_NONBLOCK is not inherited */ + if ((j=fcntl(csock,F_GETFL,0))<0) + { + Debug( LDAP_DEBUG_ANY,"nssov: fcntl(F_GETFL) failed: %s",strerror(errno),0,0); + if (close(csock)) + Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",strerror(errno),0,0); + return NULL; + } + if (fcntl(csock,F_SETFL,j&~O_NONBLOCK)<0) + { + Debug( LDAP_DEBUG_ANY,"nssov: fcntl(F_SETFL,~O_NONBLOCK) failed: %s",strerror(errno),0,0); + if (close(csock)) + Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",strerror(errno),0,0); + return NULL; + } + } + connection_fake_init( &conn, &opbuf, ctx ); + op=&opbuf.ob_op; + conn.c_ssf = conn.c_transport_ssf = local_ssf; + op->o_bd = ni->ni_db; + op->o_tag = LDAP_REQ_SEARCH; + + /* handle the connection */ + handleconnection(ni,csock,op); + + return NULL; +} + +static slap_verbmasks nss_svcs[] = { + { BER_BVC("aliases"), NM_alias }, + { BER_BVC("ethers"), NM_ether }, + { BER_BVC("group"), NM_group }, + { BER_BVC("hosts"), NM_host }, + { BER_BVC("netgroup"), NM_netgroup }, + { BER_BVC("networks"), NM_network }, + { BER_BVC("passwd"), NM_passwd }, + { BER_BVC("protocols"), NM_protocol }, + { BER_BVC("rpc"), NM_rpc }, + { BER_BVC("services"), NM_service }, + { BER_BVC("shadow"), NM_shadow }, + { BER_BVNULL, 0 } +}; + +static slap_verbmasks pam_opts[] = { + { BER_BVC("userhost"), NI_PAM_USERHOST }, + { BER_BVC("userservice"), NI_PAM_USERSVC }, + { BER_BVC("usergroup"), NI_PAM_USERGRP }, + { BER_BVC("hostservice"), NI_PAM_HOSTSVC }, + { BER_BVC("authz2dn"), NI_PAM_SASL2DN }, + { BER_BVC("uid2dn"), NI_PAM_UID2DN }, + { BER_BVNULL, 0 } +}; + +enum { + NSS_SSD=1, + NSS_MAP, + NSS_PAM, + NSS_PAMGROUP, + NSS_PAMSESS +}; + +static ConfigDriver nss_cf_gen; + +static ConfigTable nsscfg[] = { + { "nssov-ssd", "service> <url", 3, 3, 0, ARG_MAGIC|NSS_SSD, + nss_cf_gen, "(OLcfgCtAt:3.1 NAME 'olcNssSsd' " + "DESC 'URL for searches in a given service' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString )", NULL, NULL }, + { "nssov-map", "service> <orig> <new", 4, 4, 0, ARG_MAGIC|NSS_MAP, + nss_cf_gen, "(OLcfgCtAt:3.2 NAME 'olcNssMap' " + "DESC 'Map <service> lookups of <orig> attr to <new> attr' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString )", NULL, NULL }, + { "nssov-pam", "options", 2, 0, 0, ARG_MAGIC|NSS_PAM, + nss_cf_gen, "(OLcfgCtAt:3.3 NAME 'olcNssPam' " + "DESC 'PAM authentication and authorization options' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString )", NULL, NULL }, + { "nssov-pam-defhost", "hostname", 2, 2, 0, ARG_OFFSET|ARG_BERVAL, + (void *)offsetof(struct nssov_info, ni_pam_defhost), + "(OLcfgCtAt:3.4 NAME 'olcNssPamDefHost' " + "DESC 'Default hostname for service checks' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, + { "nssov-pam-group-dn", "DN", 2, 2, 0, ARG_MAGIC|ARG_DN|NSS_PAMGROUP, + nss_cf_gen, "(OLcfgCtAt:3.5 NAME 'olcNssPamGroupDN' " + "DESC 'DN of group in which membership is required' " + "EQUALITY distinguishedNameMatch " + "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL }, + { "nssov-pam-group-ad", "attr", 2, 2, 0, ARG_OFFSET|ARG_ATDESC, + (void *)offsetof(struct nssov_info, ni_pam_group_ad), + "(OLcfgCtAt:3.6 NAME 'olcNssPamGroupAD' " + "DESC 'Member attribute to use for group check' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, + { "nssov-pam-min-uid", "uid", 2, 2, 0, ARG_OFFSET|ARG_INT, + (void *)offsetof(struct nssov_info, ni_pam_min_uid), + "(OLcfgCtAt:3.7 NAME 'olcNssPamMinUid' " + "DESC 'Minimum UID allowed to login' " + "EQUALITY integerMatch " + "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, + { "nssov-pam-max-uid", "uid", 2, 2, 0, ARG_OFFSET|ARG_INT, + (void *)offsetof(struct nssov_info, ni_pam_max_uid), + "(OLcfgCtAt:3.8 NAME 'olcNssPamMaxUid' " + "DESC 'Maximum UID allowed to login' " + "EQUALITY integerMatch " + "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, + { "nssov-pam-template-ad", "attr", 2, 2, 0, ARG_OFFSET|ARG_ATDESC, + (void *)offsetof(struct nssov_info, ni_pam_template_ad), + "(OLcfgCtAt:3.9 NAME 'olcNssPamTemplateAD' " + "DESC 'Attribute to use for template login name' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, + { "nssov-pam-template", "name", 2, 2, 0, ARG_OFFSET|ARG_BERVAL, + (void *)offsetof(struct nssov_info, ni_pam_template), + "(OLcfgCtAt:3.10 NAME 'olcNssPamTemplate' " + "DESC 'Default template login name' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, + { "nssov-pam-session", "service", 2, 2, 0, ARG_MAGIC|NSS_PAMSESS, + nss_cf_gen, "(OLcfgCtAt:3.11 NAME 'olcNssPamSession' " + "DESC 'Services for which sessions will be recorded' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString )", NULL, NULL }, + { "nssov-pam-password-prohibit-message", + "password_prohibit_message", 2, 2, 0, + ARG_OFFSET|ARG_BERVAL, + (void *)offsetof(struct nssov_info, ni_pam_password_prohibit_message), + "(OLcfgCtAt:3.12 NAME 'olcNssPamPwdProhibitMsg' " + "DESC 'Prohibit password modification message' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, + { "nssov-pam-pwdmgr-dn", + "pwdmgr_dn", 2, 2, 0, + ARG_OFFSET|ARG_BERVAL, + (void *)offsetof(struct nssov_info, ni_pam_pwdmgr_dn), + "(OLcfgCtAt:3.13 NAME 'olcPamPwdmgrDn' " + "DESC 'Password Manager DN' " + "EQUALITY distinguishedNameMatch " + "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL }, + { "nssov-pam-pwdmgr-pwd", + "pwdmgr_pwd", 2, 2, 0, + ARG_OFFSET|ARG_BERVAL, + (void *)offsetof(struct nssov_info, ni_pam_pwdmgr_pwd), + "(OLcfgCtAt:3.14 NAME 'olcPamPwdmgrPwd' " + "DESC 'Password Manager Pwd' " + "EQUALITY octetStringMatch " + "SYNTAX OMsOctetString SINGLE-VALUE )", NULL, NULL }, + { NULL, NULL, 0,0,0, ARG_IGNORED } +}; + +static ConfigOCs nssocs[] = { + { "( OLcfgCtOc:3.1 " + "NAME 'olcNssOvConfig' " + "DESC 'NSS lookup configuration' " + "SUP olcOverlayConfig " + "MAY ( olcNssSsd $ olcNssMap $ olcNssPam $ olcNssPamDefHost $ " + "olcNssPamGroupDN $ olcNssPamGroupAD $ " + "olcNssPamMinUid $ olcNssPamMaxUid $ olcNssPamSession $ " + "olcNssPamTemplateAD $ olcNssPamTemplate ) )", + Cft_Overlay, nsscfg }, + { NULL, 0, NULL } +}; + +static int +nss_cf_gen(ConfigArgs *c) +{ + slap_overinst *on = (slap_overinst *)c->bi; + nssov_info *ni = on->on_bi.bi_private; + nssov_mapinfo *mi; + int i, j, rc = 0; + slap_mask_t m; + + if ( c->op == SLAP_CONFIG_EMIT ) { + switch(c->type) { + case NSS_SSD: + rc = 1; + for (i=NM_alias;i<NM_NONE;i++) { + struct berval scope; + struct berval ssd; + struct berval base; + + mi = &ni->ni_maps[i]; + + /* ignore all-default services */ + if ( mi->mi_scope == LDAP_SCOPE_DEFAULT && + bvmatch( &mi->mi_filter, &mi->mi_filter0 ) && + BER_BVISNULL( &mi->mi_base )) + continue; + + if ( BER_BVISNULL( &mi->mi_base )) + base = ni->ni_db->be_nsuffix[0]; + else + base = mi->mi_base; + ldap_pvt_scope2bv(mi->mi_scope == LDAP_SCOPE_DEFAULT ? + LDAP_SCOPE_SUBTREE : mi->mi_scope, &scope); + ssd.bv_len = STRLENOF(" ldap:///???") + nss_svcs[i].word.bv_len + + base.bv_len + scope.bv_len + mi->mi_filter.bv_len; + ssd.bv_val = ch_malloc( ssd.bv_len + 1 ); + sprintf(ssd.bv_val, "%s ldap:///%s??%s?%s", nss_svcs[i].word.bv_val, + base.bv_val, scope.bv_val, mi->mi_filter.bv_val ); + ber_bvarray_add( &c->rvalue_vals, &ssd ); + rc = 0; + } + break; + case NSS_MAP: + rc = 1; + for (i=NM_alias;i<NM_NONE;i++) { + + mi = &ni->ni_maps[i]; + for (j=0;!BER_BVISNULL(&mi->mi_attrkeys[j]);j++) { + if ( ber_bvstrcasecmp(&mi->mi_attrkeys[j], + &mi->mi_attrs[j].an_name)) { + struct berval map; + + map.bv_len = nss_svcs[i].word.bv_len + + mi->mi_attrkeys[j].bv_len + + mi->mi_attrs[j].an_desc->ad_cname.bv_len + 2; + map.bv_val = ch_malloc(map.bv_len + 1); + sprintf(map.bv_val, "%s %s %s", nss_svcs[i].word.bv_val, + mi->mi_attrkeys[j].bv_val, mi->mi_attrs[j].an_desc->ad_cname.bv_val ); + ber_bvarray_add( &c->rvalue_vals, &map ); + rc = 0; + } + } + } + break; + case NSS_PAM: + rc = mask_to_verbs( pam_opts, ni->ni_pam_opts, &c->rvalue_vals ); + break; + case NSS_PAMGROUP: + if (!BER_BVISEMPTY( &ni->ni_pam_group_dn )) { + value_add_one( &c->rvalue_vals, &ni->ni_pam_group_dn ); + value_add_one( &c->rvalue_nvals, &ni->ni_pam_group_dn ); + } else { + rc = 1; + } + break; + case NSS_PAMSESS: + if (ni->ni_pam_sessions) { + ber_bvarray_dup_x( &c->rvalue_vals, ni->ni_pam_sessions, NULL ); + } else { + rc = 1; + } + break; + } + return rc; + } else if ( c->op == LDAP_MOD_DELETE ) { + /* FIXME */ + return 1; + } + switch( c->type ) { + case NSS_SSD: { + LDAPURLDesc *lud; + + i = verb_to_mask(c->argv[1], nss_svcs); + if ( i == NM_NONE ) + return 1; + + mi = &ni->ni_maps[i]; + rc = ldap_url_parse(c->argv[2], &lud); + if ( rc ) + return 1; + do { + struct berval base; + /* Must be LDAP scheme */ + if (strcasecmp(lud->lud_scheme,"ldap")) { + rc = 1; + break; + } + /* Host part, attrs, and extensions must be empty */ + if (( lud->lud_host && *lud->lud_host ) || + lud->lud_attrs || lud->lud_exts ) { + rc = 1; + break; + } + ber_str2bv( lud->lud_dn,0,0,&base); + rc = dnNormalize( 0,NULL,NULL,&base,&mi->mi_base,NULL); + if ( rc ) + break; + if ( lud->lud_filter ) { + /* steal this */ + ber_str2bv( lud->lud_filter,0,0,&mi->mi_filter); + lud->lud_filter = NULL; + } + mi->mi_scope = lud->lud_scope; + } while(0); + ldap_free_urldesc( lud ); + } + break; + case NSS_MAP: + i = verb_to_mask(c->argv[1], nss_svcs); + if ( i == NM_NONE ) + return 1; + rc = 1; + mi = &ni->ni_maps[i]; + for (j=0; !BER_BVISNULL(&mi->mi_attrkeys[j]); j++) { + if (!strcasecmp(c->argv[2],mi->mi_attrkeys[j].bv_val)) { + AttributeDescription *ad = NULL; + const char *text; + rc = slap_str2ad( c->argv[3], &ad, &text); + if ( rc == 0 ) { + mi->mi_attrs[j].an_desc = ad; + mi->mi_attrs[j].an_name = ad->ad_cname; + } + break; + } + } + break; + case NSS_PAM: + m = ni->ni_pam_opts; + i = verbs_to_mask(c->argc, c->argv, pam_opts, &m); + if (i == 0) { + ni->ni_pam_opts = m; + if ((m & NI_PAM_USERHOST) && !nssov_pam_host_ad) { + const char *text; + i = slap_str2ad("host", &nssov_pam_host_ad, &text); + if (i != LDAP_SUCCESS) { + snprintf(c->cr_msg, sizeof(c->cr_msg), + "nssov: host attr unknown: %s", text); + Debug(LDAP_DEBUG_ANY,"%s\n",c->cr_msg,0,0); + rc = 1; + break; + } + } + if ((m & (NI_PAM_USERSVC|NI_PAM_HOSTSVC)) && !nssov_pam_svc_ad) { + const char *text; + i = slap_str2ad("authorizedService", &nssov_pam_svc_ad, &text); + if (i != LDAP_SUCCESS) { + snprintf(c->cr_msg, sizeof(c->cr_msg), + "nssov: authorizedService attr unknown: %s", text); + Debug(LDAP_DEBUG_ANY,"%s\n",c->cr_msg,0,0); + rc = 1; + break; + } + } + } else { + rc = 1; + } + break; + case NSS_PAMGROUP: + ni->ni_pam_group_dn = c->value_ndn; + ch_free( c->value_dn.bv_val ); + break; + case NSS_PAMSESS: + ber_str2bv( c->argv[1], 0, 1, &c->value_bv ); + ber_bvarray_add( &ni->ni_pam_sessions, &c->value_bv ); + break; + } + return rc; +} + +static int +nssov_db_init( + BackendDB *be, + ConfigReply *cr ) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + nssov_info *ni; + int rc; + + rc = nssov_pam_init(); + if (rc) return rc; + + ni = ch_calloc( 1, sizeof(nssov_info) ); + on->on_bi.bi_private = ni; + + /* set up map keys */ + nssov_alias_init(ni); + nssov_ether_init(ni); + nssov_group_init(ni); + nssov_host_init(ni); + nssov_netgroup_init(ni); + nssov_network_init(ni); + nssov_passwd_init(ni); + nssov_protocol_init(ni); + nssov_rpc_init(ni); + nssov_service_init(ni); + nssov_shadow_init(ni); + + ni->ni_db = be->bd_self; + ni->ni_pam_opts = NI_PAM_UID2DN; + + return 0; +} + +static int +nssov_db_destroy( + BackendDB *be, + ConfigReply *cr ) +{ + return 0; +} + +static int +nssov_db_open( + BackendDB *be, + ConfigReply *cr ) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + nssov_info *ni = on->on_bi.bi_private; + nssov_mapinfo *mi; + + int i, sock; + struct sockaddr_un addr; + + /* Set default bases */ + for (i=0; i<NM_NONE; i++) { + if ( BER_BVISNULL( &ni->ni_maps[i].mi_base )) { + ber_dupbv( &ni->ni_maps[i].mi_base, &be->be_nsuffix[0] ); + } + if ( ni->ni_maps[i].mi_scope == LDAP_SCOPE_DEFAULT ) + ni->ni_maps[i].mi_scope = LDAP_SCOPE_SUBTREE; + } + /* validate attribute maps */ + mi = ni->ni_maps; + for ( i=0; i<NM_NONE; i++,mi++) { + const char *text; + int j; + for (j=0; !BER_BVISNULL(&mi->mi_attrkeys[j]); j++) { + /* skip attrs we already validated */ + if ( mi->mi_attrs[j].an_desc ) continue; + if ( slap_bv2ad( &mi->mi_attrs[j].an_name, + &mi->mi_attrs[j].an_desc, &text )) { + Debug(LDAP_DEBUG_ANY,"nssov: invalid attr \"%s\": %s\n", + mi->mi_attrs[j].an_name.bv_val, text, 0 ); + return -1; + } + } + BER_BVZERO(&mi->mi_attrs[j].an_name); + mi->mi_attrs[j].an_desc = NULL; + } + + /* Find host and authorizedService definitions */ + if ((ni->ni_pam_opts & NI_PAM_USERHOST) && !nssov_pam_host_ad) + { + const char *text; + i = slap_str2ad("host", &nssov_pam_host_ad, &text); + if (i != LDAP_SUCCESS) { + Debug(LDAP_DEBUG_ANY,"nssov: host attr unknown: %s\n", + text, 0, 0 ); + return -1; + } + } + if ((ni->ni_pam_opts & (NI_PAM_USERSVC|NI_PAM_HOSTSVC)) && + !nssov_pam_svc_ad) + { + const char *text; + i = slap_str2ad("authorizedService", &nssov_pam_svc_ad, &text); + if (i != LDAP_SUCCESS) { + Debug(LDAP_DEBUG_ANY,"nssov: authorizedService attr unknown: %s\n", + text, 0, 0 ); + return -1; + } + } + if ( slapMode & SLAP_SERVER_MODE ) { + /* make sure /var/run/nslcd exists */ + if (mkdir(NSLCD_PATH, (mode_t) 0555)) { + Debug(LDAP_DEBUG_TRACE,"nssov: mkdir(%s) failed (ignored): %s\n", + NSLCD_PATH,strerror(errno),0); + } else { + Debug(LDAP_DEBUG_TRACE,"nssov: created %s\n",NSLCD_PATH,0,0); + } + + /* create a socket */ + if ( (sock=socket(PF_UNIX,SOCK_STREAM,0))<0 ) + { + Debug(LDAP_DEBUG_ANY,"nssov: cannot create socket: %s\n",strerror(errno),0,0); + return -1; + } + /* remove existing named socket */ + if (unlink(NSLCD_SOCKET)<0) + { + Debug( LDAP_DEBUG_TRACE,"nssov: unlink() of "NSLCD_SOCKET" failed (ignored): %s\n", + strerror(errno),0,0); + } + /* create socket address structure */ + memset(&addr,0,sizeof(struct sockaddr_un)); + addr.sun_family=AF_UNIX; + strncpy(addr.sun_path,NSLCD_SOCKET,sizeof(addr.sun_path)); + addr.sun_path[sizeof(addr.sun_path)-1]='\0'; + /* bind to the named socket */ + if (bind(sock,(struct sockaddr *)&addr,sizeof(struct sockaddr_un))) + { + Debug( LDAP_DEBUG_ANY,"nssov: bind() to "NSLCD_SOCKET" failed: %s", + strerror(errno),0,0); + if (close(sock)) + Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",strerror(errno),0,0); + return -1; + } + /* close the file descriptor on exit */ + if (fcntl(sock,F_SETFD,FD_CLOEXEC)<0) + { + Debug( LDAP_DEBUG_ANY,"nssov: fcntl(F_SETFL,O_NONBLOCK) failed: %s",strerror(errno),0,0); + if (close(sock)) + Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",strerror(errno),0,0); + return -1; + } + /* set permissions of socket so anybody can do requests */ + /* Note: we use chmod() here instead of fchmod() because + fchmod does not work on sockets + http://www.opengroup.org/onlinepubs/009695399/functions/fchmod.html + http://lkml.org/lkml/2005/5/16/11 */ + if (chmod(NSLCD_SOCKET,(mode_t)0666)) + { + Debug( LDAP_DEBUG_ANY,"nssov: chmod(0666) failed: %s",strerror(errno),0,0); + if (close(sock)) + Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",strerror(errno),0,0); + return -1; + } + /* start listening for connections */ + if (listen(sock,SOMAXCONN)<0) + { + Debug( LDAP_DEBUG_ANY,"nssov: listen() failed: %s",strerror(errno),0,0); + if (close(sock)) + Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",strerror(errno),0,0); + return -1; + } + ni->ni_socket = sock; + ni->ni_conn = connection_client_setup( sock, acceptconn, ni ); + } + + return 0; +} + +static int +nssov_db_close( + BackendDB *be, + ConfigReply *cr ) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + nssov_info *ni = on->on_bi.bi_private; + + if ( slapMode & SLAP_SERVER_MODE ) { + /* close socket if it's still in use */ + if (ni->ni_socket >= 0) + { + if (close(ni->ni_socket)) + Debug( LDAP_DEBUG_ANY,"problem closing server socket (ignored): %s",strerror(errno),0,0); + ni->ni_socket = -1; + } + /* remove existing named socket */ + if (unlink(NSLCD_SOCKET)<0) + { + Debug( LDAP_DEBUG_TRACE,"unlink() of "NSLCD_SOCKET" failed (ignored): %s", + strerror(errno),0,0); + } + } + return 0; +} + +static slap_overinst nssov; + +int +nssov_initialize( void ) +{ + int rc; + + nssov.on_bi.bi_type = "nssov"; + nssov.on_bi.bi_db_init = nssov_db_init; + nssov.on_bi.bi_db_destroy = nssov_db_destroy; + nssov.on_bi.bi_db_open = nssov_db_open; + nssov.on_bi.bi_db_close = nssov_db_close; + + nssov.on_bi.bi_cf_ocs = nssocs; + + rc = config_register_schema( nsscfg, nssocs ); + if ( rc ) return rc; + + return overlay_register(&nssov); +} + +#if SLAPD_OVER_NSSOV == SLAPD_MOD_DYNAMIC +int +init_module( int argc, char *argv[] ) +{ + return nssov_initialize(); +} +#endif diff --git a/contrib/slapd-modules/nssov/nssov.h b/contrib/slapd-modules/nssov/nssov.h new file mode 100644 index 0000000..9677e21 --- /dev/null +++ b/contrib/slapd-modules/nssov/nssov.h @@ -0,0 +1,347 @@ +/* nssov.h - NSS overlay header file */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2008-2021 The OpenLDAP Foundation. + * Portions Copyright 2008 Howard Chu. + * Portions Copyright 2013 Ted C. Cheng, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ + +#ifndef NSSOV_H +#define NSSOV_H + +#ifndef NSLCD_PATH +#define NSLCD_PATH "/var/run/nslcd" +#endif + +#ifndef NSLCD_SOCKET +#define NSLCD_SOCKET NSLCD_PATH "/socket" +#endif + +#include <stdio.h> + +#include "nslcd.h" +#include "nslcd-prot.h" +#include "tio.h" +#include "attrs.h" + +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION + +#include "portable.h" +#include "slap.h" +#include <ac/string.h> + +/* selectors for different maps */ +enum nssov_map_selector +{ + NM_alias, + NM_ether, + NM_group, + NM_host, + NM_netgroup, + NM_network, + NM_passwd, + NM_protocol, + NM_rpc, + NM_service, + NM_shadow, + NM_NONE +}; + +typedef struct nssov_mapinfo { + struct berval mi_base; + int mi_scope; + struct berval mi_filter0; + struct berval mi_filter; + struct berval *mi_attrkeys; + AttributeName *mi_attrs; +} nssov_mapinfo; + +typedef struct nssov_info +{ + /* search timelimit */ + int ni_timelimit; + struct nssov_mapinfo ni_maps[NM_NONE]; + int ni_socket; + Connection *ni_conn; + BackendDB *ni_db; + + /* PAM authz support... */ + slap_mask_t ni_pam_opts; + struct berval ni_pam_group_dn; + AttributeDescription *ni_pam_group_ad; + int ni_pam_min_uid; + int ni_pam_max_uid; + AttributeDescription *ni_pam_template_ad; + struct berval ni_pam_template; + struct berval ni_pam_defhost; + struct berval *ni_pam_sessions; + struct berval ni_pam_password_prohibit_message; + struct berval ni_pam_pwdmgr_dn; + struct berval ni_pam_pwdmgr_pwd; +} nssov_info; + +#define NI_PAM_USERHOST 1 /* old style host checking */ +#define NI_PAM_USERSVC 2 /* old style service checking */ +#define NI_PAM_USERGRP 4 /* old style group checking */ +#define NI_PAM_HOSTSVC 8 /* new style authz checking */ +#define NI_PAM_SASL2DN 0x10 /* use sasl2dn */ +#define NI_PAM_UID2DN 0x20 /* use uid2dn */ + +#define NI_PAM_OLD (NI_PAM_USERHOST|NI_PAM_USERSVC|NI_PAM_USERGRP) +#define NI_PAM_NEW NI_PAM_HOSTSVC + +extern AttributeDescription *nssov_pam_host_ad; +extern AttributeDescription *nssov_pam_svc_ad; + +/* Read the default configuration file. */ +void nssov_cfg_init(nssov_info *ni,const char *fname); + +/* macros for basic read and write operations, the following + ERROR_OUT* marcos define the action taken on errors + the stream is not closed because the caller closes the + stream */ + +#define ERROR_OUT_WRITEERROR(fp) \ + Debug(LDAP_DEBUG_ANY,"nssov: error writing to client\n",0,0,0); \ + return -1; + +#define ERROR_OUT_READERROR(fp) \ + Debug(LDAP_DEBUG_ANY,"nssov: error reading from client\n",0,0,0); \ + return -1; + +#define ERROR_OUT_BUFERROR(fp) \ + Debug(LDAP_DEBUG_ANY,"nssov: client supplied argument too large\n",0,0,0); \ + return -1; + +#define WRITE_BERVAL(fp, bv) \ + DEBUG_PRINT("WRITE_BERVAL: var="__STRING(bv)" bv_val=\"%s\"", (bv)->bv_val); \ + if ((bv) == NULL) \ + { \ + WRITE_INT32(fp, 0); \ + } \ + else \ + { \ + WRITE_INT32(fp, (bv)->bv_len); \ + tmpint32 = ntohl(tmpint32); \ + if (tmpint32 > 0) \ + { \ + WRITE(fp, (bv)->bv_val, tmpint32); \ + } \ + } \ + +#define WRITE_BVARRAY(fp, arr) \ + if ((arr) == NULL) \ + { \ + DEBUG_PRINT("WRITE_BVARRAY: var="__STRING(arr)" num=%d", 0); \ + WRITE_INT32(fp, 0); \ + } \ + else \ + { \ + /* first determine length of array */ \ + for (tmp3int32 = 0; (arr)[tmp3int32].bv_val != NULL; tmp3int32++) \ + /* nothing */ ; \ + /* write number of strings */ \ + DEBUG_PRINT("WRITE_BVARRAY: var="__STRING(arr)" num=%d", (int)tmp3int32); \ + WRITE_INT32(fp, tmp3int32); \ + /* write strings */ \ + for (tmp2int32 = 0; tmp2int32 < tmp3int32; tmp2int32++) \ + { \ + WRITE_BERVAL(fp, &(arr)[tmp2int32]); \ + } \ + } \ + +/* Find the given attribute's value in the RDN of the DN. */ +void nssov_find_rdnval(struct berval *dn,AttributeDescription *ad,struct berval *value); + +/* This tries to get the user password attribute from the entry. + It will try to return an encrypted password as it is used in /etc/passwd, + /etc/group or /etc/shadow depending upon what is in the directory. + This function will return NULL if no passwd is found and will return the + literal value in the directory if conversion is not possible. */ +void get_userpassword(struct berval *attr, struct berval *pw); + +/* write out an address, parsing the addr value */ +int write_address(TFILE *fp,struct berval *addr); + +/* a helper macro to write out addresses and bail out on errors */ +#define WRITE_ADDRESS(fp,addr) \ + if (write_address(fp,addr)) \ + return -1; + +/* read an address from the stream */ +int read_address(TFILE *fp,char *addr,int *addrlen,int *af); + +/* helper macro to read an address from the stream */ +#define READ_ADDRESS(fp,addr,len,af) \ + len=(int)sizeof(addr); \ + if (read_address(fp,addr,&(len),&(af))) \ + return -1; + +/* checks to see if the specified string is a valid username */ +int isvalidusername(struct berval *name); + +/* transforms the DN into a uid doing an LDAP lookup if needed */ +int nssov_dn2uid(Operation *op,nssov_info *ni,struct berval *dn,struct berval *uid); + +/* transforms the uid into a DN by doing an LDAP lookup */ +int nssov_uid2dn(Operation *op,nssov_info *ni,struct berval *uid,struct berval *dn); +int nssov_name2dn_cb(Operation *op, SlapReply *rs); + +/* Escapes characters in a string for use in a search filter. */ +int nssov_escape(struct berval *src,struct berval *dst); + +int nssov_filter_byname(nssov_mapinfo *mi,int key,struct berval *name,struct berval *buf); +int nssov_filter_byid(nssov_mapinfo *mi,int key,struct berval *id,struct berval *buf); + +void nssov_alias_init(nssov_info *ni); +void nssov_ether_init(nssov_info *ni); +void nssov_group_init(nssov_info *ni); +void nssov_host_init(nssov_info *ni); +void nssov_netgroup_init(nssov_info *ni); +void nssov_network_init(nssov_info *ni); +void nssov_passwd_init(nssov_info *ni); +void nssov_protocol_init(nssov_info *ni); +void nssov_rpc_init(nssov_info *ni); +void nssov_service_init(nssov_info *ni); +void nssov_shadow_init(nssov_info *ni); + +int nssov_pam_init(void); + +/* these are the different functions that handle the database + specific actions, see nslcd.h for the action descriptions */ +int nssov_alias_byname(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_alias_all(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_ether_byname(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_ether_byether(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_ether_all(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_group_byname(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_group_bygid(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_group_bymember(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_group_all(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_host_byname(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_host_byaddr(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_host_all(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_netgroup_byname(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_network_byname(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_network_byaddr(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_network_all(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_passwd_byname(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_passwd_byuid(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_passwd_all(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_protocol_byname(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_protocol_bynumber(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_protocol_all(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_rpc_byname(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_rpc_bynumber(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_rpc_all(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_service_byname(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_service_bynumber(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_service_all(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_shadow_byname(nssov_info *ni,TFILE *fp,Operation *op); +int nssov_shadow_all(nssov_info *ni,TFILE *fp,Operation *op); +int pam_authc(nssov_info *ni,TFILE *fp,Operation *op,uid_t calleruid); +int pam_authz(nssov_info *ni,TFILE *fp,Operation *op); +int pam_sess_o(nssov_info *ni,TFILE *fp,Operation *op); +int pam_sess_c(nssov_info *ni,TFILE *fp,Operation *op); +int pam_pwmod(nssov_info *ni,TFILE *fp,Operation *op,uid_t calleruid); + +/* config initialization */ +#define NSSOV_INIT(db) \ + void nssov_##db##_init(nssov_info *ni) \ + { \ + nssov_mapinfo *mi = &ni->ni_maps[NM_##db]; \ + int i; \ + for (i=0;!BER_BVISNULL(&db##_keys[i]);i++); \ + i++; \ + mi->mi_attrs = ch_malloc( i*sizeof(AttributeName)); \ + for (i=0;!BER_BVISNULL(&db##_keys[i]);i++) { \ + mi->mi_attrs[i].an_name = db##_keys[i]; \ + mi->mi_attrs[i].an_desc = NULL; \ + } \ + mi->mi_scope = LDAP_SCOPE_DEFAULT; \ + mi->mi_filter0 = db##_filter; \ + ber_dupbv( &mi->mi_filter, &mi->mi_filter0 ); \ + mi->mi_filter = db##_filter; \ + mi->mi_attrkeys = db##_keys; \ + BER_BVZERO(&mi->mi_base); \ + } + +/* param structure for search callback */ +#define NSSOV_CBPRIV(db,parms) \ + typedef struct nssov_##db##_cbp { \ + nssov_mapinfo *mi; \ + TFILE *fp; \ + Operation *op; \ + parms \ + } nssov_##db##_cbp + +/* callback for writing search results */ +#define NSSOV_CB(db) \ + static int nssov_##db##_cb(Operation *op, SlapReply *rs) \ + { \ + if ( rs->sr_type == REP_SEARCH ) { \ + nssov_##db##_cbp *cbp = op->o_callback->sc_private; \ + if (write_##db(cbp,rs->sr_entry)) return LDAP_OTHER; \ + } \ + return LDAP_SUCCESS; \ + } \ + +/* macro for generating service handling code */ +#define NSSOV_HANDLE(db,fn,readfn,logcall,action,mkfilter) \ + int nssov_##db##_##fn(nssov_info *ni,TFILE *fp,Operation *op) \ + { \ + /* define common variables */ \ + int32_t tmpint32; \ + nssov_##db##_cbp cbp; \ + slap_callback cb = {0}; \ + SlapReply rs = {REP_RESULT}; \ + cbp.mi = &ni->ni_maps[NM_##db]; \ + cbp.fp = fp; \ + cbp.op = op; \ + /* read request parameters */ \ + readfn; \ + /* log call */ \ + logcall; \ + /* write the response header */ \ + WRITE_INT32(fp,NSLCD_VERSION); \ + WRITE_INT32(fp,action); \ + /* prepare the search filter */ \ + if (mkfilter) \ + { \ + Debug(LDAP_DEBUG_ANY,"nssov_" __STRING(db) "_" __STRING(fn) "(): filter buffer too small",0,0,0); \ + return -1; \ + } \ + cb.sc_private = &cbp; \ + op->o_callback = &cb; \ + cb.sc_response = nssov_##db##_cb; \ + slap_op_time( &op->o_time, &op->o_tincr ); \ + op->o_req_dn = cbp.mi->mi_base; \ + op->o_req_ndn = cbp.mi->mi_base; \ + op->ors_scope = cbp.mi->mi_scope; \ + op->ors_filterstr = filter; \ + op->ors_filter = str2filter_x( op, filter.bv_val ); \ + op->ors_attrs = cbp.mi->mi_attrs; \ + op->ors_tlimit = SLAP_NO_LIMIT; \ + op->ors_slimit = SLAP_NO_LIMIT; \ + /* do the internal search */ \ + op->o_bd->be_search( op, &rs ); \ + filter_free_x( op, op->ors_filter, 1 ); \ + WRITE_INT32(fp,NSLCD_RESULT_END); \ + return 0; \ + } + +#endif /* NSSOV_H */ diff --git a/contrib/slapd-modules/nssov/pam.c b/contrib/slapd-modules/nssov/pam.c new file mode 100644 index 0000000..e4eb3d2 --- /dev/null +++ b/contrib/slapd-modules/nssov/pam.c @@ -0,0 +1,864 @@ +/* pam.c - pam processing routines */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2008-2021 The OpenLDAP Foundation. + * Portions Copyright 2008 by Howard Chu, Symas Corp. + * Portions Copyright 2013 by Ted C. Cheng, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ + +#include "nssov.h" +#include "lutil.h" + +#undef ldap_debug /* silence a warning in ldap-int.h */ +#include "../../../libraries/libldap/ldap-int.h" /* for ldap_ld_free */ + +static int ppolicy_cid; +static AttributeDescription *ad_loginStatus; + +struct paminfo { + struct berval uid; + struct berval dn; + struct berval svc; + struct berval ruser; + struct berval rhost; + struct berval tty; + struct berval pwd; + int authz; + struct berval msg; + int ispwdmgr; +}; + +static int pam_bindcb( + Operation *op, SlapReply *rs) +{ + struct paminfo *pi = op->o_callback->sc_private; + LDAPControl *ctrl = ldap_control_find(LDAP_CONTROL_PASSWORDPOLICYRESPONSE, + rs->sr_ctrls, NULL); + if (ctrl) { + LDAP *ld; + ber_int_t expire, grace; + LDAPPasswordPolicyError error; + + ldap_create(&ld); + if (ld) { + int rc = ldap_parse_passwordpolicy_control(ld,ctrl, + &expire,&grace,&error); + if (rc == LDAP_SUCCESS) { + if (expire >= 0) { + char *unit = "seconds"; + if (expire > 60) { + expire /= 60; + unit = "minutes"; + } + if (expire > 60) { + expire /= 60; + unit = "hours"; + } + if (expire > 24) { + expire /= 24; + unit = "days"; + } +#if 0 /* Who warns about expiration so far in advance? */ + if (expire > 7) { + expire /= 7; + unit = "weeks"; + } + if (expire > 4) { + expire /= 4; + unit = "months"; + } + if (expire > 12) { + expire /= 12; + unit = "years"; + } +#endif + pi->msg.bv_len = sprintf(pi->msg.bv_val, + "\nWARNING: Password expires in %d %s\n", expire, unit); + } else if (grace > 0) { + pi->msg.bv_len = sprintf(pi->msg.bv_val, + "Password expired; %d grace logins remaining", + grace); + pi->authz = NSLCD_PAM_NEW_AUTHTOK_REQD; + } else if (error != PP_noError) { + ber_str2bv(ldap_passwordpolicy_err2txt(error), 0, 0, + &pi->msg); + switch (error) { + case PP_passwordExpired: + /* report this during authz */ + rs->sr_err = LDAP_SUCCESS; + /* fallthru */ + case PP_changeAfterReset: + pi->authz = NSLCD_PAM_NEW_AUTHTOK_REQD; + } + } + } + ldap_ld_free(ld,0,NULL,NULL); + } + } + return LDAP_SUCCESS; +} + +static int pam_uid2dn(nssov_info *ni, Operation *op, + struct paminfo *pi) +{ + struct berval sdn; + + BER_BVZERO(&pi->dn); + + if (!isvalidusername(&pi->uid)) { + Debug(LDAP_DEBUG_ANY,"nssov_pam_uid2dn(%s): invalid user name\n", + pi->uid.bv_val ? pi->uid.bv_val : "NULL",0,0); + return NSLCD_PAM_USER_UNKNOWN; + } + + if (ni->ni_pam_opts & NI_PAM_SASL2DN) { + int hlen = global_host_bv.bv_len; + + /* cn=<service>+uid=<user>,cn=<host>,cn=pam,cn=auth */ + sdn.bv_len = pi->uid.bv_len + pi->svc.bv_len + hlen + + STRLENOF( "cn=+uid=,cn=,cn=pam,cn=auth" ); + sdn.bv_val = op->o_tmpalloc( sdn.bv_len + 1, op->o_tmpmemctx ); + sprintf(sdn.bv_val, "cn=%s+uid=%s,cn=%s,cn=pam,cn=auth", + pi->svc.bv_val, pi->uid.bv_val, global_host_bv.bv_val); + slap_sasl2dn(op, &sdn, &pi->dn, 0); + op->o_tmpfree( sdn.bv_val, op->o_tmpmemctx ); + } + + /* If no luck, do a basic uid search */ + if (BER_BVISEMPTY(&pi->dn) && (ni->ni_pam_opts & NI_PAM_UID2DN)) { + nssov_uid2dn(op, ni, &pi->uid, &pi->dn); + if (!BER_BVISEMPTY(&pi->dn)) { + sdn = pi->dn; + dnNormalize( 0, NULL, NULL, &sdn, &pi->dn, op->o_tmpmemctx ); + } + } + if (BER_BVISEMPTY(&pi->dn)) { + return NSLCD_PAM_USER_UNKNOWN; + } + return 0; +} + +int pam_do_bind(nssov_info *ni,TFILE *fp,Operation *op, + struct paminfo *pi) +{ + int rc; + slap_callback cb = {0}; + SlapReply rs = {REP_RESULT}; + + pi->msg.bv_val = pi->pwd.bv_val; + pi->msg.bv_len = 0; + pi->authz = NSLCD_PAM_SUCCESS; + + if (!pi->ispwdmgr) { + + rc = pam_uid2dn(ni, op, pi); + if (rc) goto finish; + + if (BER_BVISEMPTY(&pi->pwd)) { + rc = NSLCD_PAM_PERM_DENIED; + goto finish; + } + + /* Should only need to do this once at open time, but there's always + * the possibility that ppolicy will get loaded later. + */ + if (!ppolicy_cid) { + rc = slap_find_control_id(LDAP_CONTROL_PASSWORDPOLICYREQUEST, + &ppolicy_cid); + } + /* of course, 0 is a valid cid, but it won't be ppolicy... */ + if (ppolicy_cid) { + op->o_ctrlflag[ppolicy_cid] = SLAP_CONTROL_NONCRITICAL; + } + } + + cb.sc_response = pam_bindcb; + cb.sc_private = pi; + op->o_callback = &cb; + op->o_dn.bv_val[0] = 0; + op->o_dn.bv_len = 0; + op->o_ndn.bv_val[0] = 0; + op->o_ndn.bv_len = 0; + op->o_tag = LDAP_REQ_BIND; + op->o_protocol = LDAP_VERSION3; + op->orb_method = LDAP_AUTH_SIMPLE; + op->orb_cred = pi->pwd; + op->o_req_dn = pi->dn; + op->o_req_ndn = pi->dn; + slap_op_time( &op->o_time, &op->o_tincr ); + rc = op->o_bd->be_bind( op, &rs ); + memset(pi->pwd.bv_val,0,pi->pwd.bv_len); + /* quirk: on successful bind, caller has to send result. we need + * to make sure callbacks run. + */ + if (rc == LDAP_SUCCESS) + send_ldap_result(op, &rs); + switch(rs.sr_err) { + case LDAP_SUCCESS: rc = NSLCD_PAM_SUCCESS; break; + case LDAP_INVALID_CREDENTIALS: rc = NSLCD_PAM_AUTH_ERR; break; + default: rc = NSLCD_PAM_AUTH_ERR; break; + } +finish: + Debug(LDAP_DEBUG_ANY,"pam_do_bind (%s): rc (%d)\n", + pi->dn.bv_val ? pi->dn.bv_val : "NULL", rc, 0); + return rc; +} + +int pam_authc(nssov_info *ni,TFILE *fp,Operation *op,uid_t calleruid) +{ + int32_t tmpint32; + int rc; + char uidc[32]; + char svcc[256]; + char ruserc[32]; + char rhostc[256]; + char ttyc[256]; + char pwdc[256]; + struct paminfo pi; + + + READ_STRING(fp,uidc); + pi.uid.bv_val = uidc; + pi.uid.bv_len = tmpint32; + READ_STRING(fp,svcc); + pi.svc.bv_val = svcc; + pi.svc.bv_len = tmpint32; + READ_STRING(fp,ruserc); + pi.ruser.bv_val = ruserc; + pi.ruser.bv_len = tmpint32; + READ_STRING(fp,rhostc); + pi.rhost.bv_val = rhostc; + pi.rhost.bv_len = tmpint32; + READ_STRING(fp,ttyc); + pi.tty.bv_val = ttyc; + pi.tty.bv_len = tmpint32; + READ_STRING(fp,pwdc); + pi.pwd.bv_val = pwdc; + pi.pwd.bv_len = tmpint32; + + Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(%s)\n", + pi.uid.bv_val ? pi.uid.bv_val : "NULL",0,0); + + BER_BVZERO(&pi.msg); + pi.ispwdmgr = 0; + + /* if service is "passwd" and "nssov-pam-password-prohibit-message */ + /* is set, deny the auth request */ + if (!strcmp(svcc, "passwd") && + !BER_BVISEMPTY(&ni->ni_pam_password_prohibit_message)) { + Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(): %s (%s)\n", + "password_prohibit_message for passwd", + ni->ni_pam_password_prohibit_message.bv_val,0); + ber_str2bv(ni->ni_pam_password_prohibit_message.bv_val, 0, 0, &pi.msg); + pi.authz = NSLCD_PAM_PERM_DENIED; + rc = NSLCD_PAM_PERM_DENIED; + goto finish; + } + + /* if username is null, pwdmgr password preliminary check */ + if (BER_BVISEMPTY(&pi.uid)) { + if (BER_BVISEMPTY(&ni->ni_pam_pwdmgr_dn)) { + /* pwdmgr dn not configured */ + Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(prelim check): %s\n", + "pwdmgr dn not configured", 0, 0); + ber_str2bv("pwdmgr dn not configured", 0, 0, &pi.msg); + pi.authz = NSLCD_PAM_PERM_DENIED; + rc = NSLCD_PAM_PERM_DENIED; + goto finish; + } else if (calleruid != 0) { + Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(prelim check): %s\n", + "caller is not root", 0, 0); + ber_str2bv("only root may do that", 0, 0, &pi.msg); + pi.authz = NSLCD_PAM_PERM_DENIED; + rc = NSLCD_PAM_PERM_DENIED; + goto finish; + } else { + /* use pwdmgr dn */ + ber_str2bv(ni->ni_pam_pwdmgr_dn.bv_val, 0, 0, &pi.dn); + } + + /* use pwdmgr pwd if configured */ + if (BER_BVISEMPTY(&pi.pwd)) { + if (BER_BVISEMPTY(&ni->ni_pam_pwdmgr_pwd)) { + Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(prelim check): %s\n", + "no pwdmgr pwd", 0, 0); + ber_str2bv("pwdmgr pwd not configured", 0, 0, &pi.msg); + pi.authz = NSLCD_PAM_PERM_DENIED; + rc = NSLCD_PAM_PERM_DENIED; + goto finish; + } + /* use configured pwdmgr pwd */ + memset((void *) pwdc, 0, 256); + strncpy(pi.pwd.bv_val, ni->ni_pam_pwdmgr_pwd.bv_val, + ni->ni_pam_pwdmgr_pwd.bv_len); + pi.pwd.bv_len = ni->ni_pam_pwdmgr_pwd.bv_len; + } + pi.ispwdmgr = 1; + } + + + rc = pam_do_bind(ni, fp, op, &pi); + +finish: + Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(%s): rc (%d)\n", + pi.dn.bv_val ? pi.dn.bv_val : "NULL",rc,0); + WRITE_INT32(fp,NSLCD_VERSION); + WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHC); + WRITE_INT32(fp,NSLCD_RESULT_BEGIN); + WRITE_INT32(fp,rc); + WRITE_BERVAL(fp,&pi.uid); + WRITE_INT32(fp,pi.authz); /* authz */ + WRITE_BERVAL(fp,&pi.msg); /* authzmsg */ + WRITE_INT32(fp,NSLCD_RESULT_END); + return 0; +} + +static struct berval grpmsg = + BER_BVC("Access denied by group check"); +static struct berval hostmsg = + BER_BVC("Access denied for this host"); +static struct berval svcmsg = + BER_BVC("Access denied for this service"); +static struct berval uidmsg = + BER_BVC("Access denied by UID check"); + +static int pam_compare_cb(Operation *op, SlapReply *rs) +{ + if (rs->sr_err == LDAP_COMPARE_TRUE) + op->o_callback->sc_private = (void *)1; + return LDAP_SUCCESS; +} + +int pam_authz(nssov_info *ni,TFILE *fp,Operation *op) +{ + struct berval authzmsg = BER_BVNULL; + int32_t tmpint32; + char uidc[32]; + char svcc[256]; + char ruserc[32]; + char rhostc[256]; + char ttyc[256]; + int rc; + struct paminfo pi; + Entry *e = NULL; + Attribute *a; + slap_callback cb = {0}; + + READ_STRING(fp,uidc); + pi.uid.bv_val = uidc; + pi.uid.bv_len = tmpint32; + READ_STRING(fp,svcc); + pi.svc.bv_val = svcc; + pi.svc.bv_len = tmpint32; + READ_STRING(fp,ruserc); + pi.ruser.bv_val = ruserc; + pi.ruser.bv_len = tmpint32; + READ_STRING(fp,rhostc); + pi.rhost.bv_val = rhostc; + pi.rhost.bv_len = tmpint32; + READ_STRING(fp,ttyc); + pi.tty.bv_val = ttyc; + pi.tty.bv_len = tmpint32; + + rc = pam_uid2dn(ni, op, &pi); + if (rc) goto finish; + + Debug(LDAP_DEBUG_TRACE,"nssov_pam_authz(%s)\n", + pi.dn.bv_val ? pi.dn.bv_val : "NULL",0,0); + + /* See if they have access to the host and service */ + if ((ni->ni_pam_opts & NI_PAM_HOSTSVC) && nssov_pam_svc_ad) { + AttributeAssertion ava = ATTRIBUTEASSERTION_INIT; + struct berval hostdn = BER_BVNULL; + struct berval odn = op->o_ndn; + SlapReply rs = {REP_RESULT}; + op->o_dn = pi.dn; + op->o_ndn = pi.dn; + { + nssov_mapinfo *mi = &ni->ni_maps[NM_host]; + char fbuf[1024]; + struct berval filter = {sizeof(fbuf),fbuf}; + SlapReply rs2 = {REP_RESULT}; + + /* Lookup the host entry */ + nssov_filter_byname(mi,0,&global_host_bv,&filter); + cb.sc_private = &hostdn; + cb.sc_response = nssov_name2dn_cb; + op->o_callback = &cb; + op->o_req_dn = mi->mi_base; + op->o_req_ndn = mi->mi_base; + op->ors_scope = mi->mi_scope; + op->ors_filterstr = filter; + op->ors_filter = str2filter_x(op, filter.bv_val); + op->ors_attrs = slap_anlist_no_attrs; + op->ors_tlimit = SLAP_NO_LIMIT; + op->ors_slimit = 2; + rc = op->o_bd->be_search(op, &rs2); + filter_free_x(op, op->ors_filter, 1); + + if (BER_BVISEMPTY(&hostdn) && + !BER_BVISEMPTY(&ni->ni_pam_defhost)) { + filter.bv_len = sizeof(fbuf); + filter.bv_val = fbuf; + rs_reinit(&rs2, REP_RESULT); + nssov_filter_byname(mi,0,&ni->ni_pam_defhost,&filter); + op->ors_filterstr = filter; + op->ors_filter = str2filter_x(op, filter.bv_val); + rc = op->o_bd->be_search(op, &rs2); + filter_free_x(op, op->ors_filter, 1); + } + + /* no host entry, no default host -> deny */ + if (BER_BVISEMPTY(&hostdn)) { + rc = NSLCD_PAM_PERM_DENIED; + authzmsg = hostmsg; + goto finish; + } + } + + cb.sc_response = pam_compare_cb; + cb.sc_private = NULL; + op->o_tag = LDAP_REQ_COMPARE; + op->o_req_dn = hostdn; + op->o_req_ndn = hostdn; + ava.aa_desc = nssov_pam_svc_ad; + ava.aa_value = pi.svc; + op->orc_ava = &ava; + rc = op->o_bd->be_compare( op, &rs ); + if ( cb.sc_private == NULL ) { + authzmsg = svcmsg; + rc = NSLCD_PAM_PERM_DENIED; + goto finish; + } + op->o_dn = odn; + op->o_ndn = odn; + } + + /* See if they're a member of the group */ + if ((ni->ni_pam_opts & NI_PAM_USERGRP) && + !BER_BVISEMPTY(&ni->ni_pam_group_dn) && + ni->ni_pam_group_ad) { + AttributeAssertion ava = ATTRIBUTEASSERTION_INIT; + SlapReply rs = {REP_RESULT}; + op->o_callback = &cb; + cb.sc_response = pam_compare_cb; + cb.sc_private = NULL; + op->o_tag = LDAP_REQ_COMPARE; + op->o_req_dn = ni->ni_pam_group_dn; + op->o_req_ndn = ni->ni_pam_group_dn; + ava.aa_desc = ni->ni_pam_group_ad; + ava.aa_value = pi.dn; + op->orc_ava = &ava; + rc = op->o_bd->be_compare( op, &rs ); + if ( cb.sc_private == NULL ) { + authzmsg = grpmsg; + rc = NSLCD_PAM_PERM_DENIED; + goto finish; + } + } + + /* We need to check the user's entry for these bits */ + if ((ni->ni_pam_opts & (NI_PAM_USERHOST|NI_PAM_USERSVC)) || + ni->ni_pam_template_ad || + ni->ni_pam_min_uid || ni->ni_pam_max_uid ) { + rc = be_entry_get_rw( op, &pi.dn, NULL, NULL, 0, &e ); + if (rc != LDAP_SUCCESS) { + rc = NSLCD_PAM_USER_UNKNOWN; + goto finish; + } + } + if ((ni->ni_pam_opts & NI_PAM_USERHOST) && nssov_pam_host_ad) { + a = attr_find(e->e_attrs, nssov_pam_host_ad); + if (!a || attr_valfind( a, + SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | + SLAP_MR_VALUE_OF_SYNTAX, + &global_host_bv, NULL, op->o_tmpmemctx )) { + rc = NSLCD_PAM_PERM_DENIED; + authzmsg = hostmsg; + goto finish; + } + } + if ((ni->ni_pam_opts & NI_PAM_USERSVC) && nssov_pam_svc_ad) { + a = attr_find(e->e_attrs, nssov_pam_svc_ad); + if (!a || attr_valfind( a, + SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | + SLAP_MR_VALUE_OF_SYNTAX, + &pi.svc, NULL, op->o_tmpmemctx )) { + rc = NSLCD_PAM_PERM_DENIED; + authzmsg = svcmsg; + goto finish; + } + } + +/* from passwd.c */ +#define UIDN_KEY 2 + + if (ni->ni_pam_min_uid || ni->ni_pam_max_uid) { + int id; + char *tmp; + nssov_mapinfo *mi = &ni->ni_maps[NM_passwd]; + a = attr_find(e->e_attrs, mi->mi_attrs[UIDN_KEY].an_desc); + if (!a) { + rc = NSLCD_PAM_PERM_DENIED; + authzmsg = uidmsg; + goto finish; + } + id = (int)strtol(a->a_vals[0].bv_val,&tmp,0); + if (a->a_vals[0].bv_val[0] == '\0' || *tmp != '\0') { + rc = NSLCD_PAM_PERM_DENIED; + authzmsg = uidmsg; + goto finish; + } + if ((ni->ni_pam_min_uid && id < ni->ni_pam_min_uid) || + (ni->ni_pam_max_uid && id > ni->ni_pam_max_uid)) { + rc = NSLCD_PAM_PERM_DENIED; + authzmsg = uidmsg; + goto finish; + } + } + + if (ni->ni_pam_template_ad) { + a = attr_find(e->e_attrs, ni->ni_pam_template_ad); + if (a) + pi.uid = a->a_vals[0]; + else if (!BER_BVISEMPTY(&ni->ni_pam_template)) + pi.uid = ni->ni_pam_template; + } + rc = NSLCD_PAM_SUCCESS; + +finish: + WRITE_INT32(fp,NSLCD_VERSION); + WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHZ); + WRITE_INT32(fp,NSLCD_RESULT_BEGIN); + WRITE_INT32(fp,rc); + WRITE_BERVAL(fp,&authzmsg); + WRITE_INT32(fp,NSLCD_RESULT_END); + if (e) { + be_entry_release_r(op, e); + } + switch (rc) { + case NSLCD_PAM_SUCCESS: + Debug(LDAP_DEBUG_TRACE,"nssov_pam_authz(): success\n", 0,0,0); + break; + case NSLCD_PAM_PERM_DENIED: + Debug(LDAP_DEBUG_TRACE,"nssov_pam_authz(): %s\n", + authzmsg.bv_val ? authzmsg.bv_val : "NULL",0,0); + break; + default: + Debug(LDAP_DEBUG_TRACE, + "nssov_pam_authz(): permission denied, rc (%d)\n", + rc, 0, 0); + } + return 0; +} + +static int pam_sess(nssov_info *ni,TFILE *fp,Operation *op,int action) +{ + int32_t tmpint32; + char svcc[256]; + char uidc[32]; + char ttyc[32]; + char rhostc[256]; + char ruserc[32]; + char sessionID[64]; + struct paminfo pi; + slap_callback cb = {0}; + SlapReply rs = {REP_RESULT}; + char timebuf[LDAP_LUTIL_GENTIME_BUFSIZE]; + struct berval timestamp, bv[2], *nbv; + time_t stamp; + Modifications mod; + int rc = 0; + + READ_STRING(fp,uidc); + pi.uid.bv_val = uidc; + pi.uid.bv_len = tmpint32; + READ_STRING(fp,svcc); + pi.svc.bv_val = svcc; + pi.svc.bv_len = tmpint32; + READ_STRING(fp,ruserc); + pi.ruser.bv_val = ruserc; + pi.ruser.bv_len = tmpint32; + READ_STRING(fp,rhostc); + pi.rhost.bv_val = rhostc; + pi.rhost.bv_len = tmpint32; + READ_STRING(fp,ttyc); + pi.tty.bv_val = ttyc; + pi.tty.bv_len = tmpint32; + + if (action==NSLCD_ACTION_PAM_SESS_O) { + slap_op_time( &op->o_time, &op->o_tincr ); + timestamp.bv_len = sizeof(timebuf); + timestamp.bv_val = timebuf; + stamp = op->o_time; + slap_timestamp( &stamp, ×tamp ); + } else { + READ_STRING(fp,sessionID); + timestamp.bv_val = sessionID; + timestamp.bv_len = tmpint32; + } + + rc = pam_uid2dn(ni, op, &pi); + if (rc) goto done; + + Debug(LDAP_DEBUG_TRACE,"nssov_pam_sess_%c(%s)\n", + action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c', pi.dn.bv_val,0); + + if (!ni->ni_pam_sessions) { + Debug(LDAP_DEBUG_TRACE,"nssov_pam_sess_%c(): %s\n", + action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c', + "pam session(s) not configured, ignored",0); + rc = -1; + goto done; + } + + { + int i, found=0; + for (i=0; !BER_BVISNULL(&ni->ni_pam_sessions[i]); i++) { + if (ni->ni_pam_sessions[i].bv_len != pi.svc.bv_len) + continue; + if (!strcasecmp(ni->ni_pam_sessions[i].bv_val, pi.svc.bv_val)) { + found = 1; + break; + } + } + if (!found) { + Debug(LDAP_DEBUG_TRACE, + "nssov_pam_sess_%c(): service(%s) not configured, ignored\n", + action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c', + pi.svc.bv_val,0); + rc = -1; + goto done; + } + } + + bv[0].bv_len = timestamp.bv_len + global_host_bv.bv_len + pi.svc.bv_len + + pi.tty.bv_len + pi.ruser.bv_len + pi.rhost.bv_len + STRLENOF(" (@)"); + bv[0].bv_val = op->o_tmpalloc( bv[0].bv_len+1, op->o_tmpmemctx ); + sprintf(bv[0].bv_val, "%s %s %s %s (%s@%s)", + timestamp.bv_val, global_host_bv.bv_val, pi.svc.bv_val, pi.tty.bv_val, + pi.ruser.bv_val, pi.rhost.bv_val); + + Debug(LDAP_DEBUG_TRACE, "nssov_pam_sess_%c(): loginStatus (%s) \n", + action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c', bv[0].bv_val,0); + + mod.sml_numvals = 1; + mod.sml_values = bv; + BER_BVZERO(&bv[1]); + attr_normalize( ad_loginStatus, bv, &nbv, op->o_tmpmemctx ); + mod.sml_nvalues = nbv; + mod.sml_desc = ad_loginStatus; + mod.sml_op = action == NSLCD_ACTION_PAM_SESS_O ? LDAP_MOD_ADD : + LDAP_MOD_DELETE; + mod.sml_flags = SLAP_MOD_INTERNAL; + mod.sml_next = NULL; + + cb.sc_response = slap_null_cb; + op->o_callback = &cb; + op->o_tag = LDAP_REQ_MODIFY; + op->o_dn = op->o_bd->be_rootdn; + op->o_ndn = op->o_bd->be_rootndn; + op->orm_modlist = &mod; + op->orm_no_opattrs = 1; + op->o_req_dn = pi.dn; + op->o_req_ndn = pi.dn; + if (op->o_bd->be_modify( op, &rs ) != LDAP_SUCCESS) { + Debug(LDAP_DEBUG_TRACE, + "nssov_pam_sess_%c(): modify op failed\n", + action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c', + 0,0); + rc = -1; + } + + if ( mod.sml_next ) { + slap_mods_free( mod.sml_next, 1 ); + } + ber_bvarray_free_x( nbv, op->o_tmpmemctx ); + +done:; + + if (rc == 0) { + Debug(LDAP_DEBUG_TRACE, + "nssov_pam_sess_%c(): success\n", + action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c', + 0,0); + } + WRITE_INT32(fp,NSLCD_VERSION); + WRITE_INT32(fp,action); + WRITE_INT32(fp,NSLCD_RESULT_BEGIN); + if (action==NSLCD_ACTION_PAM_SESS_O) + WRITE_STRING(fp,timestamp.bv_val); + WRITE_INT32(fp,NSLCD_RESULT_END); + return 0; +} + +int pam_sess_o(nssov_info *ni,TFILE *fp,Operation *op) +{ + return pam_sess(ni,fp,op,NSLCD_ACTION_PAM_SESS_O); +} + +int pam_sess_c(nssov_info *ni,TFILE *fp,Operation *op) +{ + return pam_sess(ni,fp,op,NSLCD_ACTION_PAM_SESS_C); +} + +int pam_pwmod(nssov_info *ni,TFILE *fp,Operation *op,uid_t calleruid) +{ + struct berval npw; + int32_t tmpint32; + char uidc[32]; + char svcc[256]; + char ruserc[32]; + char rhostc[256]; + char ttyc[256]; + int asroot; + char opwc[256]; + char npwc[256]; + struct paminfo pi; + int rc; + + READ_STRING(fp,uidc); + pi.uid.bv_val = uidc; + pi.uid.bv_len = tmpint32; + READ_STRING(fp,svcc); + pi.svc.bv_val = svcc; + pi.svc.bv_len = tmpint32; + READ_STRING(fp,ruserc); + pi.ruser.bv_val = svcc; + pi.ruser.bv_len = tmpint32; + READ_STRING(fp,rhostc); + pi.rhost.bv_val = svcc; + pi.rhost.bv_len = tmpint32; + READ_STRING(fp,ttyc); + pi.tty.bv_val = svcc; + pi.tty.bv_len = tmpint32; + READ_INT32(fp, asroot); + READ_STRING(fp,opwc); + pi.pwd.bv_val = opwc; + pi.pwd.bv_len = tmpint32; + READ_STRING(fp,npwc); + npw.bv_val = npwc; + npw.bv_len = tmpint32; + + rc = pam_uid2dn(ni, op, &pi); + if (rc) goto done; + + Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(%s), %s %s\n", + pi.dn.bv_val ? pi.dn.bv_val : "NULL", + pi.uid.bv_val ? pi.uid.bv_val : "NULL", + asroot ? "as root" : "as user"); + + BER_BVZERO(&pi.msg); + pi.ispwdmgr = 0; + + /* nssov_pam prohibits password mod */ + if (!BER_BVISEMPTY(&ni->ni_pam_password_prohibit_message)) { + Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(): %s (%s)\n", + "password_prohibit_message", + ni->ni_pam_password_prohibit_message.bv_val,0); + ber_str2bv(ni->ni_pam_password_prohibit_message.bv_val, 0, 0, &pi.msg); + rc = NSLCD_PAM_PERM_DENIED; + goto done; + } + + if (asroot) { + if (BER_BVISEMPTY(&ni->ni_pam_pwdmgr_dn)) { + Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(), %s\n", + "pwdmgr not configured", 0, 0); + ber_str2bv("pwdmgr not configured", 0, 0, &pi.msg); + rc = NSLCD_PAM_PERM_DENIED; + goto done; + } + if (calleruid != 0) { + Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(): %s\n", + "caller is not root", 0, 0); + ber_str2bv("only root may do that", 0, 0, &pi.msg); + rc = NSLCD_PAM_PERM_DENIED; + goto done; + } + /* root user requesting pwmod */ + pi.ispwdmgr = 1; + } + + if (!pi.ispwdmgr && BER_BVISEMPTY(&pi.pwd)) { + Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(), %s\n", + "not pwdmgr and old pwd empty", 0, 0); + ber_str2bv("must provide old password", 0, 0, &pi.msg); + rc = NSLCD_PAM_PERM_DENIED; + goto done; + } + + BerElementBuffer berbuf; + BerElement *ber = (BerElement *)&berbuf; + struct berval bv; + SlapReply rs = {REP_RESULT}; + slap_callback cb = {0}; + + ber_init_w_nullc(ber, LBER_USE_DER); + ber_printf(ber, "{"); + if (!BER_BVISEMPTY(&pi.dn)) + ber_printf(ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_ID, + &pi.dn); + /* supply old pwd whenever it's given */ + if (!BER_BVISEMPTY(&pi.pwd)) + ber_printf(ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_OLD, + &pi.pwd); + if (!BER_BVISEMPTY(&npw)) + ber_printf(ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, + &npw); + ber_printf(ber, "N}"); + ber_flatten2(ber, &bv, 0); + op->o_tag = LDAP_REQ_EXTENDED; + op->ore_reqoid = slap_EXOP_MODIFY_PASSWD; + op->ore_reqdata = &bv; + + if (pi.ispwdmgr) { + /* root user changing end-user passwords */ + op->o_dn = ni->ni_pam_pwdmgr_dn; + op->o_ndn = ni->ni_pam_pwdmgr_dn; + } else { + /* end-user self-pwd-mod */ + op->o_dn = pi.dn; + op->o_ndn = pi.dn; + } + op->o_callback = &cb; + op->o_conn->c_authz_backend = op->o_bd; + cb.sc_response = slap_null_cb; + op->o_bd = frontendDB; + rc = op->o_bd->be_extended(op, &rs); + if (rs.sr_text) + ber_str2bv(rs.sr_text, 0, 0, &pi.msg); + if (rc == LDAP_SUCCESS) + rc = NSLCD_PAM_SUCCESS; + else + rc = NSLCD_PAM_PERM_DENIED; + +done:; + Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(), rc (%d)\n", rc, 0, 0); + WRITE_INT32(fp,NSLCD_VERSION); + WRITE_INT32(fp,NSLCD_ACTION_PAM_PWMOD); + WRITE_INT32(fp,NSLCD_RESULT_BEGIN); + WRITE_INT32(fp,rc); + WRITE_BERVAL(fp,&pi.msg); + return 0; +} + +int nssov_pam_init() +{ + int code = 0; + const char *text; + if (!ad_loginStatus) + code = slap_str2ad("loginStatus", &ad_loginStatus, &text); + + return code; +} diff --git a/contrib/slapd-modules/nssov/passwd.c b/contrib/slapd-modules/nssov/passwd.c new file mode 100644 index 0000000..6e141ca --- /dev/null +++ b/contrib/slapd-modules/nssov/passwd.c @@ -0,0 +1,435 @@ +/* passwd.c - password lookup routines */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2008-2021 The OpenLDAP Foundation. + * Portions Copyright 2008 by Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This code references portions of the nss-ldapd package + * written by Arthur de Jong. The nss-ldapd code was forked + * from the nss-ldap library written by Luke Howard. + */ + +#include "nssov.h" + +/* ( nisSchema.2.0 NAME 'posixAccount' SUP top AUXILIARY + * DESC 'Abstraction of an account with POSIX attributes' + * MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory ) + * MAY ( userPassword $ loginShell $ gecos $ description ) ) + */ + +/* the basic search filter for searches */ +static struct berval passwd_filter = BER_BVC("(objectClass=posixAccount)"); + +/* the attributes used in searches */ +static struct berval passwd_keys[] = { + BER_BVC("uid"), + BER_BVC("userPassword"), + BER_BVC("uidNumber"), + BER_BVC("gidNumber"), + BER_BVC("gecos"), + BER_BVC("cn"), + BER_BVC("homeDirectory"), + BER_BVC("loginShell"), + BER_BVC("objectClass"), + BER_BVNULL +}; + +#define UID_KEY 0 +#define PWD_KEY 1 +#define UIDN_KEY 2 +#define GIDN_KEY 3 +#define GEC_KEY 4 +#define CN_KEY 5 +#define DIR_KEY 6 +#define SHL_KEY 7 + +/* default values for attributes */ +static struct berval default_passwd_userPassword = BER_BVC("*"); /* unmatchable */ +static struct berval default_passwd_homeDirectory = BER_BVC(""); +static struct berval default_passwd_loginShell = BER_BVC(""); + +static struct berval shadow_passwd = BER_BVC("x"); + +NSSOV_INIT(passwd) + +/* + Checks to see if the specified name is a valid user name. + + This test is based on the definition from POSIX (IEEE Std 1003.1, 2004, 3.426 User Name + and 3.276 Portable Filename Character Set): + http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_426 + http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_276 + + The standard defines user names valid if they contain characters from + the set [A-Za-z0-9._-] where the hyphen should not be used as first + character. As an extension this test allows the dolar '$' sign as the last + character to support Samba special accounts. +*/ +int isvalidusername(struct berval *bv) +{ + int i; + char *name = bv->bv_val; + if ((name==NULL)||(name[0]=='\0')) + return 0; + /* check first character */ + if ( ! ( (name[0]>='A' && name[0] <= 'Z') || + (name[0]>='a' && name[0] <= 'z') || + (name[0]>='0' && name[0] <= '9') || + name[0]=='.' || name[0]=='_' ) ) + return 0; + /* check other characters */ + for (i=1;i<bv->bv_len;i++) + { + if ( name[i]=='$' ) + { + /* if the char is $ we require it to be the last char */ + if (name[i+1]!='\0') + return 0; + } + else if ( ! ( (name[i]>='A' && name[i] <= 'Z') || + (name[i]>='a' && name[i] <= 'z') || + (name[i]>='0' && name[i] <= '9') || + name[i]=='.' || name[i]=='_' || name[i]=='-') ) + return 0; + } + /* no test failed so it must be good */ + return -1; +} + +/* return 1 on success */ +int nssov_dn2uid(Operation *op,nssov_info *ni,struct berval *dn,struct berval *uid) +{ + nssov_mapinfo *mi = &ni->ni_maps[NM_passwd]; + AttributeDescription *ad = mi->mi_attrs[UID_KEY].an_desc; + Entry *e; + + /* check for empty string */ + if (!dn->bv_len) + return 0; + /* try to look up uid within DN string */ + if (!strncmp(dn->bv_val,ad->ad_cname.bv_val,ad->ad_cname.bv_len) && + dn->bv_val[ad->ad_cname.bv_len] == '=') + { + struct berval bv, rdn; + dnRdn(dn, &rdn); + /* check if it is valid */ + bv.bv_val = dn->bv_val + ad->ad_cname.bv_len + 1; + bv.bv_len = rdn.bv_len - ad->ad_cname.bv_len - 1; + if (!isvalidusername(&bv)) + return 0; + ber_dupbv_x( uid, &bv, op->o_tmpmemctx ); + return 1; + } + /* look up the uid from the entry itself */ + if (be_entry_get_rw( op, dn, NULL, ad, 0, &e) == LDAP_SUCCESS) + { + Attribute *a = attr_find(e->e_attrs, ad); + if (a) { + ber_dupbv_x(uid, &a->a_vals[0], op->o_tmpmemctx); + } + be_entry_release_r(op, e); + if (a) + return 1; + } + return 0; +} + +int nssov_name2dn_cb(Operation *op,SlapReply *rs) +{ + if ( rs->sr_type == REP_SEARCH ) + { + struct berval *bv = op->o_callback->sc_private; + if ( !BER_BVISNULL(bv)) { + op->o_tmpfree( bv->bv_val, op->o_tmpmemctx ); + BER_BVZERO(bv); + return LDAP_ALREADY_EXISTS; + } + ber_dupbv_x(bv, &rs->sr_entry->e_name, op->o_tmpmemctx); + } + return LDAP_SUCCESS; +} + +int nssov_uid2dn(Operation *op,nssov_info *ni,struct berval *uid,struct berval *dn) +{ + nssov_mapinfo *mi = &ni->ni_maps[NM_passwd]; + char fbuf[1024]; + struct berval filter = {sizeof(fbuf),fbuf}; + slap_callback cb = {0}; + SlapReply rs = {REP_RESULT}; + Operation op2; + int rc; + + /* if it isn't a valid username, just bail out now */ + if (!isvalidusername(uid)) + return 0; + /* we have to look up the entry */ + nssov_filter_byid(mi,UID_KEY,uid,&filter); + BER_BVZERO(dn); + cb.sc_private = dn; + cb.sc_response = nssov_name2dn_cb; + op2 = *op; + op2.o_callback = &cb; + op2.o_req_dn = mi->mi_base; + op2.o_req_ndn = mi->mi_base; + op2.ors_scope = mi->mi_scope; + op2.ors_filterstr = filter; + op2.ors_filter = str2filter_x( op, filter.bv_val ); + op2.ors_attrs = slap_anlist_no_attrs; + op2.ors_tlimit = SLAP_NO_LIMIT; + op2.ors_slimit = SLAP_NO_LIMIT; + rc = op2.o_bd->be_search( &op2, &rs ); + filter_free_x( op, op2.ors_filter, 1 ); + return rc == LDAP_SUCCESS && !BER_BVISNULL(dn); +} + +/* the maximum number of uidNumber attributes per entry */ +#define MAXUIDS_PER_ENTRY 5 + +NSSOV_CBPRIV(passwd, + char buf[256]; + struct berval name; + struct berval id;); + +static struct berval shadowclass = BER_BVC("shadowAccount"); + +static int write_passwd(nssov_passwd_cbp *cbp,Entry *entry) +{ + int32_t tmpint32; + struct berval tmparr[2], tmpuid[2]; + char *tmp; + struct berval *names; + struct berval *uids; + struct berval passwd = {0}; + gid_t gid; + struct berval gecos; + struct berval homedir; + struct berval shell; + Attribute *a; + int i,j; + int use_shadow = 0; + /* get the usernames for this entry */ + if (BER_BVISNULL(&cbp->name)) + { + a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[UID_KEY].an_desc); + if (!a) + { + Debug(LDAP_DEBUG_ANY,"passwd entry %s does not contain %s value\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[UID_KEY].an_desc->ad_cname.bv_val,0); + return 0; + } + names = a->a_vals; + } + else + { + names=tmparr; + names[0]=cbp->name; + BER_BVZERO(&names[1]); + } + /* get the password for this entry */ + a = attr_find(entry->e_attrs, slap_schema.si_ad_objectClass); + if ( a ) { + for ( i=0; i<a->a_numvals; i++) { + if ( bvmatch( &shadowclass, &a->a_nvals[i] )) { + use_shadow = 1; + break; + } + } + } + if ( use_shadow ) + { + /* if the entry has a shadowAccount entry, point to that instead */ + passwd = shadow_passwd; + } + else + { + a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[PWD_KEY].an_desc); + if (a) + get_userpassword(&a->a_vals[0], &passwd); + if (BER_BVISNULL(&passwd)) + passwd=default_passwd_userPassword; + } + /* get the uids for this entry */ + if (BER_BVISNULL(&cbp->id)) + { + a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[UIDN_KEY].an_desc); + if ( !a ) + { + Debug(LDAP_DEBUG_ANY,"passwd entry %s does not contain %s value\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[UIDN_KEY].an_desc->ad_cname.bv_val,0); + return 0; + } + uids = a->a_vals; + } + else + { + uids = tmpuid; + uids[0] = cbp->id; + BER_BVZERO(&uids[1]); + } + /* get the gid for this entry */ + a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[GIDN_KEY].an_desc); + if (!a) + { + Debug(LDAP_DEBUG_ANY,"passwd entry %s does not contain %s value\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[GIDN_KEY].an_desc->ad_cname.bv_val,0); + return 0; + } + else if (a->a_numvals != 1) + { + Debug(LDAP_DEBUG_ANY,"passwd entry %s contains multiple %s values\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[GIDN_KEY].an_desc->ad_cname.bv_val,0); + } + gid=(gid_t)strtol(a->a_vals[0].bv_val,&tmp,0); + if ((a->a_vals[0].bv_val[0]=='\0')||(*tmp!='\0')) + { + Debug(LDAP_DEBUG_ANY,"passwd entry %s contains non-numeric %s value\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[GIDN_KEY].an_desc->ad_cname.bv_val,0); + return 0; + } + /* get the gecos for this entry (fall back to cn) */ + a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[GEC_KEY].an_desc); + if (!a) + a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[CN_KEY].an_desc); + if (!a || !a->a_numvals) + { + Debug(LDAP_DEBUG_ANY,"passwd entry %s does not contain %s or %s value\n", + entry->e_name.bv_val, + cbp->mi->mi_attrs[GEC_KEY].an_desc->ad_cname.bv_val, + cbp->mi->mi_attrs[CN_KEY].an_desc->ad_cname.bv_val); + return 0; + } + else if (a->a_numvals > 1) + { + Debug(LDAP_DEBUG_ANY,"passwd entry %s contains multiple %s or %s values\n", + entry->e_name.bv_val, + cbp->mi->mi_attrs[GEC_KEY].an_desc->ad_cname.bv_val, + cbp->mi->mi_attrs[CN_KEY].an_desc->ad_cname.bv_val); + } + gecos=a->a_vals[0]; + /* get the home directory for this entry */ + a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[DIR_KEY].an_desc); + if (!a) + { + Debug(LDAP_DEBUG_ANY,"passwd entry %s does not contain %s value\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[DIR_KEY].an_desc->ad_cname.bv_val,0); + homedir=default_passwd_homeDirectory; + } + else + { + if (a->a_numvals > 1) + { + Debug(LDAP_DEBUG_ANY,"passwd entry %s contains multiple %s values\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[DIR_KEY].an_desc->ad_cname.bv_val,0); + } + homedir=a->a_vals[0]; + if (homedir.bv_val[0]=='\0') + homedir=default_passwd_homeDirectory; + } + /* get the shell for this entry */ + a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[SHL_KEY].an_desc); + if (!a) + { + shell=default_passwd_loginShell; + } + else + { + if (a->a_numvals > 1) + { + Debug(LDAP_DEBUG_ANY,"passwd entry %s contains multiple %s values\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[SHL_KEY].an_desc->ad_cname.bv_val,0); + } + shell=a->a_vals[0]; + if (shell.bv_val[0]=='\0') + shell=default_passwd_loginShell; + } + /* write the entries */ + for (i=0;!BER_BVISNULL(&names[i]);i++) + { + if (!isvalidusername(&names[i])) + { + Debug(LDAP_DEBUG_ANY,"nssov: passwd entry %s contains invalid user name: \"%s\"\n", + entry->e_name.bv_val,names[i].bv_val,0); + } + else + { + for (j=0;!BER_BVISNULL(&uids[j]);j++) + { + char *tmp; + uid_t uid; + uid = strtol(uids[j].bv_val, &tmp, 0); + if ( *tmp ) { + Debug(LDAP_DEBUG_ANY,"nssov: passwd entry %s contains non-numeric %s value: \"%s\"\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[UIDN_KEY].an_desc->ad_cname.bv_val, + names[i].bv_val); + continue; + } + WRITE_INT32(cbp->fp,NSLCD_RESULT_BEGIN); + WRITE_BERVAL(cbp->fp,&names[i]); + WRITE_BERVAL(cbp->fp,&passwd); + WRITE_INT32(cbp->fp,uid); + WRITE_INT32(cbp->fp,gid); + WRITE_BERVAL(cbp->fp,&gecos); + WRITE_BERVAL(cbp->fp,&homedir); + WRITE_BERVAL(cbp->fp,&shell); + } + } + } + return 0; +} + +NSSOV_CB(passwd) + +NSSOV_HANDLE( + passwd,byname, + char fbuf[1024]; + struct berval filter = {sizeof(fbuf)}; + filter.bv_val = fbuf; + READ_STRING(fp,cbp.buf); + cbp.name.bv_len = tmpint32; + cbp.name.bv_val = cbp.buf; + if (!isvalidusername(&cbp.name)) { + Debug(LDAP_DEBUG_ANY,"nssov_passwd_byname(%s): invalid user name\n",cbp.name.bv_val,0,0); + return -1; + } + BER_BVZERO(&cbp.id); , + Debug(LDAP_DEBUG_TRACE,"nssov_passwd_byname(%s)\n",cbp.name.bv_val,0,0);, + NSLCD_ACTION_PASSWD_BYNAME, + nssov_filter_byname(cbp.mi,UID_KEY,&cbp.name,&filter) +) + +NSSOV_HANDLE( + passwd,byuid, + uid_t uid; + char fbuf[1024]; + struct berval filter = {sizeof(fbuf)}; + filter.bv_val = fbuf; + READ_INT32(fp,uid); + cbp.id.bv_val = cbp.buf; + cbp.id.bv_len = snprintf(cbp.buf,sizeof(cbp.buf),"%d",uid); + BER_BVZERO(&cbp.name);, + Debug(LDAP_DEBUG_TRACE,"nssov_passwd_byuid(%s)\n",cbp.id.bv_val,0,0);, + NSLCD_ACTION_PASSWD_BYUID, + nssov_filter_byid(cbp.mi,UIDN_KEY,&cbp.id,&filter) +) + +NSSOV_HANDLE( + passwd,all, + struct berval filter; + /* no parameters to read */ + BER_BVZERO(&cbp.name); + BER_BVZERO(&cbp.id);, + Debug(LDAP_DEBUG_TRACE,"nssov_passwd_all()\n",0,0,0);, + NSLCD_ACTION_PASSWD_ALL, + (filter=cbp.mi->mi_filter,0) +) diff --git a/contrib/slapd-modules/nssov/protocol.c b/contrib/slapd-modules/nssov/protocol.c new file mode 100644 index 0000000..a248451 --- /dev/null +++ b/contrib/slapd-modules/nssov/protocol.c @@ -0,0 +1,156 @@ +/* protocol.c - network protocol lookup routines */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2008-2021 The OpenLDAP Foundation. + * Portions Copyright 2008 by Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* + * ACKNOWLEDGEMENTS: + * This code references portions of the nss-ldapd package + * written by Arthur de Jong. The nss-ldapd code was forked + * from the nss-ldap library written by Luke Howard. + */ + +#include "nssov.h" + +/* ( nisSchema.2.4 NAME 'ipProtocol' SUP top STRUCTURAL + * DESC 'Abstraction of an IP protocol. Maps a protocol number + * to one or more names. The distinguished value of the cn + * attribute denotes the protocol's canonical name' + * MUST ( cn $ ipProtocolNumber ) + * MAY description ) + */ + +/* the basic search filter for searches */ +static struct berval protocol_filter = BER_BVC("(objectClass=ipProtocol)"); + +/* the attributes used in searches */ +static struct berval protocol_keys[] = { + BER_BVC("cn"), + BER_BVC("ipProtocolNumber"), + BER_BVNULL +}; + +NSSOV_INIT(protocol) + +NSSOV_CBPRIV(protocol, + char buf[256]; + struct berval name; + struct berval numb;); + +static int write_protocol(nssov_protocol_cbp *cbp,Entry *entry) +{ + int32_t tmpint32; + int i,numname,dupname,proto; + struct berval name,*names; + Attribute *a; + char *tmp; + + /* get the most canonical name */ + nssov_find_rdnval( &entry->e_nname, cbp->mi->mi_attrs[0].an_desc, &name ); + /* get the other names for the protocol */ + a = attr_find( entry->e_attrs, cbp->mi->mi_attrs[0].an_desc ); + if ( !a || !a->a_vals ) + { + Debug(LDAP_DEBUG_ANY,"protocol entry %s does not contain %s value\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[0].an_desc->ad_cname.bv_val, 0 ); + return 0; + } + names = a->a_vals; + numname = a->a_numvals; + /* if the name is not yet found, get the first entry from names */ + if (BER_BVISNULL(&name)) { + name=names[0]; + dupname = 0; + } else { + dupname = -1; + for (i=0; i<numname; i++) { + if ( bvmatch(&name, &a->a_nvals[i])) { + dupname = i; + break; + } + } + } + /* get the protocol number */ + a = attr_find( entry->e_attrs, cbp->mi->mi_attrs[1].an_desc ); + if ( !a || !a->a_vals ) + { + Debug(LDAP_DEBUG_ANY,"protocol entry %s does not contain %s value\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[1].an_desc->ad_cname.bv_val, 0 ); + return 0; + } else if ( a->a_numvals > 1 ) { + Debug(LDAP_DEBUG_ANY,"protocol entry %s contains multiple %s values\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[1].an_desc->ad_cname.bv_val, 0 ); + } + proto=(int)strtol(a->a_vals[0].bv_val,&tmp,0); + if (*tmp) + { + Debug(LDAP_DEBUG_ANY,"protocol entry %s contains non-numeric %s value\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[1].an_desc->ad_cname.bv_val, 0 ); + return 0; + } + /* write the entry */ + WRITE_INT32(cbp->fp,NSLCD_RESULT_BEGIN); + WRITE_BERVAL(cbp->fp,&name); + if ( dupname >= 0 ) { + WRITE_INT32(cbp->fp,numname-1); + } else { + WRITE_INT32(cbp->fp,numname); + } + for (i=0;i<numname;i++) { + if (i == dupname) continue; + WRITE_BERVAL(cbp->fp,&names[i]); + } + WRITE_INT32(cbp->fp,proto); + return 0; +} + +NSSOV_CB(protocol) + +NSSOV_HANDLE( + protocol,byname, + char fbuf[1024]; + struct berval filter = {sizeof(fbuf)}; + filter.bv_val = fbuf; + BER_BVZERO(&cbp.numb); + READ_STRING(fp,cbp.buf); + cbp.name.bv_len = tmpint32; + cbp.name.bv_val = cbp.buf;, + Debug(LDAP_DEBUG_TRACE,"nssov_protocol_byname(%s)\n",cbp.name.bv_val,0,0);, + NSLCD_ACTION_PROTOCOL_BYNAME, + nssov_filter_byname(cbp.mi,0,&cbp.name,&filter) +) + +NSSOV_HANDLE( + protocol,bynumber, + int protocol; + char fbuf[1024]; + struct berval filter = {sizeof(fbuf)}; + filter.bv_val = fbuf; + READ_INT32(fp,protocol); + cbp.numb.bv_val = cbp.buf; + cbp.numb.bv_len = snprintf(cbp.buf,sizeof(cbp.buf),"%d",protocol); + BER_BVZERO(&cbp.name);, + Debug(LDAP_DEBUG_TRACE,"nssov_protocol_bynumber(%s)\n",cbp.numb.bv_val,0,0);, + NSLCD_ACTION_PROTOCOL_BYNUMBER, + nssov_filter_byid(cbp.mi,1,&cbp.numb,&filter) +) + +NSSOV_HANDLE( + protocol,all, + struct berval filter; + /* no parameters to read */, + Debug(LDAP_DEBUG_TRACE,"nssov_protocol_all()\n",0,0,0);, + NSLCD_ACTION_PROTOCOL_ALL, + (filter=cbp.mi->mi_filter,0) +) diff --git a/contrib/slapd-modules/nssov/rpc.c b/contrib/slapd-modules/nssov/rpc.c new file mode 100644 index 0000000..a157871 --- /dev/null +++ b/contrib/slapd-modules/nssov/rpc.c @@ -0,0 +1,158 @@ +/* rpc.c - rpc lookup routines */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2008-2021 The OpenLDAP Foundation. + * Portions Copyright 2008 by Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This code references portions of the nss-ldapd package + * written by Arthur de Jong. The nss-ldapd code was forked + * from the nss-ldap library written by Luke Howard. + */ + +#include "nssov.h" + +/* ( nisSchema.2.5 NAME 'oncRpc' SUP top STRUCTURAL + * DESC 'Abstraction of an Open Network Computing (ONC) + * [RFC1057] Remote Procedure Call (RPC) binding. + * This class maps an ONC RPC number to a name. + * The distinguished value of the cn attribute denotes + * the RPC service's canonical name' + * MUST ( cn $ oncRpcNumber ) + * MAY description ) + */ + +/* the basic search filter for searches */ +static struct berval rpc_filter = BER_BVC("(objectClass=oncRpc)"); + +/* the attributes to request with searches */ +static struct berval rpc_keys[] = { + BER_BVC("cn"), + BER_BVC("oncRpcNumber"), + BER_BVNULL +}; + +NSSOV_INIT(rpc) + +NSSOV_CBPRIV(rpc, + char buf[256]; + struct berval name; + struct berval numb;); + +/* write a single rpc entry to the stream */ +static int write_rpc(nssov_rpc_cbp *cbp,Entry *entry) +{ + int32_t tmpint32; + int i,numname,dupname,number; + struct berval name,*names; + Attribute *a; + char *tmp; + + /* get the most canonical name */ + nssov_find_rdnval( &entry->e_nname, cbp->mi->mi_attrs[0].an_desc, &name ); + /* get the other names for the rpc */ + a = attr_find( entry->e_attrs, cbp->mi->mi_attrs[0].an_desc ); + if ( !a || !a->a_vals ) + { + Debug(LDAP_DEBUG_ANY,"rpc entry %s does not contain %s value\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[0].an_desc->ad_cname.bv_val, 0 ); + return 0; + } + names = a->a_vals; + numname = a->a_numvals; + /* if the name is not yet found, get the first entry from names */ + if (BER_BVISNULL(&name)) { + name=names[0]; + dupname = 0; + } else { + dupname = -1; + for (i=0; i<numname; i++) { + if ( bvmatch(&name, &a->a_nvals[i])) { + dupname = i; + break; + } + } + } + /* get the rpc number */ + a = attr_find( entry->e_attrs, cbp->mi->mi_attrs[1].an_desc ); + if ( !a || !a->a_vals ) + { + Debug(LDAP_DEBUG_ANY,"rpc entry %s does not contain %s value\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[1].an_desc->ad_cname.bv_val, 0 ); + return 0; + } else if ( a->a_numvals > 1 ) { + Debug(LDAP_DEBUG_ANY,"rpc entry %s contains multiple %s values\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[1].an_desc->ad_cname.bv_val, 0 ); + } + number=(int)strtol(a->a_vals[0].bv_val,&tmp,0); + if (*tmp) + { + Debug(LDAP_DEBUG_ANY,"rpc entry %s contains non-numeric %s value\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[1].an_desc->ad_cname.bv_val, 0 ); + return 0; + } + /* write the entry */ + WRITE_INT32(cbp->fp,NSLCD_RESULT_BEGIN); + WRITE_BERVAL(cbp->fp,&name); + if ( dupname >= 0 ) { + WRITE_INT32(cbp->fp,numname-1); + } else { + WRITE_INT32(cbp->fp,numname); + } + for (i=0;i<numname;i++) { + if (i == dupname) continue; + WRITE_BERVAL(cbp->fp,&names[i]); + } + WRITE_INT32(cbp->fp,number); + return 0; +} + +NSSOV_CB(rpc) + +NSSOV_HANDLE( + rpc,byname, + char fbuf[1024]; + struct berval filter = {sizeof(fbuf)}; + filter.bv_val = fbuf; + BER_BVZERO(&cbp.numb); + READ_STRING(fp,cbp.buf); + cbp.name.bv_len = tmpint32; + cbp.name.bv_val = cbp.buf;, + Debug(LDAP_DEBUG_TRACE,"nssov_rpc_byname(%s)\n",cbp.name.bv_val,0,0);, + NSLCD_ACTION_RPC_BYNAME, + nssov_filter_byname(cbp.mi,0,&cbp.name,&filter) +) + +NSSOV_HANDLE( + rpc,bynumber, + int number; + char fbuf[1024]; + struct berval filter = {sizeof(fbuf)}; + filter.bv_val = fbuf; + READ_INT32(fp,number); + cbp.numb.bv_val = cbp.buf; + cbp.numb.bv_len = snprintf(cbp.buf,sizeof(cbp.buf),"%d",number); + BER_BVZERO(&cbp.name);, + Debug(LDAP_DEBUG_TRACE,"nssov_rpc_bynumber(%s)\n",cbp.numb.bv_val,0,0);, + NSLCD_ACTION_RPC_BYNUMBER, + nssov_filter_byid(cbp.mi,1,&cbp.numb,&filter) +) + +NSSOV_HANDLE( + rpc,all, + struct berval filter; + /* no parameters to read */, + Debug(LDAP_DEBUG_TRACE,"nssov_rpc_all()\n",0,0,0);, + NSLCD_ACTION_RPC_ALL, + (filter=cbp.mi->mi_filter,0) +) diff --git a/contrib/slapd-modules/nssov/service.c b/contrib/slapd-modules/nssov/service.c new file mode 100644 index 0000000..df87c86 --- /dev/null +++ b/contrib/slapd-modules/nssov/service.c @@ -0,0 +1,250 @@ +/* service.c - service lookup routines */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2008-2021 The OpenLDAP Foundation. + * Portions Copyright 2008 by Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This code references portions of the nss-ldapd package + * written by Arthur de Jong. The nss-ldapd code was forked + * from the nss-ldap library written by Luke Howard. + */ + +#include "nssov.h" + +/* ( nisSchema.2.3 NAME 'ipService' SUP top STRUCTURAL + * DESC 'Abstraction an Internet Protocol service. + * Maps an IP port and protocol (such as tcp or udp) + * to one or more names; the distinguished value of + * the cn attribute denotes the service's canonical + * name' + * MUST ( cn $ ipServicePort $ ipServiceProtocol ) + * MAY ( description ) ) + */ + +/* the basic search filter for searches */ +static struct berval service_filter = BER_BVC("(objectClass=ipService)"); + +/* the attributes to request with searches */ +static struct berval service_keys[] = { + BER_BVC("cn"), + BER_BVC("ipServicePort"), + BER_BVC("ipServiceProtocol"), + BER_BVNULL +}; + +static int mkfilter_service_byname(nssov_mapinfo *mi,struct berval *name, + struct berval *protocol,struct berval *buf) +{ + char buf2[1024],buf3[1024]; + struct berval bv2 = {sizeof(buf2),buf2}; + struct berval bv3 = {sizeof(buf3),buf3}; + + /* escape attributes */ + if (nssov_escape(name,&bv2)) + return -1; + if (!BER_BVISNULL(protocol)) { + if (nssov_escape(protocol,&bv3)) + return -1; + if (bv2.bv_len + mi->mi_filter.bv_len + mi->mi_attrs[0].an_desc->ad_cname.bv_len + + bv3.bv_len + mi->mi_attrs[2].an_desc->ad_cname.bv_len + 9 > buf->bv_len ) + return -1; + buf->bv_len = snprintf(buf->bv_val, buf->bv_len, "(&%s(%s=%s)(%s=%s))", + mi->mi_filter.bv_val, + mi->mi_attrs[0].an_desc->ad_cname.bv_val, bv2.bv_val, + mi->mi_attrs[2].an_desc->ad_cname.bv_val, bv3.bv_val ); + } else { + if (bv2.bv_len + mi->mi_filter.bv_len + mi->mi_attrs[0].an_desc->ad_cname.bv_len + 6 > + buf->bv_len ) + return -1; + buf->bv_len = snprintf(buf->bv_val, buf->bv_len, "(&%s(%s=%s))", + mi->mi_filter.bv_val, mi->mi_attrs[0].an_desc->ad_cname.bv_val, + bv2.bv_val ); + } + return 0; +} + +static int mkfilter_service_bynumber(nssov_mapinfo *mi,struct berval *numb, + struct berval *protocol,struct berval *buf) +{ + char buf2[1024]; + struct berval bv2 = {sizeof(buf2),buf2}; + + /* escape attribute */ + if (!BER_BVISNULL(protocol)) { + if (nssov_escape(protocol,&bv2)) + return -1; + if (numb->bv_len + mi->mi_filter.bv_len + mi->mi_attrs[1].an_desc->ad_cname.bv_len + + bv2.bv_len + mi->mi_attrs[2].an_desc->ad_cname.bv_len + 9 > buf->bv_len ) + return -1; + buf->bv_len = snprintf(buf->bv_val, buf->bv_len, "(&%s(%s=%s)(%s=%s))", + mi->mi_filter.bv_val, + mi->mi_attrs[1].an_desc->ad_cname.bv_val, numb->bv_val, + mi->mi_attrs[2].an_desc->ad_cname.bv_val, bv2.bv_val ); + } else { + if (numb->bv_len + mi->mi_filter.bv_len + mi->mi_attrs[1].an_desc->ad_cname.bv_len + 6 > + buf->bv_len ) + return -1; + buf->bv_len = snprintf(buf->bv_val, buf->bv_len, "(&%s(%s=%s))", + mi->mi_filter.bv_val, mi->mi_attrs[1].an_desc->ad_cname.bv_val, + numb->bv_val ); + } + return 0; +} + +NSSOV_INIT(service) + +NSSOV_CBPRIV(service, + char nbuf[256]; + char pbuf[256]; + struct berval name; + struct berval prot;); + +static int write_service(nssov_service_cbp *cbp,Entry *entry) +{ + int32_t tmpint32; + struct berval name,*names,*protos; + struct berval tmparr[2]; + Attribute *a; + char *tmp; + int port; + int i,numname,dupname,numprot; + + /* get the most canonical name */ + nssov_find_rdnval( &entry->e_nname, cbp->mi->mi_attrs[0].an_desc, &name ); + /* get the other names for the rpc */ + a = attr_find( entry->e_attrs, cbp->mi->mi_attrs[0].an_desc ); + if ( !a || !a->a_vals ) + { + Debug(LDAP_DEBUG_ANY,"service entry %s does not contain %s value\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[0].an_desc->ad_cname.bv_val, 0 ); + return 0; + } + names = a->a_vals; + numname = a->a_numvals; + /* if the name is not yet found, get the first entry from names */ + if (BER_BVISNULL(&name)) { + name=names[0]; + dupname = 0; + } else { + dupname = -1; + for (i=0; i<numname; i++) { + if ( bvmatch(&name, &a->a_nvals[i])) { + dupname = i; + break; + } + } + } + /* get the service number */ + a = attr_find( entry->e_attrs, cbp->mi->mi_attrs[1].an_desc ); + if ( !a || !a->a_vals ) + { + Debug(LDAP_DEBUG_ANY,"service entry %s does not contain %s value\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[1].an_desc->ad_cname.bv_val, 0 ); + return 0; + } else if ( a->a_numvals > 1 ) { + Debug(LDAP_DEBUG_ANY,"service entry %s contains multiple %s values\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[1].an_desc->ad_cname.bv_val, 0 ); + } + port=(int)strtol(a->a_vals[0].bv_val,&tmp,0); + if (*tmp) + { + Debug(LDAP_DEBUG_ANY,"service entry %s contains non-numeric %s value\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[1].an_desc->ad_cname.bv_val, 0 ); + return 0; + } + /* get protocols */ + if (BER_BVISNULL(&cbp->prot)) + { + a = attr_find( entry->e_attrs, cbp->mi->mi_attrs[2].an_desc ); + if ( !a || !a->a_vals ) + { + Debug(LDAP_DEBUG_ANY,"service entry %s does not contain %s value\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[2].an_desc->ad_cname.bv_val, 0 ); + return 0; + } + protos = a->a_vals; + numprot = a->a_numvals; + } + else + { + protos=tmparr; + protos[0]=cbp->prot; + BER_BVZERO(&protos[1]); + numprot = 1; + } + /* write the entries */ + for (i=0;i<numprot;i++) + { + int j; + WRITE_INT32(cbp->fp,NSLCD_RESULT_BEGIN); + WRITE_BERVAL(cbp->fp,&name); + if ( dupname >= 0 ) { + WRITE_INT32(cbp->fp,numname-1); + } else { + WRITE_INT32(cbp->fp,numname); + } + for (j=0;j<numname;j++) { + if (j == dupname) continue; + WRITE_BERVAL(cbp->fp,&names[j]); + } + WRITE_INT32(cbp->fp,port); + WRITE_BERVAL(cbp->fp,&protos[i]); + } + return 0; +} + +NSSOV_CB(service) + +NSSOV_HANDLE( + service,byname, + char fbuf[1024]; + struct berval filter = {sizeof(fbuf)}; + filter.bv_val = fbuf; + READ_STRING(fp,cbp.nbuf); + cbp.name.bv_len = tmpint32; + cbp.name.bv_val = cbp.nbuf; + READ_STRING(fp,cbp.pbuf); + cbp.prot.bv_len = tmpint32; + cbp.prot.bv_val = tmpint32 ? cbp.pbuf : NULL;, + Debug(LDAP_DEBUG_TRACE,"nssov_service_byname(%s,%s)\n",cbp.name.bv_val,cbp.prot.bv_val ? cbp.prot.bv_val : "",0);, + NSLCD_ACTION_SERVICE_BYNAME, + mkfilter_service_byname(cbp.mi,&cbp.name,&cbp.prot,&filter) +) + +NSSOV_HANDLE( + service,bynumber, + int number; + char fbuf[1024]; + struct berval filter = {sizeof(fbuf)}; + filter.bv_val = fbuf; + READ_INT32(fp,number); + cbp.name.bv_val = cbp.nbuf; + cbp.name.bv_len = snprintf(cbp.nbuf,sizeof(cbp.nbuf),"%d",number); + READ_STRING(fp,cbp.pbuf); + cbp.prot.bv_len = tmpint32; + cbp.prot.bv_val = tmpint32 ? cbp.pbuf : NULL;, + Debug(LDAP_DEBUG_TRACE,"nssov_service_bynumber(%s,%s)\n",cbp.name.bv_val,cbp.prot.bv_val,0);, + NSLCD_ACTION_SERVICE_BYNUMBER, + mkfilter_service_bynumber(cbp.mi,&cbp.name,&cbp.prot,&filter) +) + +NSSOV_HANDLE( + service,all, + struct berval filter; + /* no parameters to read */ + BER_BVZERO(&cbp.prot);, + Debug(LDAP_DEBUG_TRACE,"nssov_service_all()\n",0,0,0);, + NSLCD_ACTION_SERVICE_ALL, + (filter=cbp.mi->mi_filter,0) +) diff --git a/contrib/slapd-modules/nssov/shadow.c b/contrib/slapd-modules/nssov/shadow.c new file mode 100644 index 0000000..5789a88 --- /dev/null +++ b/contrib/slapd-modules/nssov/shadow.c @@ -0,0 +1,257 @@ +/* shadow.c - shadow account lookup routines */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2008-2021 The OpenLDAP Foundation. + * Portions Copyright 2008 by Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This code references portions of the nss-ldapd package + * written by Arthur de Jong. The nss-ldapd code was forked + * from the nss-ldap library written by Luke Howard. + */ + +#include "nssov.h" + +/* ( nisSchema.2.1 NAME 'shadowAccount' SUP top AUXILIARY + * DESC 'Additional attributes for shadow passwords' + * MUST uid + * MAY ( userPassword $ shadowLastChange $ shadowMin + * shadowMax $ shadowWarning $ shadowInactive $ + * shadowExpire $ shadowFlag $ description ) ) + */ + +/* the basic search filter for searches */ +static struct berval shadow_filter = BER_BVC("(objectClass=shadowAccount)"); + +/* the attributes to request with searches */ +static struct berval shadow_keys[] = { + BER_BVC("uid"), + BER_BVC("userPassword"), + BER_BVC("shadowLastChange"), + BER_BVC("shadowMin"), + BER_BVC("shadowMax"), + BER_BVC("shadowWarning"), + BER_BVC("shadowInactive"), + BER_BVC("shadowExpire"), + BER_BVC("shadowFlag"), + BER_BVNULL +}; + +#define UID_KEY 0 +#define PWD_KEY 1 +#define CHG_KEY 2 +#define MIN_KEY 3 +#define MAX_KEY 4 +#define WRN_KEY 5 +#define INA_KEY 6 +#define EXP_KEY 7 +#define FLG_KEY 8 + +/* default values for attributes */ +static struct berval default_shadow_userPassword = BER_BVC("*"); /* unmatchable */ +static int default_nums[] = { 0,0, + -1, /* LastChange */ + -1, /* Min */ + -1, /* Max */ + -1, /* Warning */ + -1, /* Inactive */ + -1, /* Expire */ + 0 /* Flag */ +}; + +NSSOV_INIT(shadow) + +static long to_date(struct berval *date,AttributeDescription *attr) +{ + long value; + char *tmp; + /* do some special handling for date values on AD */ + if (strcasecmp(attr->ad_cname.bv_val,"pwdLastSet")==0) + { + char buffer[8]; + size_t l; + /* we expect an AD 64-bit datetime value; + we should do date=date/864000000000-134774 + but that causes problems on 32-bit platforms, + first we devide by 1000000000 by stripping the + last 9 digits from the string and going from there */ + l=date->bv_len-9; + if (l<1 || l>(sizeof(buffer)-1)) + return 0; /* error */ + strncpy(buffer,date->bv_val,l); + buffer[l]='\0'; + value=strtol(buffer,&tmp,0); + if ((buffer[0]=='\0')||(*tmp!='\0')) + { + Debug(LDAP_DEBUG_ANY,"shadow entry contains non-numeric %s value\n", + attr->ad_cname.bv_val,0,0); + return 0; + } + return value/864-134774; + /* note that AD does not have expiry dates but a lastchangeddate + and some value that needs to be added */ + } + value=strtol(date->bv_val,&tmp,0); + if ((date->bv_val[0]=='\0')||(*tmp!='\0')) + { + Debug(LDAP_DEBUG_ANY,"shadow entry contains non-numeric %s value\n", + attr->ad_cname.bv_val,0,0); + return 0; + } + return value; +} + +#ifndef UF_DONT_EXPIRE_PASSWD +#define UF_DONT_EXPIRE_PASSWD 0x10000 +#endif + +#define GET_OPTIONAL_LONG(var,key) \ + a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[key].an_desc); \ + if ( !a || BER_BVISNULL(&a->a_vals[0])) \ + var = default_nums[key]; \ + else \ + { \ + if (a->a_numvals > 1) \ + { \ + Debug(LDAP_DEBUG_ANY,"shadow entry %s contains multiple %s values\n", \ + entry->e_name.bv_val, cbp->mi->mi_attrs[key].an_desc->ad_cname.bv_val,0); \ + } \ + var=strtol(a->a_vals[0].bv_val,&tmp,0); \ + if ((a->a_vals[0].bv_val[0]=='\0')||(*tmp!='\0')) \ + { \ + Debug(LDAP_DEBUG_ANY,"shadow entry %s contains non-numeric %s value\n", \ + entry->e_name.bv_val, cbp->mi->mi_attrs[key].an_desc->ad_cname.bv_val,0); \ + return 0; \ + } \ + } + +#define GET_OPTIONAL_DATE(var,key) \ + a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[key].an_desc); \ + if ( !a || BER_BVISNULL(&a->a_vals[0])) \ + var = default_nums[key]; \ + else \ + { \ + if (a->a_numvals > 1) \ + { \ + Debug(LDAP_DEBUG_ANY,"shadow entry %s contains multiple %s values\n", \ + entry->e_name.bv_val, cbp->mi->mi_attrs[key].an_desc->ad_cname.bv_val,0); \ + } \ + var=to_date(&a->a_vals[0],cbp->mi->mi_attrs[key].an_desc); \ + } + +NSSOV_CBPRIV(shadow, + char buf[256]; + struct berval name;); + +static int write_shadow(nssov_shadow_cbp *cbp,Entry *entry) +{ + struct berval tmparr[2]; + struct berval *names; + Attribute *a; + char *tmp; + struct berval passwd = {0}; + long lastchangedate; + long mindays; + long maxdays; + long warndays; + long inactdays; + long expiredate; + unsigned long flag; + int i; + int32_t tmpint32; + /* get username */ + if (BER_BVISNULL(&cbp->name)) + { + a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[UID_KEY].an_desc); + if (!a) + { + Debug(LDAP_DEBUG_ANY,"shadow entry %s does not contain %s value\n", + entry->e_name.bv_val, cbp->mi->mi_attrs[UID_KEY].an_desc->ad_cname.bv_val,0); + return 0; + } + names = a->a_vals; + } + else + { + names=tmparr; + names[0]=cbp->name; + BER_BVZERO(&names[1]); + } + /* get password */ + a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[PWD_KEY].an_desc); + if ( a ) + get_userpassword(&a->a_vals[0], &passwd); + if (BER_BVISNULL(&passwd)) + passwd=default_shadow_userPassword; + /* get lastchange date */ + GET_OPTIONAL_DATE(lastchangedate,CHG_KEY); + /* get mindays */ + GET_OPTIONAL_LONG(mindays,MIN_KEY); + /* get maxdays */ + GET_OPTIONAL_LONG(maxdays,MAX_KEY); + /* get warndays */ + GET_OPTIONAL_LONG(warndays,WRN_KEY); + /* get inactdays */ + GET_OPTIONAL_LONG(inactdays,INA_KEY); + /* get expire date */ + GET_OPTIONAL_LONG(expiredate,EXP_KEY); + /* get flag */ + GET_OPTIONAL_LONG(flag,FLG_KEY); + /* if we're using AD handle the flag specially */ + if (strcasecmp(cbp->mi->mi_attrs[CHG_KEY].an_desc->ad_cname.bv_val,"pwdLastSet")==0) + { + if (flag&UF_DONT_EXPIRE_PASSWD) + maxdays=99999; + flag=0; + } + /* write the entries */ + for (i=0;!BER_BVISNULL(&names[i]);i++) + { + WRITE_INT32(cbp->fp,NSLCD_RESULT_BEGIN); + WRITE_BERVAL(cbp->fp,&names[i]); + WRITE_BERVAL(cbp->fp,&passwd); + WRITE_INT32(cbp->fp,lastchangedate); + WRITE_INT32(cbp->fp,mindays); + WRITE_INT32(cbp->fp,maxdays); + WRITE_INT32(cbp->fp,warndays); + WRITE_INT32(cbp->fp,inactdays); + WRITE_INT32(cbp->fp,expiredate); + WRITE_INT32(cbp->fp,flag); + } + return 0; +} + +NSSOV_CB(shadow) + +NSSOV_HANDLE( + shadow,byname, + char fbuf[1024]; + struct berval filter = {sizeof(fbuf)}; + filter.bv_val = fbuf; + READ_STRING(fp,cbp.buf);, + cbp.name.bv_len = tmpint32; + cbp.name.bv_val = cbp.buf; + Debug(LDAP_DEBUG_ANY,"nssov_shadow_byname(%s)\n",cbp.name.bv_val,0,0);, + NSLCD_ACTION_SHADOW_BYNAME, + nssov_filter_byname(cbp.mi,UID_KEY,&cbp.name,&filter) +) + +NSSOV_HANDLE( + shadow,all, + struct berval filter; + /* no parameters to read */ + BER_BVZERO(&cbp.name);, + Debug(LDAP_DEBUG_ANY,"nssov_shadow_all()\n",0,0,0);, + NSLCD_ACTION_SHADOW_ALL, + (filter=cbp.mi->mi_filter,0) +) diff --git a/contrib/slapd-modules/nssov/slapo-nssov.5 b/contrib/slapd-modules/nssov/slapo-nssov.5 new file mode 100644 index 0000000..83f1af7 --- /dev/null +++ b/contrib/slapd-modules/nssov/slapo-nssov.5 @@ -0,0 +1,316 @@ +.TH SLAPO-NSSOV 5 "RELEASEDATE" "OpenLDAP LDVERSION" +.\" Copyright 1998-2021 The OpenLDAP Foundation, All Rights Reserved. +.\" Copying restrictions apply. See the COPYRIGHT file. +.\" $OpenLDAP$ +.SH NAME +slapo-nssov \- NSS and PAM requests through a local Unix Domain socket +.SH SYNOPSIS +ETCDIR/slapd.conf +.SH DESCRIPTION +The +.B nssov +overlay to +.BR slapd (8) +services NSS and PAM requests through a local Unix Domain socket. +It uses the same IPC protocol as Arthur de Jong's nss-pam-ldapd. +An extract of the nss-ldapd source is included along with the +nssov source code to allow the overlay to communicate with the +nss-pam-ldapd client stubs. +.LP +Using a separate IPC protocol for NSS and PAM requests eliminates the +libldap dependencies/clashes that the current pam_ldap/nss_ldap solutions +all suffer from. Both the original nss-ldapd and this nssov solution +are free from these library issues. +.LP +Unlike nss-pam-ldapd, since this overlay executes inside slapd it allows for +the possibility of sophisticated caching, without any of the weaknesses of +nscd and other related caching solutions. E.g., a remote LDAP database can +be accessed using back-ldap with proxy caching (see +.BR slapd-ldap (5) +and +.BR slapo-pcache (5) +) to leverage back-ldap's +connection pooling as well as pcache's persistent caching, to provide +high performance and a measure of support for disconnected operation. +Alternatively, cache considerations can be completely eliminated by running +a regular database with syncrepl to maintain synchronization with a remote +LDAP database. +.LP +Another major benefit of nssov is that it allows all security policy to be +administered centrally via LDAP, instead of having fragile rules scattered +across multiple flat files. As such, there is no client-side configuration at +all for the NSS/PAM stub libraries. (The stubs talk to the server via a Unix +domain socket whose path is hardcoded to NSLCDPATH). As a side benefit, +this can finally eliminate the perpetual confusion between OpenLDAP's +ldap.conf file in ETCDIR/ldap.conf and the similarly named files typically +used by pam_ldap and nss_ldap. +.LP +User authentication is performed by internal simple Binds. User authorization +leverages the slapd ACL engine, which offers much more power and flexibility +than the simple group/hostname checks in the old pam_ldap code. +.LP +To use this code, you will need the client-side stub library from +nss-pam-ldapd. You can get it from: +http://arthurdejong.org/nss-pam-ldapd +You will not need the nslcd daemon; this overlay replaces that part. +To disable building of the nslcd daemon in nss-pam-ldapd, add the +--disable-nslcd option to the nss-pam-ldapd configure script. You +should already be familiar with the RFC2307 and RFC2307bis schema +to use this overlay. See the nss-pam-ldapd README for more information +on the schema and which features are supported. +.LP +You will also need to include the nis.schema in your slapd configuration +for RFC2307 support. If you wish to use RFC2307bis you will need a slightly +different schema. You will also need the ldapns.schema for PAM authorization +management. +.LP +You must select +.B ldap +in the appropriate services in +.I /etc/nsswitch.conf +in order for these NSS features to take effect. Likewise, you must +enable +.B pam_ldap +for the authenticate, account, session, and password services in +.I /etc/pam.conf +or +.I /etc/pam.d +for these PAM features to take effect. + +.TP +.B overlay nssov +This directive adds the nssov overlay to the current backend. +.TP +.B nssov-ssd <service> <url> +This directive configures a Service Search Descriptor (SSD) for each NSS +service that will be used. The <service> may be one of +.RS +.nf + aliases + ethers + group + hosts + netgroup + networks + passwd + protocols + rpc + services + shadow +.fi +.RE +and the <url> must be of the form +.RS +.TP +.B ldap:///[<basedn>][??[<scope>][?<filter>]] +.RE +The +.B <basedn> +will default to the first suffix of the current database. +The +.B <scope> +defaults to "subtree". The default +.B <filter> +depends on which service is being used. +.TP +.B nssov-map <service> <orig> <new> +If the local database is actually a proxy to a foreign LDAP server, some +mapping of schema may be needed. This directive allows some simple attribute +substitutions to be performed. See the +.B nss-ldapd/README +for the original attribute names used in this code. +.TP +.B nssov-pam <option> [...] +This directive determines a number of PAM behaviors. Multiple options may +be used at once, and available levels are: +.RS +.RS +.PD 0 +.TP +.B userhost +check host attribute in user entry for authorization +.TP +.B userservice +check authorizedService attribute in user entry for authorization +.TP +.B usergroup +check that user is a member of specific group for authorization +.TP +.B hostservice +check authorizedService attribute in host entry for authorization +.TP +.B authz2dn +use authz-regexp mapping to map uid to LDAP DN +.TP +.B uid2dn +use NSS passwd SSD to map uid to LDAP DN +.PD +.RE + +Setting the +.BR userhost , +.BR userservice , +and +.B usergroup +options duplicates the original pam_ldap authorization behavior. + +The recommended approach is to use +.B hostservice +instead. In this case, ipHost entries must be created for all hosts +being managed, and they must also have the authorizedServiceObject +class to allow authorizedService attributes to be used. Also the +NSS host SSD must be configured so that ipHost entries can be found. +Authorization is checked by performing an LDAP Compare operation +looking for the PAM service name in the authorizedService attribute. +.B slapd +ACLs should be set to grant or deny +.B Compare +privilege to the appropriate users or groups as desired. + +If the +.B authz2dn +option is set then authz-regexp mappings will be used to map the +PAM username to an LDAP DN. The authentication DN will be of the +form +.RS +.B cn=<service>+uid=<user>,cn=<hostname>,cn=pam,cn=auth +.RE + +If no mapping is found for this authentication DN, then this +mapping will be ignored. + +If the +.B uid2dn +option is set then the NSS passwd SSD will be used to map the +PAM username to an LDAP DN. The passwd SSD must have already been +configured for this mapping to succeed. + +If neither the authz2dn nor the uid2dn mapping succeeds, the module +will return a PAM_USER_UNKNOWN failure code. If both options are set, +the authz mapping is attempted first; if it succeeds the uid2dn mapping +will be skipped. + +By default only the +.B uid2dn +option is set. +.RE +.TP +.B nssov-pam-defhost <hostname> +Specify a default hostname to check if an ipHost entry for the current +hostname cannot be found. This setting is only relevant if the +.B hostservice +option has been set. +.TP +.B nssov-pam-group-dn <DN> +Specify the DN of an LDAP group to check for authorization. The LDAP user +must be a member of this group for the login to be allowed. There is no +default value. This setting is only relevant if the +.B usergroup +option has been set. +.TP +.B nssov-pam-group-ad <attribute> +Specify the attribute to use for group membership checks. +There is no default value. This setting is only relevant if the +.B usergroup +option has been set. +.TP +.B nssov-pam-min-uid <integer> +Specify a minimum uid that is allowed to login. Users with a uidNumber +lower than this value will be denied access. The default is zero, which +disables this setting. +.TP +.B nssov-pam-max-uid <integer> +Specify a maximum uid that is allowed to login. Users with a uidNumber +higher than this value will be denied access. The default is zero, which +disables this setting. +.TP +.B nssov-pam-template-ad <attribute> +Specify an attribute to check in a user's entry for a template login name. +The template login feature is used by FreeBSD's PAM framework. It can be +viewed as a form of proxying, where a user can authenticate with one +username/password pair, but is assigned the identity and credentials of +the template user. This setting is disabled by default. +.TP +.B nssov-pam-template <name> +Specify a default username to be used if no template attribute is found +in the user's entry. The +.B nssov-pam-template-ad +directive must be configured for this setting to have any effect. +.TP +.B nssov-pam-session <service> +Specify a PAM service name whose sessions will be recorded. For the +configured services, logins will be recorded in the +.TP +.B nssov-pam-password-prohibit-message <message> +Diable password change service and return the specified message to +users. +.TP +.B nssov-pam-pwdmgr-dn <dn> +Specify the dn of the password manager. +.TP +.B nssov-pam-pwdmgr-pwd <pwd> +Specify the pwd of the password manager. +.TP +.B loginStatus +operational attribute of the user's entry. The attribute's values are +of the form +.RS +.RS +.B <generalizedTime> <host> <service> <tty> (<ruser@rhost>) +.RE +.RE +Upon logout the corresponding value will be deleted. This feature allows +a single LDAP Search to be used to check which users are logged in across +all the hosts of a network. The rootdn of the database is used to perform +the updates of the loginStatus attribute, so a rootdn must already be +configured for this feature to work. By default no services are configured. +.LP +The PAM functions support LDAP Password Policy as well. If the password +policy overlay is in use (see +.BR slapo-ppolicy (5)), +policy +information (e.g. password expiration, password quality, etc.) +may be returned to the PAM client as a result of authentication, +account management, and password modification requests. + +The overlay also supports dynamic configuration in cn=config. An example +of the config entry is +.LP +.RS +.nf + dn: olcOverlay={0}nssov,ocDatabase={1}hdb,cn=config + objectClass: olcOverlayConfig + objectClass: olcNssOvConfig + olcOverlay: {0}nssov + olcNssSsd: passwd ldap:///ou=users,dc=example,dc=com??one + olcNssMap: passwd uid accountName + olcNssPam: hostservice uid2dn + olcNssPamDefHost: defaulthost + olcNssPamMinUid: 500 + olcNssPamMaxUid: 32000 + olcNssPamSession: login + olcNssPamSession: sshd +.fi +.RE +.LP +which enables the passwd service, and uses the accountName attribute to +fetch what is usually retrieved from the uid attribute. It also enables +some PAM authorization controls, and specifies that the PAM +.B login +and +.B sshd +services should have their logins recorded. +.SH FILES +.TP +ETCDIR/slapd.conf +default slapd configuration file +.SH SEE ALSO +.BR slapd.conf (5), +.BR slapd\-config (5), +.BR slapd\-ldap (5), +.BR slapo\-pcache (5), +.BR slapo\-ppolicy (5), +.BR slapd (8). +.SH AUTHOR +Howard Chu, inspired by nss-ldapd by Arthur de Jong and pam_ldap by Luke Howard +Enhancements by Ted C. Cheng, Symas Corp. diff --git a/contrib/slapd-modules/passwd/Makefile b/contrib/slapd-modules/passwd/Makefile new file mode 100644 index 0000000..b4f2b93 --- /dev/null +++ b/contrib/slapd-modules/passwd/Makefile @@ -0,0 +1,58 @@ +# $OpenLDAP$ + +LDAP_SRC = ../../.. +LDAP_BUILD = $(LDAP_SRC) +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +CC = gcc +OPT = -g -O2 -Wall +DEFS = +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) + +PROGRAMS = pw-kerberos.la pw-netscape.la pw-radius.la pw-apr1.la +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +pw-kerberos.la: kerberos.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? -lkrb5 + +pw-netscape.la: netscape.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? + +pw-radius.la: radius.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? -lradius + +pw-apr1.la: apr1.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? + +clean: + rm -rf *.o *.lo *.la .libs + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + diff --git a/contrib/slapd-modules/passwd/README b/contrib/slapd-modules/passwd/README new file mode 100644 index 0000000..aff7c85 --- /dev/null +++ b/contrib/slapd-modules/passwd/README @@ -0,0 +1,69 @@ +This directory contains native slapd plugins for password mechanisms that +are not actively supported by the project. Currently this includes the +Kerberos, Netscape MTA-MD5 and RADIUS password mechanisms. The Apache +APR1 MD5 and BSD/Paul Henning Kamp MD5 mechanisms are also included. + +To use the Kerberos plugin, add: + +moduleload pw-kerberos.so + +to your slapd configuration file. + +To use the Netscape plugin, add: + +moduleload pw-netscape.so + +to your slapd configuration file. + +To use the APR1/BSD/MD5 plugin, add: + +moduleload pw-apr1.so + +to your slapd configuration file. + +To use the RADIUS plugin, add: + +moduleload pw-radius.so + +to your slapd configuration file; optionally, the path to a configuration +file can be appended in the form + +moduleload pw-radius.so config="/etc/radius.conf" + +Use Makefile to compile this plugin or use a command line similar to: + +gcc -shared -I../../../include -Wall -g -DHAVE_KRB5 -o pw-kerberos.so kerberos.c + +Replace HAVE_KRB5 with HAVE_KRB4 if you want to use Kerberos IV. +If your Kerberos header files are not in the C compiler's +default path, you will need to add a "-I" directive for that as well. + +The corresponding command for the Netscape plugin would be: + +gcc -shared -I../../../include -Wall -g -o pw-netscape.so netscape.c + +The corresponding command for the RADIUS plugin would be: + +gcc -shared -I../../../include -Wall -g -o pw-radius.so radius.c -lradius + +(Actually, you might want to statically link the RADIUS client library +libradius.a into the module). + +The corresponding command for the APR1 plugin would be: + +gcc -shared -I../../../include -Wall -g -o pw-apr1.so apr1.c + +--- +This work is part of OpenLDAP Software <http://www.openldap.org/>. + +Copyright 2004-2021 The OpenLDAP Foundation. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted only as authorized by the OpenLDAP +Public License. + +A copy of this license is available in the file LICENSE in the +top-level directory of the distribution or, alternatively, at +<http://www.OpenLDAP.org/license.html>. + diff --git a/contrib/slapd-modules/passwd/apr1-atol.pl b/contrib/slapd-modules/passwd/apr1-atol.pl new file mode 100644 index 0000000..d6eaee7 --- /dev/null +++ b/contrib/slapd-modules/passwd/apr1-atol.pl @@ -0,0 +1,29 @@ +#!/usr/bin/perl -w
+
+# Apache $apr1$ to OpenLDAP {APR1} hash converter
+# (C) 2011 Devin J. Pohly
+# You may use this code freely. It would be nice to be credited.
+
+use MIME::Base64;
+
+while (<>) {
+ ($user, $hash) = split(/:/, $_);
+ unless ($hash =~ /^\$apr1\$/) {
+ print STDERR "Not an Apache MD5 hash\n";
+ exit 1;
+ }
+
+ chomp $hash;
+ ($_,$_,$salt,$hash) = split(/\$/, $hash);
+
+ $hash =~ tr|./0-9A-Za-z|A-Za-z0-9+/|;
+ $hash .= "AA";
+ $hash =~ s/(.)(.)(.)(.)/$4$3$2$1/gs;
+ $hash = decode_base64($hash);
+ $hash =~ s/(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)..(.)/$1$4$7$10$13$15$2$5$8$11$14$16$3$6$9$12/s;
+ $hash .= $salt;
+ $hash = encode_base64($hash);
+ chop $hash;
+
+ print "$user:{APR1}$hash\n";
+}
\ No newline at end of file diff --git a/contrib/slapd-modules/passwd/apr1-ltoa.pl b/contrib/slapd-modules/passwd/apr1-ltoa.pl new file mode 100644 index 0000000..ee628ec --- /dev/null +++ b/contrib/slapd-modules/passwd/apr1-ltoa.pl @@ -0,0 +1,31 @@ +#!/usr/bin/perl -w
+
+# OpenLDAP {APR1} to Apache $apr1$ hash converter
+# (C) 2011 Devin J. Pohly
+# You may use this code freely. It would be nice to be credited.
+
+use MIME::Base64;
+
+while (<>) {
+ ($user, $hash) = split(/:/, $_);
+ unless ($hash =~ /^{APR1}/) {
+ print STDERR "Not an Apache MD5 hash\n";
+ next;
+ }
+
+ chomp $hash;
+ $hash = decode_base64(substr($hash, 6));
+ ($hash, $salt) = (substr($hash, 0, 16), substr($hash, 16));
+ $hash = $hash;
+ $hash =~ s/(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)/$1$7$13$2$8$14$3$9$15$4$10$16$5$11$6\0\0$12/s;
+ $hash = encode_base64($hash);
+ chomp $hash;
+ $hash =~ s/(.)(.)(.)(.)/$4$3$2$1/gs;
+ unless ($hash =~ /AA$/) {
+ #print "Problem with hash\n";
+ next;
+ }
+ $hash =~ s/AA$//;
+ $hash =~ tr|A-Za-z0-9+/|./0-9A-Za-z|;
+ print "$user:\$apr1\$$salt\$$hash\n"
+}
\ No newline at end of file diff --git a/contrib/slapd-modules/passwd/apr1.c b/contrib/slapd-modules/passwd/apr1.c new file mode 100644 index 0000000..0ddb01b --- /dev/null +++ b/contrib/slapd-modules/passwd/apr1.c @@ -0,0 +1,233 @@ +/* $OpenLDAP$ */ +/* + * This file is derived from OpenLDAP Software. All of the modifications to + * OpenLDAP Software represented in the following file were developed by + * Devin J. Pohly <djpohly@gmail.com>. I have not assigned rights and/or + * interest in this work to any party. + * + * The extensions to OpenLDAP Software herein are subject to the following + * notice: + * + * Copyright 2011 Devin J. Pohly + * Portions Copyright 2011 Howard Chu + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP Public + * License. + * + * A portion of this code is used in accordance with the Beer-ware License, + * revision 42, as noted. + * + */ +#include <lber.h> +#include <lber_pvt.h> +#include "lutil.h" +#include "lutil_md5.h" +#include <ac/string.h> + +#include <assert.h> + +/* the only difference between this and straight PHK is the magic */ +static LUTIL_PASSWD_CHK_FUNC chk_apr1; +static LUTIL_PASSWD_HASH_FUNC hash_apr1; +static const struct berval scheme_apr1 = BER_BVC("{APR1}"); +static const struct berval magic_apr1 = BER_BVC("$apr1$"); + +static LUTIL_PASSWD_CHK_FUNC chk_bsdmd5; +static LUTIL_PASSWD_HASH_FUNC hash_bsdmd5; +static const struct berval scheme_bsdmd5 = BER_BVC("{BSDMD5}"); +static const struct berval magic_bsdmd5 = BER_BVC("$1$"); + +static const unsigned char apr64[] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +#define APR_SALT_SIZE 8 + +/* The algorithm implemented in this function was created by Poul-Henning + * Kamp and released under the following license: + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return Poul-Henning Kamp + * ---------------------------------------------------------------------------- + */ +static void do_phk_hash( + const struct berval *passwd, + const struct berval *salt, + const struct berval *magic, + unsigned char *digest) +{ + lutil_MD5_CTX ctx, ctx1; + int n; + + /* Start hashing */ + lutil_MD5Init(&ctx); + lutil_MD5Update(&ctx, (const unsigned char *) passwd->bv_val, passwd->bv_len); + lutil_MD5Update(&ctx, (const unsigned char *) magic->bv_val, magic->bv_len); + lutil_MD5Update(&ctx, (const unsigned char *) salt->bv_val, salt->bv_len); + /* Inner hash */ + lutil_MD5Init(&ctx1); + lutil_MD5Update(&ctx1, (const unsigned char *) passwd->bv_val, passwd->bv_len); + lutil_MD5Update(&ctx1, (const unsigned char *) salt->bv_val, salt->bv_len); + lutil_MD5Update(&ctx1, (const unsigned char *) passwd->bv_val, passwd->bv_len); + lutil_MD5Final(digest, &ctx1); + /* Nom start mixing things up */ + for (n = passwd->bv_len; n > 0; n -= LUTIL_MD5_BYTES) + lutil_MD5Update(&ctx, digest, + (n > LUTIL_MD5_BYTES ? LUTIL_MD5_BYTES : n)); + memset(digest, 0, LUTIL_MD5_BYTES); + /* Curiouser and curiouser... */ + for (n = passwd->bv_len; n; n >>= 1) + if (n & 1) + lutil_MD5Update(&ctx, digest, 1); + else + lutil_MD5Update(&ctx, (const unsigned char *) passwd->bv_val, 1); + lutil_MD5Final(digest, &ctx); + /* + * Repeatedly hash things into the final value. This was originally + * intended to slow the algorithm down. + */ + for (n = 0; n < 1000; n++) { + lutil_MD5Init(&ctx1); + if (n & 1) + lutil_MD5Update(&ctx1, + (const unsigned char *) passwd->bv_val, passwd->bv_len); + else + lutil_MD5Update(&ctx1, digest, LUTIL_MD5_BYTES); + + if (n % 3) + lutil_MD5Update(&ctx1, + (const unsigned char *) salt->bv_val, salt->bv_len); + if (n % 7) + lutil_MD5Update(&ctx1, + (const unsigned char *) passwd->bv_val, passwd->bv_len); + + if (n & 1) + lutil_MD5Update(&ctx1, digest, LUTIL_MD5_BYTES); + else + lutil_MD5Update(&ctx1, + (const unsigned char *) passwd->bv_val, passwd->bv_len); + lutil_MD5Final(digest, &ctx1); + } +} + +static int chk_phk( + const struct berval *magic, + const struct berval *passwd, + const struct berval *cred, + const char **text) +{ + unsigned char digest[LUTIL_MD5_BYTES]; + unsigned char *orig_pass; + int rc; + struct berval salt; + size_t decode_len = LUTIL_BASE64_DECODE_LEN(passwd->bv_len); + + /* safety check */ + if (decode_len <= sizeof(digest)) + return LUTIL_PASSWD_ERR; + + /* base64 un-encode password hash */ + orig_pass = (unsigned char *) ber_memalloc(decode_len + 1); + + if (orig_pass == NULL) + return LUTIL_PASSWD_ERR; + + rc = lutil_b64_pton(passwd->bv_val, orig_pass, decode_len); + + if (rc <= (int) sizeof(digest)) { + ber_memfree(orig_pass); + return LUTIL_PASSWD_ERR; + } + + salt.bv_val = (char *) &orig_pass[sizeof(digest)]; + salt.bv_len = rc - sizeof(digest); + + do_phk_hash(cred, &salt, magic, digest); + + if (text) + *text = NULL; + + /* compare */ + rc = memcmp((char *) orig_pass, (char *) digest, sizeof(digest)); + ber_memfree(orig_pass); + return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; +} + +static int chk_apr1( + const struct berval *scheme, + const struct berval *passwd, + const struct berval *cred, + const char **text) +{ + return chk_phk(&magic_apr1, passwd, cred, text); +} + +static int chk_bsdmd5( + const struct berval *scheme, + const struct berval *passwd, + const struct berval *cred, + const char **text) +{ + return chk_phk(&magic_bsdmd5, passwd, cred, text); +} + +static int hash_phk( + const struct berval *scheme, + const struct berval *magic, + const struct berval *passwd, + struct berval *hash, + const char **text) +{ + unsigned char digest_buf[LUTIL_MD5_BYTES]; + char salt_buf[APR_SALT_SIZE]; + struct berval digest; + struct berval salt; + int n; + + digest.bv_val = (char *) digest_buf; + digest.bv_len = sizeof(digest_buf); + salt.bv_val = salt_buf; + salt.bv_len = APR_SALT_SIZE; + + /* generate random salt */ + if (lutil_entropy( (unsigned char *) salt.bv_val, salt.bv_len) < 0) + return LUTIL_PASSWD_ERR; + /* limit it to characters in the 64-char set */ + for (n = 0; n < salt.bv_len; n++) + salt.bv_val[n] = apr64[salt.bv_val[n] % (sizeof(apr64) - 1)]; + + do_phk_hash(passwd, &salt, magic, digest_buf); + + if (text) + *text = NULL; + + return lutil_passwd_string64(scheme, &digest, hash, &salt); +} + +static int hash_apr1( + const struct berval *scheme, + const struct berval *passwd, + struct berval *hash, + const char **text) +{ + return hash_phk(scheme, &magic_apr1, passwd, hash, text); +} + +static int hash_bsdmd5( + const struct berval *scheme, + const struct berval *passwd, + struct berval *hash, + const char **text) +{ + return hash_phk(scheme, &magic_bsdmd5, passwd, hash, text); +} + +int init_module(int argc, char *argv[]) { + int rc; + rc = lutil_passwd_add((struct berval *) &scheme_apr1, chk_apr1, hash_apr1); + if ( !rc ) + rc = lutil_passwd_add((struct berval *) &scheme_bsdmd5, + chk_bsdmd5, hash_bsdmd5); + return rc; +} diff --git a/contrib/slapd-modules/passwd/argon2/Makefile b/contrib/slapd-modules/passwd/argon2/Makefile new file mode 100644 index 0000000..0294ba0 --- /dev/null +++ b/contrib/slapd-modules/passwd/argon2/Makefile @@ -0,0 +1,70 @@ +# $OpenLDAP$ + +LDAP_SRC = ../../../.. +LDAP_BUILD = ../../../.. +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +INSTALL = /usr/bin/install +CC = gcc +OPT = -g -O2 -Wall +#DEFS = -DSLAPD_ARGON2_DEBUG + +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) + +implementation = sodium + +ifeq ($(implementation),argon2) +LIBS += -largon2 +DEFS += -DSLAPD_ARGON2_USE_ARGON2 +else ifeq ($(implementation),sodium) +LIBS += -lsodium +DEFS += -DSLAPD_ARGON2_USE_SODIUM +else +$(error Unsupported implementation $(implementation)) +endif + +PROGRAMS = pw-argon2.la +MANPAGES = slapd-pw-argon2.5 +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) +mandir = $(exec_prefix)/share/man +man5dir = $(mandir)/man5 + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +pw-argon2.la: pw-argon2.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: install-lib install-man FORCE + +install-lib: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + +install-man: $(MANPAGES) + mkdir -p $(DESTDIR)$(man5dir) + $(INSTALL) -m 644 $(MANPAGES) $(DESTDIR)$(man5dir) + +FORCE: diff --git a/contrib/slapd-modules/passwd/argon2/README b/contrib/slapd-modules/passwd/argon2/README new file mode 100644 index 0000000..13ba69f --- /dev/null +++ b/contrib/slapd-modules/passwd/argon2/README @@ -0,0 +1,109 @@ +Argon2 OpenLDAP support +---------------------- + +pw-argon2.c provides support for ARGON2 hashed passwords in OpenLDAP. For +instance, one could have the LDAP attribute: + +userPassword: {ARGON2}$argon2i$v=19$m=4096,t=3,p=1$c2FsdHNhbHQ$DKlexoEJUoZTmkAAC3SaMWk30El9/RvVhlqGo6afIng + +or: + +userPassword: {ARGON2}$argon2i$v=19$m=4096,t=3,p=1$c2FsdHNhbHRzYWx0$qOCkx9nMeFlaGOO4DUmPDgrlUbgMMuO9T1+vQCFuyzw + +Both hash the password "secret", the first using the salt "saltsalt", the second using the salt "saltsaltsalt" + +Building +-------- + +1) Customize the OPENLDAP variable in Makefile to point to the OpenLDAP +source root. + +For initial testing you might also want to edit DEFS to define +SLAPD_ARGON2_DEBUG, which enables logging to stderr (don't leave this on +in production, as it prints passwords in cleartext). + +2) Run 'make' to produce pw-argon2.so + +3) Copy pw-argon2.so somewhere permanent. + +4) Edit your slapd.conf (eg. /etc/ldap/slapd.conf), and add: + +moduleload ...path/to/pw-argon2.so + +5) Restart slapd. + + +Configuring +----------- + +The {ARGON2} password scheme should now be recognised. + +You can also tell OpenLDAP to use one of this scheme when processing LDAP +Password Modify Extended Operations, thanks to the password-hash option in +slapd.conf: + +password-hash {ARGON2} + + +Testing +------- + +A quick way to test whether it's working is to customize the rootdn and +rootpw in slapd.conf, eg: + +rootdn "cn=admin,dc=example,dc=com" + +# This hashes the string 'secret', with a random salt +rootpw {ARGON2}$argon2i$v=19$m=4096,t=3,p=1$uJyf0UfB25SQTfX7oCyK2w$U45DJqEFwD0yFaLvTVyACHLvGMwzNGf19dvzPR8XvGc + + +Then to test, run something like: + +ldapsearch -b "dc=example,dc=com" -D "cn=admin,dc=example,dc=com" -x -w secret + + +-- Test hashes: + +Test hashes can be generated with argon2: +$ echo -n "secret" | argon2 "saltsalt" -e +$argon2i$v=19$m=4096,t=3,p=1$c2FsdHNhbHQ$DKlexoEJUoZTmkAAC3SaMWk30El9/RvVhlqGo6afIng + +$ echo -n "secret" | argon2 "saltsaltsalt" -e +$argon2i$v=19$m=4096,t=3,p=1$c2FsdHNhbHRzYWx0$qOCkx9nMeFlaGOO4DUmPDgrlUbgMMuO9T1+vQCFuyzw + +$ echo -n "secretsecret" | argon2 "saltsalt" -e +$argon2i$v=19$m=4096,t=3,p=1$c2FsdHNhbHQ$U0Pd/wEsssZ9bHezDA8oxHnWe01xftykEy+7ehM2vic + +$ echo -n "secretsecret" | argon2 "saltsaltsalt" -e +$argon2i$v=19$m=4096,t=3,p=1$c2FsdHNhbHRzYWx0$fkvoOwKgVtlX9ZDqcHFyyArBvqnAM0Igca8SScB4Jsc + + + +Alternatively we could modify an existing user's password with +ldappasswd, and then test binding as that user: + +$ ldappasswd -D "cn=admin,dc=example,dc=com" -x -W -S uid=jturner,ou=People,dc=example,dc=com +New password: secret +Re-enter new password: secret +Enter LDAP Password: <cn=admin's password> + +$ ldapsearch -b "dc=example,dc=com" -D "uid=jturner,ou=People,dc=example,dc=com" -x -w secret + + + +--- + +This work is part of OpenLDAP Software <http://www.openldap.org/>. + +Copyright 2017-2021 The OpenLDAP Foundation. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted only as authorized by the OpenLDAP +Public License. + +A copy of this license is available in the file LICENSE in the +top-level directory of the distribution or, alternatively, at +<http://www.OpenLDAP.org/license.html>. + +--- diff --git a/contrib/slapd-modules/passwd/argon2/pw-argon2.c b/contrib/slapd-modules/passwd/argon2/pw-argon2.c new file mode 100644 index 0000000..94c9e46 --- /dev/null +++ b/contrib/slapd-modules/passwd/argon2/pw-argon2.c @@ -0,0 +1,220 @@ +/* pw-argon2.c - Password module for argon2 */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2017-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ + +#include "portable.h" +#include "ac/string.h" +#include "lber_pvt.h" +#include "lutil.h" + +#include <stdint.h> +#include <stdlib.h> + +#ifdef SLAPD_ARGON2_USE_ARGON2 +#include <argon2.h> + +/* + * For now, we hardcode the default values from the argon2 command line tool + * (as of argon2 release 20161029) + */ +#define SLAPD_ARGON2_ITERATIONS 3 +#define SLAPD_ARGON2_MEMORY (1 << 12) +#define SLAPD_ARGON2_PARALLELISM 1 +#define SLAPD_ARGON2_SALT_LENGTH 16 +#define SLAPD_ARGON2_HASH_LENGTH 32 + +#else /* !SLAPD_ARGON2_USE_ARGON2 */ +#include <sodium.h> + +/* + * Or libsodium interactive settings + */ +#define SLAPD_ARGON2_ITERATIONS crypto_pwhash_argon2id_OPSLIMIT_INTERACTIVE +#define SLAPD_ARGON2_MEMORY (crypto_pwhash_argon2id_MEMLIMIT_INTERACTIVE / 1024) +#define SLAPD_ARGON2_PARALLELISM 1 +#define SLAPD_ARGON2_SALT_LENGTH crypto_pwhash_argon2id_SALTBYTES +#define SLAPD_ARGON2_HASH_LENGTH 32 + +#endif + +static unsigned long iterations = SLAPD_ARGON2_ITERATIONS; +static unsigned long memory = SLAPD_ARGON2_MEMORY; +static unsigned long parallelism = SLAPD_ARGON2_PARALLELISM; + +const struct berval slapd_argon2_scheme = BER_BVC("{ARGON2}"); + +static int +slapd_argon2_hash( + const struct berval *scheme, + const struct berval *passwd, + struct berval *hash, + const char **text ) +{ + + /* + * Duplicate these values here so future code which allows + * configuration has an easier time. + */ + uint32_t salt_length, hash_length; + char *p; + int rc = LUTIL_PASSWD_ERR; + +#ifdef SLAPD_ARGON2_USE_ARGON2 + struct berval salt; + size_t encoded_length; + + salt_length = SLAPD_ARGON2_SALT_LENGTH; + hash_length = SLAPD_ARGON2_HASH_LENGTH; + + encoded_length = argon2_encodedlen( iterations, memory, parallelism, + salt_length, hash_length, Argon2_id ); + + salt.bv_len = salt_length; + salt.bv_val = ber_memalloc( salt.bv_len ); + + if ( salt.bv_val == NULL ) { + return LUTIL_PASSWD_ERR; + } + + if ( lutil_entropy( (unsigned char*)salt.bv_val, salt.bv_len ) ) { + ber_memfree( salt.bv_val ); + return LUTIL_PASSWD_ERR; + } + + p = hash->bv_val = ber_memalloc( scheme->bv_len + encoded_length ); + if ( p == NULL ) { + ber_memfree( salt.bv_val ); + return LUTIL_PASSWD_ERR; + } + + AC_MEMCPY( p, scheme->bv_val, scheme->bv_len ); + p += scheme->bv_len; + + /* + * Do the actual heavy lifting + */ + if ( argon2i_hash_encoded( iterations, memory, parallelism, + passwd->bv_val, passwd->bv_len, + salt.bv_val, salt_length, hash_length, + p, encoded_length ) == 0 ) { + rc = LUTIL_PASSWD_OK; + } + hash->bv_len = scheme->bv_len + encoded_length; + ber_memfree( salt.bv_val ); + +#else /* !SLAPD_ARGON2_USE_ARGON2 */ + /* Not exposed by libsodium + salt_length = SLAPD_ARGON2_SALT_LENGTH; + hash_length = SLAPD_ARGON2_HASH_LENGTH; + */ + + p = hash->bv_val = ber_memalloc( scheme->bv_len + crypto_pwhash_STRBYTES ); + if ( p == NULL ) { + return LUTIL_PASSWD_ERR; + } + + AC_MEMCPY( hash->bv_val, scheme->bv_val, scheme->bv_len ); + p += scheme->bv_len; + + if ( crypto_pwhash_str_alg( p, passwd->bv_val, passwd->bv_len, + iterations, memory * 1024, + crypto_pwhash_ALG_ARGON2ID13 ) == 0 ) { + hash->bv_len = strlen( hash->bv_val ); + rc = LUTIL_PASSWD_OK; + } +#endif + + if ( rc ) { + ber_memfree( hash->bv_val ); + return LUTIL_PASSWD_ERR; + } + + return LUTIL_PASSWD_OK; +} + +static int +slapd_argon2_verify( + const struct berval *scheme, + const struct berval *passwd, + const struct berval *cred, + const char **text ) +{ + int rc = LUTIL_PASSWD_ERR; + +#ifdef SLAPD_ARGON2_USE_ARGON2 + if ( strncmp( passwd->bv_val, "$argon2i$", STRLENOF("$argon2i$") ) == 0 ) { + rc = argon2i_verify( passwd->bv_val, cred->bv_val, cred->bv_len ); + } else if ( strncmp( passwd->bv_val, "$argon2d$", STRLENOF("$argon2d$") ) == 0 ) { + rc = argon2d_verify( passwd->bv_val, cred->bv_val, cred->bv_len ); + } else if ( strncmp( passwd->bv_val, "$argon2id$", STRLENOF("$argon2id$") ) == 0 ) { + rc = argon2id_verify( passwd->bv_val, cred->bv_val, cred->bv_len ); + } +#else /* !SLAPD_ARGON2_USE_ARGON2 */ + rc = crypto_pwhash_str_verify( passwd->bv_val, cred->bv_val, cred->bv_len ); +#endif + + if ( rc ) { + return LUTIL_PASSWD_ERR; + } + return LUTIL_PASSWD_OK; +} + +int init_module( int argc, char *argv[] ) +{ + int i; + +#ifndef SLAPD_ARGON2_USE_ARGON2 + if ( sodium_init() == -1 ) { + return -1; + } +#endif + + for ( i=0; i < argc; i++ ) { + char *p; + unsigned long value; + + switch ( *argv[i] ) { + case 'm': + p = strchr( argv[i], '=' ); + if ( !p || lutil_atoulx( &value, p+1, 0 ) ) { + return -1; + } + memory = value; + break; + + case 't': + p = strchr( argv[i], '=' ); + if ( !p || lutil_atoulx( &value, p+1, 0 ) ) { + return -1; + } + iterations = value; + break; + + case 'p': + p = strchr( argv[i], '=' ); + if ( !p || lutil_atoulx( &value, p+1, 0 ) ) { + return -1; + } + parallelism = value; + break; + + default: + return -1; + } + } + + return lutil_passwd_add( (struct berval *)&slapd_argon2_scheme, + slapd_argon2_verify, slapd_argon2_hash ); +} diff --git a/contrib/slapd-modules/passwd/argon2/slapd-pw-argon2.5 b/contrib/slapd-modules/passwd/argon2/slapd-pw-argon2.5 new file mode 100644 index 0000000..23cc87a --- /dev/null +++ b/contrib/slapd-modules/passwd/argon2/slapd-pw-argon2.5 @@ -0,0 +1,122 @@ +.TH SLAPD-PW-ARGON2 5 "RELEASEDATE" "OpenLDAP LDVERSION" +.\" Copyright 2020-2021 The OpenLDAP Foundation All Rights Reserved. +.\" Copying restrictions apply. See COPYRIGHT/LICENSE. +.\" $OpenLDAP$ +.SH NAME +slapd-pw-argon2 \- Argon2 password module to slapd +.SH SYNOPSIS +ETCDIR/slapd.conf +.RS +.LP +.B moduleload pw-argon2 +.RI [ <parameters> ] +.RE +.SH DESCRIPTION +.LP +The +.B pw-argon2 +module to +.BR slapd (8) +provides support for the use of the key derivation function Argon2, +that was selected as the winner of the Password Hashing Competition in July 2015, +in hashed passwords in OpenLDAP. +.LP +It does so by providing the additional password scheme +.B {ARGON2} +for use in slapd. + +.SH CONFIGURATION +The +.B pw-argon2 +module does not need any configuration, +but it can be configured by giving the following parameters: +.TP +.BI m= <memory> +Set memory usage to +.I <memory> +kiB. +.TP +.BI p= <parallelism> +Set parallelism to +.I <parallelism> +threads. +.TP +.BI t= <iterations> +Set the number of iterations to +.IR <iterations> . +.LP +These replace defaults when preparing hashes for new passwords where possible. +.LP +After loading the module, the password scheme +.B {ARGON2} +will be recognised in values of the +.I userPassword +attribute. +.LP +You can then instruct OpenLDAP to use this scheme when processing +the LDAPv3 Password Modify (RFC 3062) extended operations by using the +.BR password-hash +option in +.BR slapd.conf (5): +.RS +.LP +.B password\-hash {ARGON2} +.RE +.LP + +.SS NOTES +If you want to use the scheme described here with +.BR slappasswd (8), +remember to load the module using its command line options. +The relevant option/value is: +.RS +.LP +.B \-o +.BR module\-load = pw-argon2 +.LP +.RE +Depending on +.BR pw-argon2 's +location, you may also need: +.RS +.LP +.B \-o +.BR module\-path = \fIpathspec\fP +.RE + +.SH EXAMPLES +Both userPassword LDAP attributes below encode the password +.RI ' secret ' +using different salts: +.EX +.LP +userPassword: {ARGON2}$argon2i$v=19$m=4096,t=3,p=1$c2FsdHNhbHQ$DKlexoEJUoZTmkAAC3SaMWk30El9/RvVhlqGo6afIng +.LP +userPassword: {ARGON2}$argon2i$v=19$m=4096,t=3,p=1$c2FsdHNhbHRzYWx0$qOCkx9nMeFlaGOO4DUmPDgrlUbgMMuO9T1+vQCFuyzw +.EE + +.SH SEE ALSO +.BR slapd.conf (5), +.BR ldappasswd (1), +.BR slappasswd (8), +.BR ldap (3), +.LP +.UR http://www.OpenLDAP.org/doc/ +"OpenLDAP Administrator's Guide" +.UE +.LP + +.SH ACKNOWLEDGEMENTS +This manual page has been written by Peter Marschall based on the +module's README file written by +.MT simon@levermann.de +Simon Levermann +.ME . +.LP +.B OpenLDAP +is developed and maintained by +.UR http://www.openldap.org/ +The OpenLDAP Project +.UE . +.B OpenLDAP +is derived from University of Michigan LDAP 3.3 Release. diff --git a/contrib/slapd-modules/passwd/kerberos.c b/contrib/slapd-modules/passwd/kerberos.c new file mode 100644 index 0000000..eecf00a --- /dev/null +++ b/contrib/slapd-modules/passwd/kerberos.c @@ -0,0 +1,209 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 1998-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ + +#include <unistd.h> + +#include <lber.h> +#include <lber_pvt.h> /* BER_BVC definition */ +#include "lutil.h" +#include <ac/string.h> + +#ifdef HAVE_KRB5 +#include <krb5.h> +#elif defined(HAVE_KRB4) +#include <krb.h> +#endif + +/* From <ldap_pvt.h> */ +LDAP_F( char *) ldap_pvt_get_fqdn LDAP_P(( char * )); + +static LUTIL_PASSWD_CHK_FUNC chk_kerberos; +static const struct berval scheme = BER_BVC("{KERBEROS}"); + +static int chk_kerberos( + const struct berval *sc, + const struct berval * passwd, + const struct berval * cred, + const char **text ) +{ + unsigned int i; + int rtn; + + for( i=0; i<cred->bv_len; i++) { + if(cred->bv_val[i] == '\0') { + return LUTIL_PASSWD_ERR; /* NUL character in password */ + } + } + + if( cred->bv_val[i] != '\0' ) { + return LUTIL_PASSWD_ERR; /* cred must behave like a string */ + } + + for( i=0; i<passwd->bv_len; i++) { + if(passwd->bv_val[i] == '\0') { + return LUTIL_PASSWD_ERR; /* NUL character in password */ + } + } + + if( passwd->bv_val[i] != '\0' ) { + return LUTIL_PASSWD_ERR; /* passwd must behave like a string */ + } + + rtn = LUTIL_PASSWD_ERR; + +#ifdef HAVE_KRB5 /* HAVE_HEIMDAL_KRB5 */ + { +/* Portions: + * Copyright (c) 1997, 1998, 1999 Kungliga Tekniska H\xf6gskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + krb5_context context; + krb5_error_code ret; + krb5_creds creds; + krb5_get_init_creds_opt get_options; + krb5_verify_init_creds_opt verify_options; + krb5_principal client, server; +#ifdef notdef + krb5_preauthtype pre_auth_types[] = {KRB5_PADATA_ENC_TIMESTAMP}; +#endif + + ret = krb5_init_context( &context ); + if (ret) { + return LUTIL_PASSWD_ERR; + } + +#ifdef notdef + krb5_get_init_creds_opt_set_preauth_list(&get_options, + pre_auth_types, 1); +#endif + + krb5_get_init_creds_opt_init( &get_options ); + + krb5_verify_init_creds_opt_init( &verify_options ); + + ret = krb5_parse_name( context, passwd->bv_val, &client ); + + if (ret) { + krb5_free_context( context ); + return LUTIL_PASSWD_ERR; + } + + ret = krb5_get_init_creds_password( context, + &creds, client, cred->bv_val, NULL, + NULL, 0, NULL, &get_options ); + + if (ret) { + krb5_free_principal( context, client ); + krb5_free_context( context ); + return LUTIL_PASSWD_ERR; + } + + { + char *host = ldap_pvt_get_fqdn( NULL ); + + if( host == NULL ) { + krb5_free_principal( context, client ); + krb5_free_context( context ); + return LUTIL_PASSWD_ERR; + } + + ret = krb5_sname_to_principal( context, + host, "ldap", KRB5_NT_SRV_HST, &server ); + + ber_memfree( host ); + } + + if (ret) { + krb5_free_principal( context, client ); + krb5_free_context( context ); + return LUTIL_PASSWD_ERR; + } + + ret = krb5_verify_init_creds( context, + &creds, server, NULL, NULL, &verify_options ); + + krb5_free_principal( context, client ); + krb5_free_principal( context, server ); + krb5_free_cred_contents( context, &creds ); + krb5_free_context( context ); + + rtn = ret ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; + } +#elif defined(HAVE_KRB4) + { + /* Borrowed from Heimdal kpopper */ +/* Portions: + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + + int status; + char lrealm[REALM_SZ]; + char tkt[MAXHOSTNAMELEN]; + + status = krb_get_lrealm(lrealm,1); + if (status == KFAILURE) { + return LUTIL_PASSWD_ERR; + } + + snprintf(tkt, sizeof(tkt), "%s_slapd.%u", + TKT_ROOT, (unsigned)getpid()); + krb_set_tkt_string (tkt); + + status = krb_verify_user( passwd->bv_val, "", lrealm, + cred->bv_val, 1, "ldap"); + + dest_tkt(); /* no point in keeping the tickets */ + + return status == KFAILURE ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; + } +#endif + + return rtn; +} + +int init_module(int argc, char *argv[]) { + return lutil_passwd_add( (struct berval *)&scheme, chk_kerberos, NULL ); +} diff --git a/contrib/slapd-modules/passwd/netscape.c b/contrib/slapd-modules/passwd/netscape.c new file mode 100644 index 0000000..0551fe6 --- /dev/null +++ b/contrib/slapd-modules/passwd/netscape.c @@ -0,0 +1,81 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 1998-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ + +#include <unistd.h> + +#include <lber.h> +#include <lber_pvt.h> +#include "lutil.h" +#include "lutil_md5.h" +#include <ac/string.h> + +static LUTIL_PASSWD_CHK_FUNC chk_ns_mta_md5; +static const struct berval scheme = BER_BVC("{NS-MTA-MD5}"); + +#define NS_MTA_MD5_PASSLEN 64 +static int chk_ns_mta_md5( + const struct berval *scheme, + const struct berval *passwd, + const struct berval *cred, + const char **text ) +{ + lutil_MD5_CTX MD5context; + unsigned char MD5digest[LUTIL_MD5_BYTES], c; + char buffer[LUTIL_MD5_BYTES*2]; + int i; + + if( passwd->bv_len != NS_MTA_MD5_PASSLEN ) { + return LUTIL_PASSWD_ERR; + } + + /* hash credentials with salt */ + lutil_MD5Init(&MD5context); + lutil_MD5Update(&MD5context, + (const unsigned char *) &passwd->bv_val[32], + 32 ); + + c = 0x59; + lutil_MD5Update(&MD5context, + (const unsigned char *) &c, + 1 ); + + lutil_MD5Update(&MD5context, + (const unsigned char *) cred->bv_val, + cred->bv_len ); + + c = 0xF7; + lutil_MD5Update(&MD5context, + (const unsigned char *) &c, + 1 ); + + lutil_MD5Update(&MD5context, + (const unsigned char *) &passwd->bv_val[32], + 32 ); + + lutil_MD5Final(MD5digest, &MD5context); + + for( i=0; i < sizeof( MD5digest ); i++ ) { + buffer[i+i] = "0123456789abcdef"[(MD5digest[i]>>4) & 0x0F]; + buffer[i+i+1] = "0123456789abcdef"[ MD5digest[i] & 0x0F]; + } + + /* compare */ + return memcmp((char *)passwd->bv_val, + (char *)buffer, sizeof(buffer)) ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; +} + +int init_module(int argc, char *argv[]) { + return lutil_passwd_add( (struct berval *)&scheme, chk_ns_mta_md5, NULL ); +} diff --git a/contrib/slapd-modules/passwd/pbkdf2/Makefile b/contrib/slapd-modules/passwd/pbkdf2/Makefile new file mode 100644 index 0000000..5234629 --- /dev/null +++ b/contrib/slapd-modules/passwd/pbkdf2/Makefile @@ -0,0 +1,46 @@ +# $OpenLDAP$ + +LDAP_SRC = ../../../.. +LDAP_BUILD = ../../../.. +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +CC = gcc +OPT = -g -O2 -Wall +#DEFS = -DSLAPD_PBKDF2_DEBUG + +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) -lcrypto + +PROGRAMS = pw-pbkdf2.la +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +pw-pbkdf2.la: pw-pbkdf2.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done diff --git a/contrib/slapd-modules/passwd/pbkdf2/README b/contrib/slapd-modules/passwd/pbkdf2/README new file mode 100644 index 0000000..2f9a635 --- /dev/null +++ b/contrib/slapd-modules/passwd/pbkdf2/README @@ -0,0 +1,99 @@ +PBKDF2 for OpenLDAP +======================= + +pw-pbkdf2.c provides PBKDF2 key derivation functions in OpenLDAP. + +Schemes: + + * {PBKDF2} - alias to {PBKDF2-SHA1} + * {PBKDF2-SHA1} + * {PBKDF2-SHA256} + * {PBKDF2-SHA512} + +# Requirements + + * OpenSSL 1.0.0 or later + +# Installations + +First, You need to configure and build OpenLDAP. + + $ cd <OPENLDAP_BUILD_DIR>/contrib/slapd-modules/passwd/ + $ git clone https://github.com/hamano/openldap-pbkdf2.git + $ cd openldap-pbkdf2/ + $ make + # make install + +# Configration + +In slapd.conf: + + moduleload pw-pbkdf2.so + +You can also tell OpenLDAP to use the schemes when processing LDAP +Password Modify Extended Operations, thanks to the password-hash +option in slapd.conf. For example: + + password-hash {PBKDF2} +or + password-hash {PBKDF2-SHA256} +or + password-hash {PBKDF2-SHA512} + +# Testing + +You can get hash to use slappasswd. + + $ slappasswd -o module-load=pw-pbkdf2.la -h {PBKDF2} -s secret + {PBKDF2}60000$Y6ZHtTTbeUgpIbIW0QDmDA$j/aU7jFKUSbH4UobNQDm9OEIwuw + +A quick way to test whether it's working is to customize the rootdn and +rootpw in slapd.conf, eg: + + rootdn "cn=Manager,dc=example,dc=com" + rootpw {PBKDF2}60000$Y6ZHtTTbeUgpIbIW0QDmDA$j/aU7jFKUSbH4UobNQDm9OEIwuw + +Then to test, run something like: + + $ ldapsearch -x -b "dc=example,dc=com" -D "cn=Manager,dc=example,dc=com" -w secret + +# Debugging +You can specify -DSLAPD_PBKDF2_DEBUG flag for debugging. + +# Message Format + + {PBKDF2}<Iteration>$<Adapted Base64 Salt>$<Adapted Base64 DK> + +# References + +* [RFC 2898 Password-Based Cryptography][^1] +[^1]: http://tools.ietf.org/html/rfc2898 + +* [PKCS #5 PBKDF2 Test Vectors][^2] +[^2]: http://tools.ietf.org/html/draft-josefsson-pbkdf2-test-vectors-06 + +* [RFC 2307 Using LDAP as a Network Information Service][^3] +[^3]: http://tools.ietf.org/html/rfc2307 + +* [Python Passlib][^4] +[^4]: http://pythonhosted.org/passlib/ + +* [Adapted Base64 Encoding][^5] +[^5]: http://pythonhosted.org/passlib/lib/passlib.utils.html#passlib.utils.ab64_encode + +# License +This work is part of OpenLDAP Software <http://www.openldap.org/>. + +Copyright 2009-2021 The OpenLDAP Foundation. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted only as authorized by the OpenLDAP +Public License. + +A copy of this license is available in the file LICENSE in the +top-level directory of the distribution or, alternatively, at +<http://www.OpenLDAP.org/license.html>. + +# ACKNOWLEDGEMENT +This work was initially developed by HAMANO Tsukasa <hamano@osstech.co.jp> diff --git a/contrib/slapd-modules/passwd/pbkdf2/pw-pbkdf2.c b/contrib/slapd-modules/passwd/pbkdf2/pw-pbkdf2.c new file mode 100644 index 0000000..a931179 --- /dev/null +++ b/contrib/slapd-modules/passwd/pbkdf2/pw-pbkdf2.c @@ -0,0 +1,451 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2009-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENT: + * This work was initially developed by HAMANO Tsukasa <hamano@osstech.co.jp> + */ + +#define _GNU_SOURCE + +#include "portable.h" +#include <ac/string.h> +#include "lber_pvt.h" +#include "lutil.h" +#include <stdio.h> +#include <stdlib.h> + +#ifdef HAVE_OPENSSL +#include <openssl/evp.h> +#elif HAVE_GNUTLS +#include <nettle/pbkdf2.h> +#include <nettle/hmac.h> +typedef void (*pbkdf2_hmac_update)(void *, unsigned, const uint8_t *); +typedef void (*pbkdf2_hmac_digest)(void *, unsigned, uint8_t *); +#else +#error Unsupported crypto backend. +#endif + +#define PBKDF2_ITERATION 10000 +#define PBKDF2_SALT_SIZE 16 +#define PBKDF2_SHA1_DK_SIZE 20 +#define PBKDF2_SHA256_DK_SIZE 32 +#define PBKDF2_SHA512_DK_SIZE 64 +#define PBKDF2_MAX_DK_SIZE 64 + +const struct berval pbkdf2_scheme = BER_BVC("{PBKDF2}"); +const struct berval pbkdf2_sha1_scheme = BER_BVC("{PBKDF2-SHA1}"); +const struct berval pbkdf2_sha256_scheme = BER_BVC("{PBKDF2-SHA256}"); +const struct berval pbkdf2_sha512_scheme = BER_BVC("{PBKDF2-SHA512}"); + +/* + * Converting base64 string to adapted base64 string. + * Adapted base64 encode is identical to general base64 encode except + * that it uses '.' instead of '+', and omits trailing padding '=' and + * whitepsace. + * see http://pythonhosted.org/passlib/lib/passlib.utils.html + * This is destructive function. + */ +static int b64_to_ab64(char *str) +{ + char *p = str; + do { + if(*p == '+'){ + *p = '.'; + } + if(*p == '='){ + *p = '\0'; + } + } while(*p++); + return 0; +} + +/* + * Converting adapted base64 string to base64 string. + * dstsize will require src length + 2, due to output string have + * potential to append "=" or "==". + * return -1 if few output buffer. + */ +static int ab64_to_b64(char *src, char *dst, size_t dstsize){ + int i; + char *p = src; + for(i=0; p[i] && p[i] != '$'; i++){ + if(i >= dstsize){ + dst[0] = '\0'; + return -1; + } + if(p[i] == '.'){ + dst[i] = '+'; + }else{ + dst[i] = p[i]; + } + } + for(;i%4;i++){ + if(i >= dstsize){ + dst[0] = '\0'; + return -1; + } + dst[i] = '='; + } + dst[i] = '\0'; + return 0; +} + +static int pbkdf2_format( + const struct berval *sc, + int iteration, + const struct berval *salt, + const struct berval *dk, + struct berval *msg) +{ + + int rc, msg_len; + char salt_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_SALT_SIZE) + 1]; + char dk_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_MAX_DK_SIZE) + 1]; + + rc = lutil_b64_ntop((unsigned char *)salt->bv_val, salt->bv_len, + salt_b64, sizeof(salt_b64)); + if(rc < 0){ + return LUTIL_PASSWD_ERR; + } + b64_to_ab64(salt_b64); + rc = lutil_b64_ntop((unsigned char *)dk->bv_val, dk->bv_len, + dk_b64, sizeof(dk_b64)); + if(rc < 0){ + return LUTIL_PASSWD_ERR; + } + b64_to_ab64(dk_b64); + msg_len = asprintf(&msg->bv_val, "%s%d$%s$%s", + sc->bv_val, iteration, + salt_b64, dk_b64); + if(msg_len < 0){ + msg->bv_len = 0; + return LUTIL_PASSWD_ERR; + } + + msg->bv_len = msg_len; + return LUTIL_PASSWD_OK; +} + +static int pbkdf2_encrypt( + const struct berval *scheme, + const struct berval *passwd, + struct berval *msg, + const char **text) +{ + unsigned char salt_value[PBKDF2_SALT_SIZE]; + struct berval salt; + unsigned char dk_value[PBKDF2_MAX_DK_SIZE]; + struct berval dk; + int iteration = PBKDF2_ITERATION; + int rc; +#ifdef HAVE_OPENSSL + const EVP_MD *md; +#elif HAVE_GNUTLS + struct hmac_sha1_ctx sha1_ctx; + struct hmac_sha256_ctx sha256_ctx; + struct hmac_sha512_ctx sha512_ctx; + void * current_ctx = NULL; + pbkdf2_hmac_update current_hmac_update = NULL; + pbkdf2_hmac_digest current_hmac_digest = NULL; +#endif + + salt.bv_val = (char *)salt_value; + salt.bv_len = sizeof(salt_value); + dk.bv_val = (char *)dk_value; + +#ifdef HAVE_OPENSSL + if(!ber_bvcmp(scheme, &pbkdf2_scheme)){ + dk.bv_len = PBKDF2_SHA1_DK_SIZE; + md = EVP_sha1(); + }else if(!ber_bvcmp(scheme, &pbkdf2_sha1_scheme)){ + dk.bv_len = PBKDF2_SHA1_DK_SIZE; + md = EVP_sha1(); + }else if(!ber_bvcmp(scheme, &pbkdf2_sha256_scheme)){ + dk.bv_len = PBKDF2_SHA256_DK_SIZE; + md = EVP_sha256(); + }else if(!ber_bvcmp(scheme, &pbkdf2_sha512_scheme)){ + dk.bv_len = PBKDF2_SHA512_DK_SIZE; + md = EVP_sha512(); + }else{ + return LUTIL_PASSWD_ERR; + } +#elif HAVE_GNUTLS + if(!ber_bvcmp(scheme, &pbkdf2_scheme)){ + dk.bv_len = PBKDF2_SHA1_DK_SIZE; + current_ctx = &sha1_ctx; + current_hmac_update = (pbkdf2_hmac_update) &hmac_sha1_update; + current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha1_digest; + hmac_sha1_set_key(current_ctx, passwd->bv_len, (const uint8_t *) passwd->bv_val); + }else if(!ber_bvcmp(scheme, &pbkdf2_sha1_scheme)){ + dk.bv_len = PBKDF2_SHA1_DK_SIZE; + current_ctx = &sha1_ctx; + current_hmac_update = (pbkdf2_hmac_update) &hmac_sha1_update; + current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha1_digest; + hmac_sha1_set_key(current_ctx, passwd->bv_len, (const uint8_t *) passwd->bv_val); + }else if(!ber_bvcmp(scheme, &pbkdf2_sha256_scheme)){ + dk.bv_len = PBKDF2_SHA256_DK_SIZE; + current_ctx = &sha256_ctx; + current_hmac_update = (pbkdf2_hmac_update) &hmac_sha256_update; + current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha256_digest; + hmac_sha256_set_key(current_ctx, passwd->bv_len, (const uint8_t *) passwd->bv_val); + }else if(!ber_bvcmp(scheme, &pbkdf2_sha512_scheme)){ + dk.bv_len = PBKDF2_SHA512_DK_SIZE; + current_ctx = &sha512_ctx; + current_hmac_update = (pbkdf2_hmac_update) &hmac_sha512_update; + current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha512_digest; + hmac_sha512_set_key(current_ctx, passwd->bv_len, (const uint8_t *) passwd->bv_val); + }else{ + return LUTIL_PASSWD_ERR; + } +#endif + + if(lutil_entropy((unsigned char *)salt.bv_val, salt.bv_len) < 0){ + return LUTIL_PASSWD_ERR; + } + +#ifdef HAVE_OPENSSL + if(!PKCS5_PBKDF2_HMAC(passwd->bv_val, passwd->bv_len, + (unsigned char *)salt.bv_val, salt.bv_len, + iteration, md, dk.bv_len, dk_value)){ + return LUTIL_PASSWD_ERR; + } +#elif HAVE_GNUTLS + PBKDF2(current_ctx, current_hmac_update, current_hmac_digest, + dk.bv_len, iteration, + salt.bv_len, (const uint8_t *) salt.bv_val, + dk.bv_len, dk_value); +#endif + +#ifdef SLAPD_PBKDF2_DEBUG + printf("Encrypt for %s\n", scheme->bv_val); + printf(" Password:\t%s\n", passwd->bv_val); + + printf(" Salt:\t\t"); + int i; + for(i=0; i<salt.bv_len; i++){ + printf("%02x", salt_value[i]); + } + printf("\n"); + printf(" Iteration:\t%d\n", iteration); + + printf(" DK:\t\t"); + for(i=0; i<dk.bv_len; i++){ + printf("%02x", dk_value[i]); + } + printf("\n"); +#endif + + rc = pbkdf2_format(scheme, iteration, &salt, &dk, msg); + +#ifdef SLAPD_PBKDF2_DEBUG + printf(" Output:\t%s\n", msg->bv_val); +#endif + + return rc; +} + +static int pbkdf2_check( + const struct berval *scheme, + const struct berval *passwd, + const struct berval *cred, + const char **text) +{ + int rc; + int iteration; + + /* salt_value require PBKDF2_SALT_SIZE + 1 in lutil_b64_pton. */ + unsigned char salt_value[PBKDF2_SALT_SIZE + 1]; + char salt_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_SALT_SIZE) + 1]; + /* dk_value require PBKDF2_MAX_DK_SIZE + 1 in lutil_b64_pton. */ + unsigned char dk_value[PBKDF2_MAX_DK_SIZE + 1]; + char dk_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_MAX_DK_SIZE) + 1]; + unsigned char input_dk_value[PBKDF2_MAX_DK_SIZE]; + size_t dk_len; +#ifdef HAVE_OPENSSL + const EVP_MD *md; +#elif HAVE_GNUTLS + struct hmac_sha1_ctx sha1_ctx; + struct hmac_sha256_ctx sha256_ctx; + struct hmac_sha512_ctx sha512_ctx; + void * current_ctx = NULL; + pbkdf2_hmac_update current_hmac_update = NULL; + pbkdf2_hmac_digest current_hmac_digest = NULL; +#endif + +#ifdef SLAPD_PBKDF2_DEBUG + printf("Checking for %s\n", scheme->bv_val); + printf(" Stored Value:\t%s\n", passwd->bv_val); + printf(" Input Cred:\t%s\n", cred->bv_val); +#endif + +#ifdef HAVE_OPENSSL + if(!ber_bvcmp(scheme, &pbkdf2_scheme)){ + dk_len = PBKDF2_SHA1_DK_SIZE; + md = EVP_sha1(); + }else if(!ber_bvcmp(scheme, &pbkdf2_sha1_scheme)){ + dk_len = PBKDF2_SHA1_DK_SIZE; + md = EVP_sha1(); + }else if(!ber_bvcmp(scheme, &pbkdf2_sha256_scheme)){ + dk_len = PBKDF2_SHA256_DK_SIZE; + md = EVP_sha256(); + }else if(!ber_bvcmp(scheme, &pbkdf2_sha512_scheme)){ + dk_len = PBKDF2_SHA512_DK_SIZE; + md = EVP_sha512(); + }else{ + return LUTIL_PASSWD_ERR; + } +#elif HAVE_GNUTLS + if(!ber_bvcmp(scheme, &pbkdf2_scheme)){ + dk_len = PBKDF2_SHA1_DK_SIZE; + current_ctx = &sha1_ctx; + current_hmac_update = (pbkdf2_hmac_update) &hmac_sha1_update; + current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha1_digest; + hmac_sha1_set_key(current_ctx, cred->bv_len, (const uint8_t *) cred->bv_val); + }else if(!ber_bvcmp(scheme, &pbkdf2_sha1_scheme)){ + dk_len = PBKDF2_SHA1_DK_SIZE; + current_ctx = &sha1_ctx; + current_hmac_update = (pbkdf2_hmac_update) &hmac_sha1_update; + current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha1_digest; + hmac_sha1_set_key(current_ctx, cred->bv_len, (const uint8_t *) cred->bv_val); + }else if(!ber_bvcmp(scheme, &pbkdf2_sha256_scheme)){ + dk_len = PBKDF2_SHA256_DK_SIZE; + current_ctx = &sha256_ctx; + current_hmac_update = (pbkdf2_hmac_update) &hmac_sha256_update; + current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha256_digest; + hmac_sha256_set_key(current_ctx, cred->bv_len, (const uint8_t *) cred->bv_val); + }else if(!ber_bvcmp(scheme, &pbkdf2_sha512_scheme)){ + dk_len = PBKDF2_SHA512_DK_SIZE; + current_ctx = &sha512_ctx; + current_hmac_update = (pbkdf2_hmac_update) &hmac_sha512_update; + current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha512_digest; + hmac_sha512_set_key(current_ctx, cred->bv_len, (const uint8_t *) cred->bv_val); + }else{ + return LUTIL_PASSWD_ERR; + } +#endif + + iteration = atoi(passwd->bv_val); + if(iteration < 1){ + return LUTIL_PASSWD_ERR; + } + + char *ptr; + ptr = strchr(passwd->bv_val, '$'); + if(!ptr){ + return LUTIL_PASSWD_ERR; + } + ptr++; /* skip '$' */ + rc = ab64_to_b64(ptr, salt_b64, sizeof(salt_b64)); + if(rc < 0){ + return LUTIL_PASSWD_ERR; + } + + ptr = strchr(ptr, '$'); + if(!ptr){ + return LUTIL_PASSWD_ERR; + } + ptr++; /* skip '$' */ + rc = ab64_to_b64(ptr, dk_b64, sizeof(dk_b64)); + if(rc < 0){ + return LUTIL_PASSWD_ERR; + } + + /* The targetsize require PBKDF2_SALT_SIZE + 1 in lutil_b64_pton. */ + rc = lutil_b64_pton(salt_b64, salt_value, PBKDF2_SALT_SIZE + 1); + if(rc < 0){ + return LUTIL_PASSWD_ERR; + } + + /* consistency check */ + if(rc != PBKDF2_SALT_SIZE){ + return LUTIL_PASSWD_ERR; + } + + /* The targetsize require PBKDF2_MAX_DK_SIZE + 1 in lutil_b64_pton. */ + rc = lutil_b64_pton(dk_b64, dk_value, sizeof(dk_value)); + if(rc < 0){ + return LUTIL_PASSWD_ERR; + } + + /* consistency check */ + if(rc != dk_len){ + return LUTIL_PASSWD_ERR; + } + +#ifdef HAVE_OPENSSL + if(!PKCS5_PBKDF2_HMAC(cred->bv_val, cred->bv_len, + salt_value, PBKDF2_SALT_SIZE, + iteration, md, dk_len, input_dk_value)){ + return LUTIL_PASSWD_ERR; + } +#elif HAVE_GNUTLS + PBKDF2(current_ctx, current_hmac_update, current_hmac_digest, + dk_len, iteration, + PBKDF2_SALT_SIZE, salt_value, + dk_len, input_dk_value); +#endif + + rc = memcmp(dk_value, input_dk_value, dk_len); +#ifdef SLAPD_PBKDF2_DEBUG + printf(" Iteration:\t%d\n", iteration); + printf(" Base64 Salt:\t%s\n", salt_b64); + printf(" Base64 DK:\t%s\n", dk_b64); + int i; + printf(" Stored Salt:\t"); + for(i=0; i<PBKDF2_SALT_SIZE; i++){ + printf("%02x", salt_value[i]); + } + printf("\n"); + + printf(" Stored DK:\t"); + for(i=0; i<dk_len; i++){ + printf("%02x", dk_value[i]); + } + printf("\n"); + + printf(" Input DK:\t"); + for(i=0; i<dk_len; i++){ + printf("%02x", input_dk_value[i]); + } + printf("\n"); + printf(" Result:\t%d\n", rc); +#endif + return rc?LUTIL_PASSWD_ERR:LUTIL_PASSWD_OK; +} + +int init_module(int argc, char *argv[]) { + int rc; + rc = lutil_passwd_add((struct berval *)&pbkdf2_scheme, + pbkdf2_check, pbkdf2_encrypt); + if(rc) return rc; + rc = lutil_passwd_add((struct berval *)&pbkdf2_sha1_scheme, + pbkdf2_check, pbkdf2_encrypt); + if(rc) return rc; + + rc = lutil_passwd_add((struct berval *)&pbkdf2_sha256_scheme, + pbkdf2_check, pbkdf2_encrypt); + if(rc) return rc; + + rc = lutil_passwd_add((struct berval *)&pbkdf2_sha512_scheme, + pbkdf2_check, pbkdf2_encrypt); + return rc; +} + +/* + * Local variables: + * indent-tabs-mode: t + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ diff --git a/contrib/slapd-modules/passwd/radius.c b/contrib/slapd-modules/passwd/radius.c new file mode 100644 index 0000000..af8a8ef --- /dev/null +++ b/contrib/slapd-modules/passwd/radius.c @@ -0,0 +1,149 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 1998-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ + +#include "portable.h" + +#include <stdio.h> + +#include <lber.h> +#include <lber_pvt.h> /* BER_BVC definition */ +#include "lutil.h" +#include <ldap_pvt_thread.h> +#include <ac/string.h> +#include <ac/unistd.h> + +#include <radlib.h> + +extern char *global_host; /* from slapd */ +static LUTIL_PASSWD_CHK_FUNC chk_radius; +static const struct berval scheme = BER_BVC("{RADIUS}"); +static char *config_filename; +static ldap_pvt_thread_mutex_t libradius_mutex; + +static int +chk_radius( + const struct berval *sc, + const struct berval *passwd, + const struct berval *cred, + const char **text ) +{ + unsigned int i; + int rc = LUTIL_PASSWD_ERR; + + struct rad_handle *h = NULL; + + for ( i = 0; i < cred->bv_len; i++ ) { + if ( cred->bv_val[ i ] == '\0' ) { + return LUTIL_PASSWD_ERR; /* NUL character in cred */ + } + } + + if ( cred->bv_val[ i ] != '\0' ) { + return LUTIL_PASSWD_ERR; /* cred must behave like a string */ + } + + for ( i = 0; i < passwd->bv_len; i++ ) { + if ( passwd->bv_val[ i ] == '\0' ) { + return LUTIL_PASSWD_ERR; /* NUL character in password */ + } + } + + if ( passwd->bv_val[ i ] != '\0' ) { + return LUTIL_PASSWD_ERR; /* passwd must behave like a string */ + } + + ldap_pvt_thread_mutex_lock( &libradius_mutex ); + + h = rad_auth_open(); + if ( h == NULL ) { + ldap_pvt_thread_mutex_unlock( &libradius_mutex ); + return LUTIL_PASSWD_ERR; + } + + if ( rad_config( h, config_filename ) != 0 ) { + goto done; + } + + if ( rad_create_request( h, RAD_ACCESS_REQUEST ) ) { + goto done; + } + + if ( rad_put_string( h, RAD_USER_NAME, passwd->bv_val ) != 0 ) { + goto done; + } + + if ( rad_put_string( h, RAD_USER_PASSWORD, cred->bv_val ) != 0 ) { + goto done; + } + + if ( rad_put_string( h, RAD_NAS_IDENTIFIER, global_host ) != 0 ) { + goto done; + } + + switch ( rad_send_request( h ) ) { + case RAD_ACCESS_ACCEPT: + rc = LUTIL_PASSWD_OK; + break; + + case RAD_ACCESS_REJECT: + rc = LUTIL_PASSWD_ERR; + break; + + case RAD_ACCESS_CHALLENGE: + rc = LUTIL_PASSWD_ERR; + break; + + case -1: + /* no valid response is received */ + break; + } + +done:; + rad_close( h ); + + ldap_pvt_thread_mutex_unlock( &libradius_mutex ); + return rc; +} + +int +term_module() +{ + return ldap_pvt_thread_mutex_destroy( &libradius_mutex ); +} + +int +init_module( int argc, char *argv[] ) +{ + int i; + + for ( i = 0; i < argc; i++ ) { + if ( strncasecmp( argv[ i ], "config=", STRLENOF( "config=" ) ) == 0 ) { + /* FIXME: what if multiple loads of same module? + * does it make sense (e.g. override an existing one)? */ + if ( config_filename == NULL ) { + config_filename = ber_strdup( &argv[ i ][ STRLENOF( "config=" ) ] ); + } + + } else { + fprintf( stderr, "init_module(radius): unknown arg#%d=\"%s\".\n", + i, argv[ i ] ); + return 1; + } + } + + ldap_pvt_thread_mutex_init( &libradius_mutex ); + + return lutil_passwd_add( (struct berval *)&scheme, chk_radius, NULL ); +} diff --git a/contrib/slapd-modules/passwd/sha2/Makefile b/contrib/slapd-modules/passwd/sha2/Makefile new file mode 100644 index 0000000..0abab68 --- /dev/null +++ b/contrib/slapd-modules/passwd/sha2/Makefile @@ -0,0 +1,47 @@ +# $OpenLDAP$ + +LDAP_SRC = ../../../.. +LDAP_BUILD = $(LDAP_SRC) +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +CC = gcc +OPT = -g -O2 -Wall +DEFS = +#DEFS = -DSLAPD_SHA2_DEBUG +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) + +PROGRAMS = pw-sha2.la +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +pw-sha2.la: slapd-sha2.lo sha2.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + diff --git a/contrib/slapd-modules/passwd/sha2/README b/contrib/slapd-modules/passwd/sha2/README new file mode 100644 index 0000000..10a2537 --- /dev/null +++ b/contrib/slapd-modules/passwd/sha2/README @@ -0,0 +1,144 @@ +SHA-2 OpenLDAP support +---------------------- + +slapd-sha2.c provides support for SSHA-512, SSHA-384, SSHA-256, +SHA-512, SHA-384 and SHA-256 hashed passwords in OpenLDAP. For +instance, one could have the LDAP attribute: + +userPassword: {SHA512}vSsar3708Jvp9Szi2NWZZ02Bqp1qRCFpbcTZPdBhnWgs5WtNZKnvCXdhztmeD2cmW192CF5bDufKRpayrW/isg== + +or: + +userPassword: {SHA384}WKd1ukESvjAFrkQHznV9iP2nHUBJe7gCbsrFTU4//HIyzo3jq1rLMK45dg/ufFPt + +or: + +userPassword: {SHA256}K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols= + +all of which encode the password 'secret'. + + +Building +-------- + +1) Customize the OPENLDAP variable in Makefile to point to the OpenLDAP +source root. + +For initial testing you might also want to edit DEFS to define +SLAPD_SHA2_DEBUG, which enables logging to stderr (don't leave this on +in production, as it prints passwords in cleartext). + +2) Run 'make' to produce slapd-sha2.so + +3) Copy slapd-sha2.so somewhere permanent. + +4) Edit your slapd.conf (eg. /etc/ldap/slapd.conf), and add: + +moduleload ...path/to/slapd-sha2.so + +5) Restart slapd. + + +Configuring +----------- + +The {SSHA256}, {SSHA384}, {SSHA512}, {SSHA256}, {SHA384} and {SHA512} +password schemes should now be recognised. + +You can also tell OpenLDAP to use one of these new schemes when processing LDAP +Password Modify Extended Operations, thanks to the password-hash option in +slapd.conf. For example: + +password-hash {SSHA512} + + +Testing +------- + +A quick way to test whether it's working is to customize the rootdn and +rootpw in slapd.conf, eg: + +rootdn "cn=admin,dc=example,dc=com" +# This encrypts the string 'secret' + +rootpw {SHA256}K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols= + +Then to test, run something like: + +ldapsearch -b "dc=example,dc=com" -D "cn=admin,dc=example,dc=com" -x -w secret + + +-- Test hashes: + +Test hashes can be generated with openssl: + +$ echo -n "secret" | openssl dgst -sha256 -binary | openssl enc -base64 +K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols= +$ echo -n "secret" | openssl dgst -sha384 -binary | openssl enc -base64 +WKd1ukESvjAFrkQHznV9iP2nHUBJe7gCbsrFTU4//HIyzo3jq1rLMK45dg/ufFPt +$ echo -n "secret" | openssl dgst -sha512 -binary | openssl enc -base64 +vSsar3708Jvp9Szi2NWZZ02Bqp1qRCFpbcTZPdBhnWgs5WtNZKnvCXdhztmeD2cm +W192CF5bDufKRpayrW/isg== + +(join those lines up to form the full hash) + + + +Alternatively we could modify an existing user's password with +ldappasswd, and then test binding as that user: + +$ ldappasswd -D "cn=admin,dc=example,dc=com" -x -W -S uid=jturner,ou=People,dc=example,dc=com +New password: secret +Re-enter new password: secret +Enter LDAP Password: <cn=admin's password> + +$ ldapsearch -b "dc=example,dc=com" -D "uid=jturner,ou=People,dc=example,dc=com" -x -w secret + + +Debugging (SHA-512, SHA-384 and SHA-256 only) +--------------------------------------------- + +To see what's going on, recompile with SLAPD_SHA2_DEBUG (use the +commented-out DEFS in Makefile), and then run slapd from the console +to see stderr: + +$ sudo /etc/init.d/slapd stop +Stopping OpenLDAP: slapd. +$ sudo /usr/sbin/slapd -f /etc/ldap/slapd.conf -h ldap://localhost:389 -d stats +@(#) $OpenLDAP$ + buildd@palmer:/build/buildd/openldap2.3-2.4.9/debian/build/servers/slapd +slapd starting +... +Validating password + Hash scheme: {SHA256} + Password to validate: secret + Password hash: K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols= + Stored password hash: K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols= + Result: match +conn=0 op=0 BIND dn="cn=admin,dc=example,dc=com" mech=SIMPLE ssf=0 +conn=0 op=0 RESULT tag=97 err=0 text= +conn=0 op=1 SRCH base="dc=example,dc=com" scope=2 deref=0 filter="(objectClass=*)" +conn=0 fd=12 closed (connection lost) + +--- + +This work is part of OpenLDAP Software <http://www.openldap.org/>. + +Copyright 2009-2021 The OpenLDAP Foundation. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted only as authorized by the OpenLDAP +Public License. + +A copy of this license is available in the file LICENSE in the +top-level directory of the distribution or, alternatively, at +<http://www.OpenLDAP.org/license.html>. + +--- + +ACKNOWLEDGEMENT: +This work was initially developed by Jeff Turner for inclusion in +OpenLDAP Software, based upon the SHA-2 implementation independently +developed by Aaron Gifford. + diff --git a/contrib/slapd-modules/passwd/sha2/sha2.c b/contrib/slapd-modules/passwd/sha2/sha2.c new file mode 100644 index 0000000..808da10 --- /dev/null +++ b/contrib/slapd-modules/passwd/sha2/sha2.c @@ -0,0 +1,1070 @@ +/* $OpenLDAP$ */ +/* + * FILE: sha2.c + * AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/ + * + * Copyright (c) 2000-2001, Aaron D. Gifford + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: sha2.c,v 1.1 2001/11/08 00:01:51 adg Exp adg $ + */ + +#include <string.h> /* memcpy()/memset() or bcopy()/bzero() */ +#include <assert.h> /* assert() */ +#include "sha2.h" + +/* + * ASSERT NOTE: + * Some sanity checking code is included using assert(). On my FreeBSD + * system, this additional code can be removed by compiling with NDEBUG + * defined. Check your own systems manpage on assert() to see how to + * compile WITHOUT the sanity checking code on your system. + * + * UNROLLED TRANSFORM LOOP NOTE: + * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform + * loop version for the hash transform rounds (defined using macros + * later in this file). Either define on the command line, for example: + * + * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c + * + * or define below: + * + * #define SHA2_UNROLL_TRANSFORM + * + */ + + +/*** SHA-256/384/512 Machine Architecture Definitions *****************/ +/* + * BYTE_ORDER NOTE: + * + * Please make sure that your system defines BYTE_ORDER. If your + * architecture is little-endian, make sure it also defines + * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are + * equivilent. + * + * If your system does not define the above, then you can do so by + * hand like this: + * + * #define LITTLE_ENDIAN 1234 + * #define BIG_ENDIAN 4321 + * + * And for little-endian machines, add: + * + * #define BYTE_ORDER LITTLE_ENDIAN + * + * Or for big-endian machines: + * + * #define BYTE_ORDER BIG_ENDIAN + * + * The FreeBSD machine this was written on defines BYTE_ORDER + * appropriately by including <sys/types.h> (which in turn includes + * <machine/endian.h> where the appropriate definitions are actually + * made). + */ +#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN) +#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN +#endif + +/* + * Define the followingsha2_* types to types of the correct length on + * the native archtecture. Most BSD systems and Linux define u_intXX_t + * types. Machines with very recent ANSI C headers, can use the + * uintXX_t definintions from inttypes.h by defining SHA2_USE_INTTYPES_H + * during compile or in the sha.h header file. + * + * Machines that support neither u_intXX_t nor inttypes.h's uintXX_t + * will need to define these three typedefs below (and the appropriate + * ones in sha.h too) by hand according to their system architecture. + * + * Thank you, Jun-ichiro itojun Hagino, for suggesting using u_intXX_t + * types and pointing out recent ANSI C support for uintXX_t in inttypes.h. + */ +#ifdef SHA2_USE_INTTYPES_H + +typedef uint8_t sha2_byte; /* Exactly 1 byte */ +typedef uint32_t sha2_word32; /* Exactly 4 bytes */ +typedef uint64_t sha2_word64; /* Exactly 8 bytes */ + +#else /* SHA2_USE_INTTYPES_H */ + +typedef u_int8_t sha2_byte; /* Exactly 1 byte */ +typedef u_int32_t sha2_word32; /* Exactly 4 bytes */ +typedef u_int64_t sha2_word64; /* Exactly 8 bytes */ + +#endif /* SHA2_USE_INTTYPES_H */ + + +/*** SHA-256/384/512 Various Length Definitions ***********************/ +/* NOTE: Most of these are in sha2.h */ +#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) +#define SHA384_SHORT_BLOCK_LENGTH (SHA384_BLOCK_LENGTH - 16) +#define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16) + + +/*** ENDIAN REVERSAL MACROS *******************************************/ +#if BYTE_ORDER == LITTLE_ENDIAN +#define REVERSE32(w,x) { \ + sha2_word32 tmp = (w); \ + tmp = (tmp >> 16) | (tmp << 16); \ + (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ +} +#define REVERSE64(w,x) { \ + sha2_word64 tmp = (w); \ + tmp = (tmp >> 32) | (tmp << 32); \ + tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \ + ((tmp & 0x00ff00ff00ff00ffULL) << 8); \ + (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \ + ((tmp & 0x0000ffff0000ffffULL) << 16); \ +} +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +/* + * Macro for incrementally adding the unsigned 64-bit integer n to the + * unsigned 128-bit integer (represented using a two-element array of + * 64-bit words): + */ +#define ADDINC128(w,n) { \ + (w)[0] += (sha2_word64)(n); \ + if ((w)[0] < (n)) { \ + (w)[1]++; \ + } \ +} + +/* + * Macros for copying blocks of memory and for zeroing out ranges + * of memory. Using these macros makes it easy to switch from + * using memset()/memcpy() and using bzero()/bcopy(). + * + * Please define either SHA2_USE_MEMSET_MEMCPY or define + * SHA2_USE_BZERO_BCOPY depending on which function set you + * choose to use: + */ +#if !defined(SHA2_USE_MEMSET_MEMCPY) && !defined(SHA2_USE_BZERO_BCOPY) +/* Default to memset()/memcpy() if no option is specified */ +#define SHA2_USE_MEMSET_MEMCPY 1 +#endif +#if defined(SHA2_USE_MEMSET_MEMCPY) && defined(SHA2_USE_BZERO_BCOPY) +/* Abort with an error if BOTH options are defined */ +#error Define either SHA2_USE_MEMSET_MEMCPY or SHA2_USE_BZERO_BCOPY, not both! +#endif + +#ifdef SHA2_USE_MEMSET_MEMCPY +#define MEMSET_BZERO(p,l) memset((p), 0, (l)) +#define MEMCPY_BCOPY(d,s,l) memcpy((d), (s), (l)) +#endif +#ifdef SHA2_USE_BZERO_BCOPY +#define MEMSET_BZERO(p,l) bzero((p), (l)) +#define MEMCPY_BCOPY(d,s,l) bcopy((s), (d), (l)) +#endif + + +/*** THE SIX LOGICAL FUNCTIONS ****************************************/ +/* + * Bit shifting and rotation (used by the six SHA-XYZ logical functions: + * + * NOTE: The naming of R and S appears backwards here (R is a SHIFT and + * S is a ROTATION) because the SHA-256/384/512 description document + * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this + * same "backwards" definition. + */ +/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ +#define R(b,x) ((x) >> (b)) +/* 32-bit Rotate-right (used in SHA-256): */ +#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) +/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ +#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) + +/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */ +#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) +#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +/* Four of six logical functions used in SHA-256: */ +#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x))) +#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x))) +#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x))) +#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x))) + +/* Four of six logical functions used in SHA-384 and SHA-512: */ +#define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x))) +#define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x))) +#define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x))) +#define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x))) + +/*** INTERNAL FUNCTION PROTOTYPES *************************************/ +/* NOTE: These should not be accessed directly from outside this + * library -- they are intended for private internal visibility/use + * only. + */ +static void SHA512_Last(SHA512_CTX*); +static void SHA256_Transform(SHA256_CTX*, const sha2_word32*); +static void SHA512_Transform(SHA512_CTX*, const sha2_word64*); + + +/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ +/* Hash constant words K for SHA-256: */ +const static sha2_word32 K256[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, + 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, + 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, + 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, + 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; + +/* Initial hash value H for SHA-256: */ +const static sha2_word32 sha256_initial_hash_value[8] = { + 0x6a09e667UL, + 0xbb67ae85UL, + 0x3c6ef372UL, + 0xa54ff53aUL, + 0x510e527fUL, + 0x9b05688cUL, + 0x1f83d9abUL, + 0x5be0cd19UL +}; + +/* Hash constant words K for SHA-384 and SHA-512: */ +const static sha2_word64 K512[80] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, + 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, + 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, + 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, + 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, + 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, + 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, + 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, + 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, + 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, + 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, + 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, + 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, + 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, + 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, + 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, + 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, + 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, + 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, + 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, + 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, + 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, + 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, + 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, + 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL +}; + +/* Initial hash value H for SHA-384 */ +const static sha2_word64 sha384_initial_hash_value[8] = { + 0xcbbb9d5dc1059ed8ULL, + 0x629a292a367cd507ULL, + 0x9159015a3070dd17ULL, + 0x152fecd8f70e5939ULL, + 0x67332667ffc00b31ULL, + 0x8eb44a8768581511ULL, + 0xdb0c2e0d64f98fa7ULL, + 0x47b5481dbefa4fa4ULL +}; + +/* Initial hash value H for SHA-512 */ +const static sha2_word64 sha512_initial_hash_value[8] = { + 0x6a09e667f3bcc908ULL, + 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, + 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, + 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, + 0x5be0cd19137e2179ULL +}; + +/* + * Constant used by SHA256/384/512_End() functions for converting the + * digest to a readable hexadecimal character string: + */ +static const char *sha2_hex_digits = "0123456789abcdef"; + + +/*** SHA-256: *********************************************************/ +void SHA256_Init(SHA256_CTX* context) { + if (context == (SHA256_CTX*)0) { + return; + } + MEMCPY_BCOPY(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH); + MEMSET_BZERO(context->buffer, SHA256_BLOCK_LENGTH); + context->bitcount = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-256 round macros: */ + +#if BYTE_ORDER == LITTLE_ENDIAN + +#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ + REVERSE32(*data++, W256[j]); \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ + K256[j] + W256[j]; \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + + +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ + K256[j] + (W256[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND256(a,b,c,d,e,f,g,h) \ + s0 = W256[(j+1)&0x0f]; \ + s0 = sigma0_256(s0); \ + s1 = W256[(j+14)&0x0f]; \ + s1 = sigma1_256(s1); \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \ + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { + sha2_word32 a, b, c, d, e, f, g, h, s0, s1; + sha2_word32 T1, *W256; + int j; + + W256 = (sha2_word32*)context->buffer; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + /* Rounds 0 to 15 (unrolled): */ + ROUND256_0_TO_15(a,b,c,d,e,f,g,h); + ROUND256_0_TO_15(h,a,b,c,d,e,f,g); + ROUND256_0_TO_15(g,h,a,b,c,d,e,f); + ROUND256_0_TO_15(f,g,h,a,b,c,d,e); + ROUND256_0_TO_15(e,f,g,h,a,b,c,d); + ROUND256_0_TO_15(d,e,f,g,h,a,b,c); + ROUND256_0_TO_15(c,d,e,f,g,h,a,b); + ROUND256_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds to 64: */ + do { + ROUND256(a,b,c,d,e,f,g,h); + ROUND256(h,a,b,c,d,e,f,g); + ROUND256(g,h,a,b,c,d,e,f); + ROUND256(f,g,h,a,b,c,d,e); + ROUND256(e,f,g,h,a,b,c,d); + ROUND256(d,e,f,g,h,a,b,c); + ROUND256(c,d,e,f,g,h,a,b); + ROUND256(b,c,d,e,f,g,h,a); + } while (j < 64); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { + sha2_word32 a, b, c, d, e, f, g, h, s0, s1; + sha2_word32 T1, T2, *W256; + int j; + + W256 = (sha2_word32*)context->buffer; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { +#if BYTE_ORDER == LITTLE_ENDIAN + /* Copy data while converting to host byte order */ + REVERSE32(*data++,W256[j]); + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + /* Apply the SHA-256 compression function to update a..h with copy */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++); +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W256[(j+1)&0x0f]; + s0 = sigma0_256(s0); + s1 = W256[(j+14)&0x0f]; + s1 = sigma1_256(s1); + + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 64); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { + unsigned int freespace, usedspace; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + assert(context != (SHA256_CTX*)0 && data != (sha2_byte*)0); + + usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA256_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); + context->bitcount += freespace << 3; + len -= freespace; + data += freespace; + SHA256_Transform(context, (sha2_word32*)context->buffer); + } else { + /* The buffer is not yet full */ + MEMCPY_BCOPY(&context->buffer[usedspace], data, len); + context->bitcount += len << 3; + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA256_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + SHA256_Transform(context, (sha2_word32*)data); + context->bitcount += SHA256_BLOCK_LENGTH << 3; + len -= SHA256_BLOCK_LENGTH; + data += SHA256_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + MEMCPY_BCOPY(context->buffer, data, len); + context->bitcount += len << 3; + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void SHA256_Final(sha2_byte digest[], SHA256_CTX* context) { + sha2_word32 *d = (sha2_word32*)digest; + sha2_word64 *p; + unsigned int usedspace; + + /* Sanity check: */ + assert(context != (SHA256_CTX*)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + REVERSE64(context->bitcount,context->bitcount); +#endif + if (usedspace > 0) { + /* Begin padding with a 1 bit: */ + context->buffer[usedspace++] = 0x80; + + if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + MEMSET_BZERO(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < SHA256_BLOCK_LENGTH) { + MEMSET_BZERO(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace); + } + /* Do second-to-last transform: */ + SHA256_Transform(context, (sha2_word32*)context->buffer); + + /* And set-up for the last transform: */ + MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); + } + } else { + /* Set-up for the last transform: */ + MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); + + /* Begin padding with a 1 bit: */ + *context->buffer = 0x80; + } + /* Set the bit count: */ + p = (sha2_word64 *)&context->buffer[SHA256_SHORT_BLOCK_LENGTH]; + *p = context->bitcount; + + /* Final transform: */ + SHA256_Transform(context, (sha2_word32*)context->buffer); + +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 8; j++) { + REVERSE32(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + MEMCPY_BCOPY(d, context->state, SHA256_DIGEST_LENGTH); +#endif + } + + /* Clean up state data: */ + MEMSET_BZERO(context, sizeof(*context)); + usedspace = 0; +} + +char *SHA256_End(SHA256_CTX* context, char buffer[]) { + sha2_byte digest[SHA256_DIGEST_LENGTH], *d = digest; + int i; + + /* Sanity check: */ + assert(context != (SHA256_CTX*)0); + + if (buffer != (char*)0) { + SHA256_Final(digest, context); + + for (i = 0; i < SHA256_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + MEMSET_BZERO(context, sizeof(*context)); + } + MEMSET_BZERO(digest, SHA256_DIGEST_LENGTH); + return buffer; +} + +char* SHA256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) { + SHA256_CTX context; + + SHA256_Init(&context); + SHA256_Update(&context, data, len); + return SHA256_End(&context, digest); +} + + +/*** SHA-512: *********************************************************/ +void SHA512_Init(SHA512_CTX* context) { + if (context == (SHA512_CTX*)0) { + return; + } + MEMCPY_BCOPY(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH); + MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-512 round macros: */ +#if BYTE_ORDER == LITTLE_ENDIAN + +#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ + REVERSE64(*data++, W512[j]); \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ + K512[j] + W512[j]; \ + (d) += T1, \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \ + j++ + + +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ + K512[j] + (W512[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ + +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND512(a,b,c,d,e,f,g,h) \ + s0 = W512[(j+1)&0x0f]; \ + s0 = sigma0_512(s0); \ + s1 = W512[(j+14)&0x0f]; \ + s1 = sigma1_512(s1); \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \ + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ + +void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { + sha2_word64 a, b, c, d, e, f, g, h, s0, s1; + sha2_word64 T1, *W512 = (sha2_word64*)context->buffer; + int j; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + ROUND512_0_TO_15(a,b,c,d,e,f,g,h); + ROUND512_0_TO_15(h,a,b,c,d,e,f,g); + ROUND512_0_TO_15(g,h,a,b,c,d,e,f); + ROUND512_0_TO_15(f,g,h,a,b,c,d,e); + ROUND512_0_TO_15(e,f,g,h,a,b,c,d); + ROUND512_0_TO_15(d,e,f,g,h,a,b,c); + ROUND512_0_TO_15(c,d,e,f,g,h,a,b); + ROUND512_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds up to 79: */ + do { + ROUND512(a,b,c,d,e,f,g,h); + ROUND512(h,a,b,c,d,e,f,g); + ROUND512(g,h,a,b,c,d,e,f); + ROUND512(f,g,h,a,b,c,d,e); + ROUND512(e,f,g,h,a,b,c,d); + ROUND512(d,e,f,g,h,a,b,c); + ROUND512(c,d,e,f,g,h,a,b); + ROUND512(b,c,d,e,f,g,h,a); + } while (j < 80); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { + sha2_word64 a, b, c, d, e, f, g, h, s0, s1; + sha2_word64 T1, T2, *W512 = (sha2_word64*)context->buffer; + int j; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + REVERSE64(*data++, W512[j]); + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j]; +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + /* Apply the SHA-512 compression function to update a..h with copy */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++); +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W512[(j+1)&0x0f]; + s0 = sigma0_512(s0); + s1 = W512[(j+14)&0x0f]; + s1 = sigma1_512(s1); + + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 80); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void SHA512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { + unsigned int freespace, usedspace; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + assert(context != (SHA512_CTX*)0 && data != (sha2_byte*)0); + + usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA512_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); + ADDINC128(context->bitcount, freespace << 3); + len -= freespace; + data += freespace; + SHA512_Transform(context, (sha2_word64*)context->buffer); + } else { + /* The buffer is not yet full */ + MEMCPY_BCOPY(&context->buffer[usedspace], data, len); + ADDINC128(context->bitcount, len << 3); + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA512_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + SHA512_Transform(context, (sha2_word64*)data); + ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); + len -= SHA512_BLOCK_LENGTH; + data += SHA512_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + MEMCPY_BCOPY(context->buffer, data, len); + ADDINC128(context->bitcount, len << 3); + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void SHA512_Last(SHA512_CTX* context) { + sha2_word64 *p; + unsigned int usedspace; + + usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + REVERSE64(context->bitcount[0],context->bitcount[0]); + REVERSE64(context->bitcount[1],context->bitcount[1]); +#endif + if (usedspace > 0) { + /* Begin padding with a 1 bit: */ + context->buffer[usedspace++] = 0x80; + + if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + MEMSET_BZERO(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < SHA512_BLOCK_LENGTH) { + MEMSET_BZERO(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace); + } + /* Do second-to-last transform: */ + SHA512_Transform(context, (sha2_word64*)context->buffer); + + /* And set-up for the last transform: */ + MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH - 2); + } + } else { + /* Prepare for final transform: */ + MEMSET_BZERO(context->buffer, SHA512_SHORT_BLOCK_LENGTH); + + /* Begin padding with a 1 bit: */ + *context->buffer = 0x80; + } + /* Store the length of input data (in bits): */ + p = (sha2_word64 *)&context->buffer[SHA512_SHORT_BLOCK_LENGTH]; + p[0] = context->bitcount[1]; + p[1] = context->bitcount[0]; + + /* Final transform: */ + SHA512_Transform(context, (sha2_word64*)context->buffer); +} + +void SHA512_Final(sha2_byte digest[], SHA512_CTX* context) { + sha2_word64 *d = (sha2_word64*)digest; + + /* Sanity check: */ + assert(context != (SHA512_CTX*)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + SHA512_Last(context); + + /* Save the hash data for output: */ +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 8; j++) { + REVERSE64(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + MEMCPY_BCOPY(d, context->state, SHA512_DIGEST_LENGTH); +#endif + } + + /* Zero out state data */ + MEMSET_BZERO(context, sizeof(*context)); +} + +char *SHA512_End(SHA512_CTX* context, char buffer[]) { + sha2_byte digest[SHA512_DIGEST_LENGTH], *d = digest; + int i; + + /* Sanity check: */ + assert(context != (SHA512_CTX*)0); + + if (buffer != (char*)0) { + SHA512_Final(digest, context); + + for (i = 0; i < SHA512_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + MEMSET_BZERO(context, sizeof(*context)); + } + MEMSET_BZERO(digest, SHA512_DIGEST_LENGTH); + return buffer; +} + +char* SHA512_Data(const sha2_byte* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) { + SHA512_CTX context; + + SHA512_Init(&context); + SHA512_Update(&context, data, len); + return SHA512_End(&context, digest); +} + + +/*** SHA-384: *********************************************************/ +void SHA384_Init(SHA384_CTX* context) { + if (context == (SHA384_CTX*)0) { + return; + } + MEMCPY_BCOPY(context->state, sha384_initial_hash_value, SHA512_DIGEST_LENGTH); + MEMSET_BZERO(context->buffer, SHA384_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; +} + +void SHA384_Update(SHA384_CTX* context, const sha2_byte* data, size_t len) { + SHA512_Update((SHA512_CTX*)context, data, len); +} + +void SHA384_Final(sha2_byte digest[], SHA384_CTX* context) { + sha2_word64 *d = (sha2_word64*)digest; + + /* Sanity check: */ + assert(context != (SHA384_CTX*)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + SHA512_Last((SHA512_CTX*)context); + + /* Save the hash data for output: */ +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 6; j++) { + REVERSE64(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + MEMCPY_BCOPY(d, context->state, SHA384_DIGEST_LENGTH); +#endif + } + + /* Zero out state data */ + MEMSET_BZERO(context, sizeof(*context)); +} + +char *SHA384_End(SHA384_CTX* context, char buffer[]) { + sha2_byte digest[SHA384_DIGEST_LENGTH], *d = digest; + int i; + + /* Sanity check: */ + assert(context != (SHA384_CTX*)0); + + if (buffer != (char*)0) { + SHA384_Final(digest, context); + + for (i = 0; i < SHA384_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + MEMSET_BZERO(context, sizeof(*context)); + } + MEMSET_BZERO(digest, SHA384_DIGEST_LENGTH); + return buffer; +} + +char* SHA384_Data(const sha2_byte* data, size_t len, char digest[SHA384_DIGEST_STRING_LENGTH]) { + SHA384_CTX context; + + SHA384_Init(&context); + SHA384_Update(&context, data, len); + return SHA384_End(&context, digest); +} + diff --git a/contrib/slapd-modules/passwd/sha2/sha2.h b/contrib/slapd-modules/passwd/sha2/sha2.h new file mode 100644 index 0000000..7fff142 --- /dev/null +++ b/contrib/slapd-modules/passwd/sha2/sha2.h @@ -0,0 +1,236 @@ +/* $OpenLDAP$ */ +/* + * FILE: sha2.h + * AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/ + * + * Copyright (c) 2000-2001, Aaron D. Gifford + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $ + */ + +#ifndef __SHA2_H__ +#define __SHA2_H__ + +#include "portable.h" + +#ifdef HAVE_INTTYPES_H +# define SHA2_USE_INTTYPES_H 1 +#endif + +#ifndef LITTLE_ENDIAN +# define LITTLE_ENDIAN 1234 +#endif +#ifndef BIG_ENDIAN +# define BIG_ENDIAN 4321 +#endif +#ifndef BYTE_ORDER +# ifdef WORDS_BIGENDIAN +# define BYTE_ORDER BIG_ENDIAN +# else +# define BYTE_ORDER LITTLE_ENDIAN +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Import u_intXX_t size_t type definitions from system headers. You + * may need to change this, or define these things yourself in this + * file. + */ +#include <sys/types.h> + +#ifdef SHA2_USE_INTTYPES_H + +#include <inttypes.h> + +#endif /* SHA2_USE_INTTYPES_H */ + + +/*** SHA-256/384/512 Various Length Definitions ***********************/ +#define SHA256_BLOCK_LENGTH 64 +#define SHA256_DIGEST_LENGTH 32 +#define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) +#define SHA384_BLOCK_LENGTH 128 +#define SHA384_DIGEST_LENGTH 48 +#define SHA384_DIGEST_STRING_LENGTH (SHA384_DIGEST_LENGTH * 2 + 1) +#define SHA512_BLOCK_LENGTH 128 +#define SHA512_DIGEST_LENGTH 64 +#define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) + + +/*** SHA-256/384/512 Context Structures *******************************/ +/* NOTE: If your architecture does not define either u_intXX_t types or + * uintXX_t (from inttypes.h), you may need to define things by hand + * for your system: + */ +#if 0 +typedef unsigned char u_int8_t; /* 1-byte (8-bits) */ +typedef unsigned int u_int32_t; /* 4-bytes (32-bits) */ +typedef unsigned long long u_int64_t; /* 8-bytes (64-bits) */ +#endif +/* + * Most BSD systems already define u_intXX_t types, as does Linux. + * Some systems, however, like Compaq's Tru64 Unix instead can use + * uintXX_t types defined by very recent ANSI C standards and included + * in the file: + * + * #include <inttypes.h> + * + * If you choose to use <inttypes.h> then please define: + * + * #define SHA2_USE_INTTYPES_H + * + * Or on the command line during compile: + * + * cc -DSHA2_USE_INTTYPES_H ... + */ +#ifdef SHA2_USE_INTTYPES_H + +typedef struct _SHA256_CTX { + uint32_t state[8]; + uint64_t bitcount; + uint8_t buffer[SHA256_BLOCK_LENGTH]; +} SHA256_CTX; +typedef struct _SHA512_CTX { + uint64_t state[8]; + uint64_t bitcount[2]; + uint8_t buffer[SHA512_BLOCK_LENGTH]; +} SHA512_CTX; + +#else /* SHA2_USE_INTTYPES_H */ + +typedef struct _SHA256_CTX { + u_int32_t state[8]; + u_int64_t bitcount; + u_int8_t buffer[SHA256_BLOCK_LENGTH]; +} SHA256_CTX; +typedef struct _SHA512_CTX { + u_int64_t state[8]; + u_int64_t bitcount[2]; + u_int8_t buffer[SHA512_BLOCK_LENGTH]; +} SHA512_CTX; + +#endif /* SHA2_USE_INTTYPES_H */ + +typedef SHA512_CTX SHA384_CTX; + + +/*** SHA-256/384/512 Function Prototypes ******************************/ +/* avoid symbol clash with other crypto libs */ +#define SHA256_Init pw_SHA256_Init +#define SHA256_Update pw_SHA256_Update +#define SHA256_Final pw_SHA256_Final +#define SHA256_End pw_SHA256_End +#define SHA256_Data pw_SHA256_Data + +#define SHA384_Init pw_SHA384_Init +#define SHA384_Update pw_SHA384_Update +#define SHA384_Final pw_SHA384_Final +#define SHA384_End pw_SHA384_End +#define SHA384_Data pw_SHA384_Data + +#define SHA512_Init pw_SHA512_Init +#define SHA512_Update pw_SHA512_Update +#define SHA512_Final pw_SHA512_Final +#define SHA512_End pw_SHA512_End +#define SHA512_Data pw_SHA512_Data + +#ifndef NOPROTO +#ifdef SHA2_USE_INTTYPES_H + +void SHA256_Init(SHA256_CTX *); +void SHA256_Update(SHA256_CTX*, const uint8_t*, size_t); +void SHA256_Final(uint8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*); +char* SHA256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]); +char* SHA256_Data(const uint8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]); + +void SHA384_Init(SHA384_CTX*); +void SHA384_Update(SHA384_CTX*, const uint8_t*, size_t); +void SHA384_Final(uint8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*); +char* SHA384_End(SHA384_CTX*, char[SHA384_DIGEST_STRING_LENGTH]); +char* SHA384_Data(const uint8_t*, size_t, char[SHA384_DIGEST_STRING_LENGTH]); + +void SHA512_Init(SHA512_CTX*); +void SHA512_Update(SHA512_CTX*, const uint8_t*, size_t); +void SHA512_Final(uint8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*); +char* SHA512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]); +char* SHA512_Data(const uint8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]); + +#else /* SHA2_USE_INTTYPES_H */ + +void SHA256_Init(SHA256_CTX *); +void SHA256_Update(SHA256_CTX*, const u_int8_t*, size_t); +void SHA256_Final(u_int8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*); +char* SHA256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]); +char* SHA256_Data(const u_int8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]); + +void SHA384_Init(SHA384_CTX*); +void SHA384_Update(SHA384_CTX*, const u_int8_t*, size_t); +void SHA384_Final(u_int8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*); +char* SHA384_End(SHA384_CTX*, char[SHA384_DIGEST_STRING_LENGTH]); +char* SHA384_Data(const u_int8_t*, size_t, char[SHA384_DIGEST_STRING_LENGTH]); + +void SHA512_Init(SHA512_CTX*); +void SHA512_Update(SHA512_CTX*, const u_int8_t*, size_t); +void SHA512_Final(u_int8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*); +char* SHA512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]); +char* SHA512_Data(const u_int8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]); + +#endif /* SHA2_USE_INTTYPES_H */ + +#else /* NOPROTO */ + +void SHA256_Init(); +void SHA256_Update(); +void SHA256_Final(); +char* SHA256_End(); +char* SHA256_Data(); + +void SHA384_Init(); +void SHA384_Update(); +void SHA384_Final(); +char* SHA384_End(); +char* SHA384_Data(); + +void SHA512_Init(); +void SHA512_Update(); +void SHA512_Final(); +char* SHA512_End(); +char* SHA512_Data(); + +#endif /* NOPROTO */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __SHA2_H__ */ + diff --git a/contrib/slapd-modules/passwd/sha2/slapd-sha2.c b/contrib/slapd-modules/passwd/sha2/slapd-sha2.c new file mode 100644 index 0000000..c35d9d9 --- /dev/null +++ b/contrib/slapd-modules/passwd/sha2/slapd-sha2.c @@ -0,0 +1,508 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2009-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENT: + * This work was initially developed by Jeff Turner for inclusion + * in OpenLDAP Software. + * + * Hash methods for passwords generation added by Cédric Delfosse. + * + * SSHA256 / SSHA384 / SSHA512 support added, and chk_sha*() replaced + * with libraries/liblutil/passwd.c:chk_sha1() implementation to + * fix a race by SATOH Fumiyasu @ OSS Technology, Inc. + */ + +#include "portable.h" + +#include <ac/string.h> + +#include "lber_pvt.h" +#include "lutil.h" +#include "sha2.h" + +#ifdef SLAPD_SHA2_DEBUG +#include <stdio.h> +#endif + +#define SHA2_SALT_SIZE 8 + +static int hash_ssha256( + const struct berval *scheme, + const struct berval *passwd, + struct berval *hash, + const char **text ) +{ + SHA256_CTX ct; + unsigned char hash256[SHA256_DIGEST_LENGTH]; + char saltdata[SHA2_SALT_SIZE]; + struct berval digest; + struct berval salt; + + digest.bv_val = (char *) hash256; + digest.bv_len = sizeof(hash256); + salt.bv_val = saltdata; + salt.bv_len = sizeof(saltdata); + + if (lutil_entropy((unsigned char *)salt.bv_val, salt.bv_len) < 0) { + return LUTIL_PASSWD_ERR; + } + + SHA256_Init(&ct); + SHA256_Update(&ct, (const uint8_t*)passwd->bv_val, passwd->bv_len); + SHA256_Update(&ct, (const uint8_t*)salt.bv_val, salt.bv_len); + SHA256_Final(hash256, &ct); + + return lutil_passwd_string64(scheme, &digest, hash, &salt); +} + +static int hash_sha256( + const struct berval *scheme, + const struct berval *passwd, + struct berval *hash, + const char **text ) +{ + SHA256_CTX ct; + unsigned char hash256[SHA256_DIGEST_LENGTH]; + struct berval digest; + digest.bv_val = (char *) hash256; + digest.bv_len = sizeof(hash256); + + SHA256_Init(&ct); + SHA256_Update(&ct, (const uint8_t*)passwd->bv_val, passwd->bv_len); + SHA256_Final(hash256, &ct); + + return lutil_passwd_string64(scheme, &digest, hash, NULL); +} + +static int hash_ssha384( + const struct berval *scheme, + const struct berval *passwd, + struct berval *hash, + const char **text ) +{ + SHA384_CTX ct; + unsigned char hash384[SHA384_DIGEST_LENGTH]; + char saltdata[SHA2_SALT_SIZE]; + struct berval digest; + struct berval salt; + + digest.bv_val = (char *) hash384; + digest.bv_len = sizeof(hash384); + salt.bv_val = saltdata; + salt.bv_len = sizeof(saltdata); + + if (lutil_entropy((unsigned char *)salt.bv_val, salt.bv_len) < 0) { + return LUTIL_PASSWD_ERR; + } + + SHA384_Init(&ct); + SHA384_Update(&ct, (const uint8_t*)passwd->bv_val, passwd->bv_len); + SHA384_Update(&ct, (const uint8_t*)salt.bv_val, salt.bv_len); + SHA384_Final(hash384, &ct); + + return lutil_passwd_string64(scheme, &digest, hash, &salt); +} + +static int hash_sha384( + const struct berval *scheme, + const struct berval *passwd, + struct berval *hash, + const char **text ) +{ + SHA384_CTX ct; + unsigned char hash384[SHA384_DIGEST_LENGTH]; + struct berval digest; + digest.bv_val = (char *) hash384; + digest.bv_len = sizeof(hash384); + + SHA384_Init(&ct); + SHA384_Update(&ct, (const uint8_t*)passwd->bv_val, passwd->bv_len); + SHA384_Final(hash384, &ct); + + return lutil_passwd_string64(scheme, &digest, hash, NULL); +} + +static int hash_ssha512( + const struct berval *scheme, + const struct berval *passwd, + struct berval *hash, + const char **text ) +{ + SHA512_CTX ct; + unsigned char hash512[SHA512_DIGEST_LENGTH]; + char saltdata[SHA2_SALT_SIZE]; + struct berval digest; + struct berval salt; + + digest.bv_val = (char *) hash512; + digest.bv_len = sizeof(hash512); + salt.bv_val = saltdata; + salt.bv_len = sizeof(saltdata); + + if (lutil_entropy((unsigned char *)salt.bv_val, salt.bv_len) < 0) { + return LUTIL_PASSWD_ERR; + } + + SHA512_Init(&ct); + SHA512_Update(&ct, (const uint8_t*)passwd->bv_val, passwd->bv_len); + SHA512_Update(&ct, (const uint8_t*)salt.bv_val, salt.bv_len); + SHA512_Final(hash512, &ct); + + return lutil_passwd_string64(scheme, &digest, hash, &salt); +} + +static int hash_sha512( + const struct berval *scheme, + const struct berval *passwd, + struct berval *hash, + const char **text ) +{ + SHA512_CTX ct; + unsigned char hash512[SHA512_DIGEST_LENGTH]; + struct berval digest; + digest.bv_val = (char *) hash512; + digest.bv_len = sizeof(hash512); + + SHA512_Init(&ct); + SHA512_Update(&ct, (const uint8_t*)passwd->bv_val, passwd->bv_len); + SHA512_Final(hash512, &ct); + + return lutil_passwd_string64(scheme, &digest, hash, NULL); +} + +#ifdef SLAPD_SHA2_DEBUG +static void chk_sha_debug( + const struct berval *scheme, + const struct berval *passwd, + const struct berval *cred, + const char *cred_hash, + size_t cred_len, + int cmp_rc) +{ + int rc; + struct berval cred_b64; + + cred_b64.bv_len = LUTIL_BASE64_ENCODE_LEN(cred_len) + 1; + cred_b64.bv_val = ber_memalloc(cred_b64.bv_len + 1); + + if( cred_b64.bv_val == NULL ) { + return; + } + + rc = lutil_b64_ntop( + (unsigned char *) cred_hash, cred_len, + cred_b64.bv_val, cred_b64.bv_len ); + + if( rc < 0 ) { + ber_memfree(cred_b64.bv_val); + return; + } + + fprintf(stderr, "Validating password\n"); + fprintf(stderr, " Hash scheme:\t\t%s\n", scheme->bv_val); + fprintf(stderr, " Password to validate: %s\n", cred->bv_val); + fprintf(stderr, " Password hash:\t%s\n", cred_b64.bv_val); + fprintf(stderr, " Stored password hash:\t%s\n", passwd->bv_val); + fprintf(stderr, " Result:\t\t%s\n", cmp_rc ? "do not match" : "match"); + + ber_memfree(cred_b64.bv_val); +} +#endif + +static int chk_ssha256( + const struct berval *scheme, /* Scheme of hashed reference password */ + const struct berval *passwd, /* Hashed reference password to check against */ + const struct berval *cred, /* user-supplied password to check */ + const char **text ) +{ + SHA256_CTX SHAcontext; + unsigned char SHAdigest[SHA256_DIGEST_LENGTH]; + int rc; + unsigned char *orig_pass = NULL; + size_t decode_len = LUTIL_BASE64_DECODE_LEN(passwd->bv_len); + + /* safety check */ + if (decode_len <= sizeof(SHAdigest)) { + return LUTIL_PASSWD_ERR; + } + + /* base64 un-encode password */ + orig_pass = (unsigned char *) ber_memalloc(decode_len + 1); + + if( orig_pass == NULL ) return LUTIL_PASSWD_ERR; + + rc = lutil_b64_pton(passwd->bv_val, orig_pass, decode_len); + + if( rc <= (int)(sizeof(SHAdigest)) ) { + ber_memfree(orig_pass); + return LUTIL_PASSWD_ERR; + } + + /* hash credentials with salt */ + SHA256_Init(&SHAcontext); + SHA256_Update(&SHAcontext, + (const unsigned char *) cred->bv_val, cred->bv_len); + SHA256_Update(&SHAcontext, + (const unsigned char *) &orig_pass[sizeof(SHAdigest)], + rc - sizeof(SHAdigest)); + SHA256_Final(SHAdigest, &SHAcontext); + + /* compare */ + rc = memcmp((char *)orig_pass, (char *)SHAdigest, sizeof(SHAdigest)); + ber_memfree(orig_pass); + return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; +} + +static int chk_sha256( + const struct berval *scheme, /* Scheme of hashed reference password */ + const struct berval *passwd, /* Hashed reference password to check against */ + const struct berval *cred, /* user-supplied password to check */ + const char **text ) +{ + SHA256_CTX SHAcontext; + unsigned char SHAdigest[SHA256_DIGEST_LENGTH]; + int rc; + unsigned char *orig_pass = NULL; + size_t decode_len = LUTIL_BASE64_DECODE_LEN(passwd->bv_len); + + /* safety check */ + if (decode_len < sizeof(SHAdigest)) { + return LUTIL_PASSWD_ERR; + } + + /* base64 un-encode password */ + orig_pass = (unsigned char *) ber_memalloc(decode_len + 1); + + if( orig_pass == NULL ) return LUTIL_PASSWD_ERR; + + rc = lutil_b64_pton(passwd->bv_val, orig_pass, decode_len); + + if( rc != sizeof(SHAdigest) ) { + ber_memfree(orig_pass); + return LUTIL_PASSWD_ERR; + } + + /* hash credentials with salt */ + SHA256_Init(&SHAcontext); + SHA256_Update(&SHAcontext, + (const unsigned char *) cred->bv_val, cred->bv_len); + SHA256_Final(SHAdigest, &SHAcontext); + + /* compare */ + rc = memcmp((char *)orig_pass, (char *)SHAdigest, sizeof(SHAdigest)); +#ifdef SLAPD_SHA2_DEBUG + chk_sha_debug(scheme, passwd, cred, (char *)SHAdigest, sizeof(SHAdigest), rc); +#endif + ber_memfree(orig_pass); + return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; +} + +static int chk_ssha384( + const struct berval *scheme, /* Scheme of hashed reference password */ + const struct berval *passwd, /* Hashed reference password to check against */ + const struct berval *cred, /* user-supplied password to check */ + const char **text ) +{ + SHA384_CTX SHAcontext; + unsigned char SHAdigest[SHA384_DIGEST_LENGTH]; + int rc; + unsigned char *orig_pass = NULL; + size_t decode_len = LUTIL_BASE64_DECODE_LEN(passwd->bv_len); + + /* safety check */ + if (decode_len <= sizeof(SHAdigest)) { + return LUTIL_PASSWD_ERR; + } + + /* base64 un-encode password */ + orig_pass = (unsigned char *) ber_memalloc(decode_len + 1); + + if( orig_pass == NULL ) return LUTIL_PASSWD_ERR; + + rc = lutil_b64_pton(passwd->bv_val, orig_pass, decode_len); + + if( rc <= (int)(sizeof(SHAdigest)) ) { + ber_memfree(orig_pass); + return LUTIL_PASSWD_ERR; + } + + /* hash credentials with salt */ + SHA384_Init(&SHAcontext); + SHA384_Update(&SHAcontext, + (const unsigned char *) cred->bv_val, cred->bv_len); + SHA384_Update(&SHAcontext, + (const unsigned char *) &orig_pass[sizeof(SHAdigest)], + rc - sizeof(SHAdigest)); + SHA384_Final(SHAdigest, &SHAcontext); + + /* compare */ + rc = memcmp((char *)orig_pass, (char *)SHAdigest, sizeof(SHAdigest)); + ber_memfree(orig_pass); + return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; +} + +static int chk_sha384( + const struct berval *scheme, /* Scheme of hashed reference password */ + const struct berval *passwd, /* Hashed reference password to check against */ + const struct berval *cred, /* user-supplied password to check */ + const char **text ) +{ + SHA384_CTX SHAcontext; + unsigned char SHAdigest[SHA384_DIGEST_LENGTH]; + int rc; + unsigned char *orig_pass = NULL; + size_t decode_len = LUTIL_BASE64_DECODE_LEN(passwd->bv_len); + + /* safety check */ + if (decode_len < sizeof(SHAdigest)) { + return LUTIL_PASSWD_ERR; + } + + /* base64 un-encode password */ + orig_pass = (unsigned char *) ber_memalloc(decode_len + 1); + + if( orig_pass == NULL ) return LUTIL_PASSWD_ERR; + + rc = lutil_b64_pton(passwd->bv_val, orig_pass, decode_len); + + if( rc != sizeof(SHAdigest) ) { + ber_memfree(orig_pass); + return LUTIL_PASSWD_ERR; + } + + /* hash credentials with salt */ + SHA384_Init(&SHAcontext); + SHA384_Update(&SHAcontext, + (const unsigned char *) cred->bv_val, cred->bv_len); + SHA384_Final(SHAdigest, &SHAcontext); + + /* compare */ + rc = memcmp((char *)orig_pass, (char *)SHAdigest, sizeof(SHAdigest)); +#ifdef SLAPD_SHA2_DEBUG + chk_sha_debug(scheme, passwd, cred, (char *)SHAdigest, sizeof(SHAdigest), rc); +#endif + ber_memfree(orig_pass); + return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; +} + +static int chk_ssha512( + const struct berval *scheme, /* Scheme of hashed reference password */ + const struct berval *passwd, /* Hashed reference password to check against */ + const struct berval *cred, /* user-supplied password to check */ + const char **text ) +{ + SHA512_CTX SHAcontext; + unsigned char SHAdigest[SHA512_DIGEST_LENGTH]; + int rc; + unsigned char *orig_pass = NULL; + size_t decode_len = LUTIL_BASE64_DECODE_LEN(passwd->bv_len); + + /* safety check */ + if (decode_len <= sizeof(SHAdigest)) { + return LUTIL_PASSWD_ERR; + } + + /* base64 un-encode password */ + orig_pass = (unsigned char *) ber_memalloc(decode_len + 1); + + if( orig_pass == NULL ) return LUTIL_PASSWD_ERR; + + rc = lutil_b64_pton(passwd->bv_val, orig_pass, decode_len); + + if( rc <= (int)(sizeof(SHAdigest)) ) { + ber_memfree(orig_pass); + return LUTIL_PASSWD_ERR; + } + + /* hash credentials with salt */ + SHA512_Init(&SHAcontext); + SHA512_Update(&SHAcontext, + (const unsigned char *) cred->bv_val, cred->bv_len); + SHA512_Update(&SHAcontext, + (const unsigned char *) &orig_pass[sizeof(SHAdigest)], + rc - sizeof(SHAdigest)); + SHA512_Final(SHAdigest, &SHAcontext); + + /* compare */ + rc = memcmp((char *)orig_pass, (char *)SHAdigest, sizeof(SHAdigest)); + ber_memfree(orig_pass); + return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; +} + +static int chk_sha512( + const struct berval *scheme, /* Scheme of hashed reference password */ + const struct berval *passwd, /* Hashed reference password to check against */ + const struct berval *cred, /* user-supplied password to check */ + const char **text ) +{ + SHA512_CTX SHAcontext; + unsigned char SHAdigest[SHA512_DIGEST_LENGTH]; + int rc; + unsigned char *orig_pass = NULL; + size_t decode_len = LUTIL_BASE64_DECODE_LEN(passwd->bv_len); + + /* safety check */ + if (decode_len < sizeof(SHAdigest)) { + return LUTIL_PASSWD_ERR; + } + + /* base64 un-encode password */ + orig_pass = (unsigned char *) ber_memalloc(decode_len + 1); + + if( orig_pass == NULL ) return LUTIL_PASSWD_ERR; + + rc = lutil_b64_pton(passwd->bv_val, orig_pass, decode_len); + + if( rc != sizeof(SHAdigest) ) { + ber_memfree(orig_pass); + return LUTIL_PASSWD_ERR; + } + + /* hash credentials with salt */ + SHA512_Init(&SHAcontext); + SHA512_Update(&SHAcontext, + (const unsigned char *) cred->bv_val, cred->bv_len); + SHA512_Final(SHAdigest, &SHAcontext); + + /* compare */ + rc = memcmp((char *)orig_pass, (char *)SHAdigest, sizeof(SHAdigest)); +#ifdef SLAPD_SHA2_DEBUG + chk_sha_debug(scheme, passwd, cred, (char *)SHAdigest, sizeof(SHAdigest), rc); +#endif + ber_memfree(orig_pass); + return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; +} + +const struct berval ssha256scheme = BER_BVC("{SSHA256}"); +const struct berval sha256scheme = BER_BVC("{SHA256}"); +const struct berval ssha384scheme = BER_BVC("{SSHA384}"); +const struct berval sha384scheme = BER_BVC("{SHA384}"); +const struct berval ssha512scheme = BER_BVC("{SSHA512}"); +const struct berval sha512scheme = BER_BVC("{SHA512}"); + +int init_module(int argc, char *argv[]) { + int result = 0; + result = lutil_passwd_add( (struct berval *)&ssha256scheme, chk_ssha256, hash_ssha256 ); + if (result != 0) return result; + result = lutil_passwd_add( (struct berval *)&sha256scheme, chk_sha256, hash_sha256 ); + if (result != 0) return result; + result = lutil_passwd_add( (struct berval *)&ssha384scheme, chk_ssha384, hash_ssha384 ); + if (result != 0) return result; + result = lutil_passwd_add( (struct berval *)&sha384scheme, chk_sha384, hash_sha384 ); + if (result != 0) return result; + result = lutil_passwd_add( (struct berval *)&ssha512scheme, chk_ssha512, hash_ssha512 ); + if (result != 0) return result; + result = lutil_passwd_add( (struct berval *)&sha512scheme, chk_sha512, hash_sha512 ); + return result; +} diff --git a/contrib/slapd-modules/proxyOld/Makefile b/contrib/slapd-modules/proxyOld/Makefile new file mode 100644 index 0000000..1bc2f57 --- /dev/null +++ b/contrib/slapd-modules/proxyOld/Makefile @@ -0,0 +1,58 @@ +# $OpenLDAP$ +# This work is part of OpenLDAP Software <http://www.openldap.org/>. +# +# Copyright 2005-2021 The OpenLDAP Foundation. +# Portions Copyright 2005 Howard Chu, Symas Corp. All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted only as authorized by the OpenLDAP +# Public License. +# +# A copy of this license is available in the file LICENSE in the +# top-level directory of the distribution or, alternatively, at +# <http://www.OpenLDAP.org/license.html>. + +LDAP_SRC = ../../.. +LDAP_BUILD = $(LDAP_SRC) +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +CC = gcc +OPT = -g -O2 -Wall +DEFS = +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) + +PROGRAMS = proxyOld.la +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +proxyOld.la: proxyOld.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + diff --git a/contrib/slapd-modules/proxyOld/README b/contrib/slapd-modules/proxyOld/README new file mode 100644 index 0000000..b210740 --- /dev/null +++ b/contrib/slapd-modules/proxyOld/README @@ -0,0 +1,31 @@ +This directory contains a slapd module proxyOld that provides support +for the obsolete draft-weltman-ldapb3-proxy-05 revision of the LDAP +Proxy Authorization control. It is merely intended to provide compatibility +in environments where other servers only recognize this old control. +New installations should not use this code. + +To use the module, add: + + moduleload <path to>proxyOld.so + ... + +to your slapd configuration file. Since this is an obsolete feature, +the control is registered with the SLAP_CTRL_HIDE flag so that it will +not be advertised in the rootDSE's supportedControls attribute. + +This code only works as a dynamically loaded module. + +--- +This work is part of OpenLDAP Software <http://www.openldap.org/>. + +Copyright 1998-2021 The OpenLDAP Foundation. +Portions Copyright 2005 Howard Chu, Symas Corp. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted only as authorized by the OpenLDAP +Public License. + +A copy of this license is available in the file LICENSE in the +top-level directory of the distribution or, alternatively, at +<http://www.OpenLDAP.org/license.html>. + diff --git a/contrib/slapd-modules/proxyOld/proxyOld.c b/contrib/slapd-modules/proxyOld/proxyOld.c new file mode 100644 index 0000000..c161aa3 --- /dev/null +++ b/contrib/slapd-modules/proxyOld/proxyOld.c @@ -0,0 +1,128 @@ +/* proxyOld.c - module for supporting obsolete (rev 05) proxyAuthz control */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2005-2021 The OpenLDAP Foundation. + * Portions Copyright 2005 by Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ + +#include <portable.h> + +#include <slap.h> + +#include <lber.h> +/* +#include <lber_pvt.h> +#include <lutil.h> +*/ + +/* This code is based on draft-weltman-ldapv3-proxy-05. There are a lot + * of holes in that draft, it doesn't specify that the control is legal + * for Add operations, and it makes no mention of Extended operations. + * It also doesn't specify whether an empty LDAPDN is allowed in the + * control value. + * + * For usability purposes, we're copying the op / exop behavior from the + * newer -12 draft. + */ +#define LDAP_CONTROL_PROXY_AUTHZ05 "2.16.840.1.113730.3.4.12" + +static char *proxyOld_extops[] = { + LDAP_EXOP_MODIFY_PASSWD, + LDAP_EXOP_X_WHO_AM_I, + NULL +}; + +static int +proxyOld_parse( + Operation *op, + SlapReply *rs, + LDAPControl *ctrl ) +{ + int rc; + BerElement *ber; + ber_tag_t tag; + struct berval dn = BER_BVNULL; + struct berval authzDN = BER_BVNULL; + + + /* We hijack the flag for the new control. Clearly only one or the + * other can be used at any given time. + */ + if ( op->o_proxy_authz != SLAP_CONTROL_NONE ) { + rs->sr_text = "proxy authorization control specified multiple times"; + return LDAP_PROTOCOL_ERROR; + } + + op->o_proxy_authz = ctrl->ldctl_iscritical + ? SLAP_CONTROL_CRITICAL + : SLAP_CONTROL_NONCRITICAL; + + /* Parse the control value + * proxyAuthzControlValue ::= SEQUENCE { + * proxyDN LDAPDN + * } + */ + ber = ber_init( &ctrl->ldctl_value ); + if ( ber == NULL ) { + rs->sr_text = "ber_init failed"; + return LDAP_OTHER; + } + + tag = ber_scanf( ber, "{m}", &dn ); + + if ( tag == LBER_ERROR ) { + rs->sr_text = "proxyOld control could not be decoded"; + rc = LDAP_OTHER; + goto done; + } + if ( BER_BVISEMPTY( &dn )) { + Debug( LDAP_DEBUG_TRACE, + "proxyOld_parse: conn=%lu anonymous\n", + op->o_connid, 0, 0 ); + authzDN.bv_val = ch_strdup(""); + } else { + Debug( LDAP_DEBUG_ARGS, + "proxyOld_parse: conn %lu ctrl DN=\"%s\"\n", + op->o_connid, dn.bv_val, 0 ); + rc = dnNormalize( 0, NULL, NULL, &dn, &authzDN, op->o_tmpmemctx ); + if ( rc != LDAP_SUCCESS ) { + goto done; + } + rc = slap_sasl_authorized( op, &op->o_ndn, &authzDN ); + if ( rc ) { + op->o_tmpfree( authzDN.bv_val, op->o_tmpmemctx ); + rs->sr_text = "not authorized to assume identity"; + /* new spec uses LDAP_PROXY_AUTHZ_FAILURE */ + rc = LDAP_INSUFFICIENT_ACCESS; + goto done; + } + } + free( op->o_ndn.bv_val ); + free( op->o_dn.bv_val ); + op->o_ndn = authzDN; + ber_dupbv( &op->o_dn, &authzDN ); + + Statslog( LDAP_DEBUG_STATS, "conn=%lu op=%lu PROXYOLD dn=\"%s\"\n", + op->o_connid, op->o_opid, + authzDN.bv_len ? authzDN.bv_val : "anonymous", 0, 0 ); + rc = LDAP_SUCCESS; +done: + ber_free( ber, 1 ); + return rc; +} + +int init_module(int argc, char *argv[]) { + return register_supported_control( LDAP_CONTROL_PROXY_AUTHZ05, + SLAP_CTRL_GLOBAL|SLAP_CTRL_HIDE|SLAP_CTRL_ACCESS, proxyOld_extops, + proxyOld_parse, NULL ); +} diff --git a/contrib/slapd-modules/samba4/Makefile b/contrib/slapd-modules/samba4/Makefile new file mode 100644 index 0000000..6704ce7 --- /dev/null +++ b/contrib/slapd-modules/samba4/Makefile @@ -0,0 +1,68 @@ +# $OpenLDAP$ +# This work is part of OpenLDAP Software <http://www.openldap.org/>. +# +# Copyright 1998-2021 The OpenLDAP Foundation. +# Copyright 2004 Howard Chu, Symas Corp. All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted only as authorized by the OpenLDAP +# Public License. +# +# A copy of this license is available in the file LICENSE in the +# top-level directory of the distribution or, alternatively, at +# <http://www.OpenLDAP.org/license.html>. + +LDAP_SRC = ../../.. +LDAP_BUILD = $(LDAP_SRC) +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +CC = gcc +OPT = -g -O2 -Wall +DEFS = -DSLAPD_OVER_RDNVAL=SLAPD_MOD_DYNAMIC \ + -DSLAPD_OVER_PGUID=SLAPD_MOD_DYNAMIC \ + -DSLAPD_OVER_VERNUM=SLAPD_MOD_DYNAMIC +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) + +PROGRAMS = pguid.la rdnval.la vernum.la +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +pguid.la: pguid.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +rdnval.la: rdnval.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +vernum.la: vernum.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + diff --git a/contrib/slapd-modules/samba4/README b/contrib/slapd-modules/samba4/README new file mode 100644 index 0000000..b68034b --- /dev/null +++ b/contrib/slapd-modules/samba4/README @@ -0,0 +1,72 @@ +# $OpenLDAP$ + +This directory contains slapd overlays specific to samba4 LDAP backend: + + - pguid (not used) + - rdnval (under evaluation) + - vernum (under evaluation) + + + - PGUID + +This overlay maintains the operational attribute "parentUUID". It contains +the entryUUID of the parent entry. This overlay is not being considered +right now. + + + - RDNVAL + +This overlay maintains the operational attribute "rdnValue". It contains +the value of the entry's RDN. This attribute is defined by the overlay +itself as + + ( 1.3.6.1.4.1.4203.666.1.58 + NAME 'rdnValue' + DESC 'the value of the naming attributes' + SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' + EQUALITY caseIgnoreMatch + USAGE dSAOperation + NO-USER-MODIFICATION ) + +under OpenLDAP's development OID arc. This OID is temporary. + +To use the overlay, add: + + moduleload <path to>rdnval.so + ... + + database <whatever> + ... + overlay rdnval + +to your slapd configuration file. An instance is required for each database +that needs to maintain this attribute. + + + - VERNUM + +This overlay increments a counter any time an attribute is modified. +It is intended to increment the counter 'msDS-KeyVersionNumber' when +the attribute 'unicodePwd' is modified. + + +These overlays are only set up to be built as a dynamically loaded modules. +On most platforms, in order for the modules to be usable, all of the +library dependencies must also be available as shared libraries. + +If you need to build the overlays statically, you will have to move them +into the slapd/overlays directory and edit the Makefile and overlays.c +to reference them. + +--- +This work is part of OpenLDAP Software <http://www.openldap.org/>. +Copyright 2009-2021 The OpenLDAP Foundation. + +Redistribution and use in source and binary forms, with or without +modification, are permitted only as authorized by the OpenLDAP +Public License. + +A copy of this license is available in the file LICENSE in the +top-level directory of the distribution or, alternatively, at +<http://www.OpenLDAP.org/license.html>. + diff --git a/contrib/slapd-modules/samba4/pguid.c b/contrib/slapd-modules/samba4/pguid.c new file mode 100644 index 0000000..ae7d71e --- /dev/null +++ b/contrib/slapd-modules/samba4/pguid.c @@ -0,0 +1,460 @@ +/* pguid.c - Parent GUID value overlay */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 1998-2021 The OpenLDAP Foundation. + * Portions Copyright 2008 Pierangelo Masarati. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by Pierangelo Masarati + * for inclusion in OpenLDAP Software. + */ + +#include "portable.h" + +#ifdef SLAPD_OVER_PGUID + +#include <stdio.h> + +#include "ac/string.h" +#include "ac/socket.h" + +#include "slap.h" +#include "config.h" + +#include "lutil.h" + +/* + * Maintain an attribute (parentUUID) that contains the value + * of the entryUUID of the parent entry (used by Samba4) + */ + +static AttributeDescription *ad_parentUUID; + +static slap_overinst pguid; + +static int +pguid_op_add( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + + struct berval pdn, pndn; + Entry *e = NULL; + Attribute *a; + int rc; + + /* don't care about suffix entry */ + if ( dn_match( &op->o_req_ndn, &op->o_bd->be_nsuffix[0] ) ) { + return SLAP_CB_CONTINUE; + } + + dnParent( &op->o_req_dn, &pdn ); + dnParent( &op->o_req_ndn, &pndn ); + + rc = overlay_entry_get_ov( op, &pndn, NULL, slap_schema.si_ad_entryUUID, 0, &e, on ); + if ( rc != LDAP_SUCCESS || e == NULL ) { + Debug( LDAP_DEBUG_ANY, "%s: pguid_op_add: unable to get parent entry DN=\"%s\" (%d)\n", + op->o_log_prefix, pdn.bv_val, rc ); + return SLAP_CB_CONTINUE; + } + + a = attr_find( e->e_attrs, slap_schema.si_ad_entryUUID ); + if ( a == NULL ) { + Debug( LDAP_DEBUG_ANY, "%s: pguid_op_add: unable to find entryUUID of parent entry DN=\"%s\" (%d)\n", + op->o_log_prefix, pdn.bv_val, rc ); + + } else { + assert( a->a_numvals == 1 ); + + if ( op->ora_e != NULL ) { + attr_merge_one( op->ora_e, ad_parentUUID, &a->a_vals[0], a->a_nvals == a->a_vals ? NULL : &a->a_nvals[0] ); + + } else { + Modifications *ml; + Modifications *mod; + + assert( op->ora_modlist != NULL ); + + for ( ml = op->ora_modlist; ml != NULL; ml = ml->sml_next ) { + if ( ml->sml_mod.sm_desc == slap_schema.si_ad_entryUUID ) { + break; + } + } + + if ( ml == NULL ) { + ml = op->ora_modlist; + } + + mod = (Modifications *) ch_malloc( sizeof( Modifications ) ); + mod->sml_flags = SLAP_MOD_INTERNAL; + mod->sml_op = LDAP_MOD_ADD; + mod->sml_desc = ad_parentUUID; + mod->sml_type = ad_parentUUID->ad_cname; + mod->sml_values = ch_malloc( sizeof( struct berval ) * 2 ); + mod->sml_nvalues = NULL; + mod->sml_numvals = 1; + + ber_dupbv( &mod->sml_values[0], &a->a_vals[0] ); + BER_BVZERO( &mod->sml_values[1] ); + + mod->sml_next = ml->sml_next; + ml->sml_next = mod; + } + } + + if ( e != NULL ) { + (void)overlay_entry_release_ov( op, e, 0, on ); + } + + return SLAP_CB_CONTINUE; +} + +static int +pguid_op_rename( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + + Entry *e = NULL; + Attribute *a; + int rc; + + if ( op->orr_nnewSup == NULL ) { + return SLAP_CB_CONTINUE; + } + + rc = overlay_entry_get_ov( op, op->orr_nnewSup, NULL, slap_schema.si_ad_entryUUID, 0, &e, on ); + if ( rc != LDAP_SUCCESS || e == NULL ) { + Debug( LDAP_DEBUG_ANY, "%s: pguid_op_rename: unable to get newSuperior entry DN=\"%s\" (%d)\n", + op->o_log_prefix, op->orr_newSup->bv_val, rc ); + return SLAP_CB_CONTINUE; + } + + a = attr_find( e->e_attrs, slap_schema.si_ad_entryUUID ); + if ( a == NULL ) { + Debug( LDAP_DEBUG_ANY, "%s: pguid_op_rename: unable to find entryUUID of newSuperior entry DN=\"%s\" (%d)\n", + op->o_log_prefix, op->orr_newSup->bv_val, rc ); + + } else { + Modifications *mod; + + assert( a->a_numvals == 1 ); + + mod = (Modifications *) ch_malloc( sizeof( Modifications ) ); + mod->sml_flags = SLAP_MOD_INTERNAL; + mod->sml_op = LDAP_MOD_REPLACE; + mod->sml_desc = ad_parentUUID; + mod->sml_type = ad_parentUUID->ad_cname; + mod->sml_values = ch_malloc( sizeof( struct berval ) * 2 ); + mod->sml_nvalues = NULL; + mod->sml_numvals = 1; + + ber_dupbv( &mod->sml_values[0], &a->a_vals[0] ); + BER_BVZERO( &mod->sml_values[1] ); + + mod->sml_next = op->orr_modlist; + op->orr_modlist = mod; + } + + if ( e != NULL ) { + (void)overlay_entry_release_ov( op, e, 0, on ); + } + + return SLAP_CB_CONTINUE; +} + +static int +pguid_db_init( + BackendDB *be, + ConfigReply *cr) +{ + if ( SLAP_ISGLOBALOVERLAY( be ) ) { + Log0( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, + "pguid_db_init: pguid cannot be used as global overlay.\n" ); + return 1; + } + + if ( be->be_nsuffix == NULL ) { + Log0( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, + "pguid_db_init: database must have suffix\n" ); + return 1; + } + + if ( BER_BVISNULL( &be->be_rootndn ) || BER_BVISEMPTY( &be->be_rootndn ) ) { + Log1( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, + "pguid_db_init: missing rootdn for database DN=\"%s\", YMMV\n", + be->be_suffix[ 0 ].bv_val ); + } + + return 0; +} + +typedef struct pguid_mod_t { + struct berval ndn; + struct berval pguid; + struct pguid_mod_t *next; +} pguid_mod_t; + +typedef struct { + slap_overinst *on; + pguid_mod_t *mods; +} pguid_repair_cb_t; + +static int +pguid_repair_cb( Operation *op, SlapReply *rs ) +{ + int rc; + pguid_repair_cb_t *pcb = op->o_callback->sc_private; + Entry *e = NULL; + Attribute *a; + struct berval pdn, pndn; + + switch ( rs->sr_type ) { + case REP_SEARCH: + break; + + case REP_SEARCHREF: + case REP_RESULT: + return rs->sr_err; + + default: + assert( 0 ); + } + + assert( rs->sr_entry != NULL ); + + dnParent( &rs->sr_entry->e_name, &pdn ); + dnParent( &rs->sr_entry->e_nname, &pndn ); + + rc = overlay_entry_get_ov( op, &pndn, NULL, slap_schema.si_ad_entryUUID, 0, &e, pcb->on ); + if ( rc != LDAP_SUCCESS || e == NULL ) { + Debug( LDAP_DEBUG_ANY, "%s: pguid_repair_cb: unable to get parent entry DN=\"%s\" (%d)\n", + op->o_log_prefix, pdn.bv_val, rc ); + return 0; + } + + a = attr_find( e->e_attrs, slap_schema.si_ad_entryUUID ); + if ( a == NULL ) { + Debug( LDAP_DEBUG_ANY, "%s: pguid_repair_cb: unable to find entryUUID of parent entry DN=\"%s\" (%d)\n", + op->o_log_prefix, pdn.bv_val, rc ); + + } else { + ber_len_t len; + pguid_mod_t *mod; + + assert( a->a_numvals == 1 ); + + len = sizeof( pguid_mod_t ) + rs->sr_entry->e_nname.bv_len + 1 + a->a_vals[0].bv_len + 1; + mod = op->o_tmpalloc( len, op->o_tmpmemctx ); + mod->ndn.bv_len = rs->sr_entry->e_nname.bv_len; + mod->ndn.bv_val = (char *)&mod[1]; + mod->pguid.bv_len = a->a_vals[0].bv_len; + mod->pguid.bv_val = (char *)&mod->ndn.bv_val[mod->ndn.bv_len + 1]; + lutil_strncopy( mod->ndn.bv_val, rs->sr_entry->e_nname.bv_val, rs->sr_entry->e_nname.bv_len ); + lutil_strncopy( mod->pguid.bv_val, a->a_vals[0].bv_val, a->a_vals[0].bv_len ); + + mod->next = pcb->mods; + pcb->mods = mod; + + Debug( LDAP_DEBUG_TRACE, "%s: pguid_repair_cb: scheduling entry DN=\"%s\" for repair\n", + op->o_log_prefix, rs->sr_entry->e_name.bv_val, 0 ); + } + + if ( e != NULL ) { + (void)overlay_entry_release_ov( op, e, 0, pcb->on ); + } + + return 0; +} + +static int +pguid_repair( BackendDB *be ) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + void *ctx = ldap_pvt_thread_pool_context(); + Connection conn = { 0 }; + OperationBuffer opbuf; + Operation *op; + slap_callback sc = { 0 }; + pguid_repair_cb_t pcb = { 0 }; + SlapReply rs = { REP_RESULT }; + pguid_mod_t *pmod; + int nrepaired = 0; + + connection_fake_init2( &conn, &opbuf, ctx, 0 ); + op = &opbuf.ob_op; + + op->o_tag = LDAP_REQ_SEARCH; + memset( &op->oq_search, 0, sizeof( op->oq_search ) ); + + op->o_bd = select_backend( &be->be_nsuffix[ 0 ], 0 ); + + op->o_req_dn = op->o_bd->be_suffix[ 0 ]; + op->o_req_ndn = op->o_bd->be_nsuffix[ 0 ]; + + op->o_dn = op->o_bd->be_rootdn; + op->o_ndn = op->o_bd->be_rootndn; + + op->ors_scope = LDAP_SCOPE_SUBORDINATE; + op->ors_tlimit = SLAP_NO_LIMIT; + op->ors_slimit = SLAP_NO_LIMIT; + op->ors_attrs = slap_anlist_no_attrs; + + op->ors_filterstr.bv_len = STRLENOF( "(!(=*))" ) + ad_parentUUID->ad_cname.bv_len; + op->ors_filterstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len + 1, op->o_tmpmemctx ); + snprintf( op->ors_filterstr.bv_val, op->ors_filterstr.bv_len + 1, + "(!(%s=*))", ad_parentUUID->ad_cname.bv_val ); + + op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val ); + if ( op->ors_filter == NULL ) { + rs.sr_err = LDAP_OTHER; + goto done_search; + } + + op->o_callback = ≻ + sc.sc_response = pguid_repair_cb; + sc.sc_private = &pcb; + pcb.on = on; + + (void)op->o_bd->bd_info->bi_op_search( op, &rs ); + + op->o_tag = LDAP_REQ_MODIFY; + sc.sc_response = slap_null_cb; + sc.sc_private = NULL; + memset( &op->oq_modify, 0, sizeof( req_modify_s ) ); + + for ( pmod = pcb.mods; pmod != NULL; ) { + pguid_mod_t *pnext; + + Modifications *mod; + SlapReply rs2 = { REP_RESULT }; + + mod = (Modifications *) ch_malloc( sizeof( Modifications ) ); + mod->sml_flags = SLAP_MOD_INTERNAL; + mod->sml_op = LDAP_MOD_REPLACE; + mod->sml_desc = ad_parentUUID; + mod->sml_type = ad_parentUUID->ad_cname; + mod->sml_values = ch_malloc( sizeof( struct berval ) * 2 ); + mod->sml_nvalues = NULL; + mod->sml_numvals = 1; + mod->sml_next = NULL; + + ber_dupbv( &mod->sml_values[0], &pmod->pguid ); + BER_BVZERO( &mod->sml_values[1] ); + + op->o_req_dn = pmod->ndn; + op->o_req_ndn = pmod->ndn; + + op->orm_modlist = mod; + op->o_bd->be_modify( op, &rs2 ); + slap_mods_free( op->orm_modlist, 1 ); + if ( rs2.sr_err == LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "%s: pguid_repair: entry DN=\"%s\" repaired\n", + op->o_log_prefix, pmod->ndn.bv_val, 0 ); + nrepaired++; + + } else { + Debug( LDAP_DEBUG_ANY, "%s: pguid_repair: entry DN=\"%s\" repair failed (%d)\n", + op->o_log_prefix, pmod->ndn.bv_val, rs2.sr_err ); + } + + pnext = pmod->next; + op->o_tmpfree( pmod, op->o_tmpmemctx ); + pmod = pnext; + } + +done_search:; + op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx ); + filter_free_x( op, op->ors_filter, 1 ); + + Log1( LDAP_DEBUG_STATS, LDAP_LEVEL_INFO, + "pguid: repaired=%d\n", nrepaired ); + + return rs.sr_err; +} + +/* search all entries without parentUUID; "repair" them */ +static int +pguid_db_open( + BackendDB *be, + ConfigReply *cr ) +{ + if ( SLAP_SINGLE_SHADOW( be ) ) { + Log1( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, + "pguid incompatible with shadow database \"%s\".\n", + be->be_suffix[ 0 ].bv_val ); + return 1; + } + + pguid_repair( be ); + + return 0; +} + +static struct { + char *desc; + AttributeDescription **adp; +} as[] = { + { "( 1.3.6.1.4.1.4203.666.1.59 " + "NAME 'parentUUID' " + "DESC 'the value of the entryUUID of the parent' " + "EQUALITY UUIDMatch " + "ORDERING UUIDOrderingMatch " + "SYNTAX 1.3.6.1.1.16.1 " + "USAGE dSAOperation " + "SINGLE-VALUE " + "NO-USER-MODIFICATION " + ")", + &ad_parentUUID }, + { NULL } +}; + +int +pguid_initialize(void) +{ + int code, i; + + for ( i = 0; as[ i ].desc != NULL; i++ ) { + code = register_at( as[ i ].desc, as[ i ].adp, 0 ); + if ( code ) { + Debug( LDAP_DEBUG_ANY, + "pguid_initialize: register_at #%d failed\n", + i, 0, 0 ); + return code; + } + + /* Allow Manager to set these as needed */ + if ( is_at_no_user_mod( (*as[ i ].adp)->ad_type ) ) { + (*as[ i ].adp)->ad_type->sat_flags |= + SLAP_AT_MANAGEABLE; + } + } + + pguid.on_bi.bi_type = "pguid"; + + pguid.on_bi.bi_op_add = pguid_op_add; + pguid.on_bi.bi_op_modrdn = pguid_op_rename; + + pguid.on_bi.bi_db_init = pguid_db_init; + pguid.on_bi.bi_db_open = pguid_db_open; + + return overlay_register( &pguid ); +} + +#if SLAPD_OVER_PGUID == SLAPD_MOD_DYNAMIC +int +init_module( int argc, char *argv[] ) +{ + return pguid_initialize(); +} +#endif /* SLAPD_OVER_PGUID == SLAPD_MOD_DYNAMIC */ + +#endif /* SLAPD_OVER_PGUID */ diff --git a/contrib/slapd-modules/samba4/rdnval.c b/contrib/slapd-modules/samba4/rdnval.c new file mode 100644 index 0000000..95b2d4f --- /dev/null +++ b/contrib/slapd-modules/samba4/rdnval.c @@ -0,0 +1,658 @@ +/* rdnval.c - RDN value overlay */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 1998-2021 The OpenLDAP Foundation. + * Portions Copyright 2008 Pierangelo Masarati. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by Pierangelo Masarati + * for inclusion in OpenLDAP Software. + */ + +#include "portable.h" + +#ifdef SLAPD_OVER_RDNVAL + +#include <stdio.h> + +#include "ac/string.h" +#include "ac/socket.h" + +#include "slap.h" +#include "config.h" + +#include "lutil.h" + +/* + * Maintain an attribute (rdnValue) that contains the values of each AVA + * that builds up the RDN of an entry. This is required for interoperation + * with Samba4. It mimics the "name" attribute provided by Active Directory. + * The naming attributes must be directoryString-valued, or compatible. + * For example, IA5String values are cast into directoryString unless + * consisting of the empty string (""). + */ + +static AttributeDescription *ad_rdnValue; +static Syntax *syn_IA5String; + +static slap_overinst rdnval; + +static int +rdnval_is_valid( AttributeDescription *desc, struct berval *value ) +{ + if ( desc->ad_type->sat_syntax == slap_schema.si_syn_directoryString ) { + return 1; + } + + if ( desc->ad_type->sat_syntax == syn_IA5String + && !BER_BVISEMPTY( value ) ) + { + return 1; + } + + return 0; +} + +static int +rdnval_unique_check_cb( Operation *op, SlapReply *rs ) +{ + if ( rs->sr_type == REP_SEARCH ) { + int *p = (int *)op->o_callback->sc_private; + (*p)++; + } + + return 0; +} + +static int +rdnval_unique_check( Operation *op, BerVarray vals ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + + BackendDB db = *op->o_bd; + Operation op2 = *op; + SlapReply rs2 = { 0 }; + int i; + BerVarray fvals; + char *ptr; + int gotit = 0; + slap_callback cb = { 0 }; + + /* short-circuit attempts to add suffix entry */ + if ( op->o_tag == LDAP_REQ_ADD + && be_issuffix( op->o_bd, &op->o_req_ndn ) ) + { + return LDAP_SUCCESS; + } + + op2.o_bd = &db; + op2.o_bd->bd_info = (BackendInfo *)on->on_info; + op2.o_tag = LDAP_REQ_SEARCH; + op2.o_dn = op->o_bd->be_rootdn; + op2.o_ndn = op->o_bd->be_rootndn; + op2.o_callback = &cb; + cb.sc_response = rdnval_unique_check_cb; + cb.sc_private = (void *)&gotit; + + dnParent( &op->o_req_ndn, &op2.o_req_dn ); + op2.o_req_ndn = op2.o_req_dn; + + op2.ors_limit = NULL; + op2.ors_slimit = 1; + op2.ors_tlimit = SLAP_NO_LIMIT; + op2.ors_attrs = slap_anlist_no_attrs; + op2.ors_attrsonly = 1; + op2.ors_deref = LDAP_DEREF_NEVER; + op2.ors_scope = LDAP_SCOPE_ONELEVEL; + + for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) + /* just count */ ; + + fvals = op->o_tmpcalloc( sizeof( struct berval ), i + 1, + op->o_tmpmemctx ); + + op2.ors_filterstr.bv_len = 0; + if ( i > 1 ) { + op2.ors_filterstr.bv_len = STRLENOF( "(&)" ); + } + + for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { + ldap_bv2escaped_filter_value_x( &vals[ i ], &fvals[ i ], + 1, op->o_tmpmemctx ); + op2.ors_filterstr.bv_len += ad_rdnValue->ad_cname.bv_len + + fvals[ i ].bv_len + STRLENOF( "(=)" ); + } + + op2.ors_filterstr.bv_val = op->o_tmpalloc( op2.ors_filterstr.bv_len + 1, op->o_tmpmemctx ); + + ptr = op2.ors_filterstr.bv_val; + if ( i > 1 ) { + ptr = lutil_strcopy( ptr, "(&" ); + } + for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { + *ptr++ = '('; + ptr = lutil_strncopy( ptr, ad_rdnValue->ad_cname.bv_val, ad_rdnValue->ad_cname.bv_len ); + *ptr++ = '='; + ptr = lutil_strncopy( ptr, fvals[ i ].bv_val, fvals[ i ].bv_len ); + *ptr++ = ')'; + } + + if ( i > 1 ) { + *ptr++ = ')'; + } + *ptr = '\0'; + + assert( ptr == op2.ors_filterstr.bv_val + op2.ors_filterstr.bv_len ); + op2.ors_filter = str2filter_x( op, op2.ors_filterstr.bv_val ); + assert( op2.ors_filter != NULL ); + + (void)op2.o_bd->be_search( &op2, &rs2 ); + + filter_free_x( op, op2.ors_filter, 1 ); + op->o_tmpfree( op2.ors_filterstr.bv_val, op->o_tmpmemctx ); + for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { + if ( vals[ i ].bv_val != fvals[ i ].bv_val ) { + op->o_tmpfree( fvals[ i ].bv_val, op->o_tmpmemctx ); + } + } + op->o_tmpfree( fvals, op->o_tmpmemctx ); + + if ( rs2.sr_err != LDAP_SUCCESS || gotit > 0 ) { + return LDAP_CONSTRAINT_VIOLATION; + } + + return LDAP_SUCCESS; +} + +static int +rdnval_rdn2vals( + Operation *op, + SlapReply *rs, + struct berval *dn, + struct berval *ndn, + BerVarray *valsp, + BerVarray *nvalsp, + int *numvalsp ) +{ + LDAPRDN rdn = NULL, nrdn = NULL; + int nAVA, i; + + assert( *valsp == NULL ); + assert( *nvalsp == NULL ); + + *numvalsp = 0; + + if ( ldap_bv2rdn_x( dn, &rdn, (char **)&rs->sr_text, + LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx ) ) + { + Debug( LDAP_DEBUG_TRACE, + "%s rdnval: can't figure out " + "type(s)/value(s) of rdn DN=\"%s\"\n", + op->o_log_prefix, dn->bv_val, 0 ); + rs->sr_err = LDAP_INVALID_DN_SYNTAX; + rs->sr_text = "unknown type(s) used in RDN"; + + goto done; + } + + if ( ldap_bv2rdn_x( ndn, &nrdn, + (char **)&rs->sr_text, LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx ) ) + { + Debug( LDAP_DEBUG_TRACE, + "%s rdnval: can't figure out " + "type(s)/value(s) of normalized rdn DN=\"%s\"\n", + op->o_log_prefix, ndn->bv_val, 0 ); + rs->sr_err = LDAP_INVALID_DN_SYNTAX; + rs->sr_text = "unknown type(s) used in RDN"; + + goto done; + } + + for ( nAVA = 0; rdn[ nAVA ]; nAVA++ ) + /* count'em */ ; + + /* NOTE: we assume rdn and nrdn contain the same AVAs! */ + + *valsp = SLAP_CALLOC( sizeof( struct berval ), nAVA + 1 ); + *nvalsp = SLAP_CALLOC( sizeof( struct berval ), nAVA + 1 ); + + /* Add new attribute values to the entry */ + for ( i = 0; rdn[ i ]; i++ ) { + AttributeDescription *desc = NULL; + + rs->sr_err = slap_bv2ad( &rdn[ i ]->la_attr, + &desc, &rs->sr_text ); + + if ( rs->sr_err != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, + "%s rdnval: %s: %s\n", + op->o_log_prefix, + rs->sr_text, + rdn[ i ]->la_attr.bv_val ); + goto done; + } + + if ( !rdnval_is_valid( desc, &rdn[ i ]->la_value ) ) { + Debug( LDAP_DEBUG_TRACE, + "%s rdnval: syntax of naming attribute '%s' " + "not compatible with directoryString", + op->o_log_prefix, rdn[ i ]->la_attr.bv_val, 0 ); + continue; + } + + if ( value_find_ex( desc, + SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | + SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, + *nvalsp, + &nrdn[ i ]->la_value, + op->o_tmpmemctx ) + == LDAP_NO_SUCH_ATTRIBUTE ) + { + ber_dupbv( &(*valsp)[ *numvalsp ], &rdn[ i ]->la_value ); + ber_dupbv( &(*nvalsp)[ *numvalsp ], &nrdn[ i ]->la_value ); + + (*numvalsp)++; + } + } + + if ( rdnval_unique_check( op, *valsp ) != LDAP_SUCCESS ) { + rs->sr_err = LDAP_CONSTRAINT_VIOLATION; + rs->sr_text = "rdnValue not unique within siblings"; + goto done; + } + +done:; + if ( rdn != NULL ) { + ldap_rdnfree_x( rdn, op->o_tmpmemctx ); + } + + if ( nrdn != NULL ) { + ldap_rdnfree_x( nrdn, op->o_tmpmemctx ); + } + + if ( rs->sr_err != LDAP_SUCCESS ) { + if ( *valsp != NULL ) { + ber_bvarray_free( *valsp ); + ber_bvarray_free( *nvalsp ); + *valsp = NULL; + *nvalsp = NULL; + *numvalsp = 0; + } + } + + return rs->sr_err; +} + +static int +rdnval_op_add( Operation *op, SlapReply *rs ) +{ + Attribute *a, **ap; + int numvals = 0; + BerVarray vals = NULL, nvals = NULL; + int rc; + + /* NOTE: should we accept an entry still in mods format? */ + assert( op->ora_e != NULL ); + + if ( BER_BVISEMPTY( &op->ora_e->e_nname ) ) { + return SLAP_CB_CONTINUE; + } + + a = attr_find( op->ora_e->e_attrs, ad_rdnValue ); + if ( a != NULL ) { + /* TODO: check consistency? */ + return SLAP_CB_CONTINUE; + } + + rc = rdnval_rdn2vals( op, rs, &op->ora_e->e_name, &op->ora_e->e_nname, + &vals, &nvals, &numvals ); + if ( rc != LDAP_SUCCESS ) { + send_ldap_result( op, rs ); + } + + a = attr_alloc( ad_rdnValue ); + + a->a_vals = vals; + a->a_nvals = nvals; + a->a_numvals = numvals; + + for ( ap = &op->ora_e->e_attrs; *ap != NULL; ap = &(*ap)->a_next ) + /* goto tail */ ; + + *ap = a; + + return SLAP_CB_CONTINUE; +} + +static int +rdnval_op_rename( Operation *op, SlapReply *rs ) +{ + Modifications *ml, **mlp; + int numvals = 0; + BerVarray vals = NULL, nvals = NULL; + struct berval old; + int rc; + + dnRdn( &op->o_req_ndn, &old ); + if ( dn_match( &old, &op->orr_nnewrdn ) ) { + return SLAP_CB_CONTINUE; + } + + rc = rdnval_rdn2vals( op, rs, &op->orr_newrdn, &op->orr_nnewrdn, + &vals, &nvals, &numvals ); + if ( rc != LDAP_SUCCESS ) { + send_ldap_result( op, rs ); + } + + ml = SLAP_CALLOC( sizeof( Modifications ), 1 ); + ml->sml_values = vals; + ml->sml_nvalues = nvals; + + ml->sml_numvals = numvals; + + ml->sml_op = LDAP_MOD_REPLACE; + ml->sml_flags = SLAP_MOD_INTERNAL; + ml->sml_desc = ad_rdnValue; + ml->sml_type = ad_rdnValue->ad_cname; + + for ( mlp = &op->orr_modlist; *mlp != NULL; mlp = &(*mlp)->sml_next ) + /* goto tail */ ; + + *mlp = ml; + + return SLAP_CB_CONTINUE; +} + +static int +rdnval_db_init( + BackendDB *be, + ConfigReply *cr) +{ + if ( SLAP_ISGLOBALOVERLAY( be ) ) { + Log0( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, + "rdnval_db_init: rdnval cannot be used as global overlay.\n" ); + return 1; + } + + if ( be->be_nsuffix == NULL ) { + Log0( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, + "rdnval_db_init: database must have suffix\n" ); + return 1; + } + + if ( BER_BVISNULL( &be->be_rootndn ) || BER_BVISEMPTY( &be->be_rootndn ) ) { + Log1( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, + "rdnval_db_init: missing rootdn for database DN=\"%s\", YMMV\n", + be->be_suffix[ 0 ].bv_val ); + } + + return 0; +} + +typedef struct rdnval_mod_t { + struct berval ndn; + BerVarray vals; + BerVarray nvals; + int numvals; + struct rdnval_mod_t *next; +} rdnval_mod_t; + +typedef struct { + BackendDB *bd; + rdnval_mod_t *mods; +} rdnval_repair_cb_t; + +static int +rdnval_repair_cb( Operation *op, SlapReply *rs ) +{ + int rc; + rdnval_repair_cb_t *rcb = op->o_callback->sc_private; + rdnval_mod_t *mod; + BerVarray vals = NULL, nvals = NULL; + int numvals = 0; + ber_len_t len; + BackendDB *save_bd = op->o_bd; + + switch ( rs->sr_type ) { + case REP_SEARCH: + break; + + case REP_SEARCHREF: + case REP_RESULT: + return rs->sr_err; + + default: + assert( 0 ); + } + + assert( rs->sr_entry != NULL ); + + op->o_bd = rcb->bd; + rc = rdnval_rdn2vals( op, rs, &rs->sr_entry->e_name, &rs->sr_entry->e_nname, + &vals, &nvals, &numvals ); + op->o_bd = save_bd; + if ( rc != LDAP_SUCCESS ) { + return 0; + } + + len = sizeof( rdnval_mod_t ) + rs->sr_entry->e_nname.bv_len + 1; + mod = op->o_tmpalloc( len, op->o_tmpmemctx ); + mod->ndn.bv_len = rs->sr_entry->e_nname.bv_len; + mod->ndn.bv_val = (char *)&mod[1]; + lutil_strncopy( mod->ndn.bv_val, rs->sr_entry->e_nname.bv_val, rs->sr_entry->e_nname.bv_len ); + mod->vals = vals; + mod->nvals = nvals; + mod->numvals = numvals; + + mod->next = rcb->mods; + rcb->mods = mod; + + Debug( LDAP_DEBUG_TRACE, "%s: rdnval_repair_cb: scheduling entry DN=\"%s\" for repair\n", + op->o_log_prefix, rs->sr_entry->e_name.bv_val, 0 ); + + return 0; +} + +static int +rdnval_repair( BackendDB *be ) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + void *ctx = ldap_pvt_thread_pool_context(); + Connection conn = { 0 }; + OperationBuffer opbuf; + Operation *op; + BackendDB db; + slap_callback sc = { 0 }; + rdnval_repair_cb_t rcb = { 0 }; + SlapReply rs = { REP_RESULT }; + rdnval_mod_t *rmod; + int nrepaired = 0; + + connection_fake_init2( &conn, &opbuf, ctx, 0 ); + op = &opbuf.ob_op; + + op->o_tag = LDAP_REQ_SEARCH; + memset( &op->oq_search, 0, sizeof( op->oq_search ) ); + + assert( !BER_BVISNULL( &be->be_nsuffix[ 0 ] ) ); + + op->o_bd = select_backend( &be->be_nsuffix[ 0 ], 0 ); + assert( op->o_bd != NULL ); + assert( op->o_bd->be_nsuffix != NULL ); + + op->o_req_dn = op->o_bd->be_suffix[ 0 ]; + op->o_req_ndn = op->o_bd->be_nsuffix[ 0 ]; + + op->o_dn = op->o_bd->be_rootdn; + op->o_ndn = op->o_bd->be_rootndn; + + op->ors_scope = LDAP_SCOPE_SUBTREE; + op->ors_tlimit = SLAP_NO_LIMIT; + op->ors_slimit = SLAP_NO_LIMIT; + op->ors_attrs = slap_anlist_no_attrs; + + op->ors_filterstr.bv_len = STRLENOF( "(!(=*))" ) + ad_rdnValue->ad_cname.bv_len; + op->ors_filterstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len + 1, op->o_tmpmemctx ); + snprintf( op->ors_filterstr.bv_val, op->ors_filterstr.bv_len + 1, + "(!(%s=*))", ad_rdnValue->ad_cname.bv_val ); + + op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val ); + if ( op->ors_filter == NULL ) { + rs.sr_err = LDAP_OTHER; + goto done_search; + } + + op->o_callback = ≻ + sc.sc_response = rdnval_repair_cb; + sc.sc_private = &rcb; + rcb.bd = &db; + db = *be; + db.bd_info = (BackendInfo *)on; + + (void)op->o_bd->bd_info->bi_op_search( op, &rs ); + + op->o_tag = LDAP_REQ_MODIFY; + sc.sc_response = slap_null_cb; + sc.sc_private = NULL; + memset( &op->oq_modify, 0, sizeof( req_modify_s ) ); + + for ( rmod = rcb.mods; rmod != NULL; ) { + rdnval_mod_t *rnext; + + Modifications *mod; + SlapReply rs2 = { REP_RESULT }; + + mod = (Modifications *) ch_malloc( sizeof( Modifications ) ); + mod->sml_flags = SLAP_MOD_INTERNAL; + mod->sml_op = LDAP_MOD_REPLACE; + mod->sml_desc = ad_rdnValue; + mod->sml_type = ad_rdnValue->ad_cname; + mod->sml_values = rmod->vals; + mod->sml_nvalues = rmod->nvals; + mod->sml_numvals = rmod->numvals; + mod->sml_next = NULL; + + op->o_req_dn = rmod->ndn; + op->o_req_ndn = rmod->ndn; + + op->orm_modlist = mod; + + op->o_bd->be_modify( op, &rs2 ); + + slap_mods_free( op->orm_modlist, 1 ); + if ( rs2.sr_err == LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "%s: rdnval_repair: entry DN=\"%s\" repaired\n", + op->o_log_prefix, rmod->ndn.bv_val, 0 ); + nrepaired++; + + } else { + Debug( LDAP_DEBUG_ANY, "%s: rdnval_repair: entry DN=\"%s\" repair failed (%d)\n", + op->o_log_prefix, rmod->ndn.bv_val, rs2.sr_err ); + } + + rnext = rmod->next; + op->o_tmpfree( rmod, op->o_tmpmemctx ); + rmod = rnext; + } + +done_search:; + op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx ); + filter_free_x( op, op->ors_filter, 1 ); + + Log1( LDAP_DEBUG_STATS, LDAP_LEVEL_INFO, + "rdnval: repaired=%d\n", nrepaired ); + + return 0; +} + +/* search all entries without parentUUID; "repair" them */ +static int +rdnval_db_open( + BackendDB *be, + ConfigReply *cr ) +{ + if ( SLAP_SINGLE_SHADOW( be ) ) { + Log1( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, + "rdnval incompatible with shadow database \"%s\".\n", + be->be_suffix[ 0 ].bv_val ); + return 1; + } + + return rdnval_repair( be ); +} + +static struct { + char *desc; + AttributeDescription **adp; +} as[] = { + { "( 1.3.6.1.4.1.4203.666.1.58 " + "NAME 'rdnValue' " + "DESC 'the value of the naming attributes' " + "SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' " + "EQUALITY caseIgnoreMatch " + "USAGE dSAOperation " + "NO-USER-MODIFICATION " + ")", + &ad_rdnValue }, + { NULL } +}; + +int +rdnval_initialize(void) +{ + int code, i; + + for ( i = 0; as[ i ].desc != NULL; i++ ) { + code = register_at( as[ i ].desc, as[ i ].adp, 0 ); + if ( code ) { + Debug( LDAP_DEBUG_ANY, + "rdnval_initialize: register_at #%d failed\n", + i, 0, 0 ); + return code; + } + + /* Allow Manager to set these as needed */ + if ( is_at_no_user_mod( (*as[ i ].adp)->ad_type ) ) { + (*as[ i ].adp)->ad_type->sat_flags |= + SLAP_AT_MANAGEABLE; + } + } + + syn_IA5String = syn_find( "1.3.6.1.4.1.1466.115.121.1.26" ); + if ( syn_IA5String == NULL ) { + Debug( LDAP_DEBUG_ANY, + "rdnval_initialize: unable to find syntax '1.3.6.1.4.1.1466.115.121.1.26' (IA5String)\n", + 0, 0, 0 ); + return LDAP_OTHER; + } + + rdnval.on_bi.bi_type = "rdnval"; + + rdnval.on_bi.bi_op_add = rdnval_op_add; + rdnval.on_bi.bi_op_modrdn = rdnval_op_rename; + + rdnval.on_bi.bi_db_init = rdnval_db_init; + rdnval.on_bi.bi_db_open = rdnval_db_open; + + return overlay_register( &rdnval ); +} + +#if SLAPD_OVER_RDNVAL == SLAPD_MOD_DYNAMIC +int +init_module( int argc, char *argv[] ) +{ + return rdnval_initialize(); +} +#endif /* SLAPD_OVER_RDNVAL == SLAPD_MOD_DYNAMIC */ + +#endif /* SLAPD_OVER_RDNVAL */ diff --git a/contrib/slapd-modules/samba4/vernum.c b/contrib/slapd-modules/samba4/vernum.c new file mode 100644 index 0000000..6035d86 --- /dev/null +++ b/contrib/slapd-modules/samba4/vernum.c @@ -0,0 +1,459 @@ +/* vernum.c - RDN value overlay */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 1998-2021 The OpenLDAP Foundation. + * Portions Copyright 2008 Pierangelo Masarati. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by Pierangelo Masarati + * for inclusion in OpenLDAP Software. + */ + +#include "portable.h" + +#ifdef SLAPD_OVER_VERNUM + +#include <stdio.h> + +#include "ac/string.h" +#include "ac/socket.h" + +#include "slap.h" +#include "config.h" + +#include "lutil.h" + +/* + * Maintain an attribute (e.g. msDS-KeyVersionNumber) that consists + * in a counter of modifications of another attribute (e.g. unicodePwd). + */ + +typedef struct vernum_t { + AttributeDescription *vn_attr; + AttributeDescription *vn_vernum; +} vernum_t; + +static AttributeDescription *ad_msDS_KeyVersionNumber; + +static struct berval val_init = BER_BVC( "0" ); +static slap_overinst vernum; + +static int +vernum_op_add( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; + vernum_t *vn = (vernum_t *)on->on_bi.bi_private; + + Attribute *a, **ap; + int rc; + + /* NOTE: should we accept an entry still in mods format? */ + assert( op->ora_e != NULL ); + + if ( BER_BVISEMPTY( &op->ora_e->e_nname ) ) { + return SLAP_CB_CONTINUE; + } + + a = attr_find( op->ora_e->e_attrs, vn->vn_attr ); + if ( a == NULL ) { + return SLAP_CB_CONTINUE; + } + + if ( attr_find( op->ora_e->e_attrs, vn->vn_vernum ) != NULL ) { + /* already present - leave it alone */ + return SLAP_CB_CONTINUE; + } + + a = attr_alloc( vn->vn_vernum ); + + value_add_one( &a->a_vals, &val_init ); + a->a_nvals = a->a_vals; + a->a_numvals = 1; + + for ( ap = &op->ora_e->e_attrs; *ap != NULL; ap = &(*ap)->a_next ) + /* goto tail */ ; + + *ap = a; + + return SLAP_CB_CONTINUE; +} + +static int +vernum_op_modify( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; + vernum_t *vn = (vernum_t *)on->on_bi.bi_private; + + Modifications *ml, **mlp; + struct berval val = BER_BVC( "1" ); + int rc; + unsigned got = 0; + + for ( ml = op->orm_modlist; ml != NULL; ml = ml->sml_next ) { + if ( ml->sml_desc == vn->vn_vernum ) { + /* already present - leave it alone + * (or should we increment it anyway?) */ + return SLAP_CB_CONTINUE; + } + + if ( ml->sml_desc == vn->vn_attr ) { + got = 1; + } + } + + if ( !got ) { + return SLAP_CB_CONTINUE; + } + + for ( mlp = &op->orm_modlist; *mlp != NULL; mlp = &(*mlp)->sml_next ) + /* goto tail */ ; + + /* ITS#6561 */ +#ifdef SLAP_MOD_ADD_IF_NOT_PRESENT + /* the initial value is only added if the vernum attr is not present */ + ml = SLAP_CALLOC( sizeof( Modifications ), 1 ); + ml->sml_values = SLAP_CALLOC( sizeof( struct berval ) , 2 ); + value_add_one( &ml->sml_values, &val_init ); + ml->sml_nvalues = NULL; + ml->sml_numvals = 1; + ml->sml_op = SLAP_MOD_ADD_IF_NOT_PRESENT; + ml->sml_flags = SLAP_MOD_INTERNAL; + ml->sml_desc = vn->vn_vernum; + ml->sml_type = vn->vn_vernum->ad_cname; + + *mlp = ml; + mlp = &ml->sml_next; +#endif /* SLAP_MOD_ADD_IF_NOT_PRESENT */ + + /* this increments by 1 the vernum attr */ + ml = SLAP_CALLOC( sizeof( Modifications ), 1 ); + ml->sml_values = SLAP_CALLOC( sizeof( struct berval ) , 2 ); + value_add_one( &ml->sml_values, &val ); + ml->sml_nvalues = NULL; + ml->sml_numvals = 1; + ml->sml_op = LDAP_MOD_INCREMENT; + ml->sml_flags = SLAP_MOD_INTERNAL; + ml->sml_desc = vn->vn_vernum; + ml->sml_type = vn->vn_vernum->ad_cname; + + *mlp = ml; + + return SLAP_CB_CONTINUE; +} + +static int +vernum_db_init( + BackendDB *be, + ConfigReply *cr) +{ + slap_overinst *on = (slap_overinst *) be->bd_info; + vernum_t *vn = NULL; + + if ( SLAP_ISGLOBALOVERLAY( be ) ) { + Log0( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, + "vernum_db_init: vernum cannot be used as global overlay.\n" ); + return 1; + } + + if ( be->be_nsuffix == NULL ) { + Log0( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, + "vernum_db_init: database must have suffix\n" ); + return 1; + } + + if ( BER_BVISNULL( &be->be_rootndn ) || BER_BVISEMPTY( &be->be_rootndn ) ) { + Log1( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, + "vernum_db_init: missing rootdn for database DN=\"%s\", YMMV\n", + be->be_suffix[ 0 ].bv_val ); + } + + vn = (vernum_t *)ch_calloc( 1, sizeof( vernum_t ) ); + + on->on_bi.bi_private = (void *)vn; + + return 0; +} + +typedef struct vernum_mod_t { + struct berval ndn; + struct vernum_mod_t *next; +} vernum_mod_t; + +typedef struct { + BackendDB *bd; + vernum_mod_t *mods; +} vernum_repair_cb_t; + +static int +vernum_repair_cb( Operation *op, SlapReply *rs ) +{ + int rc; + vernum_repair_cb_t *rcb = op->o_callback->sc_private; + vernum_mod_t *mod; + ber_len_t len; + BackendDB *save_bd = op->o_bd; + + switch ( rs->sr_type ) { + case REP_SEARCH: + break; + + case REP_SEARCHREF: + case REP_RESULT: + return rs->sr_err; + + default: + assert( 0 ); + } + + assert( rs->sr_entry != NULL ); + + len = sizeof( vernum_mod_t ) + rs->sr_entry->e_nname.bv_len + 1; + mod = op->o_tmpalloc( len, op->o_tmpmemctx ); + mod->ndn.bv_len = rs->sr_entry->e_nname.bv_len; + mod->ndn.bv_val = (char *)&mod[1]; + lutil_strncopy( mod->ndn.bv_val, rs->sr_entry->e_nname.bv_val, rs->sr_entry->e_nname.bv_len ); + + mod->next = rcb->mods; + rcb->mods = mod; + + Debug( LDAP_DEBUG_TRACE, "%s: vernum_repair_cb: scheduling entry DN=\"%s\" for repair\n", + op->o_log_prefix, rs->sr_entry->e_name.bv_val, 0 ); + + return 0; +} + +static int +vernum_repair( BackendDB *be ) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + vernum_t *vn = (vernum_t *)on->on_bi.bi_private; + void *ctx = ldap_pvt_thread_pool_context(); + Connection conn = { 0 }; + OperationBuffer opbuf; + Operation *op; + BackendDB db; + slap_callback sc = { 0 }; + vernum_repair_cb_t rcb = { 0 }; + SlapReply rs = { REP_RESULT }; + vernum_mod_t *rmod; + int nrepaired = 0; + + connection_fake_init2( &conn, &opbuf, ctx, 0 ); + op = &opbuf.ob_op; + + op->o_tag = LDAP_REQ_SEARCH; + memset( &op->oq_search, 0, sizeof( op->oq_search ) ); + + assert( !BER_BVISNULL( &be->be_nsuffix[ 0 ] ) ); + + op->o_bd = select_backend( &be->be_nsuffix[ 0 ], 0 ); + assert( op->o_bd != NULL ); + assert( op->o_bd->be_nsuffix != NULL ); + + op->o_req_dn = op->o_bd->be_suffix[ 0 ]; + op->o_req_ndn = op->o_bd->be_nsuffix[ 0 ]; + + op->o_dn = op->o_bd->be_rootdn; + op->o_ndn = op->o_bd->be_rootndn; + + op->ors_scope = LDAP_SCOPE_SUBTREE; + op->ors_tlimit = SLAP_NO_LIMIT; + op->ors_slimit = SLAP_NO_LIMIT; + op->ors_attrs = slap_anlist_no_attrs; + + op->ors_filterstr.bv_len = STRLENOF( "(&(=*)(!(=*)))" ) + + vn->vn_attr->ad_cname.bv_len + + vn->vn_vernum->ad_cname.bv_len; + op->ors_filterstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len + 1, op->o_tmpmemctx ); + snprintf( op->ors_filterstr.bv_val, op->ors_filterstr.bv_len + 1, + "(&(%s=*)(!(%s=*)))", + vn->vn_attr->ad_cname.bv_val, + vn->vn_vernum->ad_cname.bv_val ); + + op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val ); + if ( op->ors_filter == NULL ) { + rs.sr_err = LDAP_OTHER; + goto done_search; + } + + op->o_callback = ≻ + sc.sc_response = vernum_repair_cb; + sc.sc_private = &rcb; + rcb.bd = &db; + db = *be; + db.bd_info = (BackendInfo *)on; + + (void)op->o_bd->bd_info->bi_op_search( op, &rs ); + + op->o_tag = LDAP_REQ_MODIFY; + sc.sc_response = slap_null_cb; + sc.sc_private = NULL; + memset( &op->oq_modify, 0, sizeof( req_modify_s ) ); + + for ( rmod = rcb.mods; rmod != NULL; ) { + vernum_mod_t *rnext; + Modifications mod; + struct berval vals[2] = { BER_BVNULL }; + SlapReply rs2 = { REP_RESULT }; + + mod.sml_flags = SLAP_MOD_INTERNAL; + mod.sml_op = LDAP_MOD_REPLACE; + mod.sml_desc = vn->vn_vernum; + mod.sml_type = vn->vn_vernum->ad_cname; + mod.sml_values = vals; + mod.sml_values[0] = val_init; + mod.sml_nvalues = NULL; + mod.sml_numvals = 1; + mod.sml_next = NULL; + + op->o_req_dn = rmod->ndn; + op->o_req_ndn = rmod->ndn; + + op->orm_modlist = &mod; + + op->o_bd->be_modify( op, &rs2 ); + + slap_mods_free( op->orm_modlist->sml_next, 1 ); + if ( rs2.sr_err == LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "%s: vernum_repair: entry DN=\"%s\" repaired\n", + op->o_log_prefix, rmod->ndn.bv_val, 0 ); + nrepaired++; + + } else { + Debug( LDAP_DEBUG_ANY, "%s: vernum_repair: entry DN=\"%s\" repair failed (%d)\n", + op->o_log_prefix, rmod->ndn.bv_val, rs2.sr_err ); + } + + rnext = rmod->next; + op->o_tmpfree( rmod, op->o_tmpmemctx ); + rmod = rnext; + } + +done_search:; + op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx ); + filter_free_x( op, op->ors_filter, 1 ); + + Log1( LDAP_DEBUG_STATS, LDAP_LEVEL_INFO, + "vernum: repaired=%d\n", nrepaired ); + + return 0; +} + +static int +vernum_db_open( + BackendDB *be, + ConfigReply *cr ) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + vernum_t *vn = (vernum_t *)on->on_bi.bi_private; + + if ( SLAP_SINGLE_SHADOW( be ) ) { + Log1( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, + "vernum incompatible with shadow database \"%s\".\n", + be->be_suffix[ 0 ].bv_val ); + return 1; + } + + /* default: unicodePwd & msDS-KeyVersionNumber */ + if ( vn->vn_attr == NULL ) { + const char *text = NULL; + int rc; + + rc = slap_str2ad( "unicodePwd", &vn->vn_attr, &text ); + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, "vernum: unable to find attribute 'unicodePwd' (%d: %s)\n", + rc, text, 0 ); + return 1; + } + + vn->vn_vernum = ad_msDS_KeyVersionNumber; + } + + return vernum_repair( be ); +} + +static int +vernum_db_destroy( + BackendDB *be, + ConfigReply *cr ) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + vernum_t *vn = (vernum_t *)on->on_bi.bi_private; + + if ( vn ) { + ch_free( vn ); + on->on_bi.bi_private = NULL; + } + + return 0; +} + +static struct { + char *desc; + AttributeDescription **adp; +} as[] = { + { "( 1.2.840.113556.1.4.1782 " + "NAME 'msDS-KeyVersionNumber' " + "DESC 'in the original specification the syntax is 2.5.5.9' " + "SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' " + "EQUALITY integerMatch " + "SINGLE-VALUE " + "USAGE dSAOperation " + "NO-USER-MODIFICATION " + ")", + &ad_msDS_KeyVersionNumber }, + { NULL } +}; + +int +vernum_initialize(void) +{ + int code, i; + + for ( i = 0; as[ i ].desc != NULL; i++ ) { + code = register_at( as[ i ].desc, as[ i ].adp, 0 ); + if ( code ) { + Debug( LDAP_DEBUG_ANY, + "vernum_initialize: register_at #%d failed\n", + i, 0, 0 ); + return code; + } + + /* Allow Manager to set these as needed */ + if ( is_at_no_user_mod( (*as[ i ].adp)->ad_type ) ) { + (*as[ i ].adp)->ad_type->sat_flags |= + SLAP_AT_MANAGEABLE; + } + } + + vernum.on_bi.bi_type = "vernum"; + + vernum.on_bi.bi_op_add = vernum_op_add; + vernum.on_bi.bi_op_modify = vernum_op_modify; + + vernum.on_bi.bi_db_init = vernum_db_init; + vernum.on_bi.bi_db_open = vernum_db_open; + vernum.on_bi.bi_db_destroy = vernum_db_destroy; + + return overlay_register( &vernum ); +} + +#if SLAPD_OVER_VERNUM == SLAPD_MOD_DYNAMIC +int +init_module( int argc, char *argv[] ) +{ + return vernum_initialize(); +} +#endif /* SLAPD_OVER_VERNUM == SLAPD_MOD_DYNAMIC */ + +#endif /* SLAPD_OVER_VERNUM */ diff --git a/contrib/slapd-modules/smbk5pwd/Makefile b/contrib/slapd-modules/smbk5pwd/Makefile new file mode 100644 index 0000000..7a60bc5 --- /dev/null +++ b/contrib/slapd-modules/smbk5pwd/Makefile @@ -0,0 +1,65 @@ +# $OpenLDAP$ +# This work is part of OpenLDAP Software <http://www.openldap.org/>. +# +# Copyright 1998-2021 The OpenLDAP Foundation. +# Copyright 2004 Howard Chu, Symas Corp. All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted only as authorized by the OpenLDAP +# Public License. +# +# A copy of this license is available in the file LICENSE in the +# top-level directory of the distribution or, alternatively, at +# <http://www.OpenLDAP.org/license.html>. + +LDAP_SRC = ../../.. +LDAP_BUILD = $(LDAP_SRC) +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +SSL_INC = +SSL_LIB = -lcrypto + +HEIMDAL_INC = -I/usr/heimdal/include +HEIMDAL_LIB = -L/usr/heimdal/lib -lkrb5 -lkadm5srv + +LIBTOOL = $(LDAP_BUILD)/libtool +CC = gcc +OPT = -g -O2 -Wall +# Omit DO_KRB5, DO_SAMBA or DO_SHADOW if you don't want to support it. +DEFS = -DDO_KRB5 -DDO_SAMBA -DDO_SHADOW +INCS = $(LDAP_INC) $(HEIMDAL_INC) $(SSL_INC) +LIBS = $(LDAP_LIB) $(HEIMDAL_LIB) $(SSL_LIB) + +PROGRAMS = smbk5pwd.la +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +smbk5pwd.la: smbk5pwd.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + diff --git a/contrib/slapd-modules/smbk5pwd/README b/contrib/slapd-modules/smbk5pwd/README new file mode 100644 index 0000000..ecc7cc6 --- /dev/null +++ b/contrib/slapd-modules/smbk5pwd/README @@ -0,0 +1,94 @@ +This directory contains a slapd overlay, smbk5pwd, that extends the +PasswordModify Extended Operation to update Kerberos keys and Samba +password hashes for an LDAP user. + +The Kerberos support is written for Heimdal using its hdb-ldap backend. +If a PasswordModify is performed on an entry that has the krb5KDCEntry +objectclass, then the krb5Key and krb5KeyVersionNumber will be updated +using the new password in the PasswordModify request. Additionally, a +new "{K5KEY}" password hash mechanism is provided. For krb5KDCEntries that +have this hash specifier in their userPassword attribute, Simple Binds +will be checked against the Kerberos keys of the Entry. No data is +needed after the "{K5KEY}" hash specifier in the userPassword, it is +looked up from the Entry directly. + +The Samba support is written using the Samba 3.0 LDAP schema. If a +PasswordModify is performed on an entry that has the sambaSamAccount +objectclass, then the sambaLMPassword, sambaNTPassword, and sambaPwdLastSet +attributes will be updated accordingly. + +To use the overlay, add: + + include <path to>/krb5-kdc.schema + include <path to>/samba.schema + + moduleload <path to>smbk5pwd.so + ... + + database bdb + ... + overlay smbk5pwd + +to your slapd configuration file. (You should obtain the necessary schema +files from the Heimdal and/or Samba distributions. At this time, there +are several known errors in these schema files that you will have to +correct before they will load in slapd. As of Samba 3.0 the schema looks +fine as shipped.) + +All modules compiled in (i.e. krb5 and samba) are enabled; the statement + + smbk5pwd-enable <module> + +can be used to enable only the desired one(s); legal values for <module> +are "krb5", "samba" and "shadow", if they are respectively enabled by defining +DO_KRB5, DO_SAMBA and DO_SHADOW. + +The samba module also supports the + + smbk5pwd-must-change <seconds> + +which sets the "sambaPwdMustChange" attribute accordingly to force passwd +expiry. A value of 0 disables this feature. + +The overlay now supports table-driven configuration, and thus can be run-time +loaded and configured via back-config. The layout of the entry is + + # {0}smbk5pwd, {1}bdb, config + dn: olcOverlay={0}smbk5pwd,olcDatabase={1}bdb,cn=config + objectClass: olcOverlayConfig + objectClass: olcSmbK5PwdConfig + olcOverlay: {0}smbk5pwd + olcSmbK5PwdEnable: krb5 + olcSmbK5PwdEnable: samba + olcSmbK5PwdMustChange: 2592000 + +which enables both krb5 and samba modules with a password expiry time +of 30 days. + +The provided Makefile builds both Kerberos and Samba support by default. +You must edit the Makefile to insure that the correct include and library +paths are used. You can change the DEFS macro if you only want one or the +other of Kerberos or Samba support. + +This overlay is only set up to be built as a dynamically loaded module. +On most platforms, in order for the module to be usable, all of the +library dependencies must also be available as shared libraries. + +If you need to build the overlay statically, you will have to move it into the +slapd/overlays directory and edit the Makefile and overlays.c to reference +it. You will also have to define SLAPD_OVER_SMBK5PWD to SLAPD_MOD_STATIC, +and add the relevant libraries to the main slapd link command. + +--- +This work is part of OpenLDAP Software <http://www.openldap.org/>. +Copyright 2004-2021 The OpenLDAP Foundation. +Portions Copyright 2004-2005 Howard Chu, Symas Corp. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted only as authorized by the OpenLDAP +Public License. + +A copy of this license is available in the file LICENSE in the +top-level directory of the distribution or, alternatively, at +<http://www.OpenLDAP.org/license.html>. + diff --git a/contrib/slapd-modules/smbk5pwd/smbk5pwd.c b/contrib/slapd-modules/smbk5pwd/smbk5pwd.c new file mode 100644 index 0000000..deee870 --- /dev/null +++ b/contrib/slapd-modules/smbk5pwd/smbk5pwd.c @@ -0,0 +1,1177 @@ +/* smbk5pwd.c - Overlay for managing Samba and Heimdal passwords */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2004-2021 The OpenLDAP Foundation. + * Portions Copyright 2004-2005 by Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * Support for table-driven configuration added by Pierangelo Masarati. + * Support for sambaPwdMustChange and sambaPwdCanChange added by Marco D'Ettorre. + * Support for shadowLastChange added by SATOH Fumiyasu @ OSS Technology, Inc. + */ + +#include <portable.h> + +#ifndef SLAPD_OVER_SMBK5PWD +#define SLAPD_OVER_SMBK5PWD SLAPD_MOD_DYNAMIC +#endif + +#ifdef SLAPD_OVER_SMBK5PWD + +#include <slap.h> +#include <ac/errno.h> +#include <ac/string.h> + +#include "config.h" + +#ifdef DO_KRB5 +#include <lber.h> +#include <lber_pvt.h> +#include <lutil.h> + +/* make ASN1_MALLOC_ENCODE use our allocator */ +#define malloc ch_malloc + +#include <krb5.h> +#include <kadm5/admin.h> +#include <hdb.h> + +#ifndef HDB_INTERFACE_VERSION +#define HDB_MASTER_KEY_SET master_key_set +#else +#define HDB_MASTER_KEY_SET hdb_master_key_set +#endif + +static krb5_context context; +static void *kadm_context; +static kadm5_config_params conf; +static HDB *db; + +static AttributeDescription *ad_krb5Key; +static AttributeDescription *ad_krb5KeyVersionNumber; +static AttributeDescription *ad_krb5PrincipalName; +static AttributeDescription *ad_krb5ValidEnd; +static ObjectClass *oc_krb5KDCEntry; +#endif + +#ifdef DO_SAMBA +#ifdef HAVE_GNUTLS +#include <nettle/des.h> +#include <nettle/md4.h> +typedef unsigned char DES_cblock[8]; +#elif HAVE_OPENSSL +#include <openssl/des.h> +#include <openssl/md4.h> +#else +#error Unsupported crypto backend. +#endif +#include "ldap_utf8.h" + +static AttributeDescription *ad_sambaLMPassword; +static AttributeDescription *ad_sambaNTPassword; +static AttributeDescription *ad_sambaPwdLastSet; +static AttributeDescription *ad_sambaPwdMustChange; +static AttributeDescription *ad_sambaPwdCanChange; +static ObjectClass *oc_sambaSamAccount; +#endif + +#ifdef DO_SHADOW +static AttributeDescription *ad_shadowLastChange; +static ObjectClass *oc_shadowAccount; +#endif + +/* Per-instance configuration information */ +typedef struct smbk5pwd_t { + unsigned mode; +#define SMBK5PWD_F_KRB5 (0x1U) +#define SMBK5PWD_F_SAMBA (0x2U) +#define SMBK5PWD_F_SHADOW (0x4U) + +#define SMBK5PWD_DO_KRB5(pi) ((pi)->mode & SMBK5PWD_F_KRB5) +#define SMBK5PWD_DO_SAMBA(pi) ((pi)->mode & SMBK5PWD_F_SAMBA) +#define SMBK5PWD_DO_SHADOW(pi) ((pi)->mode & SMBK5PWD_F_SHADOW) + +#ifdef DO_KRB5 + /* nothing yet */ +#endif + +#ifdef DO_SAMBA + /* How many seconds before forcing a password change? */ + time_t smb_must_change; + /* How many seconds after allowing a password change? */ + time_t smb_can_change; +#endif + +#ifdef DO_SHADOW + /* nothing yet */ +#endif +} smbk5pwd_t; + +static const unsigned SMBK5PWD_F_ALL = + 0 +#ifdef DO_KRB5 + | SMBK5PWD_F_KRB5 +#endif +#ifdef DO_SAMBA + | SMBK5PWD_F_SAMBA +#endif +#ifdef DO_SHADOW + | SMBK5PWD_F_SHADOW +#endif +; + +static int smbk5pwd_modules_init( smbk5pwd_t *pi ); + +#ifdef DO_SAMBA +static const char hex[] = "0123456789abcdef"; + +/* From liblutil/passwd.c... */ +static void lmPasswd_to_key( + const char *lmPasswd, + DES_cblock *key) +{ + const unsigned char *lpw = (const unsigned char *)lmPasswd; + unsigned char *k = (unsigned char *)key; + + /* make room for parity bits */ + k[0] = lpw[0]; + k[1] = ((lpw[0]&0x01)<<7) | (lpw[1]>>1); + k[2] = ((lpw[1]&0x03)<<6) | (lpw[2]>>2); + k[3] = ((lpw[2]&0x07)<<5) | (lpw[3]>>3); + k[4] = ((lpw[3]&0x0F)<<4) | (lpw[4]>>4); + k[5] = ((lpw[4]&0x1F)<<3) | (lpw[5]>>5); + k[6] = ((lpw[5]&0x3F)<<2) | (lpw[6]>>6); + k[7] = ((lpw[6]&0x7F)<<1); + +#ifdef HAVE_OPENSSL + DES_set_odd_parity( key ); +#endif +} + +#define MAX_PWLEN 256 +#define HASHLEN 16 + +static void hexify( + const char in[HASHLEN], + struct berval *out +) +{ + int i; + char *a; + unsigned char *b; + + out->bv_val = ch_malloc(HASHLEN*2 + 1); + out->bv_len = HASHLEN*2; + + a = out->bv_val; + b = (unsigned char *)in; + for (i=0; i<HASHLEN; i++) { + *a++ = hex[*b >> 4]; + *a++ = hex[*b++ & 0x0f]; + } + *a++ = '\0'; +} + +static void lmhash( + struct berval *passwd, + struct berval *hash +) +{ + char UcasePassword[15]; + DES_cblock key; + DES_cblock StdText = "KGS!@#$%"; + DES_cblock hbuf[2]; +#ifdef HAVE_OPENSSL + DES_key_schedule schedule; +#elif defined(HAVE_GNUTLS) + struct des_ctx ctx; +#endif + + strncpy( UcasePassword, passwd->bv_val, 14 ); + UcasePassword[14] = '\0'; + ldap_pvt_str2upper( UcasePassword ); + + lmPasswd_to_key( UcasePassword, &key ); +#ifdef HAVE_GNUTLS + des_set_key( &ctx, key ); + des_encrypt( &ctx, sizeof(key), hbuf[0], StdText ); + + lmPasswd_to_key( &UcasePassword[7], &key ); + des_set_key( &ctx, key ); + des_encrypt( &ctx, sizeof(key), hbuf[1], StdText ); +#elif defined(HAVE_OPENSSL) + DES_set_key_unchecked( &key, &schedule ); + DES_ecb_encrypt( &StdText, &hbuf[0], &schedule , DES_ENCRYPT ); + + lmPasswd_to_key( &UcasePassword[7], &key ); + DES_set_key_unchecked( &key, &schedule ); + DES_ecb_encrypt( &StdText, &hbuf[1], &schedule , DES_ENCRYPT ); +#endif + + hexify( (char *)hbuf, hash ); +} + +static void nthash( + struct berval *passwd, + struct berval *hash +) +{ + /* Windows currently only allows 14 character passwords, but + * may support up to 256 in the future. We assume this means + * 256 UCS2 characters, not 256 bytes... + */ + char hbuf[HASHLEN]; +#ifdef HAVE_OPENSSL + MD4_CTX ctx; +#elif defined(HAVE_GNUTLS) + struct md4_ctx ctx; +#endif + + if (passwd->bv_len > MAX_PWLEN*2) + passwd->bv_len = MAX_PWLEN*2; + +#ifdef HAVE_OPENSSL + MD4_Init( &ctx ); + MD4_Update( &ctx, passwd->bv_val, passwd->bv_len ); + MD4_Final( (unsigned char *)hbuf, &ctx ); +#elif defined(HAVE_GNUTLS) + md4_init( &ctx ); + md4_update( &ctx, passwd->bv_len, (unsigned char *)passwd->bv_val ); + md4_digest( &ctx, sizeof(hbuf), (unsigned char *)hbuf ); +#endif + + hexify( hbuf, hash ); +} +#endif /* DO_SAMBA */ + +#ifdef DO_KRB5 + +static int smbk5pwd_op_cleanup( + Operation *op, + SlapReply *rs ) +{ + slap_callback *cb; + + /* clear out the current key */ + ldap_pvt_thread_pool_setkey( op->o_threadctx, smbk5pwd_op_cleanup, + NULL, 0, NULL, NULL ); + + /* free the callback */ + cb = op->o_callback; + op->o_callback = cb->sc_next; + op->o_tmpfree( cb, op->o_tmpmemctx ); + return 0; +} + +static int smbk5pwd_op_bind( + Operation *op, + SlapReply *rs ) +{ + /* If this is a simple Bind, stash the Op pointer so our chk + * function can find it. Set a cleanup callback to clear it + * out when the Bind completes. + */ + if ( op->oq_bind.rb_method == LDAP_AUTH_SIMPLE ) { + slap_callback *cb; + ldap_pvt_thread_pool_setkey( op->o_threadctx, + smbk5pwd_op_cleanup, op, 0, NULL, NULL ); + cb = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx ); + cb->sc_cleanup = smbk5pwd_op_cleanup; + cb->sc_next = op->o_callback; + op->o_callback = cb; + } + return SLAP_CB_CONTINUE; +} + +static LUTIL_PASSWD_CHK_FUNC k5key_chk; +static LUTIL_PASSWD_HASH_FUNC k5key_hash; +static const struct berval k5key_scheme = BER_BVC("{K5KEY}"); + +/* This password scheme stores no data in the userPassword attribute + * other than the scheme name. It assumes the invoking entry is a + * krb5KDCentry and compares the passed-in credentials against the + * krb5Key attribute. The krb5Key may be multi-valued, but they are + * simply multiple keytypes generated from the same input string, so + * only the first value needs to be compared here. + * + * Since the lutil_passwd API doesn't pass the Entry object in, we + * have to fetch it ourselves in order to get access to the other + * attributes. We accomplish this with the help of the overlay's Bind + * function, which stores the current Operation pointer in thread-specific + * storage so we can retrieve it here. The Operation provides all + * the necessary context for us to get Entry from the database. + */ +static int k5key_chk( + const struct berval *sc, + const struct berval *passwd, + const struct berval *cred, + const char **text ) +{ + void *ctx, *op_tmp; + Operation *op; + int rc; + Entry *e; + Attribute *a; + krb5_error_code ret; + krb5_keyblock key; + krb5_salt salt; + hdb_entry ent; + + /* Find our thread context, find our Operation */ + ctx = ldap_pvt_thread_pool_context(); + + if ( ldap_pvt_thread_pool_getkey( ctx, smbk5pwd_op_cleanup, &op_tmp, NULL ) + || !op_tmp ) + return LUTIL_PASSWD_ERR; + op = op_tmp; + + rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e ); + if ( rc != LDAP_SUCCESS ) return LUTIL_PASSWD_ERR; + + rc = LUTIL_PASSWD_ERR; + do { + size_t l; + Key ekey = {0}; + + a = attr_find( e->e_attrs, ad_krb5PrincipalName ); + if (!a ) break; + + memset( &ent, 0, sizeof(ent) ); + ret = krb5_parse_name(context, a->a_vals[0].bv_val, &ent.principal); + if ( ret ) break; + + a = attr_find( e->e_attrs, ad_krb5ValidEnd ); + if (a) { + struct lutil_tm tm; + struct lutil_timet tt; + if ( lutil_parsetime( a->a_vals[0].bv_val, &tm ) == 0 && + lutil_tm2time( &tm, &tt ) == 0 && tt.tt_usec < op->o_time ) { + /* Account is expired */ + rc = LUTIL_PASSWD_ERR; + break; + } + } + + krb5_get_pw_salt( context, ent.principal, &salt ); + krb5_free_principal( context, ent.principal ); + + a = attr_find( e->e_attrs, ad_krb5Key ); + if ( !a ) break; + + ent.keys.len = 1; + ent.keys.val = &ekey; + decode_Key((unsigned char *) a->a_vals[0].bv_val, + (size_t) a->a_vals[0].bv_len, &ent.keys.val[0], &l); + if ( db->HDB_MASTER_KEY_SET ) + hdb_unseal_keys( context, db, &ent ); + + krb5_string_to_key_salt( context, ekey.key.keytype, cred->bv_val, + salt, &key ); + + krb5_free_salt( context, salt ); + + if ( memcmp( ekey.key.keyvalue.data, key.keyvalue.data, + key.keyvalue.length ) == 0 ) rc = LUTIL_PASSWD_OK; + + krb5_free_keyblock_contents( context, &key ); + krb5_free_keyblock_contents( context, &ekey.key ); + + } while(0); + be_entry_release_r( op, e ); + return rc; +} + +static int k5key_hash( + const struct berval *scheme, + const struct berval *passwd, + struct berval *hash, + const char **text ) +{ + ber_dupbv( hash, (struct berval *)&k5key_scheme ); + return LUTIL_PASSWD_OK; +} +#endif /* DO_KRB5 */ + +static int smbk5pwd_exop_passwd( + Operation *op, + SlapReply *rs ) +{ + int rc; + req_pwdexop_s *qpw = &op->oq_pwdexop; + Entry *e; + Modifications *ml; + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + smbk5pwd_t *pi = on->on_bi.bi_private; + char term; + + /* Not the operation we expected, pass it on... */ + if ( ber_bvcmp( &slap_EXOP_MODIFY_PASSWD, &op->ore_reqoid ) ) { + return SLAP_CB_CONTINUE; + } + + op->o_bd->bd_info = (BackendInfo *)on->on_info; + rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e ); + if ( rc != LDAP_SUCCESS ) return rc; + + term = qpw->rs_new.bv_val[qpw->rs_new.bv_len]; + qpw->rs_new.bv_val[qpw->rs_new.bv_len] = '\0'; + +#ifdef DO_KRB5 + /* Kerberos stuff */ + do { + krb5_error_code ret; + hdb_entry ent; + struct berval *keys; + size_t nkeys; + int kvno, i; + Attribute *a; + + if ( !SMBK5PWD_DO_KRB5( pi ) ) break; + + if ( !is_entry_objectclass(e, oc_krb5KDCEntry, 0 ) ) break; + + a = attr_find( e->e_attrs, ad_krb5PrincipalName ); + if ( !a ) break; + + memset( &ent, 0, sizeof(ent) ); + ret = krb5_parse_name(context, a->a_vals[0].bv_val, &ent.principal); + if ( ret ) break; + + a = attr_find( e->e_attrs, ad_krb5KeyVersionNumber ); + kvno = 0; + if ( a ) { + if ( lutil_atoi( &kvno, a->a_vals[0].bv_val ) != 0 ) { + Debug( LDAP_DEBUG_ANY, "%s smbk5pwd EXOP: " + "dn=\"%s\" unable to parse krb5KeyVersionNumber=\"%s\"\n", + op->o_log_prefix, e->e_name.bv_val, a->a_vals[0].bv_val ); + } + + } else { + /* shouldn't happen, this is a required attr */ + Debug( LDAP_DEBUG_ANY, "%s smbk5pwd EXOP: " + "dn=\"%s\" missing krb5KeyVersionNumber\n", + op->o_log_prefix, e->e_name.bv_val, 0 ); + } + + ret = hdb_generate_key_set_password(context, ent.principal, + qpw->rs_new.bv_val, &ent.keys.val, &nkeys); + ent.keys.len = nkeys; + hdb_seal_keys(context, db, &ent); + krb5_free_principal( context, ent.principal ); + + keys = ch_malloc( (ent.keys.len + 1) * sizeof(struct berval)); + + for (i = 0; i < ent.keys.len; i++) { + unsigned char *buf; + size_t len; + + ASN1_MALLOC_ENCODE(Key, buf, len, &ent.keys.val[i], &len, ret); + if (ret != 0) + break; + + keys[i].bv_val = (char *)buf; + keys[i].bv_len = len; + } + BER_BVZERO( &keys[i] ); + + hdb_free_keys(context, ent.keys.len, ent.keys.val); + + if ( i != ent.keys.len ) { + ber_bvarray_free( keys ); + break; + } + + ml = ch_malloc(sizeof(Modifications)); + if (!qpw->rs_modtail) qpw->rs_modtail = &ml->sml_next; + ml->sml_next = qpw->rs_mods; + qpw->rs_mods = ml; + + ml->sml_desc = ad_krb5Key; + ml->sml_op = LDAP_MOD_REPLACE; +#ifdef SLAP_MOD_INTERNAL + ml->sml_flags = SLAP_MOD_INTERNAL; +#endif + ml->sml_numvals = i; + ml->sml_values = keys; + ml->sml_nvalues = NULL; + + ml = ch_malloc(sizeof(Modifications)); + ml->sml_next = qpw->rs_mods; + qpw->rs_mods = ml; + + ml->sml_desc = ad_krb5KeyVersionNumber; + ml->sml_op = LDAP_MOD_REPLACE; +#ifdef SLAP_MOD_INTERNAL + ml->sml_flags = SLAP_MOD_INTERNAL; +#endif + ml->sml_numvals = 1; + ml->sml_values = ch_malloc( 2 * sizeof(struct berval)); + ml->sml_values[0].bv_val = ch_malloc( 64 ); + ml->sml_values[0].bv_len = sprintf(ml->sml_values[0].bv_val, + "%d", kvno+1 ); + BER_BVZERO( &ml->sml_values[1] ); + ml->sml_nvalues = NULL; + } while ( 0 ); +#endif /* DO_KRB5 */ + +#ifdef DO_SAMBA + /* Samba stuff */ + if ( SMBK5PWD_DO_SAMBA( pi ) && is_entry_objectclass(e, oc_sambaSamAccount, 0 ) ) { + struct berval *keys; + ber_len_t j,l; + wchar_t *wcs, wc; + char *c, *d; + struct berval pwd; + + /* Expand incoming UTF8 string to UCS4 */ + l = ldap_utf8_chars(qpw->rs_new.bv_val); + wcs = ch_malloc((l+1) * sizeof(wchar_t)); + + ldap_x_utf8s_to_wcs( wcs, qpw->rs_new.bv_val, l ); + + /* Truncate UCS4 to UCS2 */ + c = (char *)wcs; + for (j=0; j<l; j++) { + wc = wcs[j]; + *c++ = wc & 0xff; + *c++ = (wc >> 8) & 0xff; + } + *c++ = 0; + pwd.bv_val = (char *)wcs; + pwd.bv_len = l * 2; + + ml = ch_malloc(sizeof(Modifications)); + if (!qpw->rs_modtail) qpw->rs_modtail = &ml->sml_next; + ml->sml_next = qpw->rs_mods; + qpw->rs_mods = ml; + + keys = ch_malloc( 2 * sizeof(struct berval) ); + BER_BVZERO( &keys[1] ); + nthash( &pwd, keys ); + + ml->sml_desc = ad_sambaNTPassword; + ml->sml_op = LDAP_MOD_REPLACE; +#ifdef SLAP_MOD_INTERNAL + ml->sml_flags = SLAP_MOD_INTERNAL; +#endif + ml->sml_numvals = 1; + ml->sml_values = keys; + ml->sml_nvalues = NULL; + + /* Truncate UCS2 to 8-bit ASCII */ + c = pwd.bv_val+1; + d = pwd.bv_val+2; + for (j=1; j<l; j++) { + *c++ = *d++; + d++; + } + pwd.bv_len /= 2; + pwd.bv_val[pwd.bv_len] = '\0'; + + ml = ch_malloc(sizeof(Modifications)); + ml->sml_next = qpw->rs_mods; + qpw->rs_mods = ml; + + keys = ch_malloc( 2 * sizeof(struct berval) ); + BER_BVZERO( &keys[1] ); + lmhash( &pwd, keys ); + + ml->sml_desc = ad_sambaLMPassword; + ml->sml_op = LDAP_MOD_REPLACE; +#ifdef SLAP_MOD_INTERNAL + ml->sml_flags = SLAP_MOD_INTERNAL; +#endif + ml->sml_numvals = 1; + ml->sml_values = keys; + ml->sml_nvalues = NULL; + + ch_free(wcs); + + ml = ch_malloc(sizeof(Modifications)); + ml->sml_next = qpw->rs_mods; + qpw->rs_mods = ml; + + keys = ch_malloc( 2 * sizeof(struct berval) ); + keys[0].bv_val = ch_malloc( LDAP_PVT_INTTYPE_CHARS(long) ); + keys[0].bv_len = snprintf(keys[0].bv_val, + LDAP_PVT_INTTYPE_CHARS(long), + "%ld", slap_get_time()); + BER_BVZERO( &keys[1] ); + + ml->sml_desc = ad_sambaPwdLastSet; + ml->sml_op = LDAP_MOD_REPLACE; +#ifdef SLAP_MOD_INTERNAL + ml->sml_flags = SLAP_MOD_INTERNAL; +#endif + ml->sml_numvals = 1; + ml->sml_values = keys; + ml->sml_nvalues = NULL; + + if (pi->smb_must_change) + { + ml = ch_malloc(sizeof(Modifications)); + ml->sml_next = qpw->rs_mods; + qpw->rs_mods = ml; + + keys = ch_malloc( 2 * sizeof(struct berval) ); + keys[0].bv_val = ch_malloc( LDAP_PVT_INTTYPE_CHARS(long) ); + keys[0].bv_len = snprintf(keys[0].bv_val, + LDAP_PVT_INTTYPE_CHARS(long), + "%ld", slap_get_time() + pi->smb_must_change); + BER_BVZERO( &keys[1] ); + + ml->sml_desc = ad_sambaPwdMustChange; + ml->sml_op = LDAP_MOD_REPLACE; +#ifdef SLAP_MOD_INTERNAL + ml->sml_flags = SLAP_MOD_INTERNAL; +#endif + ml->sml_numvals = 1; + ml->sml_values = keys; + ml->sml_nvalues = NULL; + } + + if (pi->smb_can_change) + { + ml = ch_malloc(sizeof(Modifications)); + ml->sml_next = qpw->rs_mods; + qpw->rs_mods = ml; + + keys = ch_malloc( 2 * sizeof(struct berval) ); + keys[0].bv_val = ch_malloc( LDAP_PVT_INTTYPE_CHARS(long) ); + keys[0].bv_len = snprintf(keys[0].bv_val, + LDAP_PVT_INTTYPE_CHARS(long), + "%ld", slap_get_time() + pi->smb_can_change); + BER_BVZERO( &keys[1] ); + + ml->sml_desc = ad_sambaPwdCanChange; + ml->sml_op = LDAP_MOD_REPLACE; +#ifdef SLAP_MOD_INTERNAL + ml->sml_flags = SLAP_MOD_INTERNAL; +#endif + ml->sml_numvals = 1; + ml->sml_values = keys; + ml->sml_nvalues = NULL; + } + } +#endif /* DO_SAMBA */ + +#ifdef DO_SHADOW + /* shadow stuff */ + if ( SMBK5PWD_DO_SHADOW( pi ) && is_entry_objectclass(e, oc_shadowAccount, 0 ) ) { + struct berval *keys; + + ml = ch_malloc(sizeof(Modifications)); + if (!qpw->rs_modtail) qpw->rs_modtail = &ml->sml_next; + ml->sml_next = qpw->rs_mods; + qpw->rs_mods = ml; + + keys = ch_malloc( sizeof(struct berval) * 2); + BER_BVZERO( &keys[1] ); + keys[0].bv_val = ch_malloc( LDAP_PVT_INTTYPE_CHARS(long) ); + keys[0].bv_len = snprintf(keys[0].bv_val, + LDAP_PVT_INTTYPE_CHARS(long), + "%ld", (long)(slap_get_time() / (60 * 60 * 24))); + + ml->sml_desc = ad_shadowLastChange; + ml->sml_op = LDAP_MOD_REPLACE; +#ifdef SLAP_MOD_INTERNAL + ml->sml_flags = SLAP_MOD_INTERNAL; +#endif + ml->sml_numvals = 1; + ml->sml_values = keys; + ml->sml_nvalues = NULL; + } +#endif /* DO_SHADOW */ + + be_entry_release_r( op, e ); + qpw->rs_new.bv_val[qpw->rs_new.bv_len] = term; + + return SLAP_CB_CONTINUE; +} + +static slap_overinst smbk5pwd; + +/* back-config stuff */ +enum { + PC_SMB_MUST_CHANGE = 1, + PC_SMB_CAN_CHANGE, + PC_SMB_ENABLE +}; + +static ConfigDriver smbk5pwd_cf_func; + +/* + * NOTE: uses OID arcs OLcfgCtAt:1 and OLcfgCtOc:1 + */ + +static ConfigTable smbk5pwd_cfats[] = { + { "smbk5pwd-enable", "arg", + 2, 0, 0, ARG_MAGIC|PC_SMB_ENABLE, smbk5pwd_cf_func, + "( OLcfgCtAt:1.1 NAME 'olcSmbK5PwdEnable' " + "DESC 'Modules to be enabled' " + "SYNTAX OMsDirectoryString )", NULL, NULL }, + { "smbk5pwd-must-change", "time", + 2, 2, 0, ARG_MAGIC|ARG_INT|PC_SMB_MUST_CHANGE, smbk5pwd_cf_func, + "( OLcfgCtAt:1.2 NAME 'olcSmbK5PwdMustChange' " + "DESC 'Credentials validity interval' " + "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, + { "smbk5pwd-can-change", "time", + 2, 2, 0, ARG_MAGIC|ARG_INT|PC_SMB_CAN_CHANGE, smbk5pwd_cf_func, + "( OLcfgCtAt:1.3 NAME 'olcSmbK5PwdCanChange' " + "DESC 'Credentials minimum validity interval' " + "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, + + { NULL, NULL, 0, 0, 0, ARG_IGNORED } +}; + +static ConfigOCs smbk5pwd_cfocs[] = { + { "( OLcfgCtOc:1.1 " + "NAME 'olcSmbK5PwdConfig' " + "DESC 'smbk5pwd overlay configuration' " + "SUP olcOverlayConfig " + "MAY ( " + "olcSmbK5PwdEnable " + "$ olcSmbK5PwdMustChange " + "$ olcSmbK5PwdCanChange " + ") )", Cft_Overlay, smbk5pwd_cfats }, + + { NULL, 0, NULL } +}; + +/* + * add here other functionalities; handle their initialization + * as appropriate in smbk5pwd_modules_init(). + */ +static slap_verbmasks smbk5pwd_modules[] = { + { BER_BVC( "krb5" ), SMBK5PWD_F_KRB5 }, + { BER_BVC( "samba" ), SMBK5PWD_F_SAMBA }, + { BER_BVC( "shadow" ), SMBK5PWD_F_SHADOW }, + { BER_BVNULL, -1 } +}; + +static int +smbk5pwd_cf_func( ConfigArgs *c ) +{ + slap_overinst *on = (slap_overinst *)c->bi; + + int rc = 0; + smbk5pwd_t *pi = on->on_bi.bi_private; + + if ( c->op == SLAP_CONFIG_EMIT ) { + switch( c->type ) { + case PC_SMB_MUST_CHANGE: +#ifdef DO_SAMBA + c->value_int = pi->smb_must_change; +#else /* ! DO_SAMBA */ + c->value_int = 0; +#endif /* ! DO_SAMBA */ + break; + + case PC_SMB_CAN_CHANGE: +#ifdef DO_SAMBA + c->value_int = pi->smb_can_change; +#else /* ! DO_SAMBA */ + c->value_int = 0; +#endif /* ! DO_SAMBA */ + break; + + case PC_SMB_ENABLE: + c->rvalue_vals = NULL; + if ( pi->mode ) { + mask_to_verbs( smbk5pwd_modules, pi->mode, &c->rvalue_vals ); + if ( c->rvalue_vals == NULL ) { + rc = 1; + } + } + break; + + default: + assert( 0 ); + rc = 1; + } + return rc; + + } else if ( c->op == LDAP_MOD_DELETE ) { + switch( c->type ) { + case PC_SMB_MUST_CHANGE: + break; + + case PC_SMB_CAN_CHANGE: + break; + + case PC_SMB_ENABLE: + if ( !c->line ) { + pi->mode = 0; + + } else { + int i; + + i = verb_to_mask( c->line, smbk5pwd_modules ); + pi->mode &= ~smbk5pwd_modules[i].mask; + } + break; + + default: + assert( 0 ); + rc = 1; + } + return rc; + } + + switch( c->type ) { + case PC_SMB_MUST_CHANGE: +#ifdef DO_SAMBA + if ( c->value_int < 0 ) { + Debug( LDAP_DEBUG_ANY, "%s: smbk5pwd: " + "<%s> invalid negative value \"%d\".", + c->log, c->argv[ 0 ], 0 ); + return 1; + } + pi->smb_must_change = c->value_int; +#else /* ! DO_SAMBA */ + Debug( LDAP_DEBUG_ANY, "%s: smbk5pwd: " + "<%s> only meaningful " + "when compiled with -DDO_SAMBA.\n", + c->log, c->argv[ 0 ], 0 ); + return 1; +#endif /* ! DO_SAMBA */ + break; + + case PC_SMB_CAN_CHANGE: +#ifdef DO_SAMBA + if ( c->value_int < 0 ) { + Debug( LDAP_DEBUG_ANY, "%s: smbk5pwd: " + "<%s> invalid negative value \"%d\".", + c->log, c->argv[ 0 ], 0 ); + return 1; + } + pi->smb_can_change = c->value_int; +#else /* ! DO_SAMBA */ + Debug( LDAP_DEBUG_ANY, "%s: smbk5pwd: " + "<%s> only meaningful " + "when compiled with -DDO_SAMBA.\n", + c->log, c->argv[ 0 ], 0 ); + return 1; +#endif /* ! DO_SAMBA */ + break; + + case PC_SMB_ENABLE: { + slap_mask_t mode = pi->mode, m = 0; + + rc = verbs_to_mask( c->argc, c->argv, smbk5pwd_modules, &m ); + if ( rc > 0 ) { + Debug( LDAP_DEBUG_ANY, "%s: smbk5pwd: " + "<%s> unknown module \"%s\".\n", + c->log, c->argv[ 0 ], c->argv[ rc ] ); + return 1; + } + + /* we can hijack the smbk5pwd_t structure because + * from within the configuration, this is the only + * active thread. */ + pi->mode |= m; + +#ifndef DO_KRB5 + if ( SMBK5PWD_DO_KRB5( pi ) ) { + Debug( LDAP_DEBUG_ANY, "%s: smbk5pwd: " + "<%s> module \"%s\" only allowed when compiled with -DDO_KRB5.\n", + c->log, c->argv[ 0 ], c->argv[ rc ] ); + pi->mode = mode; + return 1; + } +#endif /* ! DO_KRB5 */ + +#ifndef DO_SAMBA + if ( SMBK5PWD_DO_SAMBA( pi ) ) { + Debug( LDAP_DEBUG_ANY, "%s: smbk5pwd: " + "<%s> module \"%s\" only allowed when compiled with -DDO_SAMBA.\n", + c->log, c->argv[ 0 ], c->argv[ rc ] ); + pi->mode = mode; + return 1; + } +#endif /* ! DO_SAMBA */ + +#ifndef DO_SHADOW + if ( SMBK5PWD_DO_SHADOW( pi ) ) { + Debug( LDAP_DEBUG_ANY, "%s: smbk5pwd: " + "<%s> module \"%s\" only allowed when compiled with -DDO_SHADOW.\n", + c->log, c->argv[ 0 ], c->argv[ rc ] ); + pi->mode = mode; + return 1; + } +#endif /* ! DO_SHADOW */ + + /* Re-initialize the module, because + * the configuration might have changed */ + rc = smbk5pwd_modules_init( pi ); + if ( rc ) { + pi->mode = mode; + return 1; + } + + } break; + + default: + assert( 0 ); + return 1; + } + return rc; +} + +static int +smbk5pwd_modules_init( smbk5pwd_t *pi ) +{ + static struct { + const char *name; + AttributeDescription **adp; + } +#ifdef DO_KRB5 + krb5_ad[] = { + { "krb5Key", &ad_krb5Key }, + { "krb5KeyVersionNumber", &ad_krb5KeyVersionNumber }, + { "krb5PrincipalName", &ad_krb5PrincipalName }, + { "krb5ValidEnd", &ad_krb5ValidEnd }, + { NULL } + }, +#endif /* DO_KRB5 */ +#ifdef DO_SAMBA + samba_ad[] = { + { "sambaLMPassword", &ad_sambaLMPassword }, + { "sambaNTPassword", &ad_sambaNTPassword }, + { "sambaPwdLastSet", &ad_sambaPwdLastSet }, + { "sambaPwdMustChange", &ad_sambaPwdMustChange }, + { "sambaPwdCanChange", &ad_sambaPwdCanChange }, + { NULL } + }, +#endif /* DO_SAMBA */ +#ifdef DO_SHADOW + shadow_ad[] = { + { "shadowLastChange", &ad_shadowLastChange }, + { NULL } + }, +#endif /* DO_SHADOW */ + dummy_ad; + + /* this is to silence the unused var warning */ + (void) dummy_ad; + +#ifdef DO_KRB5 + if ( SMBK5PWD_DO_KRB5( pi ) && oc_krb5KDCEntry == NULL ) { + krb5_error_code ret; + extern HDB *_kadm5_s_get_db(void *); + + int i, rc; + + /* Make sure all of our necessary schema items are loaded */ + oc_krb5KDCEntry = oc_find( "krb5KDCEntry" ); + if ( !oc_krb5KDCEntry ) { + Debug( LDAP_DEBUG_ANY, "smbk5pwd: " + "unable to find \"krb5KDCEntry\" objectClass.\n", + 0, 0, 0 ); + return -1; + } + + for ( i = 0; krb5_ad[ i ].name != NULL; i++ ) { + const char *text; + + *(krb5_ad[ i ].adp) = NULL; + + rc = slap_str2ad( krb5_ad[ i ].name, krb5_ad[ i ].adp, &text ); + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, "smbk5pwd: " + "unable to find \"%s\" attributeType: %s (%d).\n", + krb5_ad[ i ].name, text, rc ); + oc_krb5KDCEntry = NULL; + return rc; + } + } + + /* Initialize Kerberos context */ + ret = krb5_init_context(&context); + if (ret) { + Debug( LDAP_DEBUG_ANY, "smbk5pwd: " + "unable to initialize krb5 context (%d).\n", + ret, 0, 0 ); + oc_krb5KDCEntry = NULL; + return -1; + } + + ret = kadm5_s_init_with_password_ctx( context, + KADM5_ADMIN_SERVICE, + NULL, + KADM5_ADMIN_SERVICE, + &conf, 0, 0, &kadm_context ); + if (ret) { + char *err_str, *err_msg = "<unknown error>"; + err_str = krb5_get_error_string( context ); + if (!err_str) + err_msg = (char *)krb5_get_err_text( context, ret ); + Debug( LDAP_DEBUG_ANY, "smbk5pwd: " + "unable to initialize krb5 admin context: %s (%d).\n", + err_str ? err_str : err_msg, ret, 0 ); + if (err_str) + krb5_free_error_string( context, err_str ); + krb5_free_context( context ); + oc_krb5KDCEntry = NULL; + return -1; + } + + db = _kadm5_s_get_db( kadm_context ); + } +#endif /* DO_KRB5 */ + +#ifdef DO_SAMBA + if ( SMBK5PWD_DO_SAMBA( pi ) && oc_sambaSamAccount == NULL ) { + int i, rc; + + oc_sambaSamAccount = oc_find( "sambaSamAccount" ); + if ( !oc_sambaSamAccount ) { + Debug( LDAP_DEBUG_ANY, "smbk5pwd: " + "unable to find \"sambaSamAccount\" objectClass.\n", + 0, 0, 0 ); + return -1; + } + + for ( i = 0; samba_ad[ i ].name != NULL; i++ ) { + const char *text; + + *(samba_ad[ i ].adp) = NULL; + + rc = slap_str2ad( samba_ad[ i ].name, samba_ad[ i ].adp, &text ); + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, "smbk5pwd: " + "unable to find \"%s\" attributeType: %s (%d).\n", + samba_ad[ i ].name, text, rc ); + oc_sambaSamAccount = NULL; + return rc; + } + } + } +#endif /* DO_SAMBA */ + +#ifdef DO_SHADOW + if ( SMBK5PWD_DO_SHADOW( pi ) && oc_shadowAccount == NULL ) { + int i, rc; + + oc_shadowAccount = oc_find( "shadowAccount" ); + if ( !oc_shadowAccount ) { + Debug( LDAP_DEBUG_ANY, "smbk5pwd: " + "unable to find \"shadowAccount\" objectClass.\n", + 0, 0, 0 ); + return -1; + } + + for ( i = 0; shadow_ad[ i ].name != NULL; i++ ) { + const char *text; + + *(shadow_ad[ i ].adp) = NULL; + + rc = slap_str2ad( shadow_ad[ i ].name, shadow_ad[ i ].adp, &text ); + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, "smbk5pwd: " + "unable to find \"%s\" attributeType: %s (%d).\n", + shadow_ad[ i ].name, text, rc ); + oc_shadowAccount = NULL; + return rc; + } + } + } +#endif /* DO_SHADOW */ + + return 0; +} + +static int +smbk5pwd_db_init(BackendDB *be, ConfigReply *cr) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + smbk5pwd_t *pi; + + pi = ch_calloc( 1, sizeof( smbk5pwd_t ) ); + if ( pi == NULL ) { + return 1; + } + on->on_bi.bi_private = (void *)pi; + + return 0; +} + +static int +smbk5pwd_db_open(BackendDB *be, ConfigReply *cr) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + smbk5pwd_t *pi = (smbk5pwd_t *)on->on_bi.bi_private; + + int rc; + + if ( pi->mode == 0 ) { + pi->mode = SMBK5PWD_F_ALL; + } + + rc = smbk5pwd_modules_init( pi ); + if ( rc ) { + return rc; + } + + return 0; +} + +static int +smbk5pwd_db_destroy(BackendDB *be, ConfigReply *cr) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + smbk5pwd_t *pi = (smbk5pwd_t *)on->on_bi.bi_private; + + if ( pi ) { + ch_free( pi ); + } + + return 0; +} + +int +smbk5pwd_initialize(void) +{ + int rc; + + smbk5pwd.on_bi.bi_type = "smbk5pwd"; + + smbk5pwd.on_bi.bi_db_init = smbk5pwd_db_init; + smbk5pwd.on_bi.bi_db_open = smbk5pwd_db_open; + smbk5pwd.on_bi.bi_db_destroy = smbk5pwd_db_destroy; + + smbk5pwd.on_bi.bi_extended = smbk5pwd_exop_passwd; + +#ifdef DO_KRB5 + smbk5pwd.on_bi.bi_op_bind = smbk5pwd_op_bind; + + lutil_passwd_add( (struct berval *)&k5key_scheme, k5key_chk, k5key_hash ); +#endif + + smbk5pwd.on_bi.bi_cf_ocs = smbk5pwd_cfocs; + + rc = config_register_schema( smbk5pwd_cfats, smbk5pwd_cfocs ); + if ( rc ) { + return rc; + } + + return overlay_register( &smbk5pwd ); +} + +#if SLAPD_OVER_SMBK5PWD == SLAPD_MOD_DYNAMIC +int init_module(int argc, char *argv[]) { + return smbk5pwd_initialize(); +} +#endif + +#endif /* defined(SLAPD_OVER_SMBK5PWD) */ diff --git a/contrib/slapd-modules/trace/Makefile b/contrib/slapd-modules/trace/Makefile new file mode 100644 index 0000000..2c36ae7 --- /dev/null +++ b/contrib/slapd-modules/trace/Makefile @@ -0,0 +1,46 @@ +# $OpenLDAP$ + +LDAP_SRC = ../../.. +LDAP_BUILD = $(LDAP_SRC) +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +CC = gcc +OPT = -g -O2 -Wall +DEFS = -DSLAPD_OVER_TRACE=SLAPD_MOD_DYNAMIC +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) + +PROGRAMS = trace.la +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +trace.la: trace.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + diff --git a/contrib/slapd-modules/trace/trace.c b/contrib/slapd-modules/trace/trace.c new file mode 100644 index 0000000..6e4e2f7 --- /dev/null +++ b/contrib/slapd-modules/trace/trace.c @@ -0,0 +1,255 @@ +/* trace.c - traces overlay invocation */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2006-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by Pierangelo Masarati for inclusion in + * OpenLDAP Software. + */ + +#include "portable.h" + +#ifdef SLAPD_OVER_TRACE + +#include <stdio.h> + +#include <ac/string.h> +#include <ac/socket.h> + +#include "slap.h" +#include "lutil.h" + +static int +trace_op2str( Operation *op, char **op_strp ) +{ + switch ( op->o_tag ) { + case LDAP_REQ_BIND: + *op_strp = "BIND"; + break; + + case LDAP_REQ_UNBIND: + *op_strp = "UNBIND"; + break; + + case LDAP_REQ_SEARCH: + *op_strp = "SEARCH"; + break; + + case LDAP_REQ_MODIFY: + *op_strp = "MODIFY"; + break; + + case LDAP_REQ_ADD: + *op_strp = "ADD"; + break; + + case LDAP_REQ_DELETE: + *op_strp = "DELETE"; + break; + + case LDAP_REQ_MODRDN: + *op_strp = "MODRDN"; + break; + + case LDAP_REQ_COMPARE: + *op_strp = "COMPARE"; + break; + + case LDAP_REQ_ABANDON: + *op_strp = "ABANDON"; + break; + + case LDAP_REQ_EXTENDED: + *op_strp = "EXTENDED"; + break; + + default: + assert( 0 ); + } + + return 0; +} + +static int +trace_op_func( Operation *op, SlapReply *rs ) +{ + char *op_str = NULL; + + (void)trace_op2str( op, &op_str ); + + switch ( op->o_tag ) { + case LDAP_REQ_EXTENDED: + Log3( LDAP_DEBUG_ANY, LDAP_LEVEL_INFO, + "%s trace op=EXTENDED dn=\"%s\" reqoid=%s\n", + op->o_log_prefix, + BER_BVISNULL( &op->o_req_ndn ) ? "(null)" : op->o_req_ndn.bv_val, + BER_BVISNULL( &op->ore_reqoid ) ? "" : op->ore_reqoid.bv_val ); + break; + + default: + Log3( LDAP_DEBUG_ANY, LDAP_LEVEL_INFO, + "%s trace op=%s dn=\"%s\"\n", + op->o_log_prefix, op_str, + BER_BVISNULL( &op->o_req_ndn ) ? "(null)" : op->o_req_ndn.bv_val ); + break; + } + + return SLAP_CB_CONTINUE; +} + +static int +trace_response( Operation *op, SlapReply *rs ) +{ + char *op_str = NULL; + + (void)trace_op2str( op, &op_str ); + + switch ( op->o_tag ) { + case LDAP_REQ_EXTENDED: + Log5( LDAP_DEBUG_ANY, LDAP_LEVEL_INFO, + "%s trace op=EXTENDED RESPONSE dn=\"%s\" reqoid=%s rspoid=%s err=%d\n", + op->o_log_prefix, + BER_BVISNULL( &op->o_req_ndn ) ? "(null)" : op->o_req_ndn.bv_val, + BER_BVISNULL( &op->ore_reqoid ) ? "" : op->ore_reqoid.bv_val, + rs->sr_rspoid == NULL ? "" : rs->sr_rspoid, + rs->sr_err ); + break; + + case LDAP_REQ_SEARCH: + switch ( rs->sr_type ) { + case REP_SEARCH: + Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_INFO, + "%s trace op=SEARCH ENTRY dn=\"%s\"\n", + op->o_log_prefix, + rs->sr_entry->e_name.bv_val ); + goto done; + + case REP_SEARCHREF: + Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_INFO, + "%s trace op=SEARCH REFERENCE ref=\"%s\"\n", + op->o_log_prefix, + rs->sr_ref[ 0 ].bv_val ); + goto done; + + case REP_RESULT: + break; + + default: + assert( 0 ); + } + /* fallthru */ + + default: + Log4( LDAP_DEBUG_ANY, LDAP_LEVEL_INFO, + "%s trace op=%s RESPONSE dn=\"%s\" err=%d\n", + op->o_log_prefix, + op_str, + BER_BVISNULL( &op->o_req_ndn ) ? "(null)" : op->o_req_ndn.bv_val, + rs->sr_err ); + break; + } + +done:; + return SLAP_CB_CONTINUE; +} + +static int +trace_db_init( BackendDB *be, ConfigReply *cr ) +{ + Log0( LDAP_DEBUG_ANY, LDAP_LEVEL_INFO, + "trace DB_INIT\n" ); + + return 0; +} + +static int +trace_db_config( + BackendDB *be, + const char *fname, + int lineno, + int argc, + char **argv ) +{ + Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_INFO, + "trace DB_CONFIG argc=%d argv[0]=\"%s\"\n", + argc, argv[ 0 ] ); + + return 0; +} + +static int +trace_db_open( BackendDB *be, ConfigReply *cr ) +{ + Log0( LDAP_DEBUG_ANY, LDAP_LEVEL_INFO, + "trace DB_OPEN\n" ); + + return 0; +} + +static int +trace_db_close( BackendDB *be, ConfigReply *cr ) +{ + Log0( LDAP_DEBUG_ANY, LDAP_LEVEL_INFO, + "trace DB_CLOSE\n" ); + + return 0; +} + +static int +trace_db_destroy( BackendDB *be, ConfigReply *cr ) +{ + Log0( LDAP_DEBUG_ANY, LDAP_LEVEL_INFO, + "trace DB_DESTROY\n" ); + + return 0; +} + +static slap_overinst trace; + +int +trace_initialize() +{ + trace.on_bi.bi_type = "trace"; + + trace.on_bi.bi_db_init = trace_db_init; + trace.on_bi.bi_db_open = trace_db_open; + trace.on_bi.bi_db_config = trace_db_config; + trace.on_bi.bi_db_close = trace_db_close; + trace.on_bi.bi_db_destroy = trace_db_destroy; + + trace.on_bi.bi_op_add = trace_op_func; + trace.on_bi.bi_op_bind = trace_op_func; + trace.on_bi.bi_op_unbind = trace_op_func; + trace.on_bi.bi_op_compare = trace_op_func; + trace.on_bi.bi_op_delete = trace_op_func; + trace.on_bi.bi_op_modify = trace_op_func; + trace.on_bi.bi_op_modrdn = trace_op_func; + trace.on_bi.bi_op_search = trace_op_func; + trace.on_bi.bi_op_abandon = trace_op_func; + trace.on_bi.bi_extended = trace_op_func; + + trace.on_response = trace_response; + + return overlay_register( &trace ); +} + +#if SLAPD_OVER_TRACE == SLAPD_MOD_DYNAMIC +int +init_module( int argc, char *argv[] ) +{ + return trace_initialize(); +} +#endif /* SLAPD_OVER_TRACE == SLAPD_MOD_DYNAMIC */ + +#endif /* defined(SLAPD_OVER_TRACE) */ |