]> git.sur5r.net Git - openldap/blob - servers/slapd/acl.c
5b1f0434b84f1e19589728a7ec6502811c334519
[openldap] / servers / slapd / acl.c
1 /* acl.c - routines to parse and check acl's */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11
12 #include <ac/regex.h>
13 #include <ac/socket.h>
14 #include <ac/string.h>
15
16 #include "slap.h"
17 #include "sets.h"
18 #include "lber_pvt.h"
19
20 #define ACL_BUF_SIZE    1024    /* use most appropriate size */
21
22 /*
23  * speed up compares
24  */
25 static struct berval 
26         aci_bv_entry            = BER_BVC("entry"),
27         aci_bv_children         = BER_BVC("children"),
28         aci_bv_br_entry         = BER_BVC("[entry]"),
29         aci_bv_br_all           = BER_BVC("[all]"),
30         aci_bv_access_id        = BER_BVC("access-id"),
31         aci_bv_anonymous        = BER_BVC("anonymous"),
32         aci_bv_public           = BER_BVC("public"),
33         aci_bv_users            = BER_BVC("users"),
34         aci_bv_self             = BER_BVC("self"),
35         aci_bv_dnattr           = BER_BVC("dnattr"),
36         aci_bv_group            = BER_BVC("group"),
37         aci_bv_role             = BER_BVC("role"),
38         aci_bv_set              = BER_BVC("set"),
39         aci_bv_set_ref          = BER_BVC("set-ref"),
40         aci_bv_grant            = BER_BVC("grant"),
41         aci_bv_deny             = BER_BVC("deny"),
42         
43         aci_bv_group_class      = BER_BVC(SLAPD_GROUP_CLASS),
44         aci_bv_group_attr       = BER_BVC(SLAPD_GROUP_ATTR),
45         aci_bv_role_class       = BER_BVC(SLAPD_ROLE_CLASS),
46         aci_bv_role_attr        = BER_BVC(SLAPD_ROLE_ATTR);
47
48
49 static AccessControl * acl_get(
50         AccessControl *ac, int *count,
51         Operation *op, Entry *e,
52         AttributeDescription *desc,
53         int nmatches, regmatch_t *matches );
54
55 static slap_control_t acl_mask(
56         AccessControl *ac, slap_mask_t *mask,
57         Operation *op, Entry *e,
58         AttributeDescription *desc,
59         struct berval *val,
60         regmatch_t *matches,
61         int count,
62         AccessControlState *state );
63
64 #ifdef SLAPD_ACI_ENABLED
65 static int aci_mask(
66         Operation *op, Entry *e,
67         AttributeDescription *desc,
68         struct berval *val,
69         struct berval *aci,
70         regmatch_t *matches,
71         slap_access_t *grant,
72         slap_access_t *deny,
73         struct berval *scope);
74 #endif
75
76 static int      regex_matches(
77         struct berval *pat, char *str, char *buf, regmatch_t *matches);
78 static void     string_expand(
79         struct berval *newbuf, struct berval *pattern,
80         char *match, regmatch_t *matches);
81
82 typedef struct AciSetCookie {
83         Operation *op;
84         Entry *e;
85 } AciSetCookie;
86
87 SLAP_SET_GATHER aci_set_gather;
88 static int aci_match_set ( struct berval *subj, Operation *op,
89     Entry *e, int setref );
90
91 /*
92  * access_allowed - check whether op->o_ndn is allowed the requested access
93  * to entry e, attribute attr, value val.  if val is null, access to
94  * the whole attribute is assumed (all values).
95  *
96  * This routine loops through all access controls and calls
97  * acl_mask() on each applicable access control.
98  * The loop exits when a definitive answer is reached or
99  * or no more controls remain.
100  *
101  * returns:
102  *              0       access denied
103  *              1       access granted
104  */
105
106 int
107 access_allowed(
108         Operation               *op,
109         Entry           *e,
110         AttributeDescription    *desc,
111         struct berval   *val,
112         slap_access_t   access,
113         AccessControlState *state )
114 {
115         int                             ret = 1;
116         int                             count;
117         AccessControl                   *a = NULL;
118         Backend *be;
119         int     be_null = 0;
120
121 #ifdef LDAP_DEBUG
122         char accessmaskbuf[ACCESSMASK_MAXLEN];
123 #endif
124         slap_mask_t mask;
125         slap_control_t control;
126         const char *attr;
127         regmatch_t matches[MAXREMATCHES];
128         int        st_same_attr = 0;
129         int        st_initialized = 0;
130         static AccessControlState state_init = ACL_STATE_INIT;
131
132         assert( e != NULL );
133         assert( desc != NULL );
134         assert( access > ACL_NONE );
135
136         attr = desc->ad_cname.bv_val;
137
138         assert( attr != NULL );
139
140         if( op && op->o_is_auth_check &&
141                 ( access == ACL_SEARCH || access == ACL_READ ))
142         {
143                 access = ACL_AUTH;
144         }
145
146         if( state && state->as_recorded && state->as_vd_ad==desc) { 
147                 if( state->as_recorded & ACL_STATE_RECORDED_NV &&
148                         val == NULL )
149                 {
150                         return state->as_result;
151
152                 } else if ( state->as_recorded & ACL_STATE_RECORDED_VD &&
153                         val != NULL && state->as_vd_acl == NULL )
154                 {
155                         return state->as_result;
156                 }
157                 st_same_attr = 1;
158         }
159
160         if( state ) {
161                 state->as_vd_ad=desc;
162         }
163
164 #ifdef NEW_LOGGING
165         LDAP_LOG( ACL, ENTRY, 
166                 "access_allowed: %s access to \"%s\" \"%s\" requested\n",
167                 access2str( access ), e->e_dn, attr );
168 #else
169         Debug( LDAP_DEBUG_ACL,
170                 "=> access_allowed: %s access to \"%s\" \"%s\" requested\n",
171             access2str( access ), e->e_dn, attr );
172 #endif
173
174         if ( op == NULL ) {
175                 /* no-op call */
176                 goto done;
177         }
178
179 #ifdef LDAP_SLAPI
180         ret = slapi_x_access_allowed( op, e, desc, val, access, state );
181         if ( ret == 0 ) {
182                 /* ACL plugin denied access */
183                 goto done;
184         }
185 #endif /* LDAP_SLAPI */
186
187         be = op->o_bd;
188         if ( be == NULL ) {
189                 be = &backends[0];
190                 be_null = 1;
191                 op->o_bd = be;
192         }
193         assert( be != NULL );
194
195         /* grant database root access */
196         if ( be != NULL && be_isroot( be, &op->o_ndn ) ) {
197 #ifdef NEW_LOGGING
198                 LDAP_LOG( ACL, INFO, 
199                         "access_allowed: conn %lu root access granted\n", 
200                         op->o_connid, 0, 0 );
201 #else
202                 Debug( LDAP_DEBUG_ACL,
203                     "<= root access granted\n",
204                         0, 0, 0 );
205 #endif
206                 goto done;
207         }
208
209         /*
210          * no-user-modification operational attributes are ignored
211          * by ACL_WRITE checking as any found here are not provided
212          * by the user
213          */
214         if ( access >= ACL_WRITE && is_at_no_user_mod( desc->ad_type )
215                 && desc != slap_schema.si_ad_entry
216                 && desc != slap_schema.si_ad_children )
217         {
218 #ifdef NEW_LOGGING
219                 LDAP_LOG( ACL, DETAIL1, 
220                         "access_allowed: conn %lu NoUserMod Operational attribute: %s "
221                         "access granted\n", op->o_connid, attr , 0 );
222 #else
223                 Debug( LDAP_DEBUG_ACL, "NoUserMod Operational attribute:"
224                         " %s access granted\n",
225                         attr, 0, 0 );
226 #endif
227                 goto done;
228         }
229
230         /* use backend default access if no backend acls */
231         if( be != NULL && be->be_acl == NULL ) {
232 #ifdef NEW_LOGGING
233                 LDAP_LOG( ACL, DETAIL1, 
234                         "access_allowed: backend default %s access %s to \"%s\"\n",
235                     access2str( access ),
236                     be->be_dfltaccess >= access ? "granted" : "denied", 
237                         op->o_dn.bv_val ? op->o_dn.bv_val : "(anonymous)" );
238 #else
239                 Debug( LDAP_DEBUG_ACL,
240                         "=> access_allowed: backend default %s access %s to \"%s\"\n",
241                         access2str( access ),
242                         be->be_dfltaccess >= access ? "granted" : "denied",
243                         op->o_dn.bv_val ? op->o_dn.bv_val : "(anonymous)" );
244 #endif
245                 ret = be->be_dfltaccess >= access;
246                 goto done;
247
248 #ifdef notdef
249         /* be is always non-NULL */
250         /* use global default access if no global acls */
251         } else if ( be == NULL && global_acl == NULL ) {
252 #ifdef NEW_LOGGING
253                 LDAP_LOG( ACL, DETAIL1, 
254                         "access_allowed: global default %s access %s to \"%s\"\n",
255                     access2str( access ),
256                     global_default_access >= access ? "granted" : "denied", 
257                         op->o_dn.bv_val );
258 #else
259                 Debug( LDAP_DEBUG_ACL,
260                         "=> access_allowed: global default %s access %s to \"%s\"\n",
261                         access2str( access ),
262                         global_default_access >= access ? "granted" : "denied", op->o_dn.bv_val );
263 #endif
264                 ret = global_default_access >= access;
265                 goto done;
266 #endif
267         }
268
269         ret = 0;
270         control = ACL_BREAK;
271
272         if( st_same_attr ) {
273                 assert( state->as_vd_acl != NULL );
274
275                 a = state->as_vd_acl;
276                 mask = state->as_vd_acl_mask;
277                 count = state->as_vd_acl_count;
278                 AC_MEMCPY( matches, state->as_vd_acl_matches, sizeof(matches) );
279                 goto vd_access;
280
281         } else {
282                 if ( state ) state->as_vi_acl = NULL;
283                 a = NULL;
284                 ACL_INIT(mask);
285                 count = 0;
286                 memset(matches, '\0', sizeof(matches));
287         }
288
289         while((a = acl_get( a, &count, op, e, desc,
290                 MAXREMATCHES, matches )) != NULL)
291         {
292                 int i;
293
294                 for (i = 0; i < MAXREMATCHES && matches[i].rm_so > 0; i++) {
295 #ifdef NEW_LOGGING
296                         LDAP_LOG( ACL, DETAIL1, 
297                                 "access_allowed: match[%d]:  %d %d ",
298                             i, (int)matches[i].rm_so, (int)matches[i].rm_eo );
299 #else
300                         Debug( LDAP_DEBUG_ACL, "=> match[%d]: %d %d ", i,
301                             (int)matches[i].rm_so, (int)matches[i].rm_eo );
302 #endif
303                         if( matches[i].rm_so <= matches[0].rm_eo ) {
304                                 int n;
305                                 for ( n = matches[i].rm_so; n < matches[i].rm_eo; n++) {
306                                         Debug( LDAP_DEBUG_ACL, "%c", e->e_ndn[n], 0, 0 );
307                                 }
308                         }
309 #ifdef NEW_LOGGING
310                         LDAP_LOG( ACL, ARGS, "\n" , 0, 0, 0 );
311 #else
312                         Debug( LDAP_DEBUG_ARGS, "\n", 0, 0, 0 );
313 #endif
314                 }
315
316                 if (state) {
317                         if (state->as_vi_acl == a && (state->as_recorded & ACL_STATE_RECORDED_NV)) {
318                                 Debug( LDAP_DEBUG_ACL, "access_allowed: result from state (%s)\n", attr, 0, 0 );
319                                 ret = state->as_result;
320                                 goto done;
321                         } else if (!st_initialized) {
322                                 Debug( LDAP_DEBUG_ACL, "access_allowed: no res from state (%s)\n", attr, 0, 0);
323                             *state = state_init;
324                                 state->as_vd_ad=desc;
325                                 st_initialized=1;
326                         }
327                 }
328
329 vd_access:
330                 control = acl_mask( a, &mask, op,
331                         e, desc, val, matches, count, state );
332
333                 if ( control != ACL_BREAK ) {
334                         break;
335                 }
336
337                 memset(matches, '\0', sizeof(matches));
338         }
339
340         if ( ACL_IS_INVALID( mask ) ) {
341 #ifdef NEW_LOGGING
342                 LDAP_LOG( ACL, DETAIL1, 
343                         "access_allowed: conn %lu \"%s\" (%s) invalid!\n",
344                     op->o_connid, e->e_dn, attr );
345 #else
346                 Debug( LDAP_DEBUG_ACL,
347                         "=> access_allowed: \"%s\" (%s) invalid!\n",
348                         e->e_dn, attr, 0 );
349 #endif
350                 ACL_INIT(mask);
351
352         } else if ( control == ACL_BREAK ) {
353 #ifdef NEW_LOGGING
354                 LDAP_LOG( ACL, DETAIL1, 
355                         "access_allowed: conn %lu        no more rules\n", op->o_connid, 0,0 );
356 #else
357                 Debug( LDAP_DEBUG_ACL,
358                         "=> access_allowed: no more rules\n", 0, 0, 0);
359 #endif
360
361                 goto done;
362         }
363
364 #ifdef NEW_LOGGING
365         LDAP_LOG( ACL, ENTRY, 
366                 "access_allowed: %s access %s by %s\n", 
367                 access2str( access ), ACL_GRANT( mask, access ) ? "granted" : "denied",
368                 accessmask2str( mask, accessmaskbuf ) );
369 #else
370         Debug( LDAP_DEBUG_ACL,
371                 "=> access_allowed: %s access %s by %s\n",
372                 access2str( access ),
373                 ACL_GRANT(mask, access) ? "granted" : "denied",
374                 accessmask2str( mask, accessmaskbuf ) );
375 #endif
376
377         ret = ACL_GRANT(mask, access);
378
379 done:
380         if( state != NULL ) {
381                 /* If not value-dependent, save ACL in case of more attrs */
382                 if ( !(state->as_recorded & ACL_STATE_RECORDED_VD) )
383                         state->as_vi_acl = a;
384                 state->as_recorded |= ACL_STATE_RECORDED;
385                 state->as_result = ret;
386         }
387         if (be_null) op->o_bd = NULL;
388         return ret;
389 }
390
391 /*
392  * acl_get - return the acl applicable to entry e, attribute
393  * attr.  the acl returned is suitable for use in subsequent calls to
394  * acl_access_allowed().
395  */
396
397 static AccessControl *
398 acl_get(
399         AccessControl *a,
400         int                     *count,
401         Operation       *op,
402         Entry           *e,
403         AttributeDescription *desc,
404         int                     nmatch,
405         regmatch_t      *matches )
406 {
407         const char *attr;
408         int dnlen, patlen;
409
410         assert( e != NULL );
411         assert( count != NULL );
412         assert( desc != NULL );
413
414         attr = desc->ad_cname.bv_val;
415
416         assert( attr != NULL );
417
418         if( a == NULL ) {
419                 if( op->o_bd == NULL ) {
420                         a = global_acl;
421                 } else {
422                         a = op->o_bd->be_acl;
423                 }
424
425                 assert( a != NULL );
426
427         } else {
428                 a = a->acl_next;
429         }
430
431         dnlen = e->e_nname.bv_len;
432
433         for ( ; a != NULL; a = a->acl_next ) {
434                 (*count) ++;
435
436                 if ( a->acl_dn_pat.bv_len || ( a->acl_dn_style != ACL_STYLE_REGEX )) {
437                         if ( a->acl_dn_style == ACL_STYLE_REGEX ) {
438 #ifdef NEW_LOGGING
439                                 LDAP_LOG( ACL, DETAIL1, 
440                                         "acl_get: dnpat [%d] %s nsub: %d\n",
441                                         *count, a->acl_dn_pat.bv_val, 
442                                         (int) a->acl_dn_re.re_nsub );
443 #else
444                                 Debug( LDAP_DEBUG_ACL, "=> dnpat: [%d] %s nsub: %d\n", 
445                                         *count, a->acl_dn_pat.bv_val, (int) a->acl_dn_re.re_nsub );
446 #endif
447                                 if (regexec(&a->acl_dn_re, e->e_ndn, nmatch, matches, 0))
448                                         continue;
449
450                         } else {
451 #ifdef NEW_LOGGING
452                                 LDAP_LOG( ACL, DETAIL1, "acl_get: dn [%d] %s\n",
453                                            *count, a->acl_dn_pat.bv_val, 0 );
454 #else
455                                 Debug( LDAP_DEBUG_ACL, "=> dn: [%d] %s\n", 
456                                         *count, a->acl_dn_pat.bv_val, 0 );
457 #endif
458                                 patlen = a->acl_dn_pat.bv_len;
459                                 if ( dnlen < patlen )
460                                         continue;
461
462                                 if ( a->acl_dn_style == ACL_STYLE_BASE ) {
463                                         /* base dn -- entire object DN must match */
464                                         if ( dnlen != patlen )
465                                                 continue;
466
467                                 } else if ( a->acl_dn_style == ACL_STYLE_ONE ) {
468                                         int rdnlen = -1;
469
470                                         if ( dnlen <= patlen )
471                                                 continue;
472
473                                         if ( !DN_SEPARATOR( e->e_ndn[dnlen - patlen - 1] ) )
474                                                 continue;
475
476                                         rdnlen = dn_rdnlen( NULL, &e->e_nname );
477                                         if ( rdnlen != dnlen - patlen - 1 )
478                                                 continue;
479
480                                 } else if ( a->acl_dn_style == ACL_STYLE_SUBTREE ) {
481                                         if ( dnlen > patlen && !DN_SEPARATOR( e->e_ndn[dnlen - patlen - 1] ) )
482                                                 continue;
483
484                                 } else if ( a->acl_dn_style == ACL_STYLE_CHILDREN ) {
485                                         if ( dnlen <= patlen )
486                                                 continue;
487                                         if ( !DN_SEPARATOR( e->e_ndn[dnlen - patlen - 1] ) )
488                                                 continue;
489                                 }
490
491                                 if ( strcmp( a->acl_dn_pat.bv_val, e->e_ndn + dnlen - patlen ) != 0 )
492                                         continue;
493                         }
494
495 #ifdef NEW_LOGGING
496                         LDAP_LOG( ACL, DETAIL1, 
497                                 "acl_get: [%d] matched\n", *count, 0, 0 );
498 #else
499                         Debug( LDAP_DEBUG_ACL, "=> acl_get: [%d] matched\n",
500                                 *count, 0, 0 );
501 #endif
502                 }
503
504                 if ( a->acl_filter != NULL ) {
505                         ber_int_t rc = test_filter( NULL, e, a->acl_filter );
506                         if ( rc != LDAP_COMPARE_TRUE ) {
507                                 continue;
508                         }
509                 }
510
511 #ifdef NEW_LOGGING
512                 LDAP_LOG( ACL, DETAIL1, 
513                         "acl_get: [%d] check attr %s\n", *count, attr ,0 );
514 #else
515                 Debug( LDAP_DEBUG_ACL, "=> acl_get: [%d] check attr %s\n",
516                        *count, attr, 0);
517 #endif
518                 if ( attr == NULL || a->acl_attrs == NULL ||
519                         ad_inlist( desc, a->acl_attrs ) )
520                 {
521 #ifdef NEW_LOGGING
522                         LDAP_LOG( ACL, DETAIL1, 
523                                 "acl_get:  [%d] acl %s attr: %s\n", *count, e->e_dn, attr );
524 #else
525                         Debug( LDAP_DEBUG_ACL,
526                                 "<= acl_get: [%d] acl %s attr: %s\n",
527                                 *count, e->e_dn, attr );
528 #endif
529                         return a;
530                 }
531                 matches[0].rm_so = matches[0].rm_eo = -1;
532         }
533
534 #ifdef NEW_LOGGING
535         LDAP_LOG( ACL, RESULTS, "acl_get: done.\n", 0, 0, 0 );
536 #else
537         Debug( LDAP_DEBUG_ACL, "<= acl_get: done.\n", 0, 0, 0 );
538 #endif
539         return( NULL );
540 }
541
542 /*
543  * Record value-dependent access control state
544  */
545 #define ACL_RECORD_VALUE_STATE do { \
546                 if( state && !( state->as_recorded & ACL_STATE_RECORDED_VD )) { \
547                         state->as_recorded |= ACL_STATE_RECORDED_VD; \
548                         state->as_vd_acl = a; \
549                         AC_MEMCPY( state->as_vd_acl_matches, matches, \
550                                 sizeof( state->as_vd_acl_matches )) ; \
551                         state->as_vd_acl_count = count; \
552                         state->as_vd_access = b; \
553                         state->as_vd_access_count = i; \
554                 } \
555         } while( 0 )
556
557 /*
558  * acl_mask - modifies mask based upon the given acl and the
559  * requested access to entry e, attribute attr, value val.  if val
560  * is null, access to the whole attribute is assumed (all values).
561  *
562  * returns      0       access NOT allowed
563  *              1       access allowed
564  */
565
566 static slap_control_t
567 acl_mask(
568         AccessControl   *a,
569         slap_mask_t *mask,
570         Operation       *op,
571         Entry           *e,
572         AttributeDescription *desc,
573         struct berval   *val,
574         regmatch_t      *matches,
575         int     count,
576         AccessControlState *state )
577 {
578         int             i, odnlen, patlen;
579         Access  *b;
580 #ifdef LDAP_DEBUG
581         char accessmaskbuf[ACCESSMASK_MAXLEN];
582         char accessmaskbuf1[ACCESSMASK_MAXLEN];
583 #endif
584         const char *attr;
585
586         assert( a != NULL );
587         assert( mask != NULL );
588         assert( desc != NULL );
589
590         attr = desc->ad_cname.bv_val;
591
592         assert( attr != NULL );
593
594 #ifdef NEW_LOGGING
595         LDAP_LOG( ACL, ENTRY, 
596                 "acl_mask: conn %lu  access to entry \"%s\", attr \"%s\" requested\n",
597                 op->o_connid, e->e_dn, attr );
598
599         LDAP_LOG( ACL, ARGS, 
600                 " to %s by \"%s\", (%s) \n", val ? "value" : "all values",
601                 op->o_ndn.bv_val ? op->o_ndn.bv_val : "",
602                 accessmask2str( *mask, accessmaskbuf ) );
603 #else
604         Debug( LDAP_DEBUG_ACL,
605                 "=> acl_mask: access to entry \"%s\", attr \"%s\" requested\n",
606                 e->e_dn, attr, 0 );
607
608         Debug( LDAP_DEBUG_ACL,
609                 "=> acl_mask: to %s by \"%s\", (%s) \n",
610                 val ? "value" : "all values",
611                 op->o_ndn.bv_val ?  op->o_ndn.bv_val : "",
612                 accessmask2str( *mask, accessmaskbuf ) );
613 #endif
614
615         if( state && ( state->as_recorded & ACL_STATE_RECORDED_VD )
616                 && state->as_vd_acl == a )
617         {
618                 b = state->as_vd_access;
619                 i = state->as_vd_access_count;
620
621         } else {
622                 b = a->acl_access;
623                 i = 1;
624         }
625
626         for ( ; b != NULL; b = b->a_next, i++ ) {
627                 slap_mask_t oldmask, modmask;
628
629                 ACL_INVALIDATE( modmask );
630
631                 /* AND <who> clauses */
632                 if ( b->a_dn_pat.bv_len != 0 ) {
633 #ifdef NEW_LOGGING
634                         LDAP_LOG( ACL, DETAIL1, 
635                                 "acl_mask: conn %lu  check a_dn_pat: %s\n",
636                                 op->o_connid, b->a_dn_pat.bv_val ,0 );
637 #else
638                         Debug( LDAP_DEBUG_ACL, "<= check a_dn_pat: %s\n",
639                                 b->a_dn_pat.bv_val, 0, 0);
640 #endif
641                         /*
642                          * if access applies to the entry itself, and the
643                          * user is bound as somebody in the same namespace as
644                          * the entry, OR the given dn matches the dn pattern
645                          */
646                         if ( bvmatch( &b->a_dn_pat, &aci_bv_anonymous ) ) {
647                                 if ( op->o_ndn.bv_len != 0 ) {
648                                         continue;
649                                 }
650
651                         } else if ( bvmatch( &b->a_dn_pat, &aci_bv_users ) ) {
652                                 if ( op->o_ndn.bv_len == 0 ) {
653                                         continue;
654                                 }
655
656                         } else if ( bvmatch( &b->a_dn_pat, &aci_bv_self ) ) {
657                                 if ( op->o_ndn.bv_len == 0 ) {
658                                         continue;
659                                 }
660                                 
661                                 if ( e->e_dn == NULL || !dn_match( &e->e_nname, &op->o_ndn ) ) {
662                                         continue;
663                                 }
664
665                         } else if ( b->a_dn_style == ACL_STYLE_REGEX ) {
666                                 if ( !ber_bvccmp( &b->a_dn_pat, '*' ) ) {
667                                         int ret = regex_matches( &b->a_dn_pat,
668                                                 op->o_ndn.bv_val, e->e_ndn, matches );
669
670                                         if( ret == 0 ) {
671                                                 continue;
672                                         }
673                                 }
674
675                         } else {
676                                 struct berval pat;
677                                 int got_match = 0;
678
679                                 if ( e->e_dn == NULL )
680                                         continue;
681
682                                 if ( b->a_dn_expand ) {
683                                         struct berval bv;
684                                         char buf[ACL_BUF_SIZE];
685
686                                         bv.bv_len = sizeof( buf ) - 1;
687                                         bv.bv_val = buf;
688
689                                         string_expand(&bv, &b->a_dn_pat, 
690                                                         e->e_ndn, matches);
691                                         if ( dnNormalize(0, NULL, NULL, &bv, &pat, op->o_tmpmemctx ) != LDAP_SUCCESS ) {
692                                                 /* did not expand to a valid dn */
693                                                 continue;
694                                         }
695                                 } else {
696                                         pat = b->a_dn_pat;
697                                 }
698
699                                 patlen = pat.bv_len;
700                                 odnlen = op->o_ndn.bv_len;
701                                 if ( odnlen < patlen ) {
702                                         goto dn_match_cleanup;
703
704                                 }
705
706                                 if ( b->a_dn_style == ACL_STYLE_BASE ) {
707                                         /* base dn -- entire object DN must match */
708                                         if ( odnlen != patlen ) {
709                                                 goto dn_match_cleanup;
710                                         }
711
712                                 } else if ( b->a_dn_style == ACL_STYLE_ONE ) {
713                                         int rdnlen = -1;
714
715                                         if ( odnlen <= patlen ) {
716                                                 goto dn_match_cleanup;
717                                         }
718
719                                         if ( !DN_SEPARATOR( op->o_ndn.bv_val[odnlen - patlen - 1] ) ) {
720                                                 goto dn_match_cleanup;
721                                         }
722
723                                         rdnlen = dn_rdnlen( NULL, &op->o_ndn );
724                                         if ( rdnlen != odnlen - patlen - 1 ) {
725                                                 goto dn_match_cleanup;
726                                         }
727
728                                 } else if ( b->a_dn_style == ACL_STYLE_SUBTREE ) {
729                                         if ( odnlen > patlen && !DN_SEPARATOR( op->o_ndn.bv_val[odnlen - patlen - 1] ) ) {
730                                                 goto dn_match_cleanup;
731                                         }
732
733                                 } else if ( b->a_dn_style == ACL_STYLE_CHILDREN ) {
734                                         if ( odnlen <= patlen ) {
735                                                 goto dn_match_cleanup;
736                                         }
737
738                                         if ( !DN_SEPARATOR( op->o_ndn.bv_val[odnlen - patlen - 1] ) ) {
739                                                 goto dn_match_cleanup;
740                                         }
741                                 }
742
743                                 got_match = !strcmp( pat.bv_val, op->o_ndn.bv_val + odnlen - patlen );
744
745 dn_match_cleanup:;
746                                 if ( pat.bv_val != b->a_dn_pat.bv_val ) {
747                                         free( pat.bv_val );
748                                 }
749
750                                 if ( !got_match ) {
751                                         continue;
752                                 }
753                         }
754                 }
755
756                 if ( b->a_sockurl_pat.bv_len ) {
757                         if ( ! op->o_conn->c_listener ) {
758                                 continue;
759                         }
760 #ifdef NEW_LOGGING
761                         LDAP_LOG( ACL, DETAIL1, 
762                                    "acl_mask: conn %lu  check a_sockurl_pat: %s\n",
763                                    op->o_connid, b->a_sockurl_pat.bv_val , 0 );
764 #else
765                         Debug( LDAP_DEBUG_ACL, "<= check a_sockurl_pat: %s\n",
766                                 b->a_sockurl_pat.bv_val, 0, 0 );
767 #endif
768
769                         if ( !ber_bvccmp( &b->a_sockurl_pat, '*' ) ) {
770                                 if ( b->a_sockurl_style == ACL_STYLE_REGEX) {
771                                         if (!regex_matches( &b->a_sockurl_pat, op->o_conn->c_listener_url.bv_val,
772                                                         e->e_ndn, matches ) ) 
773                                         {
774                                                 continue;
775                                         }
776                                 } else {
777                                         if ( ber_bvstrcasecmp( &b->a_sockurl_pat, &op->o_conn->c_listener_url ) != 0 )
778                                                 continue;
779                                 }
780                         }
781                 }
782
783                 if ( b->a_domain_pat.bv_len ) {
784                         if ( !op->o_conn->c_peer_domain.bv_val ) {
785                                 continue;
786                         }
787 #ifdef NEW_LOGGING
788                         LDAP_LOG( ACL, DETAIL1, 
789                                    "acl_mask: conn %lu  check a_domain_pat: %s\n",
790                                    op->o_connid, b->a_domain_pat.bv_val , 0 );
791 #else
792                         Debug( LDAP_DEBUG_ACL, "<= check a_domain_pat: %s\n",
793                                 b->a_domain_pat.bv_val, 0, 0 );
794 #endif
795                         if ( !ber_bvccmp( &b->a_domain_pat, '*' ) ) {
796                                 if ( b->a_domain_style == ACL_STYLE_REGEX) {
797                                         if (!regex_matches( &b->a_domain_pat, op->o_conn->c_peer_domain.bv_val,
798                                                         e->e_ndn, matches ) ) 
799                                         {
800                                                 continue;
801                                         }
802                                 } else {
803                                         char buf[ACL_BUF_SIZE];
804
805                                         struct berval   cmp = op->o_conn->c_peer_domain;
806                                         struct berval   pat = b->a_domain_pat;
807
808                                         if ( b->a_domain_expand ) {
809                                                 struct berval bv;
810
811                                                 bv.bv_len = sizeof(buf) - 1;
812                                                 bv.bv_val = buf;
813
814                                                 string_expand(&bv, &b->a_domain_pat, e->e_ndn, matches);
815                                                 pat = bv;
816                                         }
817
818                                         if ( b->a_domain_style == ACL_STYLE_SUBTREE ) {
819                                                 int offset = cmp.bv_len - pat.bv_len;
820                                                 if ( offset < 0 ) {
821                                                         continue;
822                                                 }
823
824                                                 if ( offset == 1 || ( offset > 1 && cmp.bv_val[ offset - 1 ] != '.' ) ) {
825                                                         continue;
826                                                 }
827
828                                                 /* trim the domain */
829                                                 cmp.bv_val = &cmp.bv_val[ offset ];
830                                                 cmp.bv_len -= offset;
831                                         }
832                                         
833                                         if ( ber_bvstrcasecmp( &pat, &cmp ) != 0 ) {
834                                                 continue;
835                                         }
836                                 }
837                         }
838                 }
839
840                 if ( b->a_peername_pat.bv_len ) {
841                         if ( !op->o_conn->c_peer_name.bv_val ) {
842                                 continue;
843                         }
844 #ifdef NEW_LOGGING
845                         LDAP_LOG( ACL, DETAIL1, 
846                                    "acl_mask: conn %lu  check a_peername_path: %s\n",
847                                    op->o_connid, b->a_peername_pat.bv_val , 0 );
848 #else
849                         Debug( LDAP_DEBUG_ACL, "<= check a_peername_path: %s\n",
850                                 b->a_peername_pat.bv_val, 0, 0 );
851 #endif
852                         if ( !ber_bvccmp( &b->a_peername_pat, '*' ) ) {
853                                 if ( b->a_peername_style == ACL_STYLE_REGEX) {
854                                         if (!regex_matches( &b->a_peername_pat, op->o_conn->c_peer_name.bv_val,
855                                                         e->e_ndn, matches ) ) 
856                                         {
857                                                 continue;
858                                         }
859                                 } else {
860                                         if ( ber_bvstrcasecmp( &b->a_peername_pat, &op->o_conn->c_peer_name ) != 0 )
861                                                 continue;
862                                 }
863                         }
864                 }
865
866                 if ( b->a_sockname_pat.bv_len ) {
867                         if ( !op->o_conn->c_sock_name.bv_val ) {
868                                 continue;
869                         }
870 #ifdef NEW_LOGGING
871                         LDAP_LOG( ACL, DETAIL1, 
872                                    "acl_mask: conn %lu  check a_sockname_path: %s\n",
873                                    op->o_connid, b->a_sockname_pat.bv_val , 0 );
874 #else
875                         Debug( LDAP_DEBUG_ACL, "<= check a_sockname_path: %s\n",
876                                 b->a_sockname_pat.bv_val, 0, 0 );
877 #endif
878                         if ( !ber_bvccmp( &b->a_sockname_pat, '*' ) ) {
879                                 if ( b->a_sockname_style == ACL_STYLE_REGEX) {
880                                         if (!regex_matches( &b->a_sockname_pat, op->o_conn->c_sock_name.bv_val,
881                                                         e->e_ndn, matches ) ) 
882                                         {
883                                                 continue;
884                                         }
885                                 } else {
886                                         if ( ber_bvstrcasecmp( &b->a_sockname_pat, &op->o_conn->c_sock_name ) != 0 )
887                                                 continue;
888                                 }
889                         }
890                 }
891
892                 if ( b->a_dn_at != NULL ) {
893                         Attribute       *at;
894                         struct berval   bv;
895                         int rc, match = 0;
896                         const char *text;
897                         const char *attr = b->a_dn_at->ad_cname.bv_val;
898
899                         assert( attr != NULL );
900
901                         if ( op->o_ndn.bv_len == 0 ) {
902                                 continue;
903                         }
904
905 #ifdef NEW_LOGGING
906                         LDAP_LOG( ACL, DETAIL1, 
907                                    "acl_mask: conn %lu  check a_dn_pat: %s\n",
908                                    op->o_connid, attr , 0 );
909 #else
910                         Debug( LDAP_DEBUG_ACL, "<= check a_dn_at: %s\n",
911                                 attr, 0, 0);
912 #endif
913                         bv = op->o_ndn;
914
915                         /* see if asker is listed in dnattr */
916                         for( at = attrs_find( e->e_attrs, b->a_dn_at );
917                                 at != NULL;
918                                 at = attrs_find( at->a_next, b->a_dn_at ) )
919                         {
920                                 if( value_find_ex( b->a_dn_at,
921                                         SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
922                                                 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
923                                         at->a_nvals,
924                                         &bv, op->o_tmpmemctx ) == 0 )
925                                 {
926                                         /* found it */
927                                         match = 1;
928                                         break;
929                                 }
930                         }
931
932                         if( match ) {
933                                 /* have a dnattr match. if this is a self clause then
934                                  * the target must also match the op dn.
935                                  */
936                                 if ( b->a_dn_self ) {
937                                         /* check if the target is an attribute. */
938                                         if ( val == NULL ) continue;
939
940                                         /* target is attribute, check if the attribute value
941                                          * is the op dn.
942                                          */
943                                         rc = value_match( &match, b->a_dn_at,
944                                                 b->a_dn_at->ad_type->sat_equality, 0,
945                                                 val, &bv, &text );
946                                         /* on match error or no match, fail the ACL clause */
947                                         if (rc != LDAP_SUCCESS || match != 0 )
948                                                 continue;
949                                 }
950                         } else {
951                                 /* no dnattr match, check if this is a self clause */
952                                 if ( ! b->a_dn_self )
953                                         continue;
954
955                                 ACL_RECORD_VALUE_STATE;
956                                 
957                                 /* this is a self clause, check if the target is an
958                                  * attribute.
959                                  */
960                                 if ( val == NULL )
961                                         continue;
962
963                                 /* target is attribute, check if the attribute value
964                                  * is the op dn.
965                                  */
966                                 rc = value_match( &match, b->a_dn_at,
967                                         b->a_dn_at->ad_type->sat_equality, 0,
968                                         val, &bv, &text );
969
970                                 /* on match error or no match, fail the ACL clause */
971                                 if (rc != LDAP_SUCCESS || match != 0 )
972                                         continue;
973                         }
974                 }
975
976                 if ( b->a_group_pat.bv_len ) {
977                         struct berval bv;
978                         struct berval ndn = { 0, NULL };
979                         int rc;
980
981                         if ( op->o_ndn.bv_len == 0 ) {
982                                 continue;
983                         }
984
985                         /* b->a_group is an unexpanded entry name, expanded it should be an 
986                          * entry with objectclass group* and we test to see if odn is one of
987                          * the values in the attribute group
988                          */
989                         /* see if asker is listed in dnattr */
990                         if ( b->a_group_style == ACL_STYLE_REGEX ) {
991                                 char buf[ACL_BUF_SIZE];
992                                 bv.bv_len = sizeof(buf) - 1;
993                                 bv.bv_val = buf; 
994
995                                 string_expand( &bv, &b->a_group_pat, e->e_ndn, matches );
996                                 if ( dnNormalize( 0, NULL, NULL, &bv, &ndn, op->o_tmpmemctx ) != LDAP_SUCCESS ) {
997                                         /* did not expand to a valid dn */
998                                         continue;
999                                 }
1000
1001                                 bv = ndn;
1002
1003                         } else {
1004                                 bv = b->a_group_pat;
1005                         }
1006
1007                         rc = backend_group( op, e, &bv, &op->o_ndn,
1008                                 b->a_group_oc, b->a_group_at );
1009
1010                         if ( ndn.bv_val ) free( ndn.bv_val );
1011
1012                         if ( rc != 0 ) {
1013                                 continue;
1014                         }
1015                 }
1016
1017                 if ( b->a_set_pat.bv_len != 0 ) {
1018                         struct berval bv;
1019                         char buf[ACL_BUF_SIZE];
1020                         if( b->a_set_style == ACL_STYLE_REGEX ){
1021                                 bv.bv_len = sizeof(buf) - 1;
1022                                 bv.bv_val = buf;
1023                                 string_expand( &bv, &b->a_set_pat, e->e_ndn, matches );
1024                         }else{
1025                                 bv = b->a_set_pat;
1026                         }
1027                         if (aci_match_set( &bv, op, e, 0 ) == 0) {
1028                                 continue;
1029                         }
1030                 }
1031
1032                 if ( b->a_authz.sai_ssf ) {
1033 #ifdef NEW_LOGGING
1034                         LDAP_LOG( ACL, DETAIL1, 
1035                                 "acl_mask: conn %lu  check a_authz.sai_ssf: ACL %u > OP %u\n",
1036                                 op->o_connid, b->a_authz.sai_ssf, op->o_ssf  );
1037 #else
1038                         Debug( LDAP_DEBUG_ACL, "<= check a_authz.sai_ssf: ACL %u > OP %u\n",
1039                                 b->a_authz.sai_ssf, op->o_ssf, 0 );
1040 #endif
1041                         if ( b->a_authz.sai_ssf >  op->o_ssf ) {
1042                                 continue;
1043                         }
1044                 }
1045
1046                 if ( b->a_authz.sai_transport_ssf ) {
1047 #ifdef NEW_LOGGING
1048                         LDAP_LOG( ACL, DETAIL1, 
1049                                 "acl_mask: conn %lu  check a_authz.sai_transport_ssf: "
1050                                 "ACL %u > OP %u\n",
1051                                 op->o_connid, b->a_authz.sai_transport_ssf, 
1052                                 op->o_transport_ssf  );
1053 #else
1054                         Debug( LDAP_DEBUG_ACL,
1055                                 "<= check a_authz.sai_transport_ssf: ACL %u > OP %u\n",
1056                                 b->a_authz.sai_transport_ssf, op->o_transport_ssf, 0 );
1057 #endif
1058                         if ( b->a_authz.sai_transport_ssf >  op->o_transport_ssf ) {
1059                                 continue;
1060                         }
1061                 }
1062
1063                 if ( b->a_authz.sai_tls_ssf ) {
1064 #ifdef NEW_LOGGING
1065                         LDAP_LOG( ACL, DETAIL1, 
1066                                 "acl_mask: conn %lu  check a_authz.sai_tls_ssf: ACL %u > "
1067                                 "OP %u\n",
1068                                 op->o_connid, b->a_authz.sai_tls_ssf, op->o_tls_ssf  );
1069 #else
1070                         Debug( LDAP_DEBUG_ACL,
1071                                 "<= check a_authz.sai_tls_ssf: ACL %u > OP %u\n",
1072                                 b->a_authz.sai_tls_ssf, op->o_tls_ssf, 0 );
1073 #endif
1074                         if ( b->a_authz.sai_tls_ssf >  op->o_tls_ssf ) {
1075                                 continue;
1076                         }
1077                 }
1078
1079                 if ( b->a_authz.sai_sasl_ssf ) {
1080 #ifdef NEW_LOGGING
1081                         LDAP_LOG( ACL, DETAIL1, 
1082                            "acl_mask: conn %lu check a_authz.sai_sasl_ssf: " 
1083                            "ACL %u > OP %u\n",
1084                                 op->o_connid, b->a_authz.sai_sasl_ssf, op->o_sasl_ssf );
1085 #else
1086                         Debug( LDAP_DEBUG_ACL,
1087                                 "<= check a_authz.sai_sasl_ssf: ACL %u > OP %u\n",
1088                                 b->a_authz.sai_sasl_ssf, op->o_sasl_ssf, 0 );
1089 #endif
1090                         if ( b->a_authz.sai_sasl_ssf >  op->o_sasl_ssf ) {
1091                                 continue;
1092                         }
1093                 }
1094
1095 #ifdef SLAPD_ACI_ENABLED
1096                 if ( b->a_aci_at != NULL ) {
1097                         Attribute       *at;
1098                         slap_access_t grant, deny, tgrant, tdeny;
1099                         struct berval parent_ndn, old_parent_ndn;
1100                         BerVarray bvals = NULL;
1101                         int ret,stop;
1102
1103                         /* this case works different from the others above.
1104                          * since aci's themselves give permissions, we need
1105                          * to first check b->a_access_mask, the ACL's access level.
1106                          */
1107
1108                         if ( e->e_nname.bv_len == 0 ) {
1109                                 /* no ACIs in the root DSE */
1110                                 continue;
1111                         }
1112
1113                         /* first check if the right being requested
1114                          * is allowed by the ACL clause.
1115                          */
1116                         if ( ! ACL_GRANT( b->a_access_mask, *mask ) ) {
1117                                 continue;
1118                         }
1119                         /* start out with nothing granted, nothing denied */
1120                         ACL_INIT(tgrant);
1121                         ACL_INIT(tdeny);
1122
1123                         /* get the aci attribute */
1124                         at = attr_find( e->e_attrs, b->a_aci_at );
1125                         if ( at != NULL ) {
1126                                 ACL_RECORD_VALUE_STATE;
1127                                 /* the aci is an multi-valued attribute.  The
1128                                 * rights are determined by OR'ing the individual
1129                                 * rights given by the acis.
1130                                 */
1131                                 for ( i = 0; at->a_vals[i].bv_val != NULL; i++ ) {
1132                                         if (aci_mask( op,
1133                                                 e, desc, val,
1134                                                 &at->a_nvals[i],
1135                                                 matches, &grant, &deny,  &aci_bv_entry ) != 0)
1136                                         {
1137                                                 tgrant |= grant;
1138                                                 tdeny |= deny;
1139                                         }
1140                                 }
1141                                 Debug(LDAP_DEBUG_ACL, "<= aci_mask grant %s deny %s\n",
1142                                           accessmask2str(tgrant,accessmaskbuf), 
1143                                           accessmask2str(tdeny, accessmaskbuf1), 0);
1144
1145                         }
1146                         /* If the entry level aci didn't contain anything valid for the 
1147                          * current operation, climb up the tree and evaluate the
1148                          * acis with scope set to subtree
1149                          */
1150                         if( (tgrant == ACL_PRIV_NONE) && (tdeny == ACL_PRIV_NONE) ){
1151                                 dnParent(&(e->e_nname), &parent_ndn);
1152                                 while ( parent_ndn.bv_val != old_parent_ndn.bv_val ){
1153                                         old_parent_ndn = parent_ndn;
1154                                         Debug(LDAP_DEBUG_ACL, "checking ACI of %s\n", parent_ndn.bv_val, 0, 0);
1155                                         ret=backend_attribute(op, NULL, &parent_ndn, b->a_aci_at, &bvals);
1156                                         switch(ret){
1157                                                 case LDAP_SUCCESS :
1158                                                         if(bvals){
1159                                                                 for( i = 0; bvals[i].bv_val != NULL; i++){
1160                                                                         ACL_RECORD_VALUE_STATE;
1161                                                                         if (aci_mask(op, e, desc, val, &bvals[i], matches,
1162                                                                                         &grant, &deny, &aci_bv_children) != 0) {
1163                                                                                 tgrant |= grant;
1164                                                                                 tdeny |= deny;
1165                                                                                 /* evaluation stops as soon as either a "deny" or a 
1166                                                                                  * "grant" directive matches.
1167                                                                                  */
1168                                                                                 if( (tgrant != ACL_PRIV_NONE) || (tdeny != ACL_PRIV_NONE) ){
1169                                                                                         stop=1;
1170                                                                                 }
1171                                                                         }
1172                                                                         Debug(LDAP_DEBUG_ACL, "<= aci_mask grant %s deny %s\n", 
1173                                                                                 accessmask2str(tgrant,accessmaskbuf),
1174                                                                                 accessmask2str(tdeny, accessmaskbuf1), 0);
1175                                                                 }
1176                                                         }
1177                                                         stop=0;
1178                                                         break;
1179                                                 case LDAP_NO_SUCH_ATTRIBUTE:
1180                                                         /* just go on if the aci-Attribute is not present in
1181                                                          * the current entry 
1182                                                          */
1183                                                         Debug(LDAP_DEBUG_ACL, "no such attribute\n", 0, 0, 0);
1184                                                         stop=0;
1185                                                         break;
1186                                                 case LDAP_NO_SUCH_OBJECT:
1187                                                         /* We have reached the base object */
1188                                                         Debug(LDAP_DEBUG_ACL, "no such object\n", 0, 0, 0);
1189                                                         stop=1;
1190                                                         break;
1191                                                 default:
1192                                                         stop=1;
1193                                                         break;
1194                                         }
1195                                         if(stop){
1196                                                 break;
1197                                         }
1198                                         dnParent(&old_parent_ndn, &parent_ndn);
1199                                 }
1200                         }
1201
1202
1203                         /* remove anything that the ACL clause does not allow */
1204                         tgrant &= b->a_access_mask & ACL_PRIV_MASK;
1205                         tdeny &= ACL_PRIV_MASK;
1206
1207                         /* see if we have anything to contribute */
1208                         if( ACL_IS_INVALID(tgrant) && ACL_IS_INVALID(tdeny) ) { 
1209                                 continue;
1210                         }
1211
1212                         /* this could be improved by changing acl_mask so that it can deal with
1213                          * by clauses that return grant/deny pairs.  Right now, it does either
1214                          * additive or subtractive rights, but not both at the same time.  So,
1215                          * we need to combine the grant/deny pair into a single rights mask in
1216                          * a smart way:  if either grant or deny is "empty", then we use the
1217                          * opposite as is, otherwise we remove any denied rights from the grant
1218                          * rights mask and construct an additive mask.
1219                          */
1220                         if (ACL_IS_INVALID(tdeny)) {
1221                                 modmask = tgrant | ACL_PRIV_ADDITIVE;
1222
1223                         } else if (ACL_IS_INVALID(tgrant)) {
1224                                 modmask = tdeny | ACL_PRIV_SUBSTRACTIVE;
1225
1226                         } else {
1227                                 modmask = (tgrant & ~tdeny) | ACL_PRIV_ADDITIVE;
1228                         }
1229
1230                 } else
1231 #endif
1232                 {
1233                         modmask = b->a_access_mask;
1234                 }
1235
1236 #ifdef NEW_LOGGING
1237                 LDAP_LOG( ACL, RESULTS, 
1238                            "acl_mask: [%d] applying %s (%s)\n",
1239                            i, accessmask2str( modmask, accessmaskbuf),
1240                            b->a_type == ACL_CONTINUE ? "continue" : b->a_type == ACL_BREAK
1241                            ? "break" : "stop"  );
1242 #else
1243                 Debug( LDAP_DEBUG_ACL,
1244                         "<= acl_mask: [%d] applying %s (%s)\n",
1245                         i, accessmask2str( modmask, accessmaskbuf ), 
1246                         b->a_type == ACL_CONTINUE
1247                                 ? "continue"
1248                                 : b->a_type == ACL_BREAK
1249                                         ? "break"
1250                                         : "stop" );
1251 #endif
1252                 /* save old mask */
1253                 oldmask = *mask;
1254
1255                 if( ACL_IS_ADDITIVE(modmask) ) {
1256                         /* add privs */
1257                         ACL_PRIV_SET( *mask, modmask );
1258
1259                         /* cleanup */
1260                         ACL_PRIV_CLR( *mask, ~ACL_PRIV_MASK );
1261
1262                 } else if( ACL_IS_SUBTRACTIVE(modmask) ) {
1263                         /* substract privs */
1264                         ACL_PRIV_CLR( *mask, modmask );
1265
1266                         /* cleanup */
1267                         ACL_PRIV_CLR( *mask, ~ACL_PRIV_MASK );
1268
1269                 } else {
1270                         /* assign privs */
1271                         *mask = modmask;
1272                 }
1273
1274 #ifdef NEW_LOGGING
1275                 LDAP_LOG( ACL, DETAIL1, 
1276                            "acl_mask: conn %lu  [%d] mask: %s\n",
1277                            op->o_connid, i, accessmask2str( *mask, accessmaskbuf)  );
1278 #else
1279                 Debug( LDAP_DEBUG_ACL,
1280                         "<= acl_mask: [%d] mask: %s\n",
1281                         i, accessmask2str(*mask, accessmaskbuf), 0 );
1282 #endif
1283
1284                 if( b->a_type == ACL_CONTINUE ) {
1285                         continue;
1286
1287                 } else if ( b->a_type == ACL_BREAK ) {
1288                         return ACL_BREAK;
1289
1290                 } else {
1291                         return ACL_STOP;
1292                 }
1293         }
1294
1295         /* implicit "by * none" clause */
1296         ACL_INIT(*mask);
1297
1298 #ifdef NEW_LOGGING
1299         LDAP_LOG( ACL, RESULTS, 
1300                    "acl_mask: conn %lu  no more <who> clauses, returning %d (stop)\n",
1301                    op->o_connid, accessmask2str( *mask, accessmaskbuf) , 0 );
1302 #else
1303         Debug( LDAP_DEBUG_ACL,
1304                 "<= acl_mask: no more <who> clauses, returning %s (stop)\n",
1305                 accessmask2str(*mask, accessmaskbuf), 0, 0 );
1306 #endif
1307         return ACL_STOP;
1308 }
1309
1310 /*
1311  * acl_check_modlist - check access control on the given entry to see if
1312  * it allows the given modifications by the user associated with op.
1313  * returns      1       if mods allowed ok
1314  *                      0       mods not allowed
1315  */
1316
1317 int
1318 acl_check_modlist(
1319         Operation       *op,
1320         Entry   *e,
1321         Modifications   *mlist
1322 )
1323 {
1324         struct berval *bv;
1325         AccessControlState state = ACL_STATE_INIT;
1326
1327         assert( op->o_bd != NULL );
1328
1329         /* short circuit root database access */
1330         if ( be_isroot( op->o_bd, &op->o_ndn ) ) {
1331 #ifdef NEW_LOGGING
1332                 LDAP_LOG( ACL, DETAIL1, 
1333                            "acl_check_modlist: conn %lu  access granted to root user\n",
1334                            op->o_connid, 0, 0 );
1335 #else
1336                 Debug( LDAP_DEBUG_ACL,
1337                         "<= acl_access_allowed: granted to database root\n",
1338                     0, 0, 0 );
1339 #endif
1340                 return 1;
1341         }
1342
1343         /* use backend default access if no backend acls */
1344         if( op->o_bd != NULL && op->o_bd->be_acl == NULL ) {
1345 #ifdef NEW_LOGGING
1346                 LDAP_LOG( ACL, DETAIL1, 
1347                         "acl_check_modlist: backend default %s access %s to \"%s\"\n",
1348                         access2str( ACL_WRITE ),
1349                         op->o_bd->be_dfltaccess >= ACL_WRITE ? "granted" : "denied", 
1350                         op->o_dn.bv_val  );
1351 #else
1352                 Debug( LDAP_DEBUG_ACL,
1353                         "=> access_allowed: backend default %s access %s to \"%s\"\n",
1354                         access2str( ACL_WRITE ),
1355                         op->o_bd->be_dfltaccess >= ACL_WRITE ? "granted" : "denied", op->o_dn.bv_val );
1356 #endif
1357                 return op->o_bd->be_dfltaccess >= ACL_WRITE;
1358
1359 #ifdef notdef
1360         /* op->o_bd is always non-NULL */
1361         /* use global default access if no global acls */
1362         } else if ( op->o_bd == NULL && global_acl == NULL ) {
1363 #ifdef NEW_LOGGING
1364                 LDAP_LOG( ACL, DETAIL1, 
1365                         "acl_check_modlist: global default %s access %s to \"%s\"\n",
1366                    access2str( ACL_WRITE ),
1367                    global_default_access >= ACL_WRITE ? "granted" : "denied", 
1368                    op->o_dn  );
1369 #else
1370                 Debug( LDAP_DEBUG_ACL,
1371                         "=> access_allowed: global default %s access %s to \"%s\"\n",
1372                         access2str( ACL_WRITE ),
1373                         global_default_access >= ACL_WRITE ? "granted" : "denied", op->o_dn );
1374 #endif
1375                 return global_default_access >= ACL_WRITE;
1376 #endif
1377         }
1378
1379         for ( ; mlist != NULL; mlist = mlist->sml_next ) {
1380                 /*
1381                  * no-user-modification operational attributes are ignored
1382                  * by ACL_WRITE checking as any found here are not provided
1383                  * by the user
1384                  */
1385                 if ( is_at_no_user_mod( mlist->sml_desc->ad_type ) ) {
1386 #ifdef NEW_LOGGING
1387                         LDAP_LOG( ACL, DETAIL1, 
1388                                    "acl_check_modlist: conn %lu  no-user-mod %s: modify access granted\n",
1389                                    op->o_connid, mlist->sml_desc->ad_cname.bv_val , 0 );
1390 #else
1391                         Debug( LDAP_DEBUG_ACL, "acl: no-user-mod %s:"
1392                                 " modify access granted\n",
1393                                 mlist->sml_desc->ad_cname.bv_val, 0, 0 );
1394 #endif
1395                         continue;
1396                 }
1397
1398                 switch ( mlist->sml_op ) {
1399                 case LDAP_MOD_REPLACE:
1400                         /*
1401                          * We must check both permission to delete the whole
1402                          * attribute and permission to add the specific attributes.
1403                          * This prevents abuse from selfwriters.
1404                          */
1405                         if ( ! access_allowed( op, e,
1406                                 mlist->sml_desc, NULL, ACL_WRITE, &state ) )
1407                         {
1408                                 return( 0 );
1409                         }
1410
1411                         if ( mlist->sml_bvalues == NULL ) break;
1412
1413                         /* fall thru to check value to add */
1414
1415                 case LDAP_MOD_ADD:
1416                         assert( mlist->sml_bvalues != NULL );
1417
1418                         for ( bv = mlist->sml_nvalues
1419                                         ? mlist->sml_nvalues : mlist->sml_values;
1420                                 bv->bv_val != NULL; bv++ )
1421                         {
1422                                 if ( ! access_allowed( op, e,
1423                                         mlist->sml_desc, bv, ACL_WRITE, &state ) )
1424                                 {
1425                                         return( 0 );
1426                                 }
1427                         }
1428                         break;
1429
1430                 case LDAP_MOD_DELETE:
1431                         if ( mlist->sml_bvalues == NULL ) {
1432                                 if ( ! access_allowed( op, e,
1433                                         mlist->sml_desc, NULL, ACL_WRITE, NULL ) )
1434                                 {
1435                                         return( 0 );
1436                                 }
1437                                 break;
1438                         }
1439                         for ( bv = mlist->sml_nvalues
1440                                         ? mlist->sml_nvalues : mlist->sml_values;
1441                                 bv->bv_val != NULL; bv++ )
1442                         {
1443                                 if ( ! access_allowed( op, e,
1444                                         mlist->sml_desc, bv, ACL_WRITE, &state ) )
1445                                 {
1446                                         return( 0 );
1447                                 }
1448                         }
1449                         break;
1450
1451                 case SLAP_MOD_SOFTADD:
1452                         /* allow adding attribute via modrdn thru */
1453                         break;
1454
1455                 default:
1456                         assert( 0 );
1457                         return( 0 );
1458                 }
1459         }
1460
1461         return( 1 );
1462 }
1463
1464 static int
1465 aci_get_part(
1466         struct berval *list,
1467         int ix,
1468         char sep,
1469         struct berval *bv )
1470 {
1471         int len;
1472         char *p;
1473
1474         if (bv) {
1475                 bv->bv_len = 0;
1476                 bv->bv_val = NULL;
1477         }
1478         len = list->bv_len;
1479         p = list->bv_val;
1480         while (len >= 0 && --ix >= 0) {
1481                 while (--len >= 0 && *p++ != sep) ;
1482         }
1483         while (len >= 0 && *p == ' ') {
1484                 len--;
1485                 p++;
1486         }
1487         if (len < 0)
1488                 return(-1);
1489
1490         if (!bv)
1491                 return(0);
1492
1493         bv->bv_val = p;
1494         while (--len >= 0 && *p != sep) {
1495                 bv->bv_len++;
1496                 p++;
1497         }
1498         while (bv->bv_len > 0 && *--p == ' ')
1499                 bv->bv_len--;
1500         return(bv->bv_len);
1501 }
1502
1503 BerVarray
1504 aci_set_gather (SetCookie *cookie, struct berval *name, struct berval *attr)
1505 {
1506         AciSetCookie *cp = (AciSetCookie *)cookie;
1507         BerVarray bvals = NULL;
1508         struct berval ndn;
1509
1510         /* this routine needs to return the bervals instead of
1511          * plain strings, since syntax is not known.  It should
1512          * also return the syntax or some "comparison cookie".
1513          */
1514
1515         if (dnNormalize(0, NULL, NULL, name, &ndn, cp->op->o_tmpmemctx) == LDAP_SUCCESS) {
1516                 const char *text;
1517                 AttributeDescription *desc = NULL;
1518                 if (slap_bv2ad(attr, &desc, &text) == LDAP_SUCCESS) {
1519                         backend_attribute(cp->op,
1520                                 cp->e, &ndn, desc, &bvals);
1521                 }
1522                 sl_free(ndn.bv_val, cp->op->o_tmpmemctx);
1523         }
1524         return(bvals);
1525 }
1526
1527 static int
1528 aci_match_set (
1529         struct berval *subj,
1530         Operation *op,
1531         Entry *e,
1532         int setref
1533 )
1534 {
1535         struct berval set = { 0, NULL };
1536         int rc = 0;
1537         AciSetCookie cookie;
1538
1539         if (setref == 0) {
1540                 ber_dupbv_x( &set, subj, op->o_tmpmemctx );
1541         } else {
1542                 struct berval subjdn, ndn = { 0, NULL };
1543                 struct berval setat;
1544                 BerVarray bvals;
1545                 const char *text;
1546                 AttributeDescription *desc = NULL;
1547
1548                 /* format of string is "entry/setAttrName" */
1549                 if (aci_get_part(subj, 0, '/', &subjdn) < 0) {
1550                         return(0);
1551                 }
1552
1553                 if ( aci_get_part(subj, 1, '/', &setat) < 0 ) {
1554                         setat.bv_val = SLAPD_ACI_SET_ATTR;
1555                         setat.bv_len = sizeof(SLAPD_ACI_SET_ATTR)-1;
1556                 }
1557
1558                 if ( setat.bv_val != NULL ) {
1559                         /*
1560                          * NOTE: dnNormalize honors the ber_len field
1561                          * as the length of the dn to be normalized
1562                          */
1563                         if ( dnNormalize(0, NULL, NULL, &subjdn, &ndn, op->o_tmpmemctx) == LDAP_SUCCESS
1564                                 && slap_bv2ad(&setat, &desc, &text) == LDAP_SUCCESS )
1565                         {
1566                                 backend_attribute(op, e,
1567                                         &ndn, desc, &bvals);
1568                                 if ( bvals != NULL ) {
1569                                         if ( bvals[0].bv_val != NULL ) {
1570                                                 int i;
1571                                                 set = bvals[0];
1572                                                 bvals[0].bv_val = NULL;
1573                                                 for (i=1;bvals[i].bv_val;i++);
1574                                                 bvals[0].bv_val = bvals[i-1].bv_val;
1575                                                 bvals[i-1].bv_val = NULL;
1576                                         }
1577                                         ber_bvarray_free_x(bvals, op->o_tmpmemctx);
1578                                 }
1579                         }
1580                         if (ndn.bv_val)
1581                                 free(ndn.bv_val);
1582                 }
1583         }
1584
1585         if (set.bv_val != NULL) {
1586                 cookie.op = op;
1587                 cookie.e = e;
1588                 rc = (slap_set_filter(aci_set_gather, (SetCookie *)&cookie, &set,
1589                         &op->o_ndn, &e->e_nname, NULL) > 0);
1590                 sl_free(set.bv_val, op->o_tmpmemctx);
1591         }
1592         return(rc);
1593 }
1594
1595 #ifdef SLAPD_ACI_ENABLED
1596 static int
1597 aci_list_map_rights(
1598         struct berval *list )
1599 {
1600         struct berval bv;
1601         slap_access_t mask;
1602         int i;
1603
1604         ACL_INIT(mask);
1605         for (i = 0; aci_get_part(list, i, ',', &bv) >= 0; i++) {
1606                 if (bv.bv_len <= 0)
1607                         continue;
1608                 switch (*bv.bv_val) {
1609                 case 'c':
1610                         ACL_PRIV_SET(mask, ACL_PRIV_COMPARE);
1611                         break;
1612                 case 's':
1613                         /* **** NOTE: draft-ietf-ldapext-aci-model-0.3.txt defines
1614                          * the right 's' to mean "set", but in the examples states
1615                          * that the right 's' means "search".  The latter definition
1616                          * is used here.
1617                          */
1618                         ACL_PRIV_SET(mask, ACL_PRIV_SEARCH);
1619                         break;
1620                 case 'r':
1621                         ACL_PRIV_SET(mask, ACL_PRIV_READ);
1622                         break;
1623                 case 'w':
1624                         ACL_PRIV_SET(mask, ACL_PRIV_WRITE);
1625                         break;
1626                 case 'x':
1627                         /* **** NOTE: draft-ietf-ldapext-aci-model-0.3.txt does not 
1628                          * define any equivalent to the AUTH right, so I've just used
1629                          * 'x' for now.
1630                          */
1631                         ACL_PRIV_SET(mask, ACL_PRIV_AUTH);
1632                         break;
1633                 default:
1634                         break;
1635                 }
1636
1637         }
1638         return(mask);
1639 }
1640
1641 static int
1642 aci_list_has_attr(
1643         struct berval *list,
1644         const struct berval *attr,
1645         struct berval *val )
1646 {
1647         struct berval bv, left, right;
1648         int i;
1649
1650         for (i = 0; aci_get_part(list, i, ',', &bv) >= 0; i++) {
1651                 if (aci_get_part(&bv, 0, '=', &left) < 0
1652                         || aci_get_part(&bv, 1, '=', &right) < 0)
1653                 {
1654                         if (ber_bvstrcasecmp(attr, &bv) == 0)
1655                                 return(1);
1656                 } else if (val == NULL) {
1657                         if (ber_bvstrcasecmp(attr, &left) == 0)
1658                                 return(1);
1659                 } else {
1660                         if (ber_bvstrcasecmp(attr, &left) == 0) {
1661                                 /* this is experimental code that implements a
1662                                  * simple (prefix) match of the attribute value.
1663                                  * the ACI draft does not provide for aci's that
1664                                  * apply to specific values, but it would be
1665                                  * nice to have.  If the <attr> part of an aci's
1666                                  * rights list is of the form <attr>=<value>,
1667                                  * that means the aci applies only to attrs with
1668                                  * the given value.  Furthermore, if the attr is
1669                                  * of the form <attr>=<value>*, then <value> is
1670                                  * treated as a prefix, and the aci applies to 
1671                                  * any value with that prefix.
1672                                  *
1673                                  * Ideally, this would allow r.e. matches.
1674                                  */
1675                                 if (aci_get_part(&right, 0, '*', &left) < 0
1676                                         || right.bv_len <= left.bv_len)
1677                                 {
1678                                         if (ber_bvstrcasecmp(val, &right) == 0)
1679                                                 return(1);
1680                                 } else if (val->bv_len >= left.bv_len) {
1681                                         if (strncasecmp( val->bv_val, left.bv_val, left.bv_len ) == 0)
1682                                                 return(1);
1683                                 }
1684                         }
1685                 }
1686         }
1687         return(0);
1688 }
1689
1690 static slap_access_t
1691 aci_list_get_attr_rights(
1692         struct berval *list,
1693         const struct berval *attr,
1694         struct berval *val )
1695 {
1696     struct berval bv;
1697     slap_access_t mask;
1698     int i;
1699
1700         /* loop through each rights/attr pair, skip first part (action) */
1701         ACL_INIT(mask);
1702         for (i = 1; aci_get_part(list, i + 1, ';', &bv) >= 0; i += 2) {
1703                 if (aci_list_has_attr(&bv, attr, val) == 0)
1704                         continue;
1705                 if (aci_get_part(list, i, ';', &bv) < 0)
1706                         continue;
1707                 mask |= aci_list_map_rights(&bv);
1708         }
1709         return(mask);
1710 }
1711
1712 static int
1713 aci_list_get_rights(
1714         struct berval *list,
1715         const struct berval *attr,
1716         struct berval *val,
1717         slap_access_t *grant,
1718         slap_access_t *deny )
1719 {
1720     struct berval perm, actn;
1721     slap_access_t *mask;
1722     int i, found;
1723
1724         if (attr == NULL || attr->bv_len == 0 
1725                         || ber_bvstrcasecmp( attr, &aci_bv_entry ) == 0) {
1726                 attr = &aci_bv_br_entry;
1727         }
1728
1729         found = 0;
1730         ACL_INIT(*grant);
1731         ACL_INIT(*deny);
1732         /* loop through each permissions clause */
1733         for (i = 0; aci_get_part(list, i, '$', &perm) >= 0; i++) {
1734                 if (aci_get_part(&perm, 0, ';', &actn) < 0)
1735                         continue;
1736                 if (ber_bvstrcasecmp( &aci_bv_grant, &actn ) == 0) {
1737                         mask = grant;
1738                 } else if (ber_bvstrcasecmp( &aci_bv_deny, &actn ) == 0) {
1739                         mask = deny;
1740                 } else {
1741                         continue;
1742                 }
1743
1744                 found = 1;
1745                 *mask |= aci_list_get_attr_rights(&perm, attr, val);
1746                 *mask |= aci_list_get_attr_rights(&perm, &aci_bv_br_all, NULL);
1747         }
1748         return(found);
1749 }
1750
1751 static int
1752 aci_group_member (
1753         struct berval *subj,
1754         struct berval *defgrpoc,
1755         struct berval *defgrpat,
1756         Operation               *op,
1757         Entry           *e,
1758         regmatch_t      *matches
1759 )
1760 {
1761         struct berval subjdn;
1762         struct berval grpoc;
1763         struct berval grpat;
1764         ObjectClass *grp_oc = NULL;
1765         AttributeDescription *grp_ad = NULL;
1766         const char *text;
1767         int rc;
1768
1769         /* format of string is "group/objectClassValue/groupAttrName" */
1770         if (aci_get_part(subj, 0, '/', &subjdn) < 0) {
1771                 return(0);
1772         }
1773
1774         if (aci_get_part(subj, 1, '/', &grpoc) < 0) {
1775                 grpoc = *defgrpoc;
1776         }
1777
1778         if (aci_get_part(subj, 2, '/', &grpat) < 0) {
1779                 grpat = *defgrpat;
1780         }
1781
1782         rc = slap_bv2ad( &grpat, &grp_ad, &text );
1783         if( rc != LDAP_SUCCESS ) {
1784                 rc = 0;
1785                 goto done;
1786         }
1787         rc = 0;
1788
1789         grp_oc = oc_bvfind( &grpoc );
1790
1791         if (grp_oc != NULL && grp_ad != NULL ) {
1792                 char buf[ACL_BUF_SIZE];
1793                 struct berval bv, ndn;
1794                 bv.bv_len = sizeof( buf ) - 1;
1795                 bv.bv_val = (char *)&buf;
1796                 string_expand(&bv, &subjdn, e->e_ndn, matches);
1797                 if ( dnNormalize(0, NULL, NULL, &bv, &ndn, op->o_tmpmemctx) == LDAP_SUCCESS ) {
1798                         rc = (backend_group(op, e, &ndn, &op->o_ndn,
1799                                 grp_oc, grp_ad) == 0);
1800                         free( ndn.bv_val );
1801                 }
1802         }
1803
1804 done:
1805         return(rc);
1806 }
1807
1808 static int
1809 aci_mask(
1810     Operation           *op,
1811     Entry                       *e,
1812         AttributeDescription *desc,
1813     struct berval       *val,
1814     struct berval       *aci,
1815         regmatch_t              *matches,
1816         slap_access_t   *grant,
1817         slap_access_t   *deny,
1818         struct berval   *scope
1819 )
1820 {
1821     struct berval bv, perms, sdn;
1822         int rc;
1823                 
1824
1825         assert( desc->ad_cname.bv_val != NULL );
1826
1827         /* parse an aci of the form:
1828                 oid#scope#action;rights;attr;rights;attr$action;rights;attr;rights;attr#dnType#subjectDN
1829
1830            See draft-ietf-ldapext-aci-model-04.txt section 9.1 for
1831            a full description of the format for this attribute.
1832            Differences: "this" in the draft is "self" here, and
1833            "self" and "public" is in the position of dnType.
1834
1835            For now, this routine only supports scope=entry.
1836          */
1837         /* check that the aci has all 5 components */
1838         if (aci_get_part(aci, 4, '#', NULL) < 0)
1839                 return(0);
1840
1841         /* check that the aci family is supported */
1842         if (aci_get_part(aci, 0, '#', &bv) < 0)
1843                 return(0);
1844
1845         /* check that the scope matches */
1846         if (aci_get_part(aci, 1, '#', &bv) < 0
1847                 || ber_bvstrcasecmp( scope, &bv ) != 0)
1848         {
1849                 return(0);
1850         }
1851
1852         /* get the list of permissions clauses, bail if empty */
1853         if (aci_get_part(aci, 2, '#', &perms) <= 0)
1854                 return(0);
1855
1856         /* check if any permissions allow desired access */
1857         if (aci_list_get_rights(&perms, &desc->ad_cname, val, grant, deny) == 0)
1858                 return(0);
1859
1860         /* see if we have a DN match */
1861         if (aci_get_part(aci, 3, '#', &bv) < 0)
1862                 return(0);
1863
1864         if (aci_get_part(aci, 4, '#', &sdn) < 0)
1865                 return(0);
1866
1867         if (ber_bvstrcasecmp( &aci_bv_access_id, &bv ) == 0) {
1868                 struct berval ndn;
1869                 rc = 0;
1870                 if ( dnNormalize(0, NULL, NULL, &sdn, &ndn, op->o_tmpmemctx) == LDAP_SUCCESS ) {
1871                         if (dn_match( &op->o_ndn, &ndn))
1872                                 rc = 1;
1873                         free(ndn.bv_val);
1874                 }
1875                 return (rc);
1876
1877         } else if (ber_bvstrcasecmp( &aci_bv_public, &bv ) == 0) {
1878                 return(1);
1879
1880         } else if (ber_bvstrcasecmp( &aci_bv_self, &bv ) == 0) {
1881                 if (dn_match(&op->o_ndn, &e->e_nname))
1882                         return(1);
1883
1884         } else if (ber_bvstrcasecmp( &aci_bv_dnattr, &bv ) == 0) {
1885                 Attribute *at;
1886                 AttributeDescription *ad = NULL;
1887                 const char *text;
1888
1889                 rc = slap_bv2ad( &sdn, &ad, &text );
1890
1891                 if( rc != LDAP_SUCCESS ) {
1892                         return 0;
1893                 }
1894
1895                 rc = 0;
1896
1897                 bv = op->o_ndn;
1898
1899                 for(at = attrs_find( e->e_attrs, ad );
1900                         at != NULL;
1901                         at = attrs_find( at->a_next, ad ) )
1902                 {
1903                         if (value_find_ex( ad,
1904                                 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1905                                         SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1906                                 at->a_nvals,
1907                                 &bv, op->o_tmpmemctx) == 0 )
1908                         {
1909                                 rc = 1;
1910                                 break;
1911                         }
1912                 }
1913
1914                 return rc;
1915
1916
1917         } else if (ber_bvstrcasecmp( &aci_bv_group, &bv ) == 0) {
1918                 if (aci_group_member(&sdn, &aci_bv_group_class, &aci_bv_group_attr, op, e, matches))
1919                         return(1);
1920
1921         } else if (ber_bvstrcasecmp( &aci_bv_role, &bv ) == 0) {
1922                 if (aci_group_member(&sdn, &aci_bv_role_class, &aci_bv_role_attr, op, e, matches))
1923                         return(1);
1924
1925         } else if (ber_bvstrcasecmp( &aci_bv_set, &bv ) == 0) {
1926                 if (aci_match_set(&sdn, op, e, 0))
1927                         return(1);
1928
1929         } else if (ber_bvstrcasecmp( &aci_bv_set_ref, &bv ) == 0) {
1930                 if (aci_match_set(&sdn, op, e, 1))
1931                         return(1);
1932
1933         }
1934
1935         return(0);
1936 }
1937
1938 #endif  /* SLAPD_ACI_ENABLED */
1939
1940 static void
1941 string_expand(
1942         struct berval *bv,
1943         struct berval *pat,
1944         char *match,
1945         regmatch_t *matches)
1946 {
1947         ber_len_t       size;
1948         char   *sp;
1949         char   *dp;
1950         int     flag;
1951
1952         size = 0;
1953         bv->bv_val[0] = '\0';
1954         bv->bv_len--; /* leave space for lone $ */
1955
1956         flag = 0;
1957         for ( dp = bv->bv_val, sp = pat->bv_val; size < bv->bv_len &&
1958                 sp < pat->bv_val + pat->bv_len ; sp++ )
1959         {
1960                 /* did we previously see a $ */
1961                 if ( flag ) {
1962                         if ( flag == 1 && *sp == '$' ) {
1963                                 *dp++ = '$';
1964                                 size++;
1965                                 flag = 0;
1966
1967                         } else if ( flag == 1 && *sp == '{' /*'}'*/) {
1968                                 flag = 2;
1969
1970                         } else if ( *sp >= '0' && *sp <= '9' ) {
1971                                 int     n;
1972                                 int     i;
1973                                 int     l;
1974
1975                                 n = *sp - '0';
1976
1977                                 if ( flag == 2 ) {
1978                                         for ( sp++; *sp != '\0' && *sp != /*'{'*/ '}'; sp++ ) {
1979                                                 if ( *sp >= '0' && *sp <= '9' ) {
1980                                                         n = 10*n + ( *sp - '0' );
1981                                                 }
1982                                         }
1983
1984                                         if ( *sp != /*'{'*/ '}' ) {
1985                                                 /* error */
1986                                         }
1987                                 }
1988
1989                                 if ( n >= MAXREMATCHES ) {
1990                                 
1991                                 }
1992                                 
1993                                 *dp = '\0';
1994                                 i = matches[n].rm_so;
1995                                 l = matches[n].rm_eo; 
1996                                 for ( ; size < bv->bv_len && i < l; size++, i++ ) {
1997                                         *dp++ = match[i];
1998                                 }
1999                                 *dp = '\0';
2000
2001                                 flag = 0;
2002                         }
2003                 } else {
2004                         if (*sp == '$') {
2005                                 flag = 1;
2006                         } else {
2007                                 *dp++ = *sp;
2008                                 size++;
2009                         }
2010                 }
2011         }
2012
2013         if ( flag ) {
2014                 /* must have ended with a single $ */
2015                 *dp++ = '$';
2016                 size++;
2017         }
2018
2019         *dp = '\0';
2020         bv->bv_len = size;
2021
2022 #ifdef NEW_LOGGING
2023         LDAP_LOG( ACL, DETAIL1, 
2024            "string_expand:  pattern = %.*s\n", (int)pat->bv_len, pat->bv_val, 0 );
2025         LDAP_LOG( ACL, DETAIL1, "string_expand:  expanded = %s\n", bv->bv_val, 0, 0 );
2026 #else
2027         Debug( LDAP_DEBUG_TRACE, "=> string_expand: pattern:  %.*s\n", (int)pat->bv_len, pat->bv_val, 0 );
2028         Debug( LDAP_DEBUG_TRACE, "=> string_expand: expanded: %s\n", bv->bv_val, 0, 0 );
2029 #endif
2030 }
2031
2032 static int
2033 regex_matches(
2034         struct berval *pat,                     /* pattern to expand and match against */
2035         char *str,                              /* string to match against pattern */
2036         char *buf,                              /* buffer with $N expansion variables */
2037         regmatch_t *matches             /* offsets in buffer for $N expansion variables */
2038 )
2039 {
2040         regex_t re;
2041         char newbuf[ACL_BUF_SIZE];
2042         struct berval bv;
2043         int     rc;
2044
2045         bv.bv_len = sizeof(newbuf) - 1;
2046         bv.bv_val = newbuf;
2047
2048         if(str == NULL) str = "";
2049
2050         string_expand(&bv, pat, buf, matches);
2051         if (( rc = regcomp(&re, newbuf, REG_EXTENDED|REG_ICASE))) {
2052                 char error[ACL_BUF_SIZE];
2053                 regerror(rc, &re, error, sizeof(error));
2054
2055 #ifdef NEW_LOGGING
2056                 LDAP_LOG( ACL, ERR, 
2057                            "regex_matches: compile( \"%s\", \"%s\") failed %s\n",
2058                            pat->bv_val, str, error  );
2059 #else
2060                 Debug( LDAP_DEBUG_TRACE,
2061                     "compile( \"%s\", \"%s\") failed %s\n",
2062                         pat->bv_val, str, error );
2063 #endif
2064                 return( 0 );
2065         }
2066
2067         rc = regexec(&re, str, 0, NULL, 0);
2068         regfree( &re );
2069
2070 #ifdef NEW_LOGGING
2071         LDAP_LOG( ACL, DETAIL2, "regex_matches: string:   %s\n", str, 0, 0 );
2072         LDAP_LOG( ACL, DETAIL2, "regex_matches: rc:     %d  %s\n",
2073                    rc, rc ? "matches" : "no matches", 0  );
2074 #else
2075         Debug( LDAP_DEBUG_TRACE,
2076             "=> regex_matches: string:   %s\n", str, 0, 0 );
2077         Debug( LDAP_DEBUG_TRACE,
2078             "=> regex_matches: rc: %d %s\n",
2079                 rc, !rc ? "matches" : "no matches", 0 );
2080 #endif
2081         return( !rc );
2082 }
2083