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