pam_unix.c revision 89993
1/*- 2 * Copyright 1998 Juniper Networks, Inc. 3 * All rights reserved. 4 * Copyright (c) 2002 Networks Associates Technologies, Inc. 5 * All rights reserved. 6 * 7 * Portions of this software was developed for the FreeBSD Project by 8 * ThinkSec AS and NAI Labs, the Security Research Division of Network 9 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 10 * ("CBOSS"), as part of the DARPA CHATS research program. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. The name of the author may not be used to endorse or promote 21 * products derived from this software without specific prior written 22 * permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37#include <sys/cdefs.h> 38__FBSDID("$FreeBSD: head/lib/libpam/modules/pam_unix/pam_unix.c 89993 2002-01-30 19:09:11Z des $"); 39 40#include <sys/param.h> 41#include <sys/socket.h> 42#include <sys/time.h> 43#include <netinet/in.h> 44#include <arpa/inet.h> 45 46#ifdef YP 47#include <rpc/rpc.h> 48#include <rpcsvc/yp_prot.h> 49#include <rpcsvc/ypclnt.h> 50#include <rpcsvc/yppasswd.h> 51#endif 52 53#include <login_cap.h> 54#include <netdb.h> 55#include <pwd.h> 56#include <stdlib.h> 57#include <string.h> 58#include <stdio.h> 59#include <unistd.h> 60 61#include <pw_copy.h> 62#include <pw_util.h> 63 64#ifdef YP 65#include <pw_yp.h> 66#include "yppasswd_private.h" 67#endif 68 69#define PAM_SM_AUTH 70#define PAM_SM_ACCOUNT 71#define PAM_SM_SESSION 72#define PAM_SM_PASSWORD 73 74#include <security/pam_modules.h> 75 76#include "pam_mod_misc.h" 77 78#define USER_PROMPT "Username: " 79#define PASSWORD_PROMPT "Password:" 80#define PASSWORD_PROMPT_EXPIRED "\nPassword expired\nOld Password:" 81#define NEW_PASSWORD_PROMPT_1 "New Password:" 82#define NEW_PASSWORD_PROMPT_2 "New Password (again):" 83#define PASSWORD_HASH "md5" 84#define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */ 85#define MAX_TRIES 3 86 87enum { 88 PAM_OPT_AUTH_AS_SELF = PAM_OPT_STD_MAX, 89 PAM_OPT_NULLOK, 90 PAM_OPT_LOCAL_PASS, 91 PAM_OPT_NIS_PASS 92}; 93 94static struct opttab other_options[] = { 95 { "auth_as_self", PAM_OPT_AUTH_AS_SELF }, 96 { "nullok", PAM_OPT_NULLOK }, 97 { "local_pass", PAM_OPT_LOCAL_PASS }, 98 { "nis_pass", PAM_OPT_NIS_PASS }, 99 { NULL, 0 } 100}; 101 102#ifdef YP 103int pam_use_yp = 0; 104int yp_errno = YP_TRUE; 105#endif 106 107char *tempname = NULL; 108static int local_passwd(const char *user, const char *pass); 109#ifdef YP 110static int yp_passwd(const char *user, const char *pass); 111#endif 112 113/* 114 * authentication management 115 */ 116PAM_EXTERN int 117pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) 118{ 119 login_cap_t *lc; 120 struct options options; 121 struct passwd *pwd; 122 int retval; 123 const char *pass, *user; 124 char *encrypted, *password_prompt; 125 126 pam_std_option(&options, other_options, argc, argv); 127 128 PAM_LOG("Options processed"); 129 130 if (pam_test_option(&options, PAM_OPT_AUTH_AS_SELF, NULL)) 131 pwd = getpwnam(getlogin()); 132 else { 133 retval = pam_get_user(pamh, &user, NULL); 134 if (retval != PAM_SUCCESS) 135 PAM_RETURN(retval); 136 pwd = getpwnam(user); 137 } 138 139 PAM_LOG("Got user: %s", user); 140 141 lc = login_getclass(NULL); 142 password_prompt = login_getcapstr(lc, "passwd_prompt", 143 PASSWORD_PROMPT, PASSWORD_PROMPT); 144 login_close(lc); 145 lc = NULL; 146 147 if (pwd != NULL) { 148 149 PAM_LOG("Doing real authentication"); 150 151 if (pwd->pw_passwd[0] == '\0' 152 && pam_test_option(&options, PAM_OPT_NULLOK, NULL)) { 153 /* 154 * No password case. XXX Are we giving too much away 155 * by not prompting for a password? 156 */ 157 PAM_LOG("No password, and null password OK"); 158 PAM_RETURN(PAM_SUCCESS); 159 } 160 else { 161 retval = pam_get_pass(pamh, &pass, password_prompt, 162 &options); 163 if (retval != PAM_SUCCESS) 164 PAM_RETURN(retval); 165 PAM_LOG("Got password"); 166 } 167 encrypted = crypt(pass, pwd->pw_passwd); 168 if (pass[0] == '\0' && pwd->pw_passwd[0] != '\0') 169 encrypted = ":"; 170 171 PAM_LOG("Encrypted password 1 is: %s", encrypted); 172 PAM_LOG("Encrypted password 2 is: %s", pwd->pw_passwd); 173 174 retval = strcmp(encrypted, pwd->pw_passwd) == 0 ? 175 PAM_SUCCESS : PAM_AUTH_ERR; 176 } 177 else { 178 179 PAM_LOG("Doing dummy authentication"); 180 181 /* 182 * User unknown. 183 * Encrypt a dummy password so as to not give away too much. 184 */ 185 retval = pam_get_pass(pamh, &pass, password_prompt, 186 &options); 187 if (retval != PAM_SUCCESS) 188 PAM_RETURN(retval); 189 PAM_LOG("Got password"); 190 crypt(pass, "xx"); 191 retval = PAM_AUTH_ERR; 192 } 193 194 /* 195 * The PAM infrastructure will obliterate the cleartext 196 * password before returning to the application. 197 */ 198 if (retval != PAM_SUCCESS) 199 PAM_VERBOSE_ERROR("UNIX authentication refused"); 200 201 PAM_RETURN(retval); 202} 203 204PAM_EXTERN int 205pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) 206{ 207 struct options options; 208 209 pam_std_option(&options, other_options, argc, argv); 210 211 PAM_LOG("Options processed"); 212 213 PAM_RETURN(PAM_SUCCESS); 214} 215 216/* 217 * account management 218 */ 219PAM_EXTERN int 220pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) 221{ 222 struct addrinfo hints, *res; 223 struct options options; 224 struct passwd *pwd; 225 struct timeval tp; 226 login_cap_t *lc; 227 time_t warntime; 228 int retval; 229 const char *rhost, *tty, *user; 230 char rhostip[MAXHOSTNAMELEN]; 231 char buf[128]; 232 233 pam_std_option(&options, other_options, argc, argv); 234 235 PAM_LOG("Options processed"); 236 237 retval = pam_get_item(pamh, PAM_USER, (const void **)&user); 238 if (retval != PAM_SUCCESS) 239 PAM_RETURN(retval); 240 241 if (user == NULL || (pwd = getpwnam(user)) == NULL) 242 PAM_RETURN(PAM_SERVICE_ERR); 243 244 PAM_LOG("Got user: %s", user); 245 246 retval = pam_get_item(pamh, PAM_RHOST, (const void **)&rhost); 247 if (retval != PAM_SUCCESS) 248 PAM_RETURN(retval); 249 250 retval = pam_get_item(pamh, PAM_TTY, (const void **)&tty); 251 if (retval != PAM_SUCCESS) 252 PAM_RETURN(retval); 253 254 if (*pwd->pw_passwd == '\0' && 255 (flags & PAM_DISALLOW_NULL_AUTHTOK) != 0) 256 return (PAM_NEW_AUTHTOK_REQD); 257 258 lc = login_getpwclass(pwd); 259 if (lc == NULL) { 260 PAM_LOG("Unable to get login class for user %s", user); 261 return (PAM_SERVICE_ERR); 262 } 263 264 PAM_LOG("Got login_cap"); 265 266 if (pwd->pw_change || pwd->pw_expire) 267 gettimeofday(&tp, NULL); 268 269 /* 270 * Check pw_expire before pw_change - no point in letting the 271 * user change the password on an expired account. 272 */ 273 274 if (pwd->pw_expire) { 275 warntime = login_getcaptime(lc, "warnexpire", 276 DEFAULT_WARN, DEFAULT_WARN); 277 if (tp.tv_sec >= pwd->pw_expire) { 278 login_close(lc); 279 PAM_RETURN(PAM_ACCT_EXPIRED); 280 } else if (pwd->pw_expire - tp.tv_sec < warntime && 281 (flags & PAM_SILENT) == 0) { 282 snprintf(buf, sizeof(buf), 283 "Warning: your account expires on %s", 284 ctime(&pwd->pw_expire)); 285 pam_prompt(pamh, PAM_ERROR_MSG, buf, NULL); 286 } 287 } 288 289 retval = PAM_SUCCESS; 290 if (pwd->pw_change) { 291 warntime = login_getcaptime(lc, "warnpassword", 292 DEFAULT_WARN, DEFAULT_WARN); 293 if (tp.tv_sec >= pwd->pw_change) { 294 retval = PAM_NEW_AUTHTOK_REQD; 295 } else if (pwd->pw_change - tp.tv_sec < warntime && 296 (flags & PAM_SILENT) == 0) { 297 snprintf(buf, sizeof(buf), 298 "Warning: your password expires on %s", 299 ctime(&pwd->pw_change)); 300 pam_prompt(pamh, PAM_ERROR_MSG, buf, NULL); 301 } 302 } 303 304 /* 305 * From here on, we must leave retval untouched (unless we 306 * know we're going to fail), because we need to remember 307 * whether we're supposed to return PAM_SUCCESS or 308 * PAM_NEW_AUTHTOK_REQD. 309 */ 310 311 if (rhost) { 312 memset(&hints, 0, sizeof(hints)); 313 hints.ai_family = AF_UNSPEC; 314 if (getaddrinfo(rhost, NULL, &hints, &res) == 0) { 315 getnameinfo(res->ai_addr, res->ai_addrlen, 316 rhostip, sizeof(rhostip), NULL, 0, 317 NI_NUMERICHOST|NI_WITHSCOPEID); 318 } 319 if (res != NULL) 320 freeaddrinfo(res); 321 } 322 323 /* 324 * Check host / tty / time-of-day restrictions 325 */ 326 327 if (!auth_hostok(lc, rhost, rhostip) || 328 !auth_ttyok(lc, tty) || 329 !auth_timeok(lc, time(NULL))) 330 retval = PAM_AUTH_ERR; 331 332 login_close(lc); 333 334 PAM_RETURN(retval); 335} 336 337/* 338 * session management 339 * 340 * logging only 341 */ 342PAM_EXTERN int 343pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) 344{ 345 struct options options; 346 347 pam_std_option(&options, other_options, argc, argv); 348 349 PAM_LOG("Options processed"); 350 351 PAM_RETURN(PAM_SUCCESS); 352} 353 354PAM_EXTERN int 355pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv) 356{ 357 struct options options; 358 359 pam_std_option(&options, other_options, argc, argv); 360 361 PAM_LOG("Options processed"); 362 363 PAM_RETURN(PAM_SUCCESS); 364} 365 366/* 367 * password management 368 * 369 * standard Unix and NIS password changing 370 */ 371PAM_EXTERN int 372pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) 373{ 374 struct options options; 375 struct passwd *pwd; 376 int retval, retry, res, got; 377 const char *user, *pass; 378 char *new_pass, *new_pass_, *encrypted; 379 380 pam_std_option(&options, other_options, argc, argv); 381 382 PAM_LOG("Options processed"); 383 384 if (pam_test_option(&options, PAM_OPT_AUTH_AS_SELF, NULL)) 385 pwd = getpwnam(getlogin()); 386 else { 387 retval = pam_get_user(pamh, &user, NULL); 388 if (retval != PAM_SUCCESS) 389 PAM_RETURN(retval); 390 pwd = getpwnam(user); 391 } 392 393 PAM_LOG("Got user: %s", user); 394 395 if (flags & PAM_PRELIM_CHECK) { 396 397 PAM_LOG("PRELIM round; checking user password"); 398 399 if (pwd->pw_passwd[0] == '\0' 400 && pam_test_option(&options, PAM_OPT_NULLOK, NULL)) { 401 /* 402 * No password case. XXX Are we giving too much away 403 * by not prompting for a password? 404 */ 405 PAM_LOG("No password, and null password OK"); 406 PAM_RETURN(PAM_SUCCESS); 407 } 408 else { 409 retval = pam_get_pass(pamh, &pass, 410 PASSWORD_PROMPT_EXPIRED, &options); 411 if (retval != PAM_SUCCESS) 412 PAM_RETURN(retval); 413 PAM_LOG("Got password: %s", pass); 414 } 415 encrypted = crypt(pass, pwd->pw_passwd); 416 if (pass[0] == '\0' && pwd->pw_passwd[0] != '\0') 417 encrypted = ":"; 418 419 PAM_LOG("Encrypted password 1 is: %s", encrypted); 420 PAM_LOG("Encrypted password 2 is: %s", pwd->pw_passwd); 421 422 if (strcmp(encrypted, pwd->pw_passwd) != 0) 423 PAM_RETURN(PAM_AUTH_ERR); 424 425 retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *)pass); 426 pass = NULL; 427 if (retval != PAM_SUCCESS) 428 PAM_RETURN(retval); 429 430 PAM_LOG("Stashed old password"); 431 432 retval = pam_set_item(pamh, PAM_AUTHTOK, (const void *)pass); 433 if (retval != PAM_SUCCESS) 434 PAM_RETURN(retval); 435 436 PAM_LOG("Voided old password"); 437 438 PAM_RETURN(PAM_SUCCESS); 439 } 440 else if (flags & PAM_UPDATE_AUTHTOK) { 441 PAM_LOG("UPDATE round; checking user password"); 442 443 retval = pam_get_item(pamh, PAM_OLDAUTHTOK, 444 (const void **)&pass); 445 if (retval != PAM_SUCCESS) 446 PAM_RETURN(retval); 447 448 PAM_LOG("Got old password: %s", pass); 449 450 got = 0; 451 retry = 0; 452 while (retry++ < MAX_TRIES) { 453 new_pass = NULL; 454 retval = pam_prompt(pamh, PAM_PROMPT_ECHO_OFF, 455 NEW_PASSWORD_PROMPT_1, &new_pass); 456 457 if (new_pass == NULL) 458 new_pass = ""; 459 460 if (retval == PAM_SUCCESS) { 461 new_pass_ = NULL; 462 retval = pam_prompt(pamh, PAM_PROMPT_ECHO_OFF, 463 NEW_PASSWORD_PROMPT_2, &new_pass_); 464 465 if (new_pass_ == NULL) 466 new_pass_ = ""; 467 468 if (retval == PAM_SUCCESS) { 469 if (strcmp(new_pass, new_pass_) == 0) { 470 got = 1; 471 break; 472 } 473 else 474 PAM_VERBOSE_ERROR("Password mismatch"); 475 } 476 } 477 } 478 479 if (!got) { 480 PAM_VERBOSE_ERROR("Unable to get valid password"); 481 PAM_RETURN(PAM_PERM_DENIED); 482 } 483 484 PAM_LOG("Got new password: %s", new_pass); 485 486#ifdef YP 487 /* If NIS is set in the passwd database, use it */ 488 res = use_yp((char *)user, 0, 0); 489 if (res == USER_YP_ONLY) { 490 if (!pam_test_option(&options, PAM_OPT_LOCAL_PASS, 491 NULL)) 492 retval = yp_passwd(user, new_pass); 493 else { 494 /* Reject 'local' flag if NIS is on and the user 495 * is not local 496 */ 497 retval = PAM_PERM_DENIED; 498 PAM_LOG("Unknown local user: %s", user); 499 } 500 } 501 else if (res == USER_LOCAL_ONLY) { 502 if (!pam_test_option(&options, PAM_OPT_NIS_PASS, NULL)) 503 retval = local_passwd(user, new_pass); 504 else { 505 /* Reject 'nis' flag if user is only local */ 506 retval = PAM_PERM_DENIED; 507 PAM_LOG("Unknown NIS user: %s", user); 508 } 509 } 510 else if (res == USER_YP_AND_LOCAL) { 511 if (pam_test_option(&options, PAM_OPT_NIS_PASS, NULL)) 512 retval = yp_passwd(user, new_pass); 513 else 514 retval = local_passwd(user, new_pass); 515 } 516 else 517 retval = PAM_ABORT; /* Bad juju */ 518#else 519 retval = local_passwd(user, new_pass); 520#endif 521 522 /* XXX wipe the mem as well */ 523 pass = NULL; 524 new_pass = NULL; 525 } 526 else { 527 /* Very bad juju */ 528 retval = PAM_ABORT; 529 PAM_LOG("Illegal 'flags'"); 530 } 531 532 PAM_RETURN(retval); 533} 534 535/* Mostly stolen from passwd(1)'s local_passwd.c - markm */ 536 537static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ 538 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 539 540static void 541to64(char *s, long v, int n) 542{ 543 while (--n >= 0) { 544 *s++ = itoa64[v&0x3f]; 545 v >>= 6; 546 } 547} 548 549static int 550local_passwd(const char *user, const char *pass) 551{ 552 login_cap_t * lc; 553 struct passwd *pwd; 554 struct timeval tv; 555 int pfd, tfd; 556 char *crypt_type, salt[32]; 557 558 pwd = getpwnam(user); 559 if (pwd == NULL) 560 return(PAM_ABORT); /* Really bad things */ 561 562#ifdef YP 563 pwd = (struct passwd *)&local_password; 564#endif 565 pw_init(); 566 567 pwd->pw_change = 0; 568 lc = login_getclass(NULL); 569 crypt_type = login_getcapstr(lc, "passwd_format", 570 PASSWORD_HASH, PASSWORD_HASH); 571 if (login_setcryptfmt(lc, crypt_type, NULL) == NULL) 572 syslog(LOG_ERR, "cannot set password cipher"); 573 login_close(lc); 574 /* Salt suitable for anything */ 575 srandomdev(); 576 gettimeofday(&tv, 0); 577 to64(&salt[0], random(), 3); 578 to64(&salt[3], tv.tv_usec, 3); 579 to64(&salt[6], tv.tv_sec, 2); 580 to64(&salt[8], random(), 5); 581 to64(&salt[13], random(), 5); 582 to64(&salt[17], random(), 5); 583 to64(&salt[22], random(), 5); 584 salt[27] = '\0'; 585 586 pwd->pw_passwd = crypt(pass, salt); 587 588 pfd = pw_lock(); 589 tfd = pw_tmp(); 590 pw_copy(pfd, tfd, pwd); 591 592 if (!pw_mkdb((char *)user)) 593 pw_error((char *)NULL, 0, 1); 594 595 return PAM_SUCCESS; 596} 597 598#ifdef YP 599/* Stolen from src/usr.bin/passwd/yp_passwd.c, carrying copyrights of: 600 * Copyright (c) 1992/3 Theo de Raadt <deraadt@fsa.ca> 601 * Copyright (c) 1994 Olaf Kirch <okir@monad.swb.de> 602 * Copyright (c) 1995 Bill Paul <wpaul@ctr.columbia.edu> 603 */ 604int 605yp_passwd(const char *user, const char *pass) 606{ 607 struct master_yppasswd master_yppasswd; 608 struct passwd *pwd; 609 struct rpc_err err; 610 struct timeval tv; 611 struct yppasswd yppasswd; 612 CLIENT *clnt; 613 login_cap_t *lc; 614 int *status; 615 uid_t uid; 616 char *master, *sockname = YP_SOCKNAME, salt[32]; 617 618 _use_yp = 1; 619 620 uid = getuid(); 621 622 master = get_yp_master(1); 623 if (master == NULL) 624 return PAM_ABORT; /* Major disaster */ 625 626 /* 627 * It is presumed that by the time we get here, use_yp() 628 * has been called and that we have verified that the user 629 * actually exists. This being the case, the yp_password 630 * stucture has already been filled in for us. 631 */ 632 633 /* Use the correct password */ 634 pwd = (struct passwd *)&yp_password; 635 636 pwd->pw_change = 0; 637 638 /* Initialize password information */ 639 if (suser_override) { 640 master_yppasswd.newpw.pw_passwd = strdup(pwd->pw_passwd); 641 master_yppasswd.newpw.pw_name = strdup(pwd->pw_name); 642 master_yppasswd.newpw.pw_uid = pwd->pw_uid; 643 master_yppasswd.newpw.pw_gid = pwd->pw_gid; 644 master_yppasswd.newpw.pw_expire = pwd->pw_expire; 645 master_yppasswd.newpw.pw_change = pwd->pw_change; 646 master_yppasswd.newpw.pw_fields = pwd->pw_fields; 647 master_yppasswd.newpw.pw_gecos = strdup(pwd->pw_gecos); 648 master_yppasswd.newpw.pw_dir = strdup(pwd->pw_dir); 649 master_yppasswd.newpw.pw_shell = strdup(pwd->pw_shell); 650 master_yppasswd.newpw.pw_class = pwd->pw_class != NULL ? 651 strdup(pwd->pw_class) : ""; 652 master_yppasswd.oldpass = ""; 653 master_yppasswd.domain = yp_domain; 654 } else { 655 yppasswd.newpw.pw_passwd = strdup(pwd->pw_passwd); 656 yppasswd.newpw.pw_name = strdup(pwd->pw_name); 657 yppasswd.newpw.pw_uid = pwd->pw_uid; 658 yppasswd.newpw.pw_gid = pwd->pw_gid; 659 yppasswd.newpw.pw_gecos = strdup(pwd->pw_gecos); 660 yppasswd.newpw.pw_dir = strdup(pwd->pw_dir); 661 yppasswd.newpw.pw_shell = strdup(pwd->pw_shell); 662 yppasswd.oldpass = ""; 663 } 664 665 if (login_setcryptfmt(lc, "md5", NULL) == NULL) 666 syslog(LOG_ERR, "cannot set password cipher"); 667 login_close(lc); 668 /* Salt suitable for anything */ 669 srandomdev(); 670 gettimeofday(&tv, 0); 671 to64(&salt[0], random(), 3); 672 to64(&salt[3], tv.tv_usec, 3); 673 to64(&salt[6], tv.tv_sec, 2); 674 to64(&salt[8], random(), 5); 675 to64(&salt[13], random(), 5); 676 to64(&salt[17], random(), 5); 677 to64(&salt[22], random(), 5); 678 salt[27] = '\0'; 679 680 if (suser_override) 681 master_yppasswd.newpw.pw_passwd = crypt(pass, salt); 682 else 683 yppasswd.newpw.pw_passwd = crypt(pass, salt); 684 685 if (suser_override) { 686 if ((clnt = clnt_create(sockname, MASTER_YPPASSWDPROG, 687 MASTER_YPPASSWDVERS, "unix")) == NULL) { 688 syslog(LOG_ERR, 689 "Cannot contact rpc.yppasswdd on host %s: %s", 690 master, clnt_spcreateerror("")); 691 return PAM_ABORT; 692 } 693 } 694 else { 695 if ((clnt = clnt_create(master, YPPASSWDPROG, 696 YPPASSWDVERS, "udp")) == NULL) { 697 syslog(LOG_ERR, 698 "Cannot contact rpc.yppasswdd on host %s: %s", 699 master, clnt_spcreateerror("")); 700 return PAM_ABORT; 701 } 702 } 703 /* 704 * The yppasswd.x file said `unix authentication required', 705 * so I added it. This is the only reason it is in here. 706 * My yppasswdd doesn't use it, but maybe some others out there 707 * do. --okir 708 */ 709 clnt->cl_auth = authunix_create_default(); 710 711 if (suser_override) 712 status = yppasswdproc_update_master_1(&master_yppasswd, clnt); 713 else 714 status = yppasswdproc_update_1(&yppasswd, clnt); 715 716 clnt_geterr(clnt, &err); 717 718 auth_destroy(clnt->cl_auth); 719 clnt_destroy(clnt); 720 721 if (err.re_status != RPC_SUCCESS || status == NULL || *status) 722 return PAM_ABORT; 723 724 return (err.re_status || status == NULL || *status) 725 ? PAM_ABORT : PAM_SUCCESS; 726} 727#endif /* YP */ 728 729PAM_MODULE_ENTRY("pam_unix"); 730