/* acl.c - routines to parse and check acl's */ #include #include #include #include #include #include #include "regex.h" #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(); static void split(); static void acl_append(); static void access_append(); static void acl_usage(); #ifdef LDAP_DEBUG static void print_acl(); static void print_access(); #endif void parse_acl( Backend *be, char *fname, int lineno, int argc, char **argv ) { int i; char *e, *left, *right; struct acl *a; struct access *b; 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 = (struct acl *) ch_calloc( 1, sizeof(struct acl) ); for ( ++i; i < argc; i++ ) { if ( strcasecmp( argv[i], "by" ) == 0 ) { i--; break; } if ( strcasecmp( argv[i], "*" ) == 0 ) { a->acl_dnpat = strdup( ".*" ); continue; } split( argv[i], '=', &left, &right ); if ( right == NULL || *right == '\0' ) { fprintf( stderr, "%s: line %d: missing \"=\" in (or value after) \"%s\" in to clause\n", fname, lineno, left ); acl_usage(); } 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 ( strcasecmp( left, "dn" ) == 0 ) { if ( (e = re_comp( right )) != NULL ) { fprintf( stderr, "%s: line %d: regular expression \"%s\" bad because of %s\n", fname, lineno, right, e ); acl_usage(); } a->acl_dnpat = dn_upcase( strdup( right ) ); } else if ( strncasecmp( left, "attr", 4 ) == 0 ) { char **alist; alist = str2charray( right, "," ); charray_merge( &a->acl_attrs, alist ); free( alist ); } else { fprintf( stderr, "%s: line %d: expecting got \"%s\"\n", fname, lineno, left ); 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 = (struct access *) ch_calloc( 1, sizeof(struct access) ); if ( ++i == argc ) { fprintf( stderr, "%s: line %d: premature eol: expecting \n", fname, lineno ); acl_usage(); } /* get */ split( argv[i], '=', &left, &right ); if ( strcasecmp( argv[i], "*" ) == 0 ) { b->a_dnpat = strdup( ".*" ); } else if ( strcasecmp( argv[i], "self" ) == 0 ) { b->a_dnpat = strdup( "self" ); } else if ( strcasecmp( left, "dn" ) == 0 ) { if ( (e = re_comp( right )) != NULL ) { fprintf( stderr, "%s: line %d: regular expression \"%s\" bad: %s\n", fname, lineno, right, e ); acl_usage(); } b->a_dnpat = dn_upcase( strdup( right ) ); } else if ( strcasecmp( left, "dnattr" ) == 0 ) { b->a_dnattr = strdup( right ); } else if ( strcasecmp( left, "domain" ) == 0 ) { char *s; if ( (e = re_comp( right )) != NULL ) { fprintf( stderr, "%s: line %d: regular expression \"%s\" bad: %s\n", fname, lineno, right, e ); acl_usage(); } b->a_domainpat = strdup( right ); /* normalize the domain */ for ( s = b->a_domainpat; *s; s++ ) { *s = TOLOWER( *s ); } } else if ( strcasecmp( left, "addr" ) == 0 ) { if ( (e = re_comp( right )) != NULL ) { fprintf( stderr, "%s: line %d: regular expression \"%s\" bad: %s\n", fname, lineno, right, e ); acl_usage(); } b->a_addrpat = strdup( right ); } else { fprintf( stderr, "%s: line %d: expecting got \"%s\"\n", fname, lineno, left ); acl_usage(); } if ( ++i == argc ) { fprintf( stderr, "%s: line %d: premature eol: expecting \n", fname, lineno ); acl_usage(); } /* get */ split( argv[i], '=', &left, &right ); if ( (b->a_access = str2access( left )) == -1 ) { fprintf( stderr, "%s: line %d: expecting got \"%s\"\n", fname, lineno, left ); acl_usage(); } 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 { 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 * access2str( int access ) { static char buf[12]; if ( access & ACL_SELF ) { strcpy( buf, "self" ); } else { buf[0] = '\0'; } if ( access & ACL_NONE ) { strcat( buf, "none" ); } else if ( access & ACL_COMPARE ) { strcat( buf, "compare" ); } else if ( access & ACL_SEARCH ) { strcat( buf, "search" ); } else if ( access & ACL_READ ) { strcat( buf, "read" ); } else if ( access & ACL_WRITE ) { strcat( buf, "write" ); } else { strcat( buf, "unknown" ); } return( buf ); } int str2access( char *str ) { int access; access = 0; if ( strncasecmp( str, "self", 4 ) == 0 ) { access |= ACL_SELF; str += 4; } if ( strcasecmp( str, "none" ) == 0 ) { access |= ACL_NONE; } else if ( strcasecmp( str, "compare" ) == 0 ) { access |= ACL_COMPARE; } else if ( strcasecmp( str, "search" ) == 0 ) { access |= ACL_SEARCH; } else if ( strcasecmp( str, "read" ) == 0 ) { access |= ACL_READ; } else if ( strcasecmp( str, "write" ) == 0 ) { access |= ACL_WRITE; } else { access = -1; } return( access ); } static void acl_usage() { fprintf( stderr, "\n ::= access to [ by ]+ \n" ); fprintf( stderr, " ::= * | [dn=] [filter=] [attrs=]\n" ); fprintf( stderr, " ::= | , \n" ); fprintf( stderr, " ::= | entry | children\n" ); fprintf( stderr, " ::= * | self | dn= | addr= |\n\tdomain= | dnattr=\n" ); fprintf( stderr, " ::= [self]{none | compare | search | read | write }\n" ); exit( 1 ); } static void split( char *line, int splitchar, char **left, char **right ) { *left = line; if ( (*right = strchr( line, splitchar )) != NULL ) { *((*right)++) = '\0'; } } static void access_append( struct access **l, struct access *a ) { for ( ; *l != NULL; l = &(*l)->a_next ) ; /* NULL */ *l = a; } static void acl_append( struct acl **l, struct acl *a ) { for ( ; *l != NULL; l = &(*l)->acl_next ) ; /* NULL */ *l = a; } #ifdef LDAP_DEBUG static void print_access( struct access *b ) { printf( "\tby" ); if ( b->a_dnpat != NULL ) { printf( " dn=%s", b->a_dnpat ); } else if ( b->a_addrpat != NULL ) { printf( " addr=%s", b->a_addrpat ); } else if ( b->a_domainpat != NULL ) { printf( " domain=%s", b->a_domainpat ); } else if ( b->a_dnattr != NULL ) { printf( " dnattr=%s", b->a_dnattr ); } printf( " %s\n", access2str( b->a_access ) ); } static void print_acl( struct acl *a ) { int i; struct access *b; if ( a == NULL ) { printf( "NULL\n" ); } printf( "access to" ); if ( a->acl_filter != NULL ) { printf( " filter=" ); filter_print( a->acl_filter ); } if ( a->acl_dnpat != NULL ) { printf( " dn=" ); printf( a->acl_dnpat ); } if ( a->acl_attrs != NULL ) { int first = 1; printf( " attrs=" ); for ( i = 0; a->acl_attrs[i] != NULL; i++ ) { if ( ! first ) { printf( "," ); } printf( a->acl_attrs[i] ); first = 0; } } printf( "\n" ); for ( b = a->acl_access; b != NULL; b = b->a_next ) { print_access( b ); } } #endif