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