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