X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fcontrols.c;h=f4c3eaedc85a05e0012d1a14671dc75210c6f250;hb=562360fa181a704ebaddf5be39271aaf9e17de57;hp=730b3f68d66c86b32f6c197a6a82d8d9b904ee4a;hpb=6b37465d94b4a57698a5be0c944b90bc39ffebdf;p=openldap diff --git a/servers/slapd/controls.c b/servers/slapd/controls.c index 730b3f68d6..f4c3eaedc8 100644 --- a/servers/slapd/controls.c +++ b/servers/slapd/controls.c @@ -1,13 +1,18 @@ /* $OpenLDAP$ */ -/* - * Copyright 1999-2003 The OpenLDAP Foundation. +/* This work is part of OpenLDAP Software . + * + * Copyright 1998-2006 The OpenLDAP Foundation. * All rights reserved. * - * Redistribution and use in source and binary forms are permitted only - * as authorized by the OpenLDAP Public License. A copy of this - * license is available at http://www.OpenLDAP.org/license.html or - * in file LICENSE in the top-level directory of the distribution. + * 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 + * . */ + #include "portable.h" #include @@ -20,30 +25,42 @@ #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; +#ifdef LDAP_DEVEL +static SLAP_CTRL_PARSE_FN parseDontUseCopy; +static SLAP_CTRL_PARSE_FN parseManageDIT; +#endif static SLAP_CTRL_PARSE_FN parseManageDSAit; static SLAP_CTRL_PARSE_FN parseNoOp; static SLAP_CTRL_PARSE_FN parsePagedResults; +#ifdef LDAP_DEVEL +static SLAP_CTRL_PARSE_FN parseSortedResults; +#endif static SLAP_CTRL_PARSE_FN parseValuesReturnFilter; static SLAP_CTRL_PARSE_FN parsePermissiveModify; static SLAP_CTRL_PARSE_FN parseDomainScope; - -#ifdef LDAP_CONTROL_SUBENTRIES -static SLAP_CTRL_PARSE_FN parseSubentries; -#endif -#ifdef LDAP_CLIENT_UPDATE -static SLAP_CTRL_PARSE_FN parseClientUpdate; -#endif -#ifdef LDAP_SYNC -static SLAP_CTRL_PARSE_FN parseLdupSync; +#ifdef SLAP_CONTROL_X_TREE_DELETE +static SLAP_CTRL_PARSE_FN parseTreeDelete; #endif +static SLAP_CTRL_PARSE_FN parseSearchOptions; +static SLAP_CTRL_PARSE_FN parseSubentries; #undef sc_mask /* avoid conflict with Irix 6.5 */ +const struct berval slap_pre_read_bv = BER_BVC(LDAP_CONTROL_PRE_READ); +const struct berval slap_post_read_bv = BER_BVC(LDAP_CONTROL_POST_READ); + +struct slap_control_ids slap_cids; + struct slap_control { /* Control OID */ char *sc_oid; + /* The controlID for this control */ + int sc_cid; + /* Operations supported by control */ slap_mask_t sc_mask; @@ -62,7 +79,19 @@ static LDAP_SLIST_HEAD(ControlsList, slap_control) controls_list /* * all known request control OIDs should be added to this list */ -char **slap_known_controls = NULL; +/* + * NOTE: initialize num_known_controls to 1 so that cid = 0 always + * addresses an undefined control; this allows to safely test for + * well known controls even if they are not registered, e.g. if + * they get moved to modules. An example is sc_LDAPsync, which + * is implemented in the syncprov overlay and thus, if configured + * as dynamic module, may not be registered. One side effect is that + * slap_known_controls[0] == NULL, so it should always be used + * starting from 1. + * FIXME: should we define the "undefined control" oid? + */ +char *slap_known_controls[SLAP_MAX_CIDS+1]; +static int num_known_controls = 1; static char *proxy_authz_extops[] = { LDAP_EXOP_MODIFY_PASSWD, @@ -71,52 +100,84 @@ static char *proxy_authz_extops[] = { }; static struct slap_control control_defs[] = { - { LDAP_CONTROL_ASSERT, - SLAP_CTRL_ACCESS, NULL, + { LDAP_CONTROL_ASSERT, + (int)offsetof(struct slap_control_ids, sc_assert), + SLAP_CTRL_DELETE|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME| + SLAP_CTRL_COMPARE|SLAP_CTRL_SEARCH, NULL, parseAssert, LDAP_SLIST_ENTRY_INITIALIZER(next) }, + { LDAP_CONTROL_PRE_READ, + (int)offsetof(struct slap_control_ids, sc_preRead), + SLAP_CTRL_DELETE|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME, NULL, + parsePreRead, LDAP_SLIST_ENTRY_INITIALIZER(next) }, + { LDAP_CONTROL_POST_READ, + (int)offsetof(struct slap_control_ids, sc_postRead), + SLAP_CTRL_ADD|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME, NULL, + parsePostRead, LDAP_SLIST_ENTRY_INITIALIZER(next) }, { LDAP_CONTROL_VALUESRETURNFILTER, - SLAP_CTRL_SEARCH, NULL, + (int)offsetof(struct slap_control_ids, sc_valuesReturnFilter), + SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH, NULL, + parseValuesReturnFilter, LDAP_SLIST_ENTRY_INITIALIZER(next) }, +#ifdef LDAP_CONTROL_X_VALUESRETURNFILTER + { LDAP_CONTROL_X_VALUESRETURNFILTER, + (int)offsetof(struct slap_control_ids, sc_valuesReturnFilter), + SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH, NULL, parseValuesReturnFilter, LDAP_SLIST_ENTRY_INITIALIZER(next) }, -#ifdef LDAP_CONTROL_PAGEDRESULTS +#endif { LDAP_CONTROL_PAGEDRESULTS, + (int)offsetof(struct slap_control_ids, sc_pagedResults), SLAP_CTRL_SEARCH, NULL, parsePagedResults, LDAP_SLIST_ENTRY_INITIALIZER(next) }, +#ifdef LDAP_DEVEL + { LDAP_CONTROL_SORTREQUEST, + (int)offsetof(struct slap_control_ids, sc_sortedResults), + SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH|SLAP_CTRL_HIDE, NULL, + parseSortedResults, LDAP_SLIST_ENTRY_INITIALIZER(next) }, #endif -#ifdef LDAP_CONTROL_X_DOMAIN_SCOPE { LDAP_CONTROL_X_DOMAIN_SCOPE, - SLAP_CTRL_FRONTEND|SLAP_CTRL_SEARCH, NULL, + (int)offsetof(struct slap_control_ids, sc_domainScope), + SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH|SLAP_CTRL_HIDE, NULL, parseDomainScope, LDAP_SLIST_ENTRY_INITIALIZER(next) }, -#endif -#ifdef LDAP_CONTROL_X_PERMISSIVE_MODIFY { LDAP_CONTROL_X_PERMISSIVE_MODIFY, - SLAP_CTRL_MODIFY, NULL, + (int)offsetof(struct slap_control_ids, sc_permissiveModify), + SLAP_CTRL_MODIFY|SLAP_CTRL_HIDE, NULL, parsePermissiveModify, LDAP_SLIST_ENTRY_INITIALIZER(next) }, +#ifdef SLAP_CONTROL_X_TREE_DELETE + { LDAP_CONTROL_X_TREE_DELETE, + (int)offsetof(struct slap_control_ids, sc_treeDelete), + SLAP_CTRL_DELETE|SLAP_CTRL_HIDE, NULL, + parseTreeDelete, LDAP_SLIST_ENTRY_INITIALIZER(next) }, #endif -#ifdef LDAP_CONTROL_SUBENTRIES + { LDAP_CONTROL_X_SEARCH_OPTIONS, + (int)offsetof(struct slap_control_ids, sc_searchOptions), + SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH|SLAP_CTRL_HIDE, NULL, + parseSearchOptions, LDAP_SLIST_ENTRY_INITIALIZER(next) }, { LDAP_CONTROL_SUBENTRIES, + (int)offsetof(struct slap_control_ids, sc_subentries), SLAP_CTRL_SEARCH, NULL, parseSubentries, LDAP_SLIST_ENTRY_INITIALIZER(next) }, -#endif { LDAP_CONTROL_NOOP, - SLAP_CTRL_ACCESS, NULL, + (int)offsetof(struct slap_control_ids, sc_noOp), + SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, NULL, parseNoOp, LDAP_SLIST_ENTRY_INITIALIZER(next) }, -#ifdef LDAP_CLIENT_UPDATE - { LDAP_CONTROL_CLIENT_UPDATE, - SLAP_CTRL_HIDE|SLAP_CTRL_SEARCH, NULL, - parseClientUpdate, LDAP_SLIST_ENTRY_INITIALIZER(next) }, -#endif -#ifdef LDAP_SYNC - { LDAP_CONTROL_SYNC, - SLAP_CTRL_HIDE|SLAP_CTRL_SEARCH, NULL, - parseLdupSync, LDAP_SLIST_ENTRY_INITIALIZER(next) }, +#ifdef LDAP_DEVEL + { LDAP_CONTROL_DONTUSECOPY, + (int)offsetof(struct slap_control_ids, sc_dontUseCopy), + SLAP_CTRL_INTROGATE|SLAP_CTRL_HIDE, NULL, + parseDontUseCopy, LDAP_SLIST_ENTRY_INITIALIZER(next) }, + { LDAP_CONTROL_MANAGEDIT, + (int)offsetof(struct slap_control_ids, sc_manageDIT), + SLAP_CTRL_GLOBAL|SLAP_CTRL_UPDATE|SLAP_CTRL_HIDE, NULL, + parseManageDIT, LDAP_SLIST_ENTRY_INITIALIZER(next) }, #endif { LDAP_CONTROL_MANAGEDSAIT, + (int)offsetof(struct slap_control_ids, sc_manageDSAit), SLAP_CTRL_ACCESS, NULL, parseManageDSAit, LDAP_SLIST_ENTRY_INITIALIZER(next) }, { LDAP_CONTROL_PROXY_AUTHZ, - SLAP_CTRL_FRONTEND|SLAP_CTRL_ACCESS, proxy_authz_extops, + (int)offsetof(struct slap_control_ids, sc_proxyAuthz), + SLAP_CTRL_GLOBAL|SLAP_CTRL_ACCESS, proxy_authz_extops, parseProxyAuthz, LDAP_SLIST_ENTRY_INITIALIZER(next) }, - { NULL, 0, NULL, 0, LDAP_SLIST_ENTRY_INITIALIZER(next) } + { NULL, 0, 0, NULL, 0, LDAP_SLIST_ENTRY_INITIALIZER(next) } }; /* @@ -129,19 +190,34 @@ int register_supported_control(const char *controloid, slap_mask_t controlmask, char **controlexops, - SLAP_CTRL_PARSE_FN *controlparsefn) + SLAP_CTRL_PARSE_FN *controlparsefn, + int *controlcid) { struct slap_control *sc; int i; - if ( controloid == NULL ) { - return LDAP_PARAM_ERROR; + if ( num_known_controls >= SLAP_MAX_CIDS ) { + Debug( LDAP_DEBUG_ANY, "Too many controls registered." + " Recompile slapd with SLAP_MAX_CIDS defined > %d\n", + SLAP_MAX_CIDS, 0, 0 ); + return LDAP_OTHER; } - sc = (struct slap_control *)SLAP_MALLOC( sizeof( *sc ) ); - if ( sc == NULL ) { - return LDAP_NO_MEMORY; + if ( controloid == NULL ) return LDAP_PARAM_ERROR; + + /* sanity check - should never happen */ + for ( i = 0; slap_known_controls[ i ]; i++ ) { + if ( strcmp( controloid, slap_known_controls[ i ] ) == 0 ) { + Debug( LDAP_DEBUG_ANY, + "Control %s already registered.\n", + controloid, 0, 0 ); + return LDAP_PARAM_ERROR; + } } + + 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; if ( controlexops != NULL ) { @@ -155,32 +231,15 @@ register_supported_control(const char *controloid, } sc->sc_parse = controlparsefn; + if ( controlcid ) *controlcid = num_known_controls; + sc->sc_cid = num_known_controls; + /* Update slap_known_controls, too. */ - if ( slap_known_controls == NULL ) { - slap_known_controls = (char **)SLAP_MALLOC( 2 * sizeof(char *) ); - if ( slap_known_controls == NULL ) { - if ( sc->sc_extendedops != NULL ) ldap_charray_free( sc->sc_extendedops ); - ch_free( sc ); - return LDAP_NO_MEMORY; - } - slap_known_controls[0] = ch_strdup( sc->sc_oid ); - slap_known_controls[1] = NULL; - } else { - for ( i = 0; slap_known_controls[i] != NULL; i++ ) - ; - slap_known_controls = (char **)SLAP_REALLOC( slap_known_controls, (i + 2) * sizeof(char *) ); - if ( slap_known_controls == NULL ) { - if ( sc->sc_extendedops != NULL ) ldap_charray_free( sc->sc_extendedops ); - ch_free( sc ); - return LDAP_NO_MEMORY; - } - slap_known_controls[i++] = ch_strdup( sc->sc_oid ); - slap_known_controls[i] = NULL; - } + 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 ); - return LDAP_SUCCESS; } @@ -191,16 +250,15 @@ int slap_controls_init( void ) { int i, rc; - struct slap_control *sc; rc = LDAP_SUCCESS; for ( i = 0; control_defs[i].sc_oid != NULL; i++ ) { + int *cid = (int *)(((char *)&slap_cids) + control_defs[i].sc_cid ); rc = register_supported_control( control_defs[i].sc_oid, control_defs[i].sc_mask, control_defs[i].sc_extendedops, - control_defs[i].sc_parse ); - if ( rc != LDAP_SUCCESS ) - break; + control_defs[i].sc_parse, cid ); + if ( rc != LDAP_SUCCESS ) break; } return rc; @@ -224,7 +282,6 @@ controls_destroy( void ) } ch_free( sc ); } - ldap_charray_free( slap_known_controls ); } /* @@ -265,10 +322,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; @@ -326,10 +382,51 @@ find_ctrl( const char *oid ) return NULL; } +int +slap_find_control_id( + const char *oid, + int *cid ) +{ + struct slap_control *ctrl = find_ctrl( oid ); + if ( ctrl ) { + if ( cid ) *cid = ctrl->sc_cid; + return LDAP_SUCCESS; + } + 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; + } + + Debug( LDAP_DEBUG_TRACE, + "slap_global_control: unavailable control: %s\n", + oid, 0, 0 ); + + return LDAP_COMPARE_FALSE; +} + void slap_free_ctrls( Operation *op, - LDAPControl **ctrls -) + LDAPControl **ctrls ) { int i; @@ -339,6 +436,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_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: + *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, @@ -349,7 +535,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); @@ -369,13 +554,8 @@ int get_ctrls( goto return_results; } -#ifdef NEW_LOGGING - LDAP_LOG( OPERATION, ENTRY, - "get_ctrls: conn %lu\n", op->o_connid, 0, 0 ); -#else Debug( LDAP_DEBUG_TRACE, "=> get_ctrls\n", 0, 0, 0 ); -#endif if( op->o_protocol < LDAP_VERSION3 ) { rs->sr_err = SLAPD_DISCONNECT; @@ -433,13 +613,8 @@ int get_ctrls( c->ldctl_oid = bv.bv_val; if( tag == LBER_ERROR ) { -#ifdef NEW_LOGGING - LDAP_LOG( OPERATION, INFO, "get_ctrls: conn %lu get OID failed.\n", - op->o_connid, 0, 0 ); -#else Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get oid failed.\n", 0, 0, 0 ); -#endif slap_free_ctrls( op, op->o_ctrls ); op->o_ctrls = NULL; @@ -448,15 +623,9 @@ int get_ctrls( goto return_results; } else if( c->ldctl_oid == NULL ) { -#ifdef NEW_LOGGING - LDAP_LOG( OPERATION, INFO, - "get_ctrls: conn %lu got emtpy OID.\n", - op->o_connid, 0, 0 ); -#else Debug( LDAP_DEBUG_TRACE, "get_ctrls: conn %lu got emtpy OID.\n", op->o_connid, 0, 0 ); -#endif slap_free_ctrls( op, op->o_ctrls ); op->o_ctrls = NULL; @@ -472,14 +641,8 @@ int get_ctrls( tag = ber_scanf( ber, "b", &crit ); if( tag == LBER_ERROR ) { -#ifdef NEW_LOGGING - LDAP_LOG( OPERATION, INFO, - "get_ctrls: conn %lu get crit failed.\n", - op->o_connid, 0, 0 ); -#else Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get crit failed.\n", 0, 0, 0 ); -#endif slap_free_ctrls( op, op->o_ctrls ); op->o_ctrls = NULL; rs->sr_err = SLAPD_DISCONNECT; @@ -495,17 +658,10 @@ int get_ctrls( tag = ber_scanf( ber, "m", &c->ldctl_value ); if( tag == LBER_ERROR ) { -#ifdef NEW_LOGGING - LDAP_LOG( OPERATION, INFO, "get_ctrls: conn %lu: " - "%s (%scritical): get value failed.\n", - op->o_connid, c->ldctl_oid, - c->ldctl_iscritical ? "" : "non" ); -#else Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: conn %lu: " "%s (%scritical): get value failed.\n", op->o_connid, c->ldctl_oid, c->ldctl_iscritical ? "" : "non" ); -#endif slap_free_ctrls( op, op->o_ctrls ); op->o_ctrls = NULL; rs->sr_err = SLAPD_DISCONNECT; @@ -514,118 +670,20 @@ int get_ctrls( } } -#ifdef NEW_LOGGING - LDAP_LOG( OPERATION, INFO, - "get_ctrls: conn %lu oid=\"%s\" (%scritical)\n", - op->o_connid, c->ldctl_oid, c->ldctl_iscritical ? "" : "non" ); -#else Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: oid=\"%s\" (%scritical)\n", c->ldctl_oid, c->ldctl_iscritical ? "" : "non", 0 ); -#endif - - 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 */ - - if( !sc->sc_parse ) { - rs->sr_err = LDAP_OTHER; - rs->sr_text = "not yet implemented"; - goto return_results; - } - - rs->sr_err = sc->sc_parse( op, rs, c ); - - if( rs->sr_err != LDAP_SUCCESS ) 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; } } return_results: -#ifdef NEW_LOGGING - LDAP_LOG( OPERATION, RESULTS, - "get_ctrls: n=%d rc=%d err=\"%s\"\n", - nctrls, rs->sr_err, rs->sr_text ? rs->sr_text : "" ); -#else Debug( LDAP_DEBUG_TRACE, "<= get_ctrls: n=%d rc=%d err=\"%s\"\n", nctrls, rs->sr_err, rs->sr_text ? rs->sr_text : ""); -#endif if( sendres && rs->sr_err != LDAP_SUCCESS ) { if( rs->sr_err == SLAPD_DISCONNECT ) { @@ -640,12 +698,129 @@ return_results: return rs->sr_err; } +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; +} + +#ifdef LDAP_DEVEL +static int parseDontUseCopy ( + Operation *op, + SlapReply *rs, + LDAPControl *ctrl ) +{ + if ( op->o_dontUseCopy != SLAP_CONTROL_NONE ) { + rs->sr_text = "dontUseCopy control specified multiple times"; + return LDAP_PROTOCOL_ERROR; + } + + if ( ctrl->ldctl_value.bv_len ) { + rs->sr_text = "dontUseCopy control value not empty"; + return LDAP_PROTOCOL_ERROR; + } + + if ( ctrl->ldctl_iscritical != SLAP_CONTROL_CRITICAL ) { + rs->sr_text = "dontUseCopy criticality of FALSE not allowed"; + return LDAP_PROTOCOL_ERROR; + } + + op->o_dontUseCopy = SLAP_CONTROL_CRITICAL; + return LDAP_SUCCESS; +} + +static int parseManageDIT ( + Operation *op, + SlapReply *rs, + LDAPControl *ctrl ) +{ + if ( op->o_managedit != SLAP_CONTROL_NONE ) { + rs->sr_text = "manageDIT control specified multiple times"; + return LDAP_PROTOCOL_ERROR; + } + + if ( ctrl->ldctl_value.bv_len ) { + rs->sr_text = "manageDIT control value not empty"; + return LDAP_PROTOCOL_ERROR; + } + + op->o_managedit = ctrl->ldctl_iscritical + ? SLAP_CONTROL_CRITICAL + : SLAP_CONTROL_NONCRITICAL; + + return LDAP_SUCCESS; +} +#endif + static int parseManageDSAit ( Operation *op, SlapReply *rs, LDAPControl *ctrl ) { - if ( op->o_managedsait != SLAP_NO_CONTROL ) { + if ( op->o_managedsait != SLAP_CONTROL_NONE ) { rs->sr_text = "manageDSAit control specified multiple times"; return LDAP_PROTOCOL_ERROR; } @@ -656,8 +831,8 @@ static int parseManageDSAit ( } op->o_managedsait = ctrl->ldctl_iscritical - ? SLAP_CRITICAL_CONTROL - : SLAP_NONCRITICAL_CONTROL; + ? SLAP_CONTROL_CRITICAL + : SLAP_CONTROL_NONCRITICAL; return LDAP_SUCCESS; } @@ -667,60 +842,53 @@ static int parseProxyAuthz ( SlapReply *rs, LDAPControl *ctrl ) { - int rc; - struct berval dn = { 0, NULL }; + int rc; + struct berval dn = BER_BVNULL; - if ( op->o_proxy_authz != SLAP_NO_CONTROL ) { + if ( op->o_proxy_authz != SLAP_CONTROL_NONE ) { rs->sr_text = "proxy authorization control specified multiple times"; return LDAP_PROTOCOL_ERROR; } + if ( BER_BVISEMPTY( &op->o_ndn ) ) { + rs->sr_text = "anonymous proxyAuthz not allowed"; + return LDAP_PROXY_AUTHZ_FAILURE; + } + op->o_proxy_authz = ctrl->ldctl_iscritical - ? SLAP_CRITICAL_CONTROL - : SLAP_NONCRITICAL_CONTROL; + ? SLAP_CONTROL_CRITICAL + : SLAP_CONTROL_NONCRITICAL; -#ifdef NEW_LOGGING - LDAP_LOG( OPERATION, ARGS, - "parseProxyAuthz: conn %lu authzid=\"%s\"\n", - op->o_connid, - ctrl->ldctl_value.bv_len ? ctrl->ldctl_value.bv_val : "anonymous", - 0 ); -#else Debug( LDAP_DEBUG_ARGS, "parseProxyAuthz: conn %lu authzid=\"%s\"\n", op->o_connid, ctrl->ldctl_value.bv_len ? ctrl->ldctl_value.bv_val : "anonymous", 0 ); -#endif - if( ctrl->ldctl_value.bv_len == 0 ) { -#ifdef NEW_LOGGING - LDAP_LOG( OPERATION, RESULTS, - "parseProxyAuthz: conn=%lu anonymous\n", - op->o_connid, 0, 0 ); -#else + if ( ctrl->ldctl_value.bv_len == 0 ) { Debug( LDAP_DEBUG_TRACE, "parseProxyAuthz: conn=%lu anonymous\n", op->o_connid, 0, 0 ); -#endif /* 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; } - rc = slap_sasl_getdn( op->o_conn, op, - ctrl->ldctl_value.bv_val, ctrl->ldctl_value.bv_len, - NULL, &dn, SLAP_GETDN_AUTHZID ); + rc = slap_sasl_getdn( op->o_conn, op, &ctrl->ldctl_value, + NULL, &dn, SLAP_GETDN_AUTHZID ); - if( rc != LDAP_SUCCESS || !dn.bv_len ) { + /* FIXME: empty DN in proxyAuthz control should be legal... */ + if( rc != LDAP_SUCCESS /* || !dn.bv_len */ ) { if ( dn.bv_val ) { ch_free( dn.bv_val ); } @@ -728,38 +896,33 @@ static int parseProxyAuthz ( return LDAP_PROXY_AUTHZ_FAILURE; } -#ifdef NEW_LOGGING - LDAP_LOG( OPERATION, RESULTS, - "parseProxyAuthz: conn=%lu \"%s\"\n", - op->o_connid, - dn.bv_len ? dn.bv_val : "(NULL)", 0 ); -#else Debug( LDAP_DEBUG_TRACE, "parseProxyAuthz: conn=%lu \"%s\"\n", op->o_connid, dn.bv_len ? dn.bv_val : "(NULL)", 0 ); -#endif 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; } - ch_free( op->o_dn.bv_val ); ch_free( op->o_ndn.bv_val ); - - op->o_dn.bv_val = NULL; - op->o_ndn = dn; + 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; } @@ -768,7 +931,7 @@ static int parseNoOp ( SlapReply *rs, LDAPControl *ctrl ) { - if ( op->o_noop != SLAP_NO_CONTROL ) { + if ( op->o_noop != SLAP_CONTROL_NONE ) { rs->sr_text = "noop control specified multiple times"; return LDAP_PROTOCOL_ERROR; } @@ -779,29 +942,30 @@ static int parseNoOp ( } op->o_noop = ctrl->ldctl_iscritical - ? SLAP_CRITICAL_CONTROL - : SLAP_NONCRITICAL_CONTROL; + ? SLAP_CONTROL_CRITICAL + : SLAP_CONTROL_NONCRITICAL; return LDAP_SUCCESS; } -#ifdef LDAP_CONTROL_PAGEDRESULTS static int parsePagedResults ( Operation *op, SlapReply *rs, LDAPControl *ctrl ) { - ber_tag_t tag; - ber_int_t size; - BerElement *ber; - struct berval cookie = { 0, NULL }; + 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_NO_CONTROL ) { + if ( op->o_pagedresults != SLAP_CONTROL_NONE ) { rs->sr_text = "paged results control specified multiple times"; return LDAP_PROTOCOL_ERROR; } - if ( ctrl->ldctl_value.bv_len == 0 ) { + if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) { rs->sr_text = "paged results control value is empty (or absent)"; return LDAP_PROTOCOL_ERROR; } @@ -815,56 +979,80 @@ static int parsePagedResults ( * } */ ber = ber_init( &ctrl->ldctl_value ); - if( ber == NULL ) { + if ( ber == NULL ) { rs->sr_text = "internal error"; return LDAP_OTHER; } tag = ber_scanf( ber, "{im}", &size, &cookie ); - (void) ber_free( ber, 1 ); - if( tag == LBER_ERROR ) { + if ( tag == LBER_ERROR ) { rs->sr_text = "paged results control could not be decoded"; - return LDAP_PROTOCOL_ERROR; + rc = LDAP_PROTOCOL_ERROR; + goto done; } - if( size < 0 ) { + if ( size < 0 ) { rs->sr_text = "paged results control size invalid"; - return LDAP_PROTOCOL_ERROR; + rc = LDAP_PROTOCOL_ERROR; + goto done; } - if( cookie.bv_len ) { - PagedResultsCookie reqcookie; - if( cookie.bv_len != sizeof( reqcookie ) ) { - /* bad cookie */ - rs->sr_text = "paged results cookie is invalid"; - return LDAP_PROTOCOL_ERROR; - } + ps = op->o_tmpalloc( sizeof(PagedResultsState), op->o_tmpmemctx ); + *ps = op->o_conn->c_pagedresults_state; + ps->ps_size = size; + op->o_pagedresults_state = ps; - AC_MEMCPY( &reqcookie, cookie.bv_val, sizeof( reqcookie )); + /* NOTE: according to RFC 2696 3.: - if( reqcookie > op->o_pagedresults_state.ps_cookie ) { - /* bad cookie */ - rs->sr_text = "paged results cookie is invalid"; - return LDAP_PROTOCOL_ERROR; + If the page size is greater than or equal to the sizeLimit value, the + server should ignore the control as the request can be satisfied in a + single page. + + * NOTE: this assumes that the op->ors_slimit be set + * before the controls are parsed. + */ + + if ( op->ors_slimit > 0 && size >= op->ors_slimit ) { + op->o_pagedresults = SLAP_CONTROL_IGNORED; + + } else if ( ctrl->ldctl_iscritical ) { + op->o_pagedresults = SLAP_CONTROL_CRITICAL; - } else if( reqcookie < op->o_pagedresults_state.ps_cookie ) { - rs->sr_text = "paged results cookie is invalid or old"; - return LDAP_UNWILLING_TO_PERFORM; - } } else { - /* Initial request. Initialize state. */ - op->o_pagedresults_state.ps_cookie = 0; - op->o_pagedresults_state.ps_id = NOID; + op->o_pagedresults = SLAP_CONTROL_NONCRITICAL; + } + +done:; + (void)ber_free( ber, 1 ); + return rc; +} + +#ifdef LDAP_DEVEL +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; } - op->o_pagedresults_size = size; + if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) { + rs->sr_text = "sorted results control value is empty (or absent)"; + return LDAP_PROTOCOL_ERROR; + } - op->o_pagedresults = ctrl->ldctl_iscritical - ? SLAP_CRITICAL_CONTROL - : SLAP_NONCRITICAL_CONTROL; + /* blow off parsing the value */ - return LDAP_SUCCESS; + op->o_sortedresults = ctrl->ldctl_iscritical + ? SLAP_CONTROL_CRITICAL + : SLAP_CONTROL_NONCRITICAL; + + return rc; } #endif @@ -874,10 +1062,9 @@ static int parseAssert ( LDAPControl *ctrl ) { BerElement *ber; - struct berval fstr = { 0, NULL }; - const char *err_msg = ""; + struct berval fstr = BER_BVNULL; - if ( op->o_assert != SLAP_NO_CONTROL ) { + if ( op->o_assert != SLAP_CONTROL_NONE ) { rs->sr_text = "assert control specified multiple times"; return LDAP_PROTOCOL_ERROR; } @@ -889,12 +1076,12 @@ static int parseAssert ( ber = ber_init( &(ctrl->ldctl_value) ); if (ber == NULL) { - rs->sr_text = "internal error"; + rs->sr_text = "assert control: internal error"; return LDAP_OTHER; } - rs->sr_err = get_filter( op, ber, &(op->o_assertion), &rs->sr_text); - + rs->sr_err = get_filter( op, ber, (Filter **)&(op->o_assertion), + &rs->sr_text); if( rs->sr_err != LDAP_SUCCESS ) { if( rs->sr_err == SLAPD_DISCONNECT ) { rs->sr_err = LDAP_PROTOCOL_ERROR; @@ -903,44 +1090,153 @@ static int parseAssert ( } else { send_ldap_result( op, rs ); } - if( op->o_assertion != NULL) { - filter_free_x( op, op->o_assertion ); + if( op->o_assertion != NULL ) { + filter_free_x( op, op->o_assertion ); } + return rs->sr_err; } + #ifdef LDAP_DEBUG - else { - filter2bv_x( op, op->o_assertion, &fstr ); - } + filter2bv_x( op, op->o_assertion, &fstr ); -#ifdef NEW_LOGGING - LDAP_LOG( OPERATION, ARGS, - "parseAssert: conn %ld assert: %s\n", - op->o_connid, fstr.bv_len ? fstr.bv_val : "empty" , 0 ); -#else Debug( LDAP_DEBUG_ARGS, "parseAssert: conn %ld assert: %s\n", op->o_connid, fstr.bv_len ? fstr.bv_val : "empty" , 0 ); -#endif op->o_tmpfree( fstr.bv_val, op->o_tmpmemctx ); #endif op->o_assert = ctrl->ldctl_iscritical - ? SLAP_CRITICAL_CONTROL - : SLAP_NONCRITICAL_CONTROL; + ? SLAP_CONTROL_CRITICAL + : SLAP_CONTROL_NONCRITICAL; + + rs->sr_err = LDAP_SUCCESS; + return LDAP_SUCCESS; +} + +static int parsePreRead ( + Operation *op, + SlapReply *rs, + LDAPControl *ctrl ) +{ + ber_len_t siz, off, i; + AttributeName *an = NULL; + BerElement *ber; + + if ( op->o_preread != SLAP_CONTROL_NONE ) { + rs->sr_text = "preread control specified multiple times"; + return LDAP_PROTOCOL_ERROR; + } + + if ( ctrl->ldctl_value.bv_len == 0 ) { + rs->sr_text = "preread control value is empty (or absent)"; + return LDAP_PROTOCOL_ERROR; + } + + ber = ber_init( &(ctrl->ldctl_value) ); + if (ber == NULL) { + rs->sr_text = "preread control: internal error"; + return LDAP_OTHER; + } + + 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; + } + + for( i=0; ildctl_iscritical ) { + rs->sr_text = dummy + ? dummy + : "postread control: unknown attributeType"; + return rc; + } + } + + op->o_preread = ctrl->ldctl_iscritical + ? SLAP_CONTROL_CRITICAL + : SLAP_CONTROL_NONCRITICAL; + + op->o_preread_attrs = an; + + rs->sr_err = LDAP_SUCCESS; + return LDAP_SUCCESS; +} + +static int parsePostRead ( + Operation *op, + SlapReply *rs, + LDAPControl *ctrl ) +{ + ber_len_t siz, off, i; + AttributeName *an = NULL; + BerElement *ber; + + if ( op->o_postread != SLAP_CONTROL_NONE ) { + rs->sr_text = "postread control specified multiple times"; + return LDAP_PROTOCOL_ERROR; + } + + if ( ctrl->ldctl_value.bv_len == 0 ) { + rs->sr_text = "postread control value is empty (or absent)"; + return LDAP_PROTOCOL_ERROR; + } + + ber = ber_init( &(ctrl->ldctl_value) ); + if (ber == NULL) { + rs->sr_text = "postread control: internal error"; + return LDAP_OTHER; + } + + 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; + } + + for( i=0; ildctl_iscritical ) { + rs->sr_text = dummy + ? dummy + : "postread control: unknown attributeType"; + return rc; + } + } + + op->o_postread = ctrl->ldctl_iscritical + ? SLAP_CONTROL_CRITICAL + : SLAP_CONTROL_NONCRITICAL; + + op->o_postread_attrs = an; rs->sr_err = LDAP_SUCCESS; return LDAP_SUCCESS; } -int parseValuesReturnFilter ( +static int parseValuesReturnFilter ( Operation *op, SlapReply *rs, LDAPControl *ctrl ) { BerElement *ber; - struct berval fstr = { 0, NULL }; - const char *err_msg = ""; + struct berval fstr = BER_BVNULL; - if ( op->o_valuesreturnfilter != SLAP_NO_CONTROL ) { + if ( op->o_valuesreturnfilter != SLAP_CONTROL_NONE ) { rs->sr_text = "valuesReturnFilter control specified multiple times"; return LDAP_PROTOCOL_ERROR; } @@ -956,7 +1252,8 @@ int parseValuesReturnFilter ( return LDAP_OTHER; } - rs->sr_err = get_vrFilter( op, ber, &(op->o_vrFilter), &rs->sr_text); + rs->sr_err = get_vrFilter( op, ber, + (ValuesReturnFilter **)&(op->o_vrFilter), &rs->sr_text); if( rs->sr_err != LDAP_SUCCESS ) { if( rs->sr_err == SLAPD_DISCONNECT ) { @@ -967,69 +1264,61 @@ int parseValuesReturnFilter ( send_ldap_result( op, rs ); } if( op->o_vrFilter != NULL) vrFilter_free( op, op->o_vrFilter ); - } #ifdef LDAP_DEBUG else { vrFilter2bv( op, op->o_vrFilter, &fstr ); } -#ifdef NEW_LOGGING - LDAP_LOG( OPERATION, ARGS, - "parseValuesReturnFilter: conn %d vrFilter: %s\n", - op->o_connid, fstr.bv_len ? fstr.bv_val : "empty" , 0 ); -#else Debug( LDAP_DEBUG_ARGS, " vrFilter: %s\n", fstr.bv_len ? fstr.bv_val : "empty", 0, 0 ); -#endif op->o_tmpfree( fstr.bv_val, op->o_tmpmemctx ); #endif op->o_valuesreturnfilter = ctrl->ldctl_iscritical - ? SLAP_CRITICAL_CONTROL - : SLAP_NONCRITICAL_CONTROL; + ? SLAP_CONTROL_CRITICAL + : SLAP_CONTROL_NONCRITICAL; rs->sr_err = LDAP_SUCCESS; return LDAP_SUCCESS; } -#ifdef LDAP_CONTROL_SUBENTRIES static int parseSubentries ( Operation *op, SlapReply *rs, LDAPControl *ctrl ) { - if ( op->o_subentries != SLAP_NO_CONTROL ) { + if ( op->o_subentries != SLAP_CONTROL_NONE ) { rs->sr_text = "subentries control specified multiple times"; return LDAP_PROTOCOL_ERROR; } /* 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; } op->o_subentries = ctrl->ldctl_iscritical - ? SLAP_CRITICAL_CONTROL - : SLAP_NONCRITICAL_CONTROL; + ? SLAP_CONTROL_CRITICAL + : SLAP_CONTROL_NONCRITICAL; - op->o_subentries_visibility = (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, LDAPControl *ctrl ) { - if ( op->o_permissive_modify != SLAP_NO_CONTROL ) { + if ( op->o_permissive_modify != SLAP_CONTROL_NONE ) { rs->sr_text = "permissiveModify control specified multiple times"; return LDAP_PROTOCOL_ERROR; } @@ -1040,20 +1329,18 @@ static int parsePermissiveModify ( } op->o_permissive_modify = ctrl->ldctl_iscritical - ? SLAP_CRITICAL_CONTROL - : SLAP_NONCRITICAL_CONTROL; + ? SLAP_CONTROL_CRITICAL + : SLAP_CONTROL_NONCRITICAL; return LDAP_SUCCESS; } -#endif -#ifdef LDAP_CONTROL_X_DOMAIN_SCOPE static int parseDomainScope ( Operation *op, SlapReply *rs, LDAPControl *ctrl ) { - if ( op->o_domain_scope != SLAP_NO_CONTROL ) { + if ( op->o_domain_scope != SLAP_CONTROL_NONE ) { rs->sr_text = "domainScope control specified multiple times"; return LDAP_PROTOCOL_ERROR; } @@ -1064,248 +1351,84 @@ static int parseDomainScope ( } op->o_domain_scope = ctrl->ldctl_iscritical - ? SLAP_CRITICAL_CONTROL - : SLAP_NONCRITICAL_CONTROL; + ? SLAP_CONTROL_CRITICAL + : SLAP_CONTROL_NONCRITICAL; return LDAP_SUCCESS; } -#endif -#ifdef LDAP_CLIENT_UPDATE -static int parseClientUpdate ( +#ifdef SLAP_CONTROL_X_TREE_DELETE +static int parseTreeDelete ( Operation *op, SlapReply *rs, LDAPControl *ctrl ) { - ber_tag_t tag; - BerElement *ber; - ber_int_t type; - ber_int_t interval; - ber_len_t len; - struct berval scheme = { 0, NULL }; - struct berval cookie = { 0, NULL }; - - if ( op->o_clientupdate != SLAP_NO_CONTROL ) { - rs->sr_text = "LCUP client update control specified multiple times"; - return LDAP_PROTOCOL_ERROR; - } - -#ifdef LDAP_SYNC - if ( op->o_sync != SLAP_NO_CONTROL ) { - rs->sr_text = "LDAP Client Update and Sync controls used together"; - return LDAP_PROTOCOL_ERROR; - } -#endif - - if ( ctrl->ldctl_value.bv_len == 0 ) { - rs->sr_text = "LCUP client update control value is empty (or absent)"; - return LDAP_PROTOCOL_ERROR; - } - - /* Parse the control value - * ClientUpdateControlValue ::= SEQUENCE { - * updateType ENUMERATED { - * synchronizeOnly {0}, - * synchronizeAndPersist {1}, - * persistOnly {2} }, - * sendCookieInterval INTEGER OPTIONAL, - * cookie LCUPCookie OPTIONAL - * } - */ - - ber = ber_init( &ctrl->ldctl_value ); - if( ber == NULL ) { - rs->sr_text = "internal error"; - return LDAP_OTHER; - } - - if ( (tag = ber_scanf( ber, "{i" /*}*/, &type )) == LBER_ERROR ) { - rs->sr_text = "LCUP client update control : decoding error"; - return LDAP_PROTOCOL_ERROR; - } - - switch( type ) { - case LDAP_CUP_SYNC_ONLY: - type = SLAP_LCUP_SYNC; - break; - case LDAP_CUP_SYNC_AND_PERSIST: - type = SLAP_LCUP_SYNC_AND_PERSIST; - break; - case LDAP_CUP_PERSIST_ONLY: - type = SLAP_LCUP_PERSIST; - break; - default: - rs->sr_text = "LCUP client update control : unknown update type"; - return LDAP_PROTOCOL_ERROR; - } - - if ( (tag = ber_peek_tag( ber, &len )) == LBER_DEFAULT ) { - rs->sr_text = "LCUP client update control : decoding error"; + if ( op->o_tree_delete != SLAP_CONTROL_NONE ) { + rs->sr_text = "treeDelete control specified multiple times"; return LDAP_PROTOCOL_ERROR; } - if ( tag == LDAP_CUP_TAG_INTERVAL ) { - if ( (tag = ber_scanf( ber, "i", &interval )) == LBER_ERROR ) { - rs->sr_text = "LCUP client update control : decoding error"; - return LDAP_PROTOCOL_ERROR; - } - - if ( interval <= 0 ) { - /* server chooses interval */ - interval = LDAP_CUP_DEFAULT_SEND_COOKIE_INTERVAL; - } - - } else { - /* server chooses interval */ - interval = LDAP_CUP_DEFAULT_SEND_COOKIE_INTERVAL; - } - - if ( (tag = ber_peek_tag( ber, &len )) == LBER_DEFAULT ) { - rs->sr_text = "LCUP client update control : decoding error"; + if ( ctrl->ldctl_value.bv_len ) { + rs->sr_text = "treeDelete control value not empty"; return LDAP_PROTOCOL_ERROR; } - if ( tag == LDAP_CUP_TAG_COOKIE ) { - if ( (tag = ber_scanf( ber, /*{*/ "{mm}}", - &scheme, &cookie )) == LBER_ERROR ) - { - rs->sr_text = "LCUP client update control : decoding error"; - return LDAP_PROTOCOL_ERROR; - } - } - - /* TODO : Cookie Scheme Validation */ -#if 0 - if ( lcup_cookie_scheme_validate(scheme) != LDAP_SUCCESS ) { - rs->sr_text = "Unsupported LCUP cookie scheme"; - return LCUP_UNSUPPORTED_SCHEME; - } - - if ( lcup_cookie_validate(scheme, cookie) != LDAP_SUCCESS ) { - rs->sr_text = "Invalid LCUP cookie"; - return LCUP_INVALID_COOKIE; - } -#endif - - ber_dupbv( &op->o_clientupdate_state, &cookie ); - - (void) ber_free( ber, 1 ); - - op->o_clientupdate_type = (char) type; - op->o_clientupdate_interval = interval; - - op->o_clientupdate = ctrl->ldctl_iscritical - ? SLAP_CRITICAL_CONTROL - : SLAP_NONCRITICAL_CONTROL; + op->o_tree_delete = ctrl->ldctl_iscritical + ? SLAP_CONTROL_CRITICAL + : SLAP_CONTROL_NONCRITICAL; return LDAP_SUCCESS; } #endif -#ifdef LDAP_SYNC -static int parseLdupSync ( +static int parseSearchOptions ( Operation *op, SlapReply *rs, LDAPControl *ctrl ) { - ber_tag_t tag; BerElement *ber; - ber_int_t mode; - ber_len_t len; - struct berval cookie = { 0, NULL }; - - if ( op->o_sync != SLAP_NO_CONTROL ) { - rs->sr_text = "LDAP Sync control specified multiple times"; - return LDAP_PROTOCOL_ERROR; - } - -#ifdef LDAP_CLIENT_UPDATE - if ( op->o_clientupdate != SLAP_NO_CONTROL ) { - rs->sr_text = "LDAP Sync and LDAP Client Update controls used together"; - return LDAP_PROTOCOL_ERROR; - } -#endif + ber_int_t search_flags; + ber_tag_t tag; if ( ctrl->ldctl_value.bv_len == 0 ) { - rs->sr_text = "LDAP Sync control value is empty (or absent)"; + rs->sr_text = "searchOptions control value is empty (or absent)"; return LDAP_PROTOCOL_ERROR; } - /* Parse the control value - * syncRequestValue ::= SEQUENCE { - * mode ENUMERATED { - * -- 0 unused - * refreshOnly (1), - * -- 2 reserved - * refreshAndPersist (3) - * }, - * cookie syncCookie OPTIONAL - * } - */ - ber = ber_init( &ctrl->ldctl_value ); if( ber == NULL ) { rs->sr_text = "internal error"; return LDAP_OTHER; } - if ( (tag = ber_scanf( ber, "{i" /*}*/, &mode )) == LBER_ERROR ) { - rs->sr_text = "LDAP Sync control : mode decoding error"; + if ( (tag = ber_scanf( ber, "{i}", &search_flags )) == LBER_ERROR ) { + rs->sr_text = "searchOptions control decoding error"; return LDAP_PROTOCOL_ERROR; } - switch( mode ) { - case LDAP_SYNC_REFRESH_ONLY: - mode = SLAP_SYNC_REFRESH; - break; - case LDAP_SYNC_REFRESH_AND_PERSIST: - mode = SLAP_SYNC_REFRESH_AND_PERSIST; - break; - default: - rs->sr_text = "LDAP Sync control : unknown update mode"; - return LDAP_PROTOCOL_ERROR; - } - - tag = ber_peek_tag( ber, &len ); + (void) ber_free( ber, 1 ); - if ( tag == LDAP_SYNC_TAG_COOKIE ) { - if (( ber_scanf( ber, /*{*/ "m}", - &cookie )) == LBER_ERROR ) { - rs->sr_text = "LDAP Sync control : cookie decoding error"; + if ( search_flags & LDAP_SEARCH_FLAG_DOMAIN_SCOPE ) { + if ( op->o_domain_scope != SLAP_CONTROL_NONE ) { + rs->sr_text = "searchOptions control specified multiple times " + "or with domainScope control"; return LDAP_PROTOCOL_ERROR; } - } else { - if (( ber_scanf( ber, /*{*/ "}")) == LBER_ERROR ) { - rs->sr_text = "LDAP Sync control : decoding error"; - return LDAP_PROTOCOL_ERROR; - } - cookie.bv_len = 0; - cookie.bv_val = NULL; - } - /* TODO : Cookie Scheme Validation */ -#if 0 - if ( lcup_cookie_scheme_validate(scheme) != LDAP_SUCCESS ) { - rs->sr_text = "Unsupported LCUP cookie scheme"; - return LCUP_UNSUPPORTED_SCHEME; + op->o_domain_scope = ctrl->ldctl_iscritical + ? SLAP_CONTROL_CRITICAL + : SLAP_CONTROL_NONCRITICAL; } - if ( lcup_cookie_validate(scheme, cookie) != LDAP_SUCCESS ) { - rs->sr_text = "Invalid LCUP cookie"; - return LCUP_INVALID_COOKIE; + if ( search_flags & ~(LDAP_SEARCH_FLAG_DOMAIN_SCOPE) ) { + /* 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; } -#endif - - ber_dupbv( &op->o_sync_state, &cookie ); - - (void) ber_free( ber, 1 ); - - op->o_sync_mode = (char) mode; - - op->o_sync = ctrl->ldctl_iscritical - ? SLAP_CRITICAL_CONTROL - : SLAP_NONCRITICAL_CONTROL; return LDAP_SUCCESS; } -#endif +