X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fcontrols.c;h=042fccca8f080fabb569356d14c6a37ff3e59bc8;hb=f7e3566ceb66c65a5f581f073ceaead4d6b9e860;hp=34cf6cf731942e1030b12ff47f6f1bd5e7dede72;hpb=dc0eacd40b625258355eea866d62188e5aa7ce3b;p=openldap diff --git a/servers/slapd/controls.c b/servers/slapd/controls.c index 34cf6cf731..042fccca8f 100644 --- a/servers/slapd/controls.c +++ b/servers/slapd/controls.c @@ -1,7 +1,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 1998-2005 The OpenLDAP Foundation. + * Copyright 1998-2008 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -21,25 +21,32 @@ #include #include "slap.h" +#include "ldif.h" +#include "lutil.h" #include "../../libraries/liblber/lber-int.h" static SLAP_CTRL_PARSE_FN parseAssert; -static SLAP_CTRL_PARSE_FN parsePreRead; -static SLAP_CTRL_PARSE_FN parsePostRead; -static SLAP_CTRL_PARSE_FN parseProxyAuthz; +static SLAP_CTRL_PARSE_FN parseDomainScope; +static SLAP_CTRL_PARSE_FN parseDontUseCopy; static SLAP_CTRL_PARSE_FN parseManageDSAit; -static SLAP_CTRL_PARSE_FN parseModifyIncrement; static SLAP_CTRL_PARSE_FN parseNoOp; static SLAP_CTRL_PARSE_FN parsePagedResults; -static SLAP_CTRL_PARSE_FN parseValuesReturnFilter; static SLAP_CTRL_PARSE_FN parsePermissiveModify; -static SLAP_CTRL_PARSE_FN parseDomainScope; -static SLAP_CTRL_PARSE_FN parseTreeDelete; +static SLAP_CTRL_PARSE_FN parsePreRead, parsePostRead; +static SLAP_CTRL_PARSE_FN parseProxyAuthz; +static SLAP_CTRL_PARSE_FN parseRelax; static SLAP_CTRL_PARSE_FN parseSearchOptions; - -#ifdef LDAP_CONTROL_SUBENTRIES +#ifdef SLAP_CONTROL_X_SORTEDRESULTS +static SLAP_CTRL_PARSE_FN parseSortedResults; +#endif static SLAP_CTRL_PARSE_FN parseSubentries; +#ifdef SLAP_CONTROL_X_TREE_DELETE +static SLAP_CTRL_PARSE_FN parseTreeDelete; +#endif +static SLAP_CTRL_PARSE_FN parseValuesReturnFilter; +#ifdef SLAP_CONTROL_X_SESSION_TRACKING +static SLAP_CTRL_PARSE_FN parseSessionTracking; #endif #undef sc_mask /* avoid conflict with Irix 6.5 */ @@ -60,7 +67,8 @@ struct slap_control { slap_mask_t sc_mask; /* Extended operations supported by control */ - char **sc_extendedops; + char **sc_extendedops; /* input */ + BerVarray sc_extendedopsbv; /* run-time use */ /* Control parsing callback */ SLAP_CTRL_PARSE_FN *sc_parse; @@ -90,97 +98,151 @@ static int num_known_controls = 1; static char *proxy_authz_extops[] = { LDAP_EXOP_MODIFY_PASSWD, - LDAP_EXOP_X_WHO_AM_I, + LDAP_EXOP_WHO_AM_I, + LDAP_EXOP_REFRESH, + NULL +}; + +static char *manageDSAit_extops[] = { + LDAP_EXOP_REFRESH, + NULL +}; + +#ifdef SLAP_CONTROL_X_SESSION_TRACKING +static char *session_tracking_extops[] = { + LDAP_EXOP_MODIFY_PASSWD, + LDAP_EXOP_WHO_AM_I, + LDAP_EXOP_REFRESH, NULL }; +#endif static struct slap_control control_defs[] = { { LDAP_CONTROL_ASSERT, (int)offsetof(struct slap_control_ids, sc_assert), - SLAP_CTRL_HIDE|SLAP_CTRL_ACCESS, NULL, + SLAP_CTRL_DELETE|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME| + SLAP_CTRL_COMPARE|SLAP_CTRL_SEARCH, + NULL, NULL, parseAssert, LDAP_SLIST_ENTRY_INITIALIZER(next) }, { LDAP_CONTROL_PRE_READ, (int)offsetof(struct slap_control_ids, sc_preRead), - SLAP_CTRL_HIDE|SLAP_CTRL_DELETE|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME, NULL, + SLAP_CTRL_DELETE|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME, + NULL, NULL, parsePreRead, LDAP_SLIST_ENTRY_INITIALIZER(next) }, { LDAP_CONTROL_POST_READ, (int)offsetof(struct slap_control_ids, sc_postRead), - SLAP_CTRL_HIDE|SLAP_CTRL_ADD|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME, NULL, + SLAP_CTRL_ADD|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME, + NULL, NULL, parsePostRead, LDAP_SLIST_ENTRY_INITIALIZER(next) }, { LDAP_CONTROL_VALUESRETURNFILTER, (int)offsetof(struct slap_control_ids, sc_valuesReturnFilter), - SLAP_CTRL_SEARCH, NULL, + SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH, + NULL, NULL, parseValuesReturnFilter, LDAP_SLIST_ENTRY_INITIALIZER(next) }, { LDAP_CONTROL_PAGEDRESULTS, (int)offsetof(struct slap_control_ids, sc_pagedResults), - SLAP_CTRL_SEARCH, NULL, + SLAP_CTRL_SEARCH, + NULL, NULL, parsePagedResults, LDAP_SLIST_ENTRY_INITIALIZER(next) }, -#ifdef LDAP_CONTROL_X_DOMAIN_SCOPE +#ifdef SLAP_CONTROL_X_SORTEDRESULTS + { LDAP_CONTROL_SORTREQUEST, + (int)offsetof(struct slap_control_ids, sc_sortedResults), + SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH|SLAP_CTRL_HIDE, + NULL, NULL, + parseSortedResults, LDAP_SLIST_ENTRY_INITIALIZER(next) }, +#endif { LDAP_CONTROL_X_DOMAIN_SCOPE, (int)offsetof(struct slap_control_ids, sc_domainScope), - SLAP_CTRL_FRONTEND|SLAP_CTRL_SEARCH, NULL, + SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH|SLAP_CTRL_HIDE, + NULL, NULL, parseDomainScope, LDAP_SLIST_ENTRY_INITIALIZER(next) }, -#endif -#ifdef LDAP_CONTROL_X_PERMISSIVE_MODIFY + { LDAP_CONTROL_DONTUSECOPY, + (int)offsetof(struct slap_control_ids, sc_dontUseCopy), + SLAP_CTRL_GLOBAL|SLAP_CTRL_INTROGATE|SLAP_CTRL_HIDE, + NULL, NULL, + parseDontUseCopy, LDAP_SLIST_ENTRY_INITIALIZER(next) }, { LDAP_CONTROL_X_PERMISSIVE_MODIFY, (int)offsetof(struct slap_control_ids, sc_permissiveModify), - SLAP_CTRL_MODIFY, NULL, + SLAP_CTRL_MODIFY|SLAP_CTRL_HIDE, + NULL, NULL, parsePermissiveModify, LDAP_SLIST_ENTRY_INITIALIZER(next) }, -#endif -#ifdef LDAP_CONTROL_X_TREE_DELETE +#ifdef SLAP_CONTROL_X_TREE_DELETE { LDAP_CONTROL_X_TREE_DELETE, (int)offsetof(struct slap_control_ids, sc_treeDelete), - SLAP_CTRL_DELETE, NULL, + SLAP_CTRL_DELETE|SLAP_CTRL_HIDE, + NULL, NULL, parseTreeDelete, LDAP_SLIST_ENTRY_INITIALIZER(next) }, #endif -#ifdef LDAP_CONTORL_X_SEARCH_OPTIONS - { LDAP_CONTORL_X_SEARCH_OPTIONS, + { LDAP_CONTROL_X_SEARCH_OPTIONS, (int)offsetof(struct slap_control_ids, sc_searchOptions), - SLAP_CTRL_FRONTEND|SLAP_CTRL_SEARCH, NULL, + SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH|SLAP_CTRL_HIDE, + NULL, NULL, parseSearchOptions, LDAP_SLIST_ENTRY_INITIALIZER(next) }, -#endif -#ifdef LDAP_CONTROL_SUBENTRIES { LDAP_CONTROL_SUBENTRIES, (int)offsetof(struct slap_control_ids, sc_subentries), - SLAP_CTRL_SEARCH, NULL, + SLAP_CTRL_SEARCH, + NULL, NULL, parseSubentries, LDAP_SLIST_ENTRY_INITIALIZER(next) }, -#endif { LDAP_CONTROL_NOOP, (int)offsetof(struct slap_control_ids, sc_noOp), - SLAP_CTRL_HIDE|SLAP_CTRL_ACCESS, NULL, + SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, + NULL, NULL, parseNoOp, LDAP_SLIST_ENTRY_INITIALIZER(next) }, -#ifdef LDAP_CONTROL_MODIFY_INCREMENT - { LDAP_CONTROL_MODIFY_INCREMENT, - (int)offsetof(struct slap_control_ids, sc_modifyIncrement), - SLAP_CTRL_HIDE|SLAP_CTRL_MODIFY, NULL, - parseModifyIncrement, LDAP_SLIST_ENTRY_INITIALIZER(next) }, + { LDAP_CONTROL_RELAX, + (int)offsetof(struct slap_control_ids, sc_relax), + SLAP_CTRL_GLOBAL|SLAP_CTRL_UPDATE|SLAP_CTRL_HIDE, + NULL, NULL, + parseRelax, LDAP_SLIST_ENTRY_INITIALIZER(next) }, +#ifdef LDAP_X_TXN + { LDAP_CONTROL_X_TXN_SPEC, + (int)offsetof(struct slap_control_ids, sc_txnSpec), + SLAP_CTRL_UPDATE|SLAP_CTRL_HIDE, + NULL, NULL, + txn_spec_ctrl, LDAP_SLIST_ENTRY_INITIALIZER(next) }, #endif { LDAP_CONTROL_MANAGEDSAIT, (int)offsetof(struct slap_control_ids, sc_manageDSAit), - SLAP_CTRL_ACCESS, NULL, + SLAP_CTRL_ACCESS, + manageDSAit_extops, NULL, parseManageDSAit, LDAP_SLIST_ENTRY_INITIALIZER(next) }, { LDAP_CONTROL_PROXY_AUTHZ, (int)offsetof(struct slap_control_ids, sc_proxyAuthz), - SLAP_CTRL_FRONTEND|SLAP_CTRL_ACCESS, proxy_authz_extops, + SLAP_CTRL_GLOBAL|SLAP_CTRL_ACCESS, + proxy_authz_extops, NULL, parseProxyAuthz, LDAP_SLIST_ENTRY_INITIALIZER(next) }, - { NULL, 0, 0, NULL, 0, LDAP_SLIST_ENTRY_INITIALIZER(next) } +#ifdef SLAP_CONTROL_X_SESSION_TRACKING + { LDAP_CONTROL_X_SESSION_TRACKING, + (int)offsetof(struct slap_control_ids, sc_sessionTracking), + SLAP_CTRL_GLOBAL|SLAP_CTRL_ACCESS|SLAP_CTRL_BIND|SLAP_CTRL_HIDE, + session_tracking_extops, NULL, + parseSessionTracking, LDAP_SLIST_ENTRY_INITIALIZER(next) }, +#endif + { NULL, 0, 0, NULL, 0, NULL, LDAP_SLIST_ENTRY_INITIALIZER(next) } }; +static struct slap_control * +find_ctrl( const char *oid ); + /* * Register a supported control. * * This can be called by an OpenLDAP plugin or, indirectly, by a * SLAPI plugin calling slapi_register_supported_control(). + * + * NOTE: if flags == 1 the control is replaced if already registered; + * otherwise registering an already registered control is not allowed. */ int -register_supported_control(const char *controloid, +register_supported_control2(const char *controloid, slap_mask_t controlmask, char **controlexops, SLAP_CTRL_PARSE_FN *controlparsefn, + unsigned flags, int *controlcid) { - struct slap_control *sc; + struct slap_control *sc = NULL; int i; + BerVarray extendedopsbv = NULL; if ( num_known_controls >= SLAP_MAX_CIDS ) { Debug( LDAP_DEBUG_ANY, "Too many controls registered." @@ -189,11 +251,23 @@ register_supported_control(const char *controloid, return LDAP_OTHER; } - if ( controloid == NULL ) return LDAP_PARAM_ERROR; + if ( controloid == NULL ) { + return LDAP_PARAM_ERROR; + } - /* sanity check - should never happen */ + /* check if already registered */ for ( i = 0; slap_known_controls[ i ]; i++ ) { if ( strcmp( controloid, slap_known_controls[ i ] ) == 0 ) { + if ( flags == 1 ) { + Debug( LDAP_DEBUG_TRACE, + "Control %s already registered; replacing.\n", + controloid, 0, 0 ); + /* (find and) replace existing handler */ + sc = find_ctrl( controloid ); + assert( sc != NULL ); + break; + } + Debug( LDAP_DEBUG_ANY, "Control %s already registered.\n", controloid, 0, 0 ); @@ -201,31 +275,62 @@ register_supported_control(const char *controloid, } } - sc = (struct slap_control *)SLAP_MALLOC( sizeof( *sc ) ); - if ( sc == NULL ) return LDAP_NO_MEMORY; - - sc->sc_oid = ch_strdup( controloid ); - sc->sc_mask = controlmask; + /* turn compatible extended operations into bervals */ if ( controlexops != NULL ) { - sc->sc_extendedops = ldap_charray_dup( controlexops ); - if ( sc->sc_extendedops == NULL ) { - ch_free( sc ); + int i; + + for ( i = 0; controlexops[ i ]; i++ ); + + extendedopsbv = ber_memcalloc( i + 1, sizeof( struct berval ) ); + if ( extendedopsbv == NULL ) { return LDAP_NO_MEMORY; } - } else { - sc->sc_extendedops = NULL; + + for ( i = 0; controlexops[ i ]; i++ ) { + ber_str2bv( controlexops[ i ], 0, 1, &extendedopsbv[ i ] ); + } } - sc->sc_parse = controlparsefn; - if ( controlcid ) *controlcid = num_known_controls; - sc->sc_cid = num_known_controls; + if ( sc == NULL ) { + sc = (struct slap_control *)SLAP_MALLOC( sizeof( *sc ) ); + if ( sc == NULL ) { + return LDAP_NO_MEMORY; + } + + sc->sc_oid = ch_strdup( controloid ); + sc->sc_cid = num_known_controls; + + /* Update slap_known_controls, too. */ + slap_known_controls[num_known_controls - 1] = sc->sc_oid; + slap_known_controls[num_known_controls++] = NULL; + + LDAP_SLIST_NEXT( sc, sc_next ) = NULL; + LDAP_SLIST_INSERT_HEAD( &controls_list, sc, sc_next ); - /* Update slap_known_controls, too. */ - slap_known_controls[num_known_controls-1] = sc->sc_oid; - slap_known_controls[num_known_controls++] = NULL; + } else { + if ( sc->sc_extendedopsbv ) { + /* FIXME: in principle, we should rather merge + * existing extops with those supported by the + * new control handling implementation. + * In fact, whether a control is compatible with + * an extop should not be a matter of implementation. + * We likely also need a means for a newly + * registered extop to declare that it is + * comptible with an already registered control. + */ + ber_bvarray_free( sc->sc_extendedopsbv ); + sc->sc_extendedopsbv = NULL; + sc->sc_extendedops = NULL; + } + } + + sc->sc_extendedopsbv = extendedopsbv; + sc->sc_mask = controlmask; + sc->sc_parse = controlparsefn; + if ( controlcid ) { + *controlcid = sc->sc_cid; + } - LDAP_SLIST_NEXT( sc, sc_next ) = NULL; - LDAP_SLIST_INSERT_HEAD( &controls_list, sc, sc_next ); return LDAP_SUCCESS; } @@ -236,7 +341,6 @@ int slap_controls_init( void ) { int i, rc; - struct slap_control *sc; rc = LDAP_SUCCESS; @@ -264,8 +368,8 @@ controls_destroy( void ) LDAP_SLIST_REMOVE_HEAD(&controls_list, sc_next); ch_free( sc->sc_oid ); - if ( sc->sc_extendedops != NULL ) { - ldap_charray_free( sc->sc_extendedops ); + if ( sc->sc_extendedopsbv != NULL ) { + ber_bvarray_free( sc->sc_extendedopsbv ); } ch_free( sc ); } @@ -309,10 +413,9 @@ int get_supported_controls(char ***ctrloidsp, slap_mask_t **ctrlmasks) { - int i, n; + int n; char **oids; slap_mask_t *masks; - int rc; struct slap_control *sc; n = 0; @@ -333,7 +436,7 @@ get_supported_controls(char ***ctrloidsp, } masks = (slap_mask_t *)SLAP_MALLOC( (n + 1) * sizeof(slap_mask_t) ); if ( masks == NULL ) { - ch_free( oids ); + SLAP_FREE( oids ); return LDAP_NO_MEMORY; } @@ -383,6 +486,37 @@ slap_find_control_id( return LDAP_CONTROL_NOT_FOUND; } +int +slap_global_control( Operation *op, const char *oid, int *cid ) +{ + struct slap_control *ctrl = find_ctrl( oid ); + + if ( ctrl == NULL ) { + /* should not be reachable */ + Debug( LDAP_DEBUG_ANY, + "slap_global_control: unrecognized control: %s\n", + oid, 0, 0 ); + return LDAP_CONTROL_NOT_FOUND; + } + + if ( cid ) *cid = ctrl->sc_cid; + + if ( ( ctrl->sc_mask & SLAP_CTRL_GLOBAL ) || + ( ( op->o_tag & LDAP_REQ_SEARCH ) && + ( ctrl->sc_mask & SLAP_CTRL_GLOBAL_SEARCH ) ) ) + { + return LDAP_COMPARE_TRUE; + } + +#if 0 + Debug( LDAP_DEBUG_TRACE, + "slap_global_control: unavailable control: %s\n", + oid, 0, 0 ); +#endif + + return LDAP_COMPARE_FALSE; +} + void slap_free_ctrls( Operation *op, LDAPControl **ctrls ) @@ -395,6 +529,95 @@ void slap_free_ctrls( op->o_tmpfree( ctrls, op->o_tmpmemctx ); } +int slap_parse_ctrl( + Operation *op, + SlapReply *rs, + LDAPControl *control, + const char **text ) +{ + struct slap_control *sc; + + sc = find_ctrl( control->ldctl_oid ); + if( sc != NULL ) { + /* recognized control */ + slap_mask_t tagmask; + switch( op->o_tag ) { + case LDAP_REQ_ADD: + tagmask = SLAP_CTRL_ADD; + break; + case LDAP_REQ_BIND: + tagmask = SLAP_CTRL_BIND; + break; + case LDAP_REQ_COMPARE: + tagmask = SLAP_CTRL_COMPARE; + break; + case LDAP_REQ_DELETE: + tagmask = SLAP_CTRL_DELETE; + break; + case LDAP_REQ_MODIFY: + tagmask = SLAP_CTRL_MODIFY; + break; + case LDAP_REQ_RENAME: + tagmask = SLAP_CTRL_RENAME; + break; + case LDAP_REQ_SEARCH: + tagmask = SLAP_CTRL_SEARCH; + break; + case LDAP_REQ_UNBIND: + tagmask = SLAP_CTRL_UNBIND; + break; + case LDAP_REQ_ABANDON: + tagmask = SLAP_CTRL_ABANDON; + break; + case LDAP_REQ_EXTENDED: + tagmask=~0L; + assert( op->ore_reqoid.bv_val != NULL ); + if( sc->sc_extendedopsbv != NULL ) { + int i; + for( i=0; !BER_BVISNULL( &sc->sc_extendedopsbv[i] ); i++ ) { + if( bvmatch( &op->ore_reqoid, + &sc->sc_extendedopsbv[i] ) ) + { + tagmask=0L; + break; + } + } + } + break; + default: + *text = "controls internal error"; + return LDAP_OTHER; + } + + if (( sc->sc_mask & tagmask ) == tagmask ) { + /* available extension */ + int rc; + + if( !sc->sc_parse ) { + *text = "not yet implemented"; + return LDAP_OTHER; + } + + rc = sc->sc_parse( op, rs, control ); + if ( rc ) { + assert( rc != LDAP_UNAVAILABLE_CRITICAL_EXTENSION ); + return rc; + } + + } else if( control->ldctl_iscritical ) { + /* unavailable CRITICAL control */ + *text = "critical extension is unavailable"; + return LDAP_UNAVAILABLE_CRITICAL_EXTENSION; + } + } else if( control->ldctl_iscritical ) { + /* unrecognized CRITICAL control */ + *text = "critical extension is not recognized"; + return LDAP_UNAVAILABLE_CRITICAL_EXTENSION; + } + + return LDAP_SUCCESS; +} + int get_ctrls( Operation *op, SlapReply *rs, @@ -405,7 +628,6 @@ int get_ctrls( ber_len_t len; char *opaque; BerElement *ber = op->o_ber; - struct slap_control *sc; struct berval bv; len = ber_pvt_ber_remaining(ber); @@ -545,101 +767,10 @@ int get_ctrls( "=> get_ctrls: oid=\"%s\" (%scritical)\n", c->ldctl_oid, c->ldctl_iscritical ? "" : "non", 0 ); - sc = find_ctrl( c->ldctl_oid ); - if( sc != NULL ) { - /* recognized control */ - slap_mask_t tagmask; - switch( op->o_tag ) { - case LDAP_REQ_ADD: - tagmask = SLAP_CTRL_ADD; - break; - case LDAP_REQ_BIND: - tagmask = SLAP_CTRL_BIND; - break; - case LDAP_REQ_COMPARE: - tagmask = SLAP_CTRL_COMPARE; - break; - case LDAP_REQ_DELETE: - tagmask = SLAP_CTRL_DELETE; - break; - case LDAP_REQ_MODIFY: - tagmask = SLAP_CTRL_MODIFY; - break; - case LDAP_REQ_RENAME: - tagmask = SLAP_CTRL_RENAME; - break; - case LDAP_REQ_SEARCH: - tagmask = SLAP_CTRL_SEARCH; - break; - case LDAP_REQ_UNBIND: - tagmask = SLAP_CTRL_UNBIND; - break; - case LDAP_REQ_ABANDON: - tagmask = SLAP_CTRL_ABANDON; - break; - case LDAP_REQ_EXTENDED: - tagmask=~0L; - assert( op->ore_reqoid.bv_val != NULL ); - if( sc->sc_extendedops != NULL ) { - int i; - for( i=0; sc->sc_extendedops[i] != NULL; i++ ) { - if( strcmp( op->ore_reqoid.bv_val, - sc->sc_extendedops[i] ) == 0 ) - { - tagmask=0L; - break; - } - } - } - break; - default: - rs->sr_err = LDAP_OTHER; - rs->sr_text = "controls internal error"; - goto return_results; - } - - if (( sc->sc_mask & tagmask ) == tagmask ) { - /* available extension */ - int rc; - - if( !sc->sc_parse ) { - rs->sr_err = LDAP_OTHER; - rs->sr_text = "not yet implemented"; - goto return_results; - } - - rc = sc->sc_parse( op, rs, c ); - if ( rc ) { - assert( rc != LDAP_UNAVAILABLE_CRITICAL_EXTENSION ); - rs->sr_err = rc; - goto return_results; - } - - if ( sc->sc_mask & SLAP_CTRL_FRONTEND ) { - /* kludge to disable backend_control() check */ - c->ldctl_iscritical = 0; - - } else if ( tagmask == SLAP_CTRL_SEARCH && - sc->sc_mask & SLAP_CTRL_FRONTEND_SEARCH ) - { - /* kludge to disable backend_control() check */ - c->ldctl_iscritical = 0; - } - - } else if( c->ldctl_iscritical ) { - /* unavailable CRITICAL control */ - rs->sr_err = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; - rs->sr_text = "critical extension is unavailable"; - goto return_results; - } - - } else if( c->ldctl_iscritical ) { - /* unrecognized CRITICAL control */ - rs->sr_err = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; - rs->sr_text = "critical extension is not recognized"; + rs->sr_err = slap_parse_ctrl( op, rs, c, &rs->sr_text ); + if ( rs->sr_err != LDAP_SUCCESS ) { goto return_results; } -next_ctrl:; } return_results: @@ -660,28 +791,117 @@ return_results: return rs->sr_err; } -static int parseModifyIncrement ( +int +slap_remove_control( + Operation *op, + SlapReply *rs, + int ctrl, + BI_chk_controls fnc ) +{ + int i, j; + + switch ( op->o_ctrlflag[ ctrl ] ) { + case SLAP_CONTROL_NONCRITICAL: + for ( i = 0, j = -1; op->o_ctrls[ i ] != NULL; i++ ) { + if ( strcmp( op->o_ctrls[ i ]->ldctl_oid, + slap_known_controls[ ctrl - 1 ] ) == 0 ) + { + j = i; + } + } + + if ( j == -1 ) { + rs->sr_err = LDAP_OTHER; + break; + } + + if ( fnc ) { + (void)fnc( op, rs ); + } + + op->o_tmpfree( op->o_ctrls[ j ], op->o_tmpmemctx ); + + if ( i > 1 ) { + AC_MEMCPY( &op->o_ctrls[ j ], &op->o_ctrls[ j + 1 ], + ( i - j ) * sizeof( LDAPControl * ) ); + + } else { + op->o_tmpfree( op->o_ctrls, op->o_tmpmemctx ); + op->o_ctrls = NULL; + } + + op->o_ctrlflag[ ctrl ] = SLAP_CONTROL_IGNORED; + + Debug( LDAP_DEBUG_ANY, "%s: " + "non-critical control \"%s\" not supported; stripped.\n", + op->o_log_prefix, slap_known_controls[ ctrl ], 0 ); + /* fall thru */ + + case SLAP_CONTROL_IGNORED: + case SLAP_CONTROL_NONE: + rs->sr_err = SLAP_CB_CONTINUE; + break; + + case SLAP_CONTROL_CRITICAL: + rs->sr_err = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; + if ( fnc ) { + (void)fnc( op, rs ); + } + Debug( LDAP_DEBUG_ANY, "%s: " + "critical control \"%s\" not supported.\n", + op->o_log_prefix, slap_known_controls[ ctrl ], 0 ); + break; + + default: + /* handle all cases! */ + assert( 0 ); + } + + return rs->sr_err; +} + +static int parseDontUseCopy ( Operation *op, SlapReply *rs, LDAPControl *ctrl ) { -#if 0 - if ( op->o_modifyIncrement != SLAP_CONTROL_NONE ) { - rs->sr_text = "modifyIncrement control specified multiple times"; + if ( op->o_dontUseCopy != SLAP_CONTROL_NONE ) { + rs->sr_text = "dontUseCopy control specified multiple times"; return LDAP_PROTOCOL_ERROR; } -#endif - if ( ctrl->ldctl_value.bv_len ) { - rs->sr_text = "modifyIncrement control value not empty"; + if ( !BER_BVISNULL( &ctrl->ldctl_value )) { + rs->sr_text = "dontUseCopy control value not absent"; return LDAP_PROTOCOL_ERROR; } -#if 0 - op->o_modifyIncrement = ctrl->ldctl_iscritical + if ( !ctrl->ldctl_iscritical ) { + rs->sr_text = "dontUseCopy criticality of FALSE not allowed"; + return LDAP_PROTOCOL_ERROR; + } + + op->o_dontUseCopy = SLAP_CONTROL_CRITICAL; + return LDAP_SUCCESS; +} + +static int parseRelax ( + Operation *op, + SlapReply *rs, + LDAPControl *ctrl ) +{ + if ( op->o_relax != SLAP_CONTROL_NONE ) { + rs->sr_text = "relax control specified multiple times"; + return LDAP_PROTOCOL_ERROR; + } + + if ( !BER_BVISNULL( &ctrl->ldctl_value )) { + rs->sr_text = "relax control value not absent"; + return LDAP_PROTOCOL_ERROR; + } + + op->o_relax = ctrl->ldctl_iscritical ? SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL; -#endif return LDAP_SUCCESS; } @@ -696,8 +916,8 @@ static int parseManageDSAit ( return LDAP_PROTOCOL_ERROR; } - if ( ctrl->ldctl_value.bv_len ) { - rs->sr_text = "manageDSAit control value not empty"; + if ( !BER_BVISNULL( &ctrl->ldctl_value )) { + rs->sr_text = "manageDSAit control value not absent"; return LDAP_PROTOCOL_ERROR; } @@ -721,6 +941,18 @@ static int parseProxyAuthz ( return LDAP_PROTOCOL_ERROR; } + if ( BER_BVISNULL( &ctrl->ldctl_value )) { + rs->sr_text = "proxy authorization control value absent"; + return LDAP_PROTOCOL_ERROR; + } + + if ( !( global_allows & SLAP_ALLOW_PROXY_AUTHZ_ANON ) + && BER_BVISEMPTY( &op->o_ndn ) ) + { + rs->sr_text = "anonymous proxied authorization not allowed"; + return LDAP_PROXIED_AUTHORIZATION_DENIED; + } + op->o_proxy_authz = ctrl->ldctl_iscritical ? SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL; @@ -731,19 +963,21 @@ static int parseProxyAuthz ( ctrl->ldctl_value.bv_len ? ctrl->ldctl_value.bv_val : "anonymous", 0 ); - if( ctrl->ldctl_value.bv_len == 0 ) { + if ( BER_BVISEMPTY( &ctrl->ldctl_value )) { Debug( LDAP_DEBUG_TRACE, "parseProxyAuthz: conn=%lu anonymous\n", op->o_connid, 0, 0 ); /* anonymous */ - free( op->o_dn.bv_val ); - op->o_dn.bv_len = 0; - op->o_dn.bv_val = ch_strdup( "" ); - - free( op->o_ndn.bv_val ); + if ( !BER_BVISNULL( &op->o_ndn ) ) { + op->o_ndn.bv_val[ 0 ] = '\0'; + } op->o_ndn.bv_len = 0; - op->o_ndn.bv_val = ch_strdup( "" ); + + if ( !BER_BVISNULL( &op->o_dn ) ) { + op->o_dn.bv_val[ 0 ] = '\0'; + } + op->o_dn.bv_len = 0; return LDAP_SUCCESS; } @@ -757,7 +991,7 @@ static int parseProxyAuthz ( ch_free( dn.bv_val ); } rs->sr_text = "authzId mapping failed"; - return LDAP_PROXY_AUTHZ_FAILURE; + return LDAP_PROXIED_AUTHORIZATION_DENIED; } Debug( LDAP_DEBUG_TRACE, @@ -767,27 +1001,25 @@ static int parseProxyAuthz ( rc = slap_sasl_authorized( op, &op->o_ndn, &dn ); - if( rc ) { + if ( rc ) { ch_free( dn.bv_val ); rs->sr_text = "not authorized to assume identity"; - return LDAP_PROXY_AUTHZ_FAILURE; + return LDAP_PROXIED_AUTHORIZATION_DENIED; } - ch_free( op->o_dn.bv_val ); ch_free( op->o_ndn.bv_val ); - - op->o_dn.bv_val = NULL; - op->o_ndn = dn; - - Statslog( LDAP_DEBUG_STATS, "%s PROXYAUTHZ dn=\"%s\"\n", - op->o_log_prefix, dn.bv_val, 0, 0, 0 ); + ch_free( op->o_dn.bv_val ); /* * NOTE: since slap_sasl_getdn() returns a normalized dn, * from now on op->o_dn is normalized */ + op->o_ndn = dn; ber_dupbv( &op->o_dn, &dn ); + Statslog( LDAP_DEBUG_STATS, "%s PROXYAUTHZ dn=\"%s\"\n", + op->o_log_prefix, dn.bv_val, 0, 0, 0 ); + return LDAP_SUCCESS; } @@ -801,7 +1033,7 @@ static int parseNoOp ( return LDAP_PROTOCOL_ERROR; } - if ( ctrl->ldctl_value.bv_len ) { + if ( !BER_BVISNULL( &ctrl->ldctl_value ) ) { rs->sr_text = "noop control value not empty"; return LDAP_PROTOCOL_ERROR; } @@ -818,27 +1050,26 @@ static int parsePagedResults ( SlapReply *rs, LDAPControl *ctrl ) { + BerElementBuffer berbuf; + BerElement *ber = (BerElement *)&berbuf; + struct berval cookie; + PagedResultsState *ps; int rc = LDAP_SUCCESS; ber_tag_t tag; ber_int_t size; - BerElement *ber; - struct berval cookie = BER_BVNULL; - PagedResultsState *ps; if ( op->o_pagedresults != SLAP_CONTROL_NONE ) { rs->sr_text = "paged results control specified multiple times"; return LDAP_PROTOCOL_ERROR; } -#if 0 /* DELETE ME */ - if ( op->o_sync != SLAP_CONTROL_NONE ) { - rs->sr_text = "paged results control specified with sync control"; + if ( BER_BVISNULL( &ctrl->ldctl_value ) ) { + rs->sr_text = "paged results control value is absent"; return LDAP_PROTOCOL_ERROR; } -#endif if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) { - rs->sr_text = "paged results control value is empty (or absent)"; + rs->sr_text = "paged results control value is empty"; return LDAP_PROTOCOL_ERROR; } @@ -850,11 +1081,7 @@ static int parsePagedResults ( * cookie OCTET STRING * } */ - ber = ber_init( &ctrl->ldctl_value ); - if ( ber == NULL ) { - rs->sr_text = "internal error"; - return LDAP_OTHER; - } + ber_init2( ber, &ctrl->ldctl_value, LBER_USE_DER ); tag = ber_scanf( ber, "{im}", &size, &cookie ); @@ -870,52 +1097,15 @@ static int parsePagedResults ( goto done; } -#if 0 - /* defer cookie decoding/checks to backend... */ - if ( cookie.bv_len ) { - PagedResultsCookie reqcookie; - if( cookie.bv_len != sizeof( reqcookie ) ) { - /* bad cookie */ - rs->sr_text = "paged results cookie is invalid"; - rc = LDAP_PROTOCOL_ERROR; - goto done; - } - - AC_MEMCPY( &reqcookie, cookie.bv_val, sizeof( reqcookie )); - - if ( reqcookie > op->o_pagedresults_state.ps_cookie ) { - /* bad cookie */ - rs->sr_text = "paged results cookie is invalid"; - rc = LDAP_PROTOCOL_ERROR; - goto done; - - } else if ( reqcookie < op->o_pagedresults_state.ps_cookie ) { - rs->sr_text = "paged results cookie is invalid or old"; - rc = LDAP_UNWILLING_TO_PERFORM; - goto done; - } - - } else { - /* Initial request. Initialize state. */ -#if 0 - if ( op->o_conn->c_pagedresults_state.ps_cookie != 0 ) { - /* There's another pagedResults control on the - * same connection; reject new pagedResults controls - * (allowed by RFC2696) */ - rs->sr_text = "paged results cookie unavailable; try later"; - rc = LDAP_UNWILLING_TO_PERFORM; - goto done; - } -#endif - op->o_pagedresults_state.ps_cookie = 0; - op->o_pagedresults_state.ps_count = 0; - } -#endif - ps = op->o_tmpalloc( sizeof(PagedResultsState), op->o_tmpmemctx ); *ps = op->o_conn->c_pagedresults_state; ps->ps_size = size; + ps->ps_cookieval = cookie; op->o_pagedresults_state = ps; + if ( !cookie.bv_len ) { + ps->ps_count = 0; + ps->ps_cookie = 0; + } /* NOTE: according to RFC 2696 3.: @@ -938,10 +1128,42 @@ static int parsePagedResults ( } done:; - (void)ber_free( ber, 1 ); return rc; } +#ifdef SLAP_CONTROL_X_SORTEDRESULTS +static int parseSortedResults ( + Operation *op, + SlapReply *rs, + LDAPControl *ctrl ) +{ + int rc = LDAP_SUCCESS; + + if ( op->o_sortedresults != SLAP_CONTROL_NONE ) { + rs->sr_text = "sorted results control specified multiple times"; + return LDAP_PROTOCOL_ERROR; + } + + if ( BER_BVISNULL( &ctrl->ldctl_value ) ) { + rs->sr_text = "sorted results control value is absent"; + return LDAP_PROTOCOL_ERROR; + } + + if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) { + rs->sr_text = "sorted results control value is empty"; + return LDAP_PROTOCOL_ERROR; + } + + /* blow off parsing the value */ + + op->o_sortedresults = ctrl->ldctl_iscritical + ? SLAP_CONTROL_CRITICAL + : SLAP_CONTROL_NONCRITICAL; + + return rc; +} +#endif + static int parseAssert ( Operation *op, SlapReply *rs, @@ -949,15 +1171,19 @@ static int parseAssert ( { BerElement *ber; struct berval fstr = BER_BVNULL; - const char *err_msg = ""; if ( op->o_assert != SLAP_CONTROL_NONE ) { rs->sr_text = "assert control specified multiple times"; return LDAP_PROTOCOL_ERROR; } - if ( ctrl->ldctl_value.bv_len == 0 ) { - rs->sr_text = "assert control value is empty (or absent)"; + if ( BER_BVISNULL( &ctrl->ldctl_value )) { + rs->sr_text = "assert control value is absent"; + return LDAP_PROTOCOL_ERROR; + } + + if ( BER_BVISEMPTY( &ctrl->ldctl_value )) { + rs->sr_text = "assert control value is empty"; return LDAP_PROTOCOL_ERROR; } @@ -967,8 +1193,9 @@ static int parseAssert ( return LDAP_OTHER; } - rs->sr_err = get_filter( op, ber, (Filter **)&(op->o_assertion), &rs->sr_text); - + rs->sr_err = get_filter( op, ber, (Filter **)&(op->o_assertion), + &rs->sr_text); + (void) ber_free( ber, 1 ); if( rs->sr_err != LDAP_SUCCESS ) { if( rs->sr_err == SLAPD_DISCONNECT ) { rs->sr_err = LDAP_PROTOCOL_ERROR; @@ -1013,37 +1240,51 @@ static int parsePreRead ( return LDAP_PROTOCOL_ERROR; } - if ( ctrl->ldctl_value.bv_len == 0 ) { - rs->sr_text = "preread control value is empty (or absent)"; + if ( BER_BVISNULL( &ctrl->ldctl_value )) { + rs->sr_text = "preread control value is absent"; return LDAP_PROTOCOL_ERROR; } + if ( BER_BVISEMPTY( &ctrl->ldctl_value )) { + rs->sr_text = "preread control value is empty"; + return LDAP_PROTOCOL_ERROR; + } + +#ifdef LDAP_X_TXN + if ( op->o_txnSpec ) { /* temporary limitation */ + rs->sr_text = "cannot perform pre-read in transaction"; + return LDAP_UNWILLING_TO_PERFORM; + } +#endif + ber = ber_init( &(ctrl->ldctl_value) ); if (ber == NULL) { rs->sr_text = "preread control: internal error"; return LDAP_OTHER; } + rs->sr_err = LDAP_SUCCESS; + siz = sizeof( AttributeName ); off = offsetof( AttributeName, an_name ); if ( ber_scanf( ber, "{M}", &an, &siz, off ) == LBER_ERROR ) { rs->sr_text = "preread control: decoding error"; - return LDAP_PROTOCOL_ERROR; + rs->sr_err = LDAP_PROTOCOL_ERROR; + goto done; } for( i=0; ildctl_iscritical ) { + rs->sr_err = slap_bv2ad( &an[i].an_name, &an[i].an_desc, &dummy ); + if ( rs->sr_err != LDAP_SUCCESS && ctrl->ldctl_iscritical ) { rs->sr_text = dummy ? dummy : "postread control: unknown attributeType"; - return rc; + goto done; } } @@ -1053,8 +1294,9 @@ static int parsePreRead ( op->o_preread_attrs = an; - rs->sr_err = LDAP_SUCCESS; - return LDAP_SUCCESS; +done: + (void) ber_free( ber, 1 ); + return rs->sr_err; } static int parsePostRead ( @@ -1071,37 +1313,69 @@ static int parsePostRead ( return LDAP_PROTOCOL_ERROR; } - if ( ctrl->ldctl_value.bv_len == 0 ) { - rs->sr_text = "postread control value is empty (or absent)"; + if ( BER_BVISNULL( &ctrl->ldctl_value )) { + rs->sr_text = "postread control value is absent"; + return LDAP_PROTOCOL_ERROR; + } + + if ( BER_BVISEMPTY( &ctrl->ldctl_value )) { + rs->sr_text = "postread control value is empty"; return LDAP_PROTOCOL_ERROR; } +#ifdef LDAP_X_TXN + if ( op->o_txnSpec ) { /* temporary limitation */ + rs->sr_text = "cannot perform post-read in transaction"; + return LDAP_UNWILLING_TO_PERFORM; + } +#endif + ber = ber_init( &(ctrl->ldctl_value) ); if (ber == NULL) { rs->sr_text = "postread control: internal error"; return LDAP_OTHER; } + rs->sr_err = LDAP_SUCCESS; siz = sizeof( AttributeName ); off = offsetof( AttributeName, an_name ); if ( ber_scanf( ber, "{M}", &an, &siz, off ) == LBER_ERROR ) { rs->sr_text = "postread control: decoding error"; - return LDAP_PROTOCOL_ERROR; + rs->sr_err = LDAP_PROTOCOL_ERROR; + goto done; } - for( i=0; ildctl_iscritical ) { - rs->sr_text = dummy - ? dummy - : "postread control: unknown attributeType"; - return rc; + if ( rc != LDAP_SUCCESS ) { + int i; + static struct berval special_attrs[] = { + BER_BVC( LDAP_NO_ATTRS ), + BER_BVC( LDAP_ALL_USER_ATTRIBUTES ), + BER_BVC( LDAP_ALL_OPERATIONAL_ATTRIBUTES ), + BER_BVNULL + }; + + /* deal with special attribute types */ + for ( i = 0; !BER_BVISNULL( &special_attrs[ i ] ); i++ ) { + if ( bvmatch( &an[i].an_name, &special_attrs[ i ] ) ) { + break; + } + } + + if ( BER_BVISNULL( &special_attrs[ i ] ) && ctrl->ldctl_iscritical ) { + rs->sr_err = rc; + rs->sr_text = dummy + ? dummy + : "postread control: unknown attributeType"; + goto done; + } } } @@ -1111,26 +1385,31 @@ static int parsePostRead ( op->o_postread_attrs = an; - rs->sr_err = LDAP_SUCCESS; - return LDAP_SUCCESS; +done: + (void) ber_free( ber, 1 ); + return rs->sr_err; } -int parseValuesReturnFilter ( +static int parseValuesReturnFilter ( Operation *op, SlapReply *rs, LDAPControl *ctrl ) { BerElement *ber; struct berval fstr = BER_BVNULL; - const char *err_msg = ""; if ( op->o_valuesreturnfilter != SLAP_CONTROL_NONE ) { rs->sr_text = "valuesReturnFilter control specified multiple times"; return LDAP_PROTOCOL_ERROR; } - if ( ctrl->ldctl_value.bv_len == 0 ) { - rs->sr_text = "valuesReturnFilter control value is empty (or absent)"; + if ( BER_BVISNULL( &ctrl->ldctl_value )) { + rs->sr_text = "valuesReturnFilter control value is absent"; + return LDAP_PROTOCOL_ERROR; + } + + if ( BER_BVISEMPTY( &ctrl->ldctl_value )) { + rs->sr_text = "valuesReturnFilter control value is empty"; return LDAP_PROTOCOL_ERROR; } @@ -1140,7 +1419,10 @@ int parseValuesReturnFilter ( return LDAP_OTHER; } - rs->sr_err = get_vrFilter( op, ber, (ValuesReturnFilter **)&(op->o_vrFilter), &rs->sr_text); + rs->sr_err = get_vrFilter( op, ber, + (ValuesReturnFilter **)&(op->o_vrFilter), &rs->sr_text); + + (void) ber_free( ber, 1 ); if( rs->sr_err != LDAP_SUCCESS ) { if( rs->sr_err == SLAPD_DISCONNECT ) { @@ -1170,7 +1452,6 @@ int parseValuesReturnFilter ( return LDAP_SUCCESS; } -#ifdef LDAP_CONTROL_SUBENTRIES static int parseSubentries ( Operation *op, SlapReply *rs, @@ -1183,8 +1464,8 @@ static int parseSubentries ( /* FIXME: should use BER library */ if( ( ctrl->ldctl_value.bv_len != 3 ) - && ( ctrl->ldctl_value.bv_val[0] != 0x01 ) - && ( ctrl->ldctl_value.bv_val[1] != 0x01 )) + || ( ctrl->ldctl_value.bv_val[0] != 0x01 ) + || ( ctrl->ldctl_value.bv_val[1] != 0x01 )) { rs->sr_text = "subentries control value encoding is bogus"; return LDAP_PROTOCOL_ERROR; @@ -1194,14 +1475,13 @@ static int parseSubentries ( ? SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL; - if ( (void *)(ctrl->ldctl_value.bv_val[2] != 0x00)) + if (ctrl->ldctl_value.bv_val[2]) { set_subentries_visibility( op ); + } return LDAP_SUCCESS; } -#endif -#ifdef LDAP_CONTROL_X_PERMISSIVE_MODIFY static int parsePermissiveModify ( Operation *op, SlapReply *rs, @@ -1212,8 +1492,8 @@ static int parsePermissiveModify ( return LDAP_PROTOCOL_ERROR; } - if ( ctrl->ldctl_value.bv_len ) { - rs->sr_text = "permissiveModify control value not empty"; + if ( BER_BVISNULL( &ctrl->ldctl_value )) { + rs->sr_text = "permissiveModify control value not absent"; return LDAP_PROTOCOL_ERROR; } @@ -1223,9 +1503,7 @@ static int parsePermissiveModify ( return LDAP_SUCCESS; } -#endif -#ifdef LDAP_CONTROL_X_DOMAIN_SCOPE static int parseDomainScope ( Operation *op, SlapReply *rs, @@ -1236,7 +1514,7 @@ static int parseDomainScope ( return LDAP_PROTOCOL_ERROR; } - if ( ctrl->ldctl_value.bv_len ) { + if ( BER_BVISNULL( &ctrl->ldctl_value )) { rs->sr_text = "domainScope control value not empty"; return LDAP_PROTOCOL_ERROR; } @@ -1247,9 +1525,8 @@ static int parseDomainScope ( return LDAP_SUCCESS; } -#endif -#ifdef LDAP_CONTROL_X_TREE_DELETE +#ifdef SLAP_CONTROL_X_TREE_DELETE static int parseTreeDelete ( Operation *op, SlapReply *rs, @@ -1260,8 +1537,8 @@ static int parseTreeDelete ( return LDAP_PROTOCOL_ERROR; } - if ( ctrl->ldctl_value.bv_len ) { - rs->sr_text = "treeDelete control value not empty"; + if ( !BER_BVISNULL( &ctrl->ldctl_value )) { + rs->sr_text = "treeDelete control value not absent"; return LDAP_PROTOCOL_ERROR; } @@ -1273,7 +1550,6 @@ static int parseTreeDelete ( } #endif -#ifdef LDAP_CONTORL_X_SEARCH_OPTIONS static int parseSearchOptions ( Operation *op, SlapReply *rs, @@ -1281,9 +1557,15 @@ static int parseSearchOptions ( { BerElement *ber; ber_int_t search_flags; + ber_tag_t tag; - if ( ctrl->ldctl_value.bv_len == 0 ) { - rs->sr_text = "searchOptions control value not empty"; + if ( BER_BVISNULL( &ctrl->ldctl_value )) { + rs->sr_text = "searchOptions control value is absent"; + return LDAP_PROTOCOL_ERROR; + } + + if ( BER_BVISEMPTY( &ctrl->ldctl_value )) { + rs->sr_text = "searchOptions control value is empty"; return LDAP_PROTOCOL_ERROR; } @@ -1293,13 +1575,14 @@ static int parseSearchOptions ( return LDAP_OTHER; } - if ( (tag = ber_scanf( ber, "{i}", &search_flags )) == LBER_ERROR ) { + tag = ber_scanf( ber, "{i}", &search_flags ); + (void) ber_free( ber, 1 ); + + if ( tag == LBER_ERROR ) { rs->sr_text = "searchOptions control decoding error"; return LDAP_PROTOCOL_ERROR; } - (void) ber_free( ber, 1 ); - if ( search_flags & LDAP_SEARCH_FLAG_DOMAIN_SCOPE ) { if ( op->o_domain_scope != SLAP_CONTROL_NONE ) { rs->sr_text = "searchOptions control specified multiple times " @@ -1313,12 +1596,313 @@ static int parseSearchOptions ( } if ( search_flags & ~(LDAP_SEARCH_FLAG_DOMAIN_SCOPE) ) { - /* Other search flags not recognised so far */ - rs->sr_text = "searchOptions contained unrecongized flag"; + /* Other search flags not recognised so far, + * including: + * LDAP_SEARCH_FLAG_PHANTOM_ROOM + */ + rs->sr_text = "searchOptions contained unrecognized flag"; return LDAP_UNWILLING_TO_PERFORM; } return LDAP_SUCCESS; } -#endif +#ifdef SLAP_CONTROL_X_SESSION_TRACKING +struct berval session_tracking_formats[] = { + BER_BVC( LDAP_CONTROL_X_SESSION_TRACKING_RADIUS_ACCT_SESSION_ID ), + BER_BVC( "RADIUS-Acct-Session-Id" ), + BER_BVC( LDAP_CONTROL_X_SESSION_TRACKING_RADIUS_ACCT_MULTI_SESSION_ID ), + BER_BVC( "RADIUS-Acct-Multi-Session-Id" ), + BER_BVC( LDAP_CONTROL_X_SESSION_TRACKING_USERNAME ), + BER_BVC( "USERNAME" ), + + BER_BVNULL +}; + +static int parseSessionTracking( + Operation *op, + SlapReply *rs, + LDAPControl *ctrl ) +{ + BerElement *ber; + ber_tag_t tag; + ber_len_t len; + int i, rc; + + struct berval sessionSourceIp = BER_BVNULL, + sessionSourceName = BER_BVNULL, + formatOID = BER_BVNULL, + sessionTrackingIdentifier = BER_BVNULL; + + size_t st_len, st_pos; + + if ( ctrl->ldctl_iscritical ) { + rs->sr_text = "sessionTracking criticality is TRUE"; + return LDAP_PROTOCOL_ERROR; + } + + if ( BER_BVISNULL( &ctrl->ldctl_value ) ) { + rs->sr_text = "sessionTracking control value is absent"; + return LDAP_PROTOCOL_ERROR; + } + + if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) { + rs->sr_text = "sessionTracking control value is empty"; + return LDAP_PROTOCOL_ERROR; + } + + /* TODO: add the capability to determine if a client is allowed + * to use this control, based on identity, ip and so */ + + ber = ber_init( &ctrl->ldctl_value ); + if ( ber == NULL ) { + rs->sr_text = "internal error"; + return LDAP_OTHER; + } + + tag = ber_skip_tag( ber, &len ); + if ( tag != LBER_SEQUENCE ) { + tag = LBER_ERROR; + goto error; + } + + /* sessionSourceIp */ + tag = ber_peek_tag( ber, &len ); + if ( tag == LBER_DEFAULT ) { + tag = LBER_ERROR; + goto error; + } + + if ( len == 0 ) { + tag = ber_skip_tag( ber, &len ); + + } else if ( len > 128 ) { + rs->sr_text = "sessionTracking.sessionSourceIp too long"; + rs->sr_err = LDAP_PROTOCOL_ERROR; + goto error; + + } else { + tag = ber_scanf( ber, "m", &sessionSourceIp ); + } + + if ( ldif_is_not_printable( sessionSourceIp.bv_val, sessionSourceIp.bv_len ) ) { + BER_BVZERO( &sessionSourceIp ); + } + + /* sessionSourceName */ + tag = ber_peek_tag( ber, &len ); + if ( tag == LBER_DEFAULT ) { + tag = LBER_ERROR; + goto error; + } + + if ( len == 0 ) { + tag = ber_skip_tag( ber, &len ); + + } else if ( len > 65536 ) { + rs->sr_text = "sessionTracking.sessionSourceName too long"; + rs->sr_err = LDAP_PROTOCOL_ERROR; + goto error; + + } else { + tag = ber_scanf( ber, "m", &sessionSourceName ); + } + + if ( ldif_is_not_printable( sessionSourceName.bv_val, sessionSourceName.bv_len ) ) { + BER_BVZERO( &sessionSourceName ); + } + + /* formatOID */ + tag = ber_peek_tag( ber, &len ); + if ( tag == LBER_DEFAULT ) { + tag = LBER_ERROR; + goto error; + } + + if ( len == 0 ) { + rs->sr_text = "sessionTracking.formatOID empty"; + rs->sr_err = LDAP_PROTOCOL_ERROR; + goto error; + + } else if ( len > 1024 ) { + rs->sr_text = "sessionTracking.formatOID too long"; + rs->sr_err = LDAP_PROTOCOL_ERROR; + goto error; + + } else { + tag = ber_scanf( ber, "m", &formatOID ); + } + + rc = numericoidValidate( NULL, &formatOID ); + if ( rc != LDAP_SUCCESS ) { + rs->sr_text = "sessionTracking.formatOID invalid"; + goto error; + } + + for ( i = 0; !BER_BVISNULL( &session_tracking_formats[ i ] ); i += 2 ) + { + if ( bvmatch( &formatOID, &session_tracking_formats[ i ] ) ) { + formatOID = session_tracking_formats[ i + 1 ]; + break; + } + } + + /* sessionTrackingIdentifier */ + tag = ber_peek_tag( ber, &len ); + if ( tag == LBER_DEFAULT ) { + tag = LBER_ERROR; + goto error; + } + + if ( len == 0 ) { + tag = ber_skip_tag( ber, &len ); + + } else { + /* note: should not be more than 65536... */ + tag = ber_scanf( ber, "m", &sessionTrackingIdentifier ); + if ( ldif_is_not_printable( sessionTrackingIdentifier.bv_val, sessionTrackingIdentifier.bv_len ) ) { + /* we want the OID printed, at least */ + BER_BVSTR( &sessionTrackingIdentifier, "" ); + } + } + + /* closure */ + tag = ber_skip_tag( ber, &len ); + if ( tag != LBER_DEFAULT || len != 0 ) { + tag = LBER_ERROR; + goto error; + } + tag = 0; + + st_len = 0; + if ( !BER_BVISNULL( &sessionSourceIp ) ) { + st_len += STRLENOF( "IP=" ) + sessionSourceIp.bv_len; + } + if ( !BER_BVISNULL( &sessionSourceName ) ) { + if ( st_len ) st_len++; + st_len += STRLENOF( "NAME=" ) + sessionSourceName.bv_len; + } + if ( !BER_BVISNULL( &sessionTrackingIdentifier ) ) { + if ( st_len ) st_len++; + st_len += formatOID.bv_len + STRLENOF( "=" ) + + sessionTrackingIdentifier.bv_len; + } + + if ( st_len == 0 ) { + goto error; + } + + st_len += STRLENOF( " []" ); + st_pos = strlen( op->o_log_prefix ); + + if ( sizeof( op->o_log_prefix ) - st_pos > st_len ) { + char *ptr = &op->o_log_prefix[ st_pos ]; + + ptr = lutil_strcopy( ptr, " [" /*]*/ ); + + st_len = 0; + if ( !BER_BVISNULL( &sessionSourceIp ) ) { + ptr = lutil_strcopy( ptr, "IP=" ); + ptr = lutil_strcopy( ptr, sessionSourceIp.bv_val ); + st_len++; + } + + if ( !BER_BVISNULL( &sessionSourceName ) ) { + if ( st_len ) *ptr++ = ' '; + ptr = lutil_strcopy( ptr, "NAME=" ); + ptr = lutil_strcopy( ptr, sessionSourceName.bv_val ); + st_len++; + } + + if ( !BER_BVISNULL( &sessionTrackingIdentifier ) ) { + if ( st_len ) *ptr++ = ' '; + ptr = lutil_strcopy( ptr, formatOID.bv_val ); + *ptr++ = '='; + ptr = lutil_strcopy( ptr, sessionTrackingIdentifier.bv_val ); + } + + *ptr++ = /*[*/ ']'; + *ptr = '\0'; + } + +error:; + (void)ber_free( ber, 1 ); + + if ( tag == LBER_ERROR ) { + rs->sr_text = "sessionTracking control decoding error"; + return LDAP_PROTOCOL_ERROR; + } + + + return rs->sr_err; +} + +int +slap_ctrl_session_tracking_add( + Operation *op, + SlapReply *rs, + struct berval *ip, + struct berval *name, + struct berval *id, + LDAPControl *ctrl ) +{ + BerElementBuffer berbuf; + BerElement *ber = (BerElement *)&berbuf; + + static struct berval oid = BER_BVC( LDAP_CONTROL_X_SESSION_TRACKING_USERNAME ); + + assert( ctrl != NULL ); + + ber_init2( ber, NULL, LBER_USE_DER ); + + ber_printf( ber, "{OOOO}", ip, name, &oid, id ); + + if ( ber_flatten2( ber, &ctrl->ldctl_value, 0 ) == -1 ) { + rs->sr_err = LDAP_OTHER; + goto done; + } + + ctrl->ldctl_oid = LDAP_CONTROL_X_SESSION_TRACKING; + ctrl->ldctl_iscritical = 0; + + rs->sr_err = LDAP_SUCCESS; + +done:; + return rs->sr_err; +} + +int +slap_ctrl_session_tracking_request_add( Operation *op, SlapReply *rs, LDAPControl *ctrl ) +{ + static struct berval bv_unknown = BER_BVC( SLAP_STRING_UNKNOWN ); + struct berval ip = BER_BVNULL, + name = BER_BVNULL, + id = BER_BVNULL; + + if ( !BER_BVISNULL( &op->o_conn->c_peer_name ) && + memcmp( op->o_conn->c_peer_name.bv_val, "IP=", STRLENOF( "IP=" ) ) == 0 ) + { + char *ptr; + + ip.bv_val = op->o_conn->c_peer_name.bv_val + STRLENOF( "IP=" ); + ip.bv_len = op->o_conn->c_peer_name.bv_len - STRLENOF( "IP=" ); + + ptr = ber_bvchr( &ip, ':' ); + if ( ptr ) { + ip.bv_len = ptr - ip.bv_val; + } + } + + if ( !BER_BVISNULL( &op->o_conn->c_peer_domain ) && + !bvmatch( &op->o_conn->c_peer_domain, &bv_unknown ) ) + { + name = op->o_conn->c_peer_domain; + } + + if ( !BER_BVISNULL( &op->o_dn ) && !BER_BVISEMPTY( &op->o_dn ) ) { + id = op->o_dn; + } + + return slap_ctrl_session_tracking_add( op, rs, &ip, &name, &id, ctrl ); +} +#endif