Back to index

openldap  2.4.31
acl.c
Go to the documentation of this file.
00001 /* acl.c - routines to parse and check acl's */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 1998-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
00017  * All rights reserved.
00018  *
00019  * Redistribution and use in source and binary forms are permitted
00020  * provided that this notice is preserved and that due credit is given
00021  * to the University of Michigan at Ann Arbor. The name of the University
00022  * may not be used to endorse or promote products derived from this
00023  * software without specific prior written permission. This software
00024  * is provided ``as is'' without express or implied warranty.
00025  */
00026 
00027 #include "portable.h"
00028 
00029 #include <stdio.h>
00030 
00031 #include <ac/regex.h>
00032 #include <ac/socket.h>
00033 #include <ac/string.h>
00034 
00035 #include "slap.h"
00036 #include "sets.h"
00037 #include "lber_pvt.h"
00038 #include "lutil.h"
00039 
00040 #define ACL_BUF_SIZE        1024   /* use most appropriate size */
00041 
00042 static const struct berval  acl_bv_ip_eq = BER_BVC( "IP=" );
00043 #ifdef LDAP_PF_INET6
00044 static const struct berval  acl_bv_ipv6_eq = BER_BVC( "IP=[" );
00045 #endif /* LDAP_PF_INET6 */
00046 #ifdef LDAP_PF_LOCAL
00047 static const struct berval  acl_bv_path_eq = BER_BVC("PATH=");
00048 #endif /* LDAP_PF_LOCAL */
00049 
00050 static AccessControl * slap_acl_get(
00051        AccessControl *ac, int *count,
00052        Operation *op, Entry *e,
00053        AttributeDescription *desc,
00054        struct berval *val,
00055        AclRegexMatches *matches,
00056        slap_mask_t *mask,
00057        AccessControlState *state );
00058 
00059 static slap_control_t slap_acl_mask(
00060        AccessControl *ac,
00061        AccessControl *prev,
00062        slap_mask_t *mask,
00063        Operation *op, Entry *e,
00064        AttributeDescription *desc,
00065        struct berval *val,
00066        AclRegexMatches *matches,
00067        int count,
00068        AccessControlState *state,
00069        slap_access_t access );
00070 
00071 static int    regex_matches(
00072        struct berval *pat, char *str,
00073        struct berval *dn_matches, struct berval *val_matches,
00074        AclRegexMatches *matches);
00075 
00076 typedef       struct AclSetCookie {
00077        SetCookie     asc_cookie;
00078 #define       asc_op        asc_cookie.set_op
00079        Entry         *asc_e;
00080 } AclSetCookie;
00081 
00082 
00083 SLAP_SET_GATHER acl_set_gather;
00084 SLAP_SET_GATHER acl_set_gather2;
00085 
00086 /*
00087  * access_allowed - check whether op->o_ndn is allowed the requested access
00088  * to entry e, attribute attr, value val.  if val is null, access to
00089  * the whole attribute is assumed (all values).
00090  *
00091  * This routine loops through all access controls and calls
00092  * slap_acl_mask() on each applicable access control.
00093  * The loop exits when a definitive answer is reached or
00094  * or no more controls remain.
00095  *
00096  * returns:
00097  *            0      access denied
00098  *            1      access granted
00099  *
00100  * Notes:
00101  * - can be legally called with op == NULL
00102  * - can be legally called with op->o_bd == NULL
00103  */
00104 
00105 int
00106 slap_access_always_allowed(
00107        Operation            *op,
00108        Entry                *e,
00109        AttributeDescription *desc,
00110        struct berval        *val,
00111        slap_access_t        access,
00112        AccessControlState   *state,
00113        slap_mask_t          *maskp )
00114 {
00115        assert( maskp != NULL );
00116 
00117        /* assign all */
00118        ACL_LVL_ASSIGN_MANAGE( *maskp );
00119 
00120        return 1;
00121 }
00122 
00123 #define MATCHES_DNMAXCOUNT(m)                                  \
00124        ( sizeof ( (m)->dn_data ) / sizeof( *(m)->dn_data ) )
00125 #define MATCHES_VALMAXCOUNT(m)                                 \
00126        ( sizeof ( (m)->val_data ) / sizeof( *(m)->val_data ) )
00127 #define MATCHES_MEMSET(m) do {                                 \
00128        memset( (m)->dn_data, '\0', sizeof( (m)->dn_data ) );   \
00129        memset( (m)->val_data, '\0', sizeof( (m)->val_data ) ); \
00130        (m)->dn_count = MATCHES_DNMAXCOUNT( (m) );              \
00131        (m)->val_count = MATCHES_VALMAXCOUNT( (m) );            \
00132 } while ( 0 /* CONSTCOND */ )
00133 
00134 int
00135 slap_access_allowed(
00136        Operation            *op,
00137        Entry                *e,
00138        AttributeDescription *desc,
00139        struct berval        *val,
00140        slap_access_t        access,
00141        AccessControlState   *state,
00142        slap_mask_t          *maskp )
00143 {
00144        int                         ret = 1;
00145        int                         count;
00146        AccessControl               *a, *prev;
00147 
00148 #ifdef LDAP_DEBUG
00149        char                        accessmaskbuf[ACCESSMASK_MAXLEN];
00150 #endif
00151        slap_mask_t                 mask;
00152        slap_control_t                     control;
00153        slap_access_t               access_level;
00154        const char                  *attr;
00155        AclRegexMatches                    matches;
00156        AccessControlState          acl_state = ACL_STATE_INIT;
00157        static AccessControlState   state_init = ACL_STATE_INIT;
00158 
00159        assert( op != NULL );
00160        assert( e != NULL );
00161        assert( desc != NULL );
00162        assert( maskp != NULL );
00163 
00164        access_level = ACL_LEVEL( access );
00165        attr = desc->ad_cname.bv_val;
00166 
00167        assert( attr != NULL );
00168 
00169        ACL_INIT( mask );
00170 
00171        /* grant database root access */
00172        if ( be_isroot( op ) ) {
00173               Debug( LDAP_DEBUG_ACL, "<= root access granted\n", 0, 0, 0 );
00174               mask = ACL_LVL_MANAGE;
00175               goto done;
00176        }
00177 
00178        /*
00179         * no-user-modification operational attributes are ignored
00180         * by ACL_WRITE checking as any found here are not provided
00181         * by the user
00182         *
00183         * NOTE: but they are not ignored for ACL_MANAGE, because
00184         * if we get here it means a non-root user is trying to 
00185         * manage data, so we need to check its privileges.
00186         */
00187        if ( access_level == ACL_WRITE
00188               && is_at_no_user_mod( desc->ad_type )
00189               && desc != slap_schema.si_ad_entry
00190               && desc != slap_schema.si_ad_children )
00191        {
00192               Debug( LDAP_DEBUG_ACL, "NoUserMod Operational attribute:"
00193                      " %s access granted\n",
00194                      attr, 0, 0 );
00195               goto done;
00196        }
00197 
00198        /* use backend default access if no backend acls */
00199        if ( op->o_bd->be_acl == NULL && frontendDB->be_acl == NULL ) {
00200               int    i;
00201 
00202               Debug( LDAP_DEBUG_ACL,
00203                      "=> slap_access_allowed: backend default %s "
00204                      "access %s to \"%s\"\n",
00205                      access2str( access ),
00206                      op->o_bd->be_dfltaccess >= access_level ? "granted" : "denied",
00207                      op->o_dn.bv_val ? op->o_dn.bv_val : "(anonymous)" );
00208               ret = op->o_bd->be_dfltaccess >= access_level;
00209 
00210               mask = ACL_PRIV_LEVEL;
00211               for ( i = ACL_NONE; i <= op->o_bd->be_dfltaccess; i++ ) {
00212                      ACL_PRIV_SET( mask, ACL_ACCESS2PRIV( i ) );
00213               }
00214 
00215               goto done;
00216        }
00217 
00218        ret = 0;
00219        control = ACL_BREAK;
00220 
00221        if ( state == NULL )
00222               state = &acl_state;
00223        if ( state->as_desc == desc &&
00224               state->as_access == access &&
00225               state->as_vd_acl_present )
00226        {
00227               a = state->as_vd_acl;
00228               count = state->as_vd_acl_count;
00229               if ( state->as_fe_done )
00230                      state->as_fe_done--;
00231               ACL_PRIV_ASSIGN( mask, state->as_vd_mask );
00232        } else {
00233               *state = state_init;
00234 
00235               a = NULL;
00236               count = 0;
00237               ACL_PRIV_ASSIGN( mask, *maskp );
00238        }
00239 
00240        MATCHES_MEMSET( &matches );
00241        prev = a;
00242 
00243        while ( ( a = slap_acl_get( a, &count, op, e, desc, val,
00244               &matches, &mask, state ) ) != NULL )
00245        {
00246               int i; 
00247               int dnmaxcount = MATCHES_DNMAXCOUNT( &matches );
00248               int valmaxcount = MATCHES_VALMAXCOUNT( &matches );
00249               regmatch_t *dn_data = matches.dn_data;
00250               regmatch_t *val_data = matches.val_data;
00251 
00252               /* DN matches */
00253               for ( i = 0; i < dnmaxcount && dn_data[i].rm_eo > 0; i++ ) {
00254                      char *data = e->e_ndn;
00255 
00256                      Debug( LDAP_DEBUG_ACL, "=> match[dn%d]: %d %d ", i,
00257                             (int)dn_data[i].rm_so, 
00258                             (int)dn_data[i].rm_eo );
00259                      if ( dn_data[i].rm_so <= dn_data[0].rm_eo ) {
00260                             int n;
00261                             for ( n = dn_data[i].rm_so; 
00262                                   n < dn_data[i].rm_eo; n++ ) {
00263                                    Debug( LDAP_DEBUG_ACL, "%c", 
00264                                           data[n], 0, 0 );
00265                             }
00266                      }
00267                      Debug( LDAP_DEBUG_ACL, "\n", 0, 0, 0 );
00268               }
00269 
00270               /* val matches */
00271               for ( i = 0; i < valmaxcount && val_data[i].rm_eo > 0; i++ ) {
00272                      char *data = val->bv_val;
00273 
00274                      Debug( LDAP_DEBUG_ACL, "=> match[val%d]: %d %d ", i,
00275                             (int)val_data[i].rm_so, 
00276                             (int)val_data[i].rm_eo );
00277                      if ( val_data[i].rm_so <= val_data[0].rm_eo ) {
00278                             int n;
00279                             for ( n = val_data[i].rm_so; 
00280                                   n < val_data[i].rm_eo; n++ ) {
00281                                    Debug( LDAP_DEBUG_ACL, "%c", 
00282                                           data[n], 0, 0 );
00283                             }
00284                      }
00285                      Debug( LDAP_DEBUG_ACL, "\n", 0, 0, 0 );
00286               }
00287 
00288               control = slap_acl_mask( a, prev, &mask, op,
00289                      e, desc, val, &matches, count, state, access );
00290 
00291               if ( control != ACL_BREAK ) {
00292                      break;
00293               }
00294 
00295               MATCHES_MEMSET( &matches );
00296               prev = a;
00297        }
00298 
00299        if ( ACL_IS_INVALID( mask ) ) {
00300               Debug( LDAP_DEBUG_ACL,
00301                      "=> slap_access_allowed: \"%s\" (%s) invalid!\n",
00302                      e->e_dn, attr, 0 );
00303               ACL_PRIV_ASSIGN( mask, *maskp );
00304 
00305        } else if ( control == ACL_BREAK ) {
00306               Debug( LDAP_DEBUG_ACL,
00307                      "=> slap_access_allowed: no more rules\n", 0, 0, 0 );
00308 
00309               goto done;
00310        }
00311 
00312        ret = ACL_GRANT( mask, access );
00313 
00314        Debug( LDAP_DEBUG_ACL,
00315               "=> slap_access_allowed: %s access %s by %s\n",
00316               access2str( access ), ret ? "granted" : "denied",
00317               accessmask2str( mask, accessmaskbuf, 1 ) );
00318 
00319 done:
00320        ACL_PRIV_ASSIGN( *maskp, mask );
00321        return ret;
00322 }
00323 
00324 int
00325 fe_access_allowed(
00326        Operation            *op,
00327        Entry                *e,
00328        AttributeDescription *desc,
00329        struct berval        *val,
00330        slap_access_t        access,
00331        AccessControlState   *state,
00332        slap_mask_t          *maskp )
00333 {
00334        BackendDB            *be_orig;
00335        int                  rc;
00336 
00337        /*
00338         * NOTE: control gets here if FIXME
00339         * if an appropriate backend cannot be selected for the operation,
00340         * we assume that the frontend should handle this
00341         * FIXME: should select_backend() take care of this,
00342         * and return frontendDB instead of NULL?  maybe for some value
00343         * of the flags?
00344         */
00345        be_orig = op->o_bd;
00346 
00347        if ( op->o_bd == NULL ) {
00348               op->o_bd = select_backend( &op->o_req_ndn, 0 );
00349               if ( op->o_bd == NULL )
00350                      op->o_bd = frontendDB;
00351        }
00352        rc = slap_access_allowed( op, e, desc, val, access, state, maskp );
00353        op->o_bd = be_orig;
00354 
00355        return rc;
00356 }
00357 
00358 int
00359 access_allowed_mask(
00360        Operation            *op,
00361        Entry                *e,
00362        AttributeDescription *desc,
00363        struct berval        *val,
00364        slap_access_t        access,
00365        AccessControlState   *state,
00366        slap_mask_t          *maskp )
00367 {
00368        int                         ret = 1;
00369        int                         be_null = 0;
00370 
00371 #ifdef LDAP_DEBUG
00372        char                        accessmaskbuf[ACCESSMASK_MAXLEN];
00373 #endif
00374        slap_mask_t                 mask;
00375        slap_access_t               access_level;
00376        const char                  *attr;
00377 
00378        assert( e != NULL );
00379        assert( desc != NULL );
00380 
00381        access_level = ACL_LEVEL( access );
00382 
00383        assert( access_level > ACL_NONE );
00384 
00385        ACL_INIT( mask );
00386        if ( maskp ) ACL_INVALIDATE( *maskp );
00387 
00388        attr = desc->ad_cname.bv_val;
00389 
00390        assert( attr != NULL );
00391 
00392        if ( op ) {
00393               if ( op->o_acl_priv != ACL_NONE ) {
00394                      access = op->o_acl_priv;
00395 
00396               } else if ( op->o_is_auth_check &&
00397                      ( access_level == ACL_SEARCH || access_level == ACL_READ ) )
00398               {
00399                      access = ACL_AUTH;
00400 
00401               } else if ( get_relax( op ) && access_level == ACL_WRITE &&
00402                      desc == slap_schema.si_ad_entry )
00403               {
00404                      access = ACL_MANAGE;
00405               }
00406        }
00407 
00408        if ( state != NULL ) {
00409               if ( state->as_desc == desc &&
00410                      state->as_access == access &&
00411                      state->as_result != -1 &&
00412                      !state->as_vd_acl_present )
00413                      {
00414                      Debug( LDAP_DEBUG_ACL,
00415                             "=> access_allowed: result was in cache (%s)\n",
00416                             attr, 0, 0 );
00417                             return state->as_result;
00418               } else {
00419                      Debug( LDAP_DEBUG_ACL,
00420                             "=> access_allowed: result not in cache (%s)\n",
00421                             attr, 0, 0 );
00422               }
00423        }
00424 
00425        Debug( LDAP_DEBUG_ACL,
00426               "=> access_allowed: %s access to \"%s\" \"%s\" requested\n",
00427               access2str( access ), e->e_dn, attr );
00428 
00429        if ( op == NULL ) {
00430               /* no-op call */
00431               goto done;
00432        }
00433 
00434        if ( op->o_bd == NULL ) {
00435               op->o_bd = LDAP_STAILQ_FIRST( &backendDB );
00436               be_null = 1;
00437 
00438               /* FIXME: experimental; use first backend rules
00439                * iff there is no global_acl (ITS#3100)
00440                */
00441               if ( frontendDB->be_acl != NULL ) {
00442                      op->o_bd = frontendDB;
00443               }
00444        }
00445        assert( op->o_bd != NULL );
00446 
00447        /* this is enforced in backend_add() */
00448        if ( op->o_bd->bd_info->bi_access_allowed ) {
00449               /* delegate to backend */
00450               ret = op->o_bd->bd_info->bi_access_allowed( op, e,
00451                             desc, val, access, state, &mask );
00452 
00453        } else {
00454               /* use default (but pass through frontend
00455                * for global ACL overlays) */
00456               ret = frontendDB->bd_info->bi_access_allowed( op, e,
00457                             desc, val, access, state, &mask );
00458        }
00459 
00460        if ( !ret ) {
00461               if ( ACL_IS_INVALID( mask ) ) {
00462                      Debug( LDAP_DEBUG_ACL,
00463                             "=> access_allowed: \"%s\" (%s) invalid!\n",
00464                             e->e_dn, attr, 0 );
00465                      ACL_INIT( mask );
00466 
00467               } else {
00468                      Debug( LDAP_DEBUG_ACL,
00469                             "=> access_allowed: no more rules\n", 0, 0, 0 );
00470 
00471                      goto done;
00472               }
00473        }
00474 
00475        Debug( LDAP_DEBUG_ACL,
00476               "=> access_allowed: %s access %s by %s\n",
00477               access2str( access ), ret ? "granted" : "denied",
00478               accessmask2str( mask, accessmaskbuf, 1 ) );
00479 
00480 done:
00481        if ( state != NULL ) {
00482               state->as_access = access;
00483                      state->as_result = ret;
00484               state->as_desc = desc;
00485        }
00486        if ( be_null ) op->o_bd = NULL;
00487        if ( maskp ) ACL_PRIV_ASSIGN( *maskp, mask );
00488        return ret;
00489 }
00490 
00491 
00492 /*
00493  * slap_acl_get - return the acl applicable to entry e, attribute
00494  * attr.  the acl returned is suitable for use in subsequent calls to
00495  * acl_access_allowed().
00496  */
00497 
00498 static AccessControl *
00499 slap_acl_get(
00500        AccessControl *a,
00501        int                  *count,
00502        Operation     *op,
00503        Entry         *e,
00504        AttributeDescription *desc,
00505        struct berval *val,
00506        AclRegexMatches      *matches,
00507        slap_mask_t *mask,
00508        AccessControlState *state )
00509 {
00510        const char *attr;
00511        ber_len_t dnlen;
00512        AccessControl *prev;
00513 
00514        assert( e != NULL );
00515        assert( count != NULL );
00516        assert( desc != NULL );
00517        assert( state != NULL );
00518 
00519        attr = desc->ad_cname.bv_val;
00520 
00521        assert( attr != NULL );
00522 
00523        if( a == NULL ) {
00524               if( op->o_bd == NULL || op->o_bd->be_acl == NULL ) {
00525                      a = frontendDB->be_acl;
00526               } else {
00527                      a = op->o_bd->be_acl;
00528               }
00529               prev = NULL;
00530 
00531               assert( a != NULL );
00532               if ( a == frontendDB->be_acl )
00533                      state->as_fe_done = 1;
00534        } else {
00535               prev = a;
00536               a = a->acl_next;
00537        }
00538 
00539        dnlen = e->e_nname.bv_len;
00540 
00541  retry:
00542        for ( ; a != NULL; prev = a, a = a->acl_next ) {
00543               (*count) ++;
00544 
00545               if ( a != frontendDB->be_acl && state->as_fe_done )
00546                      state->as_fe_done++;
00547 
00548               if ( a->acl_dn_pat.bv_len || ( a->acl_dn_style != ACL_STYLE_REGEX )) {
00549                      if ( a->acl_dn_style == ACL_STYLE_REGEX ) {
00550                             Debug( LDAP_DEBUG_ACL, "=> dnpat: [%d] %s nsub: %d\n", 
00551                                    *count, a->acl_dn_pat.bv_val, (int) a->acl_dn_re.re_nsub );
00552                             if ( regexec ( &a->acl_dn_re, 
00553                                           e->e_ndn, 
00554                                           matches->dn_count, 
00555                                           matches->dn_data, 0 ) )
00556                                    continue;
00557 
00558                      } else {
00559                             ber_len_t patlen;
00560 
00561                             Debug( LDAP_DEBUG_ACL, "=> dn: [%d] %s\n", 
00562                                    *count, a->acl_dn_pat.bv_val, 0 );
00563                             patlen = a->acl_dn_pat.bv_len;
00564                             if ( dnlen < patlen )
00565                                    continue;
00566 
00567                             if ( a->acl_dn_style == ACL_STYLE_BASE ) {
00568                                    /* base dn -- entire object DN must match */
00569                                    if ( dnlen != patlen )
00570                                           continue;
00571 
00572                             } else if ( a->acl_dn_style == ACL_STYLE_ONE ) {
00573                                    ber_len_t     rdnlen = 0;
00574                                    ber_len_t     sep = 0;
00575 
00576                                    if ( dnlen <= patlen )
00577                                           continue;
00578 
00579                                    if ( patlen > 0 ) {
00580                                           if ( !DN_SEPARATOR( e->e_ndn[dnlen - patlen - 1] ) )
00581                                                  continue;
00582                                           sep = 1;
00583                                    }
00584 
00585                                    rdnlen = dn_rdnlen( NULL, &e->e_nname );
00586                                    if ( rdnlen + patlen + sep != dnlen )
00587                                           continue;
00588 
00589                             } else if ( a->acl_dn_style == ACL_STYLE_SUBTREE ) {
00590                                    if ( dnlen > patlen && !DN_SEPARATOR( e->e_ndn[dnlen - patlen - 1] ) )
00591                                           continue;
00592 
00593                             } else if ( a->acl_dn_style == ACL_STYLE_CHILDREN ) {
00594                                    if ( dnlen <= patlen )
00595                                           continue;
00596                                    if ( !DN_SEPARATOR( e->e_ndn[dnlen - patlen - 1] ) )
00597                                           continue;
00598                             }
00599 
00600                             if ( strcmp( a->acl_dn_pat.bv_val, e->e_ndn + dnlen - patlen ) != 0 )
00601                                    continue;
00602                      }
00603 
00604                      Debug( LDAP_DEBUG_ACL, "=> acl_get: [%d] matched\n",
00605                             *count, 0, 0 );
00606               }
00607 
00608               if ( a->acl_attrs && !ad_inlist( desc, a->acl_attrs ) ) {
00609                      matches->dn_data[0].rm_so = -1;
00610                      matches->dn_data[0].rm_eo = -1;
00611                      matches->val_data[0].rm_so = -1;
00612                      matches->val_data[0].rm_eo = -1;
00613                      continue;
00614               }
00615 
00616               /* Is this ACL only for a specific value? */
00617               if ( a->acl_attrval.bv_len ) {
00618                      if ( val == NULL ) {
00619                             continue;
00620                      }
00621 
00622                      if ( !state->as_vd_acl_present ) {
00623                             state->as_vd_acl_present = 1;
00624                             state->as_vd_acl = prev;
00625                             state->as_vd_acl_count = *count - 1;
00626                             ACL_PRIV_ASSIGN ( state->as_vd_mask, *mask );
00627                      }
00628 
00629                      if ( a->acl_attrval_style == ACL_STYLE_REGEX ) {
00630                             Debug( LDAP_DEBUG_ACL,
00631                                    "acl_get: valpat %s\n",
00632                                    a->acl_attrval.bv_val, 0, 0 );
00633                             if ( regexec ( &a->acl_attrval_re, 
00634                                               val->bv_val, 
00635                                               matches->val_count, 
00636                                               matches->val_data, 0 ) )
00637                             {
00638                                    continue;
00639                             }
00640 
00641                      } else {
00642                             int match = 0;
00643                             const char *text;
00644                             Debug( LDAP_DEBUG_ACL,
00645                                    "acl_get: val %s\n",
00646                                    a->acl_attrval.bv_val, 0, 0 );
00647        
00648                             if ( a->acl_attrs[0].an_desc->ad_type->sat_syntax != slap_schema.si_syn_distinguishedName ) {
00649                                    if (value_match( &match, desc,
00650                                           a->acl_attrval_mr, 0,
00651                                           val, &a->acl_attrval, &text ) != LDAP_SUCCESS ||
00652                                                  match )
00653                                           continue;
00654                                    
00655                             } else {
00656                                    ber_len_t     patlen, vdnlen;
00657        
00658                                    patlen = a->acl_attrval.bv_len;
00659                                    vdnlen = val->bv_len;
00660        
00661                                    if ( vdnlen < patlen )
00662                                           continue;
00663        
00664                                    if ( a->acl_attrval_style == ACL_STYLE_BASE ) {
00665                                           if ( vdnlen > patlen )
00666                                                  continue;
00667        
00668                                    } else if ( a->acl_attrval_style == ACL_STYLE_ONE ) {
00669                                           ber_len_t     rdnlen = 0;
00670        
00671                                           if ( !DN_SEPARATOR( val->bv_val[vdnlen - patlen - 1] ) )
00672                                                  continue;
00673        
00674                                           rdnlen = dn_rdnlen( NULL, val );
00675                                           if ( rdnlen + patlen + 1 != vdnlen )
00676                                                  continue;
00677        
00678                                    } else if ( a->acl_attrval_style == ACL_STYLE_SUBTREE ) {
00679                                           if ( vdnlen > patlen && !DN_SEPARATOR( val->bv_val[vdnlen - patlen - 1] ) )
00680                                                  continue;
00681        
00682                                    } else if ( a->acl_attrval_style == ACL_STYLE_CHILDREN ) {
00683                                           if ( vdnlen <= patlen )
00684                                                  continue;
00685        
00686                                           if ( !DN_SEPARATOR( val->bv_val[vdnlen - patlen - 1] ) )
00687                                                  continue;
00688                                    }
00689        
00690                                    if ( strcmp( a->acl_attrval.bv_val, val->bv_val + vdnlen - patlen ) )
00691                                           continue;
00692                             }
00693                      }
00694               }
00695 
00696               if ( a->acl_filter != NULL ) {
00697                      ber_int_t rc = test_filter( NULL, e, a->acl_filter );
00698                      if ( rc != LDAP_COMPARE_TRUE ) {
00699                             continue;
00700                      }
00701               }
00702 
00703               Debug( LDAP_DEBUG_ACL, "=> acl_get: [%d] attr %s\n",
00704                      *count, attr, 0);
00705               return a;
00706        }
00707 
00708        if ( !state->as_fe_done ) {
00709               state->as_fe_done = 1;
00710               a = frontendDB->be_acl;
00711               goto retry;
00712        }
00713 
00714        Debug( LDAP_DEBUG_ACL, "<= acl_get: done.\n", 0, 0, 0 );
00715        return( NULL );
00716 }
00717 
00718 /*
00719  * Record value-dependent access control state
00720  */
00721 #define ACL_RECORD_VALUE_STATE do { \
00722               if( state && !state->as_vd_acl_present ) { \
00723                      state->as_vd_acl_present = 1; \
00724                      state->as_vd_acl = prev; \
00725                      state->as_vd_acl_count = count - 1; \
00726                      ACL_PRIV_ASSIGN( state->as_vd_mask, *mask ); \
00727               } \
00728        } while( 0 )
00729 
00730 static int
00731 acl_mask_dn(
00732        Operation            *op,
00733        Entry                *e,
00734        struct berval        *val,
00735        AccessControl        *a,
00736        AclRegexMatches             *matches,
00737        slap_dn_access              *bdn,
00738        struct berval        *opndn )
00739 {
00740        /*
00741         * if access applies to the entry itself, and the
00742         * user is bound as somebody in the same namespace as
00743         * the entry, OR the given dn matches the dn pattern
00744         */
00745        /*
00746         * NOTE: styles "anonymous", "users" and "self" 
00747         * have been moved to enum slap_style_t, whose 
00748         * value is set in a_dn_style; however, the string
00749         * is maintained in a_dn_pat.
00750         */
00751 
00752        if ( bdn->a_style == ACL_STYLE_ANONYMOUS ) {
00753               if ( !BER_BVISEMPTY( opndn ) ) {
00754                      return 1;
00755               }
00756 
00757        } else if ( bdn->a_style == ACL_STYLE_USERS ) {
00758               if ( BER_BVISEMPTY( opndn ) ) {
00759                      return 1;
00760               }
00761 
00762        } else if ( bdn->a_style == ACL_STYLE_SELF ) {
00763               struct berval ndn, selfndn;
00764               int           level;
00765 
00766               if ( BER_BVISEMPTY( opndn ) || BER_BVISNULL( &e->e_nname ) ) {
00767                      return 1;
00768               }
00769 
00770               level = bdn->a_self_level;
00771               if ( level < 0 ) {
00772                      selfndn = *opndn;
00773                      ndn = e->e_nname;
00774                      level = -level;
00775 
00776               } else {
00777                      ndn = *opndn;
00778                      selfndn = e->e_nname;
00779               }
00780 
00781               for ( ; level > 0; level-- ) {
00782                      if ( BER_BVISEMPTY( &ndn ) ) {
00783                             break;
00784                      }
00785                      dnParent( &ndn, &ndn );
00786               }
00787                      
00788               if ( BER_BVISEMPTY( &ndn ) || !dn_match( &ndn, &selfndn ) )
00789               {
00790                      return 1;
00791               }
00792 
00793        } else if ( bdn->a_style == ACL_STYLE_REGEX ) {
00794               if ( !ber_bvccmp( &bdn->a_pat, '*' ) ) {
00795                      AclRegexMatches      tmp_matches,
00796                                    *tmp_matchesp = &tmp_matches;
00797                      int           rc = 0;
00798                      regmatch_t    *tmp_data;
00799 
00800                      MATCHES_MEMSET( &tmp_matches );
00801                      tmp_data = &tmp_matches.dn_data[0];
00802 
00803                      if ( a->acl_attrval_style == ACL_STYLE_REGEX )
00804                             tmp_matchesp = matches;
00805                      else switch ( a->acl_dn_style ) {
00806                      case ACL_STYLE_REGEX:
00807                             if ( !BER_BVISNULL( &a->acl_dn_pat ) ) {
00808                                    tmp_matchesp = matches; 
00809                                    break;
00810                             }
00811                      /* FALLTHRU: applies also to ACL_STYLE_REGEX when pattern is "*" */
00812 
00813                      case ACL_STYLE_BASE:
00814                             tmp_data[0].rm_so = 0;
00815                             tmp_data[0].rm_eo = e->e_nname.bv_len;
00816                             tmp_matches.dn_count = 1;
00817                             break;
00818 
00819                      case ACL_STYLE_ONE:
00820                      case ACL_STYLE_SUBTREE:
00821                      case ACL_STYLE_CHILDREN:
00822                             tmp_data[0].rm_so = 0;
00823                             tmp_data[0].rm_eo = e->e_nname.bv_len;
00824                             tmp_data[1].rm_so = e->e_nname.bv_len - a->acl_dn_pat.bv_len;
00825                             tmp_data[1].rm_eo = e->e_nname.bv_len;
00826                             tmp_matches.dn_count = 2;
00827                             break;
00828 
00829                      default:
00830                             /* error */
00831                             rc = 1;
00832                             break;
00833                      }
00834 
00835                      if ( rc ) {
00836                             return 1;
00837                      }
00838 
00839                      if ( !regex_matches( &bdn->a_pat, opndn->bv_val,
00840                             &e->e_nname, NULL, tmp_matchesp ) )
00841                      {
00842                             return 1;
00843                      }
00844               }
00845 
00846        } else {
00847               struct berval pat;
00848               ber_len_t     patlen, odnlen;
00849               int           got_match = 0;
00850 
00851               if ( e->e_dn == NULL )
00852                      return 1;
00853 
00854               if ( bdn->a_expand ) {
00855                      struct berval bv;
00856                      char          buf[ACL_BUF_SIZE];
00857                      
00858                      AclRegexMatches      tmp_matches,
00859                                    *tmp_matchesp = &tmp_matches;
00860                      int           rc = 0;
00861                      regmatch_t    *tmp_data;
00862 
00863                      MATCHES_MEMSET( &tmp_matches );
00864                      tmp_data = &tmp_matches.dn_data[0];
00865 
00866                      bv.bv_len = sizeof( buf ) - 1;
00867                      bv.bv_val = buf;
00868 
00869                      /* Expand value regex */
00870                      if ( a->acl_attrval_style == ACL_STYLE_REGEX )
00871                             tmp_matchesp = matches;
00872                      else switch ( a->acl_dn_style ) {
00873                      case ACL_STYLE_REGEX:
00874                             if ( !BER_BVISNULL( &a->acl_dn_pat ) ) {
00875                                    tmp_matchesp = matches;
00876                                    break;
00877                             }
00878                      /* FALLTHRU: applies also to ACL_STYLE_REGEX when pattern is "*" */
00879 
00880                      case ACL_STYLE_BASE:
00881                             tmp_data[0].rm_so = 0;
00882                             tmp_data[0].rm_eo = e->e_nname.bv_len;
00883                             tmp_matches.dn_count = 1;
00884                             break;
00885 
00886                      case ACL_STYLE_ONE:
00887                      case ACL_STYLE_SUBTREE:
00888                      case ACL_STYLE_CHILDREN:
00889                             tmp_data[0].rm_so = 0;
00890                             tmp_data[0].rm_eo = e->e_nname.bv_len;
00891                             tmp_data[1].rm_so = e->e_nname.bv_len - a->acl_dn_pat.bv_len;
00892                             tmp_data[1].rm_eo = e->e_nname.bv_len;
00893                             tmp_matches.dn_count = 2;
00894                             break;
00895 
00896                      default:
00897                             /* error */
00898                             rc = 1;
00899                             break;
00900                      }
00901 
00902                      if ( rc ) {
00903                             return 1;
00904                      }
00905 
00906                      if ( acl_string_expand( &bv, &bdn->a_pat, 
00907                                           &e->e_nname, 
00908                                           val, tmp_matchesp ) )
00909                      {
00910                             return 1;
00911                      }
00912                      
00913                      if ( dnNormalize(0, NULL, NULL, &bv,
00914                                    &pat, op->o_tmpmemctx )
00915                                    != LDAP_SUCCESS )
00916                      {
00917                             /* did not expand to a valid dn */
00918                             return 1;
00919                      }
00920 
00921               } else {
00922                      pat = bdn->a_pat;
00923               }
00924 
00925               patlen = pat.bv_len;
00926               odnlen = opndn->bv_len;
00927               if ( odnlen < patlen ) {
00928                      goto dn_match_cleanup;
00929 
00930               }
00931 
00932               if ( bdn->a_style == ACL_STYLE_BASE ) {
00933                      /* base dn -- entire object DN must match */
00934                      if ( odnlen != patlen ) {
00935                             goto dn_match_cleanup;
00936                      }
00937 
00938               } else if ( bdn->a_style == ACL_STYLE_ONE ) {
00939                      ber_len_t     rdnlen = 0;
00940 
00941                      if ( odnlen <= patlen ) {
00942                             goto dn_match_cleanup;
00943                      }
00944 
00945                      if ( !DN_SEPARATOR( opndn->bv_val[odnlen - patlen - 1] ) ) {
00946                             goto dn_match_cleanup;
00947                      }
00948 
00949                      rdnlen = dn_rdnlen( NULL, opndn );
00950                      if ( rdnlen - ( odnlen - patlen - 1 ) != 0 ) {
00951                             goto dn_match_cleanup;
00952                      }
00953 
00954               } else if ( bdn->a_style == ACL_STYLE_SUBTREE ) {
00955                      if ( odnlen > patlen && !DN_SEPARATOR( opndn->bv_val[odnlen - patlen - 1] ) ) {
00956                             goto dn_match_cleanup;
00957                      }
00958 
00959               } else if ( bdn->a_style == ACL_STYLE_CHILDREN ) {
00960                      if ( odnlen <= patlen ) {
00961                             goto dn_match_cleanup;
00962                      }
00963 
00964                      if ( !DN_SEPARATOR( opndn->bv_val[odnlen - patlen - 1] ) ) {
00965                             goto dn_match_cleanup;
00966                      }
00967 
00968               } else if ( bdn->a_style == ACL_STYLE_LEVEL ) {
00969                      int           level = bdn->a_level;
00970                      struct berval ndn;
00971 
00972                      if ( odnlen <= patlen ) {
00973                             goto dn_match_cleanup;
00974                      }
00975 
00976                      if ( level > 0 && !DN_SEPARATOR( opndn->bv_val[odnlen - patlen - 1] ) )
00977                      {
00978                             goto dn_match_cleanup;
00979                      }
00980                      
00981                      ndn = *opndn;
00982                      for ( ; level > 0; level-- ) {
00983                             if ( BER_BVISEMPTY( &ndn ) ) {
00984                                    goto dn_match_cleanup;
00985                             }
00986                             dnParent( &ndn, &ndn );
00987                             if ( ndn.bv_len < patlen ) {
00988                                    goto dn_match_cleanup;
00989                             }
00990                      }
00991                      
00992                      if ( ndn.bv_len != patlen ) {
00993                             goto dn_match_cleanup;
00994                      }
00995               }
00996 
00997               got_match = !strcmp( pat.bv_val, &opndn->bv_val[ odnlen - patlen ] );
00998 
00999 dn_match_cleanup:;
01000               if ( pat.bv_val != bdn->a_pat.bv_val ) {
01001                      slap_sl_free( pat.bv_val, op->o_tmpmemctx );
01002               }
01003 
01004               if ( !got_match ) {
01005                      return 1;
01006               }
01007        }
01008 
01009        return 0;
01010 }
01011 
01012 static int
01013 acl_mask_dnattr(
01014        Operation            *op,
01015        Entry                *e,
01016        struct berval        *val,
01017        AccessControl        *a,
01018        int                  count,
01019        AccessControlState   *state,
01020        slap_mask_t                 *mask,
01021        slap_dn_access              *bdn,
01022        struct berval        *opndn )
01023 {
01024        Attribute     *at;
01025        struct berval bv;
01026        int           rc, match = 0;
01027        const char    *text;
01028        const char    *attr = bdn->a_at->ad_cname.bv_val;
01029 
01030        assert( attr != NULL );
01031 
01032        if ( BER_BVISEMPTY( opndn ) ) {
01033               return 1;
01034        }
01035 
01036        Debug( LDAP_DEBUG_ACL, "<= check a_dn_at: %s\n", attr, 0, 0 );
01037        bv = *opndn;
01038 
01039        /* see if asker is listed in dnattr */
01040        for ( at = attrs_find( e->e_attrs, bdn->a_at );
01041               at != NULL;
01042               at = attrs_find( at->a_next, bdn->a_at ) )
01043        {
01044               if ( attr_valfind( at,
01045                      SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
01046                             SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
01047                      &bv, NULL, op->o_tmpmemctx ) == 0 )
01048               {
01049                      /* found it */
01050                      match = 1;
01051                      break;
01052               }
01053        }
01054 
01055        if ( match ) {
01056               /* have a dnattr match. if this is a self clause then
01057                * the target must also match the op dn.
01058                */
01059               if ( bdn->a_self ) {
01060                      /* check if the target is an attribute. */
01061                      if ( val == NULL ) return 1;
01062 
01063                      /* target is attribute, check if the attribute value
01064                       * is the op dn.
01065                       */
01066                      rc = value_match( &match, bdn->a_at,
01067                             bdn->a_at->ad_type->sat_equality, 0,
01068                             val, &bv, &text );
01069                      /* on match error or no match, fail the ACL clause */
01070                      if ( rc != LDAP_SUCCESS || match != 0 )
01071                             return 1;
01072               }
01073 
01074        } else {
01075               /* no dnattr match, check if this is a self clause */
01076               if ( ! bdn->a_self )
01077                      return 1;
01078 
01079               /* this is a self clause, check if the target is an
01080                * attribute.
01081                */
01082               if ( val == NULL )
01083                      return 1;
01084 
01085               /* target is attribute, check if the attribute value
01086                * is the op dn.
01087                */
01088               rc = value_match( &match, bdn->a_at,
01089                      bdn->a_at->ad_type->sat_equality, 0,
01090                      val, &bv, &text );
01091 
01092               /* on match error or no match, fail the ACL clause */
01093               if ( rc != LDAP_SUCCESS || match != 0 )
01094                      return 1;
01095        }
01096 
01097        return 0;
01098 }
01099 
01100 
01101 /*
01102  * slap_acl_mask - modifies mask based upon the given acl and the
01103  * requested access to entry e, attribute attr, value val.  if val
01104  * is null, access to the whole attribute is assumed (all values).
01105  *
01106  * returns    0      access NOT allowed
01107  *            1      access allowed
01108  */
01109 
01110 static slap_control_t
01111 slap_acl_mask(
01112        AccessControl        *a,
01113        AccessControl        *prev,
01114        slap_mask_t          *mask,
01115        Operation            *op,
01116        Entry                *e,
01117        AttributeDescription *desc,
01118        struct berval        *val,
01119        AclRegexMatches             *matches,
01120        int                  count,
01121        AccessControlState   *state,
01122        slap_access_t access )
01123 {
01124        int           i;
01125        Access        *b;
01126 #ifdef LDAP_DEBUG
01127        char          accessmaskbuf[ACCESSMASK_MAXLEN];
01128 #endif /* DEBUG */
01129        const char    *attr;
01130 #ifdef SLAP_DYNACL
01131        slap_mask_t   a2pmask = ACL_ACCESS2PRIV( access );
01132 #endif /* SLAP_DYNACL */
01133 
01134        assert( a != NULL );
01135        assert( mask != NULL );
01136        assert( desc != NULL );
01137 
01138        attr = desc->ad_cname.bv_val;
01139 
01140        assert( attr != NULL );
01141 
01142        Debug( LDAP_DEBUG_ACL,
01143               "=> acl_mask: access to entry \"%s\", attr \"%s\" requested\n",
01144               e->e_dn, attr, 0 );
01145 
01146        Debug( LDAP_DEBUG_ACL,
01147               "=> acl_mask: to %s by \"%s\", (%s) \n",
01148               val ? "value" : "all values",
01149               op->o_ndn.bv_val ?  op->o_ndn.bv_val : "",
01150               accessmask2str( *mask, accessmaskbuf, 1 ) );
01151 
01152 
01153        b = a->acl_access;
01154        i = 1;
01155 
01156        for ( ; b != NULL; b = b->a_next, i++ ) {
01157               slap_mask_t oldmask, modmask;
01158 
01159               ACL_INVALIDATE( modmask );
01160 
01161               /* check for the "self" modifier in the <access> field */
01162               if ( b->a_dn.a_self ) {
01163                      const char *dummy;
01164                      int rc, match = 0;
01165 
01166                      ACL_RECORD_VALUE_STATE;
01167 
01168                      /* must have DN syntax */
01169                      if ( desc->ad_type->sat_syntax != slap_schema.si_syn_distinguishedName &&
01170                             !is_at_syntax( desc->ad_type, SLAPD_NAMEUID_SYNTAX )) continue;
01171 
01172                      /* check if the target is an attribute. */
01173                      if ( val == NULL ) continue;
01174 
01175                      /* a DN must be present */
01176                      if ( BER_BVISEMPTY( &op->o_ndn ) ) {
01177                             continue;
01178                      }
01179 
01180                      /* target is attribute, check if the attribute value
01181                       * is the op dn.
01182                       */
01183                      rc = value_match( &match, desc,
01184                             desc->ad_type->sat_equality, 0,
01185                             val, &op->o_ndn, &dummy );
01186                      /* on match error or no match, fail the ACL clause */
01187                      if ( rc != LDAP_SUCCESS || match != 0 )
01188                             continue;
01189               }
01190 
01191               /* AND <who> clauses */
01192               if ( !BER_BVISEMPTY( &b->a_dn_pat ) ) {
01193                      Debug( LDAP_DEBUG_ACL, "<= check a_dn_pat: %s\n",
01194                             b->a_dn_pat.bv_val, 0, 0);
01195                      /*
01196                       * if access applies to the entry itself, and the
01197                       * user is bound as somebody in the same namespace as
01198                       * the entry, OR the given dn matches the dn pattern
01199                       */
01200                      /*
01201                       * NOTE: styles "anonymous", "users" and "self" 
01202                       * have been moved to enum slap_style_t, whose 
01203                       * value is set in a_dn_style; however, the string
01204                       * is maintained in a_dn_pat.
01205                       */
01206 
01207                      if ( acl_mask_dn( op, e, val, a, matches,
01208                             &b->a_dn, &op->o_ndn ) )
01209                      {
01210                             continue;
01211                      }
01212               }
01213 
01214               if ( !BER_BVISEMPTY( &b->a_realdn_pat ) ) {
01215                      struct berval ndn;
01216 
01217                      Debug( LDAP_DEBUG_ACL, "<= check a_realdn_pat: %s\n",
01218                             b->a_realdn_pat.bv_val, 0, 0);
01219                      /*
01220                       * if access applies to the entry itself, and the
01221                       * user is bound as somebody in the same namespace as
01222                       * the entry, OR the given dn matches the dn pattern
01223                       */
01224                      /*
01225                       * NOTE: styles "anonymous", "users" and "self" 
01226                       * have been moved to enum slap_style_t, whose 
01227                       * value is set in a_dn_style; however, the string
01228                       * is maintained in a_dn_pat.
01229                       */
01230 
01231                      if ( op->o_conn && !BER_BVISNULL( &op->o_conn->c_ndn ) )
01232                      {
01233                             ndn = op->o_conn->c_ndn;
01234                      } else {
01235                             ndn = op->o_ndn;
01236                      }
01237 
01238                      if ( acl_mask_dn( op, e, val, a, matches,
01239                             &b->a_realdn, &ndn ) )
01240                      {
01241                             continue;
01242                      }
01243               }
01244 
01245               if ( !BER_BVISEMPTY( &b->a_sockurl_pat ) ) {
01246                      if ( ! op->o_conn->c_listener ) {
01247                             continue;
01248                      }
01249                      Debug( LDAP_DEBUG_ACL, "<= check a_sockurl_pat: %s\n",
01250                             b->a_sockurl_pat.bv_val, 0, 0 );
01251 
01252                      if ( !ber_bvccmp( &b->a_sockurl_pat, '*' ) ) {
01253                             if ( b->a_sockurl_style == ACL_STYLE_REGEX) {
01254                                    if ( !regex_matches( &b->a_sockurl_pat, op->o_conn->c_listener_url.bv_val,
01255                                                  &e->e_nname, val, matches ) ) 
01256                                    {
01257                                           continue;
01258                                    }
01259 
01260                             } else if ( b->a_sockurl_style == ACL_STYLE_EXPAND ) {
01261                                    struct berval bv;
01262                                    char buf[ACL_BUF_SIZE];
01263 
01264                                    bv.bv_len = sizeof( buf ) - 1;
01265                                    bv.bv_val = buf;
01266                                    if ( acl_string_expand( &bv, &b->a_sockurl_pat, &e->e_nname, val, matches ) )
01267                                    {
01268                                           continue;
01269                                    }
01270 
01271                                    if ( ber_bvstrcasecmp( &bv, &op->o_conn->c_listener_url ) != 0 )
01272                                    {
01273                                           continue;
01274                                    }
01275 
01276                             } else {
01277                                    if ( ber_bvstrcasecmp( &b->a_sockurl_pat, &op->o_conn->c_listener_url ) != 0 )
01278                                    {
01279                                           continue;
01280                                    }
01281                             }
01282                      }
01283               }
01284 
01285               if ( !BER_BVISEMPTY( &b->a_domain_pat ) ) {
01286                      if ( !op->o_conn->c_peer_domain.bv_val ) {
01287                             continue;
01288                      }
01289                      Debug( LDAP_DEBUG_ACL, "<= check a_domain_pat: %s\n",
01290                             b->a_domain_pat.bv_val, 0, 0 );
01291                      if ( !ber_bvccmp( &b->a_domain_pat, '*' ) ) {
01292                             if ( b->a_domain_style == ACL_STYLE_REGEX) {
01293                                    if ( !regex_matches( &b->a_domain_pat, op->o_conn->c_peer_domain.bv_val,
01294                                                  &e->e_nname, val, matches ) ) 
01295                                    {
01296                                           continue;
01297                                    }
01298                             } else {
01299                                    char buf[ACL_BUF_SIZE];
01300 
01301                                    struct berval        cmp = op->o_conn->c_peer_domain;
01302                                    struct berval        pat = b->a_domain_pat;
01303 
01304                                    if ( b->a_domain_expand ) {
01305                                           struct berval bv;
01306 
01307                                           bv.bv_len = sizeof(buf) - 1;
01308                                           bv.bv_val = buf;
01309 
01310                                           if ( acl_string_expand(&bv, &b->a_domain_pat, &e->e_nname, val, matches) )
01311                                           {
01312                                                  continue;
01313                                           }
01314                                           pat = bv;
01315                                    }
01316 
01317                                    if ( b->a_domain_style == ACL_STYLE_SUBTREE ) {
01318                                           int offset = cmp.bv_len - pat.bv_len;
01319                                           if ( offset < 0 ) {
01320                                                  continue;
01321                                           }
01322 
01323                                           if ( offset == 1 || ( offset > 1 && cmp.bv_val[ offset - 1 ] != '.' ) ) {
01324                                                  continue;
01325                                           }
01326 
01327                                           /* trim the domain */
01328                                           cmp.bv_val = &cmp.bv_val[ offset ];
01329                                           cmp.bv_len -= offset;
01330                                    }
01331                                    
01332                                    if ( ber_bvstrcasecmp( &pat, &cmp ) != 0 ) {
01333                                           continue;
01334                                    }
01335                             }
01336                      }
01337               }
01338 
01339               if ( !BER_BVISEMPTY( &b->a_peername_pat ) ) {
01340                      if ( !op->o_conn->c_peer_name.bv_val ) {
01341                             continue;
01342                      }
01343                      Debug( LDAP_DEBUG_ACL, "<= check a_peername_path: %s\n",
01344                             b->a_peername_pat.bv_val, 0, 0 );
01345                      if ( !ber_bvccmp( &b->a_peername_pat, '*' ) ) {
01346                             if ( b->a_peername_style == ACL_STYLE_REGEX ) {
01347                                    if ( !regex_matches( &b->a_peername_pat, op->o_conn->c_peer_name.bv_val,
01348                                                  &e->e_nname, val, matches ) ) 
01349                                    {
01350                                           continue;
01351                                    }
01352 
01353                             } else {
01354                                    /* try exact match */
01355                                    if ( b->a_peername_style == ACL_STYLE_BASE ) {
01356                                           if ( ber_bvstrcasecmp( &b->a_peername_pat, &op->o_conn->c_peer_name ) != 0 ) {
01357                                                  continue;
01358                                           }
01359 
01360                                    } else if ( b->a_peername_style == ACL_STYLE_EXPAND ) {
01361                                           struct berval bv;
01362                                           char buf[ACL_BUF_SIZE];
01363 
01364                                           bv.bv_len = sizeof( buf ) - 1;
01365                                           bv.bv_val = buf;
01366                                           if ( acl_string_expand( &bv, &b->a_peername_pat, &e->e_nname, val, matches ) )
01367                                           {
01368                                                  continue;
01369                                           }
01370 
01371                                           if ( ber_bvstrcasecmp( &bv, &op->o_conn->c_peer_name ) != 0 ) {
01372                                                  continue;
01373                                           }
01374 
01375                                    /* extract IP and try exact match */
01376                                    } else if ( b->a_peername_style == ACL_STYLE_IP ) {
01377                                           char          *port;
01378                                           char          buf[STRLENOF("255.255.255.255") + 1];
01379                                           struct berval ip;
01380                                           unsigned long addr;
01381                                           int           port_number = -1;
01382                                           
01383                                           if ( strncasecmp( op->o_conn->c_peer_name.bv_val, 
01384                                                                acl_bv_ip_eq.bv_val,
01385                                                                acl_bv_ip_eq.bv_len ) != 0 ) 
01386                                                  continue;
01387 
01388                                           ip.bv_val = op->o_conn->c_peer_name.bv_val + acl_bv_ip_eq.bv_len;
01389                                           ip.bv_len = op->o_conn->c_peer_name.bv_len - acl_bv_ip_eq.bv_len;
01390 
01391                                           port = strrchr( ip.bv_val, ':' );
01392                                           if ( port ) {
01393                                                  ip.bv_len = port - ip.bv_val;
01394                                                  ++port;
01395                                                  if ( lutil_atoi( &port_number, port ) != 0 )
01396                                                         continue;
01397                                           }
01398                                           
01399                                           /* the port check can be anticipated here */
01400                                           if ( b->a_peername_port != -1 && port_number != b->a_peername_port )
01401                                                  continue;
01402                                           
01403                                           /* address longer than expected? */
01404                                           if ( ip.bv_len >= sizeof(buf) )
01405                                                  continue;
01406 
01407                                           AC_MEMCPY( buf, ip.bv_val, ip.bv_len );
01408                                           buf[ ip.bv_len ] = '\0';
01409 
01410                                           addr = inet_addr( buf );
01411 
01412                                           /* unable to convert? */
01413                                           if ( addr == (unsigned long)(-1) )
01414                                                  continue;
01415 
01416                                           if ( (addr & b->a_peername_mask) != b->a_peername_addr )
01417                                                  continue;
01418 
01419 #ifdef LDAP_PF_INET6
01420                                    /* extract IPv6 and try exact match */
01421                                    } else if ( b->a_peername_style == ACL_STYLE_IPV6 ) {
01422                                           char          *port;
01423                                           char          buf[STRLENOF("FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF") + 1];
01424                                           struct berval ip;
01425                                           struct in6_addr      addr;
01426                                           int           port_number = -1;
01427                                           
01428                                           if ( strncasecmp( op->o_conn->c_peer_name.bv_val, 
01429                                                                acl_bv_ipv6_eq.bv_val,
01430                                                                acl_bv_ipv6_eq.bv_len ) != 0 ) 
01431                                                  continue;
01432 
01433                                           ip.bv_val = op->o_conn->c_peer_name.bv_val + acl_bv_ipv6_eq.bv_len;
01434                                           ip.bv_len = op->o_conn->c_peer_name.bv_len - acl_bv_ipv6_eq.bv_len;
01435 
01436                                           port = strrchr( ip.bv_val, ']' );
01437                                           if ( port ) {
01438                                                  ip.bv_len = port - ip.bv_val;
01439                                                  ++port;
01440                                                  if ( port[0] == ':' && lutil_atoi( &port_number, ++port ) != 0 )
01441                                                         continue;
01442                                           }
01443                                           
01444                                           /* the port check can be anticipated here */
01445                                           if ( b->a_peername_port != -1 && port_number != b->a_peername_port )
01446                                                  continue;
01447                                           
01448                                           /* address longer than expected? */
01449                                           if ( ip.bv_len >= sizeof(buf) )
01450                                                  continue;
01451 
01452                                           AC_MEMCPY( buf, ip.bv_val, ip.bv_len );
01453                                           buf[ ip.bv_len ] = '\0';
01454 
01455                                           if ( inet_pton( AF_INET6, buf, &addr ) != 1 )
01456                                                  continue;
01457 
01458                                           /* check mask */
01459                                           if ( !slap_addr6_mask( &addr, &b->a_peername_mask6, &b->a_peername_addr6 ) )
01460                                                  continue;
01461 #endif /* LDAP_PF_INET6 */
01462 
01463 #ifdef LDAP_PF_LOCAL
01464                                    /* extract path and try exact match */
01465                                    } else if ( b->a_peername_style == ACL_STYLE_PATH ) {
01466                                           struct berval path;
01467                                           
01468                                           if ( strncmp( op->o_conn->c_peer_name.bv_val,
01469                                                                acl_bv_path_eq.bv_val,
01470                                                                acl_bv_path_eq.bv_len ) != 0 )
01471                                                  continue;
01472 
01473                                           path.bv_val = op->o_conn->c_peer_name.bv_val
01474                                                  + acl_bv_path_eq.bv_len;
01475                                           path.bv_len = op->o_conn->c_peer_name.bv_len
01476                                                  - acl_bv_path_eq.bv_len;
01477 
01478                                           if ( ber_bvcmp( &b->a_peername_pat, &path ) != 0 )
01479                                                  continue;
01480 
01481 #endif /* LDAP_PF_LOCAL */
01482 
01483                                    /* exact match (very unlikely...) */
01484                                    } else if ( ber_bvcmp( &op->o_conn->c_peer_name, &b->a_peername_pat ) != 0 ) {
01485                                                  continue;
01486                                    }
01487                             }
01488                      }
01489               }
01490 
01491               if ( !BER_BVISEMPTY( &b->a_sockname_pat ) ) {
01492                      if ( BER_BVISNULL( &op->o_conn->c_sock_name ) ) {
01493                             continue;
01494                      }
01495                      Debug( LDAP_DEBUG_ACL, "<= check a_sockname_path: %s\n",
01496                             b->a_sockname_pat.bv_val, 0, 0 );
01497                      if ( !ber_bvccmp( &b->a_sockname_pat, '*' ) ) {
01498                             if ( b->a_sockname_style == ACL_STYLE_REGEX) {
01499                                    if ( !regex_matches( &b->a_sockname_pat, op->o_conn->c_sock_name.bv_val,
01500                                                  &e->e_nname, val, matches ) ) 
01501                                    {
01502                                           continue;
01503                                    }
01504 
01505                             } else if ( b->a_sockname_style == ACL_STYLE_EXPAND ) {
01506                                    struct berval bv;
01507                                    char buf[ACL_BUF_SIZE];
01508 
01509                                    bv.bv_len = sizeof( buf ) - 1;
01510                                    bv.bv_val = buf;
01511                                    if ( acl_string_expand( &bv, &b->a_sockname_pat, &e->e_nname, val, matches ) )
01512                                    {
01513                                           continue;
01514                                    }
01515 
01516                                    if ( ber_bvstrcasecmp( &bv, &op->o_conn->c_sock_name ) != 0 ) {
01517                                           continue;
01518                                    }
01519 
01520                             } else {
01521                                    if ( ber_bvstrcasecmp( &b->a_sockname_pat, &op->o_conn->c_sock_name ) != 0 ) {
01522                                           continue;
01523                                    }
01524                             }
01525                      }
01526               }
01527 
01528               if ( b->a_dn_at != NULL ) {
01529                      if ( acl_mask_dnattr( op, e, val, a,
01530                                    count, state, mask,
01531                                    &b->a_dn, &op->o_ndn ) )
01532                      {
01533                             continue;
01534                      }
01535               }
01536 
01537               if ( b->a_realdn_at != NULL ) {
01538                      struct berval ndn;
01539 
01540                      if ( op->o_conn && !BER_BVISNULL( &op->o_conn->c_ndn ) )
01541                      {
01542                             ndn = op->o_conn->c_ndn;
01543                      } else {
01544                             ndn = op->o_ndn;
01545                      }
01546 
01547                      if ( acl_mask_dnattr( op, e, val, a,
01548                                    count, state, mask,
01549                                    &b->a_realdn, &ndn ) )
01550                      {
01551                             continue;
01552                      }
01553               }
01554 
01555               if ( !BER_BVISEMPTY( &b->a_group_pat ) ) {
01556                      struct berval bv;
01557                      struct berval ndn = BER_BVNULL;
01558                      int rc;
01559 
01560                      if ( op->o_ndn.bv_len == 0 ) {
01561                             continue;
01562                      }
01563 
01564                      Debug( LDAP_DEBUG_ACL, "<= check a_group_pat: %s\n",
01565                             b->a_group_pat.bv_val, 0, 0 );
01566 
01567                      /* b->a_group is an unexpanded entry name, expanded it should be an 
01568                       * entry with objectclass group* and we test to see if odn is one of
01569                       * the values in the attribute group
01570                       */
01571                      /* see if asker is listed in dnattr */
01572                      if ( b->a_group_style == ACL_STYLE_EXPAND ) {
01573                             char          buf[ACL_BUF_SIZE];
01574                             AclRegexMatches      tmp_matches,
01575                                           *tmp_matchesp = &tmp_matches;
01576                             regmatch_t    *tmp_data;
01577 
01578                             MATCHES_MEMSET( &tmp_matches );
01579                             tmp_data = &tmp_matches.dn_data[0];
01580 
01581                             bv.bv_len = sizeof(buf) - 1;
01582                             bv.bv_val = buf;
01583 
01584                             rc = 0;
01585 
01586                             if ( a->acl_attrval_style == ACL_STYLE_REGEX )
01587                                    tmp_matchesp = matches;
01588                             else switch ( a->acl_dn_style ) {
01589                             case ACL_STYLE_REGEX:
01590                                    if ( !BER_BVISNULL( &a->acl_dn_pat ) ) {
01591                                           tmp_matchesp = matches;
01592                                           break;
01593                                    }
01594 
01595                             /* FALLTHRU: applies also to ACL_STYLE_REGEX when pattern is "*" */
01596                             case ACL_STYLE_BASE:
01597                                    tmp_data[0].rm_so = 0;
01598                                    tmp_data[0].rm_eo = e->e_nname.bv_len;
01599                                    tmp_matches.dn_count = 1;
01600                                    break;
01601 
01602                             case ACL_STYLE_ONE:
01603                             case ACL_STYLE_SUBTREE:
01604                             case ACL_STYLE_CHILDREN:
01605                                    tmp_data[0].rm_so = 0;
01606                                    tmp_data[0].rm_eo = e->e_nname.bv_len;
01607 
01608                                    tmp_data[1].rm_so = e->e_nname.bv_len - a->acl_dn_pat.bv_len;
01609                                    tmp_data[1].rm_eo = e->e_nname.bv_len;
01610                                    tmp_matches.dn_count = 2;
01611                                    break;
01612 
01613                             default:
01614                                    /* error */
01615                                    rc = 1;
01616                                    break;
01617                             }
01618 
01619                             if ( rc ) {
01620                                    continue;
01621                             }
01622                             
01623                             if ( acl_string_expand( &bv, &b->a_group_pat,
01624                                           &e->e_nname, val,
01625                                           tmp_matchesp ) )
01626                             {
01627                                    continue;
01628                             }
01629 
01630                             if ( dnNormalize( 0, NULL, NULL, &bv, &ndn,
01631                                           op->o_tmpmemctx ) != LDAP_SUCCESS )
01632                             {
01633                                    /* did not expand to a valid dn */
01634                                    continue;
01635                             }
01636 
01637                             bv = ndn;
01638 
01639                      } else {
01640                             bv = b->a_group_pat;
01641                      }
01642 
01643                      rc = backend_group( op, e, &bv, &op->o_ndn,
01644                             b->a_group_oc, b->a_group_at );
01645 
01646                      if ( ndn.bv_val ) {
01647                             slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
01648                      }
01649 
01650                      if ( rc != 0 ) {
01651                             continue;
01652                      }
01653               }
01654 
01655               if ( !BER_BVISEMPTY( &b->a_set_pat ) ) {
01656                      struct berval bv;
01657                      char          buf[ACL_BUF_SIZE];
01658 
01659                      Debug( LDAP_DEBUG_ACL, "<= check a_set_pat: %s\n",
01660                             b->a_set_pat.bv_val, 0, 0 );
01661 
01662                      if ( b->a_set_style == ACL_STYLE_EXPAND ) {
01663                             AclRegexMatches      tmp_matches,
01664                                           *tmp_matchesp = &tmp_matches;
01665                             int           rc = 0;
01666                             regmatch_t    *tmp_data;
01667 
01668                             MATCHES_MEMSET( &tmp_matches );
01669                             tmp_data = &tmp_matches.dn_data[0];
01670 
01671                             bv.bv_len = sizeof( buf ) - 1;
01672                             bv.bv_val = buf;
01673 
01674                             rc = 0;
01675 
01676                             if ( a->acl_attrval_style == ACL_STYLE_REGEX )
01677                                    tmp_matchesp = matches;
01678                             else switch ( a->acl_dn_style ) {
01679                             case ACL_STYLE_REGEX:
01680                                    if ( !BER_BVISNULL( &a->acl_dn_pat ) ) {
01681                                           tmp_matchesp = matches;
01682                                           break;
01683                                    }
01684 
01685                             /* FALLTHRU: applies also to ACL_STYLE_REGEX when pattern is "*" */
01686                             case ACL_STYLE_BASE:
01687                                    tmp_data[0].rm_so = 0;
01688                                    tmp_data[0].rm_eo = e->e_nname.bv_len;
01689                                    tmp_matches.dn_count = 1;
01690                                    break;
01691 
01692                             case ACL_STYLE_ONE:
01693                             case ACL_STYLE_SUBTREE:
01694                             case ACL_STYLE_CHILDREN:
01695                                    tmp_data[0].rm_so = 0;
01696                                    tmp_data[0].rm_eo = e->e_nname.bv_len;
01697                                    tmp_data[1].rm_so = e->e_nname.bv_len - a->acl_dn_pat.bv_len;
01698                                    tmp_data[1].rm_eo = e->e_nname.bv_len; tmp_matches.dn_count = 2;
01699                                    break;
01700 
01701                             default:
01702                                    /* error */
01703                                    rc = 1;
01704                                    break;
01705                             }
01706 
01707                             if ( rc ) {
01708                                    continue;
01709                             }
01710                             
01711                             if ( acl_string_expand( &bv, &b->a_set_pat,
01712                                           &e->e_nname, val,
01713                                           tmp_matchesp ) )
01714                             {
01715                                    continue;
01716                             }
01717 
01718                      } else {
01719                             bv = b->a_set_pat;
01720                      }
01721                      
01722                      if ( acl_match_set( &bv, op, e, NULL ) == 0 ) {
01723                             continue;
01724                      }
01725               }
01726 
01727               if ( b->a_authz.sai_ssf ) {
01728                      Debug( LDAP_DEBUG_ACL, "<= check a_authz.sai_ssf: ACL %u > OP %u\n",
01729                             b->a_authz.sai_ssf, op->o_ssf, 0 );
01730                      if ( b->a_authz.sai_ssf >  op->o_ssf ) {
01731                             continue;
01732                      }
01733               }
01734 
01735               if ( b->a_authz.sai_transport_ssf ) {
01736                      Debug( LDAP_DEBUG_ACL,
01737                             "<= check a_authz.sai_transport_ssf: ACL %u > OP %u\n",
01738                             b->a_authz.sai_transport_ssf, op->o_transport_ssf, 0 );
01739                      if ( b->a_authz.sai_transport_ssf >  op->o_transport_ssf ) {
01740                             continue;
01741                      }
01742               }
01743 
01744               if ( b->a_authz.sai_tls_ssf ) {
01745                      Debug( LDAP_DEBUG_ACL,
01746                             "<= check a_authz.sai_tls_ssf: ACL %u > OP %u\n",
01747                             b->a_authz.sai_tls_ssf, op->o_tls_ssf, 0 );
01748                      if ( b->a_authz.sai_tls_ssf >  op->o_tls_ssf ) {
01749                             continue;
01750                      }
01751               }
01752 
01753               if ( b->a_authz.sai_sasl_ssf ) {
01754                      Debug( LDAP_DEBUG_ACL,
01755                             "<= check a_authz.sai_sasl_ssf: ACL %u > OP %u\n",
01756                             b->a_authz.sai_sasl_ssf, op->o_sasl_ssf, 0 );
01757                      if ( b->a_authz.sai_sasl_ssf >     op->o_sasl_ssf ) {
01758                             continue;
01759                      }
01760               }
01761 
01762 #ifdef SLAP_DYNACL
01763               if ( b->a_dynacl ) {
01764                      slap_dynacl_t *da;
01765                      slap_access_t tgrant, tdeny;
01766 
01767                      Debug( LDAP_DEBUG_ACL, "<= check a_dynacl\n",
01768                             0, 0, 0 );
01769 
01770                      /* this case works different from the others above.
01771                       * since dynamic ACL's themselves give permissions, we need
01772                       * to first check b->a_access_mask, the ACL's access level.
01773                       */
01774                      /* first check if the right being requested
01775                       * is allowed by the ACL clause.
01776                       */
01777                      if ( ! ACL_PRIV_ISSET( b->a_access_mask, a2pmask ) ) {
01778                             continue;
01779                      }
01780 
01781                      /* start out with nothing granted, nothing denied */
01782                      ACL_INVALIDATE(tgrant);
01783                      ACL_INVALIDATE(tdeny);
01784 
01785                      for ( da = b->a_dynacl; da; da = da->da_next ) {
01786                             slap_access_t grant,
01787                                           deny;
01788 
01789                             ACL_INVALIDATE(grant);
01790                             ACL_INVALIDATE(deny);
01791 
01792                             Debug( LDAP_DEBUG_ACL, "    <= check a_dynacl: %s\n",
01793                                    da->da_name, 0, 0 );
01794 
01795                             /*
01796                              * XXXmanu Only DN matches are supplied 
01797                              * sending attribute values matches require
01798                              * an API update
01799                              */
01800                             (void)da->da_mask( da->da_private, op, e, desc,
01801                                    val, matches->dn_count, matches->dn_data, 
01802                                    &grant, &deny ); 
01803 
01804                             tgrant |= grant;
01805                             tdeny |= deny;
01806                      }
01807 
01808                      /* remove anything that the ACL clause does not allow */
01809                      tgrant &= b->a_access_mask & ACL_PRIV_MASK;
01810                      tdeny &= ACL_PRIV_MASK;
01811 
01812                      /* see if we have anything to contribute */
01813                      if( ACL_IS_INVALID(tgrant) && ACL_IS_INVALID(tdeny) ) { 
01814                             continue;
01815                      }
01816 
01817                      /* this could be improved by changing slap_acl_mask so that it can deal with
01818                       * by clauses that return grant/deny pairs.  Right now, it does either
01819                       * additive or subtractive rights, but not both at the same time.  So,
01820                       * we need to combine the grant/deny pair into a single rights mask in
01821                       * a smart way:       if either grant or deny is "empty", then we use the
01822                       * opposite as is, otherwise we remove any denied rights from the grant
01823                       * rights mask and construct an additive mask.
01824                       */
01825                      if (ACL_IS_INVALID(tdeny)) {
01826                             modmask = tgrant | ACL_PRIV_ADDITIVE;
01827 
01828                      } else if (ACL_IS_INVALID(tgrant)) {
01829                             modmask = tdeny | ACL_PRIV_SUBSTRACTIVE;
01830 
01831                      } else {
01832                             modmask = (tgrant & ~tdeny) | ACL_PRIV_ADDITIVE;
01833                      }
01834 
01835               } else
01836 #endif /* SLAP_DYNACL */
01837               {
01838                      modmask = b->a_access_mask;
01839               }
01840 
01841               Debug( LDAP_DEBUG_ACL,
01842                      "<= acl_mask: [%d] applying %s (%s)\n",
01843                      i, accessmask2str( modmask, accessmaskbuf, 1 ), 
01844                      b->a_type == ACL_CONTINUE
01845                             ? "continue"
01846                             : b->a_type == ACL_BREAK
01847                                    ? "break"
01848                                    : "stop" );
01849               /* save old mask */
01850               oldmask = *mask;
01851 
01852               if( ACL_IS_ADDITIVE(modmask) ) {
01853                      /* add privs */
01854                      ACL_PRIV_SET( *mask, modmask );
01855 
01856                      /* cleanup */
01857                      ACL_PRIV_CLR( *mask, ~ACL_PRIV_MASK );
01858 
01859               } else if( ACL_IS_SUBTRACTIVE(modmask) ) {
01860                      /* substract privs */
01861                      ACL_PRIV_CLR( *mask, modmask );
01862 
01863                      /* cleanup */
01864                      ACL_PRIV_CLR( *mask, ~ACL_PRIV_MASK );
01865 
01866               } else {
01867                      /* assign privs */
01868                      *mask = modmask;
01869               }
01870 
01871               Debug( LDAP_DEBUG_ACL,
01872                      "<= acl_mask: [%d] mask: %s\n",
01873                      i, accessmask2str(*mask, accessmaskbuf, 1), 0 );
01874 
01875               if( b->a_type == ACL_CONTINUE ) {
01876                      continue;
01877 
01878               } else if ( b->a_type == ACL_BREAK ) {
01879                      return ACL_BREAK;
01880 
01881               } else {
01882                      return ACL_STOP;
01883               }
01884        }
01885 
01886        /* implicit "by * none" clause */
01887        ACL_INIT(*mask);
01888 
01889        Debug( LDAP_DEBUG_ACL,
01890               "<= acl_mask: no more <who> clauses, returning %s (stop)\n",
01891               accessmask2str(*mask, accessmaskbuf, 1), 0, 0 );
01892        return ACL_STOP;
01893 }
01894 
01895 /*
01896  * acl_check_modlist - check access control on the given entry to see if
01897  * it allows the given modifications by the user associated with op.
01898  * returns    1      if mods allowed ok
01899  *            0      mods not allowed
01900  */
01901 
01902 int
01903 acl_check_modlist(
01904        Operation     *op,
01905        Entry  *e,
01906        Modifications *mlist )
01907 {
01908        struct berval *bv;
01909        AccessControlState state = ACL_STATE_INIT;
01910        Backend *be;
01911        int be_null = 0;
01912        int ret = 1; /* default is access allowed */
01913 
01914        be = op->o_bd;
01915        if ( be == NULL ) {
01916               be = LDAP_STAILQ_FIRST(&backendDB);
01917               be_null = 1;
01918               op->o_bd = be;
01919        }
01920        assert( be != NULL );
01921 
01922        /* If ADD attribute checking is not enabled, just allow it */
01923        if ( op->o_tag == LDAP_REQ_ADD && !SLAP_DBACL_ADD( be ))
01924               return 1;
01925 
01926        /* short circuit root database access */
01927        if ( be_isroot( op ) ) {
01928               Debug( LDAP_DEBUG_ACL,
01929                      "<= acl_access_allowed: granted to database root\n",
01930                   0, 0, 0 );
01931               goto done;
01932        }
01933 
01934        /* use backend default access if no backend acls */
01935        if( op->o_bd != NULL && op->o_bd->be_acl == NULL && frontendDB->be_acl == NULL ) {
01936               Debug( LDAP_DEBUG_ACL,
01937                      "=> access_allowed: backend default %s access %s to \"%s\"\n",
01938                      access2str( ACL_WRITE ),
01939                      op->o_bd->be_dfltaccess >= ACL_WRITE
01940                             ? "granted" : "denied",
01941                      op->o_dn.bv_val );
01942               ret = (op->o_bd->be_dfltaccess >= ACL_WRITE);
01943               goto done;
01944        }
01945 
01946        for ( ; mlist != NULL; mlist = mlist->sml_next ) {
01947               /*
01948                * Internal mods are ignored by ACL_WRITE checking
01949                */
01950               if ( mlist->sml_flags & SLAP_MOD_INTERNAL ) {
01951                      Debug( LDAP_DEBUG_ACL, "acl: internal mod %s:"
01952                             " modify access granted\n",
01953                             mlist->sml_desc->ad_cname.bv_val, 0, 0 );
01954                      continue;
01955               }
01956 
01957               /*
01958                * no-user-modification operational attributes are ignored
01959                * by ACL_WRITE checking as any found here are not provided
01960                * by the user
01961                */
01962               if ( is_at_no_user_mod( mlist->sml_desc->ad_type )
01963                             && ! ( mlist->sml_flags & SLAP_MOD_MANAGING ) )
01964               {
01965                      Debug( LDAP_DEBUG_ACL, "acl: no-user-mod %s:"
01966                             " modify access granted\n",
01967                             mlist->sml_desc->ad_cname.bv_val, 0, 0 );
01968                      continue;
01969               }
01970 
01971               switch ( mlist->sml_op ) {
01972               case LDAP_MOD_REPLACE:
01973               case LDAP_MOD_INCREMENT:
01974                      /*
01975                       * We must check both permission to delete the whole
01976                       * attribute and permission to add the specific attributes.
01977                       * This prevents abuse from selfwriters.
01978                       */
01979                      if ( ! access_allowed( op, e,
01980                             mlist->sml_desc, NULL,
01981                             ( mlist->sml_flags & SLAP_MOD_MANAGING ) ? ACL_MANAGE : ACL_WDEL,
01982                             &state ) )
01983                      {
01984                             ret = 0;
01985                             goto done;
01986                      }
01987 
01988                      if ( mlist->sml_values == NULL ) break;
01989 
01990                      /* fall thru to check value to add */
01991 
01992               case LDAP_MOD_ADD:
01993               case SLAP_MOD_ADD_IF_NOT_PRESENT:
01994                      assert( mlist->sml_values != NULL );
01995 
01996                      if ( mlist->sml_op == SLAP_MOD_ADD_IF_NOT_PRESENT
01997                             && attr_find( e->e_attrs, mlist->sml_desc ) )
01998                      {
01999                             break;
02000                      }
02001 
02002                      for ( bv = mlist->sml_nvalues
02003                                    ? mlist->sml_nvalues : mlist->sml_values;
02004                             bv->bv_val != NULL; bv++ )
02005                      {
02006                             if ( ! access_allowed( op, e,
02007                                    mlist->sml_desc, bv,
02008                                    ( mlist->sml_flags & SLAP_MOD_MANAGING ) ? ACL_MANAGE : ACL_WADD,
02009                                    &state ) )
02010                             {
02011                                    ret = 0;
02012                                    goto done;
02013                             }
02014                      }
02015                      break;
02016 
02017               case LDAP_MOD_DELETE:
02018               case SLAP_MOD_SOFTDEL:
02019                      if ( mlist->sml_values == NULL ) {
02020                             if ( ! access_allowed( op, e,
02021                                    mlist->sml_desc, NULL,
02022                                    ( mlist->sml_flags & SLAP_MOD_MANAGING ) ? ACL_MANAGE : ACL_WDEL,
02023                                    &state ) )
02024                             {
02025                                    ret = 0;
02026                                    goto done;
02027                             }
02028                             break;
02029                      }
02030                      for ( bv = mlist->sml_nvalues
02031                                    ? mlist->sml_nvalues : mlist->sml_values;
02032                             bv->bv_val != NULL; bv++ )
02033                      {
02034                             if ( ! access_allowed( op, e,
02035                                    mlist->sml_desc, bv,
02036                                    ( mlist->sml_flags & SLAP_MOD_MANAGING ) ? ACL_MANAGE : ACL_WDEL,
02037                                    &state ) )
02038                             {
02039                                    ret = 0;
02040                                    goto done;
02041                             }
02042                      }
02043                      break;
02044 
02045               case SLAP_MOD_SOFTADD:
02046                      /* allow adding attribute via modrdn thru */
02047                      break;
02048 
02049               default:
02050                      assert( 0 );
02051                      /* not reached */
02052                      ret = 0;
02053                      break;
02054               }
02055        }
02056 
02057 done:
02058        if (be_null) op->o_bd = NULL;
02059        return( ret );
02060 }
02061 
02062 int
02063 acl_get_part(
02064        struct berval *list,
02065        int           ix,
02066        char          sep,
02067        struct berval *bv )
02068 {
02069        int    len;
02070        char   *p;
02071 
02072        if ( bv ) {
02073               BER_BVZERO( bv );
02074        }
02075        len = list->bv_len;
02076        p = list->bv_val;
02077        while ( len >= 0 && --ix >= 0 ) {
02078               while ( --len >= 0 && *p++ != sep )
02079                      ;
02080        }
02081        while ( len >= 0 && *p == ' ' ) {
02082               len--;
02083               p++;
02084        }
02085        if ( len < 0 ) {
02086               return -1;
02087        }
02088 
02089        if ( !bv ) {
02090               return 0;
02091        }
02092 
02093        bv->bv_val = p;
02094        while ( --len >= 0 && *p != sep ) {
02095               bv->bv_len++;
02096               p++;
02097        }
02098        while ( bv->bv_len > 0 && *--p == ' ' ) {
02099               bv->bv_len--;
02100        }
02101        
02102        return bv->bv_len;
02103 }
02104 
02105 typedef struct acl_set_gather_t {
02106        SetCookie            *cookie;
02107        BerVarray            bvals;
02108 } acl_set_gather_t;
02109 
02110 static int
02111 acl_set_cb_gather( Operation *op, SlapReply *rs )
02112 {
02113        acl_set_gather_t     *p = (acl_set_gather_t *)op->o_callback->sc_private;
02114        
02115        if ( rs->sr_type == REP_SEARCH ) {
02116               BerValue      bvals[ 2 ];
02117               BerVarray     bvalsp = NULL;
02118               int           j;
02119 
02120               for ( j = 0; !BER_BVISNULL( &rs->sr_attrs[ j ].an_name ); j++ ) {
02121                      AttributeDescription *desc = rs->sr_attrs[ j ].an_desc;
02122 
02123                      if ( desc == NULL ) {
02124                             continue;
02125                      }
02126                      
02127                      if ( desc == slap_schema.si_ad_entryDN ) {
02128                             bvalsp = bvals;
02129                             bvals[ 0 ] = rs->sr_entry->e_nname;
02130                             BER_BVZERO( &bvals[ 1 ] );
02131 
02132                      } else {
02133                             Attribute     *a;
02134 
02135                             a = attr_find( rs->sr_entry->e_attrs, desc );
02136                             if ( a != NULL ) {
02137                                    bvalsp = a->a_nvals;
02138                             }
02139                      }
02140 
02141                      if ( bvalsp ) {
02142                             p->bvals = slap_set_join( p->cookie, p->bvals,
02143                                           ( '|' | SLAP_SET_RREF ), bvalsp );
02144                      }
02145               }
02146 
02147        } else {
02148               switch ( rs->sr_type ) {
02149               case REP_SEARCHREF:
02150               case REP_INTERMEDIATE:
02151                      /* ignore */
02152                      break;
02153 
02154               default:
02155                      assert( rs->sr_type == REP_RESULT );
02156                      break;
02157               }
02158        }
02159 
02160        return 0;
02161 }
02162 
02163 BerVarray
02164 acl_set_gather( SetCookie *cookie, struct berval *name, AttributeDescription *desc )
02165 {
02166        AclSetCookie         *cp = (AclSetCookie *)cookie;
02167        int                  rc = 0;
02168        LDAPURLDesc          *ludp = NULL;
02169        Operation            op2 = { 0 };
02170        SlapReply            rs = {REP_RESULT};
02171        AttributeName        anlist[ 2 ], *anlistp = NULL;
02172        int                  nattrs = 0;
02173        slap_callback        cb = { NULL, acl_set_cb_gather, NULL, NULL };
02174        acl_set_gather_t     p = { 0 };
02175 
02176        /* this routine needs to return the bervals instead of
02177         * plain strings, since syntax is not known.  It should
02178         * also return the syntax or some "comparison cookie".
02179         */
02180        if ( strncasecmp( name->bv_val, "ldap:///", STRLENOF( "ldap:///" ) ) != 0 ) {
02181               return acl_set_gather2( cookie, name, desc );
02182        }
02183 
02184        rc = ldap_url_parse( name->bv_val, &ludp );
02185        if ( rc != LDAP_URL_SUCCESS ) {
02186               Debug( LDAP_DEBUG_TRACE,
02187                      "%s acl_set_gather: unable to parse URL=\"%s\"\n",
02188                      cp->asc_op->o_log_prefix, name->bv_val, 0 );
02189 
02190               rc = LDAP_PROTOCOL_ERROR;
02191               goto url_done;
02192        }
02193        
02194        if ( ( ludp->lud_host && ludp->lud_host[0] ) || ludp->lud_exts )
02195        {
02196               /* host part must be empty */
02197               /* extensions parts must be empty */
02198               Debug( LDAP_DEBUG_TRACE,
02199                      "%s acl_set_gather: host/exts must be absent in URL=\"%s\"\n",
02200                      cp->asc_op->o_log_prefix, name->bv_val, 0 );
02201 
02202               rc = LDAP_PROTOCOL_ERROR;
02203               goto url_done;
02204        }
02205 
02206        /* Grab the searchbase and see if an appropriate database can be found */
02207        ber_str2bv( ludp->lud_dn, 0, 0, &op2.o_req_dn );
02208        rc = dnNormalize( 0, NULL, NULL, &op2.o_req_dn,
02209                      &op2.o_req_ndn, cp->asc_op->o_tmpmemctx );
02210        BER_BVZERO( &op2.o_req_dn );
02211        if ( rc != LDAP_SUCCESS ) {
02212               Debug( LDAP_DEBUG_TRACE,
02213                      "%s acl_set_gather: DN=\"%s\" normalize failed\n",
02214                      cp->asc_op->o_log_prefix, ludp->lud_dn, 0 );
02215 
02216               goto url_done;
02217        }
02218 
02219        op2.o_bd = select_backend( &op2.o_req_ndn, 1 );
02220        if ( ( op2.o_bd == NULL ) || ( op2.o_bd->be_search == NULL ) ) {
02221               Debug( LDAP_DEBUG_TRACE,
02222                      "%s acl_set_gather: no database could be selected for DN=\"%s\"\n",
02223                      cp->asc_op->o_log_prefix, op2.o_req_ndn.bv_val, 0 );
02224 
02225               rc = LDAP_NO_SUCH_OBJECT;
02226               goto url_done;
02227        }
02228 
02229        /* Grab the filter */
02230        if ( ludp->lud_filter ) {
02231               ber_str2bv_x( ludp->lud_filter, 0, 0, &op2.ors_filterstr,
02232                             cp->asc_op->o_tmpmemctx );
02233               op2.ors_filter = str2filter_x( cp->asc_op, op2.ors_filterstr.bv_val );
02234               if ( op2.ors_filter == NULL ) {
02235                      Debug( LDAP_DEBUG_TRACE,
02236                             "%s acl_set_gather: unable to parse filter=\"%s\"\n",
02237                             cp->asc_op->o_log_prefix, op2.ors_filterstr.bv_val, 0 );
02238 
02239                      rc = LDAP_PROTOCOL_ERROR;
02240                      goto url_done;
02241               }
02242               
02243        } else {
02244               op2.ors_filterstr = *slap_filterstr_objectClass_pres;
02245               op2.ors_filter = (Filter *)slap_filter_objectClass_pres;
02246        }
02247 
02248 
02249        /* Grab the scope */
02250        op2.ors_scope = ludp->lud_scope;
02251 
02252        /* Grap the attributes */
02253        if ( ludp->lud_attrs ) {
02254               int i;
02255 
02256               for ( ; ludp->lud_attrs[ nattrs ]; nattrs++ )
02257                      ;
02258 
02259               anlistp = slap_sl_calloc( sizeof( AttributeName ), nattrs + 2,
02260                             cp->asc_op->o_tmpmemctx );
02261 
02262               for ( i = 0, nattrs = 0; ludp->lud_attrs[ i ]; i++ ) {
02263                      struct berval        name;
02264                      AttributeDescription *desc = NULL;
02265                      const char           *text = NULL;
02266 
02267                      ber_str2bv( ludp->lud_attrs[ i ], 0, 0, &name );
02268                      rc = slap_bv2ad( &name, &desc, &text );
02269                      if ( rc == LDAP_SUCCESS ) {
02270                             anlistp[ nattrs ].an_name = name;
02271                             anlistp[ nattrs ].an_desc = desc;
02272                             nattrs++;
02273                      }
02274               }
02275 
02276        } else {
02277               anlistp = anlist;
02278        }
02279 
02280        anlistp[ nattrs ].an_name = desc->ad_cname;
02281        anlistp[ nattrs ].an_desc = desc;
02282 
02283        BER_BVZERO( &anlistp[ nattrs + 1 ].an_name );
02284        
02285        p.cookie = cookie;
02286        
02287        op2.o_hdr = cp->asc_op->o_hdr;
02288        op2.o_tag = LDAP_REQ_SEARCH;
02289        op2.o_ndn = op2.o_bd->be_rootndn;
02290        op2.o_callback = &cb;
02291        slap_op_time( &op2.o_time, &op2.o_tincr );
02292        op2.o_do_not_cache = 1;
02293        op2.o_is_auth_check = 0;
02294        ber_dupbv_x( &op2.o_req_dn, &op2.o_req_ndn, cp->asc_op->o_tmpmemctx );
02295        op2.ors_slimit = SLAP_NO_LIMIT;
02296        op2.ors_tlimit = SLAP_NO_LIMIT;
02297        op2.ors_attrs = anlistp;
02298        op2.ors_attrsonly = 0;
02299        op2.o_private = cp->asc_op->o_private;
02300        op2.o_extra = cp->asc_op->o_extra;
02301 
02302        cb.sc_private = &p;
02303 
02304        rc = op2.o_bd->be_search( &op2, &rs );
02305        if ( rc != 0 ) {
02306               goto url_done;
02307        }
02308 
02309 url_done:;
02310        if ( op2.ors_filter && op2.ors_filter != slap_filter_objectClass_pres ) {
02311               filter_free_x( cp->asc_op, op2.ors_filter, 1 );
02312        }
02313        if ( !BER_BVISNULL( &op2.o_req_ndn ) ) {
02314               slap_sl_free( op2.o_req_ndn.bv_val, cp->asc_op->o_tmpmemctx );
02315        }
02316        if ( !BER_BVISNULL( &op2.o_req_dn ) ) {
02317               slap_sl_free( op2.o_req_dn.bv_val, cp->asc_op->o_tmpmemctx );
02318        }
02319        if ( ludp ) {
02320               ldap_free_urldesc( ludp );
02321        }
02322        if ( anlistp && anlistp != anlist ) {
02323               slap_sl_free( anlistp, cp->asc_op->o_tmpmemctx );
02324        }
02325 
02326        return p.bvals;
02327 }
02328 
02329 BerVarray
02330 acl_set_gather2( SetCookie *cookie, struct berval *name, AttributeDescription *desc )
02331 {
02332        AclSetCookie  *cp = (AclSetCookie *)cookie;
02333        BerVarray     bvals = NULL;
02334        struct berval ndn;
02335        int           rc = 0;
02336 
02337        /* this routine needs to return the bervals instead of
02338         * plain strings, since syntax is not known.  It should
02339         * also return the syntax or some "comparison cookie".
02340         */
02341        rc = dnNormalize( 0, NULL, NULL, name, &ndn, cp->asc_op->o_tmpmemctx );
02342        if ( rc == LDAP_SUCCESS ) {
02343               if ( desc == slap_schema.si_ad_entryDN ) {
02344                      bvals = (BerVarray)slap_sl_malloc( sizeof( BerValue ) * 2,
02345                                    cp->asc_op->o_tmpmemctx );
02346                      bvals[ 0 ] = ndn;
02347                      BER_BVZERO( &bvals[ 1 ] );
02348                      BER_BVZERO( &ndn );
02349 
02350               } else {
02351                      backend_attribute( cp->asc_op,
02352                             cp->asc_e, &ndn, desc, &bvals, ACL_NONE );
02353               }
02354 
02355               if ( !BER_BVISNULL( &ndn ) ) {
02356                      slap_sl_free( ndn.bv_val, cp->asc_op->o_tmpmemctx );
02357               }
02358        }
02359 
02360        return bvals;
02361 }
02362 
02363 int
02364 acl_match_set (
02365        struct berval *subj,
02366        Operation *op,
02367        Entry *e,
02368        struct berval *default_set_attribute )
02369 {
02370        struct berval set = BER_BVNULL;
02371        int           rc = 0;
02372        AclSetCookie  cookie;
02373 
02374        if ( default_set_attribute == NULL ) {
02375               set = *subj;
02376 
02377        } else {
02378               struct berval        subjdn, ndn = BER_BVNULL;
02379               struct berval        setat;
02380               BerVarray            bvals = NULL;
02381               const char           *text;
02382               AttributeDescription *desc = NULL;
02383 
02384               /* format of string is "entry/setAttrName" */
02385               if ( acl_get_part( subj, 0, '/', &subjdn ) < 0 ) {
02386                      return 0;
02387               }
02388 
02389               if ( acl_get_part( subj, 1, '/', &setat ) < 0 ) {
02390                      setat = *default_set_attribute;
02391               }
02392 
02393               /*
02394                * NOTE: dnNormalize honors the ber_len field
02395                * as the length of the dn to be normalized
02396                */
02397               if ( slap_bv2ad( &setat, &desc, &text ) == LDAP_SUCCESS ) {
02398                      if ( dnNormalize( 0, NULL, NULL, &subjdn, &ndn, op->o_tmpmemctx ) == LDAP_SUCCESS )
02399                      {
02400                             backend_attribute( op, e, &ndn, desc, &bvals, ACL_NONE );
02401                             if ( bvals != NULL && !BER_BVISNULL( &bvals[0] ) ) {
02402                                    int    i;
02403 
02404                                    set = bvals[0];
02405                                    BER_BVZERO( &bvals[0] );
02406                                    for ( i = 1; !BER_BVISNULL( &bvals[i] ); i++ )
02407                                           /* count */ ;
02408                                    bvals[0].bv_val = bvals[i-1].bv_val;
02409                                    BER_BVZERO( &bvals[i-1] );
02410                             }
02411                             ber_bvarray_free_x( bvals, op->o_tmpmemctx );
02412                             slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
02413                      }
02414               }
02415        }
02416 
02417        if ( !BER_BVISNULL( &set ) ) {
02418               cookie.asc_op = op;
02419               cookie.asc_e = e;
02420               rc = ( slap_set_filter(
02421                      acl_set_gather,
02422                      (SetCookie *)&cookie, &set,
02423                      &op->o_ndn, &e->e_nname, NULL ) > 0 );
02424               if ( set.bv_val != subj->bv_val ) {
02425                      slap_sl_free( set.bv_val, op->o_tmpmemctx );
02426               }
02427        }
02428 
02429        return(rc);
02430 }
02431 
02432 #ifdef SLAP_DYNACL
02433 
02434 /*
02435  * dynamic ACL infrastructure
02436  */
02437 static slap_dynacl_t *da_list = NULL;
02438 
02439 int
02440 slap_dynacl_register( slap_dynacl_t *da )
02441 {
02442        slap_dynacl_t *tmp;
02443 
02444        for ( tmp = da_list; tmp; tmp = tmp->da_next ) {
02445               if ( strcasecmp( da->da_name, tmp->da_name ) == 0 ) {
02446                      break;
02447               }
02448        }
02449 
02450        if ( tmp != NULL ) {
02451               return -1;
02452        }
02453        
02454        if ( da->da_mask == NULL ) {
02455               return -1;
02456        }
02457        
02458        da->da_private = NULL;
02459        da->da_next = da_list;
02460        da_list = da;
02461 
02462        return 0;
02463 }
02464 
02465 static slap_dynacl_t *
02466 slap_dynacl_next( slap_dynacl_t *da )
02467 {
02468        if ( da ) {
02469               return da->da_next;
02470        }
02471        return da_list;
02472 }
02473 
02474 slap_dynacl_t *
02475 slap_dynacl_get( const char *name )
02476 {
02477        slap_dynacl_t *da;
02478 
02479        for ( da = slap_dynacl_next( NULL ); da; da = slap_dynacl_next( da ) ) {
02480               if ( strcasecmp( da->da_name, name ) == 0 ) {
02481                      break;
02482               }
02483        }
02484 
02485        return da;
02486 }
02487 #endif /* SLAP_DYNACL */
02488 
02489 /*
02490  * statically built-in dynamic ACL initialization
02491  */
02492 static int (*acl_init_func[])( void ) = {
02493 #ifdef SLAP_DYNACL
02494        /* TODO: remove when ACI will only be dynamic */
02495 #if SLAPD_ACI_ENABLED == SLAPD_MOD_STATIC
02496        dynacl_aci_init,
02497 #endif /* SLAPD_ACI_ENABLED */
02498 #endif /* SLAP_DYNACL */
02499 
02500        NULL
02501 };
02502 
02503 int
02504 acl_init( void )
02505 {
02506        int    i, rc;
02507 
02508        for ( i = 0; acl_init_func[ i ] != NULL; i++ ) {
02509               rc = (*(acl_init_func[ i ]))();
02510               if ( rc != 0 ) {
02511                      return rc;
02512               }
02513        }
02514 
02515        return 0;
02516 }
02517 
02518 int
02519 acl_string_expand(
02520        struct berval *bv,
02521        struct berval *pat,
02522        struct berval *dn_matches,
02523        struct berval *val_matches,
02524        AclRegexMatches      *matches)
02525 {
02526        ber_len_t     size;
02527        char   *sp;
02528        char   *dp;
02529        int    flag;
02530        enum { DN_FLAG, VAL_FLAG } tflag;
02531 
02532        size = 0;
02533        bv->bv_val[0] = '\0';
02534        bv->bv_len--; /* leave space for lone $ */
02535 
02536        flag = 0;
02537        tflag = DN_FLAG;
02538        for ( dp = bv->bv_val, sp = pat->bv_val; size < bv->bv_len &&
02539               sp < pat->bv_val + pat->bv_len ; sp++ )
02540        {
02541               /* did we previously see a $ */
02542               if ( flag ) {
02543                      if ( flag == 1 && *sp == '$' ) {
02544                             *dp++ = '$';
02545                             size++;
02546                             flag = 0;
02547                             tflag = DN_FLAG;
02548 
02549                      } else if ( flag == 2 && *sp == 'v' /*'}'*/) {
02550                             tflag = VAL_FLAG;
02551 
02552                      } else if ( flag == 2 && *sp == 'd' /*'}'*/) {
02553                             tflag = DN_FLAG;
02554 
02555                      } else if ( flag == 1 && *sp == '{' /*'}'*/) {
02556                             flag = 2;
02557 
02558                      } else if ( *sp >= '0' && *sp <= '9' ) {
02559                             int    nm;
02560                             regmatch_t *m;
02561                             char *data;
02562                             int    n;
02563                             int    i;
02564                             int    l;
02565 
02566                             n = *sp - '0';
02567 
02568                             if ( flag == 2 ) {
02569                                    for ( sp++; *sp != '\0' && *sp != /*'{'*/ '}'; sp++ ) {
02570                                           if ( *sp >= '0' && *sp <= '9' ) {
02571                                                  n = 10*n + ( *sp - '0' );
02572                                           }
02573                                    }
02574 
02575                                    if ( *sp != /*'{'*/ '}' ) {
02576                                           /* FIXME: error */
02577                                           return 1;
02578                                    }
02579                             }
02580 
02581                             switch (tflag) {
02582                             case DN_FLAG:
02583                                    nm = matches->dn_count;
02584                                    m = matches->dn_data;
02585                                    data = dn_matches ? dn_matches->bv_val : NULL;
02586                                    break;
02587                             case VAL_FLAG:
02588                                    nm = matches->val_count;
02589                                    m = matches->val_data;
02590                                    data = val_matches ? val_matches->bv_val : NULL;
02591                                    break;
02592                             default:
02593                                    assert( 0 );
02594                             }
02595                             if ( n >= nm ) {
02596                                    /* FIXME: error */
02597                                    return 1;
02598                             }
02599                             if ( data == NULL ) {
02600                                    /* FIXME: error */
02601                                    return 1;
02602                             }
02603                             
02604                             *dp = '\0';
02605                             i = m[n].rm_so;
02606                             l = m[n].rm_eo; 
02607                                    
02608                             for ( ; size < bv->bv_len && i < l; size++, i++ ) {
02609                                    *dp++ = data[i];
02610                             }
02611                             *dp = '\0';
02612 
02613                             flag = 0;
02614                             tflag = DN_FLAG;
02615                      }
02616               } else {
02617                      if (*sp == '$') {
02618                             flag = 1;
02619                      } else {
02620                             *dp++ = *sp;
02621                             size++;
02622                      }
02623               }
02624        }
02625 
02626        if ( flag ) {
02627               /* must have ended with a single $ */
02628               *dp++ = '$';
02629               size++;
02630        }
02631 
02632        *dp = '\0';
02633        bv->bv_len = size;
02634 
02635        Debug( LDAP_DEBUG_ACL, "=> acl_string_expand: pattern:  %.*s\n", (int)pat->bv_len, pat->bv_val, 0 );
02636        Debug( LDAP_DEBUG_ACL, "=> acl_string_expand: expanded: %s\n", bv->bv_val, 0, 0 );
02637 
02638        return 0;
02639 }
02640 
02641 static int
02642 regex_matches(
02643        struct berval *pat,         /* pattern to expand and match against */
02644        char          *str,         /* string to match against pattern */
02645        struct berval *dn_matches,  /* buffer with $N expansion variables from DN */
02646        struct berval *val_matches, /* buffer with $N expansion variables from val */
02647        AclRegexMatches      *matches      /* offsets in buffer for $N expansion variables */
02648 )
02649 {
02650        regex_t re;
02651        char newbuf[ACL_BUF_SIZE];
02652        struct berval bv;
02653        int    rc;
02654 
02655        bv.bv_len = sizeof( newbuf ) - 1;
02656        bv.bv_val = newbuf;
02657 
02658        if (str == NULL) {
02659               str = "";
02660        };
02661 
02662        acl_string_expand( &bv, pat, dn_matches, val_matches, matches );
02663        rc = regcomp( &re, newbuf, REG_EXTENDED|REG_ICASE );
02664        if ( rc ) {
02665               char error[ACL_BUF_SIZE];
02666               regerror( rc, &re, error, sizeof( error ) );
02667 
02668               Debug( LDAP_DEBUG_TRACE,
02669                   "compile( \"%s\", \"%s\") failed %s\n",
02670                      pat->bv_val, str, error );
02671               return( 0 );
02672        }
02673 
02674        rc = regexec( &re, str, 0, NULL, 0 );
02675        regfree( &re );
02676 
02677        Debug( LDAP_DEBUG_TRACE,
02678            "=> regex_matches: string:      %s\n", str, 0, 0 );
02679        Debug( LDAP_DEBUG_TRACE,
02680            "=> regex_matches: rc: %d %s\n",
02681               rc, !rc ? "matches" : "no matches", 0 );
02682        return( !rc );
02683 }
02684