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