controls.c 50.8 KB
Newer Older
1
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
2
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
4
 * Copyright 1998-2020 The OpenLDAP Foundation.
5
6
 * All rights reserved.
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
7
8
9
10
11
12
13
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
14
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
15

16
17
18
#include "portable.h"

#include <stdio.h>
Hallvard Furuseth's avatar
Hallvard Furuseth committed
19
20

#include <ac/string.h>
21
22
23
#include <ac/socket.h>

#include "slap.h"
24
25
#include "ldif.h"
#include "lutil.h"
26
27
28

#include "../../libraries/liblber/lber-int.h"

29
static SLAP_CTRL_PARSE_FN parseAssert;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
30
static SLAP_CTRL_PARSE_FN parseDomainScope;
31
static SLAP_CTRL_PARSE_FN parseDontUseCopy;
32
static SLAP_CTRL_PARSE_FN parseManageDSAit;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
33
static SLAP_CTRL_PARSE_FN parseNoOp;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
34
static SLAP_CTRL_PARSE_FN parsePagedResults;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
35
36
37
38
39
static SLAP_CTRL_PARSE_FN parsePermissiveModify;
static SLAP_CTRL_PARSE_FN parsePreRead, parsePostRead;
static SLAP_CTRL_PARSE_FN parseProxyAuthz;
static SLAP_CTRL_PARSE_FN parseRelax;
static SLAP_CTRL_PARSE_FN parseSearchOptions;
40
#ifdef SLAP_CONTROL_X_SORTEDRESULTS
41
42
static SLAP_CTRL_PARSE_FN parseSortedResults;
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
43
static SLAP_CTRL_PARSE_FN parseSubentries;
44
#ifdef SLAP_CONTROL_X_TREE_DELETE
45
static SLAP_CTRL_PARSE_FN parseTreeDelete;
46
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
47
static SLAP_CTRL_PARSE_FN parseValuesReturnFilter;
48
49
50
#ifdef SLAP_CONTROL_X_SESSION_TRACKING
static SLAP_CTRL_PARSE_FN parseSessionTracking;
#endif
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
51
52
53
#ifdef SLAP_CONTROL_X_WHATFAILED
static SLAP_CTRL_PARSE_FN parseWhatFailed;
#endif
54

Kurt Zeilenga's avatar
Kurt Zeilenga committed
55
56
#undef sc_mask /* avoid conflict with Irix 6.5 <sys/signal.h> */

57
58
59
const struct berval slap_pre_read_bv = BER_BVC(LDAP_CONTROL_PRE_READ);
const struct berval slap_post_read_bv = BER_BVC(LDAP_CONTROL_POST_READ);

Howard Chu's avatar
Howard Chu committed
60
61
struct slap_control_ids slap_cids;

62
struct slap_control {
63
	/* Control OID */
64
	char *sc_oid;
65

Howard Chu's avatar
Howard Chu committed
66
67
68
	/* The controlID for this control */
	int sc_cid;

69
	/* Operations supported by control */
70
	slap_mask_t sc_mask;
71

72
	/* Extended operations supported by control */
73
74
	char **sc_extendedops;		/* input */
	BerVarray sc_extendedopsbv;	/* run-time use */
75

76
	/* Control parsing callback */
77
	SLAP_CTRL_PARSE_FN *sc_parse;
78

79
	LDAP_SLIST_ENTRY(slap_control) sc_next;
80
81
};

82
83
static LDAP_SLIST_HEAD(ControlsList, slap_control) controls_list
	= LDAP_SLIST_HEAD_INITIALIZER(&controls_list);
84

85
/*
86
 * all known request control OIDs should be added to this list
87
 */
88
89
90
91
92
93
94
95
96
97
98
/*
 * NOTE: initialize num_known_controls to 1 so that cid = 0 always
 * addresses an undefined control; this allows to safely test for 
 * well known controls even if they are not registered, e.g. if 
 * they get moved to modules.  An example is sc_LDAPsync, which 
 * is implemented in the syncprov overlay and thus, if configured 
 * as dynamic module, may not be registered.  One side effect is that 
 * slap_known_controls[0] == NULL, so it should always be used 
 * starting from 1.
 * FIXME: should we define the "undefined control" oid?
 */
99
char *slap_known_controls[SLAP_MAX_CIDS+1];
100
static int num_known_controls = 1;
101

102
103
static char *proxy_authz_extops[] = {
	LDAP_EXOP_MODIFY_PASSWD,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
104
	LDAP_EXOP_WHO_AM_I,
105
	LDAP_EXOP_REFRESH,
106
107
108
	NULL
};

109
static char *manageDSAit_extops[] = {
110
	LDAP_EXOP_REFRESH,
111
112
113
	NULL
};

114
115
116
117
118
119
120
121
122
#ifdef SLAP_CONTROL_X_SESSION_TRACKING
static char *session_tracking_extops[] = {
	LDAP_EXOP_MODIFY_PASSWD,
	LDAP_EXOP_WHO_AM_I,
	LDAP_EXOP_REFRESH,
	NULL
};
#endif

123
static struct slap_control control_defs[] = {
Howard Chu's avatar
Howard Chu committed
124
125
	{  LDAP_CONTROL_ASSERT,
 		(int)offsetof(struct slap_control_ids, sc_assert),
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
126
		SLAP_CTRL_UPDATE|SLAP_CTRL_COMPARE|SLAP_CTRL_SEARCH,
127
		NULL, NULL,
128
		parseAssert, LDAP_SLIST_ENTRY_INITIALIZER(next) },
129
	{ LDAP_CONTROL_PRE_READ,
Howard Chu's avatar
Howard Chu committed
130
 		(int)offsetof(struct slap_control_ids, sc_preRead),
131
132
		SLAP_CTRL_DELETE|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME,
		NULL, NULL,
133
134
		parsePreRead, LDAP_SLIST_ENTRY_INITIALIZER(next) },
	{ LDAP_CONTROL_POST_READ,
Howard Chu's avatar
Howard Chu committed
135
 		(int)offsetof(struct slap_control_ids, sc_postRead),
136
137
		SLAP_CTRL_ADD|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME,
		NULL, NULL,
138
		parsePostRead, LDAP_SLIST_ENTRY_INITIALIZER(next) },
139
 	{ LDAP_CONTROL_VALUESRETURNFILTER,
Howard Chu's avatar
Howard Chu committed
140
 		(int)offsetof(struct slap_control_ids, sc_valuesReturnFilter),
141
142
 		SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH,
		NULL, NULL,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
143
		parseValuesReturnFilter, LDAP_SLIST_ENTRY_INITIALIZER(next) },
144
	{ LDAP_CONTROL_PAGEDRESULTS,
Howard Chu's avatar
Howard Chu committed
145
 		(int)offsetof(struct slap_control_ids, sc_pagedResults),
146
147
		SLAP_CTRL_SEARCH,
		NULL, NULL,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
148
		parsePagedResults, LDAP_SLIST_ENTRY_INITIALIZER(next) },
149
#ifdef SLAP_CONTROL_X_SORTEDRESULTS
150
151
	{ LDAP_CONTROL_SORTREQUEST,
 		(int)offsetof(struct slap_control_ids, sc_sortedResults),
152
153
		SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH|SLAP_CTRL_HIDE,
		NULL, NULL,
154
155
		parseSortedResults, LDAP_SLIST_ENTRY_INITIALIZER(next) },
#endif
156
	{ LDAP_CONTROL_X_DOMAIN_SCOPE,
Howard Chu's avatar
Howard Chu committed
157
 		(int)offsetof(struct slap_control_ids, sc_domainScope),
158
159
		SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH|SLAP_CTRL_HIDE,
		NULL, NULL,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
160
		parseDomainScope, LDAP_SLIST_ENTRY_INITIALIZER(next) },
Kurt Zeilenga's avatar
Kurt Zeilenga committed
161
162
	{ LDAP_CONTROL_DONTUSECOPY,
 		(int)offsetof(struct slap_control_ids, sc_dontUseCopy),
163
		SLAP_CTRL_GLOBAL|SLAP_CTRL_INTROGATE,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
164
165
		NULL, NULL,
		parseDontUseCopy, LDAP_SLIST_ENTRY_INITIALIZER(next) },
166
	{ LDAP_CONTROL_X_PERMISSIVE_MODIFY,
Howard Chu's avatar
Howard Chu committed
167
 		(int)offsetof(struct slap_control_ids, sc_permissiveModify),
168
169
		SLAP_CTRL_MODIFY|SLAP_CTRL_HIDE,
		NULL, NULL,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
170
		parsePermissiveModify, LDAP_SLIST_ENTRY_INITIALIZER(next) },
Kurt Zeilenga's avatar
Kurt Zeilenga committed
171
#ifdef SLAP_CONTROL_X_TREE_DELETE
172
	{ LDAP_CONTROL_X_TREE_DELETE,
Howard Chu's avatar
Howard Chu committed
173
 		(int)offsetof(struct slap_control_ids, sc_treeDelete),
174
175
		SLAP_CTRL_DELETE|SLAP_CTRL_HIDE,
		NULL, NULL,
176
177
		parseTreeDelete, LDAP_SLIST_ENTRY_INITIALIZER(next) },
#endif
Howard Chu's avatar
Howard Chu committed
178
	{ LDAP_CONTROL_X_SEARCH_OPTIONS,
Howard Chu's avatar
Howard Chu committed
179
 		(int)offsetof(struct slap_control_ids, sc_searchOptions),
180
181
		SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH|SLAP_CTRL_HIDE,
		NULL, NULL,
182
		parseSearchOptions, LDAP_SLIST_ENTRY_INITIALIZER(next) },
183
	{ LDAP_CONTROL_SUBENTRIES,
Howard Chu's avatar
Howard Chu committed
184
 		(int)offsetof(struct slap_control_ids, sc_subentries),
185
186
		SLAP_CTRL_SEARCH,
		NULL, NULL,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
187
		parseSubentries, LDAP_SLIST_ENTRY_INITIALIZER(next) },
188
	{ LDAP_CONTROL_NOOP,
Howard Chu's avatar
Howard Chu committed
189
 		(int)offsetof(struct slap_control_ids, sc_noOp),
190
191
		SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE,
		NULL, NULL,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
192
		parseNoOp, LDAP_SLIST_ENTRY_INITIALIZER(next) },
Kurt Zeilenga's avatar
Kurt Zeilenga committed
193
	{ LDAP_CONTROL_RELAX,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
194
 		(int)offsetof(struct slap_control_ids, sc_relax),
195
196
		SLAP_CTRL_GLOBAL|SLAP_CTRL_UPDATE|SLAP_CTRL_HIDE,
		NULL, NULL,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
197
		parseRelax, LDAP_SLIST_ENTRY_INITIALIZER(next) },
198
199
200
201
202
203
#ifdef LDAP_X_TXN
	{ LDAP_CONTROL_X_TXN_SPEC,
 		(int)offsetof(struct slap_control_ids, sc_txnSpec),
		SLAP_CTRL_UPDATE|SLAP_CTRL_HIDE,
		NULL, NULL,
		txn_spec_ctrl, LDAP_SLIST_ENTRY_INITIALIZER(next) },
204
#endif
205
	{ LDAP_CONTROL_MANAGEDSAIT,
Howard Chu's avatar
Howard Chu committed
206
 		(int)offsetof(struct slap_control_ids, sc_manageDSAit),
207
208
		SLAP_CTRL_ACCESS,
		manageDSAit_extops, NULL,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
209
		parseManageDSAit, LDAP_SLIST_ENTRY_INITIALIZER(next) },
210
	{ LDAP_CONTROL_PROXY_AUTHZ,
Howard Chu's avatar
Howard Chu committed
211
 		(int)offsetof(struct slap_control_ids, sc_proxyAuthz),
212
213
		SLAP_CTRL_GLOBAL|SLAP_CTRL_ACCESS,
		proxy_authz_extops, NULL,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
214
		parseProxyAuthz, LDAP_SLIST_ENTRY_INITIALIZER(next) },
215
216
217
218
219
220
221
#ifdef SLAP_CONTROL_X_SESSION_TRACKING
	{ LDAP_CONTROL_X_SESSION_TRACKING,
 		(int)offsetof(struct slap_control_ids, sc_sessionTracking),
		SLAP_CTRL_GLOBAL|SLAP_CTRL_ACCESS|SLAP_CTRL_BIND|SLAP_CTRL_HIDE,
		session_tracking_extops, NULL,
		parseSessionTracking, LDAP_SLIST_ENTRY_INITIALIZER(next) },
#endif
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
222
223
224
225
226
227
228
229
#ifdef SLAP_CONTROL_X_WHATFAILED
	{ LDAP_CONTROL_X_WHATFAILED,
 		(int)offsetof(struct slap_control_ids, sc_whatFailed),
		SLAP_CTRL_GLOBAL|SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE,
		NULL, NULL,
		parseWhatFailed, LDAP_SLIST_ENTRY_INITIALIZER(next) },
#endif

Howard Chu's avatar
Howard Chu committed
230
	{ NULL, 0, 0, NULL, 0, NULL, LDAP_SLIST_ENTRY_INITIALIZER(next) }
231
232
};

233
234
235
static struct slap_control *
find_ctrl( const char *oid );

236
237
238
239
240
/*
 * Register a supported control.
 *
 * This can be called by an OpenLDAP plugin or, indirectly, by a
 * SLAPI plugin calling slapi_register_supported_control().
241
242
243
 *
 * NOTE: if flags == 1 the control is replaced if already registered;
 * otherwise registering an already registered control is not allowed.
244
245
 */
int
246
register_supported_control2(const char *controloid,
247
248
	slap_mask_t controlmask,
	char **controlexops,
Howard Chu's avatar
Howard Chu committed
249
	SLAP_CTRL_PARSE_FN *controlparsefn,
250
	unsigned flags,
Howard Chu's avatar
Howard Chu committed
251
	int *controlcid)
252
{
253
	struct slap_control *sc = NULL;
254
	int i;
255
	BerVarray extendedopsbv = NULL;
256

257
258
259
	if ( num_known_controls >= SLAP_MAX_CIDS ) {
		Debug( LDAP_DEBUG_ANY, "Too many controls registered."
			" Recompile slapd with SLAP_MAX_CIDS defined > %d\n",
260
		num_known_controls, 0, 0 );
261
262
263
		return LDAP_OTHER;
	}

264
265
266
	if ( controloid == NULL ) {
		return LDAP_PARAM_ERROR;
	}
267

268
	/* check if already registered */
269
	for ( i = 0; slap_known_controls[ i ]; i++ ) {
270
		if ( strcmp( controloid, slap_known_controls[ i ] ) == 0 ) {
271
272
273
274
275
276
277
278
279
280
			if ( flags == 1 ) {
				Debug( LDAP_DEBUG_TRACE,
					"Control %s already registered; replacing.\n",
					controloid, 0, 0 );
				/* (find and) replace existing handler */
				sc = find_ctrl( controloid );
				assert( sc != NULL );
				break;
			}

281
282
283
284
285
286
287
			Debug( LDAP_DEBUG_ANY,
				"Control %s already registered.\n",
				controloid, 0, 0 );
			return LDAP_PARAM_ERROR;
		}
	}

288
	/* turn compatible extended operations into bervals */
289
	if ( controlexops != NULL ) {
290
291
292
293
		int i;

		for ( i = 0; controlexops[ i ]; i++ );

294
295
		extendedopsbv = ber_memcalloc( i + 1, sizeof( struct berval ) );
		if ( extendedopsbv == NULL ) {
296
297
			return LDAP_NO_MEMORY;
		}
298
299

		for ( i = 0; controlexops[ i ]; i++ ) {
300
301
302
303
304
305
306
			ber_str2bv( controlexops[ i ], 0, 1, &extendedopsbv[ i ] );
		}
	}

	if ( sc == NULL ) {
		sc = (struct slap_control *)SLAP_MALLOC( sizeof( *sc ) );
		if ( sc == NULL ) {
Howard Chu's avatar
Howard Chu committed
307
			ber_bvarray_free( extendedopsbv );
308
			return LDAP_NO_MEMORY;
309
310
		}

311
312
313
314
315
316
317
318
319
320
		sc->sc_oid = ch_strdup( controloid );
		sc->sc_cid = num_known_controls;

		/* Update slap_known_controls, too. */
		slap_known_controls[num_known_controls - 1] = sc->sc_oid;
		slap_known_controls[num_known_controls++] = NULL;

		LDAP_SLIST_NEXT( sc, sc_next ) = NULL;
		LDAP_SLIST_INSERT_HEAD( &controls_list, sc, sc_next );

321
	} else {
322
		if ( sc->sc_extendedopsbv ) {
323
324
325
326
327
328
329
330
331
			/* FIXME: in principle, we should rather merge
			 * existing extops with those supported by the
			 * new control handling implementation.
			 * In fact, whether a control is compatible with
			 * an extop should not be a matter of implementation.
			 * We likely also need a means for a newly
			 * registered extop to declare that it is
			 * comptible with an already registered control.
			 */
Howard Chu's avatar
Howard Chu committed
332
333
			ber_bvarray_free( sc->sc_extendedopsbv );
			sc->sc_extendedopsbv = NULL;
334
335
			sc->sc_extendedops = NULL;
		}
336
	}
337

338
339
340
341
342
343
	sc->sc_extendedopsbv = extendedopsbv;
	sc->sc_mask = controlmask;
	sc->sc_parse = controlparsefn;
	if ( controlcid ) {
		*controlcid = sc->sc_cid;
	}
344
345
346
347

	return LDAP_SUCCESS;
}

348
349
350
351
352
353
354
355
356
357
358
359
360
#ifdef SLAP_CONFIG_DELETE
int
unregister_supported_control( const char *controloid )
{
	struct slap_control *sc;
	int i;

	if ( controloid == NULL || (sc = find_ctrl( controloid )) == NULL ){
		return -1;
	}

	for ( i = 0; slap_known_controls[ i ]; i++ ) {
		if ( strcmp( controloid, slap_known_controls[ i ] ) == 0 ) {
361
362
363
			do {
				slap_known_controls[ i ] = slap_known_controls[ i+1 ];
			} while ( slap_known_controls[ i++ ] );
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
			num_known_controls--;
			break;
		}
	}

	LDAP_SLIST_REMOVE(&controls_list, sc, slap_control, sc_next);
	ch_free( sc->sc_oid );
	if ( sc->sc_extendedopsbv != NULL ) {
		ber_bvarray_free( sc->sc_extendedopsbv );
	}
	ch_free( sc );

	return 0;
}
#endif /* SLAP_CONFIG_DELETE */

380
381
382
383
384
385
386
387
388
389
390
/*
 * One-time initialization of internal controls.
 */
int
slap_controls_init( void )
{
	int i, rc;

	rc = LDAP_SUCCESS;

	for ( i = 0; control_defs[i].sc_oid != NULL; i++ ) {
Howard Chu's avatar
Howard Chu committed
391
		int *cid = (int *)(((char *)&slap_cids) + control_defs[i].sc_cid );
392
393
		rc = register_supported_control( control_defs[i].sc_oid,
			control_defs[i].sc_mask, control_defs[i].sc_extendedops,
Howard Chu's avatar
Howard Chu committed
394
			control_defs[i].sc_parse, cid );
395
		if ( rc != LDAP_SUCCESS ) break;
396
397
398
399
400
401
402
403
404
405
	}

	return rc;
}

/*
 * Free memory associated with list of supported controls.
 */
void
controls_destroy( void )
406
{
407
408
409
410
411
412
413
	struct slap_control *sc;

	while ( !LDAP_SLIST_EMPTY(&controls_list) ) {
		sc = LDAP_SLIST_FIRST(&controls_list);
		LDAP_SLIST_REMOVE_HEAD(&controls_list, sc_next);

		ch_free( sc->sc_oid );
414
415
		if ( sc->sc_extendedopsbv != NULL ) {
			ber_bvarray_free( sc->sc_extendedopsbv );
416
		}
Howard Chu's avatar
Howard Chu committed
417
		ch_free( sc );
418
	}
419
420
}

421
422
423
424
425
426
427
/*
 * Format the supportedControl attribute of the root DSE,
 * detailing which controls are supported by the directory
 * server.
 */
int
controls_root_dse_info( Entry *e )
428
{
429
430
431
432
433
434
435
436
437
	AttributeDescription *ad_supportedControl
		= slap_schema.si_ad_supportedControl;
	struct berval vals[2];
	struct slap_control *sc;

	vals[1].bv_val = NULL;
	vals[1].bv_len = 0;

	LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
438
439
		if( sc->sc_mask & SLAP_CTRL_HIDE ) continue;

440
441
		vals[0].bv_val = sc->sc_oid;
		vals[0].bv_len = strlen( sc->sc_oid );
442
443

		if ( attr_merge( e, ad_supportedControl, vals, NULL ) ) {
444
			return -1;
445
		}
446
447
448
	}

	return 0;
449
450
}

451
452
453
454
455
456
457
458
/*
 * Return a list of OIDs and operation masks for supported
 * controls. Used by SLAPI.
 */
int
get_supported_controls(char ***ctrloidsp,
	slap_mask_t **ctrlmasks)
{
Howard Chu's avatar
Howard Chu committed
459
	int n;
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
	char **oids;
	slap_mask_t *masks;
	struct slap_control *sc;

	n = 0;

	LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
		n++;
	}

	if ( n == 0 ) {
		*ctrloidsp = NULL;
		*ctrlmasks = NULL;
		return LDAP_SUCCESS;
	}

	oids = (char **)SLAP_MALLOC( (n + 1) * sizeof(char *) );
	if ( oids == NULL ) {
		return LDAP_NO_MEMORY;
	}
	masks = (slap_mask_t *)SLAP_MALLOC( (n + 1) * sizeof(slap_mask_t) );
	if  ( masks == NULL ) {
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
482
		SLAP_FREE( oids );
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
		return LDAP_NO_MEMORY;
	}

	n = 0;

	LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
		oids[n] = ch_strdup( sc->sc_oid );
		masks[n] = sc->sc_mask;
		n++;
	}
	oids[n] = NULL;
	masks[n] = 0;

	*ctrloidsp = oids;
	*ctrlmasks = masks;

	return LDAP_SUCCESS;
}

/*
 * Find a control given its OID.
 */
505
506
507
static struct slap_control *
find_ctrl( const char *oid )
{
508
509
510
511
512
	struct slap_control *sc;

	LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
		if ( strcmp( oid, sc->sc_oid ) == 0 ) {
			return sc;
513
514
		}
	}
515

516
517
518
	return NULL;
}

Howard Chu's avatar
Howard Chu committed
519
520
521
522
523
int
slap_find_control_id(
	const char *oid,
	int *cid )
{
524
	struct slap_control *ctrl = find_ctrl( oid );
Howard Chu's avatar
Howard Chu committed
525
526
	if ( ctrl ) {
		if ( cid ) *cid = ctrl->sc_cid;
Howard Chu's avatar
Howard Chu committed
527
528
529
530
531
		return LDAP_SUCCESS;
	}
	return LDAP_CONTROL_NOT_FOUND;
}

532
int
533
slap_global_control( Operation *op, const char *oid, int *cid )
534
535
536
537
538
539
540
541
{
	struct slap_control *ctrl = find_ctrl( oid );

	if ( ctrl == NULL ) {
		/* should not be reachable */
		Debug( LDAP_DEBUG_ANY,
			"slap_global_control: unrecognized control: %s\n",      
			oid, 0, 0 );
542
		return LDAP_CONTROL_NOT_FOUND;
543
544
	}

545
546
	if ( cid ) *cid = ctrl->sc_cid;

547
	if ( ( ctrl->sc_mask & SLAP_CTRL_GLOBAL ) ||
Kurt Zeilenga's avatar
Kurt Zeilenga committed
548
549
		( ( op->o_tag & LDAP_REQ_SEARCH ) &&
		( ctrl->sc_mask & SLAP_CTRL_GLOBAL_SEARCH ) ) )
550
	{
551
		return LDAP_COMPARE_TRUE;
552
553
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
554
#if 0
555
	Debug( LDAP_DEBUG_TRACE,
556
557
		"slap_global_control: unavailable control: %s\n",      
		oid, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
558
#endif
559

560
	return LDAP_COMPARE_FALSE;
561
562
}

563
564
void slap_free_ctrls(
	Operation *op,
565
	LDAPControl **ctrls )
566
567
568
{
	int i;

Howard Chu's avatar
Howard Chu committed
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
	if( ctrls == op->o_ctrls ) {
		if( op->o_assertion != NULL ) {
			filter_free_x( op, op->o_assertion, 1 );
			op->o_assertion = NULL;
		}
		if( op->o_vrFilter != NULL) {
			vrFilter_free( op, op->o_vrFilter );
			op->o_vrFilter = NULL;
		}
		if( op->o_preread_attrs != NULL ) {
			op->o_tmpfree( op->o_preread_attrs, op->o_tmpmemctx );
			op->o_preread_attrs = NULL;
		}
		if( op->o_postread_attrs != NULL ) {
			op->o_tmpfree( op->o_postread_attrs, op->o_tmpmemctx );
			op->o_postread_attrs = NULL;
		}
		if( op->o_pagedresults_state != NULL ) {
			op->o_tmpfree( op->o_pagedresults_state, op->o_tmpmemctx );
			op->o_pagedresults_state = NULL;
		}
Howard Chu's avatar
Howard Chu committed
590
591
	}

592
	for (i=0; ctrls[i]; i++) {
593
		op->o_tmpfree(ctrls[i], op->o_tmpmemctx );
594
595
596
597
	}
	op->o_tmpfree( ctrls, op->o_tmpmemctx );
}

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
int slap_add_ctrls(
	Operation *op,
	SlapReply *rs,
	LDAPControl **ctrls )
{
	int i = 0, j;
	LDAPControl **ctrlsp;

	if ( rs->sr_ctrls ) {
		for ( ; rs->sr_ctrls[ i ]; i++ ) ;
	}

	for ( j=0; ctrls[j]; j++ ) ;

	ctrlsp = op->o_tmpalloc(( i+j+1 )*sizeof(LDAPControl *), op->o_tmpmemctx );
	i = 0;
	if ( rs->sr_ctrls ) {
		for ( ; rs->sr_ctrls[i]; i++ )
			ctrlsp[i] = rs->sr_ctrls[i];
	}
	for ( j=0; ctrls[j]; j++)
		ctrlsp[i++] = ctrls[j];
	ctrlsp[i] = NULL;

	if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED )
		op->o_tmpfree( rs->sr_ctrls, op->o_tmpmemctx );
	rs->sr_ctrls = ctrlsp;
	rs->sr_flags |= REP_CTRLS_MUSTBEFREED;
	return i;
}

629
630
631
632
633
634
635
int slap_parse_ctrl(
	Operation *op,
	SlapReply *rs,
	LDAPControl *control,
	const char **text )
{
	struct slap_control *sc;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
636
	int rc = LDAP_SUCCESS;
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672

	sc = find_ctrl( control->ldctl_oid );
	if( sc != NULL ) {
		/* recognized control */
		slap_mask_t tagmask;
		switch( op->o_tag ) {
		case LDAP_REQ_ADD:
			tagmask = SLAP_CTRL_ADD;
			break;
		case LDAP_REQ_BIND:
			tagmask = SLAP_CTRL_BIND;
			break;
		case LDAP_REQ_COMPARE:
			tagmask = SLAP_CTRL_COMPARE;
			break;
		case LDAP_REQ_DELETE:
			tagmask = SLAP_CTRL_DELETE;
			break;
		case LDAP_REQ_MODIFY:
			tagmask = SLAP_CTRL_MODIFY;
			break;
		case LDAP_REQ_RENAME:
			tagmask = SLAP_CTRL_RENAME;
			break;
		case LDAP_REQ_SEARCH:
			tagmask = SLAP_CTRL_SEARCH;
			break;
		case LDAP_REQ_UNBIND:
			tagmask = SLAP_CTRL_UNBIND;
			break;
		case LDAP_REQ_ABANDON:
			tagmask = SLAP_CTRL_ABANDON;
			break;
		case LDAP_REQ_EXTENDED:
			tagmask=~0L;
			assert( op->ore_reqoid.bv_val != NULL );
673
			if( sc->sc_extendedopsbv != NULL ) {
674
				int i;
675
676
677
				for( i=0; !BER_BVISNULL( &sc->sc_extendedopsbv[i] ); i++ ) {
					if( bvmatch( &op->ore_reqoid,
						&sc->sc_extendedopsbv[i] ) )
678
679
680
681
682
683
684
685
686
687
688
689
690
691
					{
						tagmask=0L;
						break;
					}
				}
			}
			break;
		default:
			*text = "controls internal error";
			return LDAP_OTHER;
		}

		if (( sc->sc_mask & tagmask ) == tagmask ) {
			/* available extension */
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
692
693
694
			if ( sc->sc_parse ) {
				rc = sc->sc_parse( op, rs, control );
				assert( rc != LDAP_UNAVAILABLE_CRITICAL_EXTENSION );
695

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
696
			} else if ( control->ldctl_iscritical ) {
697
				*text = "not yet implemented";
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
698
				rc = LDAP_OTHER;
699
700
701
			}


Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
702
		} else if ( control->ldctl_iscritical ) {
703
704
			/* unavailable CRITICAL control */
			*text = "critical extension is unavailable";
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
705
			rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
706
		}
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
707
708

	} else if ( control->ldctl_iscritical ) {
709
710
		/* unrecognized CRITICAL control */
		*text = "critical extension is not recognized";
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
711
		rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
712
713
	}

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
714
	return rc;
715
716
}

717
718
int get_ctrls(
	Operation *op,
719
	SlapReply *rs,
720
721
	int sendres )
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
722
	int nctrls = 0;
723
724
725
726
	ber_tag_t tag;
	ber_len_t len;
	char *opaque;
	BerElement *ber = op->o_ber;
727
	struct berval bv;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
728
729
730
731
732
733
734
735
736
#ifdef SLAP_CONTROL_X_WHATFAILED
	/* NOTE: right now, slapd checks the validity of each control
	 * while parsing.  As a consequence, it can only detect one
	 * cause of failure at a time.  This results in returning
	 * exactly one OID with the whatFailed control, or no control
	 * at all.
	 */
	char *failed_oid = NULL;
#endif
737
738
739
740
741

	len = ber_pvt_ber_remaining(ber);

	if( len == 0) {
		/* no controls */
742
743
		rs->sr_err = LDAP_SUCCESS;
		return rs->sr_err;
744
745
746
747
	}

	if(( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) {
		if( tag == LBER_ERROR ) {
748
749
			rs->sr_err = SLAPD_DISCONNECT;
			rs->sr_text = "unexpected data in PDU";
750
751
752
753
754
		}

		goto return_results;
	}

755
756
757
	Debug( LDAP_DEBUG_TRACE,
		"=> get_ctrls\n", 0, 0, 0 );

758
	if( op->o_protocol < LDAP_VERSION3 ) {
759
760
		rs->sr_err = SLAPD_DISCONNECT;
		rs->sr_text = "controls require LDAPv3";
761
762
763
		goto return_results;
	}

764
	/* one for first control, one for termination */
765
	op->o_ctrls = op->o_tmpalloc( 2 * sizeof(LDAPControl *), op->o_tmpmemctx );
766
767

#if 0
768
	if( op->ctrls == NULL ) {
769
770
		rs->sr_err = LDAP_NO_MEMORY;
		rs->sr_text = "no memory";
771
772
773
774
		goto return_results;
	}
#endif

Pierangelo Masarati's avatar
Pierangelo Masarati committed
775
	op->o_ctrls[nctrls] = NULL;
776

777
	/* step through each element */
778
779
780
781
	for( tag = ber_first_element( ber, &len, &opaque );
		tag != LBER_ERROR;
		tag = ber_next_element( ber, &len, opaque ) )
	{
782
		LDAPControl *c;
783
784
		LDAPControl **tctrls;

785
786
		c = op->o_tmpalloc( sizeof(LDAPControl), op->o_tmpmemctx );
		memset(c, 0, sizeof(LDAPControl));
787
788
789
790

		/* allocate pointer space for current controls (nctrls)
		 * + this control + extra NULL
		 */
Howard Chu's avatar
Howard Chu committed
791
		tctrls = op->o_tmprealloc( op->o_ctrls,
792
			(nctrls+2) * sizeof(LDAPControl *), op->o_tmpmemctx );
793
794
795

#if 0
		if( tctrls == NULL ) {
796
797
798
			ch_free( c );
			ldap_controls_free(op->o_ctrls);
			op->o_ctrls = NULL;
799

800
801
			rs->sr_err = LDAP_NO_MEMORY;
			rs->sr_text = "no memory";
802
803
804
			goto return_results;
		}
#endif
805
		op->o_ctrls = tctrls;
806

807
808
		op->o_ctrls[nctrls++] = c;
		op->o_ctrls[nctrls] = NULL;
809

810
811
		tag = ber_scanf( ber, "{m" /*}*/, &bv );
		c->ldctl_oid = bv.bv_val;
812

813
814
815
		if( tag == LBER_ERROR ) {
			Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get oid failed.\n",
				0, 0, 0 );
816

817
			slap_free_ctrls( op, op->o_ctrls );
818
			op->o_ctrls = NULL;
819
820
			rs->sr_err = SLAPD_DISCONNECT;
			rs->sr_text = "decoding controls error";
821
			goto return_results;
822
823
824

		} else if( c->ldctl_oid == NULL ) {
			Debug( LDAP_DEBUG_TRACE,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
825
				"get_ctrls: conn %lu got empty OID.\n",
826
				op->o_connid, 0, 0 );
827

828
			slap_free_ctrls( op, op->o_ctrls );
829
			op->o_ctrls = NULL;
830
831
			rs->sr_err = LDAP_PROTOCOL_ERROR;
			rs->sr_text = "OID field is empty";
832
			goto return_results;
833
834
		}

835
836
		tag = ber_peek_tag( ber, &len );

837
838
839
840
		if( tag == LBER_BOOLEAN ) {
			ber_int_t crit;
			tag = ber_scanf( ber, "b", &crit );

841
842
843
			if( tag == LBER_ERROR ) {
				Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get crit failed.\n",
					0, 0, 0 );
844
				slap_free_ctrls( op, op->o_ctrls );
845
				op->o_ctrls = NULL;
846
847
				rs->sr_err = SLAPD_DISCONNECT;
				rs->sr_text = "decoding controls error";
848
849
850
				goto return_results;
			}

851
			c->ldctl_iscritical = (crit != 0);
852
853
854
855
			tag = ber_peek_tag( ber, &len );
		}

		if( tag == LBER_OCTETSTRING ) {
856
			tag = ber_scanf( ber, "m", &c->ldctl_value );
857

858
			if( tag == LBER_ERROR ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
859
				Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: conn %lu: "
860
					"%s (%scritical): get value failed.\n",
861
					op->o_connid, c->ldctl_oid,
862
					c->ldctl_iscritical ? "" : "non" );
863
				slap_free_ctrls( op, op->o_ctrls );
864
				op->o_ctrls = NULL;
865
866
				rs->sr_err = SLAPD_DISCONNECT;
				rs->sr_text = "decoding controls error";
867
868
				goto return_results;
			}
869
870
		}

871
872
873
		Debug( LDAP_DEBUG_TRACE,
			"=> get_ctrls: oid=\"%s\" (%scritical)\n",
			c->ldctl_oid, c->ldctl_iscritical ? "" : "non", 0 );
874

875
876
		rs->sr_err = slap_parse_ctrl( op, rs, c, &rs->sr_text );
		if ( rs->sr_err != LDAP_SUCCESS ) {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
877
878
879
#ifdef SLAP_CONTROL_X_WHATFAILED
			failed_oid = c->ldctl_oid;
#endif
880
881
882
883
884
			goto return_results;
		}
	}

return_results:
885
886
	Debug( LDAP_DEBUG_TRACE,
		"<= get_ctrls: n=%d rc=%d err=\"%s\"\n",
887
		nctrls, rs->sr_err, rs->sr_text ? rs->sr_text : "");
Kurt Zeilenga's avatar
Kurt Zeilenga committed
888

889
890
891
892
893
	if( sendres && rs->sr_err != LDAP_SUCCESS ) {
		if( rs->sr_err == SLAPD_DISCONNECT ) {
			rs->sr_err = LDAP_PROTOCOL_ERROR;
			send_ldap_disconnect( op, rs );
			rs->sr_err = SLAPD_DISCONNECT;
894
		} else {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
#ifdef SLAP_CONTROL_X_WHATFAILED
			/* might have not been parsed yet? */
			if ( failed_oid != NULL ) {
				if ( !get_whatFailed( op ) ) {
					/* look it up */

					/* step through each remaining element */
					for ( ; tag != LBER_ERROR; tag = ber_next_element( ber, &len, opaque ) )
					{
						LDAPControl c = { 0 };

						tag = ber_scanf( ber, "{m" /*}*/, &bv );
						c.ldctl_oid = bv.bv_val;

						if ( tag == LBER_ERROR ) {
							slap_free_ctrls( op, op->o_ctrls );
							op->o_ctrls = NULL;
							break;

						} else if ( c.ldctl_oid == NULL ) {
							slap_free_ctrls( op, op->o_ctrls );
							op->o_ctrls = NULL;
							break;
						}

						tag = ber_peek_tag( ber, &len );
						if ( tag == LBER_BOOLEAN ) {
							ber_int_t crit;
							tag = ber_scanf( ber, "b", &crit );
							if( tag == LBER_ERROR ) {
								slap_free_ctrls( op, op->o_ctrls );
								op->o_ctrls = NULL;
								break;
							}

							tag = ber_peek_tag( ber, &len );
						}

						if ( tag == LBER_OCTETSTRING ) {
							tag = ber_scanf( ber, "m", &c.ldctl_value );

							if( tag == LBER_ERROR ) {
								slap_free_ctrls( op, op->o_ctrls );
								op->o_ctrls = NULL;
								break;
							}
						}

						if ( strcmp( c.ldctl_oid, LDAP_CONTROL_X_WHATFAILED ) == 0 ) {
							const char *text;
							slap_parse_ctrl( op, rs, &c, &text );
							break;
						}
					}
				}

				if ( get_whatFailed( op ) ) {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
952
953
954
					char *oids[ 2 ];
					oids[ 0 ] = failed_oid;
					oids[ 1 ] = NULL;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
955
956
957
958
959
					slap_ctrl_whatFailed_add( op, rs, oids );
				}
			}
#endif

960
			send_ldap_result( op, rs );
961
		}
962
963
	}

964
	return rs->sr_err;
965
}
966

967
968
969
970
971
972
973
974
975
976
977
978
int
slap_remove_control(
	Operation	*op,
	SlapReply	*rs,
	int		ctrl,
	BI_chk_controls	fnc )
{
	int		i, j;

	switch ( op->o_ctrlflag[ ctrl ] ) {
	case SLAP_CONTROL_NONCRITICAL:
		for ( i = 0, j = -1; op->o_ctrls[ i ] != NULL; i++ ) {
979
980
			if ( strcmp( op->o_ctrls[ i ]->ldctl_oid,
				slap_known_controls[ ctrl - 1 ] ) == 0 )
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
			{
				j = i;
			}
		}

		if ( j == -1 ) {
			rs->sr_err = LDAP_OTHER;
			break;
		}

		if ( fnc ) {
			(void)fnc( op, rs );
		}

		op->o_tmpfree( op->o_ctrls[ j ], op->o_tmpmemctx );

		if ( i > 1 ) {
			AC_MEMCPY( &op->o_ctrls[ j ], &op->o_ctrls[ j + 1 ],
				( i - j ) * sizeof( LDAPControl * ) );

		} else {
			op->o_tmpfree( op->o_ctrls, op->o_tmpmemctx );
			op->o_ctrls = NULL;
		}

		op->o_ctrlflag[ ctrl ] = SLAP_CONTROL_IGNORED;

		Debug( LDAP_DEBUG_ANY, "%s: "
			"non-critical control \"%s\" not supported; stripped.\n",
			op->o_log_prefix, slap_known_controls[ ctrl ], 0 );
		/* fall thru */

	case SLAP_CONTROL_IGNORED:
	case SLAP_CONTROL_NONE:
		rs->sr_err = SLAP_CB_CONTINUE;
		break;

	case SLAP_CONTROL_CRITICAL:
		rs->sr_err = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
		if ( fnc ) {
			(void)fnc( op, rs );
		}
		Debug( LDAP_DEBUG_ANY, "%s: "
			"critical control \"%s\" not supported.\n",
			op->o_log_prefix, slap_known_controls[ ctrl ], 0 );
		break;

	default:
		/* handle all cases! */
		assert( 0 );
	}

	return rs->sr_err;
}

1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
static int parseDontUseCopy (
	Operation *op,
	SlapReply *rs,
	LDAPControl *ctrl )
{
	if ( op->o_dontUseCopy != SLAP_CONTROL_NONE ) {
		rs->sr_text = "dontUseCopy control specified multiple times";
		return LDAP_PROTOCOL_ERROR;
	}

1046
1047
	if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
		rs->sr_text = "dontUseCopy control value not absent";
1048
1049
1050
		return LDAP_PROTOCOL_ERROR;
	}

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
1051
1052
1053
1054
1055
1056
1057
	if ( ( global_disallows & SLAP_DISALLOW_DONTUSECOPY_N_CRIT )
		&& !ctrl->ldctl_iscritical )
	{
		rs->sr_text = "dontUseCopy criticality of FALSE not allowed";
		return LDAP_PROTOCOL_ERROR;
	}

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
1058
1059
1060
	op->o_dontUseCopy = ctrl->ldctl_iscritical
		? SLAP_CONTROL_CRITICAL
		: SLAP_CONTROL_NONCRITICAL;
1061
1062
1063
1064

	return LDAP_SUCCESS;
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
1065
static int parseRelax (
1066
1067
1068
1069
	Operation *op,
	SlapReply *rs,
	LDAPControl *ctrl )
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1070
	if ( op->o_relax != SLAP_CONTROL_NONE ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1071
		rs->sr_text = "relax control specified multiple times";
1072
1073
1074
		return LDAP_PROTOCOL_ERROR;
	}

1075
1076
	if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
		rs->sr_text = "relax control value not absent";
1077
1078
1079
		return LDAP_PROTOCOL_ERROR;
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
1080
	op->o_relax = ctrl->ldctl_iscritical
1081
1082
1083
1084
1085
1086
		? SLAP_CONTROL_CRITICAL
		: SLAP_CONTROL_NONCRITICAL;

	return LDAP_SUCCESS;
}

1087
1088
static int parseManageDSAit (
	Operation *op,
1089
1090
	SlapReply *rs,
	LDAPControl *ctrl )
1091
{
Howard Chu's avatar
Howard Chu committed
1092
	if ( op->o_managedsait != SLAP_CONTROL_NONE ) {
1093
		rs->sr_text = "manageDSAit control specified multiple times";
1094
		return LDAP_PROTOCOL_ERROR;
1095
1096
	}

1097
1098
	if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
		rs->sr_text = "manageDSAit control value not absent";
1099
		return LDAP_PROTOCOL_ERROR;
1100
1101
	}

1102
	op->o_managedsait = ctrl->ldctl_iscritical
Howard Chu's avatar
Howard Chu committed
1103
1104
		? SLAP_CONTROL_CRITICAL
		: SLAP_CONTROL_NONCRITICAL;
1105
1106

	return LDAP_SUCCESS;
1107
}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1108

1109
static int parseProxyAuthz (
1110
	Operation *op,
1111
1112
	SlapReply *rs,
	LDAPControl *ctrl )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1113
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1114
	int		rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1115
	struct berval	dn = BER_BVNULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1116

Howard Chu's avatar
Howard Chu committed
1117
	if ( op->o_proxy_authz != SLAP_CONTROL_NONE ) {
1118
		rs->sr_text = "proxy authorization control specified multiple times";
1119
		return LDAP_PROTOCOL_ERROR;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1120
1121
	}

1122
1123
1124
1125
1126
	if ( BER_BVISNULL( &ctrl->ldctl_value )) {
		rs->sr_text = "proxy authorization control value absent";
		return LDAP_PROTOCOL_ERROR;
	}

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
1127
1128
1129
1130
1131
1132
1133
	if ( ( global_disallows & SLAP_DISALLOW_PROXY_AUTHZ_N_CRIT )
		&& !ctrl->ldctl_iscritical )
	{
		rs->sr_text = "proxied authorization criticality of FALSE not allowed";
		return LDAP_PROTOCOL_ERROR;
	}

Pierangelo Masarati's avatar
Pierangelo Masarati committed