controls.c 44.9 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/>.
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
4
 * Copyright 1998-2008 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
51

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

54
55
56
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
57
58
struct slap_control_ids slap_cids;

59
struct slap_control {
60
	/* Control OID */
61
	char *sc_oid;
62

Howard Chu's avatar
Howard Chu committed
63
64
65
	/* The controlID for this control */
	int sc_cid;

66
	/* Operations supported by control */
67
	slap_mask_t sc_mask;
68

69
	/* Extended operations supported by control */
70
71
	char **sc_extendedops;		/* input */
	BerVarray sc_extendedopsbv;	/* run-time use */
72

73
	/* Control parsing callback */
74
	SLAP_CTRL_PARSE_FN *sc_parse;
75

76
	LDAP_SLIST_ENTRY(slap_control) sc_next;
77
78
};

79
80
static LDAP_SLIST_HEAD(ControlsList, slap_control) controls_list
	= LDAP_SLIST_HEAD_INITIALIZER(&controls_list);
81

82
/*
83
 * all known request control OIDs should be added to this list
84
 */
85
86
87
88
89
90
91
92
93
94
95
/*
 * 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?
 */
96
char *slap_known_controls[SLAP_MAX_CIDS+1];
97
static int num_known_controls = 1;
98

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

106
static char *manageDSAit_extops[] = {
107
	LDAP_EXOP_REFRESH,
108
109
110
	NULL
};

111
112
113
114
115
116
117
118
119
#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

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

223
224
225
static struct slap_control *
find_ctrl( const char *oid );

226
227
228
229
230
/*
 * Register a supported control.
 *
 * This can be called by an OpenLDAP plugin or, indirectly, by a
 * SLAPI plugin calling slapi_register_supported_control().
231
232
233
 *
 * NOTE: if flags == 1 the control is replaced if already registered;
 * otherwise registering an already registered control is not allowed.
234
235
 */
int
236
register_supported_control2(const char *controloid,
237
238
	slap_mask_t controlmask,
	char **controlexops,
Howard Chu's avatar
Howard Chu committed
239
	SLAP_CTRL_PARSE_FN *controlparsefn,
240
	unsigned flags,
Howard Chu's avatar
Howard Chu committed
241
	int *controlcid)
242
{
243
	struct slap_control *sc = NULL;
244
	int i;
245
	BerVarray extendedopsbv = NULL;
246

247
248
249
250
251
252
253
	if ( num_known_controls >= SLAP_MAX_CIDS ) {
		Debug( LDAP_DEBUG_ANY, "Too many controls registered."
			" Recompile slapd with SLAP_MAX_CIDS defined > %d\n",
		SLAP_MAX_CIDS, 0, 0 );
		return LDAP_OTHER;
	}

254
255
256
	if ( controloid == NULL ) {
		return LDAP_PARAM_ERROR;
	}
257

258
	/* check if already registered */
259
	for ( i = 0; slap_known_controls[ i ]; i++ ) {
260
		if ( strcmp( controloid, slap_known_controls[ i ] ) == 0 ) {
261
262
263
264
265
266
267
268
269
270
			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;
			}

271
272
273
274
275
276
277
			Debug( LDAP_DEBUG_ANY,
				"Control %s already registered.\n",
				controloid, 0, 0 );
			return LDAP_PARAM_ERROR;
		}
	}

278
	/* turn compatible extended operations into bervals */
279
	if ( controlexops != NULL ) {
280
281
282
283
		int i;

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

284
285
		extendedopsbv = ber_memcalloc( i + 1, sizeof( struct berval ) );
		if ( extendedopsbv == NULL ) {
286
287
			return LDAP_NO_MEMORY;
		}
288
289

		for ( i = 0; controlexops[ i ]; i++ ) {
290
291
292
293
294
295
296
297
			ber_str2bv( controlexops[ i ], 0, 1, &extendedopsbv[ i ] );
		}
	}

	if ( sc == NULL ) {
		sc = (struct slap_control *)SLAP_MALLOC( sizeof( *sc ) );
		if ( sc == NULL ) {
			return LDAP_NO_MEMORY;
298
299
		}

300
301
302
303
304
305
306
307
308
309
		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 );

310
	} else {
311
		if ( sc->sc_extendedopsbv ) {
312
313
314
315
316
317
318
319
320
			/* 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
321
322
			ber_bvarray_free( sc->sc_extendedopsbv );
			sc->sc_extendedopsbv = NULL;
323
324
			sc->sc_extendedops = NULL;
		}
325
	}
326

327
328
329
330
331
332
	sc->sc_extendedopsbv = extendedopsbv;
	sc->sc_mask = controlmask;
	sc->sc_parse = controlparsefn;
	if ( controlcid ) {
		*controlcid = sc->sc_cid;
	}
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347

	return LDAP_SUCCESS;
}

/*
 * 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
348
		int *cid = (int *)(((char *)&slap_cids) + control_defs[i].sc_cid );
349
350
		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
351
			control_defs[i].sc_parse, cid );
352
		if ( rc != LDAP_SUCCESS ) break;
353
354
355
356
357
358
359
360
361
362
	}

	return rc;
}

/*
 * Free memory associated with list of supported controls.
 */
void
controls_destroy( void )
363
{
364
365
366
367
368
369
370
	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 );
371
372
		if ( sc->sc_extendedopsbv != NULL ) {
			ber_bvarray_free( sc->sc_extendedopsbv );
373
		}
Howard Chu's avatar
Howard Chu committed
374
		ch_free( sc );
375
	}
376
377
}

378
379
380
381
382
383
384
/*
 * Format the supportedControl attribute of the root DSE,
 * detailing which controls are supported by the directory
 * server.
 */
int
controls_root_dse_info( Entry *e )
385
{
386
387
388
389
390
391
392
393
394
	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 ) {
395
396
		if( sc->sc_mask & SLAP_CTRL_HIDE ) continue;

397
398
		vals[0].bv_val = sc->sc_oid;
		vals[0].bv_len = strlen( sc->sc_oid );
399
400

		if ( attr_merge( e, ad_supportedControl, vals, NULL ) ) {
401
			return -1;
402
		}
403
404
405
	}

	return 0;
406
407
}

408
409
410
411
412
413
414
415
/*
 * 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
416
	int n;
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
	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
439
		SLAP_FREE( oids );
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
		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.
 */
462
463
464
static struct slap_control *
find_ctrl( const char *oid )
{
465
466
467
468
469
	struct slap_control *sc;

	LDAP_SLIST_FOREACH( sc, &controls_list, sc_next ) {
		if ( strcmp( oid, sc->sc_oid ) == 0 ) {
			return sc;
470
471
		}
	}
472

473
474
475
	return NULL;
}

Howard Chu's avatar
Howard Chu committed
476
477
478
479
480
int
slap_find_control_id(
	const char *oid,
	int *cid )
{
481
	struct slap_control *ctrl = find_ctrl( oid );
Howard Chu's avatar
Howard Chu committed
482
483
	if ( ctrl ) {
		if ( cid ) *cid = ctrl->sc_cid;
Howard Chu's avatar
Howard Chu committed
484
485
486
487
488
		return LDAP_SUCCESS;
	}
	return LDAP_CONTROL_NOT_FOUND;
}

489
int
490
slap_global_control( Operation *op, const char *oid, int *cid )
491
492
493
494
495
496
497
498
{
	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 );
499
		return LDAP_CONTROL_NOT_FOUND;
500
501
	}

502
503
	if ( cid ) *cid = ctrl->sc_cid;

504
	if ( ( ctrl->sc_mask & SLAP_CTRL_GLOBAL ) ||
Kurt Zeilenga's avatar
Kurt Zeilenga committed
505
506
		( ( op->o_tag & LDAP_REQ_SEARCH ) &&
		( ctrl->sc_mask & SLAP_CTRL_GLOBAL_SEARCH ) ) )
507
	{
508
		return LDAP_COMPARE_TRUE;
509
510
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
511
#if 0
512
	Debug( LDAP_DEBUG_TRACE,
513
514
		"slap_global_control: unavailable control: %s\n",      
		oid, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
515
#endif
516

517
	return LDAP_COMPARE_FALSE;
518
519
}

520
521
void slap_free_ctrls(
	Operation *op,
522
	LDAPControl **ctrls )
523
524
525
526
527
528
529
530
531
{
	int i;

	for (i=0; ctrls[i]; i++) {
		op->o_tmpfree(ctrls[i], op->o_tmpmemctx );
	}
	op->o_tmpfree( ctrls, op->o_tmpmemctx );
}

532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
int slap_parse_ctrl(
	Operation *op,
	SlapReply *rs,
	LDAPControl *control,
	const char **text )
{
	struct slap_control *sc;

	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 );
575
			if( sc->sc_extendedopsbv != NULL ) {
576
				int i;
577
578
579
				for( i=0; !BER_BVISNULL( &sc->sc_extendedopsbv[i] ); i++ ) {
					if( bvmatch( &op->ore_reqoid,
						&sc->sc_extendedopsbv[i] ) )
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
					{
						tagmask=0L;
						break;
					}
				}
			}
			break;
		default:
			*text = "controls internal error";
			return LDAP_OTHER;
		}

		if (( sc->sc_mask & tagmask ) == tagmask ) {
			/* available extension */
			int	rc;

			if( !sc->sc_parse ) {
				*text = "not yet implemented";
				return LDAP_OTHER;
			}

			rc = sc->sc_parse( op, rs, control );
			if ( rc ) {
				assert( rc != LDAP_UNAVAILABLE_CRITICAL_EXTENSION );
				return rc;
			}

		} else if( control->ldctl_iscritical ) {
			/* unavailable CRITICAL control */
			*text = "critical extension is unavailable";
			return LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
		}
	} else if( control->ldctl_iscritical ) {
		/* unrecognized CRITICAL control */
		*text = "critical extension is not recognized";
		return LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
	}

	return LDAP_SUCCESS;
}

621
622
int get_ctrls(
	Operation *op,
623
	SlapReply *rs,
624
625
	int sendres )
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
626
	int nctrls = 0;
627
628
629
630
	ber_tag_t tag;
	ber_len_t len;
	char *opaque;
	BerElement *ber = op->o_ber;
631
	struct berval bv;
632
633
634
635
636

	len = ber_pvt_ber_remaining(ber);

	if( len == 0) {
		/* no controls */
637
638
		rs->sr_err = LDAP_SUCCESS;
		return rs->sr_err;
639
640
641
642
	}

	if(( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) {
		if( tag == LBER_ERROR ) {
643
644
			rs->sr_err = SLAPD_DISCONNECT;
			rs->sr_text = "unexpected data in PDU";
645
646
647
648
649
		}

		goto return_results;
	}

650
651
652
	Debug( LDAP_DEBUG_TRACE,
		"=> get_ctrls\n", 0, 0, 0 );

653
	if( op->o_protocol < LDAP_VERSION3 ) {
654
655
		rs->sr_err = SLAPD_DISCONNECT;
		rs->sr_text = "controls require LDAPv3";
656
657
658
		goto return_results;
	}

659
	/* one for first control, one for termination */
660
	op->o_ctrls = op->o_tmpalloc( 2 * sizeof(LDAPControl *), op->o_tmpmemctx );
661
662

#if 0
663
	if( op->ctrls == NULL ) {
664
665
		rs->sr_err = LDAP_NO_MEMORY;
		rs->sr_text = "no memory";
666
667
668
669
		goto return_results;
	}
#endif

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

672
	/* step through each element */
673
674
675
676
	for( tag = ber_first_element( ber, &len, &opaque );
		tag != LBER_ERROR;
		tag = ber_next_element( ber, &len, opaque ) )
	{
677
		LDAPControl *c;
678
679
		LDAPControl **tctrls;

680
681
		c = op->o_tmpalloc( sizeof(LDAPControl), op->o_tmpmemctx );
		memset(c, 0, sizeof(LDAPControl));
682
683
684
685

		/* allocate pointer space for current controls (nctrls)
		 * + this control + extra NULL
		 */
Howard Chu's avatar
Howard Chu committed
686
		tctrls = op->o_tmprealloc( op->o_ctrls,
687
			(nctrls+2) * sizeof(LDAPControl *), op->o_tmpmemctx );
688
689
690

#if 0
		if( tctrls == NULL ) {
691
692
693
			ch_free( c );
			ldap_controls_free(op->o_ctrls);
			op->o_ctrls = NULL;
694

695
696
			rs->sr_err = LDAP_NO_MEMORY;
			rs->sr_text = "no memory";
697
698
699
			goto return_results;
		}
#endif
700
		op->o_ctrls = tctrls;
701

702
703
		op->o_ctrls[nctrls++] = c;
		op->o_ctrls[nctrls] = NULL;
704

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

708
709
710
		if( tag == LBER_ERROR ) {
			Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get oid failed.\n",
				0, 0, 0 );
711

712
			slap_free_ctrls( op, op->o_ctrls );
713
			op->o_ctrls = NULL;
714
715
			rs->sr_err = SLAPD_DISCONNECT;
			rs->sr_text = "decoding controls error";
716
			goto return_results;
717
718
719
720

		} else if( c->ldctl_oid == NULL ) {
			Debug( LDAP_DEBUG_TRACE,
				"get_ctrls: conn %lu got emtpy OID.\n",
721
				op->o_connid, 0, 0 );
722

723
			slap_free_ctrls( op, op->o_ctrls );
724
			op->o_ctrls = NULL;
725
726
			rs->sr_err = LDAP_PROTOCOL_ERROR;
			rs->sr_text = "OID field is empty";
727
			goto return_results;
728
729
		}

730
731
		tag = ber_peek_tag( ber, &len );

732
733
734
735
		if( tag == LBER_BOOLEAN ) {
			ber_int_t crit;
			tag = ber_scanf( ber, "b", &crit );

736
737
738
			if( tag == LBER_ERROR ) {
				Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get crit failed.\n",
					0, 0, 0 );
739
				slap_free_ctrls( op, op->o_ctrls );
740
				op->o_ctrls = NULL;
741
742
				rs->sr_err = SLAPD_DISCONNECT;
				rs->sr_text = "decoding controls error";
743
744
745
				goto return_results;
			}

746
			c->ldctl_iscritical = (crit != 0);
747
748
749
750
			tag = ber_peek_tag( ber, &len );
		}

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

753
			if( tag == LBER_ERROR ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
754
				Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: conn %lu: "
755
					"%s (%scritical): get value failed.\n",
756
					op->o_connid, c->ldctl_oid,
757
					c->ldctl_iscritical ? "" : "non" );
758
				slap_free_ctrls( op, op->o_ctrls );
759
				op->o_ctrls = NULL;
760
761
				rs->sr_err = SLAPD_DISCONNECT;
				rs->sr_text = "decoding controls error";
762
763
				goto return_results;
			}
764
765
		}

766
767
768
		Debug( LDAP_DEBUG_TRACE,
			"=> get_ctrls: oid=\"%s\" (%scritical)\n",
			c->ldctl_oid, c->ldctl_iscritical ? "" : "non", 0 );
769

770
771
		rs->sr_err = slap_parse_ctrl( op, rs, c, &rs->sr_text );
		if ( rs->sr_err != LDAP_SUCCESS ) {
772
773
774
775
776
			goto return_results;
		}
	}

return_results:
777
778
	Debug( LDAP_DEBUG_TRACE,
		"<= get_ctrls: n=%d rc=%d err=\"%s\"\n",
779
		nctrls, rs->sr_err, rs->sr_text ? rs->sr_text : "");
Kurt Zeilenga's avatar
Kurt Zeilenga committed
780

781
782
783
784
785
	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;
786
		} else {
787
			send_ldap_result( op, rs );
788
		}
789
790
	}

791
	return rs->sr_err;
792
}
793

794
795
796
797
798
799
800
801
802
803
804
805
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++ ) {
806
807
			if ( strcmp( op->o_ctrls[ i ]->ldctl_oid,
				slap_known_controls[ ctrl - 1 ] ) == 0 )
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
			{
				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;
}

863
864
865
866
867
868
869
870
871
872
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;
	}

873
874
	if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
		rs->sr_text = "dontUseCopy control value not absent";
875
876
877
		return LDAP_PROTOCOL_ERROR;
	}

878
	if ( !ctrl->ldctl_iscritical ) {
879
880
881
882
883
884
885
886
		rs->sr_text = "dontUseCopy criticality of FALSE not allowed";
		return LDAP_PROTOCOL_ERROR;
	}

	op->o_dontUseCopy = SLAP_CONTROL_CRITICAL;
	return LDAP_SUCCESS;
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
887
static int parseRelax (
888
889
890
891
	Operation *op,
	SlapReply *rs,
	LDAPControl *ctrl )
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
892
	if ( op->o_relax != SLAP_CONTROL_NONE ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
893
		rs->sr_text = "relax control specified multiple times";
894
895
896
		return LDAP_PROTOCOL_ERROR;
	}

897
898
	if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
		rs->sr_text = "relax control value not absent";
899
900
901
		return LDAP_PROTOCOL_ERROR;
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
902
	op->o_relax = ctrl->ldctl_iscritical
903
904
905
906
907
908
		? SLAP_CONTROL_CRITICAL
		: SLAP_CONTROL_NONCRITICAL;

	return LDAP_SUCCESS;
}

909
910
static int parseManageDSAit (
	Operation *op,
911
912
	SlapReply *rs,
	LDAPControl *ctrl )
913
{
Howard Chu's avatar
Howard Chu committed
914
	if ( op->o_managedsait != SLAP_CONTROL_NONE ) {
915
		rs->sr_text = "manageDSAit control specified multiple times";
916
		return LDAP_PROTOCOL_ERROR;
917
918
	}

919
920
	if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
		rs->sr_text = "manageDSAit control value not absent";
921
		return LDAP_PROTOCOL_ERROR;
922
923
	}

924
	op->o_managedsait = ctrl->ldctl_iscritical
Howard Chu's avatar
Howard Chu committed
925
926
		? SLAP_CONTROL_CRITICAL
		: SLAP_CONTROL_NONCRITICAL;
927
928

	return LDAP_SUCCESS;
929
}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
930

931
static int parseProxyAuthz (
932
	Operation *op,
933
934
	SlapReply *rs,
	LDAPControl *ctrl )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
935
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
936
	int		rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
937
	struct berval	dn = BER_BVNULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
938

Howard Chu's avatar
Howard Chu committed
939
	if ( op->o_proxy_authz != SLAP_CONTROL_NONE ) {
940
		rs->sr_text = "proxy authorization control specified multiple times";
941
		return LDAP_PROTOCOL_ERROR;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
942
943
	}

944
945
946
947
948
	if ( BER_BVISNULL( &ctrl->ldctl_value )) {
		rs->sr_text = "proxy authorization control value absent";
		return LDAP_PROTOCOL_ERROR;
	}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
949
950
951
	if ( !( global_allows & SLAP_ALLOW_PROXY_AUTHZ_ANON )
		&& BER_BVISEMPTY( &op->o_ndn ) )
	{
952
953
		rs->sr_text = "anonymous proxied authorization not allowed";
		return LDAP_PROXIED_AUTHORIZATION_DENIED;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
954
955
	}

956
	op->o_proxy_authz = ctrl->ldctl_iscritical
Howard Chu's avatar
Howard Chu committed
957
958
		? SLAP_CONTROL_CRITICAL
		: SLAP_CONTROL_NONCRITICAL;
959

960
	Debug( LDAP_DEBUG_ARGS,
Hallvard Furuseth's avatar
Hallvard Furuseth committed
961
		"parseProxyAuthz: conn %lu authzid=\"%s\"\n", 
962
		op->o_connid,
963
964
		ctrl->ldctl_value.bv_len ?  ctrl->ldctl_value.bv_val : "anonymous",
		0 );
965

966
	if ( BER_BVISEMPTY( &ctrl->ldctl_value )) {
967
		Debug( LDAP_DEBUG_TRACE,
Hallvard Furuseth's avatar
Hallvard Furuseth committed
968
			"parseProxyAuthz: conn=%lu anonymous\n", 
969
			op->o_connid, 0, 0 );
970
971

		/* anonymous */
972
973
974
		if ( !BER_BVISNULL( &op->o_ndn ) ) {
			op->o_ndn.bv_val[ 0 ] = '\0';
		}
975
		op->o_ndn.bv_len = 0;
976

977
978
979
		if ( !BER_BVISNULL( &op->o_dn ) ) {
			op->o_dn.bv_val[ 0 ] = '\0';
		}
980
		op->o_dn.bv_len = 0;
981
982
983
984

		return LDAP_SUCCESS;
	}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
985
	rc = slap_sasl_getdn( op->o_conn, op, &ctrl->ldctl_value,
Howard Chu's avatar
Howard Chu committed
986
			NULL, &dn, SLAP_GETDN_AUTHZID );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
987

988
989
	/* FIXME: empty DN in proxyAuthz control should be legal... */
	if( rc != LDAP_SUCCESS /* || !dn.bv_len */ ) {
Howard Chu's avatar
Howard Chu committed
990
991
		if ( dn.bv_val ) {
			ch_free( dn.bv_val );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
992
		}
Howard Chu's avatar
Howard Chu committed
993
		rs->sr_text = "authzId mapping failed";
994
		return LDAP_PROXIED_AUTHORIZATION_DENIED;
995
996
997
	}

	Debug( LDAP_DEBUG_TRACE,
Hallvard Furuseth's avatar
Hallvard Furuseth committed
998
		"parseProxyAuthz: conn=%lu \"%s\"\n", 
999
		op->o_connid,
1000
		dn.bv_len ? dn.bv_val : "(NULL)", 0 );
For faster browsing, not all history is shown. View entire blame