1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
/* auth_pam.c
*
* Shamelessly slightly rewritten pamize.h from FreeBSD
*/
/* $FreeBSD: src/libexec/lukemftpd/pamize.h,v 1.1 2003/02/02 21:06:10 obrien Exp $ */
#ifndef lint
static const char * rcsid = "@(#) $Id: auth_pam.c,v 88c4f70961ac 2008/08/19 17:34:11 roberto $";
#endif
#include <config.h>
#include "conf.h"
#ifdef WITH_PAM
/*
* the following code is stolen from imap-uw PAM authentication module and
* login.c
*/
static int
auth_conv(int num_msg, const struct pam_message **msg,
struct pam_response **resp, void *appdata)
{
int i;
cred_t *cred = (cred_t *) appdata;
struct pam_response *reply;
reply = calloc(num_msg, sizeof *reply);
if (reply == NULL)
return PAM_BUF_ERR;
for (i = 0; i < num_msg; i++) {
switch (msg[i]->msg_style) {
case PAM_PROMPT_ECHO_ON: /* assume want user name */
reply[i].resp_retcode = PAM_SUCCESS;
reply[i].resp = COPY_STRING(cred->uname);
/* PAM frees resp. */
break;
case PAM_PROMPT_ECHO_OFF: /* assume want password */
reply[i].resp_retcode = PAM_SUCCESS;
reply[i].resp = COPY_STRING(cred->pass);
/* PAM frees resp. */
break;
case PAM_TEXT_INFO:
case PAM_ERROR_MSG:
reply[i].resp_retcode = PAM_SUCCESS;
reply[i].resp = NULL;
break;
default: /* unknown message style */
free(reply);
return PAM_CONV_ERR;
}
}
*resp = reply;
return PAM_SUCCESS;
}
/*
* Attempt to authenticate the user using PAM. Returns 0 if the user is
* authenticated, or 1 if not authenticated. If some sort of PAM system
* error occurs (e.g., the "/etc/pam.conf" file is missing) then this
* function returns -1. This can be used as an indication that we should
* fall back to a different authentication mechanism.
*/
int
auth_pam(struct passwd **ppw, const char *pass)
{
const char *tmpl_user;
const void *item;
int rval;
int e;
cred_t auth_cred = { (*ppw)->pw_name, pass };
struct pam_conv conv = { &auth_conv, &auth_cred };
e = pam_start("calife", (*ppw)->pw_name, &conv, &pamh);
if (e != PAM_SUCCESS) {
syslog(LOG_AUTH | LOG_ERR, "pam_start: %s", pam_strerror(pamh, e));
return -1;
}
MESSAGE_1("pam_start succeeded for %s\n", (*ppw)->pw_name);
/* pam_authenticate may require root privs to obtain shadow
password data */
GET_ROOT;
e = pam_authenticate(pamh, 0);
RELEASE_ROOT;
switch (e) {
case PAM_SUCCESS:
/*
* With PAM we support the concept of a "template"
* user. The user enters a login name which is
* authenticated by PAM, usually via a remote service
* such as RADIUS or TACACS+. If authentication
* succeeds, a different but related "template" name
* is used for setting the credentials, shell, and
* home directory. The name the user enters need only
* exist on the remote authentication server, but the
* template name must be present in the local password
* database.
*
* This is supported by two various mechanisms in the
* individual modules. However, from the application's
* point of view, the template user is always passed
* back as a changed value of the PAM_USER item.
*/
if ((e = pam_get_item(pamh, PAM_USER, &item)) == PAM_SUCCESS)
{
tmpl_user = (const char *) item;
if (strcmp((*ppw)->pw_name, tmpl_user) != 0)
*ppw = getpwnam(tmpl_user);
} else
syslog(LOG_AUTH | LOG_ERR, "Couldn't get PAM_USER: %s",
pam_strerror(pamh, e));
rval = 0;
break;
case PAM_AUTH_ERR:
case PAM_USER_UNKNOWN:
case PAM_MAXTRIES:
syslog(LOG_AUTH | LOG_ERR, "auth_pam: %s", pam_strerror(pamh, e));
rval = 1;
break;
default:
syslog(LOG_AUTH | LOG_ERR, "pam_authenticate: %s", pam_strerror(pamh,\
e));
rval = -1;
break;
}
/* XXX this does not work on solaris10 */
#ifndef solaris
if (rval == 0) {
e = pam_acct_mgmt(pamh, 0);
if (e == PAM_NEW_AUTHTOK_REQD) {
e = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
if (e != PAM_SUCCESS) {
syslog(LOG_AUTH | LOG_ERR, "pam_chauthtok: %s",
pam_strerror(pamh, e));
rval = 1;
}
} else if (e != PAM_SUCCESS) {
rval = 1;
}
}
#endif /* solaris */
MESSAGE_1 ("auth_pam returns %d\n", rval);
return rval;
}
#endif /* WITH_PAM */
|