From: Daniel KouĊ™il Date: Fri, 12 Mar 2010 14:26:15 +0000 (+0000) Subject: - Added support for fine-grained access control to jobstat X-Git-Tag: merge_20_2_dst~15 X-Git-Url: http://scientific.zcu.cz/git/?a=commitdiff_plain;h=72fd14e081a188c4bd2baefd9cbb9393c822c5ad;p=jra1mw.git - Added support for fine-grained access control to jobstat - Introduced a new policy configuration format --- diff --git a/org.glite.lb.server/src/authz_policy.c b/org.glite.lb.server/src/authz_policy.c new file mode 100644 index 0000000..5a2d635 --- /dev/null +++ b/org.glite.lb.server/src/authz_policy.c @@ -0,0 +1,77 @@ +#include +#include + +#include +#include "authz_policy.h" + +struct action_name action_names[] = { + { READ_ALL, "READ_ALL" }, + { READ_RTM, "READ_RTM" }, +}; + +static int num_actions = + sizeof(action_names) / sizeof(action_names[0]); + +struct attr_id_name attr_id_names[] = { + { ATTR_SUBJECT, "subject" }, + { ATTR_FQAN, "fqan" }, +}; + +static int num_attrs = + sizeof(attr_id_names) / sizeof(attr_id_names[0]); + + +int +check_authz_policy(edg_wll_Context ctx, edg_wll_authz_policy policy, + authz_action action) +{ + int i; + char **f; + _edg_wll_authz_rule *r; + + if (policy == NULL) + return 0; + + for (i = 0; i < policy->num; i++) { + r = policy->rules + i; + if (r->action != action) + break; + switch (r->attr_id) { + case ATTR_SUBJECT: + if (edg_wll_gss_equal_subj(r->attr_value, ctx->peerName)) + return 1; + break; + case ATTR_FQAN: + for (f = ctx->fqans; f && *f; f++) + if (strcmp(r->attr_value, *f) == 0) + return 1; + break; + default: + break; + } + } + + return 0; +} + +authz_action +find_authz_action(const char *name) +{ + int i; + + for (i = 0; i < num_actions; i++) + if (strcmp(action_names[i].name, name) == 0) + return action_names[i].action; + return ACTION_UNDEF; +} + +authz_attr_id +find_authz_attr(const char *name) +{ + int i; + + for (i = 0; i < num_attrs; i++) + if (strcmp(attr_id_names[i].name, name) == 0) + return attr_id_names[i].id; + return ATTR_UNDEF; +} diff --git a/org.glite.lb.server/src/authz_policy.h b/org.glite.lb.server/src/authz_policy.h new file mode 100644 index 0000000..1bba21b --- /dev/null +++ b/org.glite.lb.server/src/authz_policy.h @@ -0,0 +1,41 @@ +#ifndef GLITE_LB_AUTHZ_POLICY_H +#define GLITE_LB_AUTHZ_POLICY_H + +#include +#include + +typedef enum { + ACTION_UNDEF = 0, + READ_ALL = 2, + READ_RTM = 4, +} authz_action; + +typedef struct action_name { + authz_action action; + const char *name; +} action_name; + +typedef enum { + ATTR_UNDEF = 0, + ATTR_SUBJECT = 2, + ATTR_FQAN = 4, +} authz_attr_id; + +struct attr_id_name { + authz_attr_id id; + const char *name; +} attr_id_name; + +int +parse_server_policy(edg_wll_Context ctx, const char *filename, edg_wll_authz_policy policy); + +int +check_authz_policy(edg_wll_Context, edg_wll_authz_policy, authz_action); + +authz_action +find_authz_action(const char *name); + +authz_attr_id +find_authz_attr(const char *name); + +#endif diff --git a/org.glite.lb.server/src/bkserverd.c b/org.glite.lb.server/src/bkserverd.c index ae85faa..03b4ac3 100644 --- a/org.glite.lb.server/src/bkserverd.c +++ b/org.glite.lb.server/src/bkserverd.c @@ -58,6 +58,7 @@ enum lb_srv_perf_sink sink_mode; #include "db_calls.h" #include "db_supp.h" #include "openserver.h" +#include "authz_policy.h" #ifdef GLITE_LB_SERVER_WITH_WS # if GSOAP_VERSION < 20700 @@ -166,6 +167,8 @@ static int con_queue = CON_QUEUE; static char host[300]; static char * port; static time_t rss_time = 60*60; +static char * policy_file = NULL; +struct _edg_wll_authz_policy authz_policy = { NULL, 0}; @@ -215,10 +218,11 @@ static struct option opts[] = { {"proxy-il-fprefix", 1, NULL, 'Z'}, {"proxy-purge", 0, NULL, 'G'}, {"rss-time", 1, NULL, 'I'}, + {"policy", 1, NULL, 'l'}, {NULL,0,NULL,0} }; -static const char *get_opt_string = "Ac:k:C:V:p:a:drm:ns:i:S:D:J:jR:F:xOL:N:X:Y:T:t:zb:gPBo:q:W:Z:GI:" +static const char *get_opt_string = "Ac:k:C:V:p:a:drm:ns:i:S:D:J:jR:F:xOL:N:X:Y:T:t:zb:gPBo:q:W:Z:GI:l:" #ifdef GLITE_LB_SERVER_WITH_WS "w:" #endif @@ -275,7 +279,8 @@ static void usage(char *me) "\t-W,--proxy-il-sock\t socket to send events to\n" "\t-Z,--proxy-il-fprefix\t file prefix for events\n" "\t-G,--proxy-purge\t enable automatic purge on proxy service (disabled by default)\n" - "\t-I,--rss-time age\t (in seconds) of job states published via RSS\n" + "\t-I,--rss-time\t age (in seconds) of job states published via RSS\n" + "\t-l,--policy\tauthorization policy file\n" ,me); } @@ -483,6 +488,8 @@ int main(int argc, char *argv[]) break; case 'I': rss_time = atol(optarg); break; + case 'l': policy_file = strdup(optarg); + break; case '?': usage(name); return 1; } @@ -533,6 +540,15 @@ int main(int argc, char *argv[]) if (fprintf(fpid, "%d", getpid()) <= 0) { perror(pidfile); return 1; } if (fclose(fpid) != 0) { perror(pidfile); return 1; } + if (policy_file && parse_server_policy(ctx, policy_file, &authz_policy)) { + char *et, *ed; + + edg_wll_Error(ctx,&et,&ed); + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_FATAL, "Cannot load server policy: %s: %s\n", et, ed); + return 1; + } + + if (mode & SERVICE_SERVER) { if (check_mkdir(dumpStorage)){ glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_FATAL, "Directory for dump files not redy!"); @@ -1004,6 +1020,14 @@ int bk_handle_connection(int conn, struct timeval *timeout, void *data) ctx->hardJobsLimit = hardJobsLimit; ctx->hardEventsLimit = hardEventsLimit; if ( noAuth ) ctx->noAuth = 1; + if ( authz_policy.num ) { + int i; + for (i=0; i < authz_policy.num; i++) + edg_wll_add_authz_rule(ctx, &ctx->authz_policy, + (authz_policy.rules[i]).action, + (authz_policy.rules[i]).attr_id, + (authz_policy.rules[i]).attr_value); + } ctx->rgma_export = rgma_export; memcpy(ctx->purge_timeout, purge_timeout, sizeof(ctx->purge_timeout)); diff --git a/org.glite.lb.server/src/jobstat.c b/org.glite.lb.server/src/jobstat.c index cd2633a..e2fefba 100644 --- a/org.glite.lb.server/src/jobstat.c +++ b/org.glite.lb.server/src/jobstat.c @@ -24,6 +24,7 @@ #include "stats.h" #include "db_supp.h" #include "db_calls.h" +#include "authz_policy.h" #define DAG_ENABLE 1 @@ -71,6 +72,26 @@ static char* matched_substr(char *in, regmatch_t match) return s; } +static int +check_jobstat_authz(edg_wll_Context ctx, + char *owner, + edg_wll_Acl acl, + int *flags) +{ + *flags = 0; + if (ctx->noAuth) + return 1; + if (ctx->peerName && edg_wll_gss_equal_subj(ctx->peerName, owner)) + return 1; + if (acl && edg_wll_CheckACL(ctx, acl, EDG_WLL_CHANGEACL_READ) == 0) + return 1; + edg_wll_ResetError(ctx); + if (check_authz_policy(ctx, &ctx->authz_policy, READ_RTM)) { + *flags |= READ_RTM; + return 1; + } + return 0; +} int edg_wll_JobStatusServer( edg_wll_Context ctx, @@ -95,6 +116,7 @@ int edg_wll_JobStatusServer( char *out[1], *out_stat[3]; glite_lbu_Statement sh = NULL; int num_sub, num_f, i, ii; + int authz_flags = 0; edg_wll_ResetError(ctx); @@ -125,19 +147,11 @@ int edg_wll_JobStatusServer( if (edg_wll_GetACL(ctx, job, &acl)) goto rollback; - /* authorization check */ - if ( !(ctx->noAuth) && - (!(ctx->peerName) || !edg_wll_gss_equal_subj(ctx->peerName, stat->owner))) { - if ((acl == NULL) || edg_wll_CheckACL(ctx, acl, EDG_WLL_CHANGEACL_READ)) { - if (acl) { - goto rollback; - } else { - edg_wll_SetError(ctx,EPERM, "not owner, no ACL is set"); - goto rollback; - } - } + if (check_jobstat_authz(ctx, stat->owner, acl, &authz_flags) == 0) { + edg_wll_SetError(ctx, EPERM, "not owner"); + goto rollback; } - + if (acl) { stat->acl = strdup(acl->string); edg_wll_FreeAcl(acl); @@ -380,6 +394,18 @@ rollback: free(string_jobid); free(md5_jobid); + if (authz_flags && authz_flags & READ_RTM) { + edg_wll_JobStat new_stat; + + memset(&new_stat, 0, sizeof(new_stat)); + new_stat.state = stat->state; + /* XXX save anything else */ + + edg_wll_FreeStatus(stat); + memset(stat, 0, sizeof(*stat)); + edg_wll_CpyStatus(&new_stat, stat); + } + return edg_wll_Error(ctx, NULL, NULL); } diff --git a/org.glite.lb.server/src/policy_gram.y b/org.glite.lb.server/src/policy_gram.y new file mode 100644 index 0000000..16ab41f --- /dev/null +++ b/org.glite.lb.server/src/policy_gram.y @@ -0,0 +1,142 @@ +%{ + +#ident "$Header$" + +#include +#include +#include +#include + +#include "glite/lb/context-int.h" +#include "authz_policy.h" + +void yyerror (const char *); +void set_error(const char *format, ...); + +static edg_wll_Context parse_ctx; +static const char *parse_fname; +static edg_wll_authz_policy parse_policy; + +extern unsigned lineno; + +extern FILE *yyin; + +struct _assigs { + int id; + char *value; + struct _assigs *next; +} _assigs; + +struct _assigs *assigs = NULL; + +%} + +%union { + char *string; + struct _assigs *assigs; +} + +%token RESOURCE ACTION RULE PERMIT +%token STRING +%token LITERAL +%type assignment assignments + +%start policy + +%% + +policy : RESOURCE STRING '{' actions '}' + { + if (strcmp($2, "LB") != 0) + set_error("Undefined resource '%s'", $2); + } + ; + +actions : + | action actions + ; + +action : ACTION STRING '{' rules '}' + { + struct _assigs *a; + authz_action ac = find_authz_action($2); + + if (ac == ACTION_UNDEF) + set_error("undefined action '%s'", $2); + + for (a = assigs; a; a = a->next) { + edg_wll_add_authz_rule(parse_ctx, parse_policy, + ac, a->id, a->value); + } + assigs = NULL; /* XXX */ + } + ; + +rules : + | rule rules + ; + +rule : RULE PERMIT '{' assignments '}' + { + assigs = $4; + } + ; + +assignments : assignment assignments + { + $1->next = $2; + $$ = $1; + } + | assignment + ; + +assignment : LITERAL '=' STRING + { + $$ = malloc(sizeof(*$$)); + $$->id = find_authz_attr($1); + if ($$->id == ATTR_UNDEF) + set_error("undefined attribute '%s'", $1); + $$->value = $3; + $$->next = NULL; + } + ; + +%% + +void set_error(const char *format, ...) +{ + va_list args; + char *buf, *msg; + + va_start (args, format); + vasprintf (&buf, format, args); + va_end(args); + + asprintf(&msg, "%s:%d: %s", parse_fname, lineno, buf); + edg_wll_SetError(parse_ctx, EINVAL, msg); + free(buf); + free(msg); +} + +void yyerror(const char *str) +{ + set_error("%s", str); +} + +int +parse_server_policy(edg_wll_Context ctx, const char *filename, edg_wll_authz_policy policy) +{ + lineno = 1; + yyin = fopen(filename, "r"); + if (yyin == NULL) + return edg_wll_SetError(ctx,errno,filename); + + parse_ctx = ctx; + parse_fname = filename; + parse_policy = policy; + edg_wll_ResetError(ctx); + yyparse(); + fclose(yyin); + + return edg_wll_Error(ctx,NULL,NULL); +} diff --git a/org.glite.lb.server/src/policy_lex.l b/org.glite.lb.server/src/policy_lex.l new file mode 100644 index 0000000..50592cc --- /dev/null +++ b/org.glite.lb.server/src/policy_lex.l @@ -0,0 +1,38 @@ +%{ + +#ident "$Header$" + +#include +#include +#include +#include "policy_gram.h" + +unsigned lineno = 1; + +#define YY_NO_UNPUT + +%} +%% + +resource { return RESOURCE; } +action { return ACTION; } +rule { return RULE; } +permit { return PERMIT; } +[A-Za-z0-9_]+ { + yylval.string = strdup ((const char *)yytext); + return LITERAL; + } +\"[^\"\n]*\" { + int len; + yylval.string = malloc(len = strlen(yytext)-1); + strncpy(yylval.string,yytext+1,len-1); + yylval.string[len-1] = '\0'; + return STRING; + } +[={}] { return *yytext; } +"\n" { lineno++; } +[ \t]+ ; +. { return *yytext; } +%% + +int yywrap() { return 1; }