/* GNU Mailutils -- a suite of utilities for electronic mail Copyright (C) 2002, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <http://www.gnu.org/licenses/>. */ #ifdef HAVE_CONFIG_H # include <config.h> #endif #include <unistd.h> #include <sys/types.h> #include <pwd.h> #ifdef HAVE_SHADOW_H # include <shadow.h> #endif #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #ifdef HAVE_STRINGS_H # include <strings.h> #endif #ifdef HAVE_SECURITY_PAM_APPL_H # include <security/pam_appl.h> #endif #ifdef HAVE_CRYPT_H # include <crypt.h> #endif #include <mailutils/list.h> #include <mailutils/errno.h> #include <mailutils/iterator.h> #include <mailutils/mailbox.h> #include <mailutils/mu_auth.h> #include <mailutils/nls.h> char *mu_pam_service = PACKAGE; #ifdef USE_LIBPAM #define COPY_STRING(s) (s) ? strdup(s) : NULL static char *_pwd; static char *_user; #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 mu_pam_conv (int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr MU_ARG_UNUSED) { int status = PAM_SUCCESS; int i; struct pam_response *reply = NULL; 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 (_user); /* PAM frees resp */ break; case PAM_PROMPT_ECHO_OFF: if (_pwd) { reply[i].resp_retcode = PAM_SUCCESS; reply[i].resp = COPY_STRING (_pwd); /* 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 struct pam_conv PAM_conversation = { &mu_pam_conv, NULL }; int mu_authenticate_pam (struct mu_auth_data **return_data MU_ARG_UNUSED, const void *key, void *func_data MU_ARG_UNUSED, void *call_data) { const struct mu_auth_data *auth_data = key; char *pass = call_data; pam_handle_t *pamh; int pamerror; #define PAM_ERROR if (pamerror != PAM_SUCCESS) goto pam_errlab; if (!auth_data) return EINVAL; _user = (char *) auth_data->name; _pwd = pass; pamerror = pam_start (mu_pam_service, _user, &PAM_conversation, &pamh); PAM_ERROR; pamerror = pam_authenticate (pamh, 0); PAM_ERROR; pamerror = pam_acct_mgmt (pamh, 0); PAM_ERROR; pamerror = pam_setcred (pamh, PAM_ESTABLISH_CRED); pam_errlab: pam_end (pamh, PAM_SUCCESS); switch (pamerror) { case PAM_SUCCESS: return 0; case PAM_AUTH_ERR: return MU_ERR_AUTH_FAILURE; } return MU_ERR_FAILURE; } #else int mu_authenticate_pam (struct mu_auth_data **return_data MU_ARG_UNUSED, const void *key MU_ARG_UNUSED, void *func_data MU_ARG_UNUSED, void *call_data MU_ARG_UNUSED) { return ENOSYS; } #endif int mu_pam_module_init (enum mu_gocs_op op, void *data) { if (op == mu_gocs_op_set && data) { struct mu_gocs_pam *p = data; mu_pam_service = p->service ? strdup (p->service) : p->service; } return 0; } struct mu_auth_module mu_auth_pam_module = { "pam", mu_pam_module_init, mu_authenticate_pam, NULL, mu_auth_nosupport, NULL, mu_auth_nosupport, NULL };