summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org.ua>2015-12-17 10:50:28 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2015-12-17 10:50:28 (GMT)
commit8334b598f85317eb4d44000f6ec580c54734b15d (patch) (side-by-side diff)
tree04dd1b84443287aec625ab019b02fc170ae524a1
parent8426fc4411c9679a10863d7aa3ced077155e0016 (diff)
downloadpies-8334b598f85317eb4d44000f6ec580c54734b15d.tar.gz
pies-8334b598f85317eb4d44000f6ec580c54734b15d.tar.bz2
Implement user privileges
* src/pies.h (component): New members: list_acl and adm_acl. (control): Removed id_acl. New members: adm_acl and usr_acl. * src/pies.c (component_keywords): New keywords list-acl and admin-acl. Removed identity-acl. * ident/ident.c (pies_identity_user_name): New function. * ident/identity.h (pies_identity_user_name): New proto. * src/ctl.c (CTL_USER_STATE,CTL_ADMIN_STATE): New states. (cmdtab): Mark administrative commands as valid in CTL_ADMIN_STATE (ctlio_create): Assume CTL_ADMIN_STATE in the absense of identity providers. (auth_data): New struct. (cmd_auth): Select appropriate state depending on the user permissions. (list_matches): New function. (eval_env): Keep the list of selected progs. (count_prog): Removed. (selector): New function. (cmd_list): Rewrite to take into account access rights. (cmd_start,cmd_stop) (cmd_restart): Only allowed for users with administrative privileges.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--ident/ident.c8
-rw-r--r--ident/identity.h6
-rw-r--r--src/ctl.c291
-rw-r--r--src/pies.c34
-rw-r--r--src/pies.h14
5 files changed, 244 insertions, 109 deletions
diff --git a/ident/ident.c b/ident/ident.c
index 38ae1a8..dbf3f9b 100644
--- a/ident/ident.c
+++ b/ident/ident.c
@@ -41,6 +41,14 @@ pies_authenticate (pies_identity_provider_t pr, pies_identity_t id,
return 1;
}
+char const *
+pies_identity_user_name (pies_identity_t id)
+{
+ if (!id)
+ return NULL;
+ return id->username;
+}
+
int
pies_identity_is_user (pies_identity_t id, char * const * users)
{
diff --git a/ident/identity.h b/ident/identity.h
index 0ee129d..8a9e2ab 100644
--- a/ident/identity.h
+++ b/ident/identity.h
@@ -20,12 +20,12 @@ typedef struct pies_identity_mechanism *pies_identity_mechanism_t;
pies_identity_t pies_identity_create (char const *user);
void pies_identity_destroy (pies_identity_t id);
-
-int pies_authenticate (pies_identity_provider_t pr, pies_identity_t id,
- char const *passwd);
int pies_identity_is_user (pies_identity_t id, char * const * users);
int pies_identity_is_group_member (pies_identity_t id, char * const * groups);
+char const *pies_identity_user_name (pies_identity_t p);
+int pies_authenticate (pies_identity_provider_t pr, pies_identity_t id,
+ char const *passwd);
char const *pies_identity_provider_name (pies_identity_provider_t p);
int pies_identity_mechanism_register (pies_identity_mechanism_t mech);
diff --git a/src/ctl.c b/src/ctl.c
index 20c16e1..f422e4b 100644
--- a/src/ctl.c
+++ b/src/ctl.c
@@ -104,8 +104,11 @@ ctlbuf_chomp (struct ctlbuf *buf)
#define CTL_END_STATE 0
#define CTL_INITIAL_STATE 0x01
-#define CTL_AUTHENTICATED_STATE 0x02
-#define CTL_ACTION_STATE 0x04
+#define CTL_USER_STATE 0x02
+#define CTL_ADMIN_STATE 0x04
+#define CTL_ACTION_STATE 0x08
+
+#define CTL_AUTHENTICATED_STATE (CTL_USER_STATE|CTL_ADMIN_STATE)
#define CTL_ALL_STATES (CTL_INITIAL_STATE|CTL_AUTHENTICATED_STATE)
struct ctlio;
@@ -152,9 +155,9 @@ static struct ctlio_command cmdtab[] = {
{ "restart", "restart component",
CTL_AUTHENTICATED_STATE, 2, 2, cmd_restart },
{ "reboot", "restart pies",
- CTL_AUTHENTICATED_STATE, 1, 1, cmd_reboot },
+ CTL_ADMIN_STATE, 1, 1, cmd_reboot },
{ "shutdown", "stop pies",
- CTL_AUTHENTICATED_STATE, 1, 1, cmd_shutdown },
+ CTL_ADMIN_STATE, 1, 1, cmd_shutdown },
{ NULL }
};
@@ -190,7 +193,7 @@ ctlio_create (void)
io = xmalloc (sizeof (*io));
io->state = identity_provider_list
- ? CTL_INITIAL_STATE : CTL_AUTHENTICATED_STATE;
+ ? CTL_INITIAL_STATE : CTL_ADMIN_STATE;
io->action = ACTION_CONT;
ctlbuf_init (&io->ibuf);
ctlbuf_init (&io->obuf);
@@ -321,12 +324,42 @@ ctlio_initial_reply (struct ctlio *io)
ctlio_eol (io);
}
+struct auth_data
+{
+ union pies_sockaddr_storage addr;
+ socklen_t addrlen;
+ pies_identity_t id;
+ struct component const *comp;
+};
+
+static int
+try_auth (struct prog *prog, void *data)
+{
+ struct auth_data *auth = data;
+ if (IS_COMPONENT (prog))
+ {
+ if ((prog->v.p.comp->adm_acl
+ && check_acl (prog->v.p.comp->adm_acl,
+ (struct sockaddr *)&auth->addr, auth->addrlen,
+ auth->id) == 0)
+ || (prog->v.p.comp->list_acl
+ && check_acl (prog->v.p.comp->list_acl,
+ (struct sockaddr *)&auth->addr, auth->addrlen,
+ auth->id) == 0))
+ {
+ auth->comp = prog->v.p.comp;
+ return 1;
+ }
+ }
+ return 0;
+}
+
static void
cmd_auth (struct ctlio *io, size_t argc, char **argv)
{
struct grecs_list_entry *ep;
pies_identity_t id = pies_identity_create (argv[1]);
- int auth = 0;
+ int new_state = CTL_INITIAL_STATE;
for (ep = identity_provider_list->head; ep; ep = ep->next)
{
@@ -336,33 +369,54 @@ cmd_auth (struct ctlio *io, size_t argc, char **argv)
debug(1, ("trying %s...", pname));
if (pies_authenticate (provider, id, argv[2]) == 0)
{
- if (check_acl (control.id_acl,
- (struct sockaddr *)&io->addr, io->addrlen, id))
+ if (control.adm_acl
+ && check_acl (control.adm_acl,
+ (struct sockaddr *)&io->addr, io->addrlen,
+ id) == 0)
{
- logmsg (LOG_AUTH, "%s authenticated via %s, but failed ACL check",
+ new_state = CTL_ADMIN_STATE;
+ logmsg (LOG_AUTH, "%s granted admin access via %s",
argv[1], pname);
- auth = 0;
}
- else
+ else if (control.usr_acl
+ && check_acl (control.usr_acl,
+ (struct sockaddr *)&io->addr, io->addrlen,
+ id) == 0)
{
+ new_state = CTL_USER_STATE;
logmsg (LOG_AUTH, "%s authenticated via %s",
argv[1], pname);
- auth = 1;
+ }
+ else
+ {
+ struct auth_data ad = { io->addr, io->addrlen, id, NULL };
+ progman_foreach (try_auth, &ad);
+ if (ad.comp)
+ {
+ new_state = CTL_USER_STATE;
+ logmsg (LOG_AUTH, "%s authenticated via %s, component %s",
+ argv[1], pname, ad.comp->tag);
+ }
+ else
+ {
+ logmsg (LOG_AUTH, "%s authenticated via %s, but failed ACL check",
+ argv[1], pname);
+ }
}
break;
}
}
- if (auth)
+ if (new_state == CTL_INITIAL_STATE)
{
- ctlio_reply (io, "230", "authentication successful");
- identity = id;
- io->state = CTL_AUTHENTICATED_STATE;
+ pies_identity_destroy (id);
+ ctlio_reply (io, "531", "access denied");
}
else
{
- pies_identity_destroy (id);
- ctlio_reply (io, "531", "access denied");
+ ctlio_reply (io, "230", "authentication successful");
+ identity = id;
+ io->state = new_state;
}
}
@@ -801,67 +855,100 @@ pcond_parse (struct ctlio *io, size_t argc, char **argv,
return 0;
}
+static int
+list_matches (struct ctlio *io, struct grecs_list *matches)
+{
+ struct grecs_list_entry *ep;
+ size_t i;
+
+ for (ep = matches->head; ep; ep = ep->next)
+ {
+ struct prog *prog = ep->data;
+
+ ctlio_reply (io, "151", "%s", prog->tag);
+ FORMAT_IDX (io, "Type", pies_type_str, prog->type);
+ switch (prog->type)
+ {
+ case TYPE_COMPONENT:
+ FORMAT_IDX (io, "Mode", pies_comp_mode_str, prog->v.p.comp->mode);
+ FORMAT_IDX (io, "Status", status_str, prog->v.p.status);
+
+ if (prog->pid)
+ ctlio_printf (io, "PID: %lu%s", (unsigned long) prog->pid, CRLF);
+ else if (prog->v.p.status == status_listener
+ && prog->v.p.comp->socket_url)
+ ctlio_printf (io, "URL: %10s%s",
+ prog->v.p.comp->socket_url->string,
+ CRLF);
+
+ if (prog->v.p.status == status_sleeping)
+ {
+ ctlio_printf (io, "Wakeup-Time: %lu%s",
+ (unsigned long) (prog->v.p.timestamp + SLEEPTIME),
+ CRLF);
+ }
+
+ ctlio_printf (io, "Command:");
+ for (i = 0; i < prog->v.p.comp->argc; i++)
+ ctlio_printf (io, " %s", quotearg (prog->v.p.comp->argv[i]));
+ ctlio_eol (io);
+ break;
+
+ case TYPE_REDIRECTOR:
+ ctlio_printf (io, "PID: %10lu%s", (unsigned long) prog->pid, CRLF);
+ break;
+
+ case TYPE_COMMAND:
+ ctlio_printf (io, "Command: %s%s", prog->v.c.command, CRLF);
+ }
+ ctlio_eot (io);
+ }
+ return 0;
+}
+
struct eval_env
{
struct ctlio *io;
struct pcond_node *cond;
- size_t count;
+ struct grecs_list *list;
};
+/* Authenticate access to PROG. Return 0, CTL_USER_STATE or
+ CTL_ADMIN_STATE depending on whether and what kind of access is
+ allowed for the current identity */
static int
-list_prog (struct prog *prog, void *data)
+auth_prog (struct prog *prog, struct ctlio *io)
{
- struct eval_env *env = data;
- struct ctlio *io = env->io;
- size_t i;
-
- if (!pcond_eval (env->cond, prog))
- return 0;
- ctlio_reply (io, "151", "%s", prog->tag);
- FORMAT_IDX (io, "Type", pies_type_str, prog->type);
+ if (io->state == CTL_ADMIN_STATE)
+ return CTL_ADMIN_STATE|CTL_USER_STATE;
switch (prog->type)
{
- case TYPE_COMPONENT:
- FORMAT_IDX (io, "Mode", pies_comp_mode_str, prog->v.p.comp->mode);
- FORMAT_IDX (io, "Status", status_str, prog->v.p.status);
-
- if (prog->pid)
- ctlio_printf (io, "PID: %lu%s", (unsigned long) prog->pid, CRLF);
- else if (prog->v.p.status == status_listener
- && prog->v.p.comp->socket_url)
- ctlio_printf (io, "URL: %10s%s", prog->v.p.comp->socket_url->string,
- CRLF);
-
- if (prog->v.p.status == status_sleeping)
- {
- ctlio_printf (io, "Wakeup-Time: %lu%s",
- (unsigned long) (prog->v.p.timestamp + SLEEPTIME),
- CRLF);
- }
-
- ctlio_printf (io, "Command:");
- for (i = 0; i < prog->v.p.comp->argc; i++)
- ctlio_printf (io, " %s", quotearg (prog->v.p.comp->argv[i]));
- ctlio_eol (io);
- break;
-
case TYPE_REDIRECTOR:
- ctlio_printf (io, "PID: %10lu%s", (unsigned long) prog->pid, CRLF);
+ prog = prog->v.r.master;
+ /* FALL THROUGH */
+ case TYPE_COMPONENT:
+ if (prog->v.p.comp->adm_acl
+ && check_acl (prog->v.p.comp->adm_acl,
+ (struct sockaddr *)&io->addr, io->addrlen,
+ identity) == 0)
+ return CTL_ADMIN_STATE;
+ if (check_acl (prog->v.p.comp->list_acl,
+ (struct sockaddr *)&io->addr, io->addrlen,
+ identity) == 0)
+ return CTL_USER_STATE;
+ default:
break;
-
- case TYPE_COMMAND:
- ctlio_printf (io, "Command: %s%s", prog->v.c.command, CRLF);
}
- ctlio_eot (io);
return 0;
}
static int
-count_prog (struct prog *prog, void *data)
+selector (struct prog *prog, void *data)
{
struct eval_env *env = data;
- if (pcond_eval (env->cond, prog))
- ++env->count;
+
+ if (pcond_eval (env->cond, prog) && auth_prog (prog, env->io))
+ grecs_list_append (env->list, prog);
return 0;
}
@@ -869,24 +956,27 @@ static void
cmd_list (struct ctlio *io, size_t argc, char **argv)
{
struct eval_env env;
+ size_t size;
env.io = io;
- env.count = 0;
if (pcond_parse (io, argc - 1, argv + 1, &env.cond))
return;
+ env.list = grecs_list_create ();
- progman_foreach (count_prog, &env);
- if (env.count)
+ progman_foreach (selector, &env);
+ size = grecs_list_size (env.list);
+ if (size)
{
ctlio_reply (io, "150", "%lu matches found; list follows",
- env.count);
- progman_foreach (list_prog, &env);
+ (unsigned long) size);
+ list_matches (io, env.list);
ctlio_reply (io, "250", "complete");
}
else
ctlio_reply (io, "552", "No match");
pcond_free (env.cond);
+ grecs_list_free (env.list);
}
static void
@@ -894,19 +984,24 @@ cmd_start (struct ctlio *io, size_t argc, char **argv)
{
char const *tag = argv[1];
struct prog *prog = progman_locate (tag);
- if (!prog)
- ctlio_reply (io, "552", "Component not found");
- else if (!IS_COMPONENT (prog))
- ctlio_reply (io, "553", "Not a component");
- else if (prog->v.p.status != status_disabled)
- ctlio_reply (io, "554", "Not stopped");
- else
+ if (auth_prog (prog, io) & CTL_ADMIN_STATE)
{
- prog->v.p.comp->flags &= CF_DISABLED;
- prog->v.p.status = status_enabled;
- kill (getpid (), SIGALRM);
- ctlio_reply (io, "250", "Complete");
+ if (!prog)
+ ctlio_reply (io, "552", "Component not found");
+ else if (!IS_COMPONENT (prog))
+ ctlio_reply (io, "553", "Not a component");
+ else if (prog->v.p.status != status_disabled)
+ ctlio_reply (io, "554", "Not stopped");
+ else
+ {
+ prog->v.p.comp->flags &= CF_DISABLED;
+ prog->v.p.status = status_enabled;
+ kill (getpid (), SIGALRM);
+ ctlio_reply (io, "250", "Complete");
+ }
}
+ else
+ ctlio_reply (io, "531", "access denied");
}
static void
@@ -914,16 +1009,21 @@ cmd_stop (struct ctlio *io, size_t argc, char **argv)
{
char const *tag = argv[1];
struct prog *prog = progman_locate (tag);
- if (!prog)
- ctlio_reply (io, "552", "Component not found");
- else if (!IS_COMPONENT (prog))
- ctlio_reply (io, "553", "Not a component");
- else
+ if (auth_prog (prog, io) & CTL_ADMIN_STATE)
{
- progman_stop_component (prog);
- prog->v.p.comp->flags |= CF_DISABLED;
- ctlio_reply (io, "250", "Complete");
+ if (!prog)
+ ctlio_reply (io, "552", "Component not found");
+ else if (!IS_COMPONENT (prog))
+ ctlio_reply (io, "553", "Not a component");
+ else
+ {
+ progman_stop_component (prog);
+ prog->v.p.comp->flags |= CF_DISABLED;
+ ctlio_reply (io, "250", "Complete");
+ }
}
+ else
+ ctlio_reply (io, "531", "access denied");
}
static void
@@ -931,17 +1031,22 @@ cmd_restart (struct ctlio *io, size_t argc, char **argv)
{
char const *tag = argv[1];
struct prog *prog = progman_locate (tag);
- if (!prog)
- ctlio_reply (io, "552", "Component not found");
- else if (!(IS_COMPONENT (prog)
- && !(prog->v.p.comp->mode == pies_comp_inetd
- && prog->v.p.listener)))
- ctlio_reply (io, "553", "Not a component");
- else
+ if (auth_prog (prog, io) & CTL_ADMIN_STATE)
{
- progman_stop_component (prog);
- ctlio_reply (io, "250", "Complete");
+ if (!prog)
+ ctlio_reply (io, "552", "Component not found");
+ else if (!(IS_COMPONENT (prog)
+ && !(prog->v.p.comp->mode == pies_comp_inetd
+ && prog->v.p.listener)))
+ ctlio_reply (io, "553", "Not a component");
+ else
+ {
+ progman_stop_component (prog);
+ ctlio_reply (io, "250", "Complete");
+ }
}
+ else
+ ctlio_reply (io, "531", "access denied");
}
static void
diff --git a/src/pies.c b/src/pies.c
index 9f5f174..85d0567 100644
--- a/src/pies.c
+++ b/src/pies.c
@@ -1122,11 +1122,23 @@ struct grecs_keyword component_keywords[] = {
NULL,
},
{"acl",
- N_("name: string"),
- N_("Set ACL."),
+ NULL,
+ N_("Define connection ACL."),
grecs_type_section, GRECS_DFLT,
NULL, offsetof (struct component, acl),
acl_section_parser, NULL, acl_keywords},
+ {"list-acl",
+ NULL,
+ N_("Define who can list this component."),
+ grecs_type_section, GRECS_DFLT,
+ NULL, offsetof (struct component, list_acl),
+ acl_section_parser, NULL, acl_keywords},
+ {"admin-acl",
+ NULL,
+ N_("Define who can change this component."),
+ grecs_type_section, GRECS_DFLT,
+ NULL, offsetof (struct component, adm_acl),
+ acl_section_parser, NULL, acl_keywords},
{"access-denied-message",
NULL,
N_("Text to send back if access is denied (inetd-components only)."),
@@ -1541,16 +1553,22 @@ struct grecs_keyword control_keywords[] = {
grecs_type_string, GRECS_DFLT,
&control.url, 0, _cb_url},
{"acl",
- N_("name: string"),
+ NULL,
N_("Set connection ACL."),
grecs_type_section, GRECS_DFLT,
&control.conn_acl, 0,
acl_section_parser, NULL, acl_keywords},
- {"identity-acl",
- N_("name: string"),
- N_("Set identity ACL."),
+ {"admin-acl",
+ NULL,
+ N_("Administrative access"),
+ grecs_type_section, GRECS_DFLT,
+ &control.adm_acl, 0,
+ acl_section_parser, NULL, acl_keywords},
+ {"user-acl",
+ NULL,
+ N_("User access"),
grecs_type_section, GRECS_DFLT,
- &control.id_acl, 0,
+ &control.usr_acl, 0,
acl_section_parser, NULL, acl_keywords},
{"idle-timeout",
"n",
@@ -1722,7 +1740,7 @@ struct grecs_keyword pies_keywords[] = {
&default_component, 0,
return_code_section_parser, NULL, return_code_keywords},
{"acl",
- N_("name: string"),
+ NULL,
N_("Set global ACL."),
grecs_type_section, GRECS_DFLT,
&pies_acl, 0,
diff --git a/src/pies.h b/src/pies.h
index 69d324d..cc28c69 100644
--- a/src/pies.h
+++ b/src/pies.h
@@ -242,7 +242,7 @@ struct component
(if mode == pies_comp_pass_fd) */
unsigned pass_fd_timeout; /* Maximum time to wait for pass_fd socket to
become available. */
- pies_acl_t acl;
+ pies_acl_t acl; /* Connection ACL */
char *tcpmux; /* Master service for TCPMUX */
/* Optional error messages to be sent back on the socket: */
@@ -256,6 +256,9 @@ struct component
/* Actions to execute on various exit codes: */
struct action *act_head, *act_tail;
struct action act_temp; /* Auxiliary object used during configuration */
+ /* ACLs for control interface */
+ pies_acl_t list_acl; /* List access control list */
+ pies_acl_t adm_acl; /* Administrative ACL (stop, start, etc.) */
};
#define is_sysvinit(cp) ((cp)->mode >= pies_mark_sysvinit || (cp)->runlevels)
@@ -562,10 +565,11 @@ void sysvinit_acct (int what, const char *user, const char *id, pid_t pid,
/* ctl.c */
struct control
{
- struct pies_url *url;
- pies_acl_t conn_acl;
- pies_acl_t id_acl;
- unsigned int idle_timeout;
+ struct pies_url *url; /* Control socket URL */
+ pies_acl_t conn_acl; /* Connection ACL */
+ pies_acl_t adm_acl; /* Administrative ACL */
+ pies_acl_t usr_acl; /* User ACL */
+ unsigned int idle_timeout; /* Session idle timeout */
};
extern struct control control;

Return to:

Send suggestions and report system problems to the System administrator.