From 3705a26f2d003cc3126ef9e2d9df9a7dca75aa3c Mon Sep 17 00:00:00 2001 From: Mark Valence Date: Thu, 29 Jun 2000 22:02:15 +0000 Subject: [PATCH] Add support for Set ACLs and ACIs. Still need to make this syntax awa re. --- servers/slapd/Makefile.in | 4 +- servers/slapd/acl.c | 141 ++++++++++++ servers/slapd/sets.c | 387 ++++++++++++++++++++++++++++++++ servers/slapd/sets.h | 18 ++ servers/slapd/tools/Makefile.in | 2 +- 5 files changed, 549 insertions(+), 3 deletions(-) create mode 100644 servers/slapd/sets.c create mode 100644 servers/slapd/sets.h diff --git a/servers/slapd/Makefile.in b/servers/slapd/Makefile.in index c3915e37a0..c27ebbd315 100644 --- a/servers/slapd/Makefile.in +++ b/servers/slapd/Makefile.in @@ -17,7 +17,7 @@ SRCS = main.c daemon.c connection.c search.c filter.c add.c charray.c \ repl.c lock.c controls.c extended.c kerberos.c passwd.c \ schema.c schema_check.c schema_init.c schema_prep.c \ schemaparse.c ad.c at.c mr.c syntax.c oc.c \ - monitor.c configinfo.c starttls.c index.c \ + monitor.c configinfo.c starttls.c index.c sets.c\ root_dse.c sasl.c module.c suffixalias.c $(@PLAT@_SRCS) OBJS = main.o daemon.o connection.o search.o filter.o add.o charray.o \ @@ -28,7 +28,7 @@ OBJS = main.o daemon.o connection.o search.o filter.o add.o charray.o \ repl.o lock.o controls.o extended.o kerberos.o passwd.o \ schema.o schema_check.o schema_init.o schema_prep.o \ schemaparse.o ad.o at.o mr.o syntax.o oc.o \ - monitor.o configinfo.o starttls.o index.o \ + monitor.o configinfo.o starttls.o index.o sets.o\ root_dse.o sasl.o module.o suffixalias.o $(@PLAT@_OBJS) LDAP_INCDIR= ../../include diff --git a/servers/slapd/acl.c b/servers/slapd/acl.c index ea08d0bdda..3efffe79be 100644 --- a/servers/slapd/acl.c +++ b/servers/slapd/acl.c @@ -14,6 +14,7 @@ #include #include "slap.h" +#include "sets.h" static AccessControl * acl_get( AccessControl *ac, int *count, @@ -50,6 +51,9 @@ static void string_expand( char *newbuf, int bufsiz, char *pattern, char *match, regmatch_t *matches); +char **aci_set_gather (void *cookie, char *name, char *attr); +static int aci_match_set ( struct berval *subj, Backend *be, + Entry *e, Connection *conn, Operation *op, int setref ); /* * access_allowed - check whether op->o_ndn is allowed the requested access @@ -620,6 +624,16 @@ acl_mask( } } + if ( b->a_set_pat != NULL ) { + struct berval bv; + + bv.bv_val = b->a_set_pat; + bv.bv_len = strlen(b->a_set_pat); + if (aci_match_set( &bv, be, e, conn, op, 0 ) == 0) { + continue; + } + } + #ifdef SLAPD_ACI_ENABLED if ( b->a_aci_at != NULL ) { Attribute *at; @@ -1149,6 +1163,125 @@ done: return(rc); } +char ** +aci_set_gather (void *cookie, char *name, char *attr) +{ + struct { + Backend *be; + Entry *e; + Connection *conn; + Operation *op; + } *cp = (void *)cookie; + struct berval **bvals = NULL; + char **vals = NULL; + char *ndn; + int i; + + /* this routine needs to return the bervals instead of + * plain strings, since syntax is not known. It should + * also return the syntax or some "comparison cookie". + */ + + if ((ndn = ch_strdup(name)) != NULL) { + if (dn_normalize(ndn) != NULL) { + char *text; + AttributeDescription *desc = NULL; + if (slap_str2ad(attr, &desc, &text) == 0) { + backend_attribute(cp->be, NULL /*cp->conn*/, + NULL /*cp->op*/, cp->e, + ndn, desc, &bvals); + if (bvals != NULL) { + for (i = 0; bvals[i] != NULL; i++) { } + vals = ch_calloc(i + 1, sizeof(char *)); + if (vals != NULL) { + while (--i >= 0) { + vals[i] = bvals[i]->bv_val; + bvals[i]->bv_val = NULL; + } + } + ber_bvecfree(bvals); + } + ad_free(desc, 1); + } + } + ch_free(ndn); + } + return(vals); +} + +static int +aci_match_set ( + struct berval *subj, + Backend *be, + Entry *e, + Connection *conn, + Operation *op, + int setref +) +{ + char *set = NULL; + int rc = 0; + struct { + Backend *be; + Entry *e; + Connection *conn; + Operation *op; + } cookie; + + if (setref == 0) { + set = aci_bvstrdup(subj); + } else { + struct berval bv; + char *subjdn; + char *setat; + struct berval **bvals; + char *text; + AttributeDescription *desc = NULL; + + /* format of string is "entry/setAttrName" */ + if (aci_get_part(subj, 0, '/', &bv) < 0) { + return(0); + } + + subjdn = aci_bvstrdup(&bv); + if ( subjdn == NULL ) { + return(0); + } + + if ( aci_get_part(subj, 1, '/', &bv) < 0 ) { + setat = ch_strdup( SLAPD_ACI_SET_ATTR ); + } else { + setat = aci_bvstrdup(&bv); + } + if ( setat != NULL ) { + if ( dn_normalize(subjdn) != NULL + && slap_str2ad(setat, &desc, &text) == 0 ) + { + backend_attribute(be, NULL, NULL, e, + subjdn, desc, &bvals); + ad_free(desc, 1); + if ( bvals != NULL ) { + if ( bvals[0] != NULL ) + set = ch_strdup(bvals[0]->bv_val); + ber_bvecfree(bvals); + } + } + ch_free(setat); + } + ch_free(subjdn); + } + + if (set != NULL) { + cookie.be = be; + cookie.e = e; + cookie.conn = conn; + cookie.op = op; + rc = (set_filter(aci_set_gather, &cookie, set, op->o_ndn, e->e_ndn, NULL) > 0); + ch_free(set); + } + return(rc); +} + static int aci_mask( Backend *be, @@ -1263,6 +1396,14 @@ aci_mask( if (aci_group_member(&sdn, SLAPD_ROLE_CLASS, SLAPD_ROLE_ATTR, be, e, op, matches)) return(1); + } else if (aci_strbvcmp( "set", &bv ) == 0) { + if (aci_match_set(&sdn, be, e, conn, op, 0)) + return(1); + + } else if (aci_strbvcmp( "set-ref", &bv ) == 0) { + if (aci_match_set(&sdn, be, e, conn, op, 1)) + return(1); + } return(0); diff --git a/servers/slapd/sets.c b/servers/slapd/sets.c new file mode 100644 index 0000000000..622249377d --- /dev/null +++ b/servers/slapd/sets.c @@ -0,0 +1,387 @@ +/* $OpenLDAP$ */ +/* + * Copyright 2000 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" +#include + +#include "sets.h" + +static char **set_join (char **lset, int op, char **rset); +static char **set_chase (SET_GATHER gatherer, void *cookie, char **set, char *attr, int attrlen, int closure); +static int set_samedn (char *dn1, char *dn2); + +long +set_size (char **set) +{ + int i; + + i = 0; + if (set != NULL) { + while (set[i]) + i++; + } + return(i); +} + +void +set_dispose (char **set) +{ + int i; + + if (set != NULL) { + for (i = 0; set[i]; i++) + ch_free(set[i]); + ch_free(set); + } +} + +static char ** +set_join (char **lset, int op, char **rset) +{ + char **set; + long i, j, last; + + set = NULL; + if (op == '|') { + if (lset == NULL || *lset == NULL) { + if (rset == NULL) { + if (lset == NULL) + return(ch_calloc(1, sizeof(char *))); + return(lset); + } + set_dispose(lset); + return(rset); + } + if (rset == NULL || *rset == NULL) { + set_dispose(rset); + return(lset); + } + + i = set_size(lset) + set_size(rset) + 1; + set = ch_calloc(i, sizeof(char *)); + if (set != NULL) { + /* set_chase() depends on this routine to + * keep the first elements of the result + * set the same (and in the same order) + * as the left-set. + */ + for (i = 0; lset[i]; i++) + set[i] = lset[i]; + ch_free(lset); + for (i = 0; rset[i]; i++) { + for (j = 0; set[j]; j++) { + if (set_samedn(rset[i], set[j])) { + ch_free(rset[i]); + rset[i] = NULL; + break; + } + } + if (rset[i]) + set[j] = rset[i]; + } + ch_free(rset); + } + return(set); + } + + if (op == '&') { + if (lset == NULL || *lset == NULL || rset == NULL || *rset == NULL) { + set = ch_calloc(1, sizeof(char *)); + } else { + set = lset; + lset = NULL; + last = set_size(set) - 1; + for (i = 0; set[i]; i++) { + for (j = 0; rset[j]; j++) { + if (set_samedn(set[i], rset[j])) + break; + } + if (rset[j] == NULL) { + ch_free(set[i]); + set[i] = set[last]; + set[last] = NULL; + last--; + i--; + } + } + } + } + + set_dispose(lset); + set_dispose(rset); + return(set); +} + +static char ** +set_chase (SET_GATHER gatherer, void *cookie, char **set, char *attr, int attrlen, int closure) +{ + char **vals, **nset; + char attrstr[32]; + int i; + + if (set == NULL) + return(ch_calloc(1, sizeof(char *))); + + if (*set == NULL) + return(set); + + if (attrlen > (sizeof(attrstr) - 1)) { + set_dispose(set); + return(NULL); + } + memcpy(attrstr, attr, attrlen); + attrstr[attrlen] = 0; + + nset = ch_calloc(1, sizeof(char *)); + if (nset == NULL) { + set_dispose(set); + return(NULL); + } + for (i = 0; set[i]; i++) { + vals = (gatherer)(cookie, set[i], attrstr); + if (vals != NULL) + nset = set_join(nset, '|', vals); + } + set_dispose(set); + + if (closure) { + for (i = 0; nset[i]; i++) { + vals = (gatherer)(cookie, nset[i], attrstr); + if (vals != NULL) { + nset = set_join(nset, '|', vals); + if (nset == NULL) + break; + } + } + } + return(nset); +} + +static int +set_samedn (char *dn1, char *dn2) +{ + char c1, c2; + + while (*dn1 == ' ') dn1++; + while (*dn2 == ' ') dn2++; + while (*dn1 || *dn2) { + if (*dn1 != '=' && *dn1 != ',' + && *dn2 != '=' && *dn2 != ',') + { + c1 = *dn1++; + c2 = *dn2++; + if (c1 >= 'a' && c1 <= 'z') + c1 -= 'a' - 'A'; + if (c2 >= 'a' && c2 <= 'z') + c2 -= 'a' - 'A'; + if (c1 != c2) + return(0); + } else { + while (*dn1 == ' ') dn1++; + while (*dn2 == ' ') dn2++; + if (*dn1++ != *dn2++) + return(0); + while (*dn1 == ' ') dn1++; + while (*dn2 == ' ') dn2++; + } + } + return(1); +} + +int +set_filter (SET_GATHER gatherer, void *cookie, char *filter, char *user, char *this, char ***results) +{ + #define IS_SET(x) ( (long)(x) >= 256 ) + #define IS_OP(x) ( (long)(x) < 256 ) + #define SF_ERROR(x) { rc = -1; goto _error; } + #define SF_TOP() (char **)( (stp < 0) ? 0 : stack[stp] ) + #define SF_POP() (char **)( (stp < 0) ? 0 : stack[stp--] ) + #define SF_PUSH(x) { if (stp >= 63) SF_ERROR(overflow); stack[++stp] = (char **)(long)(x); } + char c; + char **set, **lset; + int len, op, rc, stp; + char **stack[64]; + + if (results) + *results = NULL; + + stp = -1; + while (c = *filter++) { + set = NULL; + switch (c) { + case ' ': + case '\t': + case '\x0A': + case '\x0D': + break; + + case '(': + if (IS_SET(SF_TOP())) + SF_ERROR(syntax); + SF_PUSH(c); + break; + + case ')': + set = SF_POP(); + if (IS_OP(set)) + SF_ERROR(syntax); + if (SF_TOP() == (void *)'(') { + SF_POP(); + SF_PUSH(set); + set = NULL; + } else if (IS_OP(SF_TOP())) { + op = (long)SF_POP(); + lset = SF_POP(); + SF_POP(); + set = set_join(lset, op, set); + if (set == NULL) + SF_ERROR(memory); + SF_PUSH(set); + set = NULL; + } else { + SF_ERROR(syntax); + } + break; + + case '&': + case '|': + set = SF_POP(); + if (IS_OP(set)) + SF_ERROR(syntax); + if (SF_TOP() == 0 || SF_TOP() == (void *)'(') { + SF_PUSH(set); + set = NULL; + } else if (IS_OP(SF_TOP())) { + op = (long)SF_POP(); + lset = SF_POP(); + set = set_join(lset, op, set); + if (set == NULL) + SF_ERROR(memory); + SF_PUSH(set); + set = NULL; + } else { + SF_ERROR(syntax); + } + SF_PUSH(c); + break; + + case '[': + if ((SF_TOP() == (void *)'/') || IS_SET(SF_TOP())) + SF_ERROR(syntax); + for ( len = 0; + (c = *filter++) && (c != ']'); + len++) + { } + if (c == 0) + SF_ERROR(syntax); + + set = ch_calloc(2, sizeof(char *)); + if (set == NULL) + SF_ERROR(memory); + *set = ch_calloc(len + 1, sizeof(char)); + if (*set == NULL) + SF_ERROR(memory); + memcpy(*set, &filter[-len - 1], len); + SF_PUSH(set); + set = NULL; + break; + + case '-': + c = *filter++; + if (c != '>') + SF_ERROR(syntax); + /* fall through to next case */ + + case '/': + if (IS_OP(SF_TOP())) + SF_ERROR(syntax); + SF_PUSH('/'); + break; + + default: + if ((c != '_') + && (c < 'A' || c > 'Z') + && (c < 'a' || c > 'z')) + { + SF_ERROR(syntax); + } + filter--; + for ( len = 1; + (c = filter[len]) + && ((c >= '0' && c <= '9') + || (c >= 'A' && c <= 'Z') + || (c >= 'a' && c <= 'z')); + len++) + { } + if (len == 4 + && memcmp("this", filter, len) == 0) + { + if ((SF_TOP() == (void *)'/') || IS_SET(SF_TOP())) + SF_ERROR(syntax); + set = ch_calloc(2, sizeof(char *)); + if (set == NULL) + SF_ERROR(memory); + *set = ch_strdup(this); + if (*set == NULL) + SF_ERROR(memory); + } else if (len == 4 + && memcmp("user", filter, len) == 0) + { + if ((SF_TOP() == (void *)'/') || IS_SET(SF_TOP())) + SF_ERROR(syntax); + set = ch_calloc(2, sizeof(char *)); + if (set == NULL) + SF_ERROR(memory); + *set = ch_strdup(user); + if (*set == NULL) + SF_ERROR(memory); + } else if (SF_TOP() != (void *)'/') { + SF_ERROR(syntax); + } else { + SF_POP(); + set = set_chase(gatherer, cookie, SF_POP(), filter, len, c == '*'); + if (set == NULL) + SF_ERROR(memory); + if (c == '*') + len++; + } + filter += len; + SF_PUSH(set); + set = NULL; + break; + } + } + + set = SF_POP(); + if (IS_OP(set)) + SF_ERROR(syntax); + if (SF_TOP() == 0) { + + } else if (IS_OP(SF_TOP())) { + op = (long)SF_POP(); + lset = SF_POP(); + set = set_join(lset, op, set); + if (set == NULL) + SF_ERROR(memory); + } else { + SF_ERROR(syntax); + } + + rc = set_size(set); + if (results) { + *results = set; + set = NULL; + } + +_error: + if (IS_SET(set)) + set_dispose(set); + while (set = SF_POP()) { + if (IS_SET(set)) + set_dispose(set); + } + return(rc); +} diff --git a/servers/slapd/sets.h b/servers/slapd/sets.h new file mode 100644 index 0000000000..134707fe5e --- /dev/null +++ b/servers/slapd/sets.h @@ -0,0 +1,18 @@ +/* $OpenLDAP$ */ +/* + * Copyright 2000 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +/* this routine needs to return the bervals instead of + * plain strings, since syntax is not known. It should + * also return the syntax or some "comparison cookie" + * that is used by set_filter. + */ +typedef char **(*SET_GATHER) (void *cookie, char *name, char *attr); + +long set_size (char **set); +void set_dispose (char **set); + +int set_filter (SET_GATHER gatherer, void *cookie, char *filter, char *user, char *this, char ***results); + diff --git a/servers/slapd/tools/Makefile.in b/servers/slapd/tools/Makefile.in index 308bf9ed76..fad33e3883 100644 --- a/servers/slapd/tools/Makefile.in +++ b/servers/slapd/tools/Makefile.in @@ -47,7 +47,7 @@ SLAPD_OBJS = ../config.o ../ch_malloc.o ../backend.o ../charray.o \ ../acl.o ../phonetic.o ../attr.o ../value.o ../entry.o \ ../dn.o ../filter.o ../str2filter.o ../ava.o ../init.o \ ../controls.o ../kerberos.o ../passwd.o ../index.o \ - ../extended.o ../starttls.o + ../extended.o ../starttls.o ../sets.o SLAPOBJS = $(SLAPD_OBJS) slapcommon.o mimic.o -- 2.39.5