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