6 * the following code is stolen from imap-uw PAM authentication module and
9 #define COPY_STRING(s) (s ? strdup(s) : NULL)
12 const char *uname; /* user name */
13 const char *pass; /* password */
15 typedef struct cred_t cred_t;
18 auth_conv(int num_msg, const struct pam_message **msg,
19 struct pam_response **resp, void *appdata)
22 cred_t *cred = (cred_t *) appdata;
23 struct pam_response *reply;
25 reply = calloc(num_msg, sizeof *reply);
29 for (i = 0; i < num_msg; i++) {
30 switch (msg[i]->msg_style) {
31 case PAM_PROMPT_ECHO_ON: /* assume want user name */
32 reply[i].resp_retcode = PAM_SUCCESS;
33 reply[i].resp = COPY_STRING(cred->uname);
36 case PAM_PROMPT_ECHO_OFF: /* assume want password */
37 reply[i].resp_retcode = PAM_SUCCESS;
38 reply[i].resp = COPY_STRING(cred->pass);
43 reply[i].resp_retcode = PAM_SUCCESS;
46 default: /* unknown message style */
57 * Attempt to authenticate the user using PAM. Returns 0 if the user is
58 * authenticated, or 1 if not authenticated. If some sort of PAM system
59 * error occurs (e.g., the "/etc/pam.conf" file is missing) then this
60 * function returns -1. This can be used as an indication that we should
61 * fall back to a different authentication mechanism.
64 auth_pam(struct passwd **ppw, const char *pass)
66 pam_handle_t *pamh = NULL;
67 const char *tmpl_user;
71 cred_t auth_cred = { (*ppw)->pw_name, pass };
72 struct pam_conv conv = { &auth_conv, &auth_cred };
74 e = pam_start("ftpd", (*ppw)->pw_name, &conv, &pamh);
75 if (e != PAM_SUCCESS) {
76 syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, e));
80 e = pam_set_item(pamh, PAM_RHOST, remotehost);
81 if (e != PAM_SUCCESS) {
82 syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s",
83 pam_strerror(pamh, e));
87 e = pam_authenticate(pamh, 0);
91 * With PAM we support the concept of a "template"
92 * user. The user enters a login name which is
93 * authenticated by PAM, usually via a remote service
94 * such as RADIUS or TACACS+. If authentication
95 * succeeds, a different but related "template" name
96 * is used for setting the credentials, shell, and
97 * home directory. The name the user enters need only
98 * exist on the remote authentication server, but the
99 * template name must be present in the local password
102 * This is supported by two various mechanisms in the
103 * individual modules. However, from the application's
104 * point of view, the template user is always passed
105 * back as a changed value of the PAM_USER item.
107 if ((e = pam_get_item(pamh, PAM_USER, &item)) ==
109 tmpl_user = (const char *) item;
110 if (strcmp((*ppw)->pw_name, tmpl_user) != 0)
111 *ppw = getpwnam(tmpl_user);
113 syslog(LOG_ERR, "Couldn't get PAM_USER: %s",
114 pam_strerror(pamh, e));
119 case PAM_USER_UNKNOWN:
125 syslog(LOG_ERR, "pam_authenticate: %s", pam_strerror(pamh, e));
131 e = pam_acct_mgmt(pamh, 0);
132 if (e == PAM_NEW_AUTHTOK_REQD) {
133 e = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
134 if (e != PAM_SUCCESS) {
135 syslog(LOG_ERR, "pam_chauthtok: %s",
136 pam_strerror(pamh, e));
139 } else if (e != PAM_SUCCESS) {
145 if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
146 syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));