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