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 */
56extern bool_t validloginshell(char *sh, char *arg, int);
57extern int    validstr(char *str, size_t size);
58extern int yplckpwdf();
59extern int ypulckpwdf();
60
61static char *
62cryptoldpasswd(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
81void
82changepasswd(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;
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
332loop_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
622install_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
734cleanup:
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