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