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