1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Beware those who enter here. 28 * The logic may appear hairy, but it's been ARCed. 29 * See /shared/sac/PSARC/1995/122/mail 30 */ 31 32 #include <sys/types.h> 33 #include <sys/stat.h> 34 #include <ctype.h> 35 #include <unistd.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <stdio.h> 39 #include <errno.h> 40 #include <syslog.h> 41 #include <pwd.h> 42 #include <shadow.h> 43 #include <signal.h> 44 #include <crypt.h> 45 #include <rpc/rpc.h> 46 #include <rpcsvc/yppasswd.h> 47 #include <utmpx.h> 48 #include <nss_dbdefs.h> 49 50 #define STRSIZE 100 51 #define FINGERSIZE (4 * STRSIZE - 4) 52 #define SHELLSIZE (STRSIZE - 2) 53 #define UTUSERLEN (sizeof (((struct utmpx *)0)->ut_user)) 54 55 /* Prototypes */ 56 extern bool_t validloginshell(char *sh, char *arg, int); 57 extern int validstr(char *str, size_t size); 58 extern int yplckpwdf(); 59 extern int ypulckpwdf(); 60 61 static char * 62 cryptoldpasswd(char *oldpass, char *salt, char *acctname) 63 { 64 char *oldpass_crypt = NULL; 65 66 if ((oldpass_crypt = crypt(oldpass, salt)) == NULL) { 67 if (errno == EINVAL) { 68 syslog(LOG_ERR, 69 "yppasswdd: password not changed for \"%s\" - " 70 "crypt module not supported on the master\n", 71 acctname); 72 } else { 73 syslog(LOG_ERR, 74 "yppasswdd: password not changed for \"%s\" - " 75 "%s\n", acctname, strerror(errno)); 76 } 77 } 78 return (oldpass_crypt); 79 } 80 81 void 82 changepasswd(SVCXPRT *transp) 83 { 84 /* 85 * Put these numeric constants into const variables so 86 * a) they're visible in a debugger 87 * b) the compiler can play it's cool games with em 88 */ 89 static const int cryptpwsize = CRYPT_MAXCIPHERTEXTLEN; 90 static const int fingersize = FINGERSIZE; 91 static const int shellsize = SHELLSIZE; 92 93 struct yppasswd yppwd; 94 struct passwd newpw, opwd; 95 struct spwd ospwd; 96 struct sigaction sa, osa1, osa2, osa3; 97 struct stat pwstat, spstat, adjstat; 98 char *oldpass_crypt = NULL; 99 100 char newpasswdfile[FILENAME_MAX]; 101 char newshadowfile[FILENAME_MAX]; 102 char newadjunctfile[FILENAME_MAX]; 103 char tmppasswdfile[FILENAME_MAX]; 104 char tmpshadowfile[FILENAME_MAX]; 105 char tmpadjunctfile[FILENAME_MAX]; 106 char pwbuf[NSS_LINELEN_PASSWD], spbuf[NSS_LINELEN_SHADOW]; 107 char adjbuf[BUFSIZ+1], adjbuf_new[BUFSIZ+1], cmdbuf[BUFSIZ]; 108 char adj_encrypt[CRYPT_MAXCIPHERTEXTLEN + 1]; 109 /* 110 * The adj_crypt_* pointers are used to point into adjbuf 111 * NOT adj_encrypt 112 */ 113 char *adj_crypt_begin, *adj_crypt_end = NULL; 114 char name[UTUSERLEN + sizeof (":")]; 115 char *p; 116 117 FILE *opwfp = NULL, *ospfp = NULL, *oadjfp = NULL, 118 *npwfp = NULL, *nspfp = NULL, *nadjfp = NULL; 119 int npwfd = -1, nspfd = -1, nadjfd = -1; 120 121 int i, ans, chsh, chpw, chgecos, namelen; 122 int gotadjunct = 0, gotshadow = 0, gotpasswd = 0; 123 int doneflag = 0, root_on_master = 0; 124 pid_t retval; 125 126 time_t now; 127 128 long pwpos = 0, sppos = 0; 129 130 /* Globals :-( */ 131 extern int single, nogecos, noshell, nopw, mflag, Mstart, Argc; 132 extern char **Argv; 133 extern char passwd_file[], shadow_file[], adjunct_file[]; 134 extern int useadjunct; 135 extern int useshadow; 136 137 /* Clean out yppwd */ 138 memset(&yppwd, 0, sizeof (struct yppasswd)); 139 140 /* Get the RPC args */ 141 if (!svc_getargs(transp, xdr_yppasswd, (caddr_t)&yppwd)) { 142 svcerr_decode(transp); 143 return; 144 } 145 146 /* Perform basic validation */ 147 if (/* (!validstr(yppwd.oldpass, PWSIZE)) || */ /* see PR:nis/38 */ 148 (!validstr(yppwd.newpw.pw_passwd, cryptpwsize)) || 149 (!validstr(yppwd.newpw.pw_name, UTUSERLEN)) || 150 (!validstr(yppwd.newpw.pw_gecos, fingersize)) || 151 (!validstr(yppwd.newpw.pw_shell, shellsize))) { 152 svcerr_decode(transp); 153 return; 154 } 155 156 /* 157 * Special case: root on the master server can change other users' 158 * passwords without first entering the old password. We need to 159 * ensure that this is indeed root on the master server. (bug 1253949) 160 */ 161 if (strcmp(transp->xp_netid, "ticlts") == 0) { 162 svc_local_cred_t cred; 163 if (!svc_get_local_cred(transp, &cred)) { 164 syslog(LOG_ERR, "yppasswdd: Couldn't get " 165 "local user credentials.\n"); 166 } else if (cred.ruid == 0) 167 root_on_master = 1; 168 } 169 170 newpw = yppwd.newpw; 171 strcpy(name, newpw.pw_name); 172 strcat(name, ":"); 173 namelen = strlen(name); 174 ans = 2; 175 chsh = chpw = chgecos = 0; 176 177 /* Get all the filenames straight */ 178 strcpy(newpasswdfile, passwd_file); 179 strcat(newpasswdfile, ".ptmp"); 180 strcpy(newshadowfile, shadow_file); 181 strcat(newshadowfile, ".ptmp"); 182 strcpy(newadjunctfile, adjunct_file); 183 strcat(newadjunctfile, ".ptmp"); 184 185 memset(&sa, 0, sizeof (struct sigaction)); 186 sa.sa_handler = SIG_IGN; 187 sigaction(SIGTSTP, &sa, (struct sigaction *)0); 188 sigaction(SIGHUP, &sa, &osa1); 189 sigaction(SIGINT, &sa, &osa2); 190 sigaction(SIGQUIT, &sa, &osa3); 191 192 /* Lock, then open the passwd and shadow files */ 193 194 if (yplckpwdf() < 0) { 195 syslog(LOG_ERR, 196 "yppasswdd: Password file(s) busy. " 197 "Try again later.\n"); 198 ans = 8; 199 goto cleanup; 200 } 201 202 if ((opwfp = fopen(passwd_file, "r")) == NULL) { 203 syslog(LOG_ERR, "yppasswdd: Could not open %s\n", passwd_file); 204 goto cleanup; 205 } 206 207 fstat(fileno(opwfp), &pwstat); 208 209 if (useshadow) { 210 if ((ospfp = fopen(shadow_file, "r")) == NULL) { 211 syslog(LOG_ERR, 212 "yppasswdd: Could not open %s\n", shadow_file); 213 goto cleanup; 214 } 215 216 fstat(fileno(ospfp), &spstat); 217 } 218 219 if (useadjunct) { 220 if ((oadjfp = fopen(adjunct_file, "r")) == NULL) { 221 syslog(LOG_ERR, 222 "yppasswdd: Could not open %s\n", 223 adjunct_file); 224 goto cleanup; 225 } 226 227 fstat(fileno(oadjfp), &adjstat); 228 } 229 230 /* 231 * Open the new passwd and shadow tmp files, 232 * first with open and then create a FILE * with fdopen() 233 */ 234 if ((npwfd = open(newpasswdfile, O_WRONLY | O_CREAT | O_EXCL, 235 pwstat.st_mode)) < 0) { 236 if (errno == EEXIST) { 237 syslog(LOG_WARNING, 238 "yppasswdd: passwd file busy - try again\n"); 239 ans = 8; 240 } else { 241 syslog(LOG_ERR, "yppasswdd: %s: %m", 242 newpasswdfile); 243 ans = 9; 244 } 245 goto cleanup; 246 } 247 248 fchown(npwfd, pwstat.st_uid, pwstat.st_gid); 249 250 if ((npwfp = fdopen(npwfd, "w")) == NULL) { 251 syslog(LOG_ERR, 252 "yppasswdd: fdopen() on %s failed\n", newpasswdfile); 253 goto cleanup; 254 } 255 256 if (useshadow) { 257 if ((nspfd = open(newshadowfile, O_WRONLY | O_CREAT | O_EXCL, 258 spstat.st_mode)) < 0) { 259 if (errno == EEXIST) { 260 syslog(LOG_WARNING, 261 "yppasswdd: shadow file busy - try " 262 "again\n"); 263 ans = 8; 264 } else { 265 syslog(LOG_ERR, "yppasswdd: %s: %m", 266 newshadowfile); 267 ans = 9; 268 } 269 goto cleanup; 270 } 271 272 fchown(nspfd, spstat.st_uid, spstat.st_gid); 273 274 if ((nspfp = fdopen(nspfd, "w")) == NULL) { 275 syslog(LOG_ERR, 276 "yppasswdd: fdopen() on %s failed\n", 277 newshadowfile); 278 goto cleanup; 279 } 280 } 281 282 if (useadjunct) { 283 if ((nadjfd = open(newadjunctfile, O_WRONLY | O_CREAT | O_EXCL, 284 adjstat.st_mode)) < 0) { 285 if (errno == EEXIST) { 286 syslog(LOG_WARNING, 287 "yppasswdd: adjunct file busy - try " 288 "again\n"); 289 ans = 8; 290 } else { 291 syslog(LOG_ERR, "yppasswdd: %s: %m", 292 newadjunctfile); 293 ans = 9; 294 } 295 goto cleanup; 296 } 297 298 fchown(nadjfd, adjstat.st_uid, adjstat.st_gid); 299 300 if ((nadjfp = fdopen(nadjfd, "w")) == NULL) { 301 syslog(LOG_ERR, 302 "yppasswdd: fdopen() on %s failed\n", 303 newadjunctfile); 304 goto cleanup; 305 } 306 } 307 308 /* 309 * The following code may not seem all that elegant, but my 310 * interpretation of the man pages relating to the passwd and 311 * shadow files would seem to indicate that there is no guarantee 312 * that the entries contained in those files will be in the same 313 * order... 314 * 315 * So here's the high level overview: 316 * 317 * Loop through the passwd file reading in lines and writing them 318 * out to the new file UNTIL we get to the correct entry. 319 * IF we have a shadow file, loop through it reading in lines and 320 * writing them out to the new file UNTIL we get to the correct 321 * entry. IF we have an adjunct file, loop through it reading in 322 * lines and writing them out to the new file UNTIL we get to the 323 * correct entry. 324 * 325 * Figure out what's changing, contruct the new passwd, shadow, 326 * and adjunct entries and spit em out to the temp files. 327 * At this point, set the done flag and leap back into the loop(s) 328 * until you're finished with the files and then leap to the 329 * section that installs the new files. 330 */ 331 332 loop_in_files: 333 /* While we find things in the passwd file */ 334 while (fgets(pwbuf, NSS_LINELEN_PASSWD, opwfp)) { 335 336 /* 337 * Is this the passwd entry we want? 338 * If not, then write it out to the new passwd temp file 339 * and remember our position. 340 */ 341 if (doneflag || strncmp(name, pwbuf, namelen)) { 342 if (fputs(pwbuf, npwfp) == EOF) { 343 syslog(LOG_ERR, 344 "yppasswdd: write to passwd file " 345 "failed.\n"); 346 goto cleanup; 347 } 348 pwpos = ftell(opwfp); 349 continue; 350 } 351 gotpasswd = 1; 352 break; 353 } 354 355 /* no match */ 356 if (!gotpasswd) { 357 syslog(LOG_ERR, "yppasswdd: user %s does not exist\n", name); 358 goto cleanup; 359 } 360 361 /* While we find things in the shadow file */ 362 while (useshadow && fgets(spbuf, NSS_LINELEN_SHADOW, ospfp)) { 363 364 /* 365 * Is this the shadow entry that we want? 366 * If not, write it out to the new shadow temp file 367 * and remember our position. 368 */ 369 if (doneflag || strncmp(name, spbuf, namelen)) { 370 if (fputs(spbuf, nspfp) == EOF) { 371 syslog(LOG_ERR, 372 "yppasswdd: write to shadow file " 373 "failed.\n"); 374 goto cleanup; 375 } 376 sppos = ftell(ospfp); 377 continue; 378 } 379 gotshadow = 1; 380 break; 381 } 382 383 /* While we find things in the adjunct file */ 384 while (useadjunct && fgets(adjbuf, BUFSIZ, oadjfp)) { 385 386 /* 387 * is this the adjunct entry that we want? 388 * If not, write it out to the new temp file 389 * and remember our position. 390 */ 391 if (doneflag || strncmp(name, adjbuf, namelen)) { 392 if (fputs(adjbuf, nadjfp) == EOF) { 393 syslog(LOG_ERR, 394 "yppasswdd: write to adjunct file " 395 "failed.\n"); 396 goto cleanup; 397 } 398 continue; 399 } 400 gotadjunct = 1; 401 break; 402 } 403 404 if (doneflag) 405 goto install_files; 406 407 if (useshadow && !gotshadow) { 408 syslog(LOG_ERR, "yppasswdd: no passwd in shadow for %s\n", 409 newpw.pw_name); 410 ans = 4; 411 goto cleanup; 412 } 413 if (useadjunct && !gotadjunct) { 414 syslog(LOG_ERR, "yppasswdd: no passwd in adjunct for %s\n", 415 newpw.pw_name); 416 ans = 4; 417 goto cleanup; 418 } 419 420 /* 421 * Now that we've read in the correct passwd AND 422 * shadow lines, we'll rewind to the beginning of 423 * those lines and let the fget*ent() calls do 424 * the work. Since we are only working with the 425 * first two fields of the adjunct entry, leave 426 * it as a char array. 427 */ 428 fseek(opwfp, pwpos, SEEK_SET); 429 opwd = *fgetpwent(opwfp); 430 431 if (useshadow) { 432 fseek(ospfp, sppos, SEEK_SET); 433 ospwd = *fgetspent(ospfp); 434 } 435 436 oldpass_crypt = cryptoldpasswd(yppwd.oldpass, newpw.pw_passwd, 437 newpw.pw_name); 438 if (oldpass_crypt == NULL) { 439 ans = 3; 440 goto cleanup; 441 } 442 p = newpw.pw_passwd; 443 if ((!nopw) && 444 p && *p && 445 !((*p++ == '#') && (*p++ == '#') && 446 (strcmp(p, opwd.pw_name) == 0)) && 447 (strcmp(oldpass_crypt, newpw.pw_passwd) != 0)) 448 chpw = 1; 449 oldpass_crypt = NULL; 450 451 if ((!noshell) && (strcmp(opwd.pw_shell, newpw.pw_shell) != 0)) { 452 if (single) 453 chpw = 0; 454 chsh = 1; 455 } 456 457 if ((!nogecos) && (strcmp(opwd.pw_gecos, newpw.pw_gecos) != 0)) { 458 if (single) { 459 chpw = 0; 460 chsh = 0; 461 } 462 chgecos = 1; 463 } 464 465 if (!(chpw + chsh + chgecos)) { 466 syslog(LOG_NOTICE, "yppasswdd: no change for %s\n", 467 newpw.pw_name); 468 ans = 3; 469 goto cleanup; 470 } 471 472 if (useshadow && !root_on_master) { 473 oldpass_crypt = cryptoldpasswd(yppwd.oldpass, ospwd.sp_pwdp, 474 newpw.pw_name); 475 if (oldpass_crypt == NULL) 476 goto cleanup; 477 if (ospwd.sp_pwdp && *ospwd.sp_pwdp && 478 (strcmp(oldpass_crypt, ospwd.sp_pwdp) != 0)) { 479 480 syslog(LOG_NOTICE, "yppasswdd: passwd incorrect\n", 481 newpw.pw_name); 482 ans = 7; 483 goto cleanup; 484 } 485 } else if (useadjunct) { 486 /* 487 * Clear the adj_encrypt array. Extract the encrypted passwd 488 * into adj_encrypt by setting adj_crypt_begin and 489 * adj_crypt_end to point at the first character of the 490 * encrypted passwd and the first character following the 491 * encrypted passwd in adjbuf, respectively, and copy the 492 * stuff between (there may not be anything) into adj_ecrypt. 493 * Then, check that adj_encrypt contains something and that 494 * the old passwd is correct. 495 */ 496 memset(adj_encrypt, 0, sizeof (adj_encrypt)); 497 adj_crypt_begin = adjbuf + namelen; 498 adj_crypt_end = strchr(adj_crypt_begin, ':'); 499 strncpy(adj_encrypt, adj_crypt_begin, 500 adj_crypt_end - adj_crypt_begin); 501 oldpass_crypt = cryptoldpasswd(yppwd.oldpass, adj_encrypt, 502 newpw.pw_name); 503 if (oldpass_crypt == NULL) 504 goto cleanup; 505 if (!root_on_master && *adj_encrypt && 506 (strcmp(oldpass_crypt, adj_encrypt) != 0)) { 507 508 syslog(LOG_NOTICE, "yppasswdd: passwd incorrect\n", 509 newpw.pw_name); 510 ans = 7; 511 goto cleanup; 512 } 513 } else { 514 oldpass_crypt = cryptoldpasswd(yppwd.oldpass, opwd.pw_passwd, 515 newpw.pw_name); 516 if (oldpass_crypt == NULL) 517 goto cleanup; 518 if (!root_on_master && opwd.pw_passwd && *opwd.pw_passwd && 519 (strcmp(oldpass_crypt, opwd.pw_passwd) != 0)) { 520 521 syslog(LOG_NOTICE, "yppasswdd: passwd incorrect\n", 522 newpw.pw_name); 523 ans = 7; 524 goto cleanup; 525 } 526 } 527 528 #ifdef DEBUG 529 printf("%d %d %d\n", chsh, chgecos, chpw); 530 531 printf("%s %s %s\n", 532 yppwd.newpw.pw_shell, 533 yppwd.newpw.pw_gecos, 534 yppwd.newpw.pw_passwd); 535 536 printf("%s %s %s\n", 537 opwd.pw_shell, 538 opwd.pw_gecos, 539 ospwd.sp_pwdp); 540 #endif 541 542 if (chsh && 543 !validloginshell(opwd.pw_shell, newpw.pw_shell, root_on_master)) { 544 goto cleanup; 545 } 546 547 /* security hole fix from original source */ 548 for (p = newpw.pw_name; (*p != '\0'); p++) 549 if ((*p == ':') || !(isprint(*p))) 550 *p = '$'; /* you lose buckwheat */ 551 for (p = newpw.pw_passwd; (*p != '\0'); p++) 552 if ((*p == ':') || !(isprint(*p))) 553 *p = '$'; /* you lose buckwheat */ 554 555 if (chgecos) 556 opwd.pw_gecos = newpw.pw_gecos; 557 558 if (chsh) 559 opwd.pw_shell = newpw.pw_shell; 560 561 /* 562 * If we're changing the shell or gecos fields and we're 563 * using a shadow or adjunct file or not changing the passwd 564 * then go ahead and update the passwd file. The case where 565 * the passwd is being changed and we are not using a shadow 566 * or adjunct file is handled later. 567 */ 568 if ((chsh || chgecos) && (useshadow || useadjunct || !chpw) && 569 putpwent(&opwd, npwfp)) { 570 571 syslog(LOG_ERR, "yppasswdd: putpwent failed: %s\n", 572 passwd_file); 573 goto cleanup; 574 } 575 576 if (chpw) { 577 if (useshadow) { 578 ospwd.sp_pwdp = newpw.pw_passwd; 579 now = DAY_NOW; 580 /* password aging - bug for bug compatibility */ 581 if (ospwd.sp_max != -1) { 582 if (now < ospwd.sp_lstchg + ospwd.sp_min) { 583 syslog(LOG_ERR, 584 "yppasswdd: Sorry: < %ld days " 585 "since the last change.\n", 586 ospwd.sp_min); 587 goto cleanup; 588 } 589 } 590 ospwd.sp_lstchg = now; 591 if (putspent(&ospwd, nspfp)) { 592 syslog(LOG_ERR, 593 "yppasswdd: putspent failed: %s\n", 594 shadow_file); 595 goto cleanup; 596 } 597 } else if (useadjunct) { 598 sprintf(adjbuf_new, 599 "%s%s%s", name, newpw.pw_passwd, adj_crypt_end); 600 if (fputs(adjbuf_new, nadjfp) == EOF) { 601 syslog(LOG_ERR, 602 "yppasswdd: write to adjunct failed: %s\n", 603 adjunct_file); 604 goto cleanup; 605 } 606 } else { 607 opwd.pw_passwd = newpw.pw_passwd; 608 if (putpwent(&opwd, npwfp)) { 609 syslog(LOG_ERR, 610 "yppasswdd: putpwent failed: %s\n", 611 passwd_file); 612 goto cleanup; 613 } 614 } 615 } 616 617 if (!doneflag) { 618 doneflag = 1; 619 goto loop_in_files; 620 } 621 622 install_files: 623 /* 624 * Critical section, nothing special needs to be done since we 625 * hold exclusive access to the *.ptmp files 626 */ 627 fflush(npwfp); 628 if (useshadow) 629 fflush(nspfp); 630 if (useadjunct) 631 fflush(nadjfp); 632 633 strcpy(tmppasswdfile, passwd_file); 634 strcat(tmppasswdfile, "-"); 635 if (useshadow) { 636 strcpy(tmpshadowfile, shadow_file); 637 strcat(tmpshadowfile, "-"); 638 } 639 if (useadjunct) { 640 strcpy(tmpadjunctfile, adjunct_file); 641 strcat(tmpadjunctfile, "-"); 642 } 643 644 if ((!useshadow && !useadjunct) || (chsh || chgecos)) { 645 if (rename(passwd_file, tmppasswdfile) < 0) { 646 syslog(LOG_CRIT, "yppasswdd: failed to backup " 647 "passwd file: %m"); 648 goto cleanup; 649 } else { 650 if (rename(newpasswdfile, passwd_file) < 0) { 651 syslog(LOG_CRIT, 652 "yppasswdd: failed to mv passwd: %m"); 653 if (rename(tmppasswdfile, passwd_file) < 0) { 654 syslog(LOG_CRIT, 655 "yppasswdd: failed to restore " 656 "backup of passwd file: %m"); 657 } 658 goto cleanup; 659 } 660 } 661 } 662 663 if (useshadow && chpw) { 664 if (rename(shadow_file, tmpshadowfile) < 0) { 665 syslog(LOG_CRIT, "yppasswdd: failed to back up " 666 "shadow file: %m"); 667 if (rename(tmppasswdfile, passwd_file) < 0) { 668 syslog(LOG_CRIT, 669 "yppasswdd: failed to restore " 670 "backup of passwd file: %m"); 671 } 672 goto cleanup; 673 } else { 674 if (rename(newshadowfile, shadow_file) < 0) { 675 syslog(LOG_CRIT, 676 "yppasswdd: failed to mv shadow: %m"); 677 if (rename(tmpshadowfile, shadow_file) < 0) { 678 syslog(LOG_CRIT, 679 "yppasswdd: failed to restore " 680 "backup of shadow file: %m"); 681 } 682 if (rename(tmppasswdfile, passwd_file) < 0) { 683 syslog(LOG_CRIT, 684 "yppasswdd: failed to restore " 685 "backup of passwd file: %m"); 686 } 687 goto cleanup; 688 } 689 } 690 } else if (useadjunct && chpw) { 691 if (rename(adjunct_file, tmpadjunctfile) < 0) { 692 syslog(LOG_CRIT, "yppasswdd: failed to back up " 693 "adjunct file: %m"); 694 if (rename(tmppasswdfile, passwd_file) < 0) { 695 syslog(LOG_CRIT, 696 "yppasswdd: failed to restore backup " 697 "of passwd: %m"); 698 } 699 goto cleanup; 700 } else { 701 if (rename(newadjunctfile, adjunct_file) < 0) { 702 syslog(LOG_CRIT, 703 "yppassdd: failed to mv adjunct: %m"); 704 if (rename(tmppasswdfile, passwd_file) < 0) { 705 syslog(LOG_CRIT, 706 "yppasswdd: failed to restore " 707 "backup of passwd file: %m"); 708 } 709 if (rename(tmpadjunctfile, adjunct_file) < 0) { 710 syslog(LOG_CRIT, 711 "yppasswdd: failed to restore " 712 "backup of adjunct file: %m"); 713 } 714 goto cleanup; 715 } 716 } 717 } 718 719 if (doneflag) 720 ans = 0; 721 /* End critical section */ 722 723 /* 724 * Here we have come only after the new files have been successfully 725 * renamed to original files. At this point, the temp files would still 726 * be existing we need to remove them from the /etc directory 727 */ 728 unlink(tmppasswdfile); 729 if (useshadow) 730 unlink(tmpshadowfile); 731 if (useadjunct) 732 unlink(tmpadjunctfile); 733 734 cleanup: 735 736 /* If we don't have opwfp, then we didn't do anything */ 737 if (opwfp) { 738 fclose(opwfp); 739 740 if (ospfp) { 741 fclose(ospfp); 742 } 743 744 if (oadjfp) { 745 fclose(oadjfp); 746 } 747 748 unlink(newpasswdfile); 749 /* These tests are cheaper than failing syscalls */ 750 if (useshadow) 751 unlink(newshadowfile); 752 if (useadjunct) 753 unlink(newadjunctfile); 754 755 if (npwfp) { 756 fclose(npwfp); 757 758 if (nspfp) { 759 fclose(nspfp); 760 } 761 if (nadjfp) { 762 fclose(nadjfp); 763 } 764 } 765 } 766 767 ypulckpwdf(); 768 769 if (doneflag && mflag) { 770 retval = fork(); 771 if (retval < 0) { 772 syslog(LOG_ERR, "yppasswdd: Fork failed %m"); 773 } else if (retval == 0) { 774 strcpy(cmdbuf, "/usr/ccs/bin/make"); 775 for (i = Mstart + 1; i < Argc; i++) { 776 strcat(cmdbuf, " "); 777 strcat(cmdbuf, Argv[i]); 778 } 779 780 #ifdef DEBUG 781 syslog(LOG_ERR, "yppasswdd: about to " 782 "execute %s\n", cmdbuf); 783 #else 784 if (yplckpwdf() < 0) { 785 syslog(LOG_ERR, "yppasswdd: Couldn't get the " 786 "lock to update the maps"); 787 } else { 788 setpgrp(); 789 system(cmdbuf); 790 ypulckpwdf(); 791 } 792 #endif 793 exit(0); 794 } 795 } 796 797 sigaction(SIGHUP, &osa1, (struct sigaction *)0); 798 sigaction(SIGINT, &osa2, (struct sigaction *)0); 799 sigaction(SIGQUIT, &osa3, (struct sigaction *)0); 800 801 if (!svc_sendreply(transp, xdr_int, (char *)&ans)) 802 syslog(LOG_WARNING, 803 "yppasswdd: couldn\'t reply to RPC call\n"); 804 } 805