Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / openldap / dist / servers / slapd / controls.c
blob101695a2ac6f829bf3836c6b82cb8aa9c13e54ed
1 /* $OpenLDAP: pkg/ldap/servers/slapd/controls.c,v 1.174.2.10 2008/04/14 22:15:21 quanah Exp $ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1998-2008 The OpenLDAP Foundation.
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
9 * Public License.
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>.
16 #include "portable.h"
18 #include <stdio.h>
20 #include <ac/string.h>
21 #include <ac/socket.h>
23 #include "slap.h"
24 #include "ldif.h"
25 #include "lutil.h"
27 #include "../../libraries/liblber/lber-int.h"
29 static SLAP_CTRL_PARSE_FN parseAssert;
30 static SLAP_CTRL_PARSE_FN parseDomainScope;
31 static SLAP_CTRL_PARSE_FN parseDontUseCopy;
32 static SLAP_CTRL_PARSE_FN parseManageDSAit;
33 static SLAP_CTRL_PARSE_FN parseNoOp;
34 static SLAP_CTRL_PARSE_FN parsePagedResults;
35 static SLAP_CTRL_PARSE_FN parsePermissiveModify;
36 static SLAP_CTRL_PARSE_FN parsePreRead, parsePostRead;
37 static SLAP_CTRL_PARSE_FN parseProxyAuthz;
38 static SLAP_CTRL_PARSE_FN parseRelax;
39 static SLAP_CTRL_PARSE_FN parseSearchOptions;
40 #ifdef SLAP_CONTROL_X_SORTEDRESULTS
41 static SLAP_CTRL_PARSE_FN parseSortedResults;
42 #endif
43 static SLAP_CTRL_PARSE_FN parseSubentries;
44 #ifdef SLAP_CONTROL_X_TREE_DELETE
45 static SLAP_CTRL_PARSE_FN parseTreeDelete;
46 #endif
47 static SLAP_CTRL_PARSE_FN parseValuesReturnFilter;
48 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
49 static SLAP_CTRL_PARSE_FN parseSessionTracking;
50 #endif
52 #undef sc_mask /* avoid conflict with Irix 6.5 <sys/signal.h> */
54 const struct berval slap_pre_read_bv = BER_BVC(LDAP_CONTROL_PRE_READ);
55 const struct berval slap_post_read_bv = BER_BVC(LDAP_CONTROL_POST_READ);
57 struct slap_control_ids slap_cids;
59 struct slap_control {
60 /* Control OID */
61 char *sc_oid;
63 /* The controlID for this control */
64 int sc_cid;
66 /* Operations supported by control */
67 slap_mask_t sc_mask;
69 /* Extended operations supported by control */
70 char **sc_extendedops; /* input */
71 BerVarray sc_extendedopsbv; /* run-time use */
73 /* Control parsing callback */
74 SLAP_CTRL_PARSE_FN *sc_parse;
76 LDAP_SLIST_ENTRY(slap_control) sc_next;
79 static LDAP_SLIST_HEAD(ControlsList, slap_control) controls_list
80 = LDAP_SLIST_HEAD_INITIALIZER(&controls_list);
83 * all known request control OIDs should be added to this list
86 * NOTE: initialize num_known_controls to 1 so that cid = 0 always
87 * addresses an undefined control; this allows to safely test for
88 * well known controls even if they are not registered, e.g. if
89 * they get moved to modules. An example is sc_LDAPsync, which
90 * is implemented in the syncprov overlay and thus, if configured
91 * as dynamic module, may not be registered. One side effect is that
92 * slap_known_controls[0] == NULL, so it should always be used
93 * starting from 1.
94 * FIXME: should we define the "undefined control" oid?
96 char *slap_known_controls[SLAP_MAX_CIDS+1];
97 static int num_known_controls = 1;
99 static char *proxy_authz_extops[] = {
100 LDAP_EXOP_MODIFY_PASSWD,
101 LDAP_EXOP_WHO_AM_I,
102 LDAP_EXOP_REFRESH,
103 NULL
106 static char *manageDSAit_extops[] = {
107 LDAP_EXOP_REFRESH,
108 NULL
111 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
112 static char *session_tracking_extops[] = {
113 LDAP_EXOP_MODIFY_PASSWD,
114 LDAP_EXOP_WHO_AM_I,
115 LDAP_EXOP_REFRESH,
116 NULL
118 #endif
120 static struct slap_control control_defs[] = {
121 { LDAP_CONTROL_ASSERT,
122 (int)offsetof(struct slap_control_ids, sc_assert),
123 SLAP_CTRL_DELETE|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME|
124 SLAP_CTRL_COMPARE|SLAP_CTRL_SEARCH,
125 NULL, NULL,
126 parseAssert, LDAP_SLIST_ENTRY_INITIALIZER(next) },
127 { LDAP_CONTROL_PRE_READ,
128 (int)offsetof(struct slap_control_ids, sc_preRead),
129 SLAP_CTRL_DELETE|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME,
130 NULL, NULL,
131 parsePreRead, LDAP_SLIST_ENTRY_INITIALIZER(next) },
132 { LDAP_CONTROL_POST_READ,
133 (int)offsetof(struct slap_control_ids, sc_postRead),
134 SLAP_CTRL_ADD|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME,
135 NULL, NULL,
136 parsePostRead, LDAP_SLIST_ENTRY_INITIALIZER(next) },
137 { LDAP_CONTROL_VALUESRETURNFILTER,
138 (int)offsetof(struct slap_control_ids, sc_valuesReturnFilter),
139 SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH,
140 NULL, NULL,
141 parseValuesReturnFilter, LDAP_SLIST_ENTRY_INITIALIZER(next) },
142 { LDAP_CONTROL_PAGEDRESULTS,
143 (int)offsetof(struct slap_control_ids, sc_pagedResults),
144 SLAP_CTRL_SEARCH,
145 NULL, NULL,
146 parsePagedResults, LDAP_SLIST_ENTRY_INITIALIZER(next) },
147 #ifdef SLAP_CONTROL_X_SORTEDRESULTS
148 { LDAP_CONTROL_SORTREQUEST,
149 (int)offsetof(struct slap_control_ids, sc_sortedResults),
150 SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH|SLAP_CTRL_HIDE,
151 NULL, NULL,
152 parseSortedResults, LDAP_SLIST_ENTRY_INITIALIZER(next) },
153 #endif
154 { LDAP_CONTROL_X_DOMAIN_SCOPE,
155 (int)offsetof(struct slap_control_ids, sc_domainScope),
156 SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH|SLAP_CTRL_HIDE,
157 NULL, NULL,
158 parseDomainScope, LDAP_SLIST_ENTRY_INITIALIZER(next) },
159 { LDAP_CONTROL_DONTUSECOPY,
160 (int)offsetof(struct slap_control_ids, sc_dontUseCopy),
161 SLAP_CTRL_GLOBAL|SLAP_CTRL_INTROGATE|SLAP_CTRL_HIDE,
162 NULL, NULL,
163 parseDontUseCopy, LDAP_SLIST_ENTRY_INITIALIZER(next) },
164 { LDAP_CONTROL_X_PERMISSIVE_MODIFY,
165 (int)offsetof(struct slap_control_ids, sc_permissiveModify),
166 SLAP_CTRL_MODIFY|SLAP_CTRL_HIDE,
167 NULL, NULL,
168 parsePermissiveModify, LDAP_SLIST_ENTRY_INITIALIZER(next) },
169 #ifdef SLAP_CONTROL_X_TREE_DELETE
170 { LDAP_CONTROL_X_TREE_DELETE,
171 (int)offsetof(struct slap_control_ids, sc_treeDelete),
172 SLAP_CTRL_DELETE|SLAP_CTRL_HIDE,
173 NULL, NULL,
174 parseTreeDelete, LDAP_SLIST_ENTRY_INITIALIZER(next) },
175 #endif
176 { LDAP_CONTROL_X_SEARCH_OPTIONS,
177 (int)offsetof(struct slap_control_ids, sc_searchOptions),
178 SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH|SLAP_CTRL_HIDE,
179 NULL, NULL,
180 parseSearchOptions, LDAP_SLIST_ENTRY_INITIALIZER(next) },
181 { LDAP_CONTROL_SUBENTRIES,
182 (int)offsetof(struct slap_control_ids, sc_subentries),
183 SLAP_CTRL_SEARCH,
184 NULL, NULL,
185 parseSubentries, LDAP_SLIST_ENTRY_INITIALIZER(next) },
186 { LDAP_CONTROL_NOOP,
187 (int)offsetof(struct slap_control_ids, sc_noOp),
188 SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE,
189 NULL, NULL,
190 parseNoOp, LDAP_SLIST_ENTRY_INITIALIZER(next) },
191 { LDAP_CONTROL_RELAX,
192 (int)offsetof(struct slap_control_ids, sc_relax),
193 SLAP_CTRL_GLOBAL|SLAP_CTRL_UPDATE|SLAP_CTRL_HIDE,
194 NULL, NULL,
195 parseRelax, LDAP_SLIST_ENTRY_INITIALIZER(next) },
196 #ifdef LDAP_X_TXN
197 { LDAP_CONTROL_X_TXN_SPEC,
198 (int)offsetof(struct slap_control_ids, sc_txnSpec),
199 SLAP_CTRL_UPDATE|SLAP_CTRL_HIDE,
200 NULL, NULL,
201 txn_spec_ctrl, LDAP_SLIST_ENTRY_INITIALIZER(next) },
202 #endif
203 { LDAP_CONTROL_MANAGEDSAIT,
204 (int)offsetof(struct slap_control_ids, sc_manageDSAit),
205 SLAP_CTRL_ACCESS,
206 manageDSAit_extops, NULL,
207 parseManageDSAit, LDAP_SLIST_ENTRY_INITIALIZER(next) },
208 { LDAP_CONTROL_PROXY_AUTHZ,
209 (int)offsetof(struct slap_control_ids, sc_proxyAuthz),
210 SLAP_CTRL_GLOBAL|SLAP_CTRL_ACCESS,
211 proxy_authz_extops, NULL,
212 parseProxyAuthz, LDAP_SLIST_ENTRY_INITIALIZER(next) },
213 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
214 { LDAP_CONTROL_X_SESSION_TRACKING,
215 (int)offsetof(struct slap_control_ids, sc_sessionTracking),
216 SLAP_CTRL_GLOBAL|SLAP_CTRL_ACCESS|SLAP_CTRL_BIND|SLAP_CTRL_HIDE,
217 session_tracking_extops, NULL,
218 parseSessionTracking, LDAP_SLIST_ENTRY_INITIALIZER(next) },
219 #endif
220 { NULL, 0, 0, NULL, 0, NULL, LDAP_SLIST_ENTRY_INITIALIZER(next) }
223 static struct slap_control *
224 find_ctrl( const char *oid );
227 * Register a supported control.
229 * This can be called by an OpenLDAP plugin or, indirectly, by a
230 * SLAPI plugin calling slapi_register_supported_control().
232 * NOTE: if flags == 1 the control is replaced if already registered;
233 * otherwise registering an already registered control is not allowed.
236 register_supported_control2(const char *controloid,
237 slap_mask_t controlmask,
238 char **controlexops,
239 SLAP_CTRL_PARSE_FN *controlparsefn,
240 unsigned flags,
241 int *controlcid)
243 struct slap_control *sc = NULL;
244 int i;
245 BerVarray extendedopsbv = NULL;
247 if ( num_known_controls >= SLAP_MAX_CIDS ) {
248 Debug( LDAP_DEBUG_ANY, "Too many controls registered."
249 " Recompile slapd with SLAP_MAX_CIDS defined > %d\n",
250 SLAP_MAX_CIDS, 0, 0 );
251 return LDAP_OTHER;
254 if ( controloid == NULL ) {
255 return LDAP_PARAM_ERROR;
258 /* check if already registered */
259 for ( i = 0; slap_known_controls[ i ]; i++ ) {
260 if ( strcmp( controloid, slap_known_controls[ i ] ) == 0 ) {
261 if ( flags == 1 ) {
262 Debug( LDAP_DEBUG_TRACE,
263 "Control %s already registered; replacing.\n",
264 controloid, 0, 0 );
265 /* (find and) replace existing handler */
266 sc = find_ctrl( controloid );
267 assert( sc != NULL );
268 break;
271 Debug( LDAP_DEBUG_ANY,
272 "Control %s already registered.\n",
273 controloid, 0, 0 );
274 return LDAP_PARAM_ERROR;
278 /* turn compatible extended operations into bervals */
279 if ( controlexops != NULL ) {
280 int i;
282 for ( i = 0; controlexops[ i ]; i++ );
284 extendedopsbv = ber_memcalloc( i + 1, sizeof( struct berval ) );
285 if ( extendedopsbv == NULL ) {
286 return LDAP_NO_MEMORY;
289 for ( i = 0; controlexops[ i ]; i++ ) {
290 ber_str2bv( controlexops[ i ], 0, 1, &extendedopsbv[ i ] );
294 if ( sc == NULL ) {
295 sc = (struct slap_control *)SLAP_MALLOC( sizeof( *sc ) );
296 if ( sc == NULL ) {
297 return LDAP_NO_MEMORY;
300 sc->sc_oid = ch_strdup( controloid );
301 sc->sc_cid = num_known_controls;
303 /* Update slap_known_controls, too. */
304 slap_known_controls[num_known_controls - 1] = sc->sc_oid;
305 slap_known_controls[num_known_controls++] = NULL;
307 LDAP_SLIST_NEXT( sc, sc_next ) = NULL;
308 LDAP_SLIST_INSERT_HEAD( &controls_list, sc, sc_next );
310 } else {
311 if ( sc->sc_extendedopsbv ) {
312 /* FIXME: in principle, we should rather merge
313 * existing extops with those supported by the
314 * new control handling implementation.
315 * In fact, whether a control is compatible with
316 * an extop should not be a matter of implementation.
317 * We likely also need a means for a newly
318 * registered extop to declare that it is
319 * comptible with an already registered control.
321 ber_bvarray_free( sc->sc_extendedopsbv );
322 sc->sc_extendedopsbv = NULL;
323 sc->sc_extendedops = NULL;
327 sc->sc_extendedopsbv = extendedopsbv;
328 sc->sc_mask = controlmask;
329 sc->sc_parse = controlparsefn;
330 if ( controlcid ) {
331 *controlcid = sc->sc_cid;
334 return LDAP_SUCCESS;
338 * One-time initialization of internal controls.
341 slap_controls_init( void )
343 int i, rc;
345 rc = LDAP_SUCCESS;
347 for ( i = 0; control_defs[i].sc_oid != NULL; i++ ) {
348 int *cid = (int *)(((char *)&slap_cids) + control_defs[i].sc_cid );
349 rc = register_supported_control( control_defs[i].sc_oid,
350 control_defs[i].sc_mask, control_defs[i].sc_extendedops,
351 control_defs[i].sc_parse, cid );
352 if ( rc != LDAP_SUCCESS ) break;
355 return rc;
359 * Free memory associated with list of supported controls.
361 void
362 controls_destroy( void )
364 struct slap_control *sc;
366 while ( !LDAP_SLIST_EMPTY(&controls_list) ) {
367 sc = LDAP_SLIST_FIRST(&controls_list);
368 LDAP_SLIST_REMOVE_HEAD(&controls_list, sc_next);
370 ch_free( sc->sc_oid );
371 if ( sc->sc_extendedopsbv != NULL ) {
372 ber_bvarray_free( sc->sc_extendedopsbv );
374 ch_free( sc );
379 * Format the supportedControl attribute of the root DSE,
380 * detailing which controls are supported by the directory
381 * server.
384 controls_root_dse_info( Entry *e )
386 AttributeDescription *ad_supportedControl
387 = slap_schema.si_ad_supportedControl;
388 struct berval vals[2];
389 struct slap_control *sc;
391 vals[1].bv_val = NULL;
392 vals[1].bv_len = 0;
394 LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
395 if( sc->sc_mask & SLAP_CTRL_HIDE ) continue;
397 vals[0].bv_val = sc->sc_oid;
398 vals[0].bv_len = strlen( sc->sc_oid );
400 if ( attr_merge( e, ad_supportedControl, vals, NULL ) ) {
401 return -1;
405 return 0;
409 * Return a list of OIDs and operation masks for supported
410 * controls. Used by SLAPI.
413 get_supported_controls(char ***ctrloidsp,
414 slap_mask_t **ctrlmasks)
416 int n;
417 char **oids;
418 slap_mask_t *masks;
419 struct slap_control *sc;
421 n = 0;
423 LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
424 n++;
427 if ( n == 0 ) {
428 *ctrloidsp = NULL;
429 *ctrlmasks = NULL;
430 return LDAP_SUCCESS;
433 oids = (char **)SLAP_MALLOC( (n + 1) * sizeof(char *) );
434 if ( oids == NULL ) {
435 return LDAP_NO_MEMORY;
437 masks = (slap_mask_t *)SLAP_MALLOC( (n + 1) * sizeof(slap_mask_t) );
438 if ( masks == NULL ) {
439 SLAP_FREE( oids );
440 return LDAP_NO_MEMORY;
443 n = 0;
445 LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
446 oids[n] = ch_strdup( sc->sc_oid );
447 masks[n] = sc->sc_mask;
448 n++;
450 oids[n] = NULL;
451 masks[n] = 0;
453 *ctrloidsp = oids;
454 *ctrlmasks = masks;
456 return LDAP_SUCCESS;
460 * Find a control given its OID.
462 static struct slap_control *
463 find_ctrl( const char *oid )
465 struct slap_control *sc;
467 LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
468 if ( strcmp( oid, sc->sc_oid ) == 0 ) {
469 return sc;
473 return NULL;
477 slap_find_control_id(
478 const char *oid,
479 int *cid )
481 struct slap_control *ctrl = find_ctrl( oid );
482 if ( ctrl ) {
483 if ( cid ) *cid = ctrl->sc_cid;
484 return LDAP_SUCCESS;
486 return LDAP_CONTROL_NOT_FOUND;
490 slap_global_control( Operation *op, const char *oid, int *cid )
492 struct slap_control *ctrl = find_ctrl( oid );
494 if ( ctrl == NULL ) {
495 /* should not be reachable */
496 Debug( LDAP_DEBUG_ANY,
497 "slap_global_control: unrecognized control: %s\n",
498 oid, 0, 0 );
499 return LDAP_CONTROL_NOT_FOUND;
502 if ( cid ) *cid = ctrl->sc_cid;
504 if ( ( ctrl->sc_mask & SLAP_CTRL_GLOBAL ) ||
505 ( ( op->o_tag & LDAP_REQ_SEARCH ) &&
506 ( ctrl->sc_mask & SLAP_CTRL_GLOBAL_SEARCH ) ) )
508 return LDAP_COMPARE_TRUE;
511 #if 0
512 Debug( LDAP_DEBUG_TRACE,
513 "slap_global_control: unavailable control: %s\n",
514 oid, 0, 0 );
515 #endif
517 return LDAP_COMPARE_FALSE;
520 void slap_free_ctrls(
521 Operation *op,
522 LDAPControl **ctrls )
524 int i;
526 for (i=0; ctrls[i]; i++) {
527 op->o_tmpfree(ctrls[i], op->o_tmpmemctx );
529 op->o_tmpfree( ctrls, op->o_tmpmemctx );
532 int slap_parse_ctrl(
533 Operation *op,
534 SlapReply *rs,
535 LDAPControl *control,
536 const char **text )
538 struct slap_control *sc;
540 sc = find_ctrl( control->ldctl_oid );
541 if( sc != NULL ) {
542 /* recognized control */
543 slap_mask_t tagmask;
544 switch( op->o_tag ) {
545 case LDAP_REQ_ADD:
546 tagmask = SLAP_CTRL_ADD;
547 break;
548 case LDAP_REQ_BIND:
549 tagmask = SLAP_CTRL_BIND;
550 break;
551 case LDAP_REQ_COMPARE:
552 tagmask = SLAP_CTRL_COMPARE;
553 break;
554 case LDAP_REQ_DELETE:
555 tagmask = SLAP_CTRL_DELETE;
556 break;
557 case LDAP_REQ_MODIFY:
558 tagmask = SLAP_CTRL_MODIFY;
559 break;
560 case LDAP_REQ_RENAME:
561 tagmask = SLAP_CTRL_RENAME;
562 break;
563 case LDAP_REQ_SEARCH:
564 tagmask = SLAP_CTRL_SEARCH;
565 break;
566 case LDAP_REQ_UNBIND:
567 tagmask = SLAP_CTRL_UNBIND;
568 break;
569 case LDAP_REQ_ABANDON:
570 tagmask = SLAP_CTRL_ABANDON;
571 break;
572 case LDAP_REQ_EXTENDED:
573 tagmask=~0L;
574 assert( op->ore_reqoid.bv_val != NULL );
575 if( sc->sc_extendedopsbv != NULL ) {
576 int i;
577 for( i=0; !BER_BVISNULL( &sc->sc_extendedopsbv[i] ); i++ ) {
578 if( bvmatch( &op->ore_reqoid,
579 &sc->sc_extendedopsbv[i] ) )
581 tagmask=0L;
582 break;
586 break;
587 default:
588 *text = "controls internal error";
589 return LDAP_OTHER;
592 if (( sc->sc_mask & tagmask ) == tagmask ) {
593 /* available extension */
594 int rc;
596 if( !sc->sc_parse ) {
597 *text = "not yet implemented";
598 return LDAP_OTHER;
601 rc = sc->sc_parse( op, rs, control );
602 if ( rc ) {
603 assert( rc != LDAP_UNAVAILABLE_CRITICAL_EXTENSION );
604 return rc;
607 } else if( control->ldctl_iscritical ) {
608 /* unavailable CRITICAL control */
609 *text = "critical extension is unavailable";
610 return LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
612 } else if( control->ldctl_iscritical ) {
613 /* unrecognized CRITICAL control */
614 *text = "critical extension is not recognized";
615 return LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
618 return LDAP_SUCCESS;
621 int get_ctrls(
622 Operation *op,
623 SlapReply *rs,
624 int sendres )
626 int nctrls = 0;
627 ber_tag_t tag;
628 ber_len_t len;
629 char *opaque;
630 BerElement *ber = op->o_ber;
631 struct berval bv;
633 len = ber_pvt_ber_remaining(ber);
635 if( len == 0) {
636 /* no controls */
637 rs->sr_err = LDAP_SUCCESS;
638 return rs->sr_err;
641 if(( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) {
642 if( tag == LBER_ERROR ) {
643 rs->sr_err = SLAPD_DISCONNECT;
644 rs->sr_text = "unexpected data in PDU";
647 goto return_results;
650 Debug( LDAP_DEBUG_TRACE,
651 "=> get_ctrls\n", 0, 0, 0 );
653 if( op->o_protocol < LDAP_VERSION3 ) {
654 rs->sr_err = SLAPD_DISCONNECT;
655 rs->sr_text = "controls require LDAPv3";
656 goto return_results;
659 /* one for first control, one for termination */
660 op->o_ctrls = op->o_tmpalloc( 2 * sizeof(LDAPControl *), op->o_tmpmemctx );
662 #if 0
663 if( op->ctrls == NULL ) {
664 rs->sr_err = LDAP_NO_MEMORY;
665 rs->sr_text = "no memory";
666 goto return_results;
668 #endif
670 op->o_ctrls[nctrls] = NULL;
672 /* step through each element */
673 for( tag = ber_first_element( ber, &len, &opaque );
674 tag != LBER_ERROR;
675 tag = ber_next_element( ber, &len, opaque ) )
677 LDAPControl *c;
678 LDAPControl **tctrls;
680 c = op->o_tmpalloc( sizeof(LDAPControl), op->o_tmpmemctx );
681 memset(c, 0, sizeof(LDAPControl));
683 /* allocate pointer space for current controls (nctrls)
684 * + this control + extra NULL
686 tctrls = op->o_tmprealloc( op->o_ctrls,
687 (nctrls+2) * sizeof(LDAPControl *), op->o_tmpmemctx );
689 #if 0
690 if( tctrls == NULL ) {
691 ch_free( c );
692 ldap_controls_free(op->o_ctrls);
693 op->o_ctrls = NULL;
695 rs->sr_err = LDAP_NO_MEMORY;
696 rs->sr_text = "no memory";
697 goto return_results;
699 #endif
700 op->o_ctrls = tctrls;
702 op->o_ctrls[nctrls++] = c;
703 op->o_ctrls[nctrls] = NULL;
705 tag = ber_scanf( ber, "{m" /*}*/, &bv );
706 c->ldctl_oid = bv.bv_val;
708 if( tag == LBER_ERROR ) {
709 Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get oid failed.\n",
710 0, 0, 0 );
712 slap_free_ctrls( op, op->o_ctrls );
713 op->o_ctrls = NULL;
714 rs->sr_err = SLAPD_DISCONNECT;
715 rs->sr_text = "decoding controls error";
716 goto return_results;
718 } else if( c->ldctl_oid == NULL ) {
719 Debug( LDAP_DEBUG_TRACE,
720 "get_ctrls: conn %lu got emtpy OID.\n",
721 op->o_connid, 0, 0 );
723 slap_free_ctrls( op, op->o_ctrls );
724 op->o_ctrls = NULL;
725 rs->sr_err = LDAP_PROTOCOL_ERROR;
726 rs->sr_text = "OID field is empty";
727 goto return_results;
730 tag = ber_peek_tag( ber, &len );
732 if( tag == LBER_BOOLEAN ) {
733 ber_int_t crit;
734 tag = ber_scanf( ber, "b", &crit );
736 if( tag == LBER_ERROR ) {
737 Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get crit failed.\n",
738 0, 0, 0 );
739 slap_free_ctrls( op, op->o_ctrls );
740 op->o_ctrls = NULL;
741 rs->sr_err = SLAPD_DISCONNECT;
742 rs->sr_text = "decoding controls error";
743 goto return_results;
746 c->ldctl_iscritical = (crit != 0);
747 tag = ber_peek_tag( ber, &len );
750 if( tag == LBER_OCTETSTRING ) {
751 tag = ber_scanf( ber, "m", &c->ldctl_value );
753 if( tag == LBER_ERROR ) {
754 Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: conn %lu: "
755 "%s (%scritical): get value failed.\n",
756 op->o_connid, c->ldctl_oid,
757 c->ldctl_iscritical ? "" : "non" );
758 slap_free_ctrls( op, op->o_ctrls );
759 op->o_ctrls = NULL;
760 rs->sr_err = SLAPD_DISCONNECT;
761 rs->sr_text = "decoding controls error";
762 goto return_results;
766 Debug( LDAP_DEBUG_TRACE,
767 "=> get_ctrls: oid=\"%s\" (%scritical)\n",
768 c->ldctl_oid, c->ldctl_iscritical ? "" : "non", 0 );
770 rs->sr_err = slap_parse_ctrl( op, rs, c, &rs->sr_text );
771 if ( rs->sr_err != LDAP_SUCCESS ) {
772 goto return_results;
776 return_results:
777 Debug( LDAP_DEBUG_TRACE,
778 "<= get_ctrls: n=%d rc=%d err=\"%s\"\n",
779 nctrls, rs->sr_err, rs->sr_text ? rs->sr_text : "");
781 if( sendres && rs->sr_err != LDAP_SUCCESS ) {
782 if( rs->sr_err == SLAPD_DISCONNECT ) {
783 rs->sr_err = LDAP_PROTOCOL_ERROR;
784 send_ldap_disconnect( op, rs );
785 rs->sr_err = SLAPD_DISCONNECT;
786 } else {
787 send_ldap_result( op, rs );
791 return rs->sr_err;
795 slap_remove_control(
796 Operation *op,
797 SlapReply *rs,
798 int ctrl,
799 BI_chk_controls fnc )
801 int i, j;
803 switch ( op->o_ctrlflag[ ctrl ] ) {
804 case SLAP_CONTROL_NONCRITICAL:
805 for ( i = 0, j = -1; op->o_ctrls[ i ] != NULL; i++ ) {
806 if ( strcmp( op->o_ctrls[ i ]->ldctl_oid,
807 slap_known_controls[ ctrl - 1 ] ) == 0 )
809 j = i;
813 if ( j == -1 ) {
814 rs->sr_err = LDAP_OTHER;
815 break;
818 if ( fnc ) {
819 (void)fnc( op, rs );
822 op->o_tmpfree( op->o_ctrls[ j ], op->o_tmpmemctx );
824 if ( i > 1 ) {
825 AC_MEMCPY( &op->o_ctrls[ j ], &op->o_ctrls[ j + 1 ],
826 ( i - j ) * sizeof( LDAPControl * ) );
828 } else {
829 op->o_tmpfree( op->o_ctrls, op->o_tmpmemctx );
830 op->o_ctrls = NULL;
833 op->o_ctrlflag[ ctrl ] = SLAP_CONTROL_IGNORED;
835 Debug( LDAP_DEBUG_ANY, "%s: "
836 "non-critical control \"%s\" not supported; stripped.\n",
837 op->o_log_prefix, slap_known_controls[ ctrl ], 0 );
838 /* fall thru */
840 case SLAP_CONTROL_IGNORED:
841 case SLAP_CONTROL_NONE:
842 rs->sr_err = SLAP_CB_CONTINUE;
843 break;
845 case SLAP_CONTROL_CRITICAL:
846 rs->sr_err = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
847 if ( fnc ) {
848 (void)fnc( op, rs );
850 Debug( LDAP_DEBUG_ANY, "%s: "
851 "critical control \"%s\" not supported.\n",
852 op->o_log_prefix, slap_known_controls[ ctrl ], 0 );
853 break;
855 default:
856 /* handle all cases! */
857 assert( 0 );
860 return rs->sr_err;
863 static int parseDontUseCopy (
864 Operation *op,
865 SlapReply *rs,
866 LDAPControl *ctrl )
868 if ( op->o_dontUseCopy != SLAP_CONTROL_NONE ) {
869 rs->sr_text = "dontUseCopy control specified multiple times";
870 return LDAP_PROTOCOL_ERROR;
873 if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
874 rs->sr_text = "dontUseCopy control value not absent";
875 return LDAP_PROTOCOL_ERROR;
878 if ( !ctrl->ldctl_iscritical ) {
879 rs->sr_text = "dontUseCopy criticality of FALSE not allowed";
880 return LDAP_PROTOCOL_ERROR;
883 op->o_dontUseCopy = SLAP_CONTROL_CRITICAL;
884 return LDAP_SUCCESS;
887 static int parseRelax (
888 Operation *op,
889 SlapReply *rs,
890 LDAPControl *ctrl )
892 if ( op->o_relax != SLAP_CONTROL_NONE ) {
893 rs->sr_text = "relax control specified multiple times";
894 return LDAP_PROTOCOL_ERROR;
897 if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
898 rs->sr_text = "relax control value not absent";
899 return LDAP_PROTOCOL_ERROR;
902 op->o_relax = ctrl->ldctl_iscritical
903 ? SLAP_CONTROL_CRITICAL
904 : SLAP_CONTROL_NONCRITICAL;
906 return LDAP_SUCCESS;
909 static int parseManageDSAit (
910 Operation *op,
911 SlapReply *rs,
912 LDAPControl *ctrl )
914 if ( op->o_managedsait != SLAP_CONTROL_NONE ) {
915 rs->sr_text = "manageDSAit control specified multiple times";
916 return LDAP_PROTOCOL_ERROR;
919 if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
920 rs->sr_text = "manageDSAit control value not absent";
921 return LDAP_PROTOCOL_ERROR;
924 op->o_managedsait = ctrl->ldctl_iscritical
925 ? SLAP_CONTROL_CRITICAL
926 : SLAP_CONTROL_NONCRITICAL;
928 return LDAP_SUCCESS;
931 static int parseProxyAuthz (
932 Operation *op,
933 SlapReply *rs,
934 LDAPControl *ctrl )
936 int rc;
937 struct berval dn = BER_BVNULL;
939 if ( op->o_proxy_authz != SLAP_CONTROL_NONE ) {
940 rs->sr_text = "proxy authorization control specified multiple times";
941 return LDAP_PROTOCOL_ERROR;
944 if ( BER_BVISNULL( &ctrl->ldctl_value )) {
945 rs->sr_text = "proxy authorization control value absent";
946 return LDAP_PROTOCOL_ERROR;
949 if ( !( global_allows & SLAP_ALLOW_PROXY_AUTHZ_ANON )
950 && BER_BVISEMPTY( &op->o_ndn ) )
952 rs->sr_text = "anonymous proxied authorization not allowed";
953 return LDAP_PROXIED_AUTHORIZATION_DENIED;
956 op->o_proxy_authz = ctrl->ldctl_iscritical
957 ? SLAP_CONTROL_CRITICAL
958 : SLAP_CONTROL_NONCRITICAL;
960 Debug( LDAP_DEBUG_ARGS,
961 "parseProxyAuthz: conn %lu authzid=\"%s\"\n",
962 op->o_connid,
963 ctrl->ldctl_value.bv_len ? ctrl->ldctl_value.bv_val : "anonymous",
964 0 );
966 if ( BER_BVISEMPTY( &ctrl->ldctl_value )) {
967 Debug( LDAP_DEBUG_TRACE,
968 "parseProxyAuthz: conn=%lu anonymous\n",
969 op->o_connid, 0, 0 );
971 /* anonymous */
972 if ( !BER_BVISNULL( &op->o_ndn ) ) {
973 op->o_ndn.bv_val[ 0 ] = '\0';
975 op->o_ndn.bv_len = 0;
977 if ( !BER_BVISNULL( &op->o_dn ) ) {
978 op->o_dn.bv_val[ 0 ] = '\0';
980 op->o_dn.bv_len = 0;
982 return LDAP_SUCCESS;
985 rc = slap_sasl_getdn( op->o_conn, op, &ctrl->ldctl_value,
986 NULL, &dn, SLAP_GETDN_AUTHZID );
988 /* FIXME: empty DN in proxyAuthz control should be legal... */
989 if( rc != LDAP_SUCCESS /* || !dn.bv_len */ ) {
990 if ( dn.bv_val ) {
991 ch_free( dn.bv_val );
993 rs->sr_text = "authzId mapping failed";
994 return LDAP_PROXIED_AUTHORIZATION_DENIED;
997 Debug( LDAP_DEBUG_TRACE,
998 "parseProxyAuthz: conn=%lu \"%s\"\n",
999 op->o_connid,
1000 dn.bv_len ? dn.bv_val : "(NULL)", 0 );
1002 rc = slap_sasl_authorized( op, &op->o_ndn, &dn );
1004 if ( rc ) {
1005 ch_free( dn.bv_val );
1006 rs->sr_text = "not authorized to assume identity";
1007 return LDAP_PROXIED_AUTHORIZATION_DENIED;
1010 ch_free( op->o_ndn.bv_val );
1011 ch_free( op->o_dn.bv_val );
1014 * NOTE: since slap_sasl_getdn() returns a normalized dn,
1015 * from now on op->o_dn is normalized
1017 op->o_ndn = dn;
1018 ber_dupbv( &op->o_dn, &dn );
1020 Statslog( LDAP_DEBUG_STATS, "%s PROXYAUTHZ dn=\"%s\"\n",
1021 op->o_log_prefix, dn.bv_val, 0, 0, 0 );
1023 return LDAP_SUCCESS;
1026 static int parseNoOp (
1027 Operation *op,
1028 SlapReply *rs,
1029 LDAPControl *ctrl )
1031 if ( op->o_noop != SLAP_CONTROL_NONE ) {
1032 rs->sr_text = "noop control specified multiple times";
1033 return LDAP_PROTOCOL_ERROR;
1036 if ( !BER_BVISNULL( &ctrl->ldctl_value ) ) {
1037 rs->sr_text = "noop control value not empty";
1038 return LDAP_PROTOCOL_ERROR;
1041 op->o_noop = ctrl->ldctl_iscritical
1042 ? SLAP_CONTROL_CRITICAL
1043 : SLAP_CONTROL_NONCRITICAL;
1045 return LDAP_SUCCESS;
1048 static int parsePagedResults (
1049 Operation *op,
1050 SlapReply *rs,
1051 LDAPControl *ctrl )
1053 BerElementBuffer berbuf;
1054 BerElement *ber = (BerElement *)&berbuf;
1055 struct berval cookie;
1056 PagedResultsState *ps;
1057 int rc = LDAP_SUCCESS;
1058 ber_tag_t tag;
1059 ber_int_t size;
1061 if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
1062 rs->sr_text = "paged results control specified multiple times";
1063 return LDAP_PROTOCOL_ERROR;
1066 if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
1067 rs->sr_text = "paged results control value is absent";
1068 return LDAP_PROTOCOL_ERROR;
1071 if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
1072 rs->sr_text = "paged results control value is empty";
1073 return LDAP_PROTOCOL_ERROR;
1076 /* Parse the control value
1077 * realSearchControlValue ::= SEQUENCE {
1078 * size INTEGER (0..maxInt),
1079 * -- requested page size from client
1080 * -- result set size estimate from server
1081 * cookie OCTET STRING
1084 ber_init2( ber, &ctrl->ldctl_value, LBER_USE_DER );
1086 tag = ber_scanf( ber, "{im}", &size, &cookie );
1088 if ( tag == LBER_ERROR ) {
1089 rs->sr_text = "paged results control could not be decoded";
1090 rc = LDAP_PROTOCOL_ERROR;
1091 goto done;
1094 if ( size < 0 ) {
1095 rs->sr_text = "paged results control size invalid";
1096 rc = LDAP_PROTOCOL_ERROR;
1097 goto done;
1100 ps = op->o_tmpalloc( sizeof(PagedResultsState), op->o_tmpmemctx );
1101 *ps = op->o_conn->c_pagedresults_state;
1102 ps->ps_size = size;
1103 ps->ps_cookieval = cookie;
1104 op->o_pagedresults_state = ps;
1105 if ( !cookie.bv_len ) {
1106 ps->ps_count = 0;
1107 ps->ps_cookie = 0;
1110 /* NOTE: according to RFC 2696 3.:
1112 If the page size is greater than or equal to the sizeLimit value, the
1113 server should ignore the control as the request can be satisfied in a
1114 single page.
1116 * NOTE: this assumes that the op->ors_slimit be set
1117 * before the controls are parsed.
1120 if ( op->ors_slimit > 0 && size >= op->ors_slimit ) {
1121 op->o_pagedresults = SLAP_CONTROL_IGNORED;
1123 } else if ( ctrl->ldctl_iscritical ) {
1124 op->o_pagedresults = SLAP_CONTROL_CRITICAL;
1126 } else {
1127 op->o_pagedresults = SLAP_CONTROL_NONCRITICAL;
1130 done:;
1131 return rc;
1134 #ifdef SLAP_CONTROL_X_SORTEDRESULTS
1135 static int parseSortedResults (
1136 Operation *op,
1137 SlapReply *rs,
1138 LDAPControl *ctrl )
1140 int rc = LDAP_SUCCESS;
1142 if ( op->o_sortedresults != SLAP_CONTROL_NONE ) {
1143 rs->sr_text = "sorted results control specified multiple times";
1144 return LDAP_PROTOCOL_ERROR;
1147 if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
1148 rs->sr_text = "sorted results control value is absent";
1149 return LDAP_PROTOCOL_ERROR;
1152 if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
1153 rs->sr_text = "sorted results control value is empty";
1154 return LDAP_PROTOCOL_ERROR;
1157 /* blow off parsing the value */
1159 op->o_sortedresults = ctrl->ldctl_iscritical
1160 ? SLAP_CONTROL_CRITICAL
1161 : SLAP_CONTROL_NONCRITICAL;
1163 return rc;
1165 #endif
1167 static int parseAssert (
1168 Operation *op,
1169 SlapReply *rs,
1170 LDAPControl *ctrl )
1172 BerElement *ber;
1173 struct berval fstr = BER_BVNULL;
1175 if ( op->o_assert != SLAP_CONTROL_NONE ) {
1176 rs->sr_text = "assert control specified multiple times";
1177 return LDAP_PROTOCOL_ERROR;
1180 if ( BER_BVISNULL( &ctrl->ldctl_value )) {
1181 rs->sr_text = "assert control value is absent";
1182 return LDAP_PROTOCOL_ERROR;
1185 if ( BER_BVISEMPTY( &ctrl->ldctl_value )) {
1186 rs->sr_text = "assert control value is empty";
1187 return LDAP_PROTOCOL_ERROR;
1190 ber = ber_init( &(ctrl->ldctl_value) );
1191 if (ber == NULL) {
1192 rs->sr_text = "assert control: internal error";
1193 return LDAP_OTHER;
1196 rs->sr_err = get_filter( op, ber, (Filter **)&(op->o_assertion),
1197 &rs->sr_text);
1198 (void) ber_free( ber, 1 );
1199 if( rs->sr_err != LDAP_SUCCESS ) {
1200 if( rs->sr_err == SLAPD_DISCONNECT ) {
1201 rs->sr_err = LDAP_PROTOCOL_ERROR;
1202 send_ldap_disconnect( op, rs );
1203 rs->sr_err = SLAPD_DISCONNECT;
1204 } else {
1205 send_ldap_result( op, rs );
1207 if( op->o_assertion != NULL ) {
1208 filter_free_x( op, op->o_assertion );
1210 return rs->sr_err;
1213 #ifdef LDAP_DEBUG
1214 filter2bv_x( op, op->o_assertion, &fstr );
1216 Debug( LDAP_DEBUG_ARGS, "parseAssert: conn %ld assert: %s\n",
1217 op->o_connid, fstr.bv_len ? fstr.bv_val : "empty" , 0 );
1218 op->o_tmpfree( fstr.bv_val, op->o_tmpmemctx );
1219 #endif
1221 op->o_assert = ctrl->ldctl_iscritical
1222 ? SLAP_CONTROL_CRITICAL
1223 : SLAP_CONTROL_NONCRITICAL;
1225 rs->sr_err = LDAP_SUCCESS;
1226 return LDAP_SUCCESS;
1229 static int parsePreRead (
1230 Operation *op,
1231 SlapReply *rs,
1232 LDAPControl *ctrl )
1234 ber_len_t siz, off, i;
1235 AttributeName *an = NULL;
1236 BerElement *ber;
1238 if ( op->o_preread != SLAP_CONTROL_NONE ) {
1239 rs->sr_text = "preread control specified multiple times";
1240 return LDAP_PROTOCOL_ERROR;
1243 if ( BER_BVISNULL( &ctrl->ldctl_value )) {
1244 rs->sr_text = "preread control value is absent";
1245 return LDAP_PROTOCOL_ERROR;
1248 if ( BER_BVISEMPTY( &ctrl->ldctl_value )) {
1249 rs->sr_text = "preread control value is empty";
1250 return LDAP_PROTOCOL_ERROR;
1253 #ifdef LDAP_X_TXN
1254 if ( op->o_txnSpec ) { /* temporary limitation */
1255 rs->sr_text = "cannot perform pre-read in transaction";
1256 return LDAP_UNWILLING_TO_PERFORM;
1258 #endif
1260 ber = ber_init( &(ctrl->ldctl_value) );
1261 if (ber == NULL) {
1262 rs->sr_text = "preread control: internal error";
1263 return LDAP_OTHER;
1266 rs->sr_err = LDAP_SUCCESS;
1268 siz = sizeof( AttributeName );
1269 off = offsetof( AttributeName, an_name );
1270 if ( ber_scanf( ber, "{M}", &an, &siz, off ) == LBER_ERROR ) {
1271 rs->sr_text = "preread control: decoding error";
1272 rs->sr_err = LDAP_PROTOCOL_ERROR;
1273 goto done;
1276 for( i=0; i<siz; i++ ) {
1277 const char *dummy = NULL;
1279 an[i].an_desc = NULL;
1280 an[i].an_oc = NULL;
1281 an[i].an_oc_exclude = 0;
1282 rs->sr_err = slap_bv2ad( &an[i].an_name, &an[i].an_desc, &dummy );
1283 if ( rs->sr_err != LDAP_SUCCESS && ctrl->ldctl_iscritical ) {
1284 rs->sr_text = dummy
1285 ? dummy
1286 : "postread control: unknown attributeType";
1287 goto done;
1291 op->o_preread = ctrl->ldctl_iscritical
1292 ? SLAP_CONTROL_CRITICAL
1293 : SLAP_CONTROL_NONCRITICAL;
1295 op->o_preread_attrs = an;
1297 done:
1298 (void) ber_free( ber, 1 );
1299 return rs->sr_err;
1302 static int parsePostRead (
1303 Operation *op,
1304 SlapReply *rs,
1305 LDAPControl *ctrl )
1307 ber_len_t siz, off, i;
1308 AttributeName *an = NULL;
1309 BerElement *ber;
1311 if ( op->o_postread != SLAP_CONTROL_NONE ) {
1312 rs->sr_text = "postread control specified multiple times";
1313 return LDAP_PROTOCOL_ERROR;
1316 if ( BER_BVISNULL( &ctrl->ldctl_value )) {
1317 rs->sr_text = "postread control value is absent";
1318 return LDAP_PROTOCOL_ERROR;
1321 if ( BER_BVISEMPTY( &ctrl->ldctl_value )) {
1322 rs->sr_text = "postread control value is empty";
1323 return LDAP_PROTOCOL_ERROR;
1326 #ifdef LDAP_X_TXN
1327 if ( op->o_txnSpec ) { /* temporary limitation */
1328 rs->sr_text = "cannot perform post-read in transaction";
1329 return LDAP_UNWILLING_TO_PERFORM;
1331 #endif
1333 ber = ber_init( &(ctrl->ldctl_value) );
1334 if (ber == NULL) {
1335 rs->sr_text = "postread control: internal error";
1336 return LDAP_OTHER;
1339 rs->sr_err = LDAP_SUCCESS;
1340 siz = sizeof( AttributeName );
1341 off = offsetof( AttributeName, an_name );
1342 if ( ber_scanf( ber, "{M}", &an, &siz, off ) == LBER_ERROR ) {
1343 rs->sr_text = "postread control: decoding error";
1344 rs->sr_err = LDAP_PROTOCOL_ERROR;
1345 goto done;
1348 for ( i = 0; i < siz; i++ ) {
1349 const char *dummy = NULL;
1350 int rc;
1352 an[i].an_desc = NULL;
1353 an[i].an_oc = NULL;
1354 an[i].an_oc_exclude = 0;
1355 rc = slap_bv2ad( &an[i].an_name, &an[i].an_desc, &dummy );
1356 if ( rc != LDAP_SUCCESS ) {
1357 int i;
1358 static struct berval special_attrs[] = {
1359 BER_BVC( LDAP_NO_ATTRS ),
1360 BER_BVC( LDAP_ALL_USER_ATTRIBUTES ),
1361 BER_BVC( LDAP_ALL_OPERATIONAL_ATTRIBUTES ),
1362 BER_BVNULL
1365 /* deal with special attribute types */
1366 for ( i = 0; !BER_BVISNULL( &special_attrs[ i ] ); i++ ) {
1367 if ( bvmatch( &an[i].an_name, &special_attrs[ i ] ) ) {
1368 break;
1372 if ( BER_BVISNULL( &special_attrs[ i ] ) && ctrl->ldctl_iscritical ) {
1373 rs->sr_err = rc;
1374 rs->sr_text = dummy
1375 ? dummy
1376 : "postread control: unknown attributeType";
1377 goto done;
1382 op->o_postread = ctrl->ldctl_iscritical
1383 ? SLAP_CONTROL_CRITICAL
1384 : SLAP_CONTROL_NONCRITICAL;
1386 op->o_postread_attrs = an;
1388 done:
1389 (void) ber_free( ber, 1 );
1390 return rs->sr_err;
1393 static int parseValuesReturnFilter (
1394 Operation *op,
1395 SlapReply *rs,
1396 LDAPControl *ctrl )
1398 BerElement *ber;
1399 struct berval fstr = BER_BVNULL;
1401 if ( op->o_valuesreturnfilter != SLAP_CONTROL_NONE ) {
1402 rs->sr_text = "valuesReturnFilter control specified multiple times";
1403 return LDAP_PROTOCOL_ERROR;
1406 if ( BER_BVISNULL( &ctrl->ldctl_value )) {
1407 rs->sr_text = "valuesReturnFilter control value is absent";
1408 return LDAP_PROTOCOL_ERROR;
1411 if ( BER_BVISEMPTY( &ctrl->ldctl_value )) {
1412 rs->sr_text = "valuesReturnFilter control value is empty";
1413 return LDAP_PROTOCOL_ERROR;
1416 ber = ber_init( &(ctrl->ldctl_value) );
1417 if (ber == NULL) {
1418 rs->sr_text = "internal error";
1419 return LDAP_OTHER;
1422 rs->sr_err = get_vrFilter( op, ber,
1423 (ValuesReturnFilter **)&(op->o_vrFilter), &rs->sr_text);
1425 (void) ber_free( ber, 1 );
1427 if( rs->sr_err != LDAP_SUCCESS ) {
1428 if( rs->sr_err == SLAPD_DISCONNECT ) {
1429 rs->sr_err = LDAP_PROTOCOL_ERROR;
1430 send_ldap_disconnect( op, rs );
1431 rs->sr_err = SLAPD_DISCONNECT;
1432 } else {
1433 send_ldap_result( op, rs );
1435 if( op->o_vrFilter != NULL) vrFilter_free( op, op->o_vrFilter );
1437 #ifdef LDAP_DEBUG
1438 else {
1439 vrFilter2bv( op, op->o_vrFilter, &fstr );
1442 Debug( LDAP_DEBUG_ARGS, " vrFilter: %s\n",
1443 fstr.bv_len ? fstr.bv_val : "empty", 0, 0 );
1444 op->o_tmpfree( fstr.bv_val, op->o_tmpmemctx );
1445 #endif
1447 op->o_valuesreturnfilter = ctrl->ldctl_iscritical
1448 ? SLAP_CONTROL_CRITICAL
1449 : SLAP_CONTROL_NONCRITICAL;
1451 rs->sr_err = LDAP_SUCCESS;
1452 return LDAP_SUCCESS;
1455 static int parseSubentries (
1456 Operation *op,
1457 SlapReply *rs,
1458 LDAPControl *ctrl )
1460 if ( op->o_subentries != SLAP_CONTROL_NONE ) {
1461 rs->sr_text = "subentries control specified multiple times";
1462 return LDAP_PROTOCOL_ERROR;
1465 /* FIXME: should use BER library */
1466 if( ( ctrl->ldctl_value.bv_len != 3 )
1467 || ( ctrl->ldctl_value.bv_val[0] != 0x01 )
1468 || ( ctrl->ldctl_value.bv_val[1] != 0x01 ))
1470 rs->sr_text = "subentries control value encoding is bogus";
1471 return LDAP_PROTOCOL_ERROR;
1474 op->o_subentries = ctrl->ldctl_iscritical
1475 ? SLAP_CONTROL_CRITICAL
1476 : SLAP_CONTROL_NONCRITICAL;
1478 if (ctrl->ldctl_value.bv_val[2]) {
1479 set_subentries_visibility( op );
1482 return LDAP_SUCCESS;
1485 static int parsePermissiveModify (
1486 Operation *op,
1487 SlapReply *rs,
1488 LDAPControl *ctrl )
1490 if ( op->o_permissive_modify != SLAP_CONTROL_NONE ) {
1491 rs->sr_text = "permissiveModify control specified multiple times";
1492 return LDAP_PROTOCOL_ERROR;
1495 if ( BER_BVISNULL( &ctrl->ldctl_value )) {
1496 rs->sr_text = "permissiveModify control value not absent";
1497 return LDAP_PROTOCOL_ERROR;
1500 op->o_permissive_modify = ctrl->ldctl_iscritical
1501 ? SLAP_CONTROL_CRITICAL
1502 : SLAP_CONTROL_NONCRITICAL;
1504 return LDAP_SUCCESS;
1507 static int parseDomainScope (
1508 Operation *op,
1509 SlapReply *rs,
1510 LDAPControl *ctrl )
1512 if ( op->o_domain_scope != SLAP_CONTROL_NONE ) {
1513 rs->sr_text = "domainScope control specified multiple times";
1514 return LDAP_PROTOCOL_ERROR;
1517 if ( BER_BVISNULL( &ctrl->ldctl_value )) {
1518 rs->sr_text = "domainScope control value not empty";
1519 return LDAP_PROTOCOL_ERROR;
1522 op->o_domain_scope = ctrl->ldctl_iscritical
1523 ? SLAP_CONTROL_CRITICAL
1524 : SLAP_CONTROL_NONCRITICAL;
1526 return LDAP_SUCCESS;
1529 #ifdef SLAP_CONTROL_X_TREE_DELETE
1530 static int parseTreeDelete (
1531 Operation *op,
1532 SlapReply *rs,
1533 LDAPControl *ctrl )
1535 if ( op->o_tree_delete != SLAP_CONTROL_NONE ) {
1536 rs->sr_text = "treeDelete control specified multiple times";
1537 return LDAP_PROTOCOL_ERROR;
1540 if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
1541 rs->sr_text = "treeDelete control value not absent";
1542 return LDAP_PROTOCOL_ERROR;
1545 op->o_tree_delete = ctrl->ldctl_iscritical
1546 ? SLAP_CONTROL_CRITICAL
1547 : SLAP_CONTROL_NONCRITICAL;
1549 return LDAP_SUCCESS;
1551 #endif
1553 static int parseSearchOptions (
1554 Operation *op,
1555 SlapReply *rs,
1556 LDAPControl *ctrl )
1558 BerElement *ber;
1559 ber_int_t search_flags;
1560 ber_tag_t tag;
1562 if ( BER_BVISNULL( &ctrl->ldctl_value )) {
1563 rs->sr_text = "searchOptions control value is absent";
1564 return LDAP_PROTOCOL_ERROR;
1567 if ( BER_BVISEMPTY( &ctrl->ldctl_value )) {
1568 rs->sr_text = "searchOptions control value is empty";
1569 return LDAP_PROTOCOL_ERROR;
1572 ber = ber_init( &ctrl->ldctl_value );
1573 if( ber == NULL ) {
1574 rs->sr_text = "internal error";
1575 return LDAP_OTHER;
1578 tag = ber_scanf( ber, "{i}", &search_flags );
1579 (void) ber_free( ber, 1 );
1581 if ( tag == LBER_ERROR ) {
1582 rs->sr_text = "searchOptions control decoding error";
1583 return LDAP_PROTOCOL_ERROR;
1586 if ( search_flags & LDAP_SEARCH_FLAG_DOMAIN_SCOPE ) {
1587 if ( op->o_domain_scope != SLAP_CONTROL_NONE ) {
1588 rs->sr_text = "searchOptions control specified multiple times "
1589 "or with domainScope control";
1590 return LDAP_PROTOCOL_ERROR;
1593 op->o_domain_scope = ctrl->ldctl_iscritical
1594 ? SLAP_CONTROL_CRITICAL
1595 : SLAP_CONTROL_NONCRITICAL;
1598 if ( search_flags & ~(LDAP_SEARCH_FLAG_DOMAIN_SCOPE) ) {
1599 /* Other search flags not recognised so far,
1600 * including:
1601 * LDAP_SEARCH_FLAG_PHANTOM_ROOM
1603 rs->sr_text = "searchOptions contained unrecognized flag";
1604 return LDAP_UNWILLING_TO_PERFORM;
1607 return LDAP_SUCCESS;
1610 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
1611 struct berval session_tracking_formats[] = {
1612 BER_BVC( LDAP_CONTROL_X_SESSION_TRACKING_RADIUS_ACCT_SESSION_ID ),
1613 BER_BVC( "RADIUS-Acct-Session-Id" ),
1614 BER_BVC( LDAP_CONTROL_X_SESSION_TRACKING_RADIUS_ACCT_MULTI_SESSION_ID ),
1615 BER_BVC( "RADIUS-Acct-Multi-Session-Id" ),
1616 BER_BVC( LDAP_CONTROL_X_SESSION_TRACKING_USERNAME ),
1617 BER_BVC( "USERNAME" ),
1619 BER_BVNULL
1622 static int parseSessionTracking(
1623 Operation *op,
1624 SlapReply *rs,
1625 LDAPControl *ctrl )
1627 BerElement *ber;
1628 ber_tag_t tag;
1629 ber_len_t len;
1630 int i, rc;
1632 struct berval sessionSourceIp = BER_BVNULL,
1633 sessionSourceName = BER_BVNULL,
1634 formatOID = BER_BVNULL,
1635 sessionTrackingIdentifier = BER_BVNULL;
1637 size_t st_len, st_pos;
1639 if ( ctrl->ldctl_iscritical ) {
1640 rs->sr_text = "sessionTracking criticality is TRUE";
1641 return LDAP_PROTOCOL_ERROR;
1644 if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
1645 rs->sr_text = "sessionTracking control value is absent";
1646 return LDAP_PROTOCOL_ERROR;
1649 if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
1650 rs->sr_text = "sessionTracking control value is empty";
1651 return LDAP_PROTOCOL_ERROR;
1654 /* TODO: add the capability to determine if a client is allowed
1655 * to use this control, based on identity, ip and so */
1657 ber = ber_init( &ctrl->ldctl_value );
1658 if ( ber == NULL ) {
1659 rs->sr_text = "internal error";
1660 return LDAP_OTHER;
1663 tag = ber_skip_tag( ber, &len );
1664 if ( tag != LBER_SEQUENCE ) {
1665 tag = LBER_ERROR;
1666 goto error;
1669 /* sessionSourceIp */
1670 tag = ber_peek_tag( ber, &len );
1671 if ( tag == LBER_DEFAULT ) {
1672 tag = LBER_ERROR;
1673 goto error;
1676 if ( len == 0 ) {
1677 tag = ber_skip_tag( ber, &len );
1679 } else if ( len > 128 ) {
1680 rs->sr_text = "sessionTracking.sessionSourceIp too long";
1681 rs->sr_err = LDAP_PROTOCOL_ERROR;
1682 goto error;
1684 } else {
1685 tag = ber_scanf( ber, "m", &sessionSourceIp );
1688 if ( ldif_is_not_printable( sessionSourceIp.bv_val, sessionSourceIp.bv_len ) ) {
1689 BER_BVZERO( &sessionSourceIp );
1692 /* sessionSourceName */
1693 tag = ber_peek_tag( ber, &len );
1694 if ( tag == LBER_DEFAULT ) {
1695 tag = LBER_ERROR;
1696 goto error;
1699 if ( len == 0 ) {
1700 tag = ber_skip_tag( ber, &len );
1702 } else if ( len > 65536 ) {
1703 rs->sr_text = "sessionTracking.sessionSourceName too long";
1704 rs->sr_err = LDAP_PROTOCOL_ERROR;
1705 goto error;
1707 } else {
1708 tag = ber_scanf( ber, "m", &sessionSourceName );
1711 if ( ldif_is_not_printable( sessionSourceName.bv_val, sessionSourceName.bv_len ) ) {
1712 BER_BVZERO( &sessionSourceName );
1715 /* formatOID */
1716 tag = ber_peek_tag( ber, &len );
1717 if ( tag == LBER_DEFAULT ) {
1718 tag = LBER_ERROR;
1719 goto error;
1722 if ( len == 0 ) {
1723 rs->sr_text = "sessionTracking.formatOID empty";
1724 rs->sr_err = LDAP_PROTOCOL_ERROR;
1725 goto error;
1727 } else if ( len > 1024 ) {
1728 rs->sr_text = "sessionTracking.formatOID too long";
1729 rs->sr_err = LDAP_PROTOCOL_ERROR;
1730 goto error;
1732 } else {
1733 tag = ber_scanf( ber, "m", &formatOID );
1736 rc = numericoidValidate( NULL, &formatOID );
1737 if ( rc != LDAP_SUCCESS ) {
1738 rs->sr_text = "sessionTracking.formatOID invalid";
1739 goto error;
1742 for ( i = 0; !BER_BVISNULL( &session_tracking_formats[ i ] ); i += 2 )
1744 if ( bvmatch( &formatOID, &session_tracking_formats[ i ] ) ) {
1745 formatOID = session_tracking_formats[ i + 1 ];
1746 break;
1750 /* sessionTrackingIdentifier */
1751 tag = ber_peek_tag( ber, &len );
1752 if ( tag == LBER_DEFAULT ) {
1753 tag = LBER_ERROR;
1754 goto error;
1757 if ( len == 0 ) {
1758 tag = ber_skip_tag( ber, &len );
1760 } else {
1761 /* note: should not be more than 65536... */
1762 tag = ber_scanf( ber, "m", &sessionTrackingIdentifier );
1763 if ( ldif_is_not_printable( sessionTrackingIdentifier.bv_val, sessionTrackingIdentifier.bv_len ) ) {
1764 /* we want the OID printed, at least */
1765 BER_BVSTR( &sessionTrackingIdentifier, "" );
1769 /* closure */
1770 tag = ber_skip_tag( ber, &len );
1771 if ( tag != LBER_DEFAULT || len != 0 ) {
1772 tag = LBER_ERROR;
1773 goto error;
1775 tag = 0;
1777 st_len = 0;
1778 if ( !BER_BVISNULL( &sessionSourceIp ) ) {
1779 st_len += STRLENOF( "IP=" ) + sessionSourceIp.bv_len;
1781 if ( !BER_BVISNULL( &sessionSourceName ) ) {
1782 if ( st_len ) st_len++;
1783 st_len += STRLENOF( "NAME=" ) + sessionSourceName.bv_len;
1785 if ( !BER_BVISNULL( &sessionTrackingIdentifier ) ) {
1786 if ( st_len ) st_len++;
1787 st_len += formatOID.bv_len + STRLENOF( "=" )
1788 + sessionTrackingIdentifier.bv_len;
1791 if ( st_len == 0 ) {
1792 goto error;
1795 st_len += STRLENOF( " []" );
1796 st_pos = strlen( op->o_log_prefix );
1798 if ( sizeof( op->o_log_prefix ) - st_pos > st_len ) {
1799 char *ptr = &op->o_log_prefix[ st_pos ];
1801 ptr = lutil_strcopy( ptr, " [" /*]*/ );
1803 st_len = 0;
1804 if ( !BER_BVISNULL( &sessionSourceIp ) ) {
1805 ptr = lutil_strcopy( ptr, "IP=" );
1806 ptr = lutil_strcopy( ptr, sessionSourceIp.bv_val );
1807 st_len++;
1810 if ( !BER_BVISNULL( &sessionSourceName ) ) {
1811 if ( st_len ) *ptr++ = ' ';
1812 ptr = lutil_strcopy( ptr, "NAME=" );
1813 ptr = lutil_strcopy( ptr, sessionSourceName.bv_val );
1814 st_len++;
1817 if ( !BER_BVISNULL( &sessionTrackingIdentifier ) ) {
1818 if ( st_len ) *ptr++ = ' ';
1819 ptr = lutil_strcopy( ptr, formatOID.bv_val );
1820 *ptr++ = '=';
1821 ptr = lutil_strcopy( ptr, sessionTrackingIdentifier.bv_val );
1824 *ptr++ = /*[*/ ']';
1825 *ptr = '\0';
1828 error:;
1829 (void)ber_free( ber, 1 );
1831 if ( tag == LBER_ERROR ) {
1832 rs->sr_text = "sessionTracking control decoding error";
1833 return LDAP_PROTOCOL_ERROR;
1837 return rs->sr_err;
1841 slap_ctrl_session_tracking_add(
1842 Operation *op,
1843 SlapReply *rs,
1844 struct berval *ip,
1845 struct berval *name,
1846 struct berval *id,
1847 LDAPControl *ctrl )
1849 BerElementBuffer berbuf;
1850 BerElement *ber = (BerElement *)&berbuf;
1852 static struct berval oid = BER_BVC( LDAP_CONTROL_X_SESSION_TRACKING_USERNAME );
1854 assert( ctrl != NULL );
1856 ber_init2( ber, NULL, LBER_USE_DER );
1858 ber_printf( ber, "{OOOO}", ip, name, &oid, id );
1860 if ( ber_flatten2( ber, &ctrl->ldctl_value, 0 ) == -1 ) {
1861 rs->sr_err = LDAP_OTHER;
1862 goto done;
1865 ctrl->ldctl_oid = LDAP_CONTROL_X_SESSION_TRACKING;
1866 ctrl->ldctl_iscritical = 0;
1868 rs->sr_err = LDAP_SUCCESS;
1870 done:;
1871 return rs->sr_err;
1875 slap_ctrl_session_tracking_request_add( Operation *op, SlapReply *rs, LDAPControl *ctrl )
1877 static struct berval bv_unknown = BER_BVC( SLAP_STRING_UNKNOWN );
1878 struct berval ip = BER_BVNULL,
1879 name = BER_BVNULL,
1880 id = BER_BVNULL;
1882 if ( !BER_BVISNULL( &op->o_conn->c_peer_name ) &&
1883 memcmp( op->o_conn->c_peer_name.bv_val, "IP=", STRLENOF( "IP=" ) ) == 0 )
1885 char *ptr;
1887 ip.bv_val = op->o_conn->c_peer_name.bv_val + STRLENOF( "IP=" );
1888 ip.bv_len = op->o_conn->c_peer_name.bv_len - STRLENOF( "IP=" );
1890 ptr = ber_bvchr( &ip, ':' );
1891 if ( ptr ) {
1892 ip.bv_len = ptr - ip.bv_val;
1896 if ( !BER_BVISNULL( &op->o_conn->c_peer_domain ) &&
1897 !bvmatch( &op->o_conn->c_peer_domain, &bv_unknown ) )
1899 name = op->o_conn->c_peer_domain;
1902 if ( !BER_BVISNULL( &op->o_dn ) && !BER_BVISEMPTY( &op->o_dn ) ) {
1903 id = op->o_dn;
1906 return slap_ctrl_session_tracking_add( op, rs, &ip, &name, &id, ctrl );
1908 #endif