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