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