deal with allocation size of 0 in prs_unistr when UNMARSHALLING
[Samba.git] / source / nsswitch / pam_winbind.c
blobece504411b35b6f550eac34faff54b4d6f4fb3d9
1 /* pam_winbind module
3 Copyright Andrew Tridgell <tridge@samba.org> 2000
5 largely based on pam_userdb by Christian Gafton <gafton@redhat.com>
6 */
8 #include <features.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <string.h>
12 #include <syslog.h>
13 #include <stdarg.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
17 #include <errno.h>
19 #define MODULE_NAME "pam_winbind"
20 #define PAM_SM_AUTH
21 #define PAM_SM_ACCOUNT
22 #include <security/pam_modules.h>
23 #include <security/_pam_macros.h>
25 #define PAM_DEBUG_ARG (1<<0)
26 #define PAM_USE_AUTHTOK_ARG (1<<1)
27 #define PAM_UNKNOWN_OK_ARG (1<<2)
29 #include "winbind_nss_config.h"
30 #include "winbindd_nss.h"
32 /* prototypes from common.c */
33 void init_request(struct winbindd_request *req,int rq_type);
34 int write_sock(void *buffer, int count);
35 int read_reply(struct winbindd_response *response);
37 /* some syslogging */
38 static void _pam_log(int err, const char *format, ...)
40 va_list args;
42 va_start(args, format);
43 openlog(MODULE_NAME, LOG_CONS|LOG_PID, LOG_AUTH);
44 vsyslog(err, format, args);
45 va_end(args);
46 closelog();
49 static int ctrl = 0;
51 static int _pam_parse(int argc, const char **argv)
53 /* step through arguments */
54 for (ctrl = 0; argc-- > 0; ++argv) {
56 /* generic options */
58 if (!strcmp(*argv,"debug"))
59 ctrl |= PAM_DEBUG_ARG;
60 else if (!strcasecmp(*argv, "use_authtok"))
61 ctrl |= PAM_USE_AUTHTOK_ARG;
62 else if (!strcasecmp(*argv, "unknown_ok"))
63 ctrl |= PAM_UNKNOWN_OK_ARG;
64 else {
65 _pam_log(LOG_ERR, "pam_parse: unknown option; %s", *argv);
69 return ctrl;
73 /* talk to winbindd */
74 static int winbind_request(int req_type, const char *user, const char *pass)
76 struct winbindd_request request;
77 struct winbindd_response response;
79 ZERO_STRUCT(request);
81 strncpy(request.data.auth.user, user, sizeof(request.data.auth.user)-1);
82 strncpy(request.data.auth.pass, pass, sizeof(request.data.auth.pass)-1);
84 /* Fill in request and send down pipe */
85 init_request(&request, req_type);
87 if (write_sock(&request, sizeof(request)) == -1) {
88 return -2;
91 /* Wait for reply */
92 if (read_reply(&response) == -1) {
93 return -2;
96 /* Copy reply data from socket */
97 if (response.result != WINBINDD_OK) {
98 return 1;
101 return 0;
105 * Looks up an user name and checks the password
107 * return values:
108 * 1 = User not found
109 * 0 = OK
110 * -1 = Password incorrect
111 * -2 = System error
113 static int user_lookup(const char *user, const char *pass)
115 return winbind_request(WINBINDD_PAM_AUTH, user, pass);
119 * Checks if a user has an account
121 * return values:
122 * 1 = User not found
123 * 0 = OK
124 * -1 = System error
126 static int valid_user(const char *user)
128 if (getpwnam(user)) return 0;
129 return 1;
132 /* --- authentication management functions --- */
135 * dummy conversation function sending exactly one prompt
136 * and expecting exactly one response from the other party
138 static int converse(pam_handle_t *pamh,
139 struct pam_message **message,
140 struct pam_response **response)
142 int retval;
143 struct pam_conv *conv;
145 retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv ) ;
146 if (retval == PAM_SUCCESS)
147 retval = conv->conv(1, (const struct pam_message **)message,
148 response, conv->appdata_ptr);
150 return retval; /* propagate error status */
154 static char *_pam_delete(register char *xx)
156 _pam_overwrite(xx);
157 _pam_drop(xx);
158 return NULL;
162 * This is a conversation function to obtain the user's password
164 static int conversation(pam_handle_t *pamh)
166 struct pam_message msg[2],*pmsg[2];
167 struct pam_response *resp;
168 int retval;
169 char * token;
171 pmsg[0] = &msg[0];
172 msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
173 msg[0].msg = "Password: ";
175 /* so call the conversation expecting i responses */
176 resp = NULL;
177 retval = converse(pamh, pmsg, &resp);
179 if (resp != NULL) {
180 char * const item;
181 /* interpret the response */
182 if (retval == PAM_SUCCESS) { /* a good conversation */
183 token = x_strdup(resp[0].resp);
184 if (token == NULL) {
185 return PAM_AUTHTOK_RECOVER_ERR;
189 /* set the auth token */
190 retval = pam_set_item(pamh, PAM_AUTHTOK, token);
191 token = _pam_delete(token); /* clean it up */
192 if ( (retval != PAM_SUCCESS) ||
193 (retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **) &item)) != PAM_SUCCESS ) {
194 return retval;
197 _pam_drop_reply(resp, 1);
198 } else {
199 retval = (retval == PAM_SUCCESS)
200 ? PAM_AUTHTOK_RECOVER_ERR:retval ;
203 return retval;
207 PAM_EXTERN
208 int pam_sm_authenticate(pam_handle_t *pamh, int flags,
209 int argc, const char **argv)
211 const char *username;
212 const char *password;
213 int retval = PAM_AUTH_ERR;
215 /* parse arguments */
216 ctrl = _pam_parse(argc, argv);
218 /* Get the username */
219 retval = pam_get_user(pamh, &username, NULL);
220 if ((retval != PAM_SUCCESS) || (!username)) {
221 if (ctrl & PAM_DEBUG_ARG)
222 _pam_log(LOG_DEBUG,"can not get the username");
223 return PAM_SERVICE_ERR;
226 if ((ctrl & PAM_USE_AUTHTOK_ARG) == 0) {
227 /* Converse just to be sure we have the password */
228 retval = conversation(pamh);
229 if (retval != PAM_SUCCESS) {
230 _pam_log(LOG_ERR, "could not obtain password for `%s'",
231 username);
232 return PAM_CONV_ERR;
236 /* Get the password */
237 retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **) &password);
238 if (retval != PAM_SUCCESS) {
239 _pam_log(LOG_ERR, "Could not retrive user's password");
240 return PAM_AUTHTOK_ERR;
243 if (ctrl & PAM_DEBUG_ARG)
244 _pam_log(LOG_INFO, "Verify user `%s' with password `%s'",
245 username, password);
247 /* Now use the username to look up password */
248 retval = user_lookup(username, password);
249 switch (retval) {
250 case -2:
251 /* some sort of system error. The log was already printed */
252 return PAM_SERVICE_ERR;
253 case -1:
254 /* incorrect password */
255 _pam_log(LOG_WARNING, "user `%s' denied access (incorrect password)", username);
256 return PAM_AUTH_ERR;
257 case 1:
258 /* the user does not exist */
259 if (ctrl & PAM_DEBUG_ARG)
260 _pam_log(LOG_NOTICE, "user `%s' not found",
261 username);
262 if (ctrl & PAM_UNKNOWN_OK_ARG) {
263 return PAM_IGNORE;
265 return PAM_USER_UNKNOWN;
266 case 0:
267 /* Otherwise, the authentication looked good */
268 _pam_log(LOG_NOTICE, "user '%s' granted acces", username);
269 return PAM_SUCCESS;
270 default:
271 /* we don't know anything about this return value */
272 _pam_log(LOG_ERR, "internal module error (retval = %d, user = `%s'",
273 retval, username);
274 return PAM_SERVICE_ERR;
276 /* should not be reached */
277 return PAM_IGNORE;
280 PAM_EXTERN
281 int pam_sm_setcred(pam_handle_t *pamh, int flags,
282 int argc, const char **argv)
284 return PAM_SUCCESS;
288 * Account management. We want to verify that the account exists
289 * before returning PAM_SUCCESS
291 PAM_EXTERN
292 int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
293 int argc, const char **argv)
295 const char *username;
296 int retval = PAM_USER_UNKNOWN;
298 /* parse arguments */
299 ctrl = _pam_parse(argc, argv);
301 /* Get the username */
302 retval = pam_get_user(pamh, &username, NULL);
303 if ((retval != PAM_SUCCESS) || (!username)) {
304 if (ctrl & PAM_DEBUG_ARG)
305 _pam_log(LOG_DEBUG,"can not get the username");
306 return PAM_SERVICE_ERR;
309 /* Verify the username */
310 retval = valid_user(username);
311 switch (retval) {
312 case -1:
313 /* some sort of system error. The log was already printed */
314 return PAM_SERVICE_ERR;
315 case 1:
316 /* the user does not exist */
317 if (ctrl & PAM_DEBUG_ARG)
318 _pam_log(LOG_NOTICE, "user `%s' not found",
319 username);
320 if (ctrl & PAM_UNKNOWN_OK_ARG)
321 return PAM_IGNORE;
322 return PAM_USER_UNKNOWN;
323 case 0:
324 /* Otherwise, the authentication looked good */
325 _pam_log(LOG_NOTICE, "user '%s' granted acces", username);
326 return PAM_SUCCESS;
327 default:
328 /* we don't know anything about this return value */
329 _pam_log(LOG_ERR, "internal module error (retval = %d, user = `%s'",
330 retval, username);
331 return PAM_SERVICE_ERR;
334 /* should not be reached */
335 return PAM_IGNORE;
339 #ifdef PAM_STATIC
341 /* static module data */
343 struct pam_module _pam_userdb_modstruct = {
344 MODULE_NAME,
345 pam_sm_authenticate,
346 pam_sm_setcred,
347 pam_sm_acct_mgmt,
348 NULL,
349 NULL,
350 NULL,
353 #endif
356 * Copyright (c) Andrew Tridgell <tridge@samba.org> 2000
358 * Redistribution and use in source and binary forms, with or without
359 * modification, are permitted provided that the following conditions
360 * are met:
361 * 1. Redistributions of source code must retain the above copyright
362 * notice, and the entire permission notice in its entirety,
363 * including the disclaimer of warranties.
364 * 2. Redistributions in binary form must reproduce the above copyright
365 * notice, this list of conditions and the following disclaimer in the
366 * documentation and/or other materials provided with the distribution.
367 * 3. The name of the author may not be used to endorse or promote
368 * products derived from this software without specific prior
369 * written permission.
371 * ALTERNATIVELY, this product may be distributed under the terms of
372 * the GNU Public License, in which case the provisions of the GPL are
373 * required INSTEAD OF the above restrictions. (This clause is
374 * necessary due to a potential bad interaction between the GPL and
375 * the restrictions contained in a BSD-style copyright.)
377 * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED
378 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
379 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
380 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
381 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
382 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
383 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
384 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
385 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
386 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
387 * OF THE POSSIBILITY OF SUCH DAMAGE.