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