4 * Copyright (c) 2000 Fabian Knittel. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain any existing copyright
11 * notice, and this entire permission notice in its entirety,
12 * including the disclaimer of warranties.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
19 * 2. Redistributions in binary form must reproduce all prior and current
20 * copyright notices, this list of conditions, and the following
21 * disclaimer in the documentation and/or other materials provided
22 * with the distribution.
24 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
25 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
30 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
32 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
33 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
38 * Pluggable Authentication Modules, PAM(8), based authentication module
41 * Written by Fabian Knittel <fknittel@gmx.de>. Original implementation
42 * Debian's pwcheck_pam daemon by Michael-John Turner <mj@debian.org>.
45 /* PUBLIC DEPENDENCIES */
46 #include "mechanisms.h"
57 #ifdef HAVE_SECURITY_PAM_APPL_H
58 # include <security/pam_appl.h>
59 #elif defined(HAVE_PAM_PAM_APPL_H)
60 # include <pam/pam_appl.h>
63 # include "auth_pam.h"
64 /* END PUBLIC DEPENDENCIES */
67 /* Structure for application specific data passed through PAM
68 * to our conv call-back routine saslauthd_pam_conv. */
70 const char *login; /* plaintext authenticator */
71 const char *password; /* plaintext password */
72 pam_handle_t *pamh; /* pointer to PAM handle */
75 # define RETURN(x) return strdup(x)
78 /* FUNCTION: saslauthd_pam_conv */
81 * Call-back function used by the PAM library to communicate with us. Each
82 * received message expects a response, pointed to by resp.
85 static int /* R: PAM return code */
88 int num_msg, /* I: number of messages */
89 const struct pam_message **msg, /* I: pointer to array of messages */
90 struct pam_response **resp, /* O: pointer to pointer of response */
91 void *appdata_ptr /* I: pointer to app specific data */
96 pam_appdata *my_appdata; /* application specific data */
97 struct pam_response *my_resp; /* response created by this func */
98 int i; /* loop counter */
99 const char *login_prompt; /* string prompting for user-name */
100 int rc; /* return code holder */
103 my_appdata = appdata_ptr;
105 my_resp = malloc(sizeof(struct pam_response) * num_msg);
109 for (i = 0; i < num_msg; i++)
110 switch (msg[i]->msg_style) {
112 * We assume PAM_PROMPT_ECHO_OFF to be a request for password.
113 * This assumption might be unsafe.
115 * For PAM_PROMPT_ECHO_ON we first check whether the provided
116 * request string matches PAM_USER_PROMPT and, only if they do
117 * match, assume it to be a request for the login.
119 case PAM_PROMPT_ECHO_OFF: /* password */
120 my_resp[i].resp = strdup(my_appdata->password);
121 if (my_resp[i].resp == NULL) {
122 syslog(LOG_DEBUG, "DEBUG: saslauthd_pam_conv: strdup failed");
125 my_resp[i].resp_retcode = PAM_SUCCESS;
128 case PAM_PROMPT_ECHO_ON: /* username? */
129 /* Recheck setting each time, as it might have been changed
130 in the mean-while. */
131 rc = pam_get_item(my_appdata->pamh, PAM_USER_PROMPT,
132 (void *) &login_prompt);
133 if (rc != PAM_SUCCESS) {
134 syslog(LOG_DEBUG, "DEBUG: saslauthd_pam_conv: unable to read "
135 "login prompt string: %s",
136 pam_strerror(my_appdata->pamh, rc));
140 if (strcmp(msg[i]->msg, login_prompt) == 0) {
141 my_resp[i].resp = strdup(my_appdata->login);
142 my_resp[i].resp_retcode = PAM_SUCCESS;
143 } else { /* ignore */
144 syslog(LOG_DEBUG, "DEBUG: saslauthd_pam_conv: unknown prompt "
145 "string: %s", msg[i]->msg);
146 my_resp[i].resp = NULL;
147 my_resp[i].resp_retcode = PAM_SUCCESS;
151 case PAM_ERROR_MSG: /* ignore */
152 case PAM_TEXT_INFO: /* ignore */
153 my_resp[i].resp = NULL;
154 my_resp[i].resp_retcode = PAM_SUCCESS;
165 * Free response structure. Don't free my_resp[i], as that
166 * isn't initialised yet.
171 for (y = 0; y < i; y++)
172 if (my_resp[y].resp != NULL)
173 free(my_resp[y].resp);
179 /* END FUNCTION: saslauthd_pam_conv */
181 /* FUNCTION: auth_pam */
183 char * /* R: allocated response string */
186 const char *login, /* I: plaintext authenticator */
187 const char *password, /* I: plaintext password */
188 const char *service, /* I: service name */
189 const char *realm __attribute__((unused))
194 pam_appdata my_appdata; /* application specific data */
195 struct pam_conv my_conv; /* pam conversion data */
196 pam_handle_t *pamh; /* pointer to PAM handle */
197 int rc; /* return code holder */
200 my_appdata.login = login;
201 my_appdata.password = password;
202 my_appdata.pamh = NULL;
204 my_conv.conv = saslauthd_pam_conv;
205 my_conv.appdata_ptr = &my_appdata;
207 rc = pam_start(service, login, &my_conv, &pamh);
208 if (rc != PAM_SUCCESS) {
209 syslog(LOG_DEBUG, "DEBUG: auth_pam: pam_start failed: %s",
210 pam_strerror(pamh, rc));
211 RETURN("NO PAM start error");
214 my_appdata.pamh = pamh;
216 rc = pam_authenticate(pamh, PAM_SILENT);
217 if (rc != PAM_SUCCESS) {
218 syslog(LOG_DEBUG, "DEBUG: auth_pam: pam_authenticate failed: %s",
219 pam_strerror(pamh, rc));
221 RETURN("NO PAM auth error");
224 rc = pam_acct_mgmt(pamh, PAM_SILENT);
225 if (rc != PAM_SUCCESS) {
226 syslog(LOG_DEBUG, "DEBUG: auth_pam: pam_acct_mgmt failed: %s",
227 pam_strerror(pamh, rc));
229 RETURN("NO PAM acct error");
232 pam_end(pamh, PAM_SUCCESS);
236 /* END FUNCTION: auth_pam */
238 #else /* !AUTH_PAM */
242 const char *login __attribute__((unused)),
243 const char *password __attribute__((unused)),
244 const char *service __attribute__((unused)),
245 const char *realm __attribute__((unused))
251 #endif /* !AUTH_PAM */
253 /* END MODULE: auth_pam */