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 *
cryptoldpasswd(char * oldpass,char * salt,char * acctname)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
changepasswd(SVCXPRT * transp)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