2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1998-2006 The OpenLDAP Foundation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
11 * A copy of this license is available in the file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * <http://www.OpenLDAP.org/license.html>.
20 #include <ac/string.h>
21 #include <ac/socket.h>
25 #include "../../libraries/liblber/lber-int.h"
27 static SLAP_CTRL_PARSE_FN parseAssert;
28 static SLAP_CTRL_PARSE_FN parsePreRead;
29 static SLAP_CTRL_PARSE_FN parsePostRead;
30 static SLAP_CTRL_PARSE_FN parseProxyAuthz;
32 static SLAP_CTRL_PARSE_FN parseDontUseCopy;
33 static SLAP_CTRL_PARSE_FN parseManageDIT;
35 static SLAP_CTRL_PARSE_FN parseManageDSAit;
36 static SLAP_CTRL_PARSE_FN parseNoOp;
37 static SLAP_CTRL_PARSE_FN parsePagedResults;
39 static SLAP_CTRL_PARSE_FN parseSortedResults;
41 static SLAP_CTRL_PARSE_FN parseValuesReturnFilter;
42 static SLAP_CTRL_PARSE_FN parsePermissiveModify;
43 static SLAP_CTRL_PARSE_FN parseDomainScope;
44 #ifdef SLAP_CONTROL_X_TREE_DELETE
45 static SLAP_CTRL_PARSE_FN parseTreeDelete;
47 static SLAP_CTRL_PARSE_FN parseSearchOptions;
48 static SLAP_CTRL_PARSE_FN parseSubentries;
50 #undef sc_mask /* avoid conflict with Irix 6.5 <sys/signal.h> */
52 const struct berval slap_pre_read_bv = BER_BVC(LDAP_CONTROL_PRE_READ);
53 const struct berval slap_post_read_bv = BER_BVC(LDAP_CONTROL_POST_READ);
55 struct slap_control_ids slap_cids;
61 /* The controlID for this control */
64 /* Operations supported by control */
67 /* Extended operations supported by control */
68 char **sc_extendedops;
70 /* Control parsing callback */
71 SLAP_CTRL_PARSE_FN *sc_parse;
73 LDAP_SLIST_ENTRY(slap_control) sc_next;
76 static LDAP_SLIST_HEAD(ControlsList, slap_control) controls_list
77 = LDAP_SLIST_HEAD_INITIALIZER(&controls_list);
80 * all known request control OIDs should be added to this list
83 * NOTE: initialize num_known_controls to 1 so that cid = 0 always
84 * addresses an undefined control; this allows to safely test for
85 * well known controls even if they are not registered, e.g. if
86 * they get moved to modules. An example is sc_LDAPsync, which
87 * is implemented in the syncprov overlay and thus, if configured
88 * as dynamic module, may not be registered. One side effect is that
89 * slap_known_controls[0] == NULL, so it should always be used
91 * FIXME: should we define the "undefined control" oid?
93 char *slap_known_controls[SLAP_MAX_CIDS+1];
94 static int num_known_controls = 1;
96 static char *proxy_authz_extops[] = {
97 LDAP_EXOP_MODIFY_PASSWD,
102 static struct slap_control control_defs[] = {
103 { LDAP_CONTROL_ASSERT,
104 (int)offsetof(struct slap_control_ids, sc_assert),
105 SLAP_CTRL_DELETE|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME|
106 SLAP_CTRL_COMPARE|SLAP_CTRL_SEARCH, NULL,
107 parseAssert, LDAP_SLIST_ENTRY_INITIALIZER(next) },
108 { LDAP_CONTROL_PRE_READ,
109 (int)offsetof(struct slap_control_ids, sc_preRead),
110 SLAP_CTRL_DELETE|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME, NULL,
111 parsePreRead, LDAP_SLIST_ENTRY_INITIALIZER(next) },
112 { LDAP_CONTROL_POST_READ,
113 (int)offsetof(struct slap_control_ids, sc_postRead),
114 SLAP_CTRL_ADD|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME, NULL,
115 parsePostRead, LDAP_SLIST_ENTRY_INITIALIZER(next) },
116 { LDAP_CONTROL_VALUESRETURNFILTER,
117 (int)offsetof(struct slap_control_ids, sc_valuesReturnFilter),
118 SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH, NULL,
119 parseValuesReturnFilter, LDAP_SLIST_ENTRY_INITIALIZER(next) },
120 #ifdef LDAP_CONTROL_X_VALUESRETURNFILTER
121 { LDAP_CONTROL_X_VALUESRETURNFILTER,
122 (int)offsetof(struct slap_control_ids, sc_valuesReturnFilter),
123 SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH, NULL,
124 parseValuesReturnFilter, LDAP_SLIST_ENTRY_INITIALIZER(next) },
126 { LDAP_CONTROL_PAGEDRESULTS,
127 (int)offsetof(struct slap_control_ids, sc_pagedResults),
128 SLAP_CTRL_SEARCH, NULL,
129 parsePagedResults, LDAP_SLIST_ENTRY_INITIALIZER(next) },
131 { LDAP_CONTROL_SORTREQUEST,
132 (int)offsetof(struct slap_control_ids, sc_sortedResults),
133 SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH|SLAP_CTRL_HIDE, NULL,
134 parseSortedResults, LDAP_SLIST_ENTRY_INITIALIZER(next) },
136 { LDAP_CONTROL_X_DOMAIN_SCOPE,
137 (int)offsetof(struct slap_control_ids, sc_domainScope),
138 SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH|SLAP_CTRL_HIDE, NULL,
139 parseDomainScope, LDAP_SLIST_ENTRY_INITIALIZER(next) },
140 { LDAP_CONTROL_X_PERMISSIVE_MODIFY,
141 (int)offsetof(struct slap_control_ids, sc_permissiveModify),
142 SLAP_CTRL_MODIFY|SLAP_CTRL_HIDE, NULL,
143 parsePermissiveModify, LDAP_SLIST_ENTRY_INITIALIZER(next) },
144 #ifdef SLAP_CONTROL_X_TREE_DELETE
145 { LDAP_CONTROL_X_TREE_DELETE,
146 (int)offsetof(struct slap_control_ids, sc_treeDelete),
147 SLAP_CTRL_DELETE|SLAP_CTRL_HIDE, NULL,
148 parseTreeDelete, LDAP_SLIST_ENTRY_INITIALIZER(next) },
150 { LDAP_CONTROL_X_SEARCH_OPTIONS,
151 (int)offsetof(struct slap_control_ids, sc_searchOptions),
152 SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH|SLAP_CTRL_HIDE, NULL,
153 parseSearchOptions, LDAP_SLIST_ENTRY_INITIALIZER(next) },
154 { LDAP_CONTROL_SUBENTRIES,
155 (int)offsetof(struct slap_control_ids, sc_subentries),
156 SLAP_CTRL_SEARCH, NULL,
157 parseSubentries, LDAP_SLIST_ENTRY_INITIALIZER(next) },
159 (int)offsetof(struct slap_control_ids, sc_noOp),
160 SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, NULL,
161 parseNoOp, LDAP_SLIST_ENTRY_INITIALIZER(next) },
163 { LDAP_CONTROL_DONTUSECOPY,
164 (int)offsetof(struct slap_control_ids, sc_dontUseCopy),
165 SLAP_CTRL_INTROGATE|SLAP_CTRL_HIDE, NULL,
166 parseDontUseCopy, LDAP_SLIST_ENTRY_INITIALIZER(next) },
167 { LDAP_CONTROL_MANAGEDIT,
168 (int)offsetof(struct slap_control_ids, sc_manageDIT),
169 SLAP_CTRL_GLOBAL|SLAP_CTRL_UPDATE|SLAP_CTRL_HIDE, NULL,
170 parseManageDIT, LDAP_SLIST_ENTRY_INITIALIZER(next) },
172 { LDAP_CONTROL_MANAGEDSAIT,
173 (int)offsetof(struct slap_control_ids, sc_manageDSAit),
174 SLAP_CTRL_ACCESS, NULL,
175 parseManageDSAit, LDAP_SLIST_ENTRY_INITIALIZER(next) },
176 { LDAP_CONTROL_PROXY_AUTHZ,
177 (int)offsetof(struct slap_control_ids, sc_proxyAuthz),
178 SLAP_CTRL_GLOBAL|SLAP_CTRL_ACCESS, proxy_authz_extops,
179 parseProxyAuthz, LDAP_SLIST_ENTRY_INITIALIZER(next) },
180 { NULL, 0, 0, NULL, 0, LDAP_SLIST_ENTRY_INITIALIZER(next) }
184 * Register a supported control.
186 * This can be called by an OpenLDAP plugin or, indirectly, by a
187 * SLAPI plugin calling slapi_register_supported_control().
190 register_supported_control(const char *controloid,
191 slap_mask_t controlmask,
193 SLAP_CTRL_PARSE_FN *controlparsefn,
196 struct slap_control *sc;
199 if ( num_known_controls >= SLAP_MAX_CIDS ) {
200 Debug( LDAP_DEBUG_ANY, "Too many controls registered."
201 " Recompile slapd with SLAP_MAX_CIDS defined > %d\n",
202 SLAP_MAX_CIDS, 0, 0 );
206 if ( controloid == NULL ) return LDAP_PARAM_ERROR;
208 /* sanity check - should never happen */
209 for ( i = 0; slap_known_controls[ i ]; i++ ) {
210 if ( strcmp( controloid, slap_known_controls[ i ] ) == 0 ) {
211 Debug( LDAP_DEBUG_ANY,
212 "Control %s already registered.\n",
214 return LDAP_PARAM_ERROR;
218 sc = (struct slap_control *)SLAP_MALLOC( sizeof( *sc ) );
219 if ( sc == NULL ) return LDAP_NO_MEMORY;
221 sc->sc_oid = ch_strdup( controloid );
222 sc->sc_mask = controlmask;
223 if ( controlexops != NULL ) {
224 sc->sc_extendedops = ldap_charray_dup( controlexops );
225 if ( sc->sc_extendedops == NULL ) {
227 return LDAP_NO_MEMORY;
230 sc->sc_extendedops = NULL;
232 sc->sc_parse = controlparsefn;
234 if ( controlcid ) *controlcid = num_known_controls;
235 sc->sc_cid = num_known_controls;
237 /* Update slap_known_controls, too. */
238 slap_known_controls[num_known_controls-1] = sc->sc_oid;
239 slap_known_controls[num_known_controls++] = NULL;
241 LDAP_SLIST_NEXT( sc, sc_next ) = NULL;
242 LDAP_SLIST_INSERT_HEAD( &controls_list, sc, sc_next );
247 * One-time initialization of internal controls.
250 slap_controls_init( void )
256 for ( i = 0; control_defs[i].sc_oid != NULL; i++ ) {
257 int *cid = (int *)(((char *)&slap_cids) + control_defs[i].sc_cid );
258 rc = register_supported_control( control_defs[i].sc_oid,
259 control_defs[i].sc_mask, control_defs[i].sc_extendedops,
260 control_defs[i].sc_parse, cid );
261 if ( rc != LDAP_SUCCESS ) break;
268 * Free memory associated with list of supported controls.
271 controls_destroy( void )
273 struct slap_control *sc;
275 while ( !LDAP_SLIST_EMPTY(&controls_list) ) {
276 sc = LDAP_SLIST_FIRST(&controls_list);
277 LDAP_SLIST_REMOVE_HEAD(&controls_list, sc_next);
279 ch_free( sc->sc_oid );
280 if ( sc->sc_extendedops != NULL ) {
281 ldap_charray_free( sc->sc_extendedops );
288 * Format the supportedControl attribute of the root DSE,
289 * detailing which controls are supported by the directory
293 controls_root_dse_info( Entry *e )
295 AttributeDescription *ad_supportedControl
296 = slap_schema.si_ad_supportedControl;
297 struct berval vals[2];
298 struct slap_control *sc;
300 vals[1].bv_val = NULL;
303 LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
304 if( sc->sc_mask & SLAP_CTRL_HIDE ) continue;
306 vals[0].bv_val = sc->sc_oid;
307 vals[0].bv_len = strlen( sc->sc_oid );
309 if ( attr_merge( e, ad_supportedControl, vals, NULL ) ) {
318 * Return a list of OIDs and operation masks for supported
319 * controls. Used by SLAPI.
322 get_supported_controls(char ***ctrloidsp,
323 slap_mask_t **ctrlmasks)
328 struct slap_control *sc;
332 LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
342 oids = (char **)SLAP_MALLOC( (n + 1) * sizeof(char *) );
343 if ( oids == NULL ) {
344 return LDAP_NO_MEMORY;
346 masks = (slap_mask_t *)SLAP_MALLOC( (n + 1) * sizeof(slap_mask_t) );
347 if ( masks == NULL ) {
349 return LDAP_NO_MEMORY;
354 LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
355 oids[n] = ch_strdup( sc->sc_oid );
356 masks[n] = sc->sc_mask;
369 * Find a control given its OID.
371 static struct slap_control *
372 find_ctrl( const char *oid )
374 struct slap_control *sc;
376 LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
377 if ( strcmp( oid, sc->sc_oid ) == 0 ) {
386 slap_find_control_id(
390 struct slap_control *ctrl = find_ctrl( oid );
392 if ( cid ) *cid = ctrl->sc_cid;
395 return LDAP_CONTROL_NOT_FOUND;
399 slap_global_control( Operation *op, const char *oid, int *cid )
401 struct slap_control *ctrl = find_ctrl( oid );
403 if ( ctrl == NULL ) {
404 /* should not be reachable */
405 Debug( LDAP_DEBUG_ANY,
406 "slap_global_control: unrecognized control: %s\n",
408 return LDAP_CONTROL_NOT_FOUND;
411 if ( cid ) *cid = ctrl->sc_cid;
413 if ( ( ctrl->sc_mask & SLAP_CTRL_GLOBAL ) ||
414 ( ( op->o_tag & LDAP_REQ_SEARCH ) &&
415 ( ctrl->sc_mask & SLAP_CTRL_GLOBAL_SEARCH ) ) )
417 return LDAP_COMPARE_TRUE;
420 Debug( LDAP_DEBUG_TRACE,
421 "slap_global_control: unavailable control: %s\n",
424 return LDAP_COMPARE_FALSE;
427 void slap_free_ctrls(
429 LDAPControl **ctrls )
433 for (i=0; ctrls[i]; i++) {
434 op->o_tmpfree(ctrls[i], op->o_tmpmemctx );
436 op->o_tmpfree( ctrls, op->o_tmpmemctx );
442 LDAPControl *control,
445 struct slap_control *sc;
447 sc = find_ctrl( control->ldctl_oid );
449 /* recognized control */
451 switch( op->o_tag ) {
453 tagmask = SLAP_CTRL_ADD;
456 tagmask = SLAP_CTRL_BIND;
458 case LDAP_REQ_COMPARE:
459 tagmask = SLAP_CTRL_COMPARE;
461 case LDAP_REQ_DELETE:
462 tagmask = SLAP_CTRL_DELETE;
464 case LDAP_REQ_MODIFY:
465 tagmask = SLAP_CTRL_MODIFY;
467 case LDAP_REQ_RENAME:
468 tagmask = SLAP_CTRL_RENAME;
470 case LDAP_REQ_SEARCH:
471 tagmask = SLAP_CTRL_SEARCH;
473 case LDAP_REQ_UNBIND:
474 tagmask = SLAP_CTRL_UNBIND;
476 case LDAP_REQ_ABANDON:
477 tagmask = SLAP_CTRL_ABANDON;
479 case LDAP_REQ_EXTENDED:
481 assert( op->ore_reqoid.bv_val != NULL );
482 if( sc->sc_extendedops != NULL ) {
484 for( i=0; sc->sc_extendedops[i] != NULL; i++ ) {
485 if( strcmp( op->ore_reqoid.bv_val,
486 sc->sc_extendedops[i] ) == 0 )
495 *text = "controls internal error";
499 if (( sc->sc_mask & tagmask ) == tagmask ) {
500 /* available extension */
503 if( !sc->sc_parse ) {
504 *text = "not yet implemented";
508 rc = sc->sc_parse( op, rs, control );
510 assert( rc != LDAP_UNAVAILABLE_CRITICAL_EXTENSION );
514 } else if( control->ldctl_iscritical ) {
515 /* unavailable CRITICAL control */
516 *text = "critical extension is unavailable";
517 return LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
519 } else if( control->ldctl_iscritical ) {
520 /* unrecognized CRITICAL control */
521 *text = "critical extension is not recognized";
522 return LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
537 BerElement *ber = op->o_ber;
540 len = ber_pvt_ber_remaining(ber);
544 rs->sr_err = LDAP_SUCCESS;
548 if(( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) {
549 if( tag == LBER_ERROR ) {
550 rs->sr_err = SLAPD_DISCONNECT;
551 rs->sr_text = "unexpected data in PDU";
557 Debug( LDAP_DEBUG_TRACE,
558 "=> get_ctrls\n", 0, 0, 0 );
560 if( op->o_protocol < LDAP_VERSION3 ) {
561 rs->sr_err = SLAPD_DISCONNECT;
562 rs->sr_text = "controls require LDAPv3";
566 /* one for first control, one for termination */
567 op->o_ctrls = op->o_tmpalloc( 2 * sizeof(LDAPControl *), op->o_tmpmemctx );
570 if( op->ctrls == NULL ) {
571 rs->sr_err = LDAP_NO_MEMORY;
572 rs->sr_text = "no memory";
577 op->o_ctrls[nctrls] = NULL;
579 /* step through each element */
580 for( tag = ber_first_element( ber, &len, &opaque );
582 tag = ber_next_element( ber, &len, opaque ) )
585 LDAPControl **tctrls;
587 c = op->o_tmpalloc( sizeof(LDAPControl), op->o_tmpmemctx );
588 memset(c, 0, sizeof(LDAPControl));
590 /* allocate pointer space for current controls (nctrls)
591 * + this control + extra NULL
593 tctrls = op->o_tmprealloc( op->o_ctrls,
594 (nctrls+2) * sizeof(LDAPControl *), op->o_tmpmemctx );
597 if( tctrls == NULL ) {
599 ldap_controls_free(op->o_ctrls);
602 rs->sr_err = LDAP_NO_MEMORY;
603 rs->sr_text = "no memory";
607 op->o_ctrls = tctrls;
609 op->o_ctrls[nctrls++] = c;
610 op->o_ctrls[nctrls] = NULL;
612 tag = ber_scanf( ber, "{m" /*}*/, &bv );
613 c->ldctl_oid = bv.bv_val;
615 if( tag == LBER_ERROR ) {
616 Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get oid failed.\n",
619 slap_free_ctrls( op, op->o_ctrls );
621 rs->sr_err = SLAPD_DISCONNECT;
622 rs->sr_text = "decoding controls error";
625 } else if( c->ldctl_oid == NULL ) {
626 Debug( LDAP_DEBUG_TRACE,
627 "get_ctrls: conn %lu got emtpy OID.\n",
628 op->o_connid, 0, 0 );
630 slap_free_ctrls( op, op->o_ctrls );
632 rs->sr_err = LDAP_PROTOCOL_ERROR;
633 rs->sr_text = "OID field is empty";
637 tag = ber_peek_tag( ber, &len );
639 if( tag == LBER_BOOLEAN ) {
641 tag = ber_scanf( ber, "b", &crit );
643 if( tag == LBER_ERROR ) {
644 Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get crit failed.\n",
646 slap_free_ctrls( op, op->o_ctrls );
648 rs->sr_err = SLAPD_DISCONNECT;
649 rs->sr_text = "decoding controls error";
653 c->ldctl_iscritical = (crit != 0);
654 tag = ber_peek_tag( ber, &len );
657 if( tag == LBER_OCTETSTRING ) {
658 tag = ber_scanf( ber, "m", &c->ldctl_value );
660 if( tag == LBER_ERROR ) {
661 Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: conn %lu: "
662 "%s (%scritical): get value failed.\n",
663 op->o_connid, c->ldctl_oid,
664 c->ldctl_iscritical ? "" : "non" );
665 slap_free_ctrls( op, op->o_ctrls );
667 rs->sr_err = SLAPD_DISCONNECT;
668 rs->sr_text = "decoding controls error";
673 Debug( LDAP_DEBUG_TRACE,
674 "=> get_ctrls: oid=\"%s\" (%scritical)\n",
675 c->ldctl_oid, c->ldctl_iscritical ? "" : "non", 0 );
677 rs->sr_err = slap_parse_ctrl( op, rs, c, &rs->sr_text );
678 if ( rs->sr_err != LDAP_SUCCESS ) {
684 Debug( LDAP_DEBUG_TRACE,
685 "<= get_ctrls: n=%d rc=%d err=\"%s\"\n",
686 nctrls, rs->sr_err, rs->sr_text ? rs->sr_text : "");
688 if( sendres && rs->sr_err != LDAP_SUCCESS ) {
689 if( rs->sr_err == SLAPD_DISCONNECT ) {
690 rs->sr_err = LDAP_PROTOCOL_ERROR;
691 send_ldap_disconnect( op, rs );
692 rs->sr_err = SLAPD_DISCONNECT;
694 send_ldap_result( op, rs );
706 BI_chk_controls fnc )
710 switch ( op->o_ctrlflag[ ctrl ] ) {
711 case SLAP_CONTROL_NONCRITICAL:
712 for ( i = 0, j = -1; op->o_ctrls[ i ] != NULL; i++ ) {
713 if ( strcmp( op->o_ctrls[ i ]->ldctl_oid,
714 slap_known_controls[ ctrl - 1 ] ) == 0 )
721 rs->sr_err = LDAP_OTHER;
729 op->o_tmpfree( op->o_ctrls[ j ], op->o_tmpmemctx );
732 AC_MEMCPY( &op->o_ctrls[ j ], &op->o_ctrls[ j + 1 ],
733 ( i - j ) * sizeof( LDAPControl * ) );
736 op->o_tmpfree( op->o_ctrls, op->o_tmpmemctx );
740 op->o_ctrlflag[ ctrl ] = SLAP_CONTROL_IGNORED;
742 Debug( LDAP_DEBUG_ANY, "%s: "
743 "non-critical control \"%s\" not supported; stripped.\n",
744 op->o_log_prefix, slap_known_controls[ ctrl ], 0 );
747 case SLAP_CONTROL_IGNORED:
748 case SLAP_CONTROL_NONE:
749 rs->sr_err = SLAP_CB_CONTINUE;
752 case SLAP_CONTROL_CRITICAL:
753 rs->sr_err = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
757 Debug( LDAP_DEBUG_ANY, "%s: "
758 "critical control \"%s\" not supported.\n",
759 op->o_log_prefix, slap_known_controls[ ctrl ], 0 );
763 /* handle all cases! */
771 static int parseDontUseCopy (
776 if ( op->o_dontUseCopy != SLAP_CONTROL_NONE ) {
777 rs->sr_text = "dontUseCopy control specified multiple times";
778 return LDAP_PROTOCOL_ERROR;
781 if ( ctrl->ldctl_value.bv_len ) {
782 rs->sr_text = "dontUseCopy control value not empty";
783 return LDAP_PROTOCOL_ERROR;
786 if ( ctrl->ldctl_iscritical != SLAP_CONTROL_CRITICAL ) {
787 rs->sr_text = "dontUseCopy criticality of FALSE not allowed";
788 return LDAP_PROTOCOL_ERROR;
791 op->o_dontUseCopy = SLAP_CONTROL_CRITICAL;
795 static int parseManageDIT (
800 if ( op->o_managedit != SLAP_CONTROL_NONE ) {
801 rs->sr_text = "manageDIT control specified multiple times";
802 return LDAP_PROTOCOL_ERROR;
805 if ( ctrl->ldctl_value.bv_len ) {
806 rs->sr_text = "manageDIT control value not empty";
807 return LDAP_PROTOCOL_ERROR;
810 op->o_managedit = ctrl->ldctl_iscritical
811 ? SLAP_CONTROL_CRITICAL
812 : SLAP_CONTROL_NONCRITICAL;
818 static int parseManageDSAit (
823 if ( op->o_managedsait != SLAP_CONTROL_NONE ) {
824 rs->sr_text = "manageDSAit control specified multiple times";
825 return LDAP_PROTOCOL_ERROR;
828 if ( ctrl->ldctl_value.bv_len ) {
829 rs->sr_text = "manageDSAit control value not empty";
830 return LDAP_PROTOCOL_ERROR;
833 op->o_managedsait = ctrl->ldctl_iscritical
834 ? SLAP_CONTROL_CRITICAL
835 : SLAP_CONTROL_NONCRITICAL;
840 static int parseProxyAuthz (
846 struct berval dn = BER_BVNULL;
848 if ( op->o_proxy_authz != SLAP_CONTROL_NONE ) {
849 rs->sr_text = "proxy authorization control specified multiple times";
850 return LDAP_PROTOCOL_ERROR;
853 if ( BER_BVISEMPTY( &op->o_ndn ) ) {
854 rs->sr_text = "anonymous proxyAuthz not allowed";
855 return LDAP_PROXY_AUTHZ_FAILURE;
858 op->o_proxy_authz = ctrl->ldctl_iscritical
859 ? SLAP_CONTROL_CRITICAL
860 : SLAP_CONTROL_NONCRITICAL;
862 Debug( LDAP_DEBUG_ARGS,
863 "parseProxyAuthz: conn %lu authzid=\"%s\"\n",
865 ctrl->ldctl_value.bv_len ? ctrl->ldctl_value.bv_val : "anonymous",
868 if ( ctrl->ldctl_value.bv_len == 0 ) {
869 Debug( LDAP_DEBUG_TRACE,
870 "parseProxyAuthz: conn=%lu anonymous\n",
871 op->o_connid, 0, 0 );
874 if ( !BER_BVISNULL( &op->o_ndn ) ) {
875 op->o_ndn.bv_val[ 0 ] = '\0';
877 op->o_ndn.bv_len = 0;
879 if ( !BER_BVISNULL( &op->o_dn ) ) {
880 op->o_dn.bv_val[ 0 ] = '\0';
887 rc = slap_sasl_getdn( op->o_conn, op, &ctrl->ldctl_value,
888 NULL, &dn, SLAP_GETDN_AUTHZID );
890 /* FIXME: empty DN in proxyAuthz control should be legal... */
891 if( rc != LDAP_SUCCESS /* || !dn.bv_len */ ) {
893 ch_free( dn.bv_val );
895 rs->sr_text = "authzId mapping failed";
896 return LDAP_PROXY_AUTHZ_FAILURE;
899 Debug( LDAP_DEBUG_TRACE,
900 "parseProxyAuthz: conn=%lu \"%s\"\n",
902 dn.bv_len ? dn.bv_val : "(NULL)", 0 );
904 rc = slap_sasl_authorized( op, &op->o_ndn, &dn );
907 ch_free( dn.bv_val );
908 rs->sr_text = "not authorized to assume identity";
909 return LDAP_PROXY_AUTHZ_FAILURE;
912 ch_free( op->o_ndn.bv_val );
913 ch_free( op->o_dn.bv_val );
916 * NOTE: since slap_sasl_getdn() returns a normalized dn,
917 * from now on op->o_dn is normalized
920 ber_dupbv( &op->o_dn, &dn );
923 Statslog( LDAP_DEBUG_STATS, "%s PROXYAUTHZ dn=\"%s\"\n",
924 op->o_log_prefix, dn.bv_val, 0, 0, 0 );
929 static int parseNoOp (
934 if ( op->o_noop != SLAP_CONTROL_NONE ) {
935 rs->sr_text = "noop control specified multiple times";
936 return LDAP_PROTOCOL_ERROR;
939 if ( ctrl->ldctl_value.bv_len ) {
940 rs->sr_text = "noop control value not empty";
941 return LDAP_PROTOCOL_ERROR;
944 op->o_noop = ctrl->ldctl_iscritical
945 ? SLAP_CONTROL_CRITICAL
946 : SLAP_CONTROL_NONCRITICAL;
951 static int parsePagedResults (
956 int rc = LDAP_SUCCESS;
960 struct berval cookie = BER_BVNULL;
961 PagedResultsState *ps;
963 if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
964 rs->sr_text = "paged results control specified multiple times";
965 return LDAP_PROTOCOL_ERROR;
968 if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
969 rs->sr_text = "paged results control value is empty (or absent)";
970 return LDAP_PROTOCOL_ERROR;
973 /* Parse the control value
974 * realSearchControlValue ::= SEQUENCE {
975 * size INTEGER (0..maxInt),
976 * -- requested page size from client
977 * -- result set size estimate from server
978 * cookie OCTET STRING
981 ber = ber_init( &ctrl->ldctl_value );
983 rs->sr_text = "internal error";
987 tag = ber_scanf( ber, "{im}", &size, &cookie );
989 if ( tag == LBER_ERROR ) {
990 rs->sr_text = "paged results control could not be decoded";
991 rc = LDAP_PROTOCOL_ERROR;
996 rs->sr_text = "paged results control size invalid";
997 rc = LDAP_PROTOCOL_ERROR;
1001 ps = op->o_tmpalloc( sizeof(PagedResultsState), op->o_tmpmemctx );
1002 *ps = op->o_conn->c_pagedresults_state;
1004 op->o_pagedresults_state = ps;
1006 /* NOTE: according to RFC 2696 3.:
1008 If the page size is greater than or equal to the sizeLimit value, the
1009 server should ignore the control as the request can be satisfied in a
1012 * NOTE: this assumes that the op->ors_slimit be set
1013 * before the controls are parsed.
1016 if ( op->ors_slimit > 0 && size >= op->ors_slimit ) {
1017 op->o_pagedresults = SLAP_CONTROL_IGNORED;
1019 } else if ( ctrl->ldctl_iscritical ) {
1020 op->o_pagedresults = SLAP_CONTROL_CRITICAL;
1023 op->o_pagedresults = SLAP_CONTROL_NONCRITICAL;
1027 (void)ber_free( ber, 1 );
1032 static int parseSortedResults (
1037 int rc = LDAP_SUCCESS;
1039 if ( op->o_sortedresults != SLAP_CONTROL_NONE ) {
1040 rs->sr_text = "sorted results control specified multiple times";
1041 return LDAP_PROTOCOL_ERROR;
1044 if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
1045 rs->sr_text = "sorted results control value is empty (or absent)";
1046 return LDAP_PROTOCOL_ERROR;
1049 /* blow off parsing the value */
1051 op->o_sortedresults = ctrl->ldctl_iscritical
1052 ? SLAP_CONTROL_CRITICAL
1053 : SLAP_CONTROL_NONCRITICAL;
1059 static int parseAssert (
1065 struct berval fstr = BER_BVNULL;
1067 if ( op->o_assert != SLAP_CONTROL_NONE ) {
1068 rs->sr_text = "assert control specified multiple times";
1069 return LDAP_PROTOCOL_ERROR;
1072 if ( ctrl->ldctl_value.bv_len == 0 ) {
1073 rs->sr_text = "assert control value is empty (or absent)";
1074 return LDAP_PROTOCOL_ERROR;
1077 ber = ber_init( &(ctrl->ldctl_value) );
1079 rs->sr_text = "assert control: internal error";
1083 rs->sr_err = get_filter( op, ber, (Filter **)&(op->o_assertion),
1085 if( rs->sr_err != LDAP_SUCCESS ) {
1086 if( rs->sr_err == SLAPD_DISCONNECT ) {
1087 rs->sr_err = LDAP_PROTOCOL_ERROR;
1088 send_ldap_disconnect( op, rs );
1089 rs->sr_err = SLAPD_DISCONNECT;
1091 send_ldap_result( op, rs );
1093 if( op->o_assertion != NULL ) {
1094 filter_free_x( op, op->o_assertion );
1100 filter2bv_x( op, op->o_assertion, &fstr );
1102 Debug( LDAP_DEBUG_ARGS, "parseAssert: conn %ld assert: %s\n",
1103 op->o_connid, fstr.bv_len ? fstr.bv_val : "empty" , 0 );
1104 op->o_tmpfree( fstr.bv_val, op->o_tmpmemctx );
1107 op->o_assert = ctrl->ldctl_iscritical
1108 ? SLAP_CONTROL_CRITICAL
1109 : SLAP_CONTROL_NONCRITICAL;
1111 rs->sr_err = LDAP_SUCCESS;
1112 return LDAP_SUCCESS;
1115 static int parsePreRead (
1120 ber_len_t siz, off, i;
1121 AttributeName *an = NULL;
1124 if ( op->o_preread != SLAP_CONTROL_NONE ) {
1125 rs->sr_text = "preread control specified multiple times";
1126 return LDAP_PROTOCOL_ERROR;
1129 if ( ctrl->ldctl_value.bv_len == 0 ) {
1130 rs->sr_text = "preread control value is empty (or absent)";
1131 return LDAP_PROTOCOL_ERROR;
1134 ber = ber_init( &(ctrl->ldctl_value) );
1136 rs->sr_text = "preread control: internal error";
1140 siz = sizeof( AttributeName );
1141 off = offsetof( AttributeName, an_name );
1142 if ( ber_scanf( ber, "{M}", &an, &siz, off ) == LBER_ERROR ) {
1143 rs->sr_text = "preread control: decoding error";
1144 return LDAP_PROTOCOL_ERROR;
1147 for( i=0; i<siz; i++ ) {
1148 int rc = LDAP_SUCCESS;
1149 const char *dummy = NULL;
1151 an[i].an_desc = NULL;
1153 an[i].an_oc_exclude = 0;
1154 rc = slap_bv2ad( &an[i].an_name, &an[i].an_desc, &dummy );
1155 if ( rc != LDAP_SUCCESS && ctrl->ldctl_iscritical ) {
1158 : "postread control: unknown attributeType";
1163 op->o_preread = ctrl->ldctl_iscritical
1164 ? SLAP_CONTROL_CRITICAL
1165 : SLAP_CONTROL_NONCRITICAL;
1167 op->o_preread_attrs = an;
1169 rs->sr_err = LDAP_SUCCESS;
1170 return LDAP_SUCCESS;
1173 static int parsePostRead (
1178 ber_len_t siz, off, i;
1179 AttributeName *an = NULL;
1182 if ( op->o_postread != SLAP_CONTROL_NONE ) {
1183 rs->sr_text = "postread control specified multiple times";
1184 return LDAP_PROTOCOL_ERROR;
1187 if ( ctrl->ldctl_value.bv_len == 0 ) {
1188 rs->sr_text = "postread control value is empty (or absent)";
1189 return LDAP_PROTOCOL_ERROR;
1192 ber = ber_init( &(ctrl->ldctl_value) );
1194 rs->sr_text = "postread control: internal error";
1198 siz = sizeof( AttributeName );
1199 off = offsetof( AttributeName, an_name );
1200 if ( ber_scanf( ber, "{M}", &an, &siz, off ) == LBER_ERROR ) {
1201 rs->sr_text = "postread control: decoding error";
1202 return LDAP_PROTOCOL_ERROR;
1205 for( i=0; i<siz; i++ ) {
1206 int rc = LDAP_SUCCESS;
1207 const char *dummy = NULL;
1209 an[i].an_desc = NULL;
1211 an[i].an_oc_exclude = 0;
1212 rc = slap_bv2ad( &an[i].an_name, &an[i].an_desc, &dummy );
1213 if ( rc != LDAP_SUCCESS && ctrl->ldctl_iscritical ) {
1216 : "postread control: unknown attributeType";
1221 op->o_postread = ctrl->ldctl_iscritical
1222 ? SLAP_CONTROL_CRITICAL
1223 : SLAP_CONTROL_NONCRITICAL;
1225 op->o_postread_attrs = an;
1227 rs->sr_err = LDAP_SUCCESS;
1228 return LDAP_SUCCESS;
1231 static int parseValuesReturnFilter (
1237 struct berval fstr = BER_BVNULL;
1239 if ( op->o_valuesreturnfilter != SLAP_CONTROL_NONE ) {
1240 rs->sr_text = "valuesReturnFilter control specified multiple times";
1241 return LDAP_PROTOCOL_ERROR;
1244 if ( ctrl->ldctl_value.bv_len == 0 ) {
1245 rs->sr_text = "valuesReturnFilter control value is empty (or absent)";
1246 return LDAP_PROTOCOL_ERROR;
1249 ber = ber_init( &(ctrl->ldctl_value) );
1251 rs->sr_text = "internal error";
1255 rs->sr_err = get_vrFilter( op, ber,
1256 (ValuesReturnFilter **)&(op->o_vrFilter), &rs->sr_text);
1258 if( rs->sr_err != LDAP_SUCCESS ) {
1259 if( rs->sr_err == SLAPD_DISCONNECT ) {
1260 rs->sr_err = LDAP_PROTOCOL_ERROR;
1261 send_ldap_disconnect( op, rs );
1262 rs->sr_err = SLAPD_DISCONNECT;
1264 send_ldap_result( op, rs );
1266 if( op->o_vrFilter != NULL) vrFilter_free( op, op->o_vrFilter );
1270 vrFilter2bv( op, op->o_vrFilter, &fstr );
1273 Debug( LDAP_DEBUG_ARGS, " vrFilter: %s\n",
1274 fstr.bv_len ? fstr.bv_val : "empty", 0, 0 );
1275 op->o_tmpfree( fstr.bv_val, op->o_tmpmemctx );
1278 op->o_valuesreturnfilter = ctrl->ldctl_iscritical
1279 ? SLAP_CONTROL_CRITICAL
1280 : SLAP_CONTROL_NONCRITICAL;
1282 rs->sr_err = LDAP_SUCCESS;
1283 return LDAP_SUCCESS;
1286 static int parseSubentries (
1291 if ( op->o_subentries != SLAP_CONTROL_NONE ) {
1292 rs->sr_text = "subentries control specified multiple times";
1293 return LDAP_PROTOCOL_ERROR;
1296 /* FIXME: should use BER library */
1297 if( ( ctrl->ldctl_value.bv_len != 3 )
1298 || ( ctrl->ldctl_value.bv_val[0] != 0x01 )
1299 || ( ctrl->ldctl_value.bv_val[1] != 0x01 ))
1301 rs->sr_text = "subentries control value encoding is bogus";
1302 return LDAP_PROTOCOL_ERROR;
1305 op->o_subentries = ctrl->ldctl_iscritical
1306 ? SLAP_CONTROL_CRITICAL
1307 : SLAP_CONTROL_NONCRITICAL;
1309 if (ctrl->ldctl_value.bv_val[2]) {
1310 set_subentries_visibility( op );
1313 return LDAP_SUCCESS;
1316 static int parsePermissiveModify (
1321 if ( op->o_permissive_modify != SLAP_CONTROL_NONE ) {
1322 rs->sr_text = "permissiveModify control specified multiple times";
1323 return LDAP_PROTOCOL_ERROR;
1326 if ( ctrl->ldctl_value.bv_len ) {
1327 rs->sr_text = "permissiveModify control value not empty";
1328 return LDAP_PROTOCOL_ERROR;
1331 op->o_permissive_modify = ctrl->ldctl_iscritical
1332 ? SLAP_CONTROL_CRITICAL
1333 : SLAP_CONTROL_NONCRITICAL;
1335 return LDAP_SUCCESS;
1338 static int parseDomainScope (
1343 if ( op->o_domain_scope != SLAP_CONTROL_NONE ) {
1344 rs->sr_text = "domainScope control specified multiple times";
1345 return LDAP_PROTOCOL_ERROR;
1348 if ( ctrl->ldctl_value.bv_len ) {
1349 rs->sr_text = "domainScope control value not empty";
1350 return LDAP_PROTOCOL_ERROR;
1353 op->o_domain_scope = ctrl->ldctl_iscritical
1354 ? SLAP_CONTROL_CRITICAL
1355 : SLAP_CONTROL_NONCRITICAL;
1357 return LDAP_SUCCESS;
1360 #ifdef SLAP_CONTROL_X_TREE_DELETE
1361 static int parseTreeDelete (
1366 if ( op->o_tree_delete != SLAP_CONTROL_NONE ) {
1367 rs->sr_text = "treeDelete control specified multiple times";
1368 return LDAP_PROTOCOL_ERROR;
1371 if ( ctrl->ldctl_value.bv_len ) {
1372 rs->sr_text = "treeDelete control value not empty";
1373 return LDAP_PROTOCOL_ERROR;
1376 op->o_tree_delete = ctrl->ldctl_iscritical
1377 ? SLAP_CONTROL_CRITICAL
1378 : SLAP_CONTROL_NONCRITICAL;
1380 return LDAP_SUCCESS;
1384 static int parseSearchOptions (
1390 ber_int_t search_flags;
1393 if ( ctrl->ldctl_value.bv_len == 0 ) {
1394 rs->sr_text = "searchOptions control value is empty (or absent)";
1395 return LDAP_PROTOCOL_ERROR;
1398 ber = ber_init( &ctrl->ldctl_value );
1400 rs->sr_text = "internal error";
1404 if ( (tag = ber_scanf( ber, "{i}", &search_flags )) == LBER_ERROR ) {
1405 rs->sr_text = "searchOptions control decoding error";
1406 return LDAP_PROTOCOL_ERROR;
1409 (void) ber_free( ber, 1 );
1411 if ( search_flags & LDAP_SEARCH_FLAG_DOMAIN_SCOPE ) {
1412 if ( op->o_domain_scope != SLAP_CONTROL_NONE ) {
1413 rs->sr_text = "searchOptions control specified multiple times "
1414 "or with domainScope control";
1415 return LDAP_PROTOCOL_ERROR;
1418 op->o_domain_scope = ctrl->ldctl_iscritical
1419 ? SLAP_CONTROL_CRITICAL
1420 : SLAP_CONTROL_NONCRITICAL;
1423 if ( search_flags & ~(LDAP_SEARCH_FLAG_DOMAIN_SCOPE) ) {
1424 /* Other search flags not recognised so far,
1426 * LDAP_SEARCH_FLAG_PHANTOM_ROOM
1428 rs->sr_text = "searchOptions contained unrecognized flag";
1429 return LDAP_UNWILLING_TO_PERFORM;
1432 return LDAP_SUCCESS;