1/* pam_winbind module 2 3 Copyright Andrew Tridgell <tridge@samba.org> 2000 4 Copyright Tim Potter <tpot@samba.org> 2000 5 Copyright Andrew Bartlett <abartlet@samba.org> 2002 6 7 largely based on pam_userdb by Cristian Gafton <gafton@redhat.com> 8 also contains large slabs of code from pam_unix by Elliot Lee <sopwith@redhat.com> 9 (see copyright below for full details) 10*/ 11 12#include "pam_winbind.h" 13 14/* data tokens */ 15 16#define MAX_PASSWD_TRIES 3 17 18/* some syslogging */ 19static void _pam_log(int err, const char *format, ...) 20{ 21 va_list args; 22 23 va_start(args, format); 24 openlog(MODULE_NAME, LOG_CONS|LOG_PID, LOG_AUTH); 25 vsyslog(err, format, args); 26 va_end(args); 27 closelog(); 28} 29 30static int _pam_parse(int argc, const char **argv) 31{ 32 int ctrl; 33 /* step through arguments */ 34 for (ctrl = 0; argc-- > 0; ++argv) { 35 36 /* generic options */ 37 38 if (!strcmp(*argv,"debug")) 39 ctrl |= WINBIND_DEBUG_ARG; 40 else if (!strcasecmp(*argv, "use_authtok")) 41 ctrl |= WINBIND_USE_AUTHTOK_ARG; 42 else if (!strcasecmp(*argv, "use_first_pass")) 43 ctrl |= WINBIND_USE_FIRST_PASS_ARG; 44 else if (!strcasecmp(*argv, "try_first_pass")) 45 ctrl |= WINBIND_TRY_FIRST_PASS_ARG; 46 else if (!strcasecmp(*argv, "unknown_ok")) 47 ctrl |= WINBIND_UNKNOWN_OK_ARG; 48 else if (!strncasecmp(*argv, "require_membership_of", strlen("require_membership_of"))) 49 ctrl |= WINBIND_REQUIRED_MEMBERSHIP; 50 else if (!strncasecmp(*argv, "require-membership-of", strlen("require-membership-of"))) 51 ctrl |= WINBIND_REQUIRED_MEMBERSHIP; 52 else { 53 _pam_log(LOG_ERR, "pam_parse: unknown option; %s", *argv); 54 } 55 } 56 57 return ctrl; 58} 59 60/* --- authentication management functions --- */ 61 62/* Attempt a conversation */ 63 64static int converse(pam_handle_t *pamh, int nargs, 65 struct pam_message **message, 66 struct pam_response **response) 67{ 68 int retval; 69 struct pam_conv *conv; 70 71 retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv ) ; 72 if (retval == PAM_SUCCESS) { 73 retval = conv->conv(nargs, (const struct pam_message **)message, 74 response, conv->appdata_ptr); 75 } 76 77 return retval; /* propagate error status */ 78} 79 80 81static int _make_remark(pam_handle_t * pamh, int type, const char *text) 82{ 83 int retval = PAM_SUCCESS; 84 85 struct pam_message *pmsg[1], msg[1]; 86 struct pam_response *resp; 87 88 pmsg[0] = &msg[0]; 89 msg[0].msg = text; 90 msg[0].msg_style = type; 91 92 resp = NULL; 93 retval = converse(pamh, 1, pmsg, &resp); 94 95 if (resp) { 96 _pam_drop_reply(resp, 1); 97 } 98 return retval; 99} 100 101static int pam_winbind_request(enum winbindd_cmd req_type, 102 struct winbindd_request *request, 103 struct winbindd_response *response) 104{ 105 106 /* Fill in request and send down pipe */ 107 init_request(request, req_type); 108 109 if (write_sock(request, sizeof(*request)) == -1) { 110 _pam_log(LOG_ERR, "write to socket failed!"); 111 close_sock(); 112 return PAM_SERVICE_ERR; 113 } 114 115 /* Wait for reply */ 116 if (read_reply(response) == -1) { 117 _pam_log(LOG_ERR, "read from socket failed!"); 118 close_sock(); 119 return PAM_SERVICE_ERR; 120 } 121 122 /* We are done with the socket - close it and avoid mischeif */ 123 close_sock(); 124 125 /* Copy reply data from socket */ 126 if (response->result != WINBINDD_OK) { 127 if (response->data.auth.pam_error != PAM_SUCCESS) { 128 _pam_log(LOG_ERR, "request failed: %s, PAM error was %d, NT error was %s", 129 response->data.auth.error_string, 130 response->data.auth.pam_error, 131 response->data.auth.nt_status_string); 132 return response->data.auth.pam_error; 133 } else { 134 _pam_log(LOG_ERR, "request failed, but PAM error 0!"); 135 return PAM_SERVICE_ERR; 136 } 137 } 138 139 return PAM_SUCCESS; 140} 141 142static int pam_winbind_request_log(enum winbindd_cmd req_type, 143 struct winbindd_request *request, 144 struct winbindd_response *response, 145 int ctrl, 146 const char *user) 147{ 148 int retval; 149 150 retval = pam_winbind_request(req_type, request, response); 151 152 switch (retval) { 153 case PAM_AUTH_ERR: 154 /* incorrect password */ 155 _pam_log(LOG_WARNING, "user `%s' denied access (incorrect password or invalid membership)", user); 156 return retval; 157 case PAM_ACCT_EXPIRED: 158 /* account expired */ 159 _pam_log(LOG_WARNING, "user `%s' account expired", user); 160 return retval; 161 case PAM_AUTHTOK_EXPIRED: 162 /* password expired */ 163 _pam_log(LOG_WARNING, "user `%s' password expired", user); 164 return retval; 165 case PAM_NEW_AUTHTOK_REQD: 166 /* password expired */ 167 _pam_log(LOG_WARNING, "user `%s' new password required", user); 168 return retval; 169 case PAM_USER_UNKNOWN: 170 /* the user does not exist */ 171 if (ctrl & WINBIND_DEBUG_ARG) 172 _pam_log(LOG_NOTICE, "user `%s' not found", 173 user); 174 if (ctrl & WINBIND_UNKNOWN_OK_ARG) { 175 return PAM_IGNORE; 176 } 177 return retval; 178 case PAM_SUCCESS: 179 if (req_type == WINBINDD_PAM_AUTH) { 180 /* Otherwise, the authentication looked good */ 181 _pam_log(LOG_NOTICE, "user '%s' granted access", user); 182 } else if (req_type == WINBINDD_PAM_CHAUTHTOK) { 183 /* Otherwise, the authentication looked good */ 184 _pam_log(LOG_NOTICE, "user '%s' password changed", user); 185 } else { 186 /* Otherwise, the authentication looked good */ 187 _pam_log(LOG_NOTICE, "user '%s' OK", user); 188 } 189 return retval; 190 default: 191 /* we don't know anything about this return value */ 192 _pam_log(LOG_ERR, "internal module error (retval = %d, user = `%s')", 193 retval, user); 194 return retval; 195 } 196} 197 198/* talk to winbindd */ 199static int winbind_auth_request(const char *user, const char *pass, const char *member, int ctrl) 200{ 201 struct winbindd_request request; 202 struct winbindd_response response; 203 204 ZERO_STRUCT(request); 205 206 strncpy(request.data.auth.user, user, 207 sizeof(request.data.auth.user)-1); 208 209 strncpy(request.data.auth.pass, pass, 210 sizeof(request.data.auth.pass)-1); 211 212 if (member == NULL ) 213 return pam_winbind_request_log(WINBINDD_PAM_AUTH, &request, &response, ctrl, user); 214 215 /* lookup name? */ 216 if (!strncmp("S-", member, 2) == 0) { 217 218 struct winbindd_request sid_request; 219 struct winbindd_response sid_response; 220 221 ZERO_STRUCT(sid_request); 222 ZERO_STRUCT(sid_response); 223 224 if (ctrl & WINBIND_DEBUG_ARG) 225 _pam_log(LOG_DEBUG, "no sid given, looking up: %s\n", member); 226 227 /* fortunatly winbindd can handle non-separated names */ 228 strcpy(sid_request.data.name.name, member); 229 230 if (pam_winbind_request_log(WINBINDD_LOOKUPNAME, &sid_request, &sid_response, ctrl, user)) { 231 _pam_log(LOG_INFO, "could not lookup name: %s\n", member); 232 return PAM_AUTH_ERR; 233 } 234 235 member = sid_response.data.sid.sid; 236 } 237 238 strncpy(request.data.auth.require_membership_of_sid, member, 239 sizeof(request.data.auth.require_membership_of_sid)-1); 240 241 return pam_winbind_request_log(WINBINDD_PAM_AUTH, &request, &response, ctrl, user); 242} 243 244/* talk to winbindd */ 245static int winbind_chauthtok_request(const char *user, const char *oldpass, 246 const char *newpass, int ctrl) 247{ 248 struct winbindd_request request; 249 struct winbindd_response response; 250 251 ZERO_STRUCT(request); 252 253 if (request.data.chauthtok.user == NULL) return -2; 254 255 strncpy(request.data.chauthtok.user, user, 256 sizeof(request.data.chauthtok.user) - 1); 257 258 if (oldpass != NULL) { 259 strncpy(request.data.chauthtok.oldpass, oldpass, 260 sizeof(request.data.chauthtok.oldpass) - 1); 261 } else { 262 request.data.chauthtok.oldpass[0] = '\0'; 263 } 264 265 if (newpass != NULL) { 266 strncpy(request.data.chauthtok.newpass, newpass, 267 sizeof(request.data.chauthtok.newpass) - 1); 268 } else { 269 request.data.chauthtok.newpass[0] = '\0'; 270 } 271 272 return pam_winbind_request_log(WINBINDD_PAM_CHAUTHTOK, &request, &response, ctrl, user); 273} 274 275/* 276 * Checks if a user has an account 277 * 278 * return values: 279 * 1 = User not found 280 * 0 = OK 281 * -1 = System error 282 */ 283static int valid_user(const char *user) 284{ 285 if (getpwnam(user)) return 0; 286 return 1; 287} 288 289static char *_pam_delete(register char *xx) 290{ 291 _pam_overwrite(xx); 292 _pam_drop(xx); 293 return NULL; 294} 295 296/* 297 * obtain a password from the user 298 */ 299 300static int _winbind_read_password(pam_handle_t * pamh 301 ,unsigned int ctrl 302 ,const char *comment 303 ,const char *prompt1 304 ,const char *prompt2 305 ,const char **pass) 306{ 307 int authtok_flag; 308 int retval; 309 const char *item; 310 char *token; 311 312 /* 313 * make sure nothing inappropriate gets returned 314 */ 315 316 *pass = token = NULL; 317 318 /* 319 * which authentication token are we getting? 320 */ 321 322 authtok_flag = on(WINBIND__OLD_PASSWORD, ctrl) ? PAM_OLDAUTHTOK : PAM_AUTHTOK; 323 324 /* 325 * should we obtain the password from a PAM item ? 326 */ 327 328 if (on(WINBIND_TRY_FIRST_PASS_ARG, ctrl) || on(WINBIND_USE_FIRST_PASS_ARG, ctrl)) { 329 retval = pam_get_item(pamh, authtok_flag, (const void **) &item); 330 if (retval != PAM_SUCCESS) { 331 /* very strange. */ 332 _pam_log(LOG_ALERT, 333 "pam_get_item returned error to unix-read-password" 334 ); 335 return retval; 336 } else if (item != NULL) { /* we have a password! */ 337 *pass = item; 338 item = NULL; 339 return PAM_SUCCESS; 340 } else if (on(WINBIND_USE_FIRST_PASS_ARG, ctrl)) { 341 return PAM_AUTHTOK_RECOVER_ERR; /* didn't work */ 342 } else if (on(WINBIND_USE_AUTHTOK_ARG, ctrl) 343 && off(WINBIND__OLD_PASSWORD, ctrl)) { 344 return PAM_AUTHTOK_RECOVER_ERR; 345 } 346 } 347 /* 348 * getting here implies we will have to get the password from the 349 * user directly. 350 */ 351 352 { 353 struct pam_message msg[3], *pmsg[3]; 354 struct pam_response *resp; 355 int i, replies; 356 357 /* prepare to converse */ 358 359 if (comment != NULL) { 360 pmsg[0] = &msg[0]; 361 msg[0].msg_style = PAM_TEXT_INFO; 362 msg[0].msg = comment; 363 i = 1; 364 } else { 365 i = 0; 366 } 367 368 pmsg[i] = &msg[i]; 369 msg[i].msg_style = PAM_PROMPT_ECHO_OFF; 370 msg[i++].msg = prompt1; 371 replies = 1; 372 373 if (prompt2 != NULL) { 374 pmsg[i] = &msg[i]; 375 msg[i].msg_style = PAM_PROMPT_ECHO_OFF; 376 msg[i++].msg = prompt2; 377 ++replies; 378 } 379 /* so call the conversation expecting i responses */ 380 resp = NULL; 381 retval = converse(pamh, i, pmsg, &resp); 382 383 if (resp != NULL) { 384 385 /* interpret the response */ 386 387 if (retval == PAM_SUCCESS) { /* a good conversation */ 388 389 token = x_strdup(resp[i - replies].resp); 390 if (token != NULL) { 391 if (replies == 2) { 392 393 /* verify that password entered correctly */ 394 if (!resp[i - 1].resp 395 || strcmp(token, resp[i - 1].resp)) { 396 _pam_delete(token); /* mistyped */ 397 retval = PAM_AUTHTOK_RECOVER_ERR; 398 _make_remark(pamh ,PAM_ERROR_MSG, MISTYPED_PASS); 399 } 400 } 401 } else { 402 _pam_log(LOG_NOTICE 403 ,"could not recover authentication token"); 404 } 405 406 } 407 /* 408 * tidy up the conversation (resp_retcode) is ignored 409 * -- what is it for anyway? AGM 410 */ 411 412 _pam_drop_reply(resp, i); 413 414 } else { 415 retval = (retval == PAM_SUCCESS) 416 ? PAM_AUTHTOK_RECOVER_ERR : retval; 417 } 418 } 419 420 if (retval != PAM_SUCCESS) { 421 if (on(WINBIND_DEBUG_ARG, ctrl)) 422 _pam_log(LOG_DEBUG, 423 "unable to obtain a password"); 424 return retval; 425 } 426 /* 'token' is the entered password */ 427 428 /* we store this password as an item */ 429 430 retval = pam_set_item(pamh, authtok_flag, token); 431 _pam_delete(token); /* clean it up */ 432 if (retval != PAM_SUCCESS 433 || (retval = pam_get_item(pamh, authtok_flag 434 ,(const void **) &item)) 435 != PAM_SUCCESS) { 436 437 _pam_log(LOG_CRIT, "error manipulating password"); 438 return retval; 439 440 } 441 442 *pass = item; 443 item = NULL; /* break link to password */ 444 445 return PAM_SUCCESS; 446} 447 448PAM_EXTERN 449int pam_sm_authenticate(pam_handle_t *pamh, int flags, 450 int argc, const char **argv) 451{ 452 const char *username; 453 const char *password; 454 const char *member = NULL; 455 int retval = PAM_AUTH_ERR; 456 int i; 457 458 /* parse arguments */ 459 int ctrl = _pam_parse(argc, argv); 460 461 /* Get the username */ 462 retval = pam_get_user(pamh, &username, NULL); 463 if ((retval != PAM_SUCCESS) || (!username)) { 464 if (ctrl & WINBIND_DEBUG_ARG) 465 _pam_log(LOG_DEBUG,"can not get the username"); 466 return PAM_SERVICE_ERR; 467 } 468 469 retval = _winbind_read_password(pamh, ctrl, NULL, 470 "Password: ", NULL, 471 &password); 472 473 if (retval != PAM_SUCCESS) { 474 _pam_log(LOG_ERR, "Could not retrieve user's password"); 475 return PAM_AUTHTOK_ERR; 476 } 477 478 if (ctrl & WINBIND_DEBUG_ARG) { 479 480 /* Let's not give too much away in the log file */ 481 482#ifdef DEBUG_PASSWORD 483 _pam_log(LOG_INFO, "Verify user `%s' with password `%s'", 484 username, password); 485#else 486 _pam_log(LOG_INFO, "Verify user `%s'", username); 487#endif 488 } 489 490 /* Retrieve membership-string here */ 491 for ( i=0; i<argc; i++ ) { 492 493 if ((strncmp(argv[i], "require_membership_of", strlen("require_membership_of")) == 0) 494 || (strncmp(argv[i], "require-membership-of", strlen("require-membership-of")) == 0)) { 495 496 char *p; 497 char *parm = strdup(argv[i]); 498 499 if ( (p = strchr( parm, '=' )) == NULL) { 500 _pam_log(LOG_INFO, "no \"=\" delimiter for \"require_membership_of\" found\n"); 501 break; 502 } 503 504 member = strdup(p+1); 505 } 506 } 507 508 /* Now use the username to look up password */ 509 return winbind_auth_request(username, password, member, ctrl); 510} 511 512PAM_EXTERN 513int pam_sm_setcred(pam_handle_t *pamh, int flags, 514 int argc, const char **argv) 515{ 516 return PAM_SUCCESS; 517} 518 519/* 520 * Account management. We want to verify that the account exists 521 * before returning PAM_SUCCESS 522 */ 523PAM_EXTERN 524int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, 525 int argc, const char **argv) 526{ 527 const char *username; 528 int retval = PAM_USER_UNKNOWN; 529 530 /* parse arguments */ 531 int ctrl = _pam_parse(argc, argv); 532 533 /* Get the username */ 534 retval = pam_get_user(pamh, &username, NULL); 535 if ((retval != PAM_SUCCESS) || (!username)) { 536 if (ctrl & WINBIND_DEBUG_ARG) 537 _pam_log(LOG_DEBUG,"can not get the username"); 538 return PAM_SERVICE_ERR; 539 } 540 541 /* Verify the username */ 542 retval = valid_user(username); 543 switch (retval) { 544 case -1: 545 /* some sort of system error. The log was already printed */ 546 return PAM_SERVICE_ERR; 547 case 1: 548 /* the user does not exist */ 549 if (ctrl & WINBIND_DEBUG_ARG) 550 _pam_log(LOG_NOTICE, "user `%s' not found", 551 username); 552 if (ctrl & WINBIND_UNKNOWN_OK_ARG) 553 return PAM_IGNORE; 554 return PAM_USER_UNKNOWN; 555 case 0: 556 /* Otherwise, the authentication looked good */ 557 _pam_log(LOG_NOTICE, "user '%s' granted access", username); 558 return PAM_SUCCESS; 559 default: 560 /* we don't know anything about this return value */ 561 _pam_log(LOG_ERR, "internal module error (retval = %d, user = `%s'", 562 retval, username); 563 return PAM_SERVICE_ERR; 564 } 565 566 /* should not be reached */ 567 return PAM_IGNORE; 568} 569PAM_EXTERN 570int pam_sm_open_session(pam_handle_t *pamh, int flags, 571 int argc, const char **argv) 572{ 573 /* parse arguments */ 574 int ctrl = _pam_parse(argc, argv); 575 if (ctrl & WINBIND_DEBUG_ARG) 576 _pam_log(LOG_DEBUG,"libpam_winbind:pam_sm_open_session handler"); 577 return PAM_SUCCESS; 578} 579PAM_EXTERN 580int pam_sm_close_session(pam_handle_t *pamh, int flags, 581 int argc, const char **argv) 582{ 583 /* parse arguments */ 584 int ctrl = _pam_parse(argc, argv); 585 if (ctrl & WINBIND_DEBUG_ARG) 586 _pam_log(LOG_DEBUG,"libpam_winbind:pam_sm_close_session handler"); 587 return PAM_SUCCESS; 588} 589 590 591 592PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, 593 int argc, const char **argv) 594{ 595 unsigned int lctrl; 596 int retval; 597 unsigned int ctrl = _pam_parse(argc, argv); 598 599 /* <DO NOT free() THESE> */ 600 const char *user; 601 const char *member = NULL; 602 char *pass_old, *pass_new; 603 /* </DO NOT free() THESE> */ 604 605 char *Announce; 606 607 int retry = 0; 608 609 /* 610 * First get the name of a user 611 */ 612 retval = pam_get_user(pamh, &user, "Username: "); 613 if (retval == PAM_SUCCESS) { 614 if (user == NULL) { 615 _pam_log(LOG_ERR, "username was NULL!"); 616 return PAM_USER_UNKNOWN; 617 } 618 if (retval == PAM_SUCCESS && on(WINBIND_DEBUG_ARG, ctrl)) 619 _pam_log(LOG_DEBUG, "username [%s] obtained", 620 user); 621 } else { 622 if (on(WINBIND_DEBUG_ARG, ctrl)) 623 _pam_log(LOG_DEBUG, 624 "password - could not identify user"); 625 return retval; 626 } 627 628 /* 629 * obtain and verify the current password (OLDAUTHTOK) for 630 * the user. 631 */ 632 633 if (flags & PAM_PRELIM_CHECK) { 634 635 /* instruct user what is happening */ 636#define greeting "Changing password for " 637 Announce = (char *) malloc(sizeof(greeting) + strlen(user)); 638 if (Announce == NULL) { 639 _pam_log(LOG_CRIT, 640 "password - out of memory"); 641 return PAM_BUF_ERR; 642 } 643 (void) strcpy(Announce, greeting); 644 (void) strcpy(Announce + sizeof(greeting) - 1, user); 645#undef greeting 646 647 lctrl = ctrl | WINBIND__OLD_PASSWORD; 648 retval = _winbind_read_password(pamh, lctrl 649 ,Announce 650 ,"(current) NT password: " 651 ,NULL 652 ,(const char **) &pass_old); 653 free(Announce); 654 655 if (retval != PAM_SUCCESS) { 656 _pam_log(LOG_NOTICE 657 ,"password - (old) token not obtained"); 658 return retval; 659 } 660 /* verify that this is the password for this user */ 661 662 retval = winbind_auth_request(user, pass_old, member, ctrl); 663 664 if (retval != PAM_ACCT_EXPIRED 665 && retval != PAM_AUTHTOK_EXPIRED 666 && retval != PAM_NEW_AUTHTOK_REQD 667 && retval != PAM_SUCCESS) { 668 pass_old = NULL; 669 return retval; 670 } 671 672 retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *) pass_old); 673 pass_old = NULL; 674 if (retval != PAM_SUCCESS) { 675 _pam_log(LOG_CRIT, 676 "failed to set PAM_OLDAUTHTOK"); 677 } 678 } else if (flags & PAM_UPDATE_AUTHTOK) { 679 680 /* 681 * obtain the proposed password 682 */ 683 684 /* 685 * get the old token back. 686 */ 687 688 retval = pam_get_item(pamh, PAM_OLDAUTHTOK 689 ,(const void **) &pass_old); 690 691 if (retval != PAM_SUCCESS) { 692 _pam_log(LOG_NOTICE, "user not authenticated"); 693 return retval; 694 } 695 696 lctrl = ctrl; 697 698 if (on(WINBIND_USE_AUTHTOK_ARG, lctrl)) { 699 lctrl |= WINBIND_USE_FIRST_PASS_ARG; 700 } 701 retry = 0; 702 retval = PAM_AUTHTOK_ERR; 703 while ((retval != PAM_SUCCESS) && (retry++ < MAX_PASSWD_TRIES)) { 704 /* 705 * use_authtok is to force the use of a previously entered 706 * password -- needed for pluggable password strength checking 707 */ 708 709 retval = _winbind_read_password(pamh, lctrl 710 ,NULL 711 ,"Enter new NT password: " 712 ,"Retype new NT password: " 713 ,(const char **) &pass_new); 714 715 if (retval != PAM_SUCCESS) { 716 if (on(WINBIND_DEBUG_ARG, ctrl)) { 717 _pam_log(LOG_ALERT 718 ,"password - new password not obtained"); 719 } 720 pass_old = NULL;/* tidy up */ 721 return retval; 722 } 723 724 /* 725 * At this point we know who the user is and what they 726 * propose as their new password. Verify that the new 727 * password is acceptable. 728 */ 729 730 if (pass_new[0] == '\0') {/* "\0" password = NULL */ 731 pass_new = NULL; 732 } 733 } 734 735 /* 736 * By reaching here we have approved the passwords and must now 737 * rebuild the password database file. 738 */ 739 740 retval = winbind_chauthtok_request(user, pass_old, pass_new, ctrl); 741 _pam_overwrite(pass_new); 742 _pam_overwrite(pass_old); 743 pass_old = pass_new = NULL; 744 } else { 745 retval = PAM_SERVICE_ERR; 746 } 747 748 return retval; 749} 750 751#ifdef PAM_STATIC 752 753/* static module data */ 754 755struct pam_module _pam_winbind_modstruct = { 756 MODULE_NAME, 757 pam_sm_authenticate, 758 pam_sm_setcred, 759 pam_sm_acct_mgmt, 760 pam_sm_open_session, 761 pam_sm_close_session, 762 pam_sm_chauthtok 763}; 764 765#endif 766 767/* 768 * Copyright (c) Andrew Tridgell <tridge@samba.org> 2000 769 * Copyright (c) Tim Potter <tpot@samba.org> 2000 770 * Copyright (c) Andrew Bartlettt <abartlet@samba.org> 2002 771 * Copyright (c) Jan R�korajski 1999. 772 * Copyright (c) Andrew G. Morgan 1996-8. 773 * Copyright (c) Alex O. Yuriev, 1996. 774 * Copyright (c) Cristian Gafton 1996. 775 * Copyright (C) Elliot Lee <sopwith@redhat.com> 1996, Red Hat Software. 776 * 777 * Redistribution and use in source and binary forms, with or without 778 * modification, are permitted provided that the following conditions 779 * are met: 780 * 1. Redistributions of source code must retain the above copyright 781 * notice, and the entire permission notice in its entirety, 782 * including the disclaimer of warranties. 783 * 2. Redistributions in binary form must reproduce the above copyright 784 * notice, this list of conditions and the following disclaimer in the 785 * documentation and/or other materials provided with the distribution. 786 * 3. The name of the author may not be used to endorse or promote 787 * products derived from this software without specific prior 788 * written permission. 789 * 790 * ALTERNATIVELY, this product may be distributed under the terms of 791 * the GNU Public License, in which case the provisions of the GPL are 792 * required INSTEAD OF the above restrictions. (This clause is 793 * necessary due to a potential bad interaction between the GPL and 794 * the restrictions contained in a BSD-style copyright.) 795 * 796 * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED 797 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 798 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 799 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 800 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 801 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 802 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 803 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 804 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 805 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 806 * OF THE POSSIBILITY OF SUCH DAMAGE. 807 */ 808