diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ctl.c | 291 | ||||
-rw-r--r-- | src/pies.c | 34 | ||||
-rw-r--r-- | src/pies.h | 14 |
3 files changed, 233 insertions, 106 deletions
@@ -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 @@ -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, @@ -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; |