]> git.sur5r.net Git - openldap/blob - servers/slapd/controls.c
Sync with HEAD
[openldap] / servers / slapd / controls.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2006 The OpenLDAP Foundation.
5  * All rights reserved.
6  *
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.
10  *
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>.
14  */
15
16 #include "portable.h"
17
18 #include <stdio.h>
19
20 #include <ac/string.h>
21 #include <ac/socket.h>
22
23 #include "slap.h"
24
25 #include "../../libraries/liblber/lber-int.h"
26
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;
31 #ifdef LDAP_DEVEL
32 static SLAP_CTRL_PARSE_FN parseDontUseCopy;
33 static SLAP_CTRL_PARSE_FN parseManageDIT;
34 #endif
35 static SLAP_CTRL_PARSE_FN parseManageDSAit;
36 static SLAP_CTRL_PARSE_FN parseNoOp;
37 static SLAP_CTRL_PARSE_FN parsePagedResults;
38 #ifdef LDAP_DEVEL
39 static SLAP_CTRL_PARSE_FN parseSortedResults;
40 #endif
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;
46 #endif
47 static SLAP_CTRL_PARSE_FN parseSearchOptions;
48 static SLAP_CTRL_PARSE_FN parseSubentries;
49
50 #undef sc_mask /* avoid conflict with Irix 6.5 <sys/signal.h> */
51
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);
54
55 struct slap_control_ids slap_cids;
56
57 struct slap_control {
58         /* Control OID */
59         char *sc_oid;
60
61         /* The controlID for this control */
62         int sc_cid;
63
64         /* Operations supported by control */
65         slap_mask_t sc_mask;
66
67         /* Extended operations supported by control */
68         char **sc_extendedops;
69
70         /* Control parsing callback */
71         SLAP_CTRL_PARSE_FN *sc_parse;
72
73         LDAP_SLIST_ENTRY(slap_control) sc_next;
74 };
75
76 static LDAP_SLIST_HEAD(ControlsList, slap_control) controls_list
77         = LDAP_SLIST_HEAD_INITIALIZER(&controls_list);
78
79 /*
80  * all known request control OIDs should be added to this list
81  */
82 /*
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 
90  * starting from 1.
91  * FIXME: should we define the "undefined control" oid?
92  */
93 char *slap_known_controls[SLAP_MAX_CIDS+1];
94 static int num_known_controls = 1;
95
96 static char *proxy_authz_extops[] = {
97         LDAP_EXOP_MODIFY_PASSWD,
98         LDAP_EXOP_X_WHO_AM_I,
99         NULL
100 };
101
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         { LDAP_CONTROL_PAGEDRESULTS,
121                 (int)offsetof(struct slap_control_ids, sc_pagedResults),
122                 SLAP_CTRL_SEARCH, NULL,
123                 parsePagedResults, LDAP_SLIST_ENTRY_INITIALIZER(next) },
124 #ifdef LDAP_DEVEL
125         { LDAP_CONTROL_SORTREQUEST,
126                 (int)offsetof(struct slap_control_ids, sc_sortedResults),
127                 SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH|SLAP_CTRL_HIDE, NULL,
128                 parseSortedResults, LDAP_SLIST_ENTRY_INITIALIZER(next) },
129 #endif
130         { LDAP_CONTROL_X_DOMAIN_SCOPE,
131                 (int)offsetof(struct slap_control_ids, sc_domainScope),
132                 SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH|SLAP_CTRL_HIDE, NULL,
133                 parseDomainScope, LDAP_SLIST_ENTRY_INITIALIZER(next) },
134         { LDAP_CONTROL_X_PERMISSIVE_MODIFY,
135                 (int)offsetof(struct slap_control_ids, sc_permissiveModify),
136                 SLAP_CTRL_MODIFY|SLAP_CTRL_HIDE, NULL,
137                 parsePermissiveModify, LDAP_SLIST_ENTRY_INITIALIZER(next) },
138 #ifdef SLAP_CONTROL_X_TREE_DELETE
139         { LDAP_CONTROL_X_TREE_DELETE,
140                 (int)offsetof(struct slap_control_ids, sc_treeDelete),
141                 SLAP_CTRL_DELETE|SLAP_CTRL_HIDE, NULL,
142                 parseTreeDelete, LDAP_SLIST_ENTRY_INITIALIZER(next) },
143 #endif
144         { LDAP_CONTROL_X_SEARCH_OPTIONS,
145                 (int)offsetof(struct slap_control_ids, sc_searchOptions),
146                 SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH|SLAP_CTRL_HIDE, NULL,
147                 parseSearchOptions, LDAP_SLIST_ENTRY_INITIALIZER(next) },
148         { LDAP_CONTROL_SUBENTRIES,
149                 (int)offsetof(struct slap_control_ids, sc_subentries),
150                 SLAP_CTRL_SEARCH, NULL,
151                 parseSubentries, LDAP_SLIST_ENTRY_INITIALIZER(next) },
152         { LDAP_CONTROL_NOOP,
153                 (int)offsetof(struct slap_control_ids, sc_noOp),
154                 SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, NULL,
155                 parseNoOp, LDAP_SLIST_ENTRY_INITIALIZER(next) },
156 #ifdef LDAP_DEVEL
157         { LDAP_CONTROL_DONTUSECOPY,
158                 (int)offsetof(struct slap_control_ids, sc_dontUseCopy),
159                 SLAP_CTRL_INTROGATE|SLAP_CTRL_HIDE, NULL,
160                 parseDontUseCopy, LDAP_SLIST_ENTRY_INITIALIZER(next) },
161         { LDAP_CONTROL_MANAGEDIT,
162                 (int)offsetof(struct slap_control_ids, sc_manageDIT),
163                 SLAP_CTRL_GLOBAL|SLAP_CTRL_UPDATE|SLAP_CTRL_HIDE, NULL,
164                 parseManageDIT, LDAP_SLIST_ENTRY_INITIALIZER(next) },
165 #endif
166         { LDAP_CONTROL_MANAGEDSAIT,
167                 (int)offsetof(struct slap_control_ids, sc_manageDSAit),
168                 SLAP_CTRL_ACCESS, NULL,
169                 parseManageDSAit, LDAP_SLIST_ENTRY_INITIALIZER(next) },
170         { LDAP_CONTROL_PROXY_AUTHZ,
171                 (int)offsetof(struct slap_control_ids, sc_proxyAuthz),
172                 SLAP_CTRL_GLOBAL|SLAP_CTRL_ACCESS, proxy_authz_extops,
173                 parseProxyAuthz, LDAP_SLIST_ENTRY_INITIALIZER(next) },
174         { NULL, 0, 0, NULL, 0, LDAP_SLIST_ENTRY_INITIALIZER(next) }
175 };
176
177 /*
178  * Register a supported control.
179  *
180  * This can be called by an OpenLDAP plugin or, indirectly, by a
181  * SLAPI plugin calling slapi_register_supported_control().
182  */
183 int
184 register_supported_control(const char *controloid,
185         slap_mask_t controlmask,
186         char **controlexops,
187         SLAP_CTRL_PARSE_FN *controlparsefn,
188         int *controlcid)
189 {
190         struct slap_control *sc;
191         int i;
192
193         if ( num_known_controls >= SLAP_MAX_CIDS ) {
194                 Debug( LDAP_DEBUG_ANY, "Too many controls registered."
195                         " Recompile slapd with SLAP_MAX_CIDS defined > %d\n",
196                 SLAP_MAX_CIDS, 0, 0 );
197                 return LDAP_OTHER;
198         }
199
200         if ( controloid == NULL ) return LDAP_PARAM_ERROR;
201
202         /* sanity check - should never happen */
203         for ( i = 0; slap_known_controls[ i ]; i++ ) {
204                 if ( strcmp( controloid, slap_known_controls[ i ] ) == 0 ) {
205                         Debug( LDAP_DEBUG_ANY,
206                                 "Control %s already registered.\n",
207                                 controloid, 0, 0 );
208                         return LDAP_PARAM_ERROR;
209                 }
210         }
211
212         sc = (struct slap_control *)SLAP_MALLOC( sizeof( *sc ) );
213         if ( sc == NULL ) return LDAP_NO_MEMORY;
214
215         sc->sc_oid = ch_strdup( controloid );
216         sc->sc_mask = controlmask;
217         if ( controlexops != NULL ) {
218                 sc->sc_extendedops = ldap_charray_dup( controlexops );
219                 if ( sc->sc_extendedops == NULL ) {
220                         ch_free( sc );
221                         return LDAP_NO_MEMORY;
222                 }
223         } else {
224                 sc->sc_extendedops = NULL;
225         }
226         sc->sc_parse = controlparsefn;
227
228         if ( controlcid ) *controlcid = num_known_controls;
229         sc->sc_cid = num_known_controls;
230
231         /* Update slap_known_controls, too. */
232         slap_known_controls[num_known_controls-1] = sc->sc_oid;
233         slap_known_controls[num_known_controls++] = NULL;
234
235         LDAP_SLIST_NEXT( sc, sc_next ) = NULL;
236         LDAP_SLIST_INSERT_HEAD( &controls_list, sc, sc_next );
237         return LDAP_SUCCESS;
238 }
239
240 /*
241  * One-time initialization of internal controls.
242  */
243 int
244 slap_controls_init( void )
245 {
246         int i, rc;
247
248         rc = LDAP_SUCCESS;
249
250         for ( i = 0; control_defs[i].sc_oid != NULL; i++ ) {
251                 int *cid = (int *)(((char *)&slap_cids) + control_defs[i].sc_cid );
252                 rc = register_supported_control( control_defs[i].sc_oid,
253                         control_defs[i].sc_mask, control_defs[i].sc_extendedops,
254                         control_defs[i].sc_parse, cid );
255                 if ( rc != LDAP_SUCCESS ) break;
256         }
257
258         return rc;
259 }
260
261 /*
262  * Free memory associated with list of supported controls.
263  */
264 void
265 controls_destroy( void )
266 {
267         struct slap_control *sc;
268
269         while ( !LDAP_SLIST_EMPTY(&controls_list) ) {
270                 sc = LDAP_SLIST_FIRST(&controls_list);
271                 LDAP_SLIST_REMOVE_HEAD(&controls_list, sc_next);
272
273                 ch_free( sc->sc_oid );
274                 if ( sc->sc_extendedops != NULL ) {
275                         ldap_charray_free( sc->sc_extendedops );
276                 }
277                 ch_free( sc );
278         }
279 }
280
281 /*
282  * Format the supportedControl attribute of the root DSE,
283  * detailing which controls are supported by the directory
284  * server.
285  */
286 int
287 controls_root_dse_info( Entry *e )
288 {
289         AttributeDescription *ad_supportedControl
290                 = slap_schema.si_ad_supportedControl;
291         struct berval vals[2];
292         struct slap_control *sc;
293
294         vals[1].bv_val = NULL;
295         vals[1].bv_len = 0;
296
297         LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
298                 if( sc->sc_mask & SLAP_CTRL_HIDE ) continue;
299
300                 vals[0].bv_val = sc->sc_oid;
301                 vals[0].bv_len = strlen( sc->sc_oid );
302
303                 if ( attr_merge( e, ad_supportedControl, vals, NULL ) ) {
304                         return -1;
305                 }
306         }
307
308         return 0;
309 }
310
311 /*
312  * Return a list of OIDs and operation masks for supported
313  * controls. Used by SLAPI.
314  */
315 int
316 get_supported_controls(char ***ctrloidsp,
317         slap_mask_t **ctrlmasks)
318 {
319         int n;
320         char **oids;
321         slap_mask_t *masks;
322         struct slap_control *sc;
323
324         n = 0;
325
326         LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
327                 n++;
328         }
329
330         if ( n == 0 ) {
331                 *ctrloidsp = NULL;
332                 *ctrlmasks = NULL;
333                 return LDAP_SUCCESS;
334         }
335
336         oids = (char **)SLAP_MALLOC( (n + 1) * sizeof(char *) );
337         if ( oids == NULL ) {
338                 return LDAP_NO_MEMORY;
339         }
340         masks = (slap_mask_t *)SLAP_MALLOC( (n + 1) * sizeof(slap_mask_t) );
341         if  ( masks == NULL ) {
342                 ch_free( oids );
343                 return LDAP_NO_MEMORY;
344         }
345
346         n = 0;
347
348         LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
349                 oids[n] = ch_strdup( sc->sc_oid );
350                 masks[n] = sc->sc_mask;
351                 n++;
352         }
353         oids[n] = NULL;
354         masks[n] = 0;
355
356         *ctrloidsp = oids;
357         *ctrlmasks = masks;
358
359         return LDAP_SUCCESS;
360 }
361
362 /*
363  * Find a control given its OID.
364  */
365 static struct slap_control *
366 find_ctrl( const char *oid )
367 {
368         struct slap_control *sc;
369
370         LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
371                 if ( strcmp( oid, sc->sc_oid ) == 0 ) {
372                         return sc;
373                 }
374         }
375
376         return NULL;
377 }
378
379 int
380 slap_find_control_id(
381         const char *oid,
382         int *cid )
383 {
384         struct slap_control *ctrl = find_ctrl( oid );
385         if ( ctrl ) {
386                 if ( cid ) *cid = ctrl->sc_cid;
387                 return LDAP_SUCCESS;
388         }
389         return LDAP_CONTROL_NOT_FOUND;
390 }
391
392 int
393 slap_global_control( Operation *op, const char *oid, int *cid )
394 {
395         struct slap_control *ctrl = find_ctrl( oid );
396
397         if ( ctrl == NULL ) {
398                 /* should not be reachable */
399                 Debug( LDAP_DEBUG_ANY,
400                         "slap_global_control: unrecognized control: %s\n",      
401                         oid, 0, 0 );
402                 return LDAP_CONTROL_NOT_FOUND;
403         }
404
405         if ( cid ) *cid = ctrl->sc_cid;
406
407         if ( ( ctrl->sc_mask & SLAP_CTRL_GLOBAL ) ||
408                 ( ( op->o_tag & LDAP_REQ_SEARCH ) &&
409                 ( ctrl->sc_mask & SLAP_CTRL_GLOBAL_SEARCH ) ) )
410         {
411                 return LDAP_COMPARE_TRUE;
412         }
413
414         Debug( LDAP_DEBUG_TRACE,
415                 "slap_global_control: unavailable control: %s\n",      
416                 oid, 0, 0 );
417
418         return LDAP_COMPARE_FALSE;
419 }
420
421 void slap_free_ctrls(
422         Operation *op,
423         LDAPControl **ctrls )
424 {
425         int i;
426
427         for (i=0; ctrls[i]; i++) {
428                 op->o_tmpfree(ctrls[i], op->o_tmpmemctx );
429         }
430         op->o_tmpfree( ctrls, op->o_tmpmemctx );
431 }
432
433 int slap_parse_ctrl(
434         Operation *op,
435         SlapReply *rs,
436         LDAPControl *control,
437         const char **text )
438 {
439         struct slap_control *sc;
440
441         sc = find_ctrl( control->ldctl_oid );
442         if( sc != NULL ) {
443                 /* recognized control */
444                 slap_mask_t tagmask;
445                 switch( op->o_tag ) {
446                 case LDAP_REQ_ADD:
447                         tagmask = SLAP_CTRL_ADD;
448                         break;
449                 case LDAP_REQ_BIND:
450                         tagmask = SLAP_CTRL_BIND;
451                         break;
452                 case LDAP_REQ_COMPARE:
453                         tagmask = SLAP_CTRL_COMPARE;
454                         break;
455                 case LDAP_REQ_DELETE:
456                         tagmask = SLAP_CTRL_DELETE;
457                         break;
458                 case LDAP_REQ_MODIFY:
459                         tagmask = SLAP_CTRL_MODIFY;
460                         break;
461                 case LDAP_REQ_RENAME:
462                         tagmask = SLAP_CTRL_RENAME;
463                         break;
464                 case LDAP_REQ_SEARCH:
465                         tagmask = SLAP_CTRL_SEARCH;
466                         break;
467                 case LDAP_REQ_UNBIND:
468                         tagmask = SLAP_CTRL_UNBIND;
469                         break;
470                 case LDAP_REQ_ABANDON:
471                         tagmask = SLAP_CTRL_ABANDON;
472                         break;
473                 case LDAP_REQ_EXTENDED:
474                         tagmask=~0L;
475                         assert( op->ore_reqoid.bv_val != NULL );
476                         if( sc->sc_extendedops != NULL ) {
477                                 int i;
478                                 for( i=0; sc->sc_extendedops[i] != NULL; i++ ) {
479                                         if( strcmp( op->ore_reqoid.bv_val,
480                                                 sc->sc_extendedops[i] ) == 0 )
481                                         {
482                                                 tagmask=0L;
483                                                 break;
484                                         }
485                                 }
486                         }
487                         break;
488                 default:
489                         *text = "controls internal error";
490                         return LDAP_OTHER;
491                 }
492
493                 if (( sc->sc_mask & tagmask ) == tagmask ) {
494                         /* available extension */
495                         int     rc;
496
497                         if( !sc->sc_parse ) {
498                                 *text = "not yet implemented";
499                                 return LDAP_OTHER;
500                         }
501
502                         rc = sc->sc_parse( op, rs, control );
503                         if ( rc ) {
504                                 assert( rc != LDAP_UNAVAILABLE_CRITICAL_EXTENSION );
505                                 return rc;
506                         }
507
508                 } else if( control->ldctl_iscritical ) {
509                         /* unavailable CRITICAL control */
510                         *text = "critical extension is unavailable";
511                         return LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
512                 }
513         } else if( control->ldctl_iscritical ) {
514                 /* unrecognized CRITICAL control */
515                 *text = "critical extension is not recognized";
516                 return LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
517         }
518
519         return LDAP_SUCCESS;
520 }
521
522 int get_ctrls(
523         Operation *op,
524         SlapReply *rs,
525         int sendres )
526 {
527         int nctrls = 0;
528         ber_tag_t tag;
529         ber_len_t len;
530         char *opaque;
531         BerElement *ber = op->o_ber;
532         struct berval bv;
533
534         len = ber_pvt_ber_remaining(ber);
535
536         if( len == 0) {
537                 /* no controls */
538                 rs->sr_err = LDAP_SUCCESS;
539                 return rs->sr_err;
540         }
541
542         if(( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) {
543                 if( tag == LBER_ERROR ) {
544                         rs->sr_err = SLAPD_DISCONNECT;
545                         rs->sr_text = "unexpected data in PDU";
546                 }
547
548                 goto return_results;
549         }
550
551         Debug( LDAP_DEBUG_TRACE,
552                 "=> get_ctrls\n", 0, 0, 0 );
553
554         if( op->o_protocol < LDAP_VERSION3 ) {
555                 rs->sr_err = SLAPD_DISCONNECT;
556                 rs->sr_text = "controls require LDAPv3";
557                 goto return_results;
558         }
559
560         /* one for first control, one for termination */
561         op->o_ctrls = op->o_tmpalloc( 2 * sizeof(LDAPControl *), op->o_tmpmemctx );
562
563 #if 0
564         if( op->ctrls == NULL ) {
565                 rs->sr_err = LDAP_NO_MEMORY;
566                 rs->sr_text = "no memory";
567                 goto return_results;
568         }
569 #endif
570
571         op->o_ctrls[nctrls] = NULL;
572
573         /* step through each element */
574         for( tag = ber_first_element( ber, &len, &opaque );
575                 tag != LBER_ERROR;
576                 tag = ber_next_element( ber, &len, opaque ) )
577         {
578                 LDAPControl *c;
579                 LDAPControl **tctrls;
580
581                 c = op->o_tmpalloc( sizeof(LDAPControl), op->o_tmpmemctx );
582                 memset(c, 0, sizeof(LDAPControl));
583
584                 /* allocate pointer space for current controls (nctrls)
585                  * + this control + extra NULL
586                  */
587                 tctrls = op->o_tmprealloc( op->o_ctrls,
588                         (nctrls+2) * sizeof(LDAPControl *), op->o_tmpmemctx );
589
590 #if 0
591                 if( tctrls == NULL ) {
592                         ch_free( c );
593                         ldap_controls_free(op->o_ctrls);
594                         op->o_ctrls = NULL;
595
596                         rs->sr_err = LDAP_NO_MEMORY;
597                         rs->sr_text = "no memory";
598                         goto return_results;
599                 }
600 #endif
601                 op->o_ctrls = tctrls;
602
603                 op->o_ctrls[nctrls++] = c;
604                 op->o_ctrls[nctrls] = NULL;
605
606                 tag = ber_scanf( ber, "{m" /*}*/, &bv );
607                 c->ldctl_oid = bv.bv_val;
608
609                 if( tag == LBER_ERROR ) {
610                         Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get oid failed.\n",
611                                 0, 0, 0 );
612
613                         slap_free_ctrls( op, op->o_ctrls );
614                         op->o_ctrls = NULL;
615                         rs->sr_err = SLAPD_DISCONNECT;
616                         rs->sr_text = "decoding controls error";
617                         goto return_results;
618
619                 } else if( c->ldctl_oid == NULL ) {
620                         Debug( LDAP_DEBUG_TRACE,
621                                 "get_ctrls: conn %lu got emtpy OID.\n",
622                                 op->o_connid, 0, 0 );
623
624                         slap_free_ctrls( op, op->o_ctrls );
625                         op->o_ctrls = NULL;
626                         rs->sr_err = LDAP_PROTOCOL_ERROR;
627                         rs->sr_text = "OID field is empty";
628                         goto return_results;
629                 }
630
631                 tag = ber_peek_tag( ber, &len );
632
633                 if( tag == LBER_BOOLEAN ) {
634                         ber_int_t crit;
635                         tag = ber_scanf( ber, "b", &crit );
636
637                         if( tag == LBER_ERROR ) {
638                                 Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get crit failed.\n",
639                                         0, 0, 0 );
640                                 slap_free_ctrls( op, op->o_ctrls );
641                                 op->o_ctrls = NULL;
642                                 rs->sr_err = SLAPD_DISCONNECT;
643                                 rs->sr_text = "decoding controls error";
644                                 goto return_results;
645                         }
646
647                         c->ldctl_iscritical = (crit != 0);
648                         tag = ber_peek_tag( ber, &len );
649                 }
650
651                 if( tag == LBER_OCTETSTRING ) {
652                         tag = ber_scanf( ber, "m", &c->ldctl_value );
653
654                         if( tag == LBER_ERROR ) {
655                                 Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: conn %lu: "
656                                         "%s (%scritical): get value failed.\n",
657                                         op->o_connid, c->ldctl_oid,
658                                         c->ldctl_iscritical ? "" : "non" );
659                                 slap_free_ctrls( op, op->o_ctrls );
660                                 op->o_ctrls = NULL;
661                                 rs->sr_err = SLAPD_DISCONNECT;
662                                 rs->sr_text = "decoding controls error";
663                                 goto return_results;
664                         }
665                 }
666
667                 Debug( LDAP_DEBUG_TRACE,
668                         "=> get_ctrls: oid=\"%s\" (%scritical)\n",
669                         c->ldctl_oid, c->ldctl_iscritical ? "" : "non", 0 );
670
671                 rs->sr_err = slap_parse_ctrl( op, rs, c, &rs->sr_text );
672                 if ( rs->sr_err != LDAP_SUCCESS ) {
673                         goto return_results;
674                 }
675         }
676
677 return_results:
678         Debug( LDAP_DEBUG_TRACE,
679                 "<= get_ctrls: n=%d rc=%d err=\"%s\"\n",
680                 nctrls, rs->sr_err, rs->sr_text ? rs->sr_text : "");
681
682         if( sendres && rs->sr_err != LDAP_SUCCESS ) {
683                 if( rs->sr_err == SLAPD_DISCONNECT ) {
684                         rs->sr_err = LDAP_PROTOCOL_ERROR;
685                         send_ldap_disconnect( op, rs );
686                         rs->sr_err = SLAPD_DISCONNECT;
687                 } else {
688                         send_ldap_result( op, rs );
689                 }
690         }
691
692         return rs->sr_err;
693 }
694
695 int
696 slap_remove_control(
697         Operation       *op,
698         SlapReply       *rs,
699         int             ctrl,
700         BI_chk_controls fnc )
701 {
702         int             i, j;
703
704         switch ( op->o_ctrlflag[ ctrl ] ) {
705         case SLAP_CONTROL_NONCRITICAL:
706                 for ( i = 0, j = -1; op->o_ctrls[ i ] != NULL; i++ ) {
707                         if ( strcmp( op->o_ctrls[ i ]->ldctl_oid,
708                                 slap_known_controls[ ctrl - 1 ] ) == 0 )
709                         {
710                                 j = i;
711                         }
712                 }
713
714                 if ( j == -1 ) {
715                         rs->sr_err = LDAP_OTHER;
716                         break;
717                 }
718
719                 if ( fnc ) {
720                         (void)fnc( op, rs );
721                 }
722
723                 op->o_tmpfree( op->o_ctrls[ j ], op->o_tmpmemctx );
724
725                 if ( i > 1 ) {
726                         AC_MEMCPY( &op->o_ctrls[ j ], &op->o_ctrls[ j + 1 ],
727                                 ( i - j ) * sizeof( LDAPControl * ) );
728
729                 } else {
730                         op->o_tmpfree( op->o_ctrls, op->o_tmpmemctx );
731                         op->o_ctrls = NULL;
732                 }
733
734                 op->o_ctrlflag[ ctrl ] = SLAP_CONTROL_IGNORED;
735
736                 Debug( LDAP_DEBUG_ANY, "%s: "
737                         "non-critical control \"%s\" not supported; stripped.\n",
738                         op->o_log_prefix, slap_known_controls[ ctrl ], 0 );
739                 /* fall thru */
740
741         case SLAP_CONTROL_IGNORED:
742         case SLAP_CONTROL_NONE:
743                 rs->sr_err = SLAP_CB_CONTINUE;
744                 break;
745
746         case SLAP_CONTROL_CRITICAL:
747                 rs->sr_err = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
748                 if ( fnc ) {
749                         (void)fnc( op, rs );
750                 }
751                 Debug( LDAP_DEBUG_ANY, "%s: "
752                         "critical control \"%s\" not supported.\n",
753                         op->o_log_prefix, slap_known_controls[ ctrl ], 0 );
754                 break;
755
756         default:
757                 /* handle all cases! */
758                 assert( 0 );
759         }
760
761         return rs->sr_err;
762 }
763
764 #ifdef LDAP_DEVEL
765 static int parseDontUseCopy (
766         Operation *op,
767         SlapReply *rs,
768         LDAPControl *ctrl )
769 {
770         if ( op->o_dontUseCopy != SLAP_CONTROL_NONE ) {
771                 rs->sr_text = "dontUseCopy control specified multiple times";
772                 return LDAP_PROTOCOL_ERROR;
773         }
774
775         if ( ctrl->ldctl_value.bv_len ) {
776                 rs->sr_text = "dontUseCopy control value not empty";
777                 return LDAP_PROTOCOL_ERROR;
778         }
779
780         if ( ctrl->ldctl_iscritical != SLAP_CONTROL_CRITICAL ) {
781                 rs->sr_text = "dontUseCopy criticality of FALSE not allowed";
782                 return LDAP_PROTOCOL_ERROR;
783         }
784
785         op->o_dontUseCopy = SLAP_CONTROL_CRITICAL;
786         return LDAP_SUCCESS;
787 }
788
789 static int parseManageDIT (
790         Operation *op,
791         SlapReply *rs,
792         LDAPControl *ctrl )
793 {
794         if ( op->o_managedit != SLAP_CONTROL_NONE ) {
795                 rs->sr_text = "manageDIT control specified multiple times";
796                 return LDAP_PROTOCOL_ERROR;
797         }
798
799         if ( ctrl->ldctl_value.bv_len ) {
800                 rs->sr_text = "manageDIT control value not empty";
801                 return LDAP_PROTOCOL_ERROR;
802         }
803
804         op->o_managedit = ctrl->ldctl_iscritical
805                 ? SLAP_CONTROL_CRITICAL
806                 : SLAP_CONTROL_NONCRITICAL;
807
808         return LDAP_SUCCESS;
809 }
810 #endif
811
812 static int parseManageDSAit (
813         Operation *op,
814         SlapReply *rs,
815         LDAPControl *ctrl )
816 {
817         if ( op->o_managedsait != SLAP_CONTROL_NONE ) {
818                 rs->sr_text = "manageDSAit control specified multiple times";
819                 return LDAP_PROTOCOL_ERROR;
820         }
821
822         if ( ctrl->ldctl_value.bv_len ) {
823                 rs->sr_text = "manageDSAit control value not empty";
824                 return LDAP_PROTOCOL_ERROR;
825         }
826
827         op->o_managedsait = ctrl->ldctl_iscritical
828                 ? SLAP_CONTROL_CRITICAL
829                 : SLAP_CONTROL_NONCRITICAL;
830
831         return LDAP_SUCCESS;
832 }
833
834 static int parseProxyAuthz (
835         Operation *op,
836         SlapReply *rs,
837         LDAPControl *ctrl )
838 {
839         int             rc;
840         struct berval   dn = BER_BVNULL;
841
842         if ( op->o_proxy_authz != SLAP_CONTROL_NONE ) {
843                 rs->sr_text = "proxy authorization control specified multiple times";
844                 return LDAP_PROTOCOL_ERROR;
845         }
846
847         op->o_proxy_authz = ctrl->ldctl_iscritical
848                 ? SLAP_CONTROL_CRITICAL
849                 : SLAP_CONTROL_NONCRITICAL;
850
851         Debug( LDAP_DEBUG_ARGS,
852                 "parseProxyAuthz: conn %lu authzid=\"%s\"\n", 
853                 op->o_connid,
854                 ctrl->ldctl_value.bv_len ?  ctrl->ldctl_value.bv_val : "anonymous",
855                 0 );
856
857         if ( ctrl->ldctl_value.bv_len == 0 ) {
858                 Debug( LDAP_DEBUG_TRACE,
859                         "parseProxyAuthz: conn=%lu anonymous\n", 
860                         op->o_connid, 0, 0 );
861
862                 /* anonymous */
863                 op->o_ndn.bv_val[ 0 ] = '\0';
864                 op->o_ndn.bv_len = 0;
865
866                 op->o_dn.bv_val[ 0 ] = '\0';
867                 op->o_dn.bv_len = 0;
868
869                 return LDAP_SUCCESS;
870         }
871
872         rc = slap_sasl_getdn( op->o_conn, op, &ctrl->ldctl_value,
873                         NULL, &dn, SLAP_GETDN_AUTHZID );
874
875         /* FIXME: empty DN in proxyAuthz control should be legal... */
876         if( rc != LDAP_SUCCESS /* || !dn.bv_len */ ) {
877                 if ( dn.bv_val ) {
878                         ch_free( dn.bv_val );
879                 }
880                 rs->sr_text = "authzId mapping failed";
881                 return LDAP_PROXY_AUTHZ_FAILURE;
882         }
883
884         Debug( LDAP_DEBUG_TRACE,
885                 "parseProxyAuthz: conn=%lu \"%s\"\n", 
886                 op->o_connid,
887                 dn.bv_len ? dn.bv_val : "(NULL)", 0 );
888
889         rc = slap_sasl_authorized( op, &op->o_ndn, &dn );
890
891         if ( rc ) {
892                 ch_free( dn.bv_val );
893                 rs->sr_text = "not authorized to assume identity";
894                 return LDAP_PROXY_AUTHZ_FAILURE;
895         }
896
897         ch_free( op->o_ndn.bv_val );
898         ch_free( op->o_dn.bv_val );
899
900         /*
901          * NOTE: since slap_sasl_getdn() returns a normalized dn,
902          * from now on op->o_dn is normalized
903          */
904         op->o_ndn = dn;
905         ber_dupbv( &op->o_dn, &dn );
906
907
908         Statslog( LDAP_DEBUG_STATS, "%s PROXYAUTHZ dn=\"%s\"\n",
909             op->o_log_prefix, dn.bv_val, 0, 0, 0 );
910
911         return LDAP_SUCCESS;
912 }
913
914 static int parseNoOp (
915         Operation *op,
916         SlapReply *rs,
917         LDAPControl *ctrl )
918 {
919         if ( op->o_noop != SLAP_CONTROL_NONE ) {
920                 rs->sr_text = "noop control specified multiple times";
921                 return LDAP_PROTOCOL_ERROR;
922         }
923
924         if ( ctrl->ldctl_value.bv_len ) {
925                 rs->sr_text = "noop control value not empty";
926                 return LDAP_PROTOCOL_ERROR;
927         }
928
929         op->o_noop = ctrl->ldctl_iscritical
930                 ? SLAP_CONTROL_CRITICAL
931                 : SLAP_CONTROL_NONCRITICAL;
932
933         return LDAP_SUCCESS;
934 }
935
936 static int parsePagedResults (
937         Operation *op,
938         SlapReply *rs,
939         LDAPControl *ctrl )
940 {
941         int             rc = LDAP_SUCCESS;
942         ber_tag_t       tag;
943         ber_int_t       size;
944         BerElement      *ber;
945         struct berval   cookie = BER_BVNULL;
946         PagedResultsState       *ps;
947
948         if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
949                 rs->sr_text = "paged results control specified multiple times";
950                 return LDAP_PROTOCOL_ERROR;
951         }
952
953         if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
954                 rs->sr_text = "paged results control value is empty (or absent)";
955                 return LDAP_PROTOCOL_ERROR;
956         }
957
958         /* Parse the control value
959          *      realSearchControlValue ::= SEQUENCE {
960          *              size    INTEGER (0..maxInt),
961          *                              -- requested page size from client
962          *                              -- result set size estimate from server
963          *              cookie  OCTET STRING
964          * }
965          */
966         ber = ber_init( &ctrl->ldctl_value );
967         if ( ber == NULL ) {
968                 rs->sr_text = "internal error";
969                 return LDAP_OTHER;
970         }
971
972         tag = ber_scanf( ber, "{im}", &size, &cookie );
973
974         if ( tag == LBER_ERROR ) {
975                 rs->sr_text = "paged results control could not be decoded";
976                 rc = LDAP_PROTOCOL_ERROR;
977                 goto done;
978         }
979
980         if ( size < 0 ) {
981                 rs->sr_text = "paged results control size invalid";
982                 rc = LDAP_PROTOCOL_ERROR;
983                 goto done;
984         }
985
986         ps = op->o_tmpalloc( sizeof(PagedResultsState), op->o_tmpmemctx );
987         *ps = op->o_conn->c_pagedresults_state;
988         ps->ps_size = size;
989         op->o_pagedresults_state = ps;
990
991         /* NOTE: according to RFC 2696 3.:
992
993     If the page size is greater than or equal to the sizeLimit value, the
994     server should ignore the control as the request can be satisfied in a
995     single page.
996          
997          * NOTE: this assumes that the op->ors_slimit be set
998          * before the controls are parsed.     
999          */
1000                 
1001         if ( op->ors_slimit > 0 && size >= op->ors_slimit ) {
1002                 op->o_pagedresults = SLAP_CONTROL_IGNORED;
1003
1004         } else if ( ctrl->ldctl_iscritical ) {
1005                 op->o_pagedresults = SLAP_CONTROL_CRITICAL;
1006
1007         } else {
1008                 op->o_pagedresults = SLAP_CONTROL_NONCRITICAL;
1009         }
1010
1011 done:;
1012         (void)ber_free( ber, 1 );
1013         return rc;
1014 }
1015
1016 #ifdef LDAP_DEVEL
1017 static int parseSortedResults (
1018         Operation *op,
1019         SlapReply *rs,
1020         LDAPControl *ctrl )
1021 {
1022         int             rc = LDAP_SUCCESS;
1023
1024         if ( op->o_sortedresults != SLAP_CONTROL_NONE ) {
1025                 rs->sr_text = "sorted results control specified multiple times";
1026                 return LDAP_PROTOCOL_ERROR;
1027         }
1028
1029         if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
1030                 rs->sr_text = "sorted results control value is empty (or absent)";
1031                 return LDAP_PROTOCOL_ERROR;
1032         }
1033
1034         /* blow off parsing the value */
1035
1036         op->o_sortedresults = ctrl->ldctl_iscritical
1037                 ? SLAP_CONTROL_CRITICAL
1038                 : SLAP_CONTROL_NONCRITICAL;
1039
1040         return rc;
1041 }
1042 #endif
1043
1044 static int parseAssert (
1045         Operation *op,
1046         SlapReply *rs,
1047         LDAPControl *ctrl )
1048 {
1049         BerElement      *ber;
1050         struct berval   fstr = BER_BVNULL;
1051
1052         if ( op->o_assert != SLAP_CONTROL_NONE ) {
1053                 rs->sr_text = "assert control specified multiple times";
1054                 return LDAP_PROTOCOL_ERROR;
1055         }
1056
1057         if ( ctrl->ldctl_value.bv_len == 0 ) {
1058                 rs->sr_text = "assert control value is empty (or absent)";
1059                 return LDAP_PROTOCOL_ERROR;
1060         }
1061
1062         ber = ber_init( &(ctrl->ldctl_value) );
1063         if (ber == NULL) {
1064                 rs->sr_text = "assert control: internal error";
1065                 return LDAP_OTHER;
1066         }
1067         
1068         rs->sr_err = get_filter( op, ber, (Filter **)&(op->o_assertion),
1069                 &rs->sr_text);
1070         if( rs->sr_err != LDAP_SUCCESS ) {
1071                 if( rs->sr_err == SLAPD_DISCONNECT ) {
1072                         rs->sr_err = LDAP_PROTOCOL_ERROR;
1073                         send_ldap_disconnect( op, rs );
1074                         rs->sr_err = SLAPD_DISCONNECT;
1075                 } else {
1076                         send_ldap_result( op, rs );
1077                 }
1078                 if( op->o_assertion != NULL ) {
1079                         filter_free_x( op, op->o_assertion );
1080                 }
1081                 return rs->sr_err;
1082         }
1083
1084 #ifdef LDAP_DEBUG
1085         filter2bv_x( op, op->o_assertion, &fstr );
1086
1087         Debug( LDAP_DEBUG_ARGS, "parseAssert: conn %ld assert: %s\n",
1088                 op->o_connid, fstr.bv_len ? fstr.bv_val : "empty" , 0 );
1089         op->o_tmpfree( fstr.bv_val, op->o_tmpmemctx );
1090 #endif
1091
1092         op->o_assert = ctrl->ldctl_iscritical
1093                 ? SLAP_CONTROL_CRITICAL
1094                 : SLAP_CONTROL_NONCRITICAL;
1095
1096         rs->sr_err = LDAP_SUCCESS;
1097         return LDAP_SUCCESS;
1098 }
1099
1100 static int parsePreRead (
1101         Operation *op,
1102         SlapReply *rs,
1103         LDAPControl *ctrl )
1104 {
1105         ber_len_t siz, off, i;
1106         AttributeName *an = NULL;
1107         BerElement      *ber;
1108
1109         if ( op->o_preread != SLAP_CONTROL_NONE ) {
1110                 rs->sr_text = "preread control specified multiple times";
1111                 return LDAP_PROTOCOL_ERROR;
1112         }
1113
1114         if ( ctrl->ldctl_value.bv_len == 0 ) {
1115                 rs->sr_text = "preread control value is empty (or absent)";
1116                 return LDAP_PROTOCOL_ERROR;
1117         }
1118
1119         ber = ber_init( &(ctrl->ldctl_value) );
1120         if (ber == NULL) {
1121                 rs->sr_text = "preread control: internal error";
1122                 return LDAP_OTHER;
1123         }
1124
1125         siz = sizeof( AttributeName );
1126         off = offsetof( AttributeName, an_name );
1127         if ( ber_scanf( ber, "{M}", &an, &siz, off ) == LBER_ERROR ) {
1128                 rs->sr_text = "preread control: decoding error";
1129                 return LDAP_PROTOCOL_ERROR;
1130         }
1131
1132         for( i=0; i<siz; i++ ) {
1133                 int             rc = LDAP_SUCCESS;
1134                 const char      *dummy = NULL;
1135
1136                 an[i].an_desc = NULL;
1137                 an[i].an_oc = NULL;
1138                 an[i].an_oc_exclude = 0;
1139                 rc = slap_bv2ad( &an[i].an_name, &an[i].an_desc, &dummy );
1140                 if ( rc != LDAP_SUCCESS && ctrl->ldctl_iscritical ) {
1141                         rs->sr_text = dummy
1142                                 ? dummy
1143                                 : "postread control: unknown attributeType";
1144                         return rc;
1145                 }
1146         }
1147
1148         op->o_preread = ctrl->ldctl_iscritical
1149                 ? SLAP_CONTROL_CRITICAL
1150                 : SLAP_CONTROL_NONCRITICAL;
1151
1152         op->o_preread_attrs = an;
1153
1154         rs->sr_err = LDAP_SUCCESS;
1155         return LDAP_SUCCESS;
1156 }
1157
1158 static int parsePostRead (
1159         Operation *op,
1160         SlapReply *rs,
1161         LDAPControl *ctrl )
1162 {
1163         ber_len_t siz, off, i;
1164         AttributeName *an = NULL;
1165         BerElement      *ber;
1166
1167         if ( op->o_postread != SLAP_CONTROL_NONE ) {
1168                 rs->sr_text = "postread control specified multiple times";
1169                 return LDAP_PROTOCOL_ERROR;
1170         }
1171
1172         if ( ctrl->ldctl_value.bv_len == 0 ) {
1173                 rs->sr_text = "postread control value is empty (or absent)";
1174                 return LDAP_PROTOCOL_ERROR;
1175         }
1176
1177         ber = ber_init( &(ctrl->ldctl_value) );
1178         if (ber == NULL) {
1179                 rs->sr_text = "postread control: internal error";
1180                 return LDAP_OTHER;
1181         }
1182
1183         siz = sizeof( AttributeName );
1184         off = offsetof( AttributeName, an_name );
1185         if ( ber_scanf( ber, "{M}", &an, &siz, off ) == LBER_ERROR ) {
1186                 rs->sr_text = "postread control: decoding error";
1187                 return LDAP_PROTOCOL_ERROR;
1188         }
1189
1190         for( i=0; i<siz; i++ ) {
1191                 int             rc = LDAP_SUCCESS;
1192                 const char      *dummy = NULL;
1193
1194                 an[i].an_desc = NULL;
1195                 an[i].an_oc = NULL;
1196                 an[i].an_oc_exclude = 0;
1197                 rc = slap_bv2ad( &an[i].an_name, &an[i].an_desc, &dummy );
1198                 if ( rc != LDAP_SUCCESS && ctrl->ldctl_iscritical ) {
1199                         rs->sr_text = dummy
1200                                 ? dummy
1201                                 : "postread control: unknown attributeType";
1202                         return rc;
1203                 }
1204         }
1205
1206         op->o_postread = ctrl->ldctl_iscritical
1207                 ? SLAP_CONTROL_CRITICAL
1208                 : SLAP_CONTROL_NONCRITICAL;
1209
1210         op->o_postread_attrs = an;
1211
1212         rs->sr_err = LDAP_SUCCESS;
1213         return LDAP_SUCCESS;
1214 }
1215
1216 static int parseValuesReturnFilter (
1217         Operation *op,
1218         SlapReply *rs,
1219         LDAPControl *ctrl )
1220 {
1221         BerElement      *ber;
1222         struct berval   fstr = BER_BVNULL;
1223
1224         if ( op->o_valuesreturnfilter != SLAP_CONTROL_NONE ) {
1225                 rs->sr_text = "valuesReturnFilter control specified multiple times";
1226                 return LDAP_PROTOCOL_ERROR;
1227         }
1228
1229         if ( ctrl->ldctl_value.bv_len == 0 ) {
1230                 rs->sr_text = "valuesReturnFilter control value is empty (or absent)";
1231                 return LDAP_PROTOCOL_ERROR;
1232         }
1233
1234         ber = ber_init( &(ctrl->ldctl_value) );
1235         if (ber == NULL) {
1236                 rs->sr_text = "internal error";
1237                 return LDAP_OTHER;
1238         }
1239         
1240         rs->sr_err = get_vrFilter( op, ber,
1241                 (ValuesReturnFilter **)&(op->o_vrFilter), &rs->sr_text);
1242
1243         if( rs->sr_err != LDAP_SUCCESS ) {
1244                 if( rs->sr_err == SLAPD_DISCONNECT ) {
1245                         rs->sr_err = LDAP_PROTOCOL_ERROR;
1246                         send_ldap_disconnect( op, rs );
1247                         rs->sr_err = SLAPD_DISCONNECT;
1248                 } else {
1249                         send_ldap_result( op, rs );
1250                 }
1251                 if( op->o_vrFilter != NULL) vrFilter_free( op, op->o_vrFilter ); 
1252         }
1253 #ifdef LDAP_DEBUG
1254         else {
1255                 vrFilter2bv( op, op->o_vrFilter, &fstr );
1256         }
1257
1258         Debug( LDAP_DEBUG_ARGS, "       vrFilter: %s\n",
1259                 fstr.bv_len ? fstr.bv_val : "empty", 0, 0 );
1260         op->o_tmpfree( fstr.bv_val, op->o_tmpmemctx );
1261 #endif
1262
1263         op->o_valuesreturnfilter = ctrl->ldctl_iscritical
1264                 ? SLAP_CONTROL_CRITICAL
1265                 : SLAP_CONTROL_NONCRITICAL;
1266
1267         rs->sr_err = LDAP_SUCCESS;
1268         return LDAP_SUCCESS;
1269 }
1270
1271 static int parseSubentries (
1272         Operation *op,
1273         SlapReply *rs,
1274         LDAPControl *ctrl )
1275 {
1276         if ( op->o_subentries != SLAP_CONTROL_NONE ) {
1277                 rs->sr_text = "subentries control specified multiple times";
1278                 return LDAP_PROTOCOL_ERROR;
1279         }
1280
1281         /* FIXME: should use BER library */
1282         if( ( ctrl->ldctl_value.bv_len != 3 )
1283                 || ( ctrl->ldctl_value.bv_val[0] != 0x01 )
1284                 || ( ctrl->ldctl_value.bv_val[1] != 0x01 ))
1285         {
1286                 rs->sr_text = "subentries control value encoding is bogus";
1287                 return LDAP_PROTOCOL_ERROR;
1288         }
1289
1290         op->o_subentries = ctrl->ldctl_iscritical
1291                 ? SLAP_CONTROL_CRITICAL
1292                 : SLAP_CONTROL_NONCRITICAL;
1293
1294         if (ctrl->ldctl_value.bv_val[2]) {
1295                 set_subentries_visibility( op );
1296         }
1297
1298         return LDAP_SUCCESS;
1299 }
1300
1301 static int parsePermissiveModify (
1302         Operation *op,
1303         SlapReply *rs,
1304         LDAPControl *ctrl )
1305 {
1306         if ( op->o_permissive_modify != SLAP_CONTROL_NONE ) {
1307                 rs->sr_text = "permissiveModify control specified multiple times";
1308                 return LDAP_PROTOCOL_ERROR;
1309         }
1310
1311         if ( ctrl->ldctl_value.bv_len ) {
1312                 rs->sr_text = "permissiveModify control value not empty";
1313                 return LDAP_PROTOCOL_ERROR;
1314         }
1315
1316         op->o_permissive_modify = ctrl->ldctl_iscritical
1317                 ? SLAP_CONTROL_CRITICAL
1318                 : SLAP_CONTROL_NONCRITICAL;
1319
1320         return LDAP_SUCCESS;
1321 }
1322
1323 static int parseDomainScope (
1324         Operation *op,
1325         SlapReply *rs,
1326         LDAPControl *ctrl )
1327 {
1328         if ( op->o_domain_scope != SLAP_CONTROL_NONE ) {
1329                 rs->sr_text = "domainScope control specified multiple times";
1330                 return LDAP_PROTOCOL_ERROR;
1331         }
1332
1333         if ( ctrl->ldctl_value.bv_len ) {
1334                 rs->sr_text = "domainScope control value not empty";
1335                 return LDAP_PROTOCOL_ERROR;
1336         }
1337
1338         op->o_domain_scope = ctrl->ldctl_iscritical
1339                 ? SLAP_CONTROL_CRITICAL
1340                 : SLAP_CONTROL_NONCRITICAL;
1341
1342         return LDAP_SUCCESS;
1343 }
1344
1345 #ifdef SLAP_CONTROL_X_TREE_DELETE
1346 static int parseTreeDelete (
1347         Operation *op,
1348         SlapReply *rs,
1349         LDAPControl *ctrl )
1350 {
1351         if ( op->o_tree_delete != SLAP_CONTROL_NONE ) {
1352                 rs->sr_text = "treeDelete control specified multiple times";
1353                 return LDAP_PROTOCOL_ERROR;
1354         }
1355
1356         if ( ctrl->ldctl_value.bv_len ) {
1357                 rs->sr_text = "treeDelete control value not empty";
1358                 return LDAP_PROTOCOL_ERROR;
1359         }
1360
1361         op->o_tree_delete = ctrl->ldctl_iscritical
1362                 ? SLAP_CONTROL_CRITICAL
1363                 : SLAP_CONTROL_NONCRITICAL;
1364
1365         return LDAP_SUCCESS;
1366 }
1367 #endif
1368
1369 static int parseSearchOptions (
1370         Operation *op,
1371         SlapReply *rs,
1372         LDAPControl *ctrl )
1373 {
1374         BerElement *ber;
1375         ber_int_t search_flags;
1376         ber_tag_t tag;
1377
1378         if ( ctrl->ldctl_value.bv_len == 0 ) {
1379                 rs->sr_text = "searchOptions control value is empty (or absent)";
1380                 return LDAP_PROTOCOL_ERROR;
1381         }
1382
1383         ber = ber_init( &ctrl->ldctl_value );
1384         if( ber == NULL ) {
1385                 rs->sr_text = "internal error";
1386                 return LDAP_OTHER;
1387         }
1388
1389         if ( (tag = ber_scanf( ber, "{i}", &search_flags )) == LBER_ERROR ) {
1390                 rs->sr_text = "searchOptions control decoding error";
1391                 return LDAP_PROTOCOL_ERROR;
1392         }
1393
1394         (void) ber_free( ber, 1 );
1395
1396         if ( search_flags & LDAP_SEARCH_FLAG_DOMAIN_SCOPE ) {
1397                 if ( op->o_domain_scope != SLAP_CONTROL_NONE ) {
1398                         rs->sr_text = "searchOptions control specified multiple times "
1399                                 "or with domainScope control";
1400                         return LDAP_PROTOCOL_ERROR;
1401                 }
1402
1403                 op->o_domain_scope = ctrl->ldctl_iscritical
1404                         ? SLAP_CONTROL_CRITICAL
1405                         : SLAP_CONTROL_NONCRITICAL;
1406         }
1407
1408         if ( search_flags & ~(LDAP_SEARCH_FLAG_DOMAIN_SCOPE) ) {
1409                 /* Other search flags not recognised so far,
1410                  * including:
1411                  *              LDAP_SEARCH_FLAG_PHANTOM_ROOM
1412                  */
1413                 rs->sr_text = "searchOptions contained unrecognized flag";
1414                 return LDAP_UNWILLING_TO_PERFORM;
1415         }
1416
1417         return LDAP_SUCCESS;
1418 }
1419