From: Kurt Zeilenga Date: Wed, 19 Aug 1998 20:02:01 +0000 (+0000) Subject: Merged in ACL changes. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b7fb751822d19b37e1a7fcc672de78cec1e66599;p=thirdparty%2Fopenldap.git Merged in ACL changes. --- diff --git a/libraries/libldap/regex.c b/libraries/libldap/regex.c index 4f309c5fb0..f34fc85eb2 100644 --- a/libraries/libldap/regex.c +++ b/libraries/libldap/regex.c @@ -1,7 +1,7 @@ #include "portable.h" #if defined( MACOS ) || defined( DOS ) || defined( _WIN32 ) || defined( NEED_BSDREGEX ) -#include "regex.h" +#include "compat_regex.h" /* * regex - Regular expression pattern matching and replacement @@ -20,9 +20,8 @@ * see Henry Spencer's regexp routines, or GNU Emacs pattern * matching module. * - * Modification history: + * Vendor Modification history: * - * $Log: regex.c,v $ * Revision 1.12 1996/04/25 16:20:59 mcs * make re_exec() match "" with ".*" and similar patterns * hopefully this change doesn't break anything else! diff --git a/servers/slapd/acl.c b/servers/slapd/acl.c index 6c3b22ee85..7e4379ecb7 100644 --- a/servers/slapd/acl.c +++ b/servers/slapd/acl.c @@ -11,6 +11,7 @@ #else #include "regex.h" #endif + #include "slap.h" extern Attribute *attr_find(); @@ -25,8 +26,12 @@ int access_allowed(); struct acl *acl_get_applicable(); static int regex_matches(); +#ifdef USEREGEX +static string_expand(char *newbuf, int bufsiz, char *pattern, char *match, regmatch_t *matches); +#endif extern pthread_mutex_t regex_mutex; +extern Entry * be_dn2entry(Backend *be, char *bdn, char **matched); /* * access_allowed - check whether dn is allowed the requested access @@ -39,6 +44,7 @@ extern pthread_mutex_t regex_mutex; * 1 access allowed */ + int access_allowed( Backend *be, @@ -53,13 +59,47 @@ access_allowed( { int rc; struct acl *a; + char *edn; + +#ifdef USEREGEX + regmatch_t matches[MAXREMATCHES]; + int i; + int n; +#endif if ( be == NULL ) { return( 0 ); } - a = acl_get_applicable( be, op, e, attr ); - rc = acl_access_allowed( a, be, conn, e, val, op, access ); + edn = dn_normalize_case( strdup( e->e_dn ) ); + Debug( LDAP_DEBUG_ACL, "\n=> access_allowed: entry (%s) attr (%s)\n", e->e_dn, attr, 0 ); + /* the lastmod attributes are ignored by ACL checking */ + if ( strcasecmp( attr, "modifiersname" ) == 0 || + strcasecmp( attr, "modifytimestamp" ) == 0 || + strcasecmp( attr, "creatorsname" ) == 0 || + strcasecmp( attr, "createtimestamp" ) == 0 + ) { + Debug( LDAP_DEBUG_ACL, "LASTMOD attribute: %s access allowed\n", attr, 0, 0 ); + return(1); + } +#ifdef USEREGEX + a = acl_get_applicable( be, op, e, attr, edn, MAXREMATCHES, matches ); + + if (a) { + for (i = 0; i < MAXREMATCHES && matches[i].rm_so>-1; i++) { + Debug( LDAP_DEBUG_ARGS, "=> match[%d]: %d %d ", i, matches[i].rm_so, matches[i].rm_eo ); + for ( n = matches[i].rm_so; n < matches[i].rm_eo; n++) + Debug( LDAP_DEBUG_ARGS, "%c", edn[n], 0, 0 ); + Debug( LDAP_DEBUG_ARGS, "\n", 0, 0, 0 ); + } + } + + rc = acl_access_allowed( a, be, conn, e, val, op, access, edn, matches ); +#else + a = acl_get_applicable( be, op, e, attr, edn ); + rc = acl_access_allowed( a, be, conn, e, val, op, access, edn ); +#endif + free(edn); return( rc ); } @@ -70,20 +110,32 @@ access_allowed( * acl_access_allowed(). */ +#ifdef USEREGEX struct acl * acl_get_applicable( Backend *be, Operation *op, Entry *e, - char *attr + char *attr, + char *edn, + int nmatch, + regmatch_t matches[] ) +#else +struct acl * +acl_get_applicable( + Backend *be, + Operation *op, + Entry *e, + char *attr, + char *edn +) +#endif { int i; struct acl *a; - char *edn; - Debug( LDAP_DEBUG_ACL, "=> acl_get: entry (%s) attr (%s)\n", e->e_dn, - attr, 0 ); + Debug( LDAP_DEBUG_ACL, "\n=> acl_get: entry (%s) attr (%s)\n", e->e_dn, attr, 0 ); if ( be_isroot( be, op->o_dn ) ) { Debug( LDAP_DEBUG_ACL, @@ -92,58 +144,78 @@ acl_get_applicable( return( NULL ); } + Debug( LDAP_DEBUG_ARGS, "=> acl_get: edn %s\n", edn, 0, 0 ); + /* check for a backend-specific acl that matches the entry */ for ( i = 1, a = be->be_acl; a != NULL; a = a->acl_next, i++ ) { +#ifdef USEREGEX + if (a->acl_dnpat != NULL) { + Debug( LDAP_DEBUG_TRACE, "=> dnpat: [%d] %s nsub: %d\n", + i, a->acl_dnpat, a->acl_dnre.re_nsub); + if (regexec(&a->acl_dnre, edn, nmatch, matches, 0)) + continue; + else + Debug( LDAP_DEBUG_TRACE, "=> acl_get:[%d] backend ACL match\n", i, 0, 0); + } +#else if ( a->acl_dnpat != NULL ) { - edn = dn_normalize_case( strdup( e->e_dn ) ); - if ( ! regex_matches( a->acl_dnpat, edn ) ) { - free( edn ); + if ( ! regex_matches( a->acl_dnpat, edn ) ) continue; - } - free( edn ); } +#endif if ( a->acl_filter != NULL ) { - if ( test_filter( NULL, NULL, NULL, e, a->acl_filter ) - != 0 ) { + if ( test_filter( NULL, NULL, NULL, e, a->acl_filter ) != 0 ) { continue; } } - if ( attr == NULL || a->acl_attrs == NULL || - charray_inlist( a->acl_attrs, attr ) ) { - Debug( LDAP_DEBUG_ACL, "<= acl_get: backend acl #%d\n", - i, e->e_dn, attr ); + Debug( LDAP_DEBUG_ARGS, "=> acl_get: [%d] check attr %s\n", i, attr, 0); + if ( attr == NULL || a->acl_attrs == NULL || charray_inlist( a->acl_attrs, attr ) ) { + Debug( LDAP_DEBUG_ACL, "<= acl_get: [%d] backend acl %s attr: %s\n", i, e->e_dn, attr ); return( a ); } +#ifdef USEREGEX + matches[0].rm_so = matches[0].rm_eo = -1; +#endif } /* check for a global acl that matches the entry */ for ( i = 1, a = global_acl; a != NULL; a = a->acl_next, i++ ) { +#ifdef USEREGEX + if (a->acl_dnpat != NULL) { + Debug( LDAP_DEBUG_TRACE, "=> dnpat: [%d] %s nsub: %d\n", + i, a->acl_dnpat, a->acl_dnre.re_nsub); + if (regexec(&a->acl_dnre, edn, nmatch, matches, 0)) + continue; + else + Debug( LDAP_DEBUG_TRACE, "=> acl_get: [%d] global ACL match\n", i, 0, 0); + } +#else if ( a->acl_dnpat != NULL ) { - edn = dn_normalize_case( strdup( e->e_dn ) ); - if ( ! regex_matches( a->acl_dnpat, edn ) ) { - free( edn ); + if ( ! regex_matches( a->acl_dnpat, edn ) ) continue; - } - free( edn ); } +#endif if ( a->acl_filter != NULL ) { - if ( test_filter( NULL, NULL, NULL, e, a->acl_filter ) - != 0 ) { + if ( test_filter( NULL, NULL, NULL, e, a->acl_filter ) != 0 ) { continue; } } - if ( attr == NULL || a->acl_attrs == NULL || charray_inlist( - a->acl_attrs, attr ) ) { - Debug( LDAP_DEBUG_ACL, "<= acl_get: global acl #%d\n", - i, e->e_dn, attr ); + Debug( LDAP_DEBUG_ARGS, "=> acl_get: [%d] check attr\n", i, 0, 0); + if ( attr == NULL || a->acl_attrs == NULL || charray_inlist( a->acl_attrs, attr ) ) { + Debug( LDAP_DEBUG_ACL, "<= acl_get: [%d] global acl %s attr: %s\n", i, e->e_dn, attr ); + free( edn ); return( a ); } +#ifdef USEREGEX + matches[0].rm_so = matches[0].rm_eo = -1; +#endif } Debug( LDAP_DEBUG_ACL, "<= acl_get: no match\n", 0, 0, 0 ); return( NULL ); } + /* * acl_access_allowed - check whether the given acl allows dn the * requested access to entry e, attribute attr, value val. if val @@ -153,6 +225,7 @@ acl_get_applicable( * 1 access allowed */ +#ifdef USEREGEX int acl_access_allowed( struct acl *a, @@ -161,19 +234,36 @@ acl_access_allowed( Entry *e, struct berval *val, Operation *op, - int access + int access, + char *edn, + regmatch_t matches[] +) +#else +int +acl_access_allowed( + struct acl *a, + Backend *be, + Connection *conn, + Entry *e, + struct berval *val, + Operation *op, + int access, + char *edn ) +#endif { int i; - char *edn, *odn; + char *odn; struct access *b; Attribute *at; struct berval bv; int default_access; - Debug( LDAP_DEBUG_ACL, "=> acl: %s access to value \"%s\" by \"%s\"\n", - access2str( access ), val ? val->bv_val : "any", op->o_dn ? - op->o_dn : "" ); + Debug( LDAP_DEBUG_ACL, "\n=> acl: %s access to entry \"%s\" attr: \"%s\"\n", + access2str( access ), e->e_dn, e->e_attrs); + + Debug( LDAP_DEBUG_ACL, "\n=> acl: %s access to value \"%s\" by \"%s\"\n", + access2str( access ), val ? val->bv_val : "any", op->o_dn ? op->o_dn : "" ); if ( be_isroot( be, op->o_dn ) ) { Debug( LDAP_DEBUG_ACL, "<= acl: granted to database root\n", @@ -181,8 +271,8 @@ acl_access_allowed( return( 1 ); } - default_access = be->be_dfltaccess ? be->be_dfltaccess : - global_default_access; + default_access = be->be_dfltaccess ? be->be_dfltaccess : global_default_access; + if ( a == NULL ) { Debug( LDAP_DEBUG_ACL, "<= acl: %s by default (no matching to)\n", @@ -198,69 +288,84 @@ acl_access_allowed( } for ( i = 1, b = a->acl_access; b != NULL; b = b->a_next, i++ ) { if ( b->a_dnpat != NULL ) { + Debug( LDAP_DEBUG_TRACE, "<= check a_dnpat: %s\n", b->a_dnpat, 0, 0); /* * if access applies to the entry itself, and the * user is bound as somebody in the same namespace as * the entry, OR the given dn matches the dn pattern */ - if ( strcasecmp( b->a_dnpat, "self" ) == 0 && op->o_dn - != NULL && *(op->o_dn) && e->e_dn != NULL ) { - edn = dn_normalize_case( strdup( e->e_dn ) ); + if ( strcasecmp( b->a_dnpat, "self" ) == 0 && + op->o_dn != NULL && *(op->o_dn) && e->e_dn != NULL ) + { if ( strcasecmp( edn, op->o_dn ) == 0 ) { - free( edn ); - if ( odn ) free( odn ); Debug( LDAP_DEBUG_ACL, "<= acl: matched by clause #%d access %s\n", i, (b->a_access & ~ACL_SELF) >= access ? "granted" : "denied", 0 ); - return( (b->a_access & ~ACL_SELF) - >= access ); + if ( odn ) free( odn ); + return( (b->a_access & ~ACL_SELF) >= access ); } - free( edn ); } else { - if ( regex_matches( b->a_dnpat, odn ) ) { - if ( odn ) free( odn ); +#ifdef USEREGEX + if ( regex_matches( b->a_dnpat, odn, edn, matches ) ) +#else + if ( regex_matches( b->a_dnpat, odn ) ) +#endif + { Debug( LDAP_DEBUG_ACL, "<= acl: matched by clause #%d access %s\n", i, (b->a_access & ~ACL_SELF) >= access ? "granted" : "denied", 0 ); - return( (b->a_access & ~ACL_SELF) - >= access ); + if ( odn ) free( odn ); + return( (b->a_access & ~ACL_SELF) >= access ); } } } if ( b->a_addrpat != NULL ) { - if ( regex_matches( b->a_addrpat, conn->c_addr ) ) { - if ( odn ) free( odn ); + Debug( LDAP_DEBUG_ARGS, "<= check a_addrpat: %s\n", b->a_addrpat, 0, 0); +#ifdef USEREGEX + if ( regex_matches( b->a_addrpat, conn->c_addr, edn, matches ) ) +#else + if ( regex_matches( b->a_addrpat, conn->c_addr ) ) +#endif + { Debug( LDAP_DEBUG_ACL, "<= acl: matched by clause #%d access %s\n", i, (b->a_access & ~ACL_SELF) >= access ? "granted" : "denied", 0 ); + if ( odn ) free( odn ); return( (b->a_access & ~ACL_SELF) >= access ); } } if ( b->a_domainpat != NULL ) { - if ( regex_matches( b->a_domainpat, conn->c_domain ) ) { - if ( odn ) free( odn ); + Debug( LDAP_DEBUG_ARGS, "<= check a_domainpat: %s\n", b->a_domainpat, 0, 0); +#ifdef USEREGEX + if ( regex_matches( b->a_domainpat, conn->c_domain, edn, matches ) ) +#else + if ( regex_matches( b->a_domainpat, conn->c_domain ) ) +#endif + { Debug( LDAP_DEBUG_ACL, "<= acl: matched by clause #%d access %s\n", i, (b->a_access & ~ACL_SELF) >= access ? "granted" : "denied", 0 ); + if ( odn ) free( odn ); return( (b->a_access & ~ACL_SELF) >= access ); } } if ( b->a_dnattr != NULL && op->o_dn != NULL ) { + + Debug( LDAP_DEBUG_ARGS, "<= check a_dnattr: %s\n", b->a_dnattr, 0, 0); /* see if asker is listed in dnattr */ - if ( (at = attr_find( e->e_attrs, b->a_dnattr )) - != NULL && value_find( at->a_vals, &bv, - at->a_syntax, 3 ) == 0 ) + if ( (at = attr_find( e->e_attrs, b->a_dnattr )) != NULL && + value_find( at->a_vals, &bv, at->a_syntax, 3 ) == 0 ) { - if ( (b->a_access & ACL_SELF) && (val == NULL - || value_cmp( &bv, val, at->a_syntax, + if ( (b->a_access & ACL_SELF) && + (val == NULL || value_cmp( &bv, val, at->a_syntax, 2 )) ) { continue; } @@ -275,8 +380,7 @@ acl_access_allowed( } /* asker not listed in dnattr - check for self access */ - if ( ! (b->a_access & ACL_SELF) || val == NULL || - value_cmp( &bv, val, at->a_syntax, 2 ) != 0 ) { + if ( ! (b->a_access & ACL_SELF) || val == NULL || value_cmp( &bv, val, at->a_syntax, 2 ) != 0 ) { continue; } @@ -288,6 +392,30 @@ acl_access_allowed( return( (b->a_access & ~ACL_SELF) >= access ); } +#ifdef ACLGROUP + if ( b->a_group != NULL && op->o_dn != NULL ) { + + char buf[512]; + + /* b->a_group is an unexpanded entry name, expanded it should be an + * entry with objectclass group* and we test to see if odn is one of + * the values in the attribute uniquegroup + * */ + Debug( LDAP_DEBUG_ARGS, "<= check a_group: %s\n", b->a_group, 0, 0); + Debug( LDAP_DEBUG_ARGS, "<= check a_group: odn: %s\n", odn, 0, 0); + /* see if asker is listed in dnattr */ + + string_expand(buf, 512, b->a_group, edn, matches); + + if (be_group(be, buf, odn) == 0) { + + Debug( LDAP_DEBUG_ACL, + "<= acl: matched by clause #%d (group) access granted\n",i, 0, 0 ); + if ( odn ) free( odn ); + return( (b->a_access & ~ACL_SELF) >= access ); + } + } +#endif } if ( odn ) free( odn ); @@ -316,14 +444,32 @@ acl_check_mods( { int i; struct acl *a; + char *edn; + + edn = dn_normalize_case( strdup( e->e_dn ) ); for ( ; mods != NULL; mods = mods->mod_next ) { + +#ifdef USEREGEX + regmatch_t matches[MAXREMATCHES]; +#endif + + /* the lastmod attributes are ignored by ACL checking */ if ( strcasecmp( mods->mod_type, "modifiersname" ) == 0 || - strcasecmp( mods->mod_type, "modifytimestamp" ) == 0 ) { - continue; + strcasecmp( mods->mod_type, "modifytimestamp" ) == 0 || + strcasecmp( mods->mod_type, "creatorsname" ) == 0 || + strcasecmp( mods->mod_type, "createtimestamp" ) == 0 + ) + { + Debug( LDAP_DEBUG_ACL, "LASTMOD attribute: %s access allowed\n", mods->mod_type, 0, 0 ); + continue; } - a = acl_get_applicable( be, op, e, mods->mod_type ); +#ifdef USEREGEX + a = acl_get_applicable( be, op, e, mods->mod_type, edn, MAXREMATCHES, matches ); +#else + a = acl_get_applicable( be, op, e, mods->mod_type, edn ); +#endif switch ( mods->mod_op & ~LDAP_MOD_BVALUES ) { case LDAP_MOD_REPLACE: @@ -332,8 +478,15 @@ acl_check_mods( break; } for ( i = 0; mods->mod_bvalues[i] != NULL; i++ ) { - if ( ! acl_access_allowed( a, be, conn, e, - mods->mod_bvalues[i], op, ACL_WRITE ) ) { +#ifdef USEREGEX + if ( ! acl_access_allowed( a, be, conn, e, mods->mod_bvalues[i], + op, ACL_WRITE, edn, matches) ) +#else + if ( ! acl_access_allowed( a, be, conn, e, mods->mod_bvalues[i], + op, ACL_WRITE, edn ) ) +#endif + { + free(edn); return( LDAP_INSUFFICIENT_ACCESS ); } } @@ -341,15 +494,29 @@ acl_check_mods( case LDAP_MOD_DELETE: if ( mods->mod_bvalues == NULL ) { +#ifdef USEREGEX if ( ! acl_access_allowed( a, be, conn, e, - NULL, op, ACL_WRITE ) ) { + NULL, op, ACL_WRITE, edn, matches) ) +#else + if ( ! acl_access_allowed( a, be, conn, e, + NULL, op, ACL_WRITE, edn ) ) +#endif + { + free(edn); return( LDAP_INSUFFICIENT_ACCESS ); } break; } for ( i = 0; mods->mod_bvalues[i] != NULL; i++ ) { - if ( ! acl_access_allowed( a, be, conn, e, - mods->mod_bvalues[i], op, ACL_WRITE ) ) { +#ifdef USEREGEX + if ( ! acl_access_allowed( a, be, conn, e, mods->mod_bvalues[i], + op, ACL_WRITE, edn, matches) ) +#else + if ( ! acl_access_allowed( a, be, conn, e, mods->mod_bvalues[i], + op, ACL_WRITE, edn ) ) +#endif + { + free(edn); return( LDAP_INSUFFICIENT_ACCESS ); } } @@ -357,9 +524,95 @@ acl_check_mods( } } + free(edn); return( LDAP_SUCCESS ); } +#ifdef USEREGEX +static string_expand(char *newbuf, int bufsiz, char *pat, char *match, regmatch_t *matches) +{ + int size; + char *sp; + char *dp; + int flag; + + size = 0; + newbuf[0] = '\0'; + + flag = 0; + for ( dp = newbuf, sp = pat; size < 512 && *sp ; sp++) { + /* did we previously see a $ */ + if (flag) { + if (*sp == '$') { + *dp++ = '$'; + size++; + } + else if (*sp >= '0' && *sp <= '9' ) { + int n; + int i; + char *ep; + int l; + n = *sp - '0'; + *dp = '\0'; + i = matches[n].rm_so; + l = matches[n].rm_eo; + for ( ; size < 512 && i < l; size++, i++ ) { + *dp++ = match[i]; + size++; + } + *dp = '\0'; + } + flag = 0; + } + else { + if (*sp == '$') + flag = 1; + else { + *dp++ = *sp; + size++; + } + } + } + *dp = '\0'; + Debug( LDAP_DEBUG_TRACE, "=> string_expand: pattern: %s\n", pat, 0, 0 ); + Debug( LDAP_DEBUG_TRACE, "=> string_expand: expanded: %s\n", newbuf, 0, 0 ); +} + +static int +regex_matches( + char *pat, /* pattern to expand and match against */ + char *str, /* string to match against pattern */ + char *buf, /* buffer with $N expansion variables */ + regmatch_t matches[] /* offsets in buffer for $N expansion variables */ + ) +{ + regex_t re; + char newbuf[512]; + int rc; + + string_expand(newbuf, 512, pat, buf, matches); + + if (( rc = regcomp(&re, newbuf, REG_EXTENDED|REG_ICASE))) { + + char error[512]; + + regerror(rc, &re, error, sizeof(error)); + + Debug( LDAP_DEBUG_ANY, + "compile( \"%s\", \"%s\") failed %s\n", pat, str, error ); + return( 0 ); + } + + rc = regexec(&re, str, 0, NULL, 0); + regfree( &re ); + + Debug( LDAP_DEBUG_ARGS, "=> regex_matches: string: %s\n", str, 0, 0 ); + Debug( LDAP_DEBUG_ARGS, "=> regex_matches: rc: %d %s\n", rc, !rc?"matched":"no match", 0 ); + + return( !rc ); +} + +#else #ifdef sunos5 static int @@ -402,3 +655,4 @@ regex_matches( char *pat, char *str ) } #endif /* sunos5 */ +#endif diff --git a/servers/slapd/aclparse.c b/servers/slapd/aclparse.c index 10fa6a0721..ac48963a54 100644 --- a/servers/slapd/aclparse.c +++ b/servers/slapd/aclparse.c @@ -7,12 +7,19 @@ #include #include #include + +#include + +#ifdef sunos5 +#include "regexpr.h" +#else #include "regex.h" +#endif + #include "slap.h" #include "portable.h" extern Filter *str2filter(); -extern char *re_comp(); extern struct acl *global_acl; extern char **str2charray(); extern char *dn_upcase(); @@ -26,6 +33,64 @@ static void print_acl(); static void print_access(); #endif +#ifdef USEREGEX +int +regtest(char *fname, int lineno, char *pat) { + int e; + regex_t re; + + char buf[512]; + int size; + + char *sp; + char *dp; + int flag; + + sp = pat; + dp = buf; + size = 0; + buf[0] = '\0'; + + for (size = 0, flag = 0; (size < 512) && *sp; sp++) { + if (flag) { + if (*sp == '$'|| (*sp >= '0' && *sp <= '9')) { + *dp++ = *sp; + size++; + } + flag = 0; + + } else { + if (*sp == '$') { + flag = 1; + } else { + *dp++ = *sp; + size++; + } + } + } + + *dp = '\0'; + if (size >= 511) { + fprintf( stderr, + "%s: line %d: regular expression \"%s\" too large\n", + fname, lineno, pat, 0 ); + acl_usage(); + } + + if ((e = regcomp(&re, buf, REG_EXTENDED|REG_ICASE))) { + char buf[512]; + regerror(e, &re, buf, 512); + fprintf( stderr, + "%s: line %d: regular expression \"%s\" bad because of %s\n", + fname, lineno, pat, buf ); + acl_usage(); + return(0); + } + regfree(&re); + return(1); +} +#endif + void parse_acl( Backend *be, @@ -58,6 +123,19 @@ parse_acl( } if ( strcasecmp( argv[i], "*" ) == 0 ) { +#ifdef USEREGEX + int e; + if ((e = regcomp( &a->acl_dnre, ".*", + REG_EXTENDED|REG_ICASE))) + { + char buf[512]; + regerror(e, &a->acl_dnre, buf, 512); + fprintf( stderr, + "%s: line %d: regular expression \"%s\" bad because of %s\n", + fname, lineno, right, buf ); + acl_usage(); + } +#endif a->acl_dnpat = strdup( ".*" ); continue; } @@ -79,14 +157,31 @@ parse_acl( acl_usage(); } } else if ( strcasecmp( left, "dn" ) == 0 ) { +#ifdef USEREGEX + int e; + if ((e = regcomp(&a->acl_dnre, right, + REG_EXTENDED|REG_ICASE))) { + char buf[512]; + regerror(e, &a->acl_dnre, buf, 512); + fprintf( stderr, + "%s: line %d: regular expression \"%s\" bad because of %s\n", + fname, lineno, right, buf ); + acl_usage(); + + } else { + a->acl_dnpat = dn_upcase(strdup( right )); + } +#else if ( (e = re_comp( right )) != NULL ) { fprintf( stderr, - "%s: line %d: regular expression \"%s\" bad because of %s\n", - fname, lineno, right, e ); + "%s: line %d: regular expression \"%s\" bad because of %s\n", + fname, lineno, right, e ); acl_usage(); + + } else { + a->acl_dnpat = dn_upcase( strdup( right ) ); } - a->acl_dnpat = dn_upcase( strdup( - right ) ); +#endif } else if ( strncasecmp( left, "attr", 4 ) == 0 ) { char **alist; @@ -131,38 +226,65 @@ parse_acl( } else if ( strcasecmp( argv[i], "self" ) == 0 ) { b->a_dnpat = strdup( "self" ); } else if ( strcasecmp( left, "dn" ) == 0 ) { +#ifdef USEREGEX + regtest(fname, lineno, right); +#else if ( (e = re_comp( right )) != NULL ) { - fprintf( stderr, - "%s: line %d: regular expression \"%s\" bad: %s\n", + fprintf( stderr, "%s: line %d: regular expression \"%s\" bad: %s\n", fname, lineno, right, e ); acl_usage(); } +#endif b->a_dnpat = dn_upcase( strdup( right ) ); } else if ( strcasecmp( left, "dnattr" ) == 0 ) { b->a_dnattr = strdup( right ); + +#ifdef ACLGROUP + } else if ( strcasecmp( left, "group" ) + == 0 ) { + char *s; +#ifdef USEREGEX + regtest(fname, lineno, right); +#else + if ( (e = re_comp( right )) != NULL ) { + fprintf( stderr, "%s: line %d: regular expression \"%s\" bad: %s\n", + fname, lineno, right, e ); + acl_usage(); + } +#endif + b->a_group = dn_upcase(strdup( right )); +#endif } else if ( strcasecmp( left, "domain" ) == 0 ) { char *s; - +#ifdef USEREGEX + regtest(fname, lineno, right); +#else if ( (e = re_comp( right )) != NULL ) { fprintf( stderr, - "%s: line %d: regular expression \"%s\" bad: %s\n", + "%s: line %d: regular expression \"%s\" bad: %s\n", fname, lineno, right, e ); acl_usage(); } +#endif b->a_domainpat = strdup( right ); + /* normalize the domain */ for ( s = b->a_domainpat; *s; s++ ) { *s = TOLOWER( *s ); } } else if ( strcasecmp( left, "addr" ) == 0 ) { +#ifdef USEREGEX + regtest(fname, lineno, right); +#else if ( (e = re_comp( right )) != NULL ) { fprintf( stderr, - "%s: line %d: regular expression \"%s\" bad: %s\n", + "%s: line %d: regular expression \"%s\" bad: %s\n", fname, lineno, right, e ); acl_usage(); } +#endif b->a_addrpat = strdup( right ); } else { fprintf( stderr, @@ -198,16 +320,15 @@ parse_acl( /* if we have no real access clause, complain and do nothing */ if ( a == NULL ) { - fprintf( stderr, - "%s: line %d: warning: no access clause(s) specified in access line\n", + "%s: line %d: warning: no access clause(s) specified in access line\n", fname, lineno ); } else { if ( a->acl_access == NULL ) { fprintf( stderr, - "%s: line %d: warning: no by clause(s) specified in access line\n", + "%s: line %d: warning: no by clause(s) specified in access line\n", fname, lineno ); } diff --git a/servers/slapd/back-ldbm/Make-template b/servers/slapd/back-ldbm/Make-template index 51ef7a8171..748c521464 100644 --- a/servers/slapd/back-ldbm/Make-template +++ b/servers/slapd/back-ldbm/Make-template @@ -20,21 +20,21 @@ VERSIONFILE = $(LDAPSRC)/build/version SRCS = idl.c add.c search.c cache.c dbcache.c dn2id.c id2entry.c \ index.c id2children.c nextid.c abandon.c compare.c \ modify.c modrdn.c delete.c init.c config.c bind.c attr.c \ - filterindex.c unbind.c kerberos.c close.c + filterindex.c unbind.c kerberos.c close.c group.c OBJS = idl.o add.o search.o cache.o dbcache.o dn2id.o id2entry.o \ index.o id2children.o nextid.o abandon.o compare.o \ modify.o modrdn.o delete.o init.o config.o bind.o attr.o \ - filterindex.o unbind.o kerberos.o close.o + filterindex.o unbind.o kerberos.o close.o group.o INCLUDES= -I. -I.. -I$(HDIR) $(KRBINCLUDEFLAG) -DEFINES = $(DEFS) $(THREADS) +DEFINES = $(DEFS) $(LDAP_CRYPT) $(THREADS) CFLAGS = $(INCLUDES) $(THREADSINCLUDE) $(DEFINES) $(ACFLAGS) -LDFLAGS = -L$(LDIR) $(KRBLIBFLAG) +LDFLAGS = -L$(LDIR) $(KRBLIBFLAG) $(LDAP_CRYPT_LIB) all: FORCE -@echo "$(SLAPD_BACKENDS)" | grep LDAP_LDBM 2>&1 > /dev/null; \ if [ $$? = 0 ]; then \ - $(MAKE) $(MFLAGS) CC=$(CC) libback-ldbm.a; \ + $(MAKE) $(MFLAGS) CC="$(CC)" libback-ldbm.a; \ else \ echo "Include -DLDAP_LDBM in SLAPD_BACKENDS in the"; \ echo "Make-common file to build the ldbm backend"; \ @@ -72,77 +72,60 @@ links: # DO NOT DELETE THIS LINE -- mkdep uses it. # DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. -idl.o: idl.c ../slap.h ../../../include/avl.h ../../../include/lber.h -idl.o: ../../../include/ldap.h ../../../include/lthread.h -idl.o: ../../../include/ldif.h ../../../include/ldapconfig.h back-ldbm.h -idl.o: ../../../include/ldbm.h -add.o: add.c ../slap.h ../../../include/avl.h ../../../include/lber.h -add.o: ../../../include/ldap.h ../../../include/lthread.h -add.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h -search.o: search.c ../slap.h ../../../include/avl.h ../../../include/lber.h -search.o: ../../../include/ldap.h ../../../include/lthread.h -search.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h -cache.o: cache.c ../slap.h ../../../include/avl.h ../../../include/lber.h -cache.o: ../../../include/ldap.h ../../../include/lthread.h -cache.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h -dbcache.o: dbcache.c ../../../include/portable.h ../slap.h -dbcache.o: ../../../include/avl.h ../../../include/lber.h -dbcache.o: ../../../include/ldap.h ../../../include/lthread.h -dbcache.o: ../../../include/ldif.h ../../../include/ldapconfig.h back-ldbm.h -dbcache.o: ../../../include/ldbm.h -dn2id.o: dn2id.c ../slap.h ../../../include/avl.h ../../../include/lber.h -dn2id.o: ../../../include/ldap.h ../../../include/lthread.h -dn2id.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h -id2entry.o: id2entry.c ../slap.h ../../../include/avl.h ../../../include/lber.h -id2entry.o: ../../../include/ldap.h ../../../include/lthread.h -id2entry.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h -index.o: index.c ../slap.h ../../../include/avl.h ../../../include/lber.h -index.o: ../../../include/ldap.h ../../../include/lthread.h -index.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h -id2children.o: id2children.c ../slap.h ../../../include/avl.h -id2children.o: ../../../include/lber.h ../../../include/ldap.h -id2children.o: ../../../include/lthread.h ../../../include/ldif.h back-ldbm.h +idl.o: idl.c ../../../include/avl.h ../../../include/proto-lber.h +idl.o: ../../../include/proto-ldap.h ../../../include/ldif.h back-ldbm.h +add.o: add.c ../../../include/proto-lber.h ../../../include/proto-ldap.h +add.o: ../../../include/ldif.h ../../../include/ldbm.h +search.o: search.c ../../../include/proto-lber.h ../../../include/proto-ldap.h +search.o: ../../../include/ldif.h ../../../include/ldbm.h +cache.o: cache.c ../../../include/avl.h ../../../include/proto-lber.h +cache.o: ../../../include/proto-ldap.h ../../../include/ldif.h +cache.o: ../../../include/ldbm.h +dbcache.o: dbcache.c ../../../include/portable.h ../../../include/avl.h +dbcache.o: ../../../include/proto-lber.h ../../../include/proto-ldap.h +dbcache.o: ../../../include/ldif.h back-ldbm.h +dn2id.o: dn2id.c ../../../include/proto-lber.h ../../../include/proto-ldap.h +dn2id.o: ../../../include/ldif.h ../../../include/ldbm.h +id2entry.o: id2entry.c ../../../include/avl.h ../../../include/proto-lber.h +id2entry.o: ../../../include/proto-ldap.h ../../../include/ldif.h +id2entry.o: ../../../include/ldbm.h +index.o: index.c ../../../include/avl.h ../../../include/proto-lber.h +index.o: ../../../include/proto-ldap.h ../../../include/ldif.h +index.o: ../../../include/ldbm.h +id2children.o: id2children.c ../../../include/proto-lber.h +id2children.o: ../../../include/proto-ldap.h ../../../include/ldif.h id2children.o: ../../../include/ldbm.h -nextid.o: nextid.c ../slap.h ../../../include/avl.h ../../../include/lber.h -nextid.o: ../../../include/ldap.h ../../../include/lthread.h -nextid.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h +nextid.o: nextid.c ../../../include/avl.h ../../../include/proto-lber.h +nextid.o: ../../../include/proto-ldap.h ../../../include/ldif.h +nextid.o: ../../../include/ldbm.h abandon.o: abandon.c -compare.o: compare.c ../slap.h ../../../include/avl.h ../../../include/lber.h -compare.o: ../../../include/ldap.h ../../../include/lthread.h -compare.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h -modify.o: modify.c ../slap.h ../../../include/avl.h ../../../include/lber.h -modify.o: ../../../include/ldap.h ../../../include/lthread.h -modify.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h -modrdn.o: modrdn.c ../slap.h ../../../include/avl.h ../../../include/lber.h -modrdn.o: ../../../include/ldap.h ../../../include/lthread.h -modrdn.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h -delete.o: delete.c ../slap.h ../../../include/avl.h ../../../include/lber.h -delete.o: ../../../include/ldap.h ../../../include/lthread.h -delete.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h -init.o: init.c ../slap.h ../../../include/avl.h ../../../include/lber.h -init.o: ../../../include/ldap.h ../../../include/lthread.h -init.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h -config.o: config.c ../slap.h ../../../include/avl.h ../../../include/lber.h -config.o: ../../../include/ldap.h ../../../include/lthread.h -config.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h -bind.o: bind.c ../slap.h ../../../include/avl.h ../../../include/lber.h -bind.o: ../../../include/ldap.h ../../../include/lthread.h -bind.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h -attr.o: attr.c ../slap.h ../../../include/avl.h ../../../include/lber.h -attr.o: ../../../include/ldap.h ../../../include/lthread.h -attr.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h -filterindex.o: filterindex.c ../slap.h ../../../include/avl.h -filterindex.o: ../../../include/lber.h ../../../include/ldap.h -filterindex.o: ../../../include/lthread.h ../../../include/ldif.h back-ldbm.h -filterindex.o: ../../../include/ldbm.h -unbind.o: unbind.c ../slap.h ../../../include/avl.h ../../../include/lber.h -unbind.o: ../../../include/ldap.h ../../../include/lthread.h -unbind.o: ../../../include/ldif.h -kerberos.o: kerberos.c ../slap.h ../../../include/avl.h ../../../include/lber.h -kerberos.o: ../../../include/ldap.h ../../../include/lthread.h -kerberos.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h -close.o: close.c ../slap.h ../../../include/avl.h ../../../include/lber.h -close.o: ../../../include/ldap.h ../../../include/lthread.h -close.o: ../../../include/ldif.h back-ldbm.h ../../../include/ldbm.h +compare.o: compare.c ../../../include/proto-lber.h +compare.o: ../../../include/proto-ldap.h ../../../include/ldif.h +compare.o: ../../../include/ldbm.h +modify.o: modify.c ../../../include/proto-lber.h ../../../include/proto-ldap.h +modify.o: ../../../include/ldif.h ../../../include/ldbm.h +modrdn.o: modrdn.c ../../../include/proto-lber.h ../../../include/proto-ldap.h +modrdn.o: ../../../include/ldif.h ../../../include/ldbm.h +delete.o: delete.c ../../../include/proto-lber.h ../../../include/proto-ldap.h +delete.o: ../../../include/ldif.h ../../../include/ldbm.h +init.o: init.c ../../../include/proto-lber.h ../../../include/proto-ldap.h +init.o: ../../../include/ldif.h ../../../include/ldbm.h +config.o: config.c ../../../include/proto-lber.h ../../../include/proto-ldap.h +config.o: ../../../include/ldif.h ../../../include/ldbm.h +bind.o: bind.c ../../../include/proto-lber.h ../../../include/proto-ldap.h +bind.o: ../../../include/ldif.h ../../../include/ldbm.h +attr.o: attr.c ../../../include/proto-lber.h ../../../include/proto-ldap.h +attr.o: ../../../include/ldif.h ../../../include/ldbm.h +filterindex.o: filterindex.c ../../../include/avl.h +filterindex.o: ../../../include/proto-lber.h ../../../include/proto-ldap.h +filterindex.o: ../../../include/ldif.h ../../../include/ldbm.h +unbind.o: unbind.c ../../../include/avl.h ../../../include/proto-lber.h +unbind.o: ../../../include/proto-ldap.h ../../../include/ldif.h +kerberos.o: kerberos.c ../../../include/proto-lber.h +kerberos.o: ../../../include/proto-ldap.h ../../../include/ldif.h +kerberos.o: ../../../include/ldbm.h +close.o: close.c ../../../include/avl.h ../../../include/proto-lber.h +close.o: ../../../include/proto-ldap.h ../../../include/ldif.h +close.o: ../../../include/ldbm.h # IF YOU PUT ANYTHING HERE IT WILL GO AWAY diff --git a/servers/slapd/backend.c b/servers/slapd/backend.c index 998bfa8c6a..c0e32b12d1 100644 --- a/servers/slapd/backend.c +++ b/servers/slapd/backend.c @@ -21,6 +21,7 @@ extern int ldbm_back_abandon(); extern int ldbm_back_config(); extern int ldbm_back_init(); extern int ldbm_back_close(); +extern int ldbm_back_group(); #endif #ifdef LDAP_PASSWD @@ -86,6 +87,9 @@ new_backend( be->be_config = ldbm_back_config; be->be_init = ldbm_back_init; be->be_close = ldbm_back_close; +#ifdef ACLGROUP + be->be_group = ldbm_back_group; +#endif be->be_type = "ldbm"; foundit = 1; } @@ -105,6 +109,9 @@ new_backend( be->be_config = passwd_back_config; be->be_init = NULL; be->be_close = NULL; +#ifdef ACLGROUP + be->be_group = NULL; +#endif be->be_type = "passwd"; foundit = 1; } @@ -124,6 +131,9 @@ new_backend( be->be_config = shell_back_config; be->be_init = shell_back_init; be->be_close = NULL; +#ifdef ACLGROUP + be->be_group = NULL; +#endif be->be_type = "shell"; foundit = 1; } @@ -231,3 +241,14 @@ be_unbind( } } } + +#ifdef ACLGROUP +int +be_group(Backend *be, char *bdn, char *edn) +{ + if (be->be_group) + return(be->be_group(be, bdn, edn)); + else + return(1); +} +#endif diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index a1ff6e5e75..98faf2faaa 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -7,10 +7,19 @@ int access_allowed( Backend *be, Connection *conn, Operation *op, Entry *e, char *attr, struct berval *val, char *dn, int access ); + +#ifdef USEREGEX +struct acl * acl_get_applicable( Backend *be, Operation *op, Entry *e, + char *attr, char *edn, int nmatches, regmatch_t matches[] ); +int acl_access_allowed( struct acl *a, Backend *be, Connection *conn, Entry *e, + struct berval *val, Operation *op, int access, char *edn, regmatch_t matches[] ); +#else struct acl * acl_get_applicable( Backend *be, Operation *op, Entry *e, - char *attr ); + char *attr, char *edn ); int acl_access_allowed( struct acl *a, Backend *be, Connection *conn, Entry *e, - struct berval *val, Operation *op, int access ); + struct berval *val, Operation *op, int access, char *edn ); +#endif + int acl_check_mods( Backend *be, Connection *conn, Operation *op, Entry *e, LDAPMod *mods ); diff --git a/servers/slapd/result.c b/servers/slapd/result.c index 0ef82a7b3e..1e761f2649 100644 --- a/servers/slapd/result.c +++ b/servers/slapd/result.c @@ -121,7 +121,13 @@ send_ldap_result2( pthread_mutex_lock( &active_threads_mutex ); active_threads--; conn->c_writewaiter = 1; + +#ifdef SIGSTKFLT + pthread_kill( listener_tid, SIGSTKFLT ); +#else pthread_kill( listener_tid, SIGUSR1 ); +#endif + pthread_cond_wait( &conn->c_wcv, &active_threads_mutex ); pthread_mutex_unlock( &active_threads_mutex ); @@ -192,6 +198,9 @@ send_search_entry( Attribute *a; int i, rc, bytes, sd; struct acl *acl; + char *edn; + + Debug( LDAP_DEBUG_TRACE, "=> send_search_entry (%s)\n", e->e_dn, 0, 0 ); @@ -202,15 +211,18 @@ send_search_entry( return( 1 ); } + edn = dn_normalize_case( strdup( e->e_dn ) ); + #ifdef COMPAT30 if ( (ber = ber_alloc_t( conn->c_version == 30 ? 0 : LBER_USE_DER )) - == NULLBER ) { + == NULLBER ) { #else if ( (ber = der_alloc()) == NULLBER ) { #endif Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 ); send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, - "ber_alloc" ); + "ber_alloc" ); + free(edn); return( 1 ); } @@ -220,26 +232,53 @@ send_search_entry( LDAP_RES_SEARCH_ENTRY, e->e_dn ); } else #endif - rc = ber_printf( ber, "{it{s{", op->o_msgid, - LDAP_RES_SEARCH_ENTRY, e->e_dn ); + rc = ber_printf( ber, "{it{s{", op->o_msgid, + LDAP_RES_SEARCH_ENTRY, e->e_dn ); if ( rc == -1 ) { Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 ); ber_free( ber, 1 ); send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, "ber_printf dn" ); + free(edn); return( 1 ); } for ( a = e->e_attrs; a != NULL; a = a->a_next ) { +#ifdef USEREGEX + regmatch_t matches[MAXREMATCHES]; +#endif + if ( attrs != NULL && ! charray_inlist( attrs, a->a_type ) ) { continue; } - acl = acl_get_applicable( be, op, e, a->a_type ); +#ifdef USEREGEX + /* the lastmod attributes are ignored by ACL checking */ + if ( strcasecmp( a->a_type, "modifiersname" ) == 0 || + strcasecmp( a->a_type, "modifytimestamp" ) == 0 || + strcasecmp( a->a_type, "creatorsname" ) == 0 || + strcasecmp( a->a_type, "createtimestamp" ) == 0 ) + { + Debug( LDAP_DEBUG_ACL, "LASTMOD attribute: %s access DEFAULT\n", + a->a_type, 0, 0 ); + acl = NULL; + } else { + acl = acl_get_applicable( be, op, e, a->a_type, edn, + MAXREMATCHES, matches ); + } +#else + acl= acl_get_applicable( be, op, e, a->a_type, edn ); +#endif - if ( ! acl_access_allowed( acl, be, conn, e, NULL, op, - ACL_READ ) ) { +#ifdef USEREGEX + if ( ! acl_access_allowed( acl, be, conn, e, NULL, op, ACL_READ, + edn, matches ) ) +#else + if ( ! acl_access_allowed( acl, be, conn, e, NULL, op, ACL_READ, + edn ) ) +#endif + { continue; } @@ -248,14 +287,21 @@ send_search_entry( ber_free( ber, 1 ); send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, "ber_printf type" ); + free(edn); return( 1 ); } if ( ! attrsonly ) { for ( i = 0; a->a_vals[i] != NULL; i++ ) { - if ( a->a_syntax & SYNTAX_DN && - ! acl_access_allowed( acl, be, conn, e, - a->a_vals[i], op, ACL_READ ) ) +#ifdef USEREGEX + if ( a->a_syntax & SYNTAX_DN && + ! acl_access_allowed( acl, be, conn, e, a->a_vals[i], op, + ACL_READ, edn, matches) ) +#else + if ( a->a_syntax & SYNTAX_DN && + ! acl_access_allowed( acl, be, conn, e, a->a_vals[i], op, + ACL_READ, edn ) ) +#endif { continue; } @@ -270,6 +316,7 @@ send_search_entry( send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, "ber_printf value" ); + free(edn); return( 1 ); } } @@ -280,10 +327,13 @@ send_search_entry( ber_free( ber, 1 ); send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, "ber_printf type end" ); + free(edn); return( 1 ); } } + free(edn); + #ifdef COMPAT30 if ( conn->c_version == 30 ) { rc = ber_printf( ber, "}}}}" ); diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index a67e567cbe..ebdb2d6c43 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -6,6 +6,11 @@ #define LDAP_SYSLOG #include + +#ifdef USEREGEX +#include +#endif + #include "avl.h" #include "lber.h" #include "ldap.h" @@ -122,6 +127,9 @@ struct access { char *a_domainpat; char *a_dnattr; long a_access; +#ifdef USEREGEX + char *a_group; +#endif #define ACL_NONE 0x01 #define ACL_COMPARE 0x02 #define ACL_SEARCH 0x04 @@ -135,6 +143,9 @@ struct access { struct acl { /* "to" part: the entries this acl applies to */ Filter *acl_filter; +#ifdef USEREGEX + regex_t acl_dnre; +#endif char *acl_dnpat; char **acl_attrs; @@ -188,6 +199,10 @@ typedef struct backend { IFP be_config; /* backend config routine */ IFP be_init; /* backend init routine */ IFP be_close; /* backend close routine */ + +#ifdef ACLGROUP + IFP be_group; /* backend group member test */ +#endif } Backend; /*