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