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