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