1 /* MODULE: auth_pam */
2
3 /* COPYRIGHT
4 * Copyright (c) 2000 Fabian Knittel. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
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.
13 *
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
17 * distribution.
18 *
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.
23 *
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
34 * DAMAGE.
35 * END COPYRIGHT */
36
37 /*
38 * Pluggable Authentication Modules, PAM(8), based authentication module
39 * for saslauthd.
40 *
41 * Written by Fabian Knittel <fknittel@gmx.de>. Original implementation
42 * Debian's pwcheck_pam daemon by Michael-John Turner <mj@debian.org>.
43 */
44
45 /* PUBLIC DEPENDENCIES */
46 #include "mechanisms.h"
47 #include <stdio.h>
48
49 #ifdef HAVE_CONFIG_H
50 #include <config.h>
51 #endif
52
53 #ifdef AUTH_PAM
54
55 # include <string.h>
56 # include <syslog.h>
57 # include <security/pam_appl.h>
58 # include "auth_pam.h"
59 /* END PUBLIC DEPENDENCIES */
60
61
62 /* Structure for application specific data passed through PAM
63 * to our conv call-back routine saslauthd_pam_conv. */
64 typedef struct {
65 const char *login; /* plaintext authenticator */
66 const char *password; /* plaintext password */
67 pam_handle_t *pamh; /* pointer to PAM handle */
68 } pam_appdata;
69
70 # define RETURN(x) return strdup(x)
71
72
73 /* FUNCTION: saslauthd_pam_conv */
74
75 /* SYNOPSIS
76 * Call-back function used by the PAM library to communicate with us. Each
77 * received message expects a response, pointed to by resp.
78 * END SYNOPSIS */
79
80 static int /* R: PAM return code */
saslauthd_pam_conv(int num_msg,const struct pam_message ** msg,struct pam_response ** resp,void * appdata_ptr)81 saslauthd_pam_conv (
82 /* PARAMETERS */
83 int num_msg, /* I: number of messages */
84 const struct pam_message **msg, /* I: pointer to array of messages */
85 struct pam_response **resp, /* O: pointer to pointer of response */
86 void *appdata_ptr /* I: pointer to app specific data */
87 /* END PARAMETERS */
88 )
89 {
90 /* VARIABLES */
91 pam_appdata *my_appdata; /* application specific data */
92 struct pam_response *my_resp; /* response created by this func */
93 int i; /* loop counter */
94 const char *login_prompt; /* string prompting for user-name */
95 int rc; /* return code holder */
96 /* END VARIABLES */
97
98 my_appdata = appdata_ptr;
99
100 my_resp = malloc(sizeof(struct pam_response) * num_msg);
101 if (my_resp == NULL)
102 return PAM_CONV_ERR;
103
104 for (i = 0; i < num_msg; i++)
105 switch (msg[i]->msg_style) {
106 /*
107 * We assume PAM_PROMPT_ECHO_OFF to be a request for password.
108 * This assumption might be unsafe.
109 *
110 * For PAM_PROMPT_ECHO_ON we first check whether the provided
111 * request string matches PAM_USER_PROMPT and, only if they do
112 * match, assume it to be a request for the login.
113 */
114 case PAM_PROMPT_ECHO_OFF: /* password */
115 my_resp[i].resp = strdup(my_appdata->password);
116 if (my_resp[i].resp == NULL) {
117 syslog(LOG_DEBUG, "DEBUG: saslauthd_pam_conv: strdup failed");
118 goto ret_error;
119 }
120 my_resp[i].resp_retcode = PAM_SUCCESS;
121 break;
122
123 case PAM_PROMPT_ECHO_ON: /* username? */
124 /* Recheck setting each time, as it might have been changed
125 in the mean-while. */
126 rc = pam_get_item(my_appdata->pamh, PAM_USER_PROMPT,
127 (void *) &login_prompt);
128 if (rc != PAM_SUCCESS) {
129 syslog(LOG_DEBUG, "DEBUG: saslauthd_pam_conv: unable to read "
130 "login prompt string: %s",
131 pam_strerror(my_appdata->pamh, rc));
132 goto ret_error;
133 }
134
135 if (strcmp(msg[i]->msg, login_prompt) == 0) {
136 my_resp[i].resp = strdup(my_appdata->login);
137 my_resp[i].resp_retcode = PAM_SUCCESS;
138 } else { /* ignore */
139 syslog(LOG_DEBUG, "DEBUG: saslauthd_pam_conv: unknown prompt "
140 "string: %s", msg[i]->msg);
141 my_resp[i].resp = NULL;
142 my_resp[i].resp_retcode = PAM_SUCCESS;
143 }
144 break;
145
146 case PAM_ERROR_MSG: /* ignore */
147 case PAM_TEXT_INFO: /* ignore */
148 my_resp[i].resp = NULL;
149 my_resp[i].resp_retcode = PAM_SUCCESS;
150 break;
151
152 default: /* error */
153 goto ret_error;
154 }
155 *resp = my_resp;
156 return PAM_SUCCESS;
157
158 ret_error:
159 /*
160 * Free response structure. Don't free my_resp[i], as that
161 * isn't initialised yet.
162 */
163 {
164 int y;
165
166 for (y = 0; y < i; y++)
167 if (my_resp[y].resp != NULL)
168 free(my_resp[y].resp);
169 free(my_resp);
170 }
171 return PAM_CONV_ERR;
172 }
173
174 /* END FUNCTION: saslauthd_pam_conv */
175
176 /* FUNCTION: auth_pam */
177
178 char * /* R: allocated response string */
auth_pam(const char * login,const char * password,const char * service,const char * realm)179 auth_pam (
180 /* PARAMETERS */
181 const char *login, /* I: plaintext authenticator */
182 const char *password, /* I: plaintext password */
183 const char *service, /* I: service name */
184 const char *realm __attribute__((unused))
185 /* END PARAMETERS */
186 )
187 {
188 /* VARIABLES */
189 pam_appdata my_appdata; /* application specific data */
190 struct pam_conv my_conv; /* pam conversion data */
191 pam_handle_t *pamh; /* pointer to PAM handle */
192 int rc; /* return code holder */
193 /* END VARIABLES */
194
195 my_appdata.login = login;
196 my_appdata.password = password;
197 my_appdata.pamh = NULL;
198
199 my_conv.conv = saslauthd_pam_conv;
200 my_conv.appdata_ptr = &my_appdata;
201
202 rc = pam_start(service, login, &my_conv, &pamh);
203 if (rc != PAM_SUCCESS) {
204 syslog(LOG_DEBUG, "DEBUG: auth_pam: pam_start failed: %s",
205 pam_strerror(pamh, rc));
206 RETURN("NO PAM start error");
207 }
208
209 my_appdata.pamh = pamh;
210
211 rc = pam_authenticate(pamh, PAM_SILENT);
212 if (rc != PAM_SUCCESS) {
213 syslog(LOG_DEBUG, "DEBUG: auth_pam: pam_authenticate failed: %s",
214 pam_strerror(pamh, rc));
215 pam_end(pamh, rc);
216 RETURN("NO PAM auth error");
217 }
218
219 rc = pam_acct_mgmt(pamh, PAM_SILENT);
220 if (rc != PAM_SUCCESS) {
221 syslog(LOG_DEBUG, "DEBUG: auth_pam: pam_acct_mgmt failed: %s",
222 pam_strerror(pamh, rc));
223 pam_end(pamh, rc);
224 RETURN("NO PAM acct error");
225 }
226
227 pam_end(pamh, PAM_SUCCESS);
228 RETURN("OK");
229 }
230
231 /* END FUNCTION: auth_pam */
232
233 #else /* !AUTH_PAM */
234
235 char *
auth_pam(const char * login,const char * password,const char * service,const char * realm)236 auth_pam(
237 const char *login __attribute__((unused)),
238 const char *password __attribute__((unused)),
239 const char *service __attribute__((unused)),
240 const char *realm __attribute__((unused))
241 )
242 {
243 return NULL;
244 }
245
246 #endif /* !AUTH_PAM */
247
248 /* END MODULE: auth_pam */
249