]> git.sur5r.net Git - openldap/blob - servers/slapd/controls.c
large X (for version.sh)
[openldap] / servers / slapd / controls.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2008 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         if ( !cookie.bv_len ) {
1005                 ps->ps_count = 0;
1006                 ps->ps_cookie = 0;
1007         }
1008
1009         /* NOTE: according to RFC 2696 3.:
1010
1011     If the page size is greater than or equal to the sizeLimit value, the
1012     server should ignore the control as the request can be satisfied in a
1013     single page.
1014          
1015          * NOTE: this assumes that the op->ors_slimit be set
1016          * before the controls are parsed.     
1017          */
1018                 
1019         if ( op->ors_slimit > 0 && size >= op->ors_slimit ) {
1020                 op->o_pagedresults = SLAP_CONTROL_IGNORED;
1021
1022         } else if ( ctrl->ldctl_iscritical ) {
1023                 op->o_pagedresults = SLAP_CONTROL_CRITICAL;
1024
1025         } else {
1026                 op->o_pagedresults = SLAP_CONTROL_NONCRITICAL;
1027         }
1028
1029 done:;
1030         (void)ber_free( ber, 1 );
1031         return rc;
1032 }
1033
1034 #ifdef LDAP_DEVEL
1035 static int parseSortedResults (
1036         Operation *op,
1037         SlapReply *rs,
1038         LDAPControl *ctrl )
1039 {
1040         int             rc = LDAP_SUCCESS;
1041
1042         if ( op->o_sortedresults != SLAP_CONTROL_NONE ) {
1043                 rs->sr_text = "sorted results control specified multiple times";
1044                 return LDAP_PROTOCOL_ERROR;
1045         }
1046
1047         if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
1048                 rs->sr_text = "sorted results control value is empty (or absent)";
1049                 return LDAP_PROTOCOL_ERROR;
1050         }
1051
1052         /* blow off parsing the value */
1053
1054         op->o_sortedresults = ctrl->ldctl_iscritical
1055                 ? SLAP_CONTROL_CRITICAL
1056                 : SLAP_CONTROL_NONCRITICAL;
1057
1058         return rc;
1059 }
1060 #endif
1061
1062 static int parseAssert (
1063         Operation *op,
1064         SlapReply *rs,
1065         LDAPControl *ctrl )
1066 {
1067         BerElement      *ber;
1068         struct berval   fstr = BER_BVNULL;
1069
1070         if ( op->o_assert != SLAP_CONTROL_NONE ) {
1071                 rs->sr_text = "assert control specified multiple times";
1072                 return LDAP_PROTOCOL_ERROR;
1073         }
1074
1075         if ( ctrl->ldctl_value.bv_len == 0 ) {
1076                 rs->sr_text = "assert control value is empty (or absent)";
1077                 return LDAP_PROTOCOL_ERROR;
1078         }
1079
1080         ber = ber_init( &(ctrl->ldctl_value) );
1081         if (ber == NULL) {
1082                 rs->sr_text = "assert control: internal error";
1083                 return LDAP_OTHER;
1084         }
1085         
1086         rs->sr_err = get_filter( op, ber, (Filter **)&(op->o_assertion),
1087                 &rs->sr_text);
1088         if( rs->sr_err != LDAP_SUCCESS ) {
1089                 if( rs->sr_err == SLAPD_DISCONNECT ) {
1090                         rs->sr_err = LDAP_PROTOCOL_ERROR;
1091                         send_ldap_disconnect( op, rs );
1092                         rs->sr_err = SLAPD_DISCONNECT;
1093                 } else {
1094                         send_ldap_result( op, rs );
1095                 }
1096                 if( op->o_assertion != NULL ) {
1097                         filter_free_x( op, op->o_assertion );
1098                 }
1099                 return rs->sr_err;
1100         }
1101
1102 #ifdef LDAP_DEBUG
1103         filter2bv_x( op, op->o_assertion, &fstr );
1104
1105         Debug( LDAP_DEBUG_ARGS, "parseAssert: conn %ld assert: %s\n",
1106                 op->o_connid, fstr.bv_len ? fstr.bv_val : "empty" , 0 );
1107         op->o_tmpfree( fstr.bv_val, op->o_tmpmemctx );
1108 #endif
1109
1110         op->o_assert = ctrl->ldctl_iscritical
1111                 ? SLAP_CONTROL_CRITICAL
1112                 : SLAP_CONTROL_NONCRITICAL;
1113
1114         rs->sr_err = LDAP_SUCCESS;
1115         return LDAP_SUCCESS;
1116 }
1117
1118 static int parsePreRead (
1119         Operation *op,
1120         SlapReply *rs,
1121         LDAPControl *ctrl )
1122 {
1123         ber_len_t siz, off, i;
1124         AttributeName *an = NULL;
1125         BerElement      *ber;
1126
1127         if ( op->o_preread != SLAP_CONTROL_NONE ) {
1128                 rs->sr_text = "preread control specified multiple times";
1129                 return LDAP_PROTOCOL_ERROR;
1130         }
1131
1132         if ( ctrl->ldctl_value.bv_len == 0 ) {
1133                 rs->sr_text = "preread control value is empty (or absent)";
1134                 return LDAP_PROTOCOL_ERROR;
1135         }
1136
1137         ber = ber_init( &(ctrl->ldctl_value) );
1138         if (ber == NULL) {
1139                 rs->sr_text = "preread control: internal error";
1140                 return LDAP_OTHER;
1141         }
1142
1143         siz = sizeof( AttributeName );
1144         off = offsetof( AttributeName, an_name );
1145         if ( ber_scanf( ber, "{M}", &an, &siz, off ) == LBER_ERROR ) {
1146                 rs->sr_text = "preread control: decoding error";
1147                 return LDAP_PROTOCOL_ERROR;
1148         }
1149
1150         for( i=0; i<siz; i++ ) {
1151                 int             rc = LDAP_SUCCESS;
1152                 const char      *dummy = NULL;
1153
1154                 an[i].an_desc = NULL;
1155                 an[i].an_oc = NULL;
1156                 an[i].an_oc_exclude = 0;
1157                 rc = slap_bv2ad( &an[i].an_name, &an[i].an_desc, &dummy );
1158                 if ( rc != LDAP_SUCCESS && ctrl->ldctl_iscritical ) {
1159                         rs->sr_text = dummy
1160                                 ? dummy
1161                                 : "postread control: unknown attributeType";
1162                         return rc;
1163                 }
1164         }
1165
1166         op->o_preread = ctrl->ldctl_iscritical
1167                 ? SLAP_CONTROL_CRITICAL
1168                 : SLAP_CONTROL_NONCRITICAL;
1169
1170         op->o_preread_attrs = an;
1171
1172         rs->sr_err = LDAP_SUCCESS;
1173         return LDAP_SUCCESS;
1174 }
1175
1176 static int parsePostRead (
1177         Operation *op,
1178         SlapReply *rs,
1179         LDAPControl *ctrl )
1180 {
1181         ber_len_t siz, off, i;
1182         AttributeName *an = NULL;
1183         BerElement      *ber;
1184
1185         if ( op->o_postread != SLAP_CONTROL_NONE ) {
1186                 rs->sr_text = "postread control specified multiple times";
1187                 return LDAP_PROTOCOL_ERROR;
1188         }
1189
1190         if ( ctrl->ldctl_value.bv_len == 0 ) {
1191                 rs->sr_text = "postread control value is empty (or absent)";
1192                 return LDAP_PROTOCOL_ERROR;
1193         }
1194
1195         ber = ber_init( &(ctrl->ldctl_value) );
1196         if (ber == NULL) {
1197                 rs->sr_text = "postread control: internal error";
1198                 return LDAP_OTHER;
1199         }
1200
1201         siz = sizeof( AttributeName );
1202         off = offsetof( AttributeName, an_name );
1203         if ( ber_scanf( ber, "{M}", &an, &siz, off ) == LBER_ERROR ) {
1204                 rs->sr_text = "postread control: decoding error";
1205                 return LDAP_PROTOCOL_ERROR;
1206         }
1207
1208         for( i=0; i<siz; i++ ) {
1209                 int             rc = LDAP_SUCCESS;
1210                 const char      *dummy = NULL;
1211
1212                 an[i].an_desc = NULL;
1213                 an[i].an_oc = NULL;
1214                 an[i].an_oc_exclude = 0;
1215                 rc = slap_bv2ad( &an[i].an_name, &an[i].an_desc, &dummy );
1216                 if ( rc != LDAP_SUCCESS && ctrl->ldctl_iscritical ) {
1217                         rs->sr_text = dummy
1218                                 ? dummy
1219                                 : "postread control: unknown attributeType";
1220                         return rc;
1221                 }
1222         }
1223
1224         op->o_postread = ctrl->ldctl_iscritical
1225                 ? SLAP_CONTROL_CRITICAL
1226                 : SLAP_CONTROL_NONCRITICAL;
1227
1228         op->o_postread_attrs = an;
1229
1230         rs->sr_err = LDAP_SUCCESS;
1231         return LDAP_SUCCESS;
1232 }
1233
1234 static int parseValuesReturnFilter (
1235         Operation *op,
1236         SlapReply *rs,
1237         LDAPControl *ctrl )
1238 {
1239         BerElement      *ber;
1240         struct berval   fstr = BER_BVNULL;
1241
1242         if ( op->o_valuesreturnfilter != SLAP_CONTROL_NONE ) {
1243                 rs->sr_text = "valuesReturnFilter control specified multiple times";
1244                 return LDAP_PROTOCOL_ERROR;
1245         }
1246
1247         if ( ctrl->ldctl_value.bv_len == 0 ) {
1248                 rs->sr_text = "valuesReturnFilter control value is empty (or absent)";
1249                 return LDAP_PROTOCOL_ERROR;
1250         }
1251
1252         ber = ber_init( &(ctrl->ldctl_value) );
1253         if (ber == NULL) {
1254                 rs->sr_text = "internal error";
1255                 return LDAP_OTHER;
1256         }
1257         
1258         rs->sr_err = get_vrFilter( op, ber,
1259                 (ValuesReturnFilter **)&(op->o_vrFilter), &rs->sr_text);
1260
1261         (void) ber_free( ber, 1 );
1262
1263         if( rs->sr_err != LDAP_SUCCESS ) {
1264                 if( rs->sr_err == SLAPD_DISCONNECT ) {
1265                         rs->sr_err = LDAP_PROTOCOL_ERROR;
1266                         send_ldap_disconnect( op, rs );
1267                         rs->sr_err = SLAPD_DISCONNECT;
1268                 } else {
1269                         send_ldap_result( op, rs );
1270                 }
1271                 if( op->o_vrFilter != NULL) vrFilter_free( op, op->o_vrFilter ); 
1272         }
1273 #ifdef LDAP_DEBUG
1274         else {
1275                 vrFilter2bv( op, op->o_vrFilter, &fstr );
1276         }
1277
1278         Debug( LDAP_DEBUG_ARGS, "       vrFilter: %s\n",
1279                 fstr.bv_len ? fstr.bv_val : "empty", 0, 0 );
1280         op->o_tmpfree( fstr.bv_val, op->o_tmpmemctx );
1281 #endif
1282
1283         op->o_valuesreturnfilter = ctrl->ldctl_iscritical
1284                 ? SLAP_CONTROL_CRITICAL
1285                 : SLAP_CONTROL_NONCRITICAL;
1286
1287         rs->sr_err = LDAP_SUCCESS;
1288         return LDAP_SUCCESS;
1289 }
1290
1291 static int parseSubentries (
1292         Operation *op,
1293         SlapReply *rs,
1294         LDAPControl *ctrl )
1295 {
1296         if ( op->o_subentries != SLAP_CONTROL_NONE ) {
1297                 rs->sr_text = "subentries control specified multiple times";
1298                 return LDAP_PROTOCOL_ERROR;
1299         }
1300
1301         /* FIXME: should use BER library */
1302         if( ( ctrl->ldctl_value.bv_len != 3 )
1303                 || ( ctrl->ldctl_value.bv_val[0] != 0x01 )
1304                 || ( ctrl->ldctl_value.bv_val[1] != 0x01 ))
1305         {
1306                 rs->sr_text = "subentries control value encoding is bogus";
1307                 return LDAP_PROTOCOL_ERROR;
1308         }
1309
1310         op->o_subentries = ctrl->ldctl_iscritical
1311                 ? SLAP_CONTROL_CRITICAL
1312                 : SLAP_CONTROL_NONCRITICAL;
1313
1314         if (ctrl->ldctl_value.bv_val[2]) {
1315                 set_subentries_visibility( op );
1316         }
1317
1318         return LDAP_SUCCESS;
1319 }
1320
1321 static int parsePermissiveModify (
1322         Operation *op,
1323         SlapReply *rs,
1324         LDAPControl *ctrl )
1325 {
1326         if ( op->o_permissive_modify != SLAP_CONTROL_NONE ) {
1327                 rs->sr_text = "permissiveModify control specified multiple times";
1328                 return LDAP_PROTOCOL_ERROR;
1329         }
1330
1331         if ( ctrl->ldctl_value.bv_len ) {
1332                 rs->sr_text = "permissiveModify control value not empty";
1333                 return LDAP_PROTOCOL_ERROR;
1334         }
1335
1336         op->o_permissive_modify = ctrl->ldctl_iscritical
1337                 ? SLAP_CONTROL_CRITICAL
1338                 : SLAP_CONTROL_NONCRITICAL;
1339
1340         return LDAP_SUCCESS;
1341 }
1342
1343 static int parseDomainScope (
1344         Operation *op,
1345         SlapReply *rs,
1346         LDAPControl *ctrl )
1347 {
1348         if ( op->o_domain_scope != SLAP_CONTROL_NONE ) {
1349                 rs->sr_text = "domainScope control specified multiple times";
1350                 return LDAP_PROTOCOL_ERROR;
1351         }
1352
1353         if ( ctrl->ldctl_value.bv_len ) {
1354                 rs->sr_text = "domainScope control value not empty";
1355                 return LDAP_PROTOCOL_ERROR;
1356         }
1357
1358         op->o_domain_scope = ctrl->ldctl_iscritical
1359                 ? SLAP_CONTROL_CRITICAL
1360                 : SLAP_CONTROL_NONCRITICAL;
1361
1362         return LDAP_SUCCESS;
1363 }
1364
1365 #ifdef SLAP_CONTROL_X_TREE_DELETE
1366 static int parseTreeDelete (
1367         Operation *op,
1368         SlapReply *rs,
1369         LDAPControl *ctrl )
1370 {
1371         if ( op->o_tree_delete != SLAP_CONTROL_NONE ) {
1372                 rs->sr_text = "treeDelete control specified multiple times";
1373                 return LDAP_PROTOCOL_ERROR;
1374         }
1375
1376         if ( ctrl->ldctl_value.bv_len ) {
1377                 rs->sr_text = "treeDelete control value not empty";
1378                 return LDAP_PROTOCOL_ERROR;
1379         }
1380
1381         op->o_tree_delete = ctrl->ldctl_iscritical
1382                 ? SLAP_CONTROL_CRITICAL
1383                 : SLAP_CONTROL_NONCRITICAL;
1384
1385         return LDAP_SUCCESS;
1386 }
1387 #endif
1388
1389 static int parseSearchOptions (
1390         Operation *op,
1391         SlapReply *rs,
1392         LDAPControl *ctrl )
1393 {
1394         BerElement *ber;
1395         ber_int_t search_flags;
1396         ber_tag_t tag;
1397
1398         if ( ctrl->ldctl_value.bv_len == 0 ) {
1399                 rs->sr_text = "searchOptions control value is empty (or absent)";
1400                 return LDAP_PROTOCOL_ERROR;
1401         }
1402
1403         ber = ber_init( &ctrl->ldctl_value );
1404         if( ber == NULL ) {
1405                 rs->sr_text = "internal error";
1406                 return LDAP_OTHER;
1407         }
1408
1409         if ( (tag = ber_scanf( ber, "{i}", &search_flags )) == LBER_ERROR ) {
1410                 rs->sr_text = "searchOptions control decoding error";
1411                 return LDAP_PROTOCOL_ERROR;
1412         }
1413
1414         (void) ber_free( ber, 1 );
1415
1416         if ( search_flags & LDAP_SEARCH_FLAG_DOMAIN_SCOPE ) {
1417                 if ( op->o_domain_scope != SLAP_CONTROL_NONE ) {
1418                         rs->sr_text = "searchOptions control specified multiple times "
1419                                 "or with domainScope control";
1420                         return LDAP_PROTOCOL_ERROR;
1421                 }
1422
1423                 op->o_domain_scope = ctrl->ldctl_iscritical
1424                         ? SLAP_CONTROL_CRITICAL
1425                         : SLAP_CONTROL_NONCRITICAL;
1426         }
1427
1428         if ( search_flags & ~(LDAP_SEARCH_FLAG_DOMAIN_SCOPE) ) {
1429                 /* Other search flags not recognised so far,
1430                  * including:
1431                  *              LDAP_SEARCH_FLAG_PHANTOM_ROOM
1432                  */
1433                 rs->sr_text = "searchOptions contained unrecognized flag";
1434                 return LDAP_UNWILLING_TO_PERFORM;
1435         }
1436
1437         return LDAP_SUCCESS;
1438 }
1439