preparing for release of 2.2.3a
[Samba.git] / source / nsswitch / pam_winbind.c
blob048140fd7906df312063ef48893efe598a748a6e
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 "pam_winbind.h"
10 /* prototypes from common.c */
11 void init_request(struct winbindd_request *req,int rq_type);
12 int write_sock(void *buffer, int count);
13 int read_reply(struct winbindd_response *response);
15 /* some syslogging */
16 static void _pam_log(int err, const char *format, ...)
18 va_list args;
20 va_start(args, format);
21 openlog(MODULE_NAME, LOG_CONS|LOG_PID, LOG_AUTH);
22 vsyslog(err, format, args);
23 va_end(args);
24 closelog();
27 static int ctrl = 0;
29 static int _pam_parse(int argc, const char **argv)
31 /* step through arguments */
32 for (ctrl = 0; argc-- > 0; ++argv) {
34 /* generic options */
36 if (!strcmp(*argv,"debug"))
37 ctrl |= PAM_DEBUG_ARG;
38 else if (!strcasecmp(*argv, "use_authtok"))
39 ctrl |= PAM_USE_AUTHTOK_ARG;
40 else if (!strcasecmp(*argv, "unknown_ok"))
41 ctrl |= PAM_UNKNOWN_OK_ARG;
42 else {
43 _pam_log(LOG_ERR, "pam_parse: unknown option; %s", *argv);
47 return ctrl;
50 static int winbind_request(enum winbindd_cmd req_type,
51 struct winbindd_request *request,
52 struct winbindd_response *response)
54 /* Fill in request and send down pipe */
55 init_request(request, req_type);
57 if (write_sock(request, sizeof(*request)) == -1) {
58 return -2;
61 /* Wait for reply */
62 if (read_reply(response) == -1) {
63 return -2;
66 /* Copy reply data from socket */
67 if (response->result != WINBINDD_OK) {
68 return 1;
71 return 0;
74 /* talk to winbindd */
75 static int winbind_auth_request(const char *user, const char *pass)
77 struct winbindd_request request;
78 struct winbindd_response response;
80 ZERO_STRUCT(request);
82 strncpy(request.data.auth.user, user,
83 sizeof(request.data.auth.user)-1);
85 strncpy(request.data.auth.pass, pass,
86 sizeof(request.data.auth.pass)-1);
88 return winbind_request(WINBINDD_PAM_AUTH, &request, &response);
91 /* talk to winbindd */
92 static int winbind_chauthtok_request(const char *user, const char *oldpass,
93 const char *newpass)
95 struct winbindd_request request;
96 struct winbindd_response response;
98 ZERO_STRUCT(request);
100 if (request.data.chauthtok.user == NULL) return -2;
102 strncpy(request.data.chauthtok.user, user,
103 sizeof(request.data.chauthtok.user) - 1);
105 if (oldpass != NULL) {
106 strncpy(request.data.chauthtok.oldpass, oldpass,
107 sizeof(request.data.chauthtok.oldpass) - 1);
108 } else {
109 request.data.chauthtok.oldpass[0] = '\0';
112 if (newpass != NULL) {
113 strncpy(request.data.chauthtok.newpass, newpass,
114 sizeof(request.data.chauthtok.newpass) - 1);
115 } else {
116 request.data.chauthtok.newpass[0] = '\0';
119 return winbind_request(WINBINDD_PAM_CHAUTHTOK, &request, &response);
123 * Looks up an user name and checks the password
125 * return values:
126 * 1 = User not found
127 * 0 = OK
128 * -1 = Password incorrect
129 * -2 = System error
131 static int user_lookup(const char *user, const char *pass)
133 return winbind_auth_request(user, pass);
137 * Checks if a user has an account
139 * return values:
140 * 1 = User not found
141 * 0 = OK
142 * -1 = System error
144 static int valid_user(const char *user)
146 if (getpwnam(user)) return 0;
147 return 1;
150 /* --- authentication management functions --- */
152 /* Attempt a conversation */
154 static int converse(pam_handle_t *pamh, int nargs,
155 struct pam_message **message,
156 struct pam_response **response)
158 int retval;
159 struct pam_conv *conv;
161 retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv ) ;
162 if (retval == PAM_SUCCESS) {
163 retval = conv->conv(nargs, (const struct pam_message **)message,
164 response, conv->appdata_ptr);
167 return retval; /* propagate error status */
171 static char *_pam_delete(register char *xx)
173 _pam_overwrite(xx);
174 _pam_drop(xx);
175 return NULL;
179 * This is a conversation function to obtain the user's password
181 static int auth_conversation(pam_handle_t *pamh)
183 struct pam_message msg, *pmsg;
184 struct pam_response *resp;
185 int retval;
186 char * token = NULL;
188 pmsg = &msg;
189 msg.msg_style = PAM_PROMPT_ECHO_OFF;
190 msg.msg = "Password: ";
192 /* so call the conversation expecting i responses */
193 resp = NULL;
194 retval = converse(pamh, 1, &pmsg, &resp);
196 if (resp != NULL) {
197 char * const item;
198 /* interpret the response */
199 if (retval == PAM_SUCCESS) { /* a good conversation */
200 token = x_strdup(resp[0].resp);
201 if (token == NULL) {
202 return PAM_AUTHTOK_RECOVER_ERR;
206 /* set the auth token */
207 retval = pam_set_item(pamh, PAM_AUTHTOK, token);
208 token = _pam_delete(token); /* clean it up */
209 if ( (retval != PAM_SUCCESS) ||
210 (retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **) &item)) != PAM_SUCCESS ) {
211 return retval;
214 _pam_drop_reply(resp, 1);
215 } else {
216 retval = (retval == PAM_SUCCESS)
217 ? PAM_AUTHTOK_RECOVER_ERR:retval ;
220 return retval;
223 PAM_EXTERN
224 int pam_sm_authenticate(pam_handle_t *pamh, int flags,
225 int argc, const char **argv)
227 const char *username;
228 const char *password;
229 int retval = PAM_AUTH_ERR;
231 /* parse arguments */
232 ctrl = _pam_parse(argc, argv);
234 /* Get the username */
235 retval = pam_get_user(pamh, &username, NULL);
236 if ((retval != PAM_SUCCESS) || (!username)) {
237 if (ctrl & PAM_DEBUG_ARG)
238 _pam_log(LOG_DEBUG,"can not get the username");
239 return PAM_SERVICE_ERR;
242 if ((ctrl & PAM_USE_AUTHTOK_ARG) == 0) {
243 /* Converse just to be sure we have the password */
244 retval = auth_conversation(pamh);
245 if (retval != PAM_SUCCESS) {
246 _pam_log(LOG_ERR, "could not obtain password for `%s'",
247 username);
248 return PAM_CONV_ERR;
252 /* Get the password */
253 retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **) &password);
254 if (retval != PAM_SUCCESS) {
255 _pam_log(LOG_ERR, "Could not retrive user's password");
256 return PAM_AUTHTOK_ERR;
259 if (ctrl & PAM_DEBUG_ARG)
260 _pam_log(LOG_INFO, "Verify user `%s' with password `%s'",
261 username, password);
263 /* Now use the username to look up password */
264 retval = user_lookup(username, password);
265 switch (retval) {
266 case -2:
267 /* some sort of system error. The log was already printed */
268 return PAM_SERVICE_ERR;
269 case -1:
270 /* incorrect password */
271 _pam_log(LOG_WARNING, "user `%s' denied access (incorrect password)", username);
272 return PAM_AUTH_ERR;
273 case 1:
274 /* the user does not exist */
275 if (ctrl & PAM_DEBUG_ARG)
276 _pam_log(LOG_NOTICE, "user `%s' not found",
277 username);
278 if (ctrl & PAM_UNKNOWN_OK_ARG) {
279 return PAM_IGNORE;
281 return PAM_USER_UNKNOWN;
282 case 0:
283 /* Otherwise, the authentication looked good */
284 _pam_log(LOG_NOTICE, "user '%s' granted access", username);
285 return PAM_SUCCESS;
286 default:
287 /* we don't know anything about this return value */
288 _pam_log(LOG_ERR, "internal module error (retval = %d, user = `%s'",
289 retval, username);
290 return PAM_SERVICE_ERR;
292 /* should not be reached */
293 return PAM_IGNORE;
296 PAM_EXTERN
297 int pam_sm_setcred(pam_handle_t *pamh, int flags,
298 int argc, const char **argv)
300 return PAM_SUCCESS;
304 * Account management. We want to verify that the account exists
305 * before returning PAM_SUCCESS
307 PAM_EXTERN
308 int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
309 int argc, const char **argv)
311 const char *username;
312 int retval = PAM_USER_UNKNOWN;
314 /* parse arguments */
315 ctrl = _pam_parse(argc, argv);
317 /* Get the username */
318 retval = pam_get_user(pamh, &username, NULL);
319 if ((retval != PAM_SUCCESS) || (!username)) {
320 if (ctrl & PAM_DEBUG_ARG)
321 _pam_log(LOG_DEBUG,"can not get the username");
322 return PAM_SERVICE_ERR;
325 /* Verify the username */
326 retval = valid_user(username);
327 switch (retval) {
328 case -1:
329 /* some sort of system error. The log was already printed */
330 return PAM_SERVICE_ERR;
331 case 1:
332 /* the user does not exist */
333 if (ctrl & PAM_DEBUG_ARG)
334 _pam_log(LOG_NOTICE, "user `%s' not found",
335 username);
336 if (ctrl & PAM_UNKNOWN_OK_ARG)
337 return PAM_IGNORE;
338 return PAM_USER_UNKNOWN;
339 case 0:
340 /* Otherwise, the authentication looked good */
341 _pam_log(LOG_NOTICE, "user '%s' granted access", username);
342 return PAM_SUCCESS;
343 default:
344 /* we don't know anything about this return value */
345 _pam_log(LOG_ERR, "internal module error (retval = %d, user = `%s'",
346 retval, username);
347 return PAM_SERVICE_ERR;
350 /* should not be reached */
351 return PAM_IGNORE;
355 PAM_EXTERN
356 int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc,
357 const char **argv)
359 int retval;
360 char *newpw, *oldpw;
361 const char *user;
363 /* Get name of a user */
365 retval = pam_get_user(pamh, &user, "Username: ");
367 if (retval != PAM_SUCCESS) {
368 return retval;
371 /* XXX check in domain format */
373 /* Perform preliminary check and store requested password for updating
374 later on */
376 if (flags & PAM_PRELIM_CHECK) {
377 struct pam_message msg[3], *pmsg[3];
378 struct pam_response *resp;
380 /* Converse to ensure we have the current password */
382 retval = auth_conversation(pamh);
384 if (retval != PAM_SUCCESS) {
385 return retval;
388 /* Obtain and verify current password */
390 pmsg[0] = &msg[0];
391 msg[0].msg_style = PAM_TEXT_INFO;
392 msg[0].msg = "Changing password for user %s";
394 pmsg[1] = &msg[1];
395 msg[1].msg_style = PAM_PROMPT_ECHO_OFF;
396 msg[1].msg = "New NT password: ";
398 pmsg[2] = &msg[2];
399 msg[2].msg_style = PAM_PROMPT_ECHO_OFF;
400 msg[2].msg = "Retype new NT password: ";
402 resp = NULL;
404 retval = converse(pamh, 3, pmsg, &resp);
406 if (resp != NULL) {
408 if (retval == PAM_SUCCESS) {
410 /* Check password entered correctly */
412 if (strcmp(resp[1].resp, resp[2].resp) != 0) {
413 struct pam_response *resp2;
415 msg[0].msg_style = PAM_ERROR_MSG;
416 msg[0].msg = "Sorry, passwords do not match";
418 converse(pamh, 1, pmsg, &resp2);
420 _pam_drop_reply(resp, 3);
421 _pam_drop_reply(resp2, 1);
423 return PAM_AUTHTOK_RECOVER_ERR;
426 /* Store passwords */
428 retval = pam_set_item(pamh, PAM_OLDAUTHTOK, resp[1].resp);
429 _pam_drop_reply(resp, 3);
433 /* XXX What happens if root? */
434 /* XXX try first pass and use first pass args */
436 return retval;
439 if (flags & PAM_UPDATE_AUTHTOK) {
441 retval = pam_get_item(pamh, PAM_OLDAUTHTOK, (const void **)&newpw);
442 if (retval != PAM_SUCCESS) {
443 return PAM_AUTHTOK_ERR;
446 retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&oldpw);
447 if (retval != PAM_SUCCESS) {
448 return PAM_AUTHTOK_ERR;
451 fprintf(stderr, "oldpw = %s, newpw = %s\n", oldpw, newpw);
453 if (retval == PAM_SUCCESS &&
454 winbind_chauthtok_request(user, oldpw, newpw) == 0) {
455 return PAM_SUCCESS;
458 return PAM_AUTHTOK_ERR;
461 return PAM_SERVICE_ERR;
464 /* HP added session open and close handlers to always return success */
465 PAM_EXTERN
466 int pam_sm_open_session(pam_handle_t *pamh, int flags,
467 int argc, const char **argv)
469 /* parse arguments */
470 ctrl = _pam_parse(argc, argv);
471 if (ctrl & PAM_DEBUG_ARG)
472 _pam_log(LOG_DEBUG,"libpam_winbind:pam_sm_open_session handler") ;
473 return PAM_SUCCESS;
476 PAM_EXTERN
477 int pam_sm_close_session(pam_handle_t *pamh, int flags,
478 int argc, const char **argv)
480 /* parse arguments */
481 ctrl = _pam_parse(argc, argv);
482 if (ctrl & PAM_DEBUG_ARG)
483 _pam_log(LOG_DEBUG,"libpam_winbind:pam_sm_close_session handler");
484 return PAM_SUCCESS;
486 /* end HP add */
488 #ifdef PAM_STATIC
490 /* static module data */
492 struct pam_module _pam_winbind_modstruct = {
493 MODULE_NAME,
494 pam_sm_authenticate,
495 pam_sm_setcred,
496 pam_sm_acct_mgmt,
497 pam_sm_open_session,
498 pam_sm_close_session,
499 pam_sm_chauthtok
502 #endif
505 * Copyright (c) Andrew Tridgell <tridge@samba.org> 2000
506 * Copyright (c) Tim Potter <tpot@samba.org> 2000
508 * Redistribution and use in source and binary forms, with or without
509 * modification, are permitted provided that the following conditions
510 * are met:
511 * 1. Redistributions of source code must retain the above copyright
512 * notice, and the entire permission notice in its entirety,
513 * including the disclaimer of warranties.
514 * 2. Redistributions in binary form must reproduce the above copyright
515 * notice, this list of conditions and the following disclaimer in the
516 * documentation and/or other materials provided with the distribution.
517 * 3. The name of the author may not be used to endorse or promote
518 * products derived from this software without specific prior
519 * written permission.
521 * ALTERNATIVELY, this product may be distributed under the terms of
522 * the GNU Public License, in which case the provisions of the GPL are
523 * required INSTEAD OF the above restrictions. (This clause is
524 * necessary due to a potential bad interaction between the GPL and
525 * the restrictions contained in a BSD-style copyright.)
527 * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED
528 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
529 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
530 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
531 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
532 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
533 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
534 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
535 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
536 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
537 * OF THE POSSIBILITY OF SUCH DAMAGE.