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