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