/* aclparse.c - routines to parse and check acl's */ /* $OpenLDAP$ */ /* * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. * COPYING RESTRICTIONS APPLY, see COPYRIGHT file */ #include "portable.h" #include #include #include #include #include #include #include "slap.h" #include "lber_pvt.h" #include "lutil.h" static void split(char *line, int splitchar, char **left, char **right); static void access_append(Access **l, Access *a); static void acl_usage(void) LDAP_GCCATTR((noreturn)); static void acl_regex_normalized_dn(const char *src, struct berval *pat); #ifdef LDAP_DEBUG static void print_acl(Backend *be, AccessControl *a); static void print_access(Access *b); #endif static void regtest(const char *fname, int lineno, char *pat) { int e; regex_t re; char buf[512]; unsigned size; char *sp; char *dp; int flag; sp = pat; dp = buf; size = 0; buf[0] = '\0'; for (size = 0, flag = 0; (size < sizeof(buf)) && *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 >= (sizeof(buf)-1) ) { fprintf( stderr, "%s: line %d: regular expression \"%s\" too large\n", fname, lineno, pat ); acl_usage(); } if ((e = regcomp(&re, buf, REG_EXTENDED|REG_ICASE))) { char error[512]; regerror(e, &re, error, sizeof(error)); fprintf( stderr, "%s: line %d: regular expression \"%s\" bad because of %s\n", fname, lineno, pat, error ); acl_usage(); } regfree(&re); } void parse_acl( Backend *be, const char *fname, int lineno, int argc, char **argv ) { int i; char *left, *right, *style; struct berval bv; AccessControl *a; Access *b; int rc; const char *text; a = NULL; for ( i = 1; i < argc; i++ ) { /* to clause - select which entries are protected */ if ( strcasecmp( argv[i], "to" ) == 0 ) { if ( a != NULL ) { fprintf( stderr, "%s: line %d: only one to clause allowed in access line\n", fname, lineno ); acl_usage(); } a = (AccessControl *) ch_calloc( 1, sizeof(AccessControl) ); for ( ++i; i < argc; i++ ) { if ( strcasecmp( argv[i], "by" ) == 0 ) { i--; break; } if ( strcasecmp( argv[i], "*" ) == 0 ) { if( a->acl_dn_pat.bv_len || ( a->acl_dn_style != ACL_STYLE_REGEX ) ) { fprintf( stderr, "%s: line %d: dn pattern" " already specified in to clause.\n", fname, lineno ); acl_usage(); } a->acl_dn_pat.bv_val = ch_strdup( "*" ); a->acl_dn_pat.bv_len = 1; continue; } split( argv[i], '=', &left, &right ); split( left, '.', &left, &style ); if ( right == NULL ) { fprintf( stderr, "%s: line %d: missing \"=\" in \"%s\" in to clause\n", fname, lineno, left ); acl_usage(); } if ( strcasecmp( left, "dn" ) == 0 ) { if( a->acl_dn_pat.bv_len != 0 || ( a->acl_dn_style != ACL_STYLE_REGEX ) ) { fprintf( stderr, "%s: line %d: dn pattern" " already specified in to clause.\n", fname, lineno ); acl_usage(); } if ( style == NULL || *style == '\0' || strcasecmp( style, "regex" ) == 0 ) { a->acl_dn_style = ACL_STYLE_REGEX; if ( *right == '\0' ) { /* empty regex should match empty DN */ a->acl_dn_style = ACL_STYLE_BASE; ber_str2bv( right, 0, 1, &a->acl_dn_pat ); } else if ( strcmp(right, "*") == 0 || strcmp(right, ".*") == 0 || strcmp(right, ".*$") == 0 || strcmp(right, "^.*") == 0 || strcmp(right, "^.*$") == 0 || strcmp(right, ".*$$") == 0 || strcmp(right, "^.*$$") == 0 ) { a->acl_dn_pat.bv_val = ch_strdup( "*" ); a->acl_dn_pat.bv_len = sizeof("*")-1; } else { acl_regex_normalized_dn( right, &a->acl_dn_pat ); } } else if ( strcasecmp( style, "base" ) == 0 ) { a->acl_dn_style = ACL_STYLE_BASE; ber_str2bv( right, 0, 1, &a->acl_dn_pat ); } else if ( strcasecmp( style, "one" ) == 0 ) { a->acl_dn_style = ACL_STYLE_ONE; ber_str2bv( right, 0, 1, &a->acl_dn_pat ); } else if ( strcasecmp( style, "subtree" ) == 0 ) { a->acl_dn_style = ACL_STYLE_SUBTREE; ber_str2bv( right, 0, 1, &a->acl_dn_pat ); } else if ( strcasecmp( style, "children" ) == 0 ) { a->acl_dn_style = ACL_STYLE_CHILDREN; ber_str2bv( right, 0, 1, &a->acl_dn_pat ); } else { fprintf( stderr, "%s: line %d: unknown dn style \"%s\" in to clause\n", fname, lineno, style ); acl_usage(); } continue; } if ( strcasecmp( left, "filter" ) == 0 ) { if ( (a->acl_filter = str2filter( right )) == NULL ) { fprintf( stderr, "%s: line %d: bad filter \"%s\" in to clause\n", fname, lineno, right ); acl_usage(); } } else if ( strncasecmp( left, "attr", 4 ) == 0 ) { a->acl_attrs = str2anlist( a->acl_attrs, right, "," ); if ( a->acl_attrs == NULL ) { fprintf( stderr, "%s: line %d: unknown attr \"%s\" in to clause\n", fname, lineno, right ); acl_usage(); } } else { fprintf( stderr, "%s: line %d: expecting got \"%s\"\n", fname, lineno, left ); acl_usage(); } } if ( a->acl_dn_pat.bv_len != 0 && strcmp(a->acl_dn_pat.bv_val, "*") == 0 ) { free( a->acl_dn_pat.bv_val ); a->acl_dn_pat.bv_val = NULL; a->acl_dn_pat.bv_len = 0; } if( a->acl_dn_pat.bv_len != 0 || ( a->acl_dn_style != ACL_STYLE_REGEX ) ) { if ( a->acl_dn_style != ACL_STYLE_REGEX ) { struct berval bv; rc = dnNormalize2( NULL, &a->acl_dn_pat, &bv); if ( rc != LDAP_SUCCESS ) { fprintf( stderr, "%s: line %d: bad DN \"%s\"\n", fname, lineno, a->acl_dn_pat.bv_val ); acl_usage(); } free( a->acl_dn_pat.bv_val ); a->acl_dn_pat = bv; } else { int e = regcomp( &a->acl_dn_re, a->acl_dn_pat.bv_val, REG_EXTENDED | REG_ICASE ); if ( e ) { char buf[512]; regerror( e, &a->acl_dn_re, buf, sizeof(buf) ); fprintf( stderr, "%s: line %d: " "regular expression \"%s\" bad because of %s\n", fname, lineno, right, buf ); acl_usage(); } } } /* by clause - select who has what access to entries */ } else if ( strcasecmp( argv[i], "by" ) == 0 ) { if ( a == NULL ) { fprintf( stderr, "%s: line %d: to clause required before by clause in access line\n", fname, lineno ); acl_usage(); } /* * by clause consists of and */ b = (Access *) ch_calloc( 1, sizeof(Access) ); ACL_INVALIDATE( b->a_access_mask ); if ( ++i == argc ) { fprintf( stderr, "%s: line %d: premature eol: expecting \n", fname, lineno ); acl_usage(); } /* get */ for ( ; i < argc; i++ ) { slap_style_t sty = ACL_STYLE_REGEX; char *style_modifier = NULL; int expand = 0; split( argv[i], '=', &left, &right ); split( left, '.', &left, &style ); if ( style ) { split( style, ',', &style, &style_modifier); } if ( style == NULL || *style == '\0' || strcasecmp( style, "regex" ) == 0 ) { sty = ACL_STYLE_REGEX; } else if ( strcasecmp( style, "exact" ) == 0 ) { sty = ACL_STYLE_EXACT; } else if ( strcasecmp( style, "base" ) == 0 ) { sty = ACL_STYLE_BASE; } else if ( strcasecmp( style, "one" ) == 0 ) { sty = ACL_STYLE_ONE; } else if ( strcasecmp( style, "subtree" ) == 0 ) { sty = ACL_STYLE_SUBTREE; } else if ( strcasecmp( style, "children" ) == 0 ) { sty = ACL_STYLE_CHILDREN; } else { fprintf( stderr, "%s: line %d: unknown style \"%s\" in by clause\n", fname, lineno, style ); acl_usage(); } if ( style_modifier && strcasecmp( style_modifier, "expand" ) == 0 ) { expand = 1; } if ( strcasecmp( argv[i], "*" ) == 0 ) { bv.bv_val = ch_strdup( "*" ); bv.bv_len = 1; } else if ( strcasecmp( argv[i], "anonymous" ) == 0 ) { ber_str2bv("anonymous", sizeof("anonymous")-1, 1, &bv); } else if ( strcasecmp( argv[i], "self" ) == 0 ) { ber_str2bv("self", sizeof("self")-1, 1, &bv); } else if ( strcasecmp( argv[i], "users" ) == 0 ) { ber_str2bv("users", sizeof("users")-1, 1, &bv); } else if ( strcasecmp( left, "dn" ) == 0 ) { if ( sty == ACL_STYLE_REGEX ) { b->a_dn_style = ACL_STYLE_REGEX; if( right == NULL ) { /* no '=' */ ber_str2bv("users", sizeof("users")-1, 1, &bv); } else if (*right == '\0' ) { /* dn="" */ ber_str2bv("anonymous", sizeof("anonymous")-1, 1, &bv); } else if ( strcmp( right, "*" ) == 0 ) { /* dn=* */ /* any or users? users for now */ ber_str2bv("users", sizeof("users")-1, 1, &bv); } else if ( strcmp( right, ".+" ) == 0 || strcmp( right, "^.+" ) == 0 || strcmp( right, ".+$" ) == 0 || strcmp( right, "^.+$" ) == 0 || strcmp( right, ".+$$" ) == 0 || strcmp( right, "^.+$$" ) == 0 ) { ber_str2bv("users", sizeof("users")-1, 1, &bv); } else if ( strcmp( right, ".*" ) == 0 || strcmp( right, "^.*" ) == 0 || strcmp( right, ".*$" ) == 0 || strcmp( right, "^.*$" ) == 0 || strcmp( right, ".*$$" ) == 0 || strcmp( right, "^.*$$" ) == 0 ) { ber_str2bv("*", sizeof("*")-1, 1, &bv); } else { acl_regex_normalized_dn( right, &bv ); if ( !ber_bvccmp( &bv, '*' ) ) { regtest(fname, lineno, bv.bv_val); } } } else if ( right == NULL || *right == '\0' ) { fprintf( stderr, "%s: line %d: missing \"=\" in (or value after) \"%s\" in by clause\n", fname, lineno, left ); acl_usage(); } else { ber_str2bv( right, 0, 1, &bv ); } } else { bv.bv_val = NULL; } if( bv.bv_val != NULL ) { if( b->a_dn_pat.bv_len != 0 ) { fprintf( stderr, "%s: line %d: dn pattern already specified.\n", fname, lineno ); acl_usage(); } if ( sty != ACL_STYLE_REGEX && expand == 0 ) { rc = dnNormalize2(NULL, &bv, &b->a_dn_pat); if ( rc != LDAP_SUCCESS ) { fprintf( stderr, "%s: line %d: bad DN \"%s\"\n", fname, lineno, bv.bv_val ); acl_usage(); } free(bv.bv_val); } else { b->a_dn_pat = bv; } b->a_dn_style = sty; b->a_dn_expand = expand; continue; } if ( strcasecmp( left, "dnattr" ) == 0 ) { if ( right == NULL || right[ 0 ] == '\0' ) { fprintf( stderr, "%s: line %d: missing \"=\" in (or value after) \"%s\" in by clause\n", fname, lineno, left ); acl_usage(); } if( b->a_dn_at != NULL ) { fprintf( stderr, "%s: line %d: dnattr already specified.\n", fname, lineno ); acl_usage(); } rc = slap_str2ad( right, &b->a_dn_at, &text ); if( rc != LDAP_SUCCESS ) { fprintf( stderr, "%s: line %d: dnattr \"%s\": %s\n", fname, lineno, right, text ); acl_usage(); } if( !is_at_syntax( b->a_dn_at->ad_type, SLAPD_DN_SYNTAX ) && !is_at_syntax( b->a_dn_at->ad_type, SLAPD_NAMEUID_SYNTAX )) { fprintf( stderr, "%s: line %d: dnattr \"%s\": " "inappropriate syntax: %s\n", fname, lineno, right, b->a_dn_at->ad_type->sat_syntax_oid ); acl_usage(); } continue; } if ( strncasecmp( left, "group", sizeof("group")-1 ) == 0 ) { char *name = NULL; char *value = NULL; if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) { fprintf( stderr, "%s: line %d: inappropriate style \"%s\" in by clause\n", fname, lineno, style ); acl_usage(); } if ( right == NULL || right[ 0 ] == '\0' ) { fprintf( stderr, "%s: line %d: missing \"=\" in (or value after) \"%s\" in by clause\n", fname, lineno, left ); acl_usage(); } if( b->a_group_pat.bv_len ) { fprintf( stderr, "%s: line %d: group pattern already specified.\n", fname, lineno ); acl_usage(); } /* format of string is "group/objectClassValue/groupAttrName" */ if ((value = strchr(left, '/')) != NULL) { *value++ = '\0'; if (*value && (name = strchr(value, '/')) != NULL) { *name++ = '\0'; } } b->a_group_style = sty; if (sty == ACL_STYLE_REGEX) { acl_regex_normalized_dn( right, &bv ); if ( !ber_bvccmp( &bv, '*' ) ) { regtest(fname, lineno, bv.bv_val); } b->a_group_pat = bv; } else { ber_str2bv( right, 0, 0, &bv ); rc = dnNormalize2( NULL, &bv, &b->a_group_pat ); if ( rc != LDAP_SUCCESS ) { fprintf( stderr, "%s: line %d: bad DN \"%s\"\n", fname, lineno, right ); acl_usage(); } } if (value && *value) { b->a_group_oc = oc_find( value ); *--value = '/'; if( b->a_group_oc == NULL ) { fprintf( stderr, "%s: line %d: group objectclass " "\"%s\" unknown\n", fname, lineno, value ); acl_usage(); } } else { b->a_group_oc = oc_find(SLAPD_GROUP_CLASS); if( b->a_group_oc == NULL ) { fprintf( stderr, "%s: line %d: group default objectclass " "\"%s\" unknown\n", fname, lineno, SLAPD_GROUP_CLASS ); acl_usage(); } } if( is_object_subclass( slap_schema.si_oc_referral, b->a_group_oc )) { fprintf( stderr, "%s: line %d: group objectclass \"%s\" " "is subclass of referral\n", fname, lineno, value ); acl_usage(); } if( is_object_subclass( slap_schema.si_oc_alias, b->a_group_oc )) { fprintf( stderr, "%s: line %d: group objectclass \"%s\" " "is subclass of alias\n", fname, lineno, value ); acl_usage(); } if (name && *name) { rc = slap_str2ad( name, &b->a_group_at, &text ); if( rc != LDAP_SUCCESS ) { fprintf( stderr, "%s: line %d: group \"%s\": %s\n", fname, lineno, right, text ); acl_usage(); } *--name = '/'; } else { rc = slap_str2ad( SLAPD_GROUP_ATTR, &b->a_group_at, &text ); if( rc != LDAP_SUCCESS ) { fprintf( stderr, "%s: line %d: group \"%s\": %s\n", fname, lineno, SLAPD_GROUP_ATTR, text ); acl_usage(); } } if( !is_at_syntax( b->a_group_at->ad_type, SLAPD_DN_SYNTAX ) && !is_at_syntax( b->a_group_at->ad_type, SLAPD_NAMEUID_SYNTAX ) ) { fprintf( stderr, "%s: line %d: group \"%s\": inappropriate syntax: %s\n", fname, lineno, right, b->a_group_at->ad_type->sat_syntax_oid ); acl_usage(); } { int rc; struct berval vals[2]; vals[0].bv_val = b->a_group_oc->soc_oid; vals[0].bv_len = strlen(vals[0].bv_val); vals[1].bv_val = NULL; rc = oc_check_allowed( b->a_group_at->ad_type, vals, NULL ); if( rc != 0 ) { fprintf( stderr, "%s: line %d: group: \"%s\" not allowed by \"%s\"\n", fname, lineno, b->a_group_at->ad_cname.bv_val, b->a_group_oc->soc_oid ); acl_usage(); } } continue; } if ( strcasecmp( left, "peername" ) == 0 ) { if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) { fprintf( stderr, "%s: line %d: inappropriate style \"%s\" in by clause\n", fname, lineno, style ); acl_usage(); } if ( right == NULL || right[ 0 ] == '\0' ) { fprintf( stderr, "%s: line %d: missing \"=\" in (or value after) \"%s\" in by clause\n", fname, lineno, left ); acl_usage(); } if( b->a_peername_pat.bv_len ) { fprintf( stderr, "%s: line %d: peername pattern already specified.\n", fname, lineno ); acl_usage(); } b->a_peername_style = sty; if (sty == ACL_STYLE_REGEX) { acl_regex_normalized_dn( right, &bv ); if ( !ber_bvccmp( &bv, '*' ) ) { regtest(fname, lineno, bv.bv_val); } b->a_peername_pat = bv; } else { ber_str2bv( right, 0, 1, &b->a_peername_pat ); } continue; } if ( strcasecmp( left, "sockname" ) == 0 ) { if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) { fprintf( stderr, "%s: line %d: inappropriate style \"%s\" in by clause\n", fname, lineno, style ); acl_usage(); } if ( right == NULL || right[ 0 ] == '\0' ) { fprintf( stderr, "%s: line %d: missing \"=\" in (or value after) \"%s\" in by clause\n", fname, lineno, left ); acl_usage(); } if( b->a_sockname_pat.bv_len ) { fprintf( stderr, "%s: line %d: sockname pattern already specified.\n", fname, lineno ); acl_usage(); } b->a_sockname_style = sty; if (sty == ACL_STYLE_REGEX) { acl_regex_normalized_dn( right, &bv ); if ( !ber_bvccmp( &bv, '*' ) ) { regtest(fname, lineno, bv.bv_val); } b->a_sockname_pat = bv; } else { ber_str2bv( right, 0, 1, &b->a_sockname_pat ); } continue; } if ( strcasecmp( left, "domain" ) == 0 ) { switch ( sty ) { case ACL_STYLE_REGEX: case ACL_STYLE_BASE: case ACL_STYLE_SUBTREE: break; default: fprintf( stderr, "%s: line %d: inappropriate style \"%s\" in by clause\n", fname, lineno, style ); acl_usage(); } if ( right == NULL || right[ 0 ] == '\0' ) { fprintf( stderr, "%s: line %d: missing \"=\" in (or value after) \"%s\" in by clause\n", fname, lineno, left ); acl_usage(); } if( b->a_domain_pat.bv_len ) { fprintf( stderr, "%s: line %d: domain pattern already specified.\n", fname, lineno ); acl_usage(); } b->a_domain_style = sty; b->a_domain_expand = expand; if (sty == ACL_STYLE_REGEX) { acl_regex_normalized_dn( right, &bv ); if ( !ber_bvccmp( &bv, '*' ) ) { regtest(fname, lineno, bv.bv_val); } b->a_domain_pat = bv; } else { ber_str2bv( right, 0, 1, &b->a_domain_pat ); } continue; } if ( strcasecmp( left, "sockurl" ) == 0 ) { if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) { fprintf( stderr, "%s: line %d: inappropriate style \"%s\" in by clause\n", fname, lineno, style ); acl_usage(); } if ( right == NULL || right[ 0 ] == '\0' ) { fprintf( stderr, "%s: line %d: missing \"=\" in (or value after) \"%s\" in by clause\n", fname, lineno, left ); acl_usage(); } if( b->a_sockurl_pat.bv_len ) { fprintf( stderr, "%s: line %d: sockurl pattern already specified.\n", fname, lineno ); acl_usage(); } b->a_sockurl_style = sty; if (sty == ACL_STYLE_REGEX) { acl_regex_normalized_dn( right, &bv ); if ( !ber_bvccmp( &bv, '*' ) ) { regtest(fname, lineno, bv.bv_val); } b->a_sockurl_pat = bv; } else { ber_str2bv( right, 0, 1, &b->a_sockurl_pat ); } continue; } if ( strcasecmp( left, "set" ) == 0 ) { if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) { fprintf( stderr, "%s: line %d: inappropriate style \"%s\" in by clause\n", fname, lineno, style ); acl_usage(); } if( b->a_set_pat.bv_len != 0 ) { fprintf( stderr, "%s: line %d: set attribute already specified.\n", fname, lineno ); acl_usage(); } if ( right == NULL || *right == '\0' ) { fprintf( stderr, "%s: line %d: no set is defined\n", fname, lineno ); acl_usage(); } b->a_set_style = sty; ber_str2bv( right, 0, 1, &b->a_set_pat ); continue; } #ifdef SLAPD_ACI_ENABLED if ( strcasecmp( left, "aci" ) == 0 ) { if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) { fprintf( stderr, "%s: line %d: inappropriate style \"%s\" in by clause\n", fname, lineno, style ); acl_usage(); } if( b->a_aci_at != NULL ) { fprintf( stderr, "%s: line %d: aci attribute already specified.\n", fname, lineno ); acl_usage(); } if ( right != NULL && *right != '\0' ) { rc = slap_str2ad( right, &b->a_aci_at, &text ); if( rc != LDAP_SUCCESS ) { fprintf( stderr, "%s: line %d: aci \"%s\": %s\n", fname, lineno, right, text ); acl_usage(); } } else { b->a_aci_at = slap_schema.si_ad_aci; } if( !is_at_syntax( b->a_aci_at->ad_type, SLAPD_ACI_SYNTAX) ) { fprintf( stderr, "%s: line %d: aci \"%s\": inappropriate syntax: %s\n", fname, lineno, right, b->a_aci_at->ad_type->sat_syntax_oid ); acl_usage(); } continue; } #endif /* SLAPD_ACI_ENABLED */ if ( strcasecmp( left, "ssf" ) == 0 ) { if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) { fprintf( stderr, "%s: line %d: inappropriate style \"%s\" in by clause\n", fname, lineno, style ); acl_usage(); } if( b->a_authz.sai_ssf ) { fprintf( stderr, "%s: line %d: ssf attribute already specified.\n", fname, lineno ); acl_usage(); } if ( right == NULL || *right == '\0' ) { fprintf( stderr, "%s: line %d: no ssf is defined\n", fname, lineno ); acl_usage(); } b->a_authz.sai_ssf = atoi( right ); if( !b->a_authz.sai_ssf ) { fprintf( stderr, "%s: line %d: invalid ssf value (%s)\n", fname, lineno, right ); acl_usage(); } continue; } if ( strcasecmp( left, "transport_ssf" ) == 0 ) { if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) { fprintf( stderr, "%s: line %d: inappropriate style \"%s\" in by clause\n", fname, lineno, style ); acl_usage(); } if( b->a_authz.sai_transport_ssf ) { fprintf( stderr, "%s: line %d: transport_ssf attribute already specified.\n", fname, lineno ); acl_usage(); } if ( right == NULL || *right == '\0' ) { fprintf( stderr, "%s: line %d: no transport_ssf is defined\n", fname, lineno ); acl_usage(); } b->a_authz.sai_transport_ssf = atoi( right ); if( !b->a_authz.sai_transport_ssf ) { fprintf( stderr, "%s: line %d: invalid transport_ssf value (%s)\n", fname, lineno, right ); acl_usage(); } continue; } if ( strcasecmp( left, "tls_ssf" ) == 0 ) { if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) { fprintf( stderr, "%s: line %d: inappropriate style \"%s\" in by clause\n", fname, lineno, style ); acl_usage(); } if( b->a_authz.sai_tls_ssf ) { fprintf( stderr, "%s: line %d: tls_ssf attribute already specified.\n", fname, lineno ); acl_usage(); } if ( right == NULL || *right == '\0' ) { fprintf( stderr, "%s: line %d: no tls_ssf is defined\n", fname, lineno ); acl_usage(); } b->a_authz.sai_tls_ssf = atoi( right ); if( !b->a_authz.sai_tls_ssf ) { fprintf( stderr, "%s: line %d: invalid tls_ssf value (%s)\n", fname, lineno, right ); acl_usage(); } continue; } if ( strcasecmp( left, "sasl_ssf" ) == 0 ) { if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) { fprintf( stderr, "%s: line %d: inappropriate style \"%s\" in by clause\n", fname, lineno, style ); acl_usage(); } if( b->a_authz.sai_sasl_ssf ) { fprintf( stderr, "%s: line %d: sasl_ssf attribute already specified.\n", fname, lineno ); acl_usage(); } if ( right == NULL || *right == '\0' ) { fprintf( stderr, "%s: line %d: no sasl_ssf is defined\n", fname, lineno ); acl_usage(); } b->a_authz.sai_sasl_ssf = atoi( right ); if( !b->a_authz.sai_sasl_ssf ) { fprintf( stderr, "%s: line %d: invalid sasl_ssf value (%s)\n", fname, lineno, right ); acl_usage(); } continue; } if( right != NULL ) { /* unsplit */ right[-1] = '='; } break; } if( i == argc || ( strcasecmp( left, "stop" ) == 0 )) { /* out of arguments or plain stop */ ACL_PRIV_ASSIGN(b->a_access_mask, ACL_PRIV_ADDITIVE); b->a_type = ACL_STOP; access_append( &a->acl_access, b ); continue; } if( strcasecmp( left, "continue" ) == 0 ) { /* plain continue */ ACL_PRIV_ASSIGN(b->a_access_mask, ACL_PRIV_ADDITIVE); b->a_type = ACL_CONTINUE; access_append( &a->acl_access, b ); continue; } if( strcasecmp( left, "break" ) == 0 ) { /* plain continue */ ACL_PRIV_ASSIGN(b->a_access_mask, ACL_PRIV_ADDITIVE); b->a_type = ACL_BREAK; access_append( &a->acl_access, b ); continue; } if ( strcasecmp( left, "by" ) == 0 ) { /* we've gone too far */ --i; ACL_PRIV_ASSIGN(b->a_access_mask, ACL_PRIV_ADDITIVE); b->a_type = ACL_STOP; access_append( &a->acl_access, b ); continue; } /* get */ if( strncasecmp( left, "self", 4 ) == 0 ) { b->a_dn_self = 1; ACL_PRIV_ASSIGN( b->a_access_mask, str2accessmask( &left[4] ) ); } else { ACL_PRIV_ASSIGN( b->a_access_mask, str2accessmask( left ) ); } if( ACL_IS_INVALID( b->a_access_mask ) ) { fprintf( stderr, "%s: line %d: expecting got \"%s\"\n", fname, lineno, left ); acl_usage(); } b->a_type = ACL_STOP; if( ++i == argc ) { /* out of arguments or plain stop */ access_append( &a->acl_access, b ); continue; } if( strcasecmp( argv[i], "continue" ) == 0 ) { /* plain continue */ b->a_type = ACL_CONTINUE; } else if( strcasecmp( argv[i], "break" ) == 0 ) { /* plain continue */ b->a_type = ACL_BREAK; } else if ( strcasecmp( argv[i], "stop" ) != 0 ) { /* gone to far */ i--; } access_append( &a->acl_access, b ); } else { fprintf( stderr, "%s: line %d: expecting \"to\" or \"by\" got \"%s\"\n", fname, lineno, argv[i] ); acl_usage(); } } /* 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", fname, lineno ); } else { #ifdef LDAP_DEBUG if (ldap_debug & LDAP_DEBUG_ACL) print_acl(be, a); #endif if ( a->acl_access == NULL ) { fprintf( stderr, "%s: line %d: warning: no by clause(s) specified in access line\n", fname, lineno ); } if ( be != NULL ) { acl_append( &be->be_acl, a ); } else { acl_append( &global_acl, a ); } } } char * accessmask2str( slap_mask_t mask, char *buf ) { int none=1; char *ptr = buf; assert( buf != NULL ); if ( ACL_IS_INVALID( mask ) ) { return "invalid"; } buf[0] = '\0'; if ( ACL_IS_LEVEL( mask ) ) { if ( ACL_LVL_IS_NONE(mask) ) { ptr = lutil_strcopy( ptr, "none" ); } else if ( ACL_LVL_IS_AUTH(mask) ) { ptr = lutil_strcopy( ptr, "auth" ); } else if ( ACL_LVL_IS_COMPARE(mask) ) { ptr = lutil_strcopy( ptr, "compare" ); } else if ( ACL_LVL_IS_SEARCH(mask) ) { ptr = lutil_strcopy( ptr, "search" ); } else if ( ACL_LVL_IS_READ(mask) ) { ptr = lutil_strcopy( ptr, "read" ); } else if ( ACL_LVL_IS_WRITE(mask) ) { ptr = lutil_strcopy( ptr, "write" ); } else { ptr = lutil_strcopy( ptr, "unknown" ); } *ptr++ = '('; } if( ACL_IS_ADDITIVE( mask ) ) { *ptr++ = '+'; } else if( ACL_IS_SUBTRACTIVE( mask ) ) { *ptr++ = '-'; } else { *ptr++ = '='; } if ( ACL_PRIV_ISSET(mask, ACL_PRIV_WRITE) ) { none = 0; *ptr++ = 'w'; } if ( ACL_PRIV_ISSET(mask, ACL_PRIV_READ) ) { none = 0; *ptr++ = 'r'; } if ( ACL_PRIV_ISSET(mask, ACL_PRIV_SEARCH) ) { none = 0; *ptr++ = 's'; } if ( ACL_PRIV_ISSET(mask, ACL_PRIV_COMPARE) ) { none = 0; *ptr++ = 'c'; } if ( ACL_PRIV_ISSET(mask, ACL_PRIV_AUTH) ) { none = 0; *ptr++ = 'x'; } if ( none && ACL_PRIV_ISSET(mask, ACL_PRIV_NONE) ) { none = 0; *ptr++ = 'n'; } if ( none ) { *ptr++ = '0'; } if ( ACL_IS_LEVEL( mask ) ) { *ptr++ = ')'; } *ptr = '\0'; return buf; } slap_mask_t str2accessmask( const char *str ) { slap_mask_t mask; if( !ASCII_ALPHA(str[0]) ) { int i; if ( str[0] == '=' ) { ACL_INIT(mask); } else if( str[0] == '+' ) { ACL_PRIV_ASSIGN(mask, ACL_PRIV_ADDITIVE); } else if( str[0] == '-' ) { ACL_PRIV_ASSIGN(mask, ACL_PRIV_SUBSTRACTIVE); } else { ACL_INVALIDATE(mask); return mask; } for( i=1; str[i] != '\0'; i++ ) { if( TOLOWER((unsigned char) str[i]) == 'w' ) { ACL_PRIV_SET(mask, ACL_PRIV_WRITE); } else if( TOLOWER((unsigned char) str[i]) == 'r' ) { ACL_PRIV_SET(mask, ACL_PRIV_READ); } else if( TOLOWER((unsigned char) str[i]) == 's' ) { ACL_PRIV_SET(mask, ACL_PRIV_SEARCH); } else if( TOLOWER((unsigned char) str[i]) == 'c' ) { ACL_PRIV_SET(mask, ACL_PRIV_COMPARE); } else if( TOLOWER((unsigned char) str[i]) == 'x' ) { ACL_PRIV_SET(mask, ACL_PRIV_AUTH); } else if( str[i] != '0' ) { ACL_INVALIDATE(mask); return mask; } } return mask; } if ( strcasecmp( str, "none" ) == 0 ) { ACL_LVL_ASSIGN_NONE(mask); } else if ( strcasecmp( str, "auth" ) == 0 ) { ACL_LVL_ASSIGN_AUTH(mask); } else if ( strcasecmp( str, "compare" ) == 0 ) { ACL_LVL_ASSIGN_COMPARE(mask); } else if ( strcasecmp( str, "search" ) == 0 ) { ACL_LVL_ASSIGN_SEARCH(mask); } else if ( strcasecmp( str, "read" ) == 0 ) { ACL_LVL_ASSIGN_READ(mask); } else if ( strcasecmp( str, "write" ) == 0 ) { ACL_LVL_ASSIGN_WRITE(mask); } else { ACL_INVALIDATE( mask ); } return mask; } static void acl_usage( void ) { fprintf( stderr, "\n" " ::= access to " "[ by [ ] ]+ \n" " ::= * | [dn[.]=] [filter=] [attrs=]\n" " ::= | , \n" " ::= | entry | children\n" " ::= [ * | anonymous | users | self | dn[.]= ]\n" "\t[dnattr=]\n" "\t[group[/[/]][.