acl.c 14.1 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
2
/* acl.c - routines to parse and check acl's */

Kurt Zeilenga's avatar
Kurt Zeilenga committed
3
4
#include "portable.h"

Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
#include <stdio.h>
6
7
8
9

#include <ac/regex.h>
#include <ac/socket.h>
#include <ac/string.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
10

Kurt Zeilenga's avatar
Kurt Zeilenga committed
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include "slap.h"

extern Attribute	*attr_find();
extern struct acl	*global_acl;
extern int		global_default_access;
extern char		*access2str();
extern char		*dn_normalize_case();

int		acl_access_allowed();
int		access_allowed();
struct acl	*acl_get_applicable();

static int	regex_matches();

Kurt Zeilenga's avatar
Kurt Zeilenga committed
25
26
27
static string_expand(char *newbuf, int bufsiz, char *pattern,
	char *match, regmatch_t *matches);

Kurt Zeilenga's avatar
Kurt Zeilenga committed
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

/*
 * access_allowed - check whether dn is allowed the requested access
 * to entry e, attribute attr, value val.  if val is null, access to
 * the whole attribute is assumed (all values).  this routine finds
 * the applicable acl and calls acl_access_allowed() to make the
 * decision.
 *
 * returns	0	access NOT allowed
 *		1	access allowed
 */

int
access_allowed(
    Backend		*be,
    Connection		*conn,
    Operation		*op,
    Entry		*e,
    char		*attr,
    struct berval	*val,
    char		*dn,
    int			access
)
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
52
53
54
55
56
57
58
	int				rc;
	struct acl		*a;
	char            *edn;

	regmatch_t       matches[MAXREMATCHES];
	int              i;
	int              n;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
59
60
61
62
63

	if ( be == NULL ) {
		return( 0 );
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
	edn = dn_normalize_case( strdup( e->e_dn ) );
	Debug( LDAP_DEBUG_ACL, "\n=> access_allowed: entry (%s) attr (%s)\n",
		e->e_dn, attr, 0 );

	/* the lastmod attributes are ignored by ACL checking */
	if ( strcasecmp( attr, "modifiersname" ) == 0 ||
		strcasecmp( attr, "modifytimestamp" ) == 0 ||
		strcasecmp( attr, "creatorsname" ) == 0 ||
		strcasecmp( attr, "createtimestamp" ) == 0 )
	{
 		Debug( LDAP_DEBUG_ACL, "LASTMOD attribute: %s access allowed\n",
			attr, 0, 0 );
		free( edn );
		return(1);
	}

	memset(matches, 0, sizeof(matches));

	a = acl_get_applicable( be, op, e, attr, edn, MAXREMATCHES, matches );

	if (a) {
		for (i = 0; i < MAXREMATCHES && matches[i].rm_so > 0; i++) {
			Debug( LDAP_DEBUG_ARGS, "=> match[%d]: %d %d ",
				i, matches[i].rm_so, matches[i].rm_eo );

			if( matches[i].rm_so <= matches[0].rm_eo ) {
				for ( n = matches[i].rm_so; n < matches[i].rm_eo; n++) {
					Debug( LDAP_DEBUG_ARGS, "%c", edn[n], 0, 0 );
				}
			}
			Debug( LDAP_DEBUG_ARGS, "\n", 0, 0, 0 );
		}
	}

	rc = acl_access_allowed( a, be, conn, e, val, op, access, edn, matches );
	free( edn );

	Debug( LDAP_DEBUG_ACL, "\n=> access_allowed: exit (%s) attr (%s)\n",
		e->e_dn, attr, 0);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117

	return( rc );
}

/*
 * acl_get_applicable - return the acl applicable to entry e, attribute
 * attr.  the acl returned is suitable for use in subsequent calls to
 * acl_access_allowed().
 */

struct acl *
acl_get_applicable(
    Backend		*be,
    Operation		*op,
    Entry		*e,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
118
119
120
121
    char		*attr,
    char		*edn,
    int			nmatch,
    regmatch_t	*matches
Kurt Zeilenga's avatar
Kurt Zeilenga committed
122
123
)
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
124
	int		i, j;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
125
126
	struct acl	*a;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
127
128
	Debug( LDAP_DEBUG_ACL, "\n=> acl_get: entry (%s) attr (%s)\n",
		e->e_dn, attr, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
129
130
131
132
133
134
135
136

	if ( be_isroot( be, op->o_dn ) ) {
		Debug( LDAP_DEBUG_ACL,
		    "<= acl_get: no acl applicable to database root\n", 0, 0,
		    0 );
		return( NULL );
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
137
138
	Debug( LDAP_DEBUG_ARGS, "=> acl_get: edn %s\n", edn, 0, 0 );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
139
140
	/* check for a backend-specific acl that matches the entry */
	for ( i = 1, a = be->be_acl; a != NULL; a = a->acl_next, i++ ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
141
142
143
144
145
		if (a->acl_dnpat != NULL) {
			Debug( LDAP_DEBUG_TRACE, "=> dnpat: [%d] %s nsub: %d\n", 
				i, a->acl_dnpat, a->acl_dnre.re_nsub);

			if (regexec(&a->acl_dnre, edn, nmatch, matches, 0))
Kurt Zeilenga's avatar
Kurt Zeilenga committed
146
				continue;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
147
148
149
			else
				Debug( LDAP_DEBUG_TRACE, "=> acl_get:[%d]  backend ACL match\n",
					i, 0, 0);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
150
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
151

Kurt Zeilenga's avatar
Kurt Zeilenga committed
152
		if ( a->acl_filter != NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
153
			if ( test_filter( NULL, NULL, NULL, e, a->acl_filter ) != 0 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
154
155
156
				continue;
			}
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
157
158
159

        Debug( LDAP_DEBUG_ARGS, "=> acl_get: [%d] check attr %s\n", i, attr, 0);

Kurt Zeilenga's avatar
Kurt Zeilenga committed
160
		if ( attr == NULL || a->acl_attrs == NULL ||
Kurt Zeilenga's avatar
Kurt Zeilenga committed
161
162
163
164
			charray_inlist( a->acl_attrs, attr ) )
		{
			Debug( LDAP_DEBUG_ACL, "<= acl_get: [%d] backend acl %s attr: %s\n",
				i, e->e_dn, attr );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
165
166
			return( a );
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
167
		matches[0].rm_so = matches[0].rm_eo = -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
168
169
170
171
	}

	/* check for a global acl that matches the entry */
	for ( i = 1, a = global_acl; a != NULL; a = a->acl_next, i++ ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
172
173
174
175
176
		if (a->acl_dnpat != NULL) {
			Debug( LDAP_DEBUG_TRACE, "=> dnpat: [%d] %s nsub: %d\n", 
				i, a->acl_dnpat, a->acl_dnre.re_nsub);

			if (regexec(&a->acl_dnre, edn, nmatch, matches, 0)) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
177
				continue;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
178
179
180
			} else {
				Debug( LDAP_DEBUG_TRACE, "=> acl_get: [%d] global ACL match\n",
					i, 0, 0);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
181
182
			}
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
183

Kurt Zeilenga's avatar
Kurt Zeilenga committed
184
		if ( a->acl_filter != NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
185
			if ( test_filter( NULL, NULL, NULL, e, a->acl_filter ) != 0 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
186
187
188
				continue;
			}
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
189
190
191
192
193
194
195
196

		Debug( LDAP_DEBUG_ARGS, "=> acl_get: [%d] check attr\n", i, 0, 0);

		if ( attr == NULL || a->acl_attrs == NULL ||
			charray_inlist( a->acl_attrs, attr ) )
		{
			Debug( LDAP_DEBUG_ACL, "<= acl_get: [%d] global acl %s attr: %s\n",
				i, e->e_dn, attr );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
197
198
			return( a );
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
199
200

		matches[0].rm_so = matches[0].rm_eo = -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
201
202
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
203
	Debug( LDAP_DEBUG_ACL, "<= acl_get: no match\n", 0, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
	return( NULL );
}

/*
 * acl_access_allowed - check whether the given acl allows dn the
 * 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
 */

int
acl_access_allowed(
    struct acl		*a,
    Backend		*be,
    Connection		*conn,
    Entry		*e,
    struct berval	*val,
    Operation		*op,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
224
225
226
    int			access,
	char		*edn,
	regmatch_t	*matches
Kurt Zeilenga's avatar
Kurt Zeilenga committed
227
228
229
)
{
	int		i;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
230
	char		*odn;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
231
232
233
234
235
	struct access	*b;
	Attribute	*at;
	struct berval	bv;
	int		default_access;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
236
237
238
239
240
241
242
243
244
	Debug( LDAP_DEBUG_ACL,
		"\n=> acl_access_allowed: %s access to entry \"%s\"\n",
		access2str( access ), e->e_dn, 0 );

	Debug( LDAP_DEBUG_ACL,
		"\n=> acl_access_allowed: %s access to value \"%s\" by \"%s\"\n",
	    access2str( access ),
		val ? val->bv_val : "any",
		op->o_dn ?  op->o_dn : "" );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
245
246

	if ( be_isroot( be, op->o_dn ) ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
247
248
		Debug( LDAP_DEBUG_ACL,
			"<= acl_access_allowed: granted to database root\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
249
250
251
252
		    0, 0, 0 );
		return( 1 );
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
253
254
	default_access = be->be_dfltaccess ? be->be_dfltaccess : global_default_access;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
255
256
	if ( a == NULL ) {
		Debug( LDAP_DEBUG_ACL,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
257
		    "<= acl_access_allowed: %s by default (no matching to)\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
258
259
260
261
262
263
264
265
266
267
268
269
		    default_access >= access ? "granted" : "denied", 0, 0 );
		return( default_access >= access );
	}

	odn = NULL;
	if ( op->o_dn != NULL ) {
		odn = dn_normalize_case( strdup( op->o_dn ) );
		bv.bv_val = odn;
		bv.bv_len = strlen( odn );
	}
	for ( i = 1, b = a->acl_access; b != NULL; b = b->a_next, i++ ) {
		if ( b->a_dnpat != NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
270
271
			Debug( LDAP_DEBUG_TRACE, "<= check a_dnpat: %s\n",
				b->a_dnpat, 0, 0);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
272
273
274
275
276
			/*
			 * 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
			 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
277
278
279
			if ( strcasecmp( b->a_dnpat, "self" ) == 0 && 
				op->o_dn != NULL && *(op->o_dn) && e->e_dn != NULL ) 
			{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
280
281
				if ( strcasecmp( edn, op->o_dn ) == 0 ) {
					Debug( LDAP_DEBUG_ACL,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
282
					"<= acl_access_allowed: matched by clause #%d access %s\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
283
284
285
					    i, (b->a_access & ~ACL_SELF) >=
					    access ? "granted" : "denied", 0 );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
286
287
					if ( odn ) free( odn );
					return( (b->a_access & ~ACL_SELF) >= access );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
288
289
				}
			} else {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
290
				if ( regex_matches( b->a_dnpat, odn, edn, matches ) ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
291
					Debug( LDAP_DEBUG_ACL,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
292
				    "<= acl_access_allowed: matched by clause #%d access %s\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
293
294
295
				    i, (b->a_access & ~ACL_SELF) >= access ?
					    "granted" : "denied", 0 );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
296
297
					if ( odn ) free( odn );
					return( (b->a_access & ~ACL_SELF) >= access );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
298
299
300
301
				}
			}
		}
		if ( b->a_addrpat != NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
302
			if ( regex_matches( b->a_addrpat, conn->c_addr, edn, matches ) ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
303
				Debug( LDAP_DEBUG_ACL,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
304
				    "<= acl_access_allowed: matched by clause #%d access %s\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
305
306
307
				    i, (b->a_access & ~ACL_SELF) >= access ?
				    "granted" : "denied", 0 );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
308
				if ( odn ) free( odn );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
309
310
311
312
				return( (b->a_access & ~ACL_SELF) >= access );
			}
		}
		if ( b->a_domainpat != NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
313
314
315
316
			Debug( LDAP_DEBUG_ARGS, "<= check a_domainpath: %s\n",
				b->a_domainpat, 0, 0 );
			if ( regex_matches( b->a_domainpat, conn->c_domain, edn, matches ) ) 
			{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
317
				Debug( LDAP_DEBUG_ACL,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
318
				    "<= acl_access_allowed: matched by clause #%d access %s\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
319
320
321
				    i, (b->a_access & ~ACL_SELF) >= access ?
				    "granted" : "denied", 0 );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
322
				if ( odn ) free( odn );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
323
324
325
326
				return( (b->a_access & ~ACL_SELF) >= access );
			}
		}
		if ( b->a_dnattr != NULL && op->o_dn != NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
327
328
			Debug( LDAP_DEBUG_ARGS, "<= check a_dnattr: %s\n",
				b->a_dnattr, 0, 0);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
329
			/* see if asker is listed in dnattr */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
330
331
			if ( (at = attr_find( e->e_attrs, b->a_dnattr )) != NULL && 
				value_find( at->a_vals, &bv, at->a_syntax, 3 ) == 0 )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
332
			{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
333
334
335
				if ( (b->a_access & ACL_SELF) && 
					(val == NULL || value_cmp( &bv, val, at->a_syntax, 2 )) )
				{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
336
337
338
339
340
					continue;
				}

				if ( odn ) free( odn );
				Debug( LDAP_DEBUG_ACL,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
341
				    "<= acl_acces_allowed: matched by clause #%d access %s\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
342
343
344
345
346
347
348
349
				    i, (b->a_access & ~ACL_SELF) >= access ?
				    "granted" : "denied", 0 );

				return( (b->a_access & ~ACL_SELF) >= access );
			}

			/* asker not listed in dnattr - check for self access */
			if ( ! (b->a_access & ACL_SELF) || val == NULL ||
Kurt Zeilenga's avatar
Kurt Zeilenga committed
350
351
				value_cmp( &bv, val, at->a_syntax, 2 ) != 0 )
			{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
352
353
354
355
356
				continue;
			}

			if ( odn ) free( odn );
			Debug( LDAP_DEBUG_ACL,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
357
				"<= acl_access_allowed: matched by clause #%d (self) access %s\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
358
359
360
361
362
			    i, (b->a_access & ~ACL_SELF) >= access ? "granted"
			    : "denied", 0 );

			return( (b->a_access & ~ACL_SELF) >= access );
		}
363
#ifdef SLAPD_ACLGROUPS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
364
365
366
367
368
		if ( b->a_group != NULL && op->o_dn != NULL ) {
			char buf[512];

			/* 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
Kurt Zeilenga's avatar
Kurt Zeilenga committed
369
			 * the values in the attribute group
Kurt Zeilenga's avatar
Kurt Zeilenga committed
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
			 */
			Debug( LDAP_DEBUG_ARGS, "<= check a_group: %s\n",
				b->a_group, 0, 0);
			Debug( LDAP_DEBUG_ARGS, "<= check a_group: odn: %s\n",
				odn, 0, 0);

			/* see if asker is listed in dnattr */
			string_expand(buf, sizeof(buf), b->a_group, edn, matches);

			if (be_group(be, buf, odn) == 0) {
				Debug( LDAP_DEBUG_ACL,
					"<= acl_access_allowed: matched by clause #%d (group) access granted\n",
					i, 0, 0 );
				if ( odn ) free( odn );
				return( (b->a_access & ~ACL_SELF) >= access );
			}
		}
387
#endif /* SLAPD_ACLGROUPS */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
388
389
390
	}

	if ( odn ) free( odn );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
391
392
	Debug( LDAP_DEBUG_ACL,
		"<= acl_access_allowed: %s by default (no matching by)\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
	    default_access >= access ? "granted" : "denied", 0, 0 );

	return( default_access >= access );
}

/*
 * acl_check_mods - check access control on the given entry to see if
 * it allows the given modifications by the user associated with op.
 * returns	LDAP_SUCCESS	mods allowed ok
 *		anything else	mods not allowed - return is an error
 *				code indicating the problem
 */

int
acl_check_mods(
    Backend	*be,
    Connection	*conn,
    Operation	*op,
    Entry	*e,
    LDAPMod	*mods
)
{
	int		i;
	struct acl	*a;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
417
418
419
	char            *edn;

	edn = dn_normalize_case( strdup( e->e_dn ) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
420
421

	for ( ; mods != NULL; mods = mods->mod_next ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
422
423
424
		regmatch_t       matches[MAXREMATCHES];

		/* the lastmod attributes are ignored by ACL checking */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
425
		if ( strcasecmp( mods->mod_type, "modifiersname" ) == 0 ||
Kurt Zeilenga's avatar
Kurt Zeilenga committed
426
427
428
429
430
431
			strcasecmp( mods->mod_type, "modifytimestamp" ) == 0 ||
			strcasecmp( mods->mod_type, "creatorsname" ) == 0 ||
			strcasecmp( mods->mod_type, "createtimestamp" ) == 0 ) 
		{
			Debug( LDAP_DEBUG_ACL, "LASTMOD attribute: %s access allowed\n",
				mods->mod_type, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
432
433
434
			continue;
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
435
436
		a = acl_get_applicable( be, op, e, mods->mod_type, edn,
			MAXREMATCHES, matches );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
437
438
439
440
441
442
443
444

		switch ( mods->mod_op & ~LDAP_MOD_BVALUES ) {
		case LDAP_MOD_REPLACE:
		case LDAP_MOD_ADD:
			if ( mods->mod_bvalues == NULL ) {
				break;
			}
			for ( i = 0; mods->mod_bvalues[i] != NULL; i++ ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
445
446
447
448
				if ( ! acl_access_allowed( a, be, conn, e, mods->mod_bvalues[i], 
					op, ACL_WRITE, edn, matches) ) 
				{
					free(edn);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
449
450
451
452
453
454
455
456
					return( LDAP_INSUFFICIENT_ACCESS );
				}
			}
			break;

		case LDAP_MOD_DELETE:
			if ( mods->mod_bvalues == NULL ) {
				if ( ! acl_access_allowed( a, be, conn, e,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
457
458
459
					NULL, op, ACL_WRITE, edn, matches) ) 
				{
					free(edn);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
460
461
462
463
464
					return( LDAP_INSUFFICIENT_ACCESS );
				}
				break;
			}
			for ( i = 0; mods->mod_bvalues[i] != NULL; i++ ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
465
466
467
468
				if ( ! acl_access_allowed( a, be, conn, e, mods->mod_bvalues[i], 
					op, ACL_WRITE, edn, matches) ) 
				{
					free(edn);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
469
470
471
472
473
474
475
					return( LDAP_INSUFFICIENT_ACCESS );
				}
			}
			break;
		}
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
476
	free(edn);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
477
478
479
	return( LDAP_SUCCESS );
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
480
481
482
483
484
485
static string_expand(
	char *newbuf,
	int bufsiz,
	char *pat,
	char *match,
	regmatch_t *matches)
Kurt Zeilenga's avatar
Kurt Zeilenga committed
486
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
	int     size;
	char   *sp;
	char   *dp;
	int     flag;

	size = 0;
	newbuf[0] = '\0';

	flag = 0;
	for ( dp = newbuf, sp = pat; size < 512 && *sp ; sp++) {
		/* did we previously see a $ */
		if (flag) {
			if (*sp == '$') {
				*dp++ = '$';
				size++;
			} else if (*sp >= '0' && *sp <= '9' ) {
				int     n;
				int     i;
				char   *ep;
				int     l;

				n = *sp - '0';
				*dp = '\0';
				i = matches[n].rm_so;
				l = matches[n].rm_eo; 
				for ( ; size < 512 && i < l; size++, i++ ) {
					*dp++ = match[i];
					size++;
				}
				*dp = '\0';
			}
			flag = 0;
		} else {
			if (*sp == '$') {
				flag = 1;
			} else {
				*dp++ = *sp;
				size++;
			}
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
527
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
528
	*dp = '\0';
Kurt Zeilenga's avatar
Kurt Zeilenga committed
529

Kurt Zeilenga's avatar
Kurt Zeilenga committed
530
531
	Debug( LDAP_DEBUG_TRACE, "=> string_expand: pattern:  %s\n", pat, 0, 0 );
	Debug( LDAP_DEBUG_TRACE, "=> string_expand: expanded: %s\n", newbuf, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
532
533
534
}

static int
Kurt Zeilenga's avatar
Kurt Zeilenga committed
535
536
537
538
539
540
regex_matches(
	char *pat,				/* pattern to expand and match against */
	char *str,				/* string to match against pattern */
	char *buf,				/* buffer with $N expansion variables */
	regmatch_t *matches		/* offsets in buffer for $N expansion variables */
)
Kurt Zeilenga's avatar
Kurt Zeilenga committed
541
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
542
543
	regex_t re;
	char newbuf[512];
Kurt Zeilenga's avatar
Kurt Zeilenga committed
544
545
	int	rc;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
546
547
548
549
550
551
552
553
	string_expand(newbuf, sizeof(newbuf), pat, buf, matches);
	if (( rc = regcomp(&re, newbuf, REG_EXTENDED|REG_ICASE))) {
		char error[512];
		regerror(rc, &re, error, sizeof(error));

		Debug( LDAP_DEBUG_TRACE,
		    "compile( \"%s\", \"%s\") failed %s\n",
			pat, str, error );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
554
555
556
		return( 0 );
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
557
558
559
560
561
562
563
564
565
	rc = regexec(&re, str, 0, NULL, 0);
	regfree( &re );

	Debug( LDAP_DEBUG_TRACE,
	    "=> regex_matches: string:   %s\n", str, 0, 0 );
	Debug( LDAP_DEBUG_TRACE,
	    "=> regex_matches: rc: %d %s\n",
		rc, !rc ? "matches" : "no matches", 0 );
	return( !rc );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
566
567
}