acl.c 42.9 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
/* acl.c - routines to parse and check acl's */
2
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
3
/*
Kurt Zeilenga's avatar
Kurt Zeilenga committed
4
 * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
6
 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
7

Kurt Zeilenga's avatar
Kurt Zeilenga committed
8
9
#include "portable.h"

Kurt Zeilenga's avatar
Kurt Zeilenga committed
10
#include <stdio.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
11
12
13
14

#include <ac/regex.h>
#include <ac/socket.h>
#include <ac/string.h>
15

Kurt Zeilenga's avatar
Kurt Zeilenga committed
16
#include "slap.h"
17
#include "sets.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
18

19
20
21
static AccessControl * acl_get(
	AccessControl *ac, int *count,
	Backend *be, Operation *op,
22
	Entry *e,
23
	AttributeDescription *desc,
24
25
26
	int nmatches, regmatch_t *matches );

static slap_control_t acl_mask(
27
	AccessControl *ac, slap_mask_t *mask,
28
	Backend *be, Connection *conn, Operation *op,
29
	Entry *e,
30
	AttributeDescription *desc,
31
	struct berval *val,
32
33
	regmatch_t *matches );

34
#ifdef SLAPD_ACI_ENABLED
35
static int aci_mask(
36
	Backend *be,
37
    Connection *conn,
38
	Operation *op,
39
	Entry *e,
40
	AttributeDescription *desc,
41
42
43
44
45
	struct berval *val,
	struct berval *aci,
	regmatch_t *matches,
	slap_access_t *grant,
	slap_access_t *deny );
46
47
#endif

48
49
50
static int	regex_matches(
	char *pat, char *str, char *buf, regmatch_t *matches);
static void	string_expand(
51
	struct berval *newbuf, char *pattern,
52
	char *match, regmatch_t *matches);
53

54
55
56
57
58
59
60
typedef	struct AciSetCookie {
	Backend *be;
	Entry *e;
	Connection *conn;
	Operation *op;
} AciSetCookie;

61
BVarray aci_set_gather (void *cookie, char *name, struct berval *attr);
62
63
static int aci_match_set ( struct berval *subj, Backend *be,
    Entry *e, Connection *conn, Operation *op, int setref );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
64
65

/*
66
 * access_allowed - check whether op->o_ndn is allowed the requested access
Kurt Zeilenga's avatar
Kurt Zeilenga committed
67
 * to entry e, attribute attr, value val.  if val is null, access to
68
 * the whole attribute is assumed (all values).
Kurt Zeilenga's avatar
Kurt Zeilenga committed
69
 *
70
71
72
73
74
75
76
77
 * This routine loops through all access controls and calls
 * acl_mask() on each applicable access control.
 * The loop exits when a definitive answer is reached or
 * or no more controls remain.
 *
 * returns:
 *		0	access denied
 *		1	access granted
Kurt Zeilenga's avatar
Kurt Zeilenga committed
78
79
80
81
82
83
84
85
 */

int
access_allowed(
    Backend		*be,
    Connection		*conn,
    Operation		*op,
    Entry		*e,
86
	AttributeDescription	*desc,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
87
    struct berval	*val,
88
    slap_access_t	access )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
89
{
90
	int				count;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
91
	AccessControl	*a;
92
#ifdef LDAP_DEBUG
Kurt Zeilenga's avatar
Kurt Zeilenga committed
93
	char accessmaskbuf[ACCESSMASK_MAXLEN];
94
#endif
95
	slap_mask_t mask;
96
	slap_control_t control;
97
98
	const char *attr;
	regmatch_t matches[MAXREMATCHES];
99

100
101
102
	assert( e != NULL );
	assert( desc != NULL );
	assert( access > ACL_NONE );
103

104
	attr = desc->ad_cname.bv_val;
105
106

	assert( attr != NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
107

108
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
109
	LDAP_LOG(( "acl", LDAP_LEVEL_ENTRY,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
110
111
		"access_allowed: conn %d %s access to \"%s\" \"%s\" requested\n",
		conn ? conn->c_connid : -1, access2str( access ), e->e_dn, attr ));
112
#else
113
114
	Debug( LDAP_DEBUG_ACL,
		"=> access_allowed: %s access to \"%s\" \"%s\" requested\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
115
	    access2str( access ), e->e_dn, attr );
116
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
117

118
119
120
121
122
123
124
125
	if ( op == NULL ) {
		/* no-op call */
		return 1;
	}

	if ( be == NULL ) be = &backends[0];
	assert( be != NULL );

126
	/* grant database root access */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
127
	if ( be != NULL && be_isroot( be, &op->o_ndn ) ) {
128
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
129
130
131
		LDAP_LOG(( "acl", LDAP_LEVEL_INFO,
		       "access_allowed: conn %d root access granted\n",
		       conn->c_connid));
132
#else
133
134
135
		Debug( LDAP_DEBUG_ACL,
		    "<= root access granted\n",
			0, 0, 0 );
136
#endif
137
138
		return 1;
	}
139

140
141
142
143
144
	/*
	 * no-user-modification operational attributes are ignored
	 * by ACL_WRITE checking as any found here are not provided
	 * by the user
	 */
145
146
147
	if ( access >= ACL_WRITE && is_at_no_user_mod( desc->ad_type )
		&& desc != slap_schema.si_ad_entry
		&& desc != slap_schema.si_ad_children )
148
	{
149
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
150
151
152
		LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1,
		       "access_allowed: conn %d NoUserMod Operational attribute: %s access granted\n",
		       conn->c_connid, attr ));
153
#else
Gary Williams's avatar
Gary Williams committed
154
		Debug( LDAP_DEBUG_ACL, "NoUserMod Operational attribute:"
155
			" %s access granted\n",
156
			attr, 0, 0 );
157
#endif
158
159
160
161
162
		return 1;
	}

	/* use backend default access if no backend acls */
	if( be != NULL && be->be_acl == NULL ) {
163
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
164
165
166
		LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1,
		       "access_allowed: conn %d backend default %s access %s to \"%s\"\n",
		       conn->c_connid, access2str( access ),
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
167
		       be->be_dfltaccess >= access ? "granted" : "denied", op->o_dn.bv_val ));
168
#else
169
170
171
		Debug( LDAP_DEBUG_ACL,
			"=> access_allowed: backend default %s access %s to \"%s\"\n",
			access2str( access ),
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
172
			be->be_dfltaccess >= access ? "granted" : "denied", op->o_dn.bv_val );
173
#endif
174
175
176
177
178
179
		return be->be_dfltaccess >= access;

#ifdef notdef
	/* be is always non-NULL */
	/* use global default access if no global acls */
	} else if ( be == NULL && global_acl == NULL ) {
180
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
181
182
183
		LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1,
		       "access_allowed: conn %d global default %s access %s to \"%s\"\n",
		       conn->c_connid, access2str( access ),
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
184
		       global_default_access >= access ? "granted" : "denied", op->o_dn.bv_val ));
185
#else
186
187
188
		Debug( LDAP_DEBUG_ACL,
			"=> access_allowed: global default %s access %s to \"%s\"\n",
			access2str( access ),
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
189
			global_default_access >= access ? "granted" : "denied", op->o_dn.bv_val );
190
#endif
191
192
		return global_default_access >= access;
#endif
193
194
	}

195
	ACL_INIT(mask);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
196
	memset(matches, '\0', sizeof(matches));
197
198
199
200
	
	control = ACL_BREAK;
	a = NULL;
	count = 0;
201

202
	while((a = acl_get( a, &count, be, op, e, desc, MAXREMATCHES, matches )) != NULL)
203
204
	{
		int i;
205
206

		for (i = 0; i < MAXREMATCHES && matches[i].rm_so > 0; i++) {
207
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
208
209
210
			LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1,
			       "access_allowed: conn %d match[%d]:  %d %d ",
			       conn->c_connid, i, (int)matches[i].rm_so, (int)matches[i].rm_eo ));
211
#else
212
			Debug( LDAP_DEBUG_ACL, "=> match[%d]: %d %d ", i,
Hallvard Furuseth's avatar
Hallvard Furuseth committed
213
			       (int)matches[i].rm_so, (int)matches[i].rm_eo );
214
#endif
215
			if( matches[i].rm_so <= matches[0].rm_eo ) {
216
				int n;
217
				for ( n = matches[i].rm_so; n < matches[i].rm_eo; n++) {
218
					Debug( LDAP_DEBUG_ACL, "%c", e->e_ndn[n], 0, 0 );
219
220
				}
			}
221
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
222
			LDAP_LOG(( "acl", LDAP_LEVEL_ARGS, "\n" ));
223
#else
224
			Debug( LDAP_DEBUG_ARGS, "\n", 0, 0, 0 );
225
#endif
226
		}
227
228

		control = acl_mask( a, &mask, be, conn, op,
229
			e, desc, val, matches );
230
231
232
233
234

		if ( control != ACL_BREAK ) {
			break;
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
235
		memset(matches, '\0', sizeof(matches));
236
237
	}

238
	if ( ACL_IS_INVALID( mask ) ) {
239
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
240
241
242
		LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1,
		       "access_allowed: conn %d	 \"%s\" (%s) invalid!\n",
		       conn->c_connid, e->e_dn, attr ));
243
#else
244
245
246
		Debug( LDAP_DEBUG_ACL,
			"=> access_allowed: \"%s\" (%s) invalid!\n",
			e->e_dn, attr, 0 );
247
#endif
248
249
250
		ACL_INIT( mask );

	} else if ( control == ACL_BREAK ) {
251
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
252
253
		LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1,
		       "access_allowed: conn %d	 no more rules\n", conn->c_connid ));
254
#else
255
256
		Debug( LDAP_DEBUG_ACL,
			"=> access_allowed: no more rules\n", 0, 0, 0);
257
#endif
258
259
		ACL_INIT( mask );
	}
260

261
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
262
263
	LDAP_LOG(( "acl", LDAP_LEVEL_ENTRY,
		   "access_allowed: conn %d  %s access %s by %s\n",
Gary Williams's avatar
Gary Williams committed
264
		   conn->c_connid,
Gary Williams's avatar
Gary Williams committed
265
266
267
		   access2str( access ),
		   ACL_GRANT( mask, access ) ? "granted" : "denied",
		   accessmask2str( mask, accessmaskbuf ) ));
268
#else
269
	Debug( LDAP_DEBUG_ACL,
270
		"=> access_allowed: %s access %s by %s\n",
271
		access2str( access ),
272
		ACL_GRANT(mask, access) ? "granted" : "denied",
273
		accessmask2str( mask, accessmaskbuf ) );
274
#endif
275
	return ACL_GRANT(mask, access);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
276
277
278
}

/*
279
 * acl_get - return the acl applicable to entry e, attribute
Kurt Zeilenga's avatar
Kurt Zeilenga committed
280
281
282
283
 * attr.  the acl returned is suitable for use in subsequent calls to
 * acl_access_allowed().
 */

284
285
286
287
static AccessControl *
acl_get(
	AccessControl *a,
	int			*count,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
288
    Backend		*be,
289
    Operation	*op,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
290
    Entry		*e,
291
	AttributeDescription *desc,
292
    int			nmatch,
293
    regmatch_t	*matches )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
294
{
295
	const char *attr;
296
297
	int dnlen, patlen;

298
299
	assert( e != NULL );
	assert( count != NULL );
300
	assert( desc != NULL );
301

302
	attr = desc->ad_cname.bv_val;
303
304

	assert( attr != NULL );
305

306
307
308
309
310
	if( a == NULL ) {
		if( be == NULL ) {
			a = global_acl;
		} else {
			a = be->be_acl;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
311
		}
312

313
		assert( a != NULL );
314

315
316
	} else {
		a = a->acl_next;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
317
318
	}

Howard Chu's avatar
Howard Chu committed
319
	dnlen = e->e_nname.bv_len;
320

321
322
323
	for ( ; a != NULL; a = a->acl_next ) {
		(*count) ++;

324
		if (a->acl_dn_pat.bv_len != 0) {
325
			if ( a->acl_dn_style == ACL_STYLE_REGEX ) {
326
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
327
328
				LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1,
					   "acl_get: dnpat [%d] %s nsub: %d\n",
329
					   *count, a->acl_dn_pat.bv_val, (int) a->acl_dn_re.re_nsub ));
330
#else
331
				Debug( LDAP_DEBUG_ACL, "=> dnpat: [%d] %s nsub: %d\n", 
332
					*count, a->acl_dn_pat.bv_val, (int) a->acl_dn_re.re_nsub );
333
#endif
334
335
				if (regexec(&a->acl_dn_re, e->e_ndn, nmatch, matches, 0))
					continue;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
336

337
			} else {
338
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
339
340
				LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1,
					   "acl_get: dn [%d] %s\n",
341
					   *count, a->acl_dn_pat.bv_val ));
342
#else
343
				Debug( LDAP_DEBUG_ACL, "=> dn: [%d] %s\n", 
344
					*count, a->acl_dn_pat.bv_val, 0 );
345
#endif
346
				patlen = a->acl_dn_pat.bv_len;
347
348
349
350
351
352
353
354
355
356
357
358
359
360
				if ( dnlen < patlen )
					continue;

				if ( a->acl_dn_style == ACL_STYLE_BASE ) {
					/* base dn -- entire object DN must match */
					if ( dnlen != patlen )
						continue;

				} else if ( a->acl_dn_style == ACL_STYLE_ONE ) {
					int rdnlen = -1;

					if ( dnlen <= patlen )
						continue;

361
					if ( !DN_SEPARATOR( e->e_ndn[dnlen - patlen - 1] ) || DN_ESCAPE( e->e_ndn[dnlen - patlen - 2] ) )
362
363
						continue;

364
					rdnlen = dn_rdnlen( NULL, &e->e_nname );
365
366
367
368
					if ( rdnlen != dnlen - patlen - 1 )
						continue;

				} else if ( a->acl_dn_style == ACL_STYLE_SUBTREE ) {
369
					if ( dnlen > patlen && ( !DN_SEPARATOR( e->e_ndn[dnlen - patlen - 1] ) || DN_ESCAPE( e->e_ndn[dnlen - patlen - 2] ) ) )
370
371
372
373
374
						continue;

				} else if ( a->acl_dn_style == ACL_STYLE_CHILDREN ) {
					if ( dnlen <= patlen )
						continue;
375
					if ( !DN_SEPARATOR( e->e_ndn[dnlen - patlen - 1] ) || DN_ESCAPE( e->e_ndn[dnlen - patlen - 2] ) )
376
377
378
						continue;
				}

379
				if ( strcmp( a->acl_dn_pat.bv_val, e->e_ndn + dnlen - patlen ) != 0 )
380
					continue;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
381
			}
382

383
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
384
385
386
			LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1,
				   "acl_get: [%d] matched\n",
				   *count ));
387
#else
388
389
			Debug( LDAP_DEBUG_ACL, "=> acl_get: [%d] matched\n",
				*count, 0, 0 );
390
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
391
		}
392

Kurt Zeilenga's avatar
Kurt Zeilenga committed
393
		if ( a->acl_filter != NULL ) {
394
395
			ber_int_t rc = test_filter( NULL, NULL, NULL, e, a->acl_filter );
			if ( rc != LDAP_COMPARE_TRUE ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
396
397
398
				continue;
			}
		}
399

400
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
401
402
403
		LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1,
			   "acl_get: [%d] check attr %s\n",
			   *count, attr ));
404
#else
Gary Williams's avatar
Gary Williams committed
405
406
		Debug( LDAP_DEBUG_ACL, "=> acl_get: [%d] check attr %s\n",
		       *count, attr, 0);
407
#endif
408
		if ( attr == NULL || a->acl_attrs == NULL ||
409
			ad_inlist( desc, a->acl_attrs ) )
410
		{
411
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
412
413
414
			LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1,
				   "acl_get:  [%d] acl %s attr: %s\n",
				   *count, e->e_dn, attr ));
415
#else
416
417
418
			Debug( LDAP_DEBUG_ACL,
				"<= acl_get: [%d] acl %s attr: %s\n",
				*count, e->e_dn, attr );
419
#endif
420
			return a;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
421
		}
422
		matches[0].rm_so = matches[0].rm_eo = -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
423
424
	}

425
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
426
427
	LDAP_LOG(( "acl", LDAP_LEVEL_ENTRY,
		   "acl_get: done.\n" ));
428
#else
429
	Debug( LDAP_DEBUG_ACL, "<= acl_get: done.\n", 0, 0, 0 );
430
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
431
432
433
	return( NULL );
}

434

Kurt Zeilenga's avatar
Kurt Zeilenga committed
435
/*
436
 * acl_mask - modifies mask based upon the given acl and the
Kurt Zeilenga's avatar
Kurt Zeilenga committed
437
438
439
440
441
442
443
 * requested access to entry e, attribute attr, value val.  if val
 * is null, access to the whole attribute is assumed (all values).
 *
 * returns	0	access NOT allowed
 *		1	access allowed
 */

444
445
static slap_control_t
acl_mask(
Kurt Zeilenga's avatar
Kurt Zeilenga committed
446
    AccessControl	*a,
447
	slap_mask_t *mask,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
448
    Backend		*be,
449
450
    Connection	*conn,
    Operation	*op,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
451
    Entry		*e,
452
	AttributeDescription *desc,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
453
    struct berval	*val,
454
	regmatch_t	*matches
Kurt Zeilenga's avatar
Kurt Zeilenga committed
455
456
)
{
457
	int		i, odnlen, patlen;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
458
	Access	*b;
459
#ifdef LDAP_DEBUG
Kurt Zeilenga's avatar
Kurt Zeilenga committed
460
	char accessmaskbuf[ACCESSMASK_MAXLEN];
461
#endif
462
	const char *attr;
463
464
465

	assert( a != NULL );
	assert( mask != NULL );
466
467
	assert( desc != NULL );

468
	attr = desc->ad_cname.bv_val;
469
470

	assert( attr != NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
471

472
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
473
474
475
476
477
478
479
	LDAP_LOG(( "acl", LDAP_LEVEL_ENTRY,
		   "acl_mask: conn %d  access to entry \"%s\", attr \"%s\" requested\n",
		   conn->c_connid, e->e_dn, attr ));

	LDAP_LOG(( "acl", LDAP_LEVEL_ARGS,
		   " to %s by \"%s\", (%s) \n",
		   val ? "value" : "all values",
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
480
		   op->o_ndn.bv_val ? op->o_ndn.bv_val : "",
Gary Williams's avatar
Gary Williams committed
481
		   accessmask2str( *mask, accessmaskbuf ) ));
482
#else
483
	Debug( LDAP_DEBUG_ACL,
484
		"=> acl_mask: access to entry \"%s\", attr \"%s\" requested\n",
485
		e->e_dn, attr, 0 );
486
487

	Debug( LDAP_DEBUG_ACL,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
488
489
		"=> acl_mask: to %s by \"%s\", (%s) \n",
		val ? "value" : "all values",
490
		op->o_ndn.bv_val ?  op->o_ndn.bv_val : "",
491
		accessmask2str( *mask, accessmaskbuf ) );
492
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
493

494
	for ( i = 1, b = a->acl_access; b != NULL; b = b->a_next, i++ ) {
495
		slap_mask_t oldmask, modmask;
496

497
		ACL_INVALIDATE( modmask );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
498

Kurt Zeilenga's avatar
Kurt Zeilenga committed
499
		/* AND <who> clauses */
500
		if ( b->a_dn_pat.bv_len != 0 ) {
501
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
502
503
			LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1,
				   "acl_mask: conn %d  check a_dn_pat: %s\n",
504
				   conn->c_connid, b->a_dn_pat.bv_val ));
505
#else
506
			Debug( LDAP_DEBUG_ACL, "<= check a_dn_pat: %s\n",
507
				b->a_dn_pat.bv_val, 0, 0);
508
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
509
510
511
512
513
			/*
			 * if access applies to the entry itself, and the
			 * user is bound as somebody in the same namespace as
			 * the entry, OR the given dn matches the dn pattern
			 */
514
515
516
			if ( b->a_dn_pat.bv_len == sizeof("anonymous") -1 &&
			    strcmp( b->a_dn_pat.bv_val, "anonymous" ) == 0 ) {
				if (op->o_ndn.bv_len != 0 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
517
518
519
					continue;
				}

520
521
522
			} else if ( b->a_dn_pat.bv_len == sizeof("users") - 1 &&
			    strcmp( b->a_dn_pat.bv_val, "users" ) == 0 ) {
				if (op->o_ndn.bv_len == 0 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
523
524
525
					continue;
				}

526
527
528
			} else if ( b->a_dn_pat.bv_len == sizeof("self") - 1 &&
			    strcmp( b->a_dn_pat.bv_val, "self" ) == 0 ) {
				if( op->o_ndn.bv_len == 0 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
529
530
531
					continue;
				}
				
532
				if ( e->e_dn == NULL || strcmp( e->e_ndn, op->o_ndn.bv_val ) != 0 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
533
534
535
					continue;
				}

536
			} else if ( b->a_dn_style == ACL_STYLE_REGEX ) {
537
538
539
540
				if ( b->a_dn_pat.bv_len != 1 || 
				    strcmp( b->a_dn_pat.bv_val, "*" ) != 0 ) {
					int ret = regex_matches( b->a_dn_pat.bv_val,
						op->o_ndn.bv_val, e->e_ndn, matches );
541
542
543
544
545
546
547
548
549

					if( ret == 0 ) {
						continue;
					}
				}

			} else {
				if ( e->e_dn == NULL )
					continue;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
550

551
552
				patlen = b->a_dn_pat.bv_len;
				odnlen = op->o_ndn.bv_len;
553
				if ( odnlen < patlen )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
554
					continue;
555
556
557
558
559
560
561
562
563
564
565
566

				if ( b->a_dn_style == ACL_STYLE_BASE ) {
					/* base dn -- entire object DN must match */
					if ( odnlen != patlen )
						continue;

				} else if ( b->a_dn_style == ACL_STYLE_ONE ) {
					int rdnlen = -1;

					if ( odnlen <= patlen )
						continue;

567
					if ( !DN_SEPARATOR( op->o_ndn.bv_val[odnlen - patlen - 1] ) || DN_ESCAPE( op->o_ndn.bv_val[odnlen - patlen - 2] ) )
568
569
						continue;

570
					rdnlen = dn_rdnlen( NULL, &op->o_ndn );
571
572
573
574
					if ( rdnlen != odnlen - patlen - 1 )
						continue;

				} else if ( b->a_dn_style == ACL_STYLE_SUBTREE ) {
575
					if ( odnlen > patlen && ( !DN_SEPARATOR( op->o_ndn.bv_val[odnlen - patlen - 1] ) || DN_ESCAPE( op->o_ndn.bv_val[odnlen - patlen - 2] ) ) )
576
577
578
579
580
						continue;

				} else if ( b->a_dn_style == ACL_STYLE_CHILDREN ) {
					if ( odnlen <= patlen )
						continue;
581
					if ( !DN_SEPARATOR( op->o_ndn.bv_val[odnlen - patlen - 1] ) || DN_ESCAPE( op->o_ndn.bv_val[odnlen - patlen - 2] ) )
582
						continue;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
583
				}
584

585
				if ( strcmp( b->a_dn_pat.bv_val, op->o_ndn.bv_val + odnlen - patlen ) != 0 )
586
587
					continue;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
588
589
			}
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
590

591
		if ( b->a_sockurl_pat != NULL ) {
592
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
593
594
595
			LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1,
				   "acl_mask: conn %d  check a_sockurl_pat: %s\n",
				   conn->c_connid, b->a_sockurl_pat ));
596
#else
597
			Debug( LDAP_DEBUG_ACL, "<= check a_sockurl_pat: %s\n",
598
				b->a_sockurl_pat, 0, 0 );
599
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
600

601
602
603
604
605
606
607
608
609
610
611
			if ( strcmp( b->a_sockurl_pat, "*" ) != 0) {
				if ( b->a_sockurl_style == ACL_STYLE_REGEX) {
					if (!regex_matches( b->a_sockurl_pat, conn->c_listener_url,
							e->e_ndn, matches ) ) 
					{
						continue;
					}
				} else {
					if ( strcasecmp( b->a_sockurl_pat, conn->c_listener_url ) == 0 )
						continue;
				}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
612
613
			}
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
614

Kurt Zeilenga's avatar
Kurt Zeilenga committed
615
		if ( b->a_domain_pat != NULL ) {
616
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
617
618
619
			LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1,
				   "acl_mask: conn %d  check a_domain_pat: %s\n",
				   conn->c_connid, b->a_domain_pat ));
620
#else
621
			Debug( LDAP_DEBUG_ACL, "<= check a_domain_pat: %s\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
622
				b->a_domain_pat, 0, 0 );
623
#endif
624
625
626
627
628
629
630
631
632
633
634
			if ( strcmp( b->a_domain_pat, "*" ) != 0) {
				if ( b->a_domain_style == ACL_STYLE_REGEX) {
					if (!regex_matches( b->a_domain_pat, conn->c_peer_domain,
							e->e_ndn, matches ) ) 
					{
						continue;
					}
				} else {
					if ( strcasecmp( b->a_domain_pat, conn->c_peer_domain ) == 0 )
						continue;
				}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
635
636
			}
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
637
638

		if ( b->a_peername_pat != NULL ) {
639
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
640
641
642
			LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1,
				   "acl_mask: conn %d  check a_perrname_path: %s\n",
				   conn->c_connid, b->a_peername_pat ));
643
#else
644
			Debug( LDAP_DEBUG_ACL, "<= check a_peername_path: %s\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
645
				b->a_peername_pat, 0, 0 );
646
#endif
647
648
649
650
651
652
653
654
655
656
657
			if ( strcmp( b->a_peername_pat, "*" ) != 0) {
				if ( b->a_peername_style == ACL_STYLE_REGEX) {
					if (!regex_matches( b->a_peername_pat, conn->c_peer_name,
							e->e_ndn, matches ) ) 
					{
						continue;
					}
				} else {
					if ( strcasecmp( b->a_peername_pat, conn->c_peer_name ) == 0 )
						continue;
				}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
658
659
660
			}
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
661
		if ( b->a_sockname_pat != NULL ) {
662
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
663
664
665
			LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1,
				   "acl_mask: conn %d  check a_sockname_path: %s\n",
				   conn->c_connid, b->a_sockname_pat ));
666
#else
667
			Debug( LDAP_DEBUG_ACL, "<= check a_sockname_path: %s\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
668
				b->a_sockname_pat, 0, 0 );
669
#endif
670
671
672
673
674
675
676
677
678
679
680
			if ( strcmp( b->a_sockname_pat, "*" ) != 0) {
				if ( b->a_sockname_style == ACL_STYLE_REGEX) {
					if (!regex_matches( b->a_sockname_pat, conn->c_sock_name,
							e->e_ndn, matches ) ) 
					{
						continue;
					}
				} else {
					if ( strcasecmp( b->a_sockname_pat, conn->c_sock_name ) == 0 )
						continue;
				}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
681
682
			}
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
683

684
		if ( b->a_dn_at != NULL && op->o_ndn.bv_len != 0 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
685
686
			Attribute	*at;
			struct berval	bv;
687
			int rc, match = 0;
688
			const char *text;
689
			const char *attr = b->a_dn_at->ad_cname.bv_val;
690
691

			assert( attr != NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
692

693
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
694
695
			LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1,
				   "acl_mask: conn %d  check a_dn_pat: %s\n",
696
				   conn->c_connid, attr ));
697
#else
698
			Debug( LDAP_DEBUG_ACL, "<= check a_dn_at: %s\n",
699
				attr, 0, 0);
700
#endif
701
			bv = op->o_ndn;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
702

703
704
			/* see if asker is listed in dnattr */
			for( at = attrs_find( e->e_attrs, b->a_dn_at );
705
706
				at != NULL;
				at = attrs_find( at->a_next, b->a_dn_at ) )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
707
			{
708
				if( value_find( b->a_dn_at, at->a_vals, &bv ) == 0 ) {
709
710
711
					/* found it */
					match = 1;
					break;
712
713
714
				}
			}

715
			if( match ) {
716
717
718
719
720
721
722
723
724
725
				/* have a dnattr match. if this is a self clause then
				 * the target must also match the op dn.
				 */
				if ( b->a_dn_self ) {
					/* check if the target is an attribute. */
					if ( val == NULL )
						continue;
					/* target is attribute, check if the attribute value
					 * is the op dn.
					 */
726
727
728
					rc = value_match( &match, b->a_dn_at,
						b->a_dn_at->ad_type->sat_equality, 0,
						val, &bv, &text );
729
730
731
					/* on match error or no match, fail the ACL clause */
					if (rc != LDAP_SUCCESS || match != 0 )
						continue;
732
				}
733
734
735
736
737
738
739
740
741
742
743
744
			} else {
				/* no dnattr match, check if this is a self clause */
				if ( ! b->a_dn_self )
					continue;
				/* this is a self clause, check if the target is an
				 * attribute.
				 */
				if ( val == NULL )
					continue;
				/* target is attribute, check if the attribute value
				 * is the op dn.
				 */
745
746
747
748
				rc = value_match( &match, b->a_dn_at,
					b->a_dn_at->ad_type->sat_equality, 0,
					val, &bv, &text );

749
750
751
				/* on match error or no match, fail the ACL clause */
				if (rc != LDAP_SUCCESS || match != 0 )
					continue;
752
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
753
		}
754

755
		if ( b->a_group_pat.bv_len && op->o_ndn.bv_len ) {
756
			char buf[1024];
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
757
758
			struct berval bv = { sizeof(buf) - 1, buf };
			struct berval ndn = { 0, NULL };
759
			int rc;
760
761
762

			/* b->a_group is an unexpanded entry name, expanded it should be an 
			 * entry with objectclass group* and we test to see if odn is one of
763
			 * the values in the attribute group
764
765
			 */
			/* see if asker is listed in dnattr */
766
			if ( b->a_group_style == ACL_STYLE_REGEX ) {
767
				string_expand(&bv, b->a_group_pat.bv_val, e->e_ndn, matches);
768
				if ( dnNormalize2(NULL, &bv, &ndn) != LDAP_SUCCESS ) {
769
770
771
					/* did not expand to a valid dn */
					continue;
				}
772
				bv = ndn;
773
			} else {
774
				bv = b->a_group_pat;
775
			}
776

777
778
			rc = backend_group(be, conn, op, e, &bv, &op->o_ndn,
				b->a_group_oc, b->a_group_at);
779
780
			if ( ndn.bv_val )
				free( ndn.bv_val );
781
			if ( rc != 0 )
782
			{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
783
				continue;
784
785
			}
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
786

787
788
		if ( b->a_set_pat.bv_len != 0 ) {
			if (aci_match_set( &b->a_set_pat, be, e, conn, op, 0 ) == 0) {
789
790
791
792
				continue;
			}
		}

793
		if ( b->a_authz.sai_ssf ) {
794
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
795
796
797
			LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1,
				   "acl_mask: conn %d  check a_authz.sai_ssf: ACL %u > OP %u\n",
				   conn->c_connid, b->a_authz.sai_ssf, op->o_ssf ));
798
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
799
800
			Debug( LDAP_DEBUG_ACL, "<= check a_authz.sai_ssf: ACL %u > OP %u\n",
				b->a_authz.sai_ssf, op->o_ssf, 0 );
801
#endif
802
803
804
805
806
807
			if ( b->a_authz.sai_ssf >  op->o_ssf ) {
				continue;
			}
		}

		if ( b->a_authz.sai_transport_ssf ) {
808
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
809
810
811
			LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1,
				   "acl_mask: conn %d  check a_authz.sai_transport_ssf: ACL %u > OP %u\n",
				   conn->c_connid, b->a_authz.sai_transport_ssf, op->o_transport_ssf ));
812
#else
813
			Debug( LDAP_DEBUG_ACL,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
814
815
				"<= check a_authz.sai_transport_ssf: ACL %u > OP %u\n",
				b->a_authz.sai_transport_ssf, op->o_transport_ssf, 0 );
816
#endif
817
818
819
820
821
822
			if ( b->a_authz.sai_transport_ssf >  op->o_transport_ssf ) {
				continue;
			}
		}

		if ( b->a_authz.sai_tls_ssf ) {
823
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
824
825
826
			LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1,
				   "acl_mask: conn %d  check a_authz.sai_tls_ssf: ACL %u > OP %u\n",
				   conn->c_connid, b->a_authz.sai_tls_ssf, op->o_tls_ssf ));
827
#else
828
			Debug( LDAP_DEBUG_ACL,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
829
				"<= check a_authz.sai_tls_ssf: ACL %u > OP %u\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
830
				b->a_authz.sai_tls_ssf, op->o_tls_ssf, 0 );
831
#endif
832
833
834
835
836
837
			if ( b->a_authz.sai_tls_ssf >  op->o_tls_ssf ) {
				continue;
			}
		}

		if ( b->a_authz.sai_sasl_ssf ) {
838
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
839
840
841
			LDAP_LOG(( "acl", LDAP_LEVEL_DETAIL1,
				   "acl_mask: conn %d check a_authz.sai_sasl_ssf: ACL %u > OP %u\n",
				   conn->c_connid, b->a_authz.sai_sasl_ssf, op->o_sasl_ssf ));
842
#else
843
			Debug( LDAP_DEBUG_ACL,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
844
				"<= check a_authz.sai_sasl_ssf: ACL %u > OP %u\n",