diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2015-12-16 14:58:07 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2015-12-16 14:58:07 +0200 |
commit | 6bb908898b833ec69c66e918de732af5bad68934 (patch) | |
tree | dd715a052f67849d38aedaa25eafa93241e938df /src | |
parent | 9cb7455b12462a3679ed5208540793d802570481 (diff) | |
download | pies-6bb908898b833ec69c66e918de732af5bad68934.tar.gz pies-6bb908898b833ec69c66e918de732af5bad68934.tar.bz2 |
Implement authentication on control socket.
* Makefile.am (SUBDIRS): Add src.
* configure.ac: Check for crypt.h and PAM
Build ident/Makefile
* grecs: Update.
* ident/Makefile.am: New file.
* ident/ident.c: New file.
* ident/ident.h: New file.
* ident/identity.h: New file.
* ident/pam.c: New file.
* ident/provider.c: New file.
* ident/system.c: New file.
* lib/Makefile.am: Add arraymember.c
* lib/arraymember.c: New file.
* lib/libpies.h (is_array_member): New proto.
* src/Makefile.am (LDADD): Add libident.a and @PAM_LIBS@
* src/acl.c (acl_entry): Remove groups. Add new members:
names and name_match.
(pies_acl_create): Deep copy the locus.
Set free_entry function for the list.
(pies_acl_free): Free locus.
(_parse_from): Set free_entry function for the list.
(_parse_group): Parse the "user" construct.
(parse_acl_line): Deep copy the locus.
Allow for null value.
(acl_keywords): Update docstrings.
(_acl_check): Rewrite identity checks.
* src/acl.h (acl_input)<user,groups>: Remove.
<identity>: New member.
(pies_acl_free): New proto.
* src/ctl.c (identity): New global.
(cmdtab): New command: auth
(ctlio) <addr,addrlen>: New members.
(ctlio_create): Start from authenticated state
only if no identity_providers are configured.
(cmd_auth): New function.
(cmd_help): Print only commands that are available
in the current state.
(ctl_accept): Initialize io->addr and io->addrlen.
* src/inetd-bi.c: Change call to check_acl
* src/pies.c: Include identity.h
(control_keywords): New statement "identity-acl"
(pies_keywords): New statement "identity-provider"
(config_init): Register identity mechanisms.
(config_parse): New function.
(config_help): Print help on identity-provider
statements.
(main): Use config_parse to parse grecs-style configurations.
* src/pies.h: Include identity.h
(check_acl): Change argument list. All callers changed.
(control): Remove acl. Add conn_acl and id_acl instead.
* src/progman.c (check_acl): Change argument list. Take
identity as the 3rd argument.
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 5 | ||||
-rw-r--r-- | src/acl.c | 164 | ||||
-rw-r--r-- | src/acl.h | 4 | ||||
-rw-r--r-- | src/ctl.c | 68 | ||||
-rw-r--r-- | src/inetd-bi.c | 2 | ||||
-rw-r--r-- | src/pies.c | 63 | ||||
-rw-r--r-- | src/pies.h | 7 | ||||
-rw-r--r-- | src/progman.c | 10 |
8 files changed, 248 insertions, 75 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 04634c7..ab4546f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -62,2 +62,3 @@ cmdline.h: cmdline.opt LDADD = \ + ../ident/libident.a\ ../lib/libpies.a\ @@ -65,3 +66,4 @@ LDADD = \ ../gnu/libgnu.a\ - $(MF_PROCTITLE_LIBS) + $(MF_PROCTITLE_LIBS)\ + @PAM_LIBS@ @@ -71,2 +73,3 @@ AM_CPPFLAGS=\ -I$(top_srcdir)/lib\ + -I$(top_srcdir)/ident\ -I$(top_srcdir)/gnu\ @@ -35,2 +35,9 @@ struct pies_sockaddr +enum name_match + { + match_none, + match_user_name, + match_group_name + }; + struct acl_entry @@ -41,3 +48,4 @@ struct acl_entry pies_acl_t acl; - struct grecs_list *groups; + enum name_match name_match; + char **names; struct grecs_list *sockaddrs; @@ -55,2 +63,48 @@ struct pies_acl /* ACL creation */ +void +grecs_locus_point_copy (struct grecs_locus_point *dst, + struct grecs_locus_point *src) +{ + dst->file = grecs_strdup (src->file); + dst->line = src->line; + dst->col = src->col; +} + +void +grecs_locus_copy (struct grecs_locus *dst, struct grecs_locus *src) +{ + grecs_locus_point_copy (&dst->beg, &src->beg); + grecs_locus_point_copy (&dst->end, &src->end); +} + +void +grecs_locus_point_free (struct grecs_locus_point *p) +{ + grecs_free (p->file); +} + +void +grecs_locus_free (struct grecs_locus *loc) +{ + grecs_locus_point_free (&loc->beg); + grecs_locus_point_free (&loc->end); +} + +static void +acl_free_entry (void *p) +{ + struct acl_entry *ent = p; + pies_acl_free (ent->acl); + grecs_locus_free (&ent->locus); + grecs_list_free (ent->sockaddrs); + if (ent->names) + { + size_t i; + + for (i = 0; ent->names[i]; i++) + free (ent->names[i]); + free (ent->names); + } + free (ent); +} @@ -61,4 +115,5 @@ pies_acl_create (const char *name, grecs_locus_t *locus) acl->name = name ? xstrdup (name) : NULL; - acl->locus = *locus; + grecs_locus_copy (&acl->locus, locus); acl->list = grecs_list_create (); + acl->list->free_entry = acl_free_entry; return acl; @@ -70,2 +125,3 @@ pies_acl_free (pies_acl_t acl) free (acl->name); + grecs_locus_free (&acl->locus); grecs_list_free (acl->list); @@ -198,2 +254,8 @@ _parse_sockaddr (struct acl_entry *entry, const grecs_value_t *value) +static void +sockaddr_free (void *p) +{ + free (p); +} + static int @@ -225,2 +287,3 @@ _parse_from (struct acl_entry *entry, size_t argc, grecs_value_t **argv) entry->sockaddrs = grecs_list_create (); + entry->sockaddrs->free_entry = sockaddr_free; if (argv[0]->type == GRECS_TYPE_STRING) @@ -290,2 +353,9 @@ _parse_group (struct acl_entry *entry, size_t argc, grecs_value_t **argv) if (strcmp (argv[0]->v.string, "group") == 0) + entry->name_match = match_group_name; + else if (strcmp (argv[0]->v.string, "user") == 0) + entry->name_match = match_user_name; + else + entry->name_match = match_none; + + if (entry->name_match != match_none) { @@ -296,3 +366,3 @@ _parse_group (struct acl_entry *entry, size_t argc, grecs_value_t **argv) grecs_error (&entry->locus, 0, - _("expected group list, but found end of statement")); + _("expected identity list, but found end of statement")); return 1; @@ -301,7 +371,16 @@ _parse_group (struct acl_entry *entry, size_t argc, grecs_value_t **argv) { - entry->groups = grecs_list_create (); - grecs_list_append (entry->groups, xstrdup (argv[0]->v.string)); + entry->names = xcalloc (2, sizeof (entry->names[0])); + entry->names[0] = xstrdup (argv[0]->v.string); + entry->names[1] = NULL; } else - entry->groups = argv[0]->v.list; + { + size_t i; + struct grecs_list_entry *ep; + entry->names = xcalloc (argv[0]->v.list->count + 1, + sizeof (entry->names[0])); + for (i = 0, ep = argv[0]->v.list->head; ep; ep = ep->next, ++i) + entry->names[i] = xstrdup (ep->data); + entry->names[i] = NULL; + } argc--; @@ -329,25 +408,26 @@ parse_acl_line (grecs_locus_t *locus, int allow, pies_acl_t acl, - entry->locus = *locus; + grecs_locus_copy (&entry->locus, locus); entry->allow = allow; - switch (value->type) - { - case GRECS_TYPE_STRING: - if (_parse_token (entry, value)) - { - grecs_error (&entry->locus, 0, _("unknown word `%s'"), - value->v.string); + if (value) + switch (value->type) + { + case GRECS_TYPE_STRING: + if (_parse_token (entry, value)) + { + grecs_error (&entry->locus, 0, _("unknown word `%s'"), + value->v.string); + return 1; + } + break; + + case GRECS_TYPE_ARRAY: + if (_parse_acl (entry, value->v.arg.c, value->v.arg.v)) return 1; - } - break; - - case GRECS_TYPE_ARRAY: - if (_parse_acl (entry, value->v.arg.c, value->v.arg.v)) + break; + + case GRECS_TYPE_LIST: + grecs_error (locus, 0, _("unexpected list")); return 1; - break; - - case GRECS_TYPE_LIST: - grecs_error (locus, 0, _("unexpected list")); - return 1; - } + } grecs_list_append (acl->list, entry); @@ -482,3 +562,3 @@ struct grecs_keyword acl_keywords[] = { /* TRANSLATORS: only words within angle brackets are translatable */ - { "allow", N_("[all|authenticated|group <grp: list>] [from <addr: list>]"), + { "allow", N_("[all|authenticated|user <usr: list>|group <grp: list>] [from <addr: list>]"), N_("Allow access"), @@ -487,3 +567,3 @@ struct grecs_keyword acl_keywords[] = { /* TRANSLATORS: only words within angle brackets are translatable */ - { "deny", N_("[all|authenticated|group <grp: list>] [from <addr: list>]"), + { "deny", N_("[all|authenticated|user <usr: list>|group <grp: list>] [from <addr: list>]"), N_("Deny access"), @@ -536,11 +616,2 @@ _check_sockaddr (struct pies_sockaddr *sptr, struct acl_input *input) static int -match_group (const char **groups, const char *arg) -{ - for (; *groups; groups++) - if (strcmp (*groups, arg) == 0) - return 1; - return 0; -} - -static int _acl_check (struct acl_entry *ent, struct acl_input *input) @@ -551,3 +622,3 @@ _acl_check (struct acl_entry *ent, struct acl_input *input) { - result = input->user != NULL; + result = input->identity != NULL; if (!result) @@ -556,8 +627,15 @@ _acl_check (struct acl_entry *ent, struct acl_input *input) - if (ent->groups) + switch (ent->name_match) { - struct grecs_list_entry *ep; + case match_none: + break; - for (ep = ent->groups->head; result && ep; ep = ep->next) - result = match_group (input->groups, ep->data); + case match_user_name: + result = pies_identity_is_user (input->identity, ent->names); + if (!result) + return result; + break; + + case match_group_name: + result = pies_identity_is_group_member (input->identity, ent->names); if (!result) @@ -648,3 +726,3 @@ acl_copy (void *a, void *b) static void -acl_free_entry (void *p) +acl_free (void *p) { @@ -666,3 +744,3 @@ pies_acl_install (pies_acl_t acl) NULL, - acl_free_entry); + acl_free); if (!acl_table) @@ -23,4 +23,3 @@ struct acl_input socklen_t addrlen; - const char *user; - const char **groups; + pies_identity_t identity; }; @@ -28,2 +27,3 @@ struct acl_input pies_acl_t pies_acl_create (const char *name, grecs_locus_t *locus); +void pies_acl_free (pies_acl_t acl); int pies_acl_check (pies_acl_t acl, struct acl_input *input, int result); @@ -19,2 +19,3 @@ #include "xvasprintf.h" +#include "identity.h" @@ -24,2 +25,4 @@ struct control control; +pies_identity_t identity; + @@ -109,2 +112,3 @@ struct ctlio; +static void cmd_auth (struct ctlio *, size_t, char **); static void cmd_quit (struct ctlio *, size_t, char **); @@ -131,2 +135,4 @@ struct ctlio_command static struct ctlio_command cmdtab[] = { + { "auth", "authenticate", + CTL_INITIAL_STATE, 3, 3, cmd_auth }, { "noop", "no operation", @@ -169,2 +175,4 @@ struct ctlio { + union pies_sockaddr_storage addr; + socklen_t addrlen; int state; @@ -183,3 +191,4 @@ ctlio_create (void) io = xmalloc (sizeof (*io)); - io->state = CTL_AUTHENTICATED_STATE; //FIXME CTL_INITIAL_STATE; + io->state = identity_provider_list + ? CTL_INITIAL_STATE : CTL_AUTHENTICATED_STATE; io->action = ACTION_CONT; @@ -310,3 +319,2 @@ ctlio_initial_reply (struct ctlio *io) ctlio_printf (io, "220 %s", instance); - ctlio_printf (io, " <%s>", "foobarbaz"); //FIXME: auth mechanisms @@ -316,2 +324,47 @@ ctlio_initial_reply (struct ctlio *io) 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; + + for (ep = identity_provider_list->head; ep; ep = ep->next) + { + pies_identity_provider_t provider = ep->data; + char const *pname = pies_identity_provider_name (provider); + + 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)) + { + logmsg (LOG_AUTH, "%s authenticated via %s, but failed ACL check", + argv[1], pname); + auth = 0; + } + else + { + logmsg (LOG_AUTH, "%s authenticated via %s", + argv[1], pname); + auth = 1; + } + break; + } + } + + if (auth) + { + ctlio_reply (io, "230", "authentication successful"); + identity = id; + io->state = CTL_AUTHENTICATED_STATE; + } + else + { + pies_identity_destroy (id); + ctlio_reply (io, "531", "access denied"); + } +} + +static void cmd_noop (struct ctlio *io, size_t argc, char **argv) @@ -349,4 +402,7 @@ cmd_help (struct ctlio *io, size_t argc, char **argv) { - ctlio_printf (io, "%-9s%s", cp->verb, cp->descr); - ctlio_eol (io); + if (cp->states & io->state) + { + ctlio_printf (io, "%-9s%s", cp->verb, cp->descr); + ctlio_eol (io); + } } @@ -1002,3 +1058,3 @@ ctl_accept (int socket, void *data) - if (check_acl (control.acl, (struct sockaddr *)&addr, addrlen)) + if (check_acl (control.conn_acl, (struct sockaddr *)&addr, addrlen, NULL)) { @@ -1010,2 +1066,4 @@ ctl_accept (int socket, void *data) io = ctlio_create (); + io->addr = addr; + io->addrlen = addrlen; ctlio_initial_reply (io); diff --git a/src/inetd-bi.c b/src/inetd-bi.c index e472390..de9cfa0 100644 --- a/src/inetd-bi.c +++ b/src/inetd-bi.c @@ -359,3 +359,3 @@ tcpmux (int fd, struct component const *comp) - if (check_acl (comp->acl, (struct sockaddr *) &sa, salen)) + if (check_acl (comp->acl, (struct sockaddr *) &sa, salen, NULL)) { @@ -20,2 +20,3 @@ #include "meta1lex.h" +#include "identity.h" @@ -1543,5 +1544,11 @@ struct grecs_keyword control_keywords[] = { N_("name: string"), - N_("Set ACL."), + 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."), grecs_type_section, GRECS_DFLT, - &control.acl, 0, + &control.id_acl, 0, acl_section_parser, NULL, acl_keywords}, @@ -1762,2 +1769,4 @@ struct grecs_keyword pies_keywords[] = { }, + { "identity-provider", "name: string", "Configure identity provider", + grecs_type_section, GRECS_INAC | GRECS_HIDDEN }, {NULL} @@ -1777,2 +1786,35 @@ config_init () } + pies_identity_mechanism_register (&system_identity_mechanism); +#ifdef WITH_PAM + pies_identity_mechanism_register (&pam_identity_mechanism); +#endif +} + +static void +config_error () +{ + if (!init_process) + exit (EX_CONFIG); +} + +void +config_parse (char const *name) +{ + struct grecs_node *node; + struct grecs_node *tree = grecs_parse (name); + if (!tree) + config_error (); + + for (node = tree; node; node = node->next) + { + node = grecs_find_node (node, "identity-provider"); + if (!node) + break; + pies_config_provider (node); + } + + if (grecs_tree_process (tree, pies_keywords)) + config_error (); + + grecs_tree_free (tree); } @@ -1788,2 +1830,3 @@ config_help () grecs_print_statement_array (pies_keywords, 1, 0, stdout); + pies_config_identity_mechanisms_help (); } @@ -2243,9 +2286,2 @@ set_state_file_names (const char *base) -static void -config_error () -{ - if (!init_process) - exit (EX_CONFIG); -} - int @@ -2369,9 +2405,4 @@ main (int argc, char **argv) case CONF_PIES: - { - struct grecs_node *tree = grecs_parse (file->name); - if (!tree || grecs_tree_process (tree, pies_keywords)) - config_error (); - grecs_tree_free (tree); - break; - } + config_parse (file->name); + break; @@ -60,2 +60,3 @@ +#include "identity.h" #include "acl.h" @@ -340,3 +341,4 @@ void fd_report (int fd, const char *msg); -int check_acl (pies_acl_t acl, struct sockaddr *s, socklen_t salen); +int check_acl (pies_acl_t acl, struct sockaddr *s, socklen_t salen, + pies_identity_t identity); @@ -563,3 +565,4 @@ struct control struct pies_url *url; - pies_acl_t acl; + pies_acl_t conn_acl; + pies_acl_t id_acl; unsigned int idle_timeout; diff --git a/src/progman.c b/src/progman.c index 12969ab..1ec5a8d 100644 --- a/src/progman.c +++ b/src/progman.c @@ -1303,3 +1303,4 @@ prog_start (struct prog *prog) int -check_acl (pies_acl_t acl, struct sockaddr *s, socklen_t salen) +check_acl (pies_acl_t acl, struct sockaddr *s, socklen_t salen, + pies_identity_t identity) { @@ -1313,4 +1314,3 @@ check_acl (pies_acl_t acl, struct sockaddr *s, socklen_t salen) input.addrlen = salen; - input.user = NULL; - input.groups = NULL; + input.identity = identity; @@ -1376,4 +1376,4 @@ _prog_accept (struct prog *p) - if (check_acl (p->v.p.comp->acl, (struct sockaddr *)&addr, addrlen) - || check_acl (pies_acl, (struct sockaddr *)&addr, addrlen)) + if (check_acl (p->v.p.comp->acl, (struct sockaddr *)&addr, addrlen, NULL) + || check_acl (pies_acl, (struct sockaddr *)&addr, addrlen, NULL)) { |