- Added support for fine-grained access control to jobstat
authorDaniel Kouřil <kouril@ics.muni.cz>
Fri, 12 Mar 2010 14:26:15 +0000 (14:26 +0000)
committerDaniel Kouřil <kouril@ics.muni.cz>
Fri, 12 Mar 2010 14:26:15 +0000 (14:26 +0000)
- Introduced a new policy configuration format

org.glite.lb.server/src/authz_policy.c [new file with mode: 0644]
org.glite.lb.server/src/authz_policy.h [new file with mode: 0644]
org.glite.lb.server/src/bkserverd.c
org.glite.lb.server/src/jobstat.c
org.glite.lb.server/src/policy_gram.y [new file with mode: 0644]
org.glite.lb.server/src/policy_lex.l [new file with mode: 0644]

diff --git a/org.glite.lb.server/src/authz_policy.c b/org.glite.lb.server/src/authz_policy.c
new file mode 100644 (file)
index 0000000..5a2d635
--- /dev/null
@@ -0,0 +1,77 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include <glite/security/glite_gss.h>
+#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 (file)
index 0000000..1bba21b
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef GLITE_LB_AUTHZ_POLICY_H
+#define GLITE_LB_AUTHZ_POLICY_H
+
+#include <glite/lb/context-int.h>
+#include <glite/lb/authz.h>
+
+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
index ae85faa..03b4ac3 100644 (file)
@@ -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));
 
index cd2633a..e2fefba 100644 (file)
@@ -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 (file)
index 0000000..16ab41f
--- /dev/null
@@ -0,0 +1,142 @@
+%{
+
+#ident "$Header$"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#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> STRING
+%token <string> LITERAL
+%type <assigs> 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 (file)
index 0000000..50592cc
--- /dev/null
@@ -0,0 +1,38 @@
+%{
+
+#ident "$Header$"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#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; }