/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2002-2021 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
. */
#ifdef HAVE_CONFIG_H
# include
#endif
#include
#include
#include
#ifdef HAVE_SHADOW_H
# include
#endif
#include
#include
#include
#include
#ifdef HAVE_STRINGS_H
# include
#endif
#ifdef HAVE_SECURITY_PAM_APPL_H
# include
#endif
#ifdef HAVE_CRYPT_H
# include
#endif
#include
#include
#include
#include
#include
#include
char *mu_pam_service = PACKAGE;
#ifdef USE_LIBPAM
static struct mu_cfg_param mu_pam_param[] = {
{ "service", mu_c_string, &mu_pam_service, 0, NULL,
N_("Set PAM service name."),
N_("name") },
{ NULL }
};
#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
# define mu_pam_param NULL
# define mu_authenticate_pam NULL
#endif
struct mu_auth_module mu_auth_pam_module = {
.name = "pam",
.handler = { [mu_auth_authenticate] = mu_authenticate_pam },
.cfg = mu_pam_param
};