2 * Copyright (c) 1995, 1996
3 * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Bill Paul.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * $FreeBSD: src/usr.sbin/rpc.yppasswdd/yppasswdd_server.c,v 1.29 2003/06/15 21:24:45 mbr Exp $
35 #include <sys/param.h>
36 #include <sys/fcntl.h>
37 #include <sys/socket.h>
41 #include <arpa/inet.h>
42 #include <netinet/in.h>
60 #include <rpcsvc/yp.h>
62 #include <rpcsvc/ypclnt.h>
63 #include "yppasswdd_extern.h"
65 #include "yppasswd_private.h"
66 #include "ypxfr_extern.h"
67 #include "yp_extern.h"
69 static struct passwd yp_password
;
72 copy_yp_pass(char *p
, int x
, int m
)
77 yp_password
.pw_fields
= 0;
79 buf
= realloc(buf
, m
+ 10);
82 /* Turn all colons into NULLs */
83 while (strchr(s
, ':')) {
84 s
= (strchr(s
, ':') + 1);
89 #define EXPAND(e) e = t; while ((*t++ = *p++));
90 EXPAND(yp_password
.pw_name
);
91 yp_password
.pw_fields
|= _PWF_NAME
;
92 EXPAND(yp_password
.pw_passwd
);
93 yp_password
.pw_fields
|= _PWF_PASSWD
;
94 yp_password
.pw_uid
= atoi(p
);
96 yp_password
.pw_fields
|= _PWF_UID
;
97 yp_password
.pw_gid
= atoi(p
);
99 yp_password
.pw_fields
|= _PWF_GID
;
101 EXPAND(yp_password
.pw_class
);
102 yp_password
.pw_fields
|= _PWF_CLASS
;
103 yp_password
.pw_change
= atol(p
);
104 p
+= (strlen(p
) + 1);
105 yp_password
.pw_fields
|= _PWF_CHANGE
;
106 yp_password
.pw_expire
= atol(p
);
107 p
+= (strlen(p
) + 1);
108 yp_password
.pw_fields
|= _PWF_EXPIRE
;
110 EXPAND(yp_password
.pw_gecos
);
111 yp_password
.pw_fields
|= _PWF_GECOS
;
112 EXPAND(yp_password
.pw_dir
);
113 yp_password
.pw_fields
|= _PWF_DIR
;
114 EXPAND(yp_password
.pw_shell
);
115 yp_password
.pw_fields
|= _PWF_SHELL
;
121 validchars(char *arg
)
125 for (i
= 0; i
< strlen(arg
); i
++) {
126 if (iscntrl(arg
[i
])) {
127 yp_error("string contains a control character");
131 yp_error("string contains a colon");
134 /* Be evil: truncate strings with \n in them silently. */
135 if (arg
[i
] == '\n') {
144 validate_master(struct passwd
*opw __unused
, struct x_master_passwd
*npw
)
147 if (npw
->pw_name
[0] == '+' || npw
->pw_name
[0] == '-') {
148 yp_error("client tried to modify an NIS entry");
152 if (validchars(npw
->pw_shell
)) {
153 yp_error("specified shell contains invalid characters");
157 if (validchars(npw
->pw_gecos
)) {
158 yp_error("specified gecos field contains invalid characters");
162 if (validchars(npw
->pw_passwd
)) {
163 yp_error("specified password contains invalid characters");
170 validate(struct passwd
*opw
, struct x_passwd
*npw
)
173 if (npw
->pw_name
[0] == '+' || npw
->pw_name
[0] == '-') {
174 yp_error("client tried to modify an NIS entry");
178 if ((uid_t
)npw
->pw_uid
!= opw
->pw_uid
) {
179 yp_error("UID mismatch: client says user %s has UID %d",
180 npw
->pw_name
, npw
->pw_uid
);
181 yp_error("database says user %s has UID %d", opw
->pw_name
,
186 if ((gid_t
)npw
->pw_gid
!= opw
->pw_gid
) {
187 yp_error("GID mismatch: client says user %s has GID %d",
188 npw
->pw_name
, npw
->pw_gid
);
189 yp_error("database says user %s has GID %d", opw
->pw_name
,
195 * Don't allow the user to shoot himself in the foot,
198 if (!ok_shell(npw
->pw_shell
)) {
199 yp_error("%s is not a valid shell", npw
->pw_shell
);
203 if (validchars(npw
->pw_shell
)) {
204 yp_error("specified shell contains invalid characters");
208 if (validchars(npw
->pw_gecos
)) {
209 yp_error("specified gecos field contains invalid characters");
213 if (validchars(npw
->pw_passwd
)) {
214 yp_error("specified password contains invalid characters");
222 * In order to have one rpc.yppasswdd support multiple domains,
223 * we have to cheat: we search each directory under /var/yp
224 * and try to match the user in each master.passwd.byname
225 * map that we find. If the user matches (username, uid and gid
226 * all agree), then we use that domain. If we match the user in
227 * more than one database, we must abort.
230 find_domain(struct x_passwd
*pw
)
235 char yp_mapdir
[MAXPATHLEN
+ 2];
236 static char domain
[YPMAXDOMAIN
];
241 yp_error("performing multidomain lookup");
243 if ((dird
= opendir(yp_dir
)) == NULL
) {
244 yp_error("opendir(%s) failed: %s", yp_dir
, strerror(errno
));
248 while ((dirp
= readdir(dird
)) != NULL
) {
249 snprintf(yp_mapdir
, sizeof yp_mapdir
, "%s/%s",
250 yp_dir
, dirp
->d_name
);
251 if (stat(yp_mapdir
, &statbuf
) < 0) {
252 yp_error("stat(%s) failed: %s", yp_mapdir
,
257 if (S_ISDIR(statbuf
.st_mode
)) {
258 tmp
= (char *)dirp
->d_name
;
259 key
.data
= pw
->pw_name
;
260 key
.size
= strlen(pw
->pw_name
);
262 if (yp_get_record(tmp
,"master.passwd.byname",
263 &key
, &data
, 0) != YP_TRUE
) {
266 *((char *)data
.data
+ data
.size
) = '\0';
267 copy_yp_pass(data
.data
, 1, data
.size
);
268 if (yp_password
.pw_uid
== (uid_t
)pw
->pw_uid
&&
269 yp_password
.pw_gid
== (gid_t
)pw
->pw_gid
) {
271 snprintf(domain
, YPMAXDOMAIN
, "%s", tmp
);
278 yp_error("found same user in two different domains");
281 return((char *)&domain
);
284 static const char *maps
[] = {
285 "master.passwd.byname",
286 "master.passwd.byuid",
291 static const char *formats
[] = {
292 "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s",
293 "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s",
294 "%s:%s:%d:%d:%s:%s:%s",
295 "%s:%s:%d:%d:%s:%s:%s"
299 update_inplace(struct passwd
*pw
, char *domain
)
302 DBT key
= { NULL
, 0 };
303 DBT data
= { NULL
, 0 };
304 char pwbuf
[YPMAXRECORD
];
308 static char yp_last
[] = "YP_LAST_MODIFIED";
309 char yplastbuf
[YPMAXRECORD
];
311 snprintf(yplastbuf
, sizeof yplastbuf
, "%llu",
312 (unsigned long long)time(NULL
));
314 for (i
= 0; i
< 4; i
++) {
317 snprintf(keybuf
, sizeof keybuf
,
318 "%llu", (unsigned long long)pw
->pw_uid
);
320 key
.size
= strlen(keybuf
);
322 key
.data
= pw
->pw_name
;
323 key
.size
= strlen(pw
->pw_name
);
327 * XXX The passwd.byname and passwd.byuid maps come in
328 * two flavors: secure and insecure. The secure version
329 * has a '*' in the password field whereas the insecure one
330 * has a real crypted password. The maps will be insecure
331 * if they were built with 'unsecure = TRUE' enabled in
332 * /var/yp/Makefile, but we'd have no way of knowing if
333 * this has been done unless we were to try parsing the
334 * Makefile, which is a disgusting thought. Instead, we
335 * read the records from the maps, skip to the first ':'
336 * in them, and then look at the character immediately
337 * following it. If it's an '*' then the map is 'secure'
338 * and we must not insert a real password into the pw_passwd
339 * field. If it's not an '*', then we put the real crypted
342 if (yp_get_record(domain
,maps
[i
],&key
,&data
,1) != YP_TRUE
) {
343 yp_error("couldn't read %s/%s: %s", domain
,
344 maps
[i
], strerror(errno
));
348 if ((ptr
= strchr(data
.data
, ':')) == NULL
) {
349 yp_error("no colon in passwd record?!");
354 * XXX Supposing we have more than one user with the same
355 * UID? (Or more than one user with the same name?) We could
356 * end up modifying the wrong record if were not careful.
359 if (strncmp(data
.data
, pw
->pw_name
,
360 strlen(pw
->pw_name
))) {
361 yp_error("warning: found entry for UID %d "
362 "in map %s@%s with wrong name (%.*s)",
363 pw
->pw_uid
, maps
[i
], domain
,
364 (int)(ptr
- (char *)data
.data
),
366 yp_error("there may be more than one user "
367 "with the same UID - continuing");
372 * We're really being ultra-paranoid here.
373 * This is generally a 'can't happen' condition.
375 snprintf(pwbuf
, sizeof pwbuf
, ":%d:%d:", pw
->pw_uid
,
377 if (!strstr(data
.data
, pwbuf
)) {
378 yp_error("warning: found entry for user %s \
379 in map %s@%s with wrong UID", pw
->pw_name
, maps
[i
], domain
);
380 yp_error("there may be more than one user \
381 with the same name - continuing");
387 snprintf(pwbuf
, sizeof pwbuf
, formats
[i
],
388 pw
->pw_name
, pw
->pw_passwd
, pw
->pw_uid
,
389 pw
->pw_gid
, pw
->pw_class
, pw
->pw_change
,
390 pw
->pw_expire
, pw
->pw_gecos
, pw
->pw_dir
,
393 snprintf(pwbuf
, sizeof pwbuf
, formats
[i
],
394 pw
->pw_name
, *(ptr
+1) == '*' ? "*" : pw
->pw_passwd
,
395 pw
->pw_uid
, pw
->pw_gid
, pw
->pw_gecos
, pw
->pw_dir
,
399 #define FLAGS O_RDWR|O_CREAT
401 if ((dbp
= yp_open_db_rw(domain
, maps
[i
], FLAGS
)) == NULL
) {
402 yp_error("couldn't open %s/%s r/w: %s",domain
,
403 maps
[i
],strerror(errno
));
408 data
.size
= strlen(pwbuf
);
410 if (yp_put_record(dbp
, &key
, &data
, 1) != YP_TRUE
) {
411 yp_error("failed to update record in %s/%s", domain
,
418 key
.size
= strlen(yp_last
);
419 data
.data
= (char *)&yplastbuf
;
420 data
.size
= strlen(yplastbuf
);
422 if (yp_put_record(dbp
, &key
, &data
, 1) != YP_TRUE
) {
423 yp_error("failed to update timestamp in %s/%s", domain
,
436 yppasswdproc_update_1_svc(yppasswd
*argp
, struct svc_req
*rqstp
)
439 struct sockaddr_in
*rqhost
;
444 int passwd_changed
= 0;
445 int shell_changed
= 0;
446 int gecos_changed
= 0;
447 char *oldshell
= NULL
;
448 char *oldgecos
= NULL
;
450 char passfile_buf
[MAXPATHLEN
+ 2];
451 char passfile_hold_buf
[MAXPATHLEN
+ 2];
452 char *domain
= yppasswd_domain
;
454 static struct sockaddr_in clntaddr
;
455 static struct timeval t_saved
, t_test
;
458 * Normal user updates always use the 'default' master.passwd file.
461 passfile
= passfile_default
;
464 rqhost
= svc_getcaller(rqstp
->rq_xprt
);
466 gettimeofday(&t_test
, NULL
);
467 if (!bcmp(rqhost
, &clntaddr
, sizeof *rqhost
) &&
468 t_test
.tv_sec
> t_saved
.tv_sec
&&
469 t_test
.tv_sec
- t_saved
.tv_sec
< 300) {
471 bzero(&clntaddr
, sizeof clntaddr
);
472 bzero(&t_saved
, sizeof t_saved
);
476 bcopy(rqhost
, &clntaddr
, sizeof clntaddr
);
477 gettimeofday(&t_saved
, NULL
);
479 if (yp_access(resvport
? "master.passwd.byname" : NULL
, rqstp
)) {
480 yp_error("rejected update request from unauthorized host");
481 svcerr_auth(rqstp
->rq_xprt
, AUTH_BADCRED
);
486 * Step one: find the user. (It's kinda pointless to
487 * proceed if the user doesn't exist.) We look for the
488 * user in the master.passwd.byname database, _NOT_ by
489 * using getpwent() and friends! We can't use getpwent()
490 * since the NIS master server is not guaranteed to be
491 * configured as an NIS client.
495 if ((domain
= find_domain(&argp
->newpw
)) == NULL
) {
496 yp_error("multidomain lookup failed - aborting update");
499 yp_error("updating user %s in domain %s",
500 argp
->newpw
.pw_name
, domain
);
503 key
.data
= argp
->newpw
.pw_name
;
504 key
.size
= strlen(argp
->newpw
.pw_name
);
506 if ((rval
= yp_get_record(domain
,"master.passwd.byname",
507 &key
, &data
, 0)) != YP_TRUE
) {
508 if (rval
== YP_NOKEY
) {
509 yp_error("user %s not found in passwd database",
510 argp
->newpw
.pw_name
);
512 yp_error("database access error: %s",
518 /* Nul terminate, please. */
519 *((char *)data
.data
+ data
.size
) = '\0';
521 copy_yp_pass(data
.data
, 1, data
.size
);
523 /* Step 2: check that the supplied oldpass is valid. */
525 cryptpw
= crypt(argp
->oldpass
, yp_password
.pw_passwd
);
527 if (cryptpw
== NULL
|| strcmp(cryptpw
, yp_password
.pw_passwd
) != 0) {
528 yp_error("rejected change attempt -- bad password");
529 yp_error("client address: %s username: %s",
530 inet_ntoa(rqhost
->sin_addr
),
531 argp
->newpw
.pw_name
);
535 /* Step 3: validate the arguments passed to us by the client. */
537 if (validate(&yp_password
, &argp
->newpw
)) {
538 yp_error("rejecting change attempt: bad arguments");
539 yp_error("client address: %s username: %s",
540 inet_ntoa(rqhost
->sin_addr
),
541 argp
->newpw
.pw_name
);
542 svcerr_decode(rqstp
->rq_xprt
);
546 /* Step 4: update the user's passwd structure. */
548 if (!no_chsh
&& strcmp(argp
->newpw
.pw_shell
, yp_password
.pw_shell
)) {
549 oldshell
= yp_password
.pw_shell
;
550 yp_password
.pw_shell
= argp
->newpw
.pw_shell
;
555 if (!no_chfn
&& strcmp(argp
->newpw
.pw_gecos
, yp_password
.pw_gecos
)) {
556 oldgecos
= yp_password
.pw_gecos
;
557 yp_password
.pw_gecos
= argp
->newpw
.pw_gecos
;
561 if (strcmp(argp
->newpw
.pw_passwd
, yp_password
.pw_passwd
)) {
562 yp_password
.pw_passwd
= argp
->newpw
.pw_passwd
;
563 yp_password
.pw_change
= 0;
568 * If the caller specified a domain other than our 'default'
569 * domain, change the path to master.passwd accordingly.
572 if (strcmp(domain
, yppasswd_domain
)) {
573 snprintf(passfile_buf
, sizeof(passfile_buf
),
574 "%s/%s/master.passwd", yp_dir
, domain
);
575 passfile
= (char *)&passfile_buf
;
579 * Create a filename to hold the original master.passwd
580 * so if our call to yppwupdate fails we can roll back
582 snprintf(passfile_hold_buf
, sizeof(passfile_hold_buf
),
583 "%s.hold", passfile
);
584 passfile_hold
= (char *)&passfile_hold_buf
;
587 /* Step 5: make a new password file with the updated info. */
589 if (pw_init(dirname(passfile
), passfile
)) {
590 yp_error("pw_init() failed");
593 if ((pfd
= pw_lock()) == -1) {
595 yp_error("pw_lock() failed");
598 if ((tfd
= pw_tmp(-1)) == -1) {
600 yp_error("pw_tmp() failed");
603 if (pw_copy(pfd
, tfd
, &yp_password
, NULL
) == -1) {
605 yp_error("pw_copy() failed");
608 if (rename(passfile
, passfile_hold
) == -1) {
610 yp_error("rename of %s to %s failed", passfile
,
615 if (strcmp(passfile
, _PATH_MASTERPASSWD
) == 0) {
617 * NIS server is exporting the system's master.passwd.
618 * Call pw_mkdb to rebuild passwd and the .db files
620 if (pw_mkdb(yp_password
.pw_name
) == -1) {
622 yp_error("pw_mkdb() failed");
623 rename(passfile_hold
, passfile
);
628 * NIS server is exporting a private master.passwd.
629 * Rename tempfile into final location
631 if (rename(pw_tempname(), passfile
) == -1) {
633 yp_error("rename of %s to %s failed",
634 pw_tempname(), passfile
);
635 rename(passfile_hold
, passfile
);
643 if ((rval
= update_inplace(&yp_password
, domain
))) {
644 yp_error("inplace update failed -- rebuilding maps");
648 switch ((pid
= fork())) {
650 if (inplace
&& !rval
) {
651 execlp(MAP_UPDATE_PATH
, MAP_UPDATE
, passfile
,
652 yppasswd_domain
, "pushpw", NULL
);
654 execlp(MAP_UPDATE_PATH
, MAP_UPDATE
, passfile
,
655 yppasswd_domain
, NULL
);
657 yp_error("couldn't exec map update process: %s",
660 rename(passfile_hold
, passfile
);
664 yp_error("fork() failed: %s", strerror(errno
));
666 rename(passfile_hold
, passfile
);
670 unlink(passfile_hold
);
675 yp_error("update completed for user %s (uid %d) in %s:",
676 argp
->newpw
.pw_name
, argp
->newpw
.pw_uid
, passfile
);
679 yp_error("password changed");
682 yp_error("gecos changed ('%s' -> '%s')",
683 oldgecos
, argp
->newpw
.pw_gecos
);
686 yp_error("shell changed ('%s' -> '%s')",
687 oldshell
, argp
->newpw
.pw_shell
);
695 * Note that this function performs a little less sanity checking
696 * than the last one. Since only the superuser is allowed to use it,
697 * it is assumed that the caller knows what he's doing.
700 yppasswdproc_update_master_1_svc(master_yppasswd
*argp
, struct svc_req
*rqstp
)
709 char passfile_buf
[MAXPATHLEN
+ 2];
710 char passfile_hold_buf
[MAXPATHLEN
+ 2];
711 struct sockaddr_in
*rqhost
;
715 transp
= rqstp
->rq_xprt
;
718 * NO AF_INET CONNETCIONS ALLOWED!
720 rqhost
= svc_getcaller(transp
);
721 if (rqhost
->sin_family
!= AF_UNIX
) {
722 yp_error("Alert! %s/%d attempted to use superuser-only \
723 procedure!\n", inet_ntoa(rqhost
->sin_addr
), rqhost
->sin_port
);
724 svcerr_auth(transp
, AUTH_BADCRED
);
728 if (rqstp
->rq_cred
.oa_flavor
!= AUTH_SYS
) {
729 yp_error("caller didn't send proper credentials");
730 svcerr_auth(transp
, AUTH_BADCRED
);
734 if (__rpc_get_local_uid(transp
, &uid
) < 0) {
735 yp_error("caller didn't send proper credentials");
736 svcerr_auth(transp
, AUTH_BADCRED
);
741 yp_error("caller euid is %d, expecting 0 -- rejecting request",
743 svcerr_auth(rqstp
->rq_xprt
, AUTH_BADCRED
);
747 passfile
= passfile_default
;
749 key
.data
= argp
->newpw
.pw_name
;
750 key
.size
= strlen(argp
->newpw
.pw_name
);
753 * The superuser may add entries to the passwd maps if
754 * rpc.yppasswdd is started with the -a flag. Paranoia
755 * prevents me from allowing additions by default.
757 if ((rval
= yp_get_record(argp
->domain
, "master.passwd.byname",
758 &key
, &data
, 0)) != YP_TRUE
) {
759 if (rval
== YP_NOKEY
) {
760 yp_error("user %s not found in passwd database",
761 argp
->newpw
.pw_name
);
763 yp_error("notice: adding user %s to \
764 master.passwd database for domain %s", argp
->newpw
.pw_name
, argp
->domain
);
766 yp_error("restart rpc.yppasswdd with the -a flag to \
767 allow additions to be made to the password database");
769 yp_error("database access error: %s",
772 if (!allow_additions
)
776 /* Nul terminate, please. */
777 *((char *)data
.data
+ data
.size
) = '\0';
779 copy_yp_pass(data
.data
, 1, data
.size
);
783 * Perform a small bit of sanity checking.
785 if (validate_master(rval
== YP_TRUE
? &yp_password
:NULL
,&argp
->newpw
)){
786 yp_error("rejecting update attempt for %s: bad arguments",
787 argp
->newpw
.pw_name
);
792 * If the caller specified a domain other than our 'default'
793 * domain, change the path to master.passwd accordingly.
796 if (strcmp(argp
->domain
, yppasswd_domain
)) {
797 snprintf(passfile_buf
, sizeof(passfile_buf
),
798 "%s/%s/master.passwd", yp_dir
, argp
->domain
);
799 passfile
= (char *)&passfile_buf
;
803 * Create a filename to hold the original master.passwd
804 * so if our call to yppwupdate fails we can roll back
806 snprintf(passfile_hold_buf
, sizeof(passfile_hold_buf
),
807 "%s.hold", passfile
);
808 passfile_hold
= (char *)&passfile_hold_buf
;
810 if (pw_init(dirname(passfile
), passfile
)) {
811 yp_error("pw_init() failed");
814 if ((pfd
= pw_lock()) == -1) {
816 yp_error("pw_lock() failed");
819 if ((tfd
= pw_tmp(-1)) == -1) {
821 yp_error("pw_tmp() failed");
824 if (pw_copy(pfd
, tfd
, (struct passwd
*)&argp
->newpw
, NULL
) == -1) {
826 yp_error("pw_copy() failed");
829 if (rename(passfile
, passfile_hold
) == -1) {
831 yp_error("rename of %s to %s failed", passfile
,
835 if (strcmp(passfile
, _PATH_MASTERPASSWD
) == 0) {
837 * NIS server is exporting the system's master.passwd.
838 * Call pw_mkdb to rebuild passwd and the .db files
840 if (pw_mkdb(argp
->newpw
.pw_name
) == -1) {
842 yp_error("pw_mkdb() failed");
843 rename(passfile_hold
, passfile
);
848 * NIS server is exporting a private master.passwd.
849 * Rename tempfile into final location
851 if (rename(pw_tempname(), passfile
) == -1) {
853 yp_error("rename of %s to %s failed",
854 pw_tempname(), passfile
);
855 rename(passfile_hold
, passfile
);
862 if ((rval
= update_inplace((struct passwd
*)&argp
->newpw
,
864 yp_error("inplace update failed -- rebuilding maps");
868 switch ((pid
= fork())) {
870 if (inplace
&& !rval
) {
871 execlp(MAP_UPDATE_PATH
, MAP_UPDATE
, passfile
,
872 argp
->domain
, "pushpw", NULL
);
874 execlp(MAP_UPDATE_PATH
, MAP_UPDATE
, passfile
,
877 yp_error("couldn't exec map update process: %s",
880 rename(passfile_hold
, passfile
);
884 yp_error("fork() failed: %s", strerror(errno
));
886 rename(passfile_hold
, passfile
);
890 unlink(passfile_hold
);
894 yp_error("performed update of user %s (uid %d) domain %s",