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 /ident/pam.c | |
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 'ident/pam.c')
-rw-r--r-- | ident/pam.c | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/ident/pam.c b/ident/pam.c new file mode 100644 index 0000000..ef32c4d --- /dev/null +++ b/ident/pam.c @@ -0,0 +1,230 @@ +/* This file is part of GNU Pies. + Copyright (C) 2015 Sergey Poznyakoff + + GNU Pies is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GNU Pies is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Pies. If not, see <http://www.gnu.org/licenses/>. */ + +#include "ident.h" +#include <grp.h> +#include <security/pam_appl.h> + +struct pam_identity_provider_data +{ + char *service; +}; + +struct pam_cred +{ + const char *user; + const char *pass; +}; + +#define COPY_STRING(s) (s) ? strdup(s) : NULL + +#define overwrite_and_free(ptr) \ + do { \ + char *s = ptr; \ + while (*s) \ + *s++ = 0; \ + } while (0) + +#ifndef PAM_AUTHTOK_RECOVER_ERR +# define PAM_AUTHTOK_RECOVER_ERR PAM_CONV_ERR +#endif + +static int +pies_conv (int num_msg, const struct pam_message **msg, + struct pam_response **resp, void *appdata_ptr) +{ + int status = PAM_SUCCESS; + int i; + struct pam_response *reply = NULL; + struct pam_cred *cred = appdata_ptr; + + reply = calloc (num_msg, sizeof (*reply)); + if (!reply) + return PAM_CONV_ERR; + + for (i = 0; i < num_msg && status == PAM_SUCCESS; i++) + { + switch (msg[i]->msg_style) + { + case PAM_PROMPT_ECHO_ON: + reply[i].resp_retcode = PAM_SUCCESS; + reply[i].resp = COPY_STRING (cred->user); + /* PAM frees resp */ + break; + + case PAM_PROMPT_ECHO_OFF: + if (cred->pass) + { + reply[i].resp_retcode = PAM_SUCCESS; + reply[i].resp = COPY_STRING (cred->pass); + /* PAM frees resp */ + } else + status = PAM_AUTHTOK_RECOVER_ERR; + break; + + case PAM_TEXT_INFO: + case PAM_ERROR_MSG: + reply[i].resp_retcode = PAM_SUCCESS; + reply[i].resp = NULL; + break; + + default: + status = PAM_CONV_ERR; + } + } + + if (status != PAM_SUCCESS) + { + for (i = 0; i < num_msg; i++) + if (reply[i].resp) + { + switch (msg[i]->msg_style) + { + case PAM_PROMPT_ECHO_ON: + case PAM_PROMPT_ECHO_OFF: + overwrite_and_free (reply[i].resp); + break; + + case PAM_ERROR_MSG: + case PAM_TEXT_INFO: + free (reply[i].resp); + } + } + free (reply); + } else + *resp = reply; + return status; +} + +static int +authenticate (pies_identity_provider_t provider, + pies_identity_t id, char const *passwd) +{ + struct pam_identity_provider_data *pamdata = provider->data; + pam_handle_t *pamh; + int pamerror; + struct pam_cred cred = { id->username, passwd }; + struct pam_conv pam_conv = { &pies_conv, &cred }; + char const *service = pamdata->service ? pamdata->service : "pies"; + + do + { + pamerror = pam_start (service, id->username, &pam_conv, &pamh); + if (pamerror != PAM_SUCCESS) + break; + + pamerror = pam_authenticate (pamh, 0); + if (pamerror != PAM_SUCCESS) + break; + + pamerror = pam_acct_mgmt (pamh, 0); + if (pamerror != PAM_SUCCESS) + break; + + pamerror = pam_setcred (pamh, PAM_ESTABLISH_CRED); + } + while (0); + + pam_end (pamh, PAM_SUCCESS); + + switch (pamerror) + { + case PAM_SUCCESS: + return 0; + + case PAM_AUTH_ERR: + return -1; + } + + //FIXME _log(L_ERR, 0, "PAM authentication error"); + return -1; +} + +static int +is_group_member (pies_identity_provider_t p, + pies_identity_t id, char * const * groups) +{ + struct group *gr; + int result = 0; + + setgrent (); + while ((gr = getgrent ())) + { + char **p; + + if (!is_array_member (groups, gr->gr_name)) + continue; + + for (p = gr->gr_mem; *p; p++) + if (strcmp (*p, id->username) == 0) + { + result = 1; + break; + } + } + endgrent (); + return result; +} + +static struct grecs_keyword pam_kw[] = { + { "type", "'pam", "Set mechanism type", grecs_type_null }, + { "service", NULL, "Service name", + grecs_type_string, GRECS_DFLT, NULL, + offsetof(struct pam_identity_provider_data, service) }, + { NULL } +}; + +static int +configure (struct grecs_node *node, pies_identity_provider_t provider) +{ + int i; + struct pam_identity_provider_data *data = xcalloc (1, sizeof (*data)); + provider->data = data; + for (i = 0; pam_kw[i].ident; i++) + pam_kw[i].varptr = data; + if (grecs_tree_process (node->down, pam_kw)) + { + //FIXME: memory leak + return -1; + } + provider->locus = node->locus; + return 0; +} + +static void +confhelp (void) +{ + static struct grecs_keyword top[] = { + { "identity-provider", "name: string", + "Configuration for system identity provider", + grecs_type_section, GRECS_INAC, NULL, 0, NULL, NULL, + pam_kw }, + { NULL } + }; + grecs_print_statement_array (top, 1, 0, stdout); +} + +struct pies_identity_mechanism pam_identity_mechanism = { + "pam", + authenticate, + is_group_member, + NULL, + configure, + confhelp +}; + + + |