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