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 $
33 * $DragonFly: src/usr.sbin/rpc.yppasswdd/yppasswdd_server.c,v 1.7 2005/11/25 00:32:49 swildner Exp $
36 #include <sys/param.h>
37 #include <sys/fcntl.h>
38 #include <sys/socket.h>
42 #include <arpa/inet.h>
43 #include <netinet/in.h>
61 #include <rpcsvc/yp.h>
63 #include <rpcsvc/ypclnt.h>
64 #include "yppasswdd_extern.h"
66 #include "yppasswd_private.h"
67 #include "ypxfr_extern.h"
68 #include "yp_extern.h"
70 static struct passwd yp_password
;
73 copy_yp_pass(char *p
, int x
, int m
)
78 yp_password
.pw_fields
= 0;
80 buf
= realloc(buf
, m
+ 10);
83 /* Turn all colons into NULLs */
84 while (strchr(s
, ':')) {
85 s
= (strchr(s
, ':') + 1);
90 #define EXPAND(e) e = t; while ((*t++ = *p++));
91 EXPAND(yp_password
.pw_name
);
92 yp_password
.pw_fields
|= _PWF_NAME
;
93 EXPAND(yp_password
.pw_passwd
);
94 yp_password
.pw_fields
|= _PWF_PASSWD
;
95 yp_password
.pw_uid
= atoi(p
);
97 yp_password
.pw_fields
|= _PWF_UID
;
98 yp_password
.pw_gid
= atoi(p
);
100 yp_password
.pw_fields
|= _PWF_GID
;
102 EXPAND(yp_password
.pw_class
);
103 yp_password
.pw_fields
|= _PWF_CLASS
;
104 yp_password
.pw_change
= atol(p
);
105 p
+= (strlen(p
) + 1);
106 yp_password
.pw_fields
|= _PWF_CHANGE
;
107 yp_password
.pw_expire
= atol(p
);
108 p
+= (strlen(p
) + 1);
109 yp_password
.pw_fields
|= _PWF_EXPIRE
;
111 EXPAND(yp_password
.pw_gecos
);
112 yp_password
.pw_fields
|= _PWF_GECOS
;
113 EXPAND(yp_password
.pw_dir
);
114 yp_password
.pw_fields
|= _PWF_DIR
;
115 EXPAND(yp_password
.pw_shell
);
116 yp_password
.pw_fields
|= _PWF_SHELL
;
122 validchars(char *arg
)
126 for (i
= 0; i
< strlen(arg
); i
++) {
127 if (iscntrl(arg
[i
])) {
128 yp_error("string contains a control character");
132 yp_error("string contains a colon");
135 /* Be evil: truncate strings with \n in them silently. */
136 if (arg
[i
] == '\n') {
145 validate_master(struct passwd
*opw __unused
, struct x_master_passwd
*npw
)
148 if (npw
->pw_name
[0] == '+' || npw
->pw_name
[0] == '-') {
149 yp_error("client tried to modify an NIS entry");
153 if (validchars(npw
->pw_shell
)) {
154 yp_error("specified shell contains invalid characters");
158 if (validchars(npw
->pw_gecos
)) {
159 yp_error("specified gecos field contains invalid characters");
163 if (validchars(npw
->pw_passwd
)) {
164 yp_error("specified password contains invalid characters");
171 validate(struct passwd
*opw
, struct x_passwd
*npw
)
174 if (npw
->pw_name
[0] == '+' || npw
->pw_name
[0] == '-') {
175 yp_error("client tried to modify an NIS entry");
179 if ((uid_t
)npw
->pw_uid
!= opw
->pw_uid
) {
180 yp_error("UID mismatch: client says user %s has UID %d",
181 npw
->pw_name
, npw
->pw_uid
);
182 yp_error("database says user %s has UID %d", opw
->pw_name
,
187 if ((gid_t
)npw
->pw_gid
!= opw
->pw_gid
) {
188 yp_error("GID mismatch: client says user %s has GID %d",
189 npw
->pw_name
, npw
->pw_gid
);
190 yp_error("database says user %s has GID %d", opw
->pw_name
,
196 * Don't allow the user to shoot himself in the foot,
199 if (!ok_shell(npw
->pw_shell
)) {
200 yp_error("%s is not a valid shell", npw
->pw_shell
);
204 if (validchars(npw
->pw_shell
)) {
205 yp_error("specified shell contains invalid characters");
209 if (validchars(npw
->pw_gecos
)) {
210 yp_error("specified gecos field contains invalid characters");
214 if (validchars(npw
->pw_passwd
)) {
215 yp_error("specified password contains invalid characters");
223 * In order to have one rpc.yppasswdd support multiple domains,
224 * we have to cheat: we search each directory under /var/yp
225 * and try to match the user in each master.passwd.byname
226 * map that we find. If the user matches (username, uid and gid
227 * all agree), then we use that domain. If we match the user in
228 * more than one database, we must abort.
231 find_domain(struct x_passwd
*pw
)
236 char yp_mapdir
[MAXPATHLEN
+ 2];
237 static char domain
[YPMAXDOMAIN
];
242 yp_error("performing multidomain lookup");
244 if ((dird
= opendir(yp_dir
)) == NULL
) {
245 yp_error("opendir(%s) failed: %s", yp_dir
, strerror(errno
));
249 while ((dirp
= readdir(dird
)) != NULL
) {
250 snprintf(yp_mapdir
, sizeof yp_mapdir
, "%s/%s",
251 yp_dir
, dirp
->d_name
);
252 if (stat(yp_mapdir
, &statbuf
) < 0) {
253 yp_error("stat(%s) failed: %s", yp_mapdir
,
258 if (S_ISDIR(statbuf
.st_mode
)) {
259 tmp
= (char *)dirp
->d_name
;
260 key
.data
= pw
->pw_name
;
261 key
.size
= strlen(pw
->pw_name
);
263 if (yp_get_record(tmp
,"master.passwd.byname",
264 &key
, &data
, 0) != YP_TRUE
) {
267 *((char *)data
.data
+ data
.size
) = '\0';
268 copy_yp_pass(data
.data
, 1, data
.size
);
269 if (yp_password
.pw_uid
== (uid_t
)pw
->pw_uid
&&
270 yp_password
.pw_gid
== (gid_t
)pw
->pw_gid
) {
272 snprintf(domain
, YPMAXDOMAIN
, "%s", tmp
);
279 yp_error("found same user in two different domains");
282 return((char *)&domain
);
285 static const char *maps
[] = {
286 "master.passwd.byname",
287 "master.passwd.byuid",
292 static const char *formats
[] = {
293 "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s",
294 "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s",
295 "%s:%s:%d:%d:%s:%s:%s",
296 "%s:%s:%d:%d:%s:%s:%s"
300 update_inplace(struct passwd
*pw
, char *domain
)
303 DBT key
= { NULL
, 0 };
304 DBT data
= { NULL
, 0 };
305 char pwbuf
[YPMAXRECORD
];
309 static char yp_last
[] = "YP_LAST_MODIFIED";
310 char yplastbuf
[YPMAXRECORD
];
312 snprintf(yplastbuf
, sizeof yplastbuf
, "%llu",
313 (unsigned long long)time(NULL
));
315 for (i
= 0; i
< 4; i
++) {
318 snprintf(keybuf
, sizeof keybuf
,
319 "%llu", (unsigned long long)pw
->pw_uid
);
321 key
.size
= strlen(keybuf
);
323 key
.data
= pw
->pw_name
;
324 key
.size
= strlen(pw
->pw_name
);
328 * XXX The passwd.byname and passwd.byuid maps come in
329 * two flavors: secure and insecure. The secure version
330 * has a '*' in the password field whereas the insecure one
331 * has a real crypted password. The maps will be insecure
332 * if they were built with 'unsecure = TRUE' enabled in
333 * /var/yp/Makefile, but we'd have no way of knowing if
334 * this has been done unless we were to try parsing the
335 * Makefile, which is a disgusting thought. Instead, we
336 * read the records from the maps, skip to the first ':'
337 * in them, and then look at the character immediately
338 * following it. If it's an '*' then the map is 'secure'
339 * and we must not insert a real password into the pw_passwd
340 * field. If it's not an '*', then we put the real crypted
343 if (yp_get_record(domain
,maps
[i
],&key
,&data
,1) != YP_TRUE
) {
344 yp_error("couldn't read %s/%s: %s", domain
,
345 maps
[i
], strerror(errno
));
349 if ((ptr
= strchr(data
.data
, ':')) == NULL
) {
350 yp_error("no colon in passwd record?!");
355 * XXX Supposing we have more than one user with the same
356 * UID? (Or more than one user with the same name?) We could
357 * end up modifying the wrong record if were not careful.
360 if (strncmp(data
.data
, pw
->pw_name
,
361 strlen(pw
->pw_name
))) {
362 yp_error("warning: found entry for UID %d "
363 "in map %s@%s with wrong name (%.*s)",
364 pw
->pw_uid
, maps
[i
], domain
,
365 (int)(ptr
- (char *)data
.data
),
367 yp_error("there may be more than one user "
368 "with the same UID - continuing");
373 * We're really being ultra-paranoid here.
374 * This is generally a 'can't happen' condition.
376 snprintf(pwbuf
, sizeof pwbuf
, ":%d:%d:", pw
->pw_uid
,
378 if (!strstr(data
.data
, pwbuf
)) {
379 yp_error("warning: found entry for user %s \
380 in map %s@%s with wrong UID", pw
->pw_name
, maps
[i
], domain
);
381 yp_error("there may be more than one user \
382 with the same name - continuing");
388 snprintf(pwbuf
, sizeof pwbuf
, formats
[i
],
389 pw
->pw_name
, pw
->pw_passwd
, pw
->pw_uid
,
390 pw
->pw_gid
, pw
->pw_class
, pw
->pw_change
,
391 pw
->pw_expire
, pw
->pw_gecos
, pw
->pw_dir
,
394 snprintf(pwbuf
, sizeof pwbuf
, formats
[i
],
395 pw
->pw_name
, *(ptr
+1) == '*' ? "*" : pw
->pw_passwd
,
396 pw
->pw_uid
, pw
->pw_gid
, pw
->pw_gecos
, pw
->pw_dir
,
400 #define FLAGS O_RDWR|O_CREAT
402 if ((dbp
= yp_open_db_rw(domain
, maps
[i
], FLAGS
)) == NULL
) {
403 yp_error("couldn't open %s/%s r/w: %s",domain
,
404 maps
[i
],strerror(errno
));
409 data
.size
= strlen(pwbuf
);
411 if (yp_put_record(dbp
, &key
, &data
, 1) != YP_TRUE
) {
412 yp_error("failed to update record in %s/%s", domain
,
419 key
.size
= strlen(yp_last
);
420 data
.data
= (char *)&yplastbuf
;
421 data
.size
= strlen(yplastbuf
);
423 if (yp_put_record(dbp
, &key
, &data
, 1) != YP_TRUE
) {
424 yp_error("failed to update timestamp in %s/%s", domain
,
437 yppasswdproc_update_1_svc(yppasswd
*argp
, struct svc_req
*rqstp
)
440 struct sockaddr_in
*rqhost
;
445 int passwd_changed
= 0;
446 int shell_changed
= 0;
447 int gecos_changed
= 0;
448 char *oldshell
= NULL
;
449 char *oldgecos
= NULL
;
451 char passfile_buf
[MAXPATHLEN
+ 2];
452 char passfile_hold_buf
[MAXPATHLEN
+ 2];
453 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 if (strcmp(crypt(argp
->oldpass
, yp_password
.pw_passwd
),
526 yp_password
.pw_passwd
)) {
527 yp_error("rejected change attempt -- bad password");
528 yp_error("client address: %s username: %s",
529 inet_ntoa(rqhost
->sin_addr
),
530 argp
->newpw
.pw_name
);
534 /* Step 3: validate the arguments passed to us by the client. */
536 if (validate(&yp_password
, &argp
->newpw
)) {
537 yp_error("rejecting change attempt: bad arguments");
538 yp_error("client address: %s username: %s",
539 inet_ntoa(rqhost
->sin_addr
),
540 argp
->newpw
.pw_name
);
541 svcerr_decode(rqstp
->rq_xprt
);
545 /* Step 4: update the user's passwd structure. */
547 if (!no_chsh
&& strcmp(argp
->newpw
.pw_shell
, yp_password
.pw_shell
)) {
548 oldshell
= yp_password
.pw_shell
;
549 yp_password
.pw_shell
= argp
->newpw
.pw_shell
;
554 if (!no_chfn
&& strcmp(argp
->newpw
.pw_gecos
, yp_password
.pw_gecos
)) {
555 oldgecos
= yp_password
.pw_gecos
;
556 yp_password
.pw_gecos
= argp
->newpw
.pw_gecos
;
560 if (strcmp(argp
->newpw
.pw_passwd
, yp_password
.pw_passwd
)) {
561 yp_password
.pw_passwd
= argp
->newpw
.pw_passwd
;
562 yp_password
.pw_change
= 0;
567 * If the caller specified a domain other than our 'default'
568 * domain, change the path to master.passwd accordingly.
571 if (strcmp(domain
, yppasswd_domain
)) {
572 snprintf(passfile_buf
, sizeof(passfile_buf
),
573 "%s/%s/master.passwd", yp_dir
, domain
);
574 passfile
= (char *)&passfile_buf
;
578 * Create a filename to hold the original master.passwd
579 * so if our call to yppwupdate fails we can roll back
581 snprintf(passfile_hold_buf
, sizeof(passfile_hold_buf
),
582 "%s.hold", passfile
);
583 passfile_hold
= (char *)&passfile_hold_buf
;
586 /* Step 5: make a new password file with the updated info. */
588 if (pw_init(dirname(passfile
), passfile
)) {
589 yp_error("pw_init() failed");
592 if ((pfd
= pw_lock()) == -1) {
594 yp_error("pw_lock() failed");
597 if ((tfd
= pw_tmp(-1)) == -1) {
599 yp_error("pw_tmp() failed");
602 if (pw_copy(pfd
, tfd
, &yp_password
, NULL
) == -1) {
604 yp_error("pw_copy() failed");
607 if (rename(passfile
, passfile_hold
) == -1) {
609 yp_error("rename of %s to %s failed", passfile
,
614 if (strcmp(passfile
, _PATH_MASTERPASSWD
) == 0) {
616 * NIS server is exporting the system's master.passwd.
617 * Call pw_mkdb to rebuild passwd and the .db files
619 if (pw_mkdb(yp_password
.pw_name
) == -1) {
621 yp_error("pw_mkdb() failed");
622 rename(passfile_hold
, passfile
);
627 * NIS server is exporting a private master.passwd.
628 * Rename tempfile into final location
630 if (rename(pw_tempname(), passfile
) == -1) {
632 yp_error("rename of %s to %s failed",
633 pw_tempname(), passfile
);
634 rename(passfile_hold
, passfile
);
642 if ((rval
= update_inplace(&yp_password
, domain
))) {
643 yp_error("inplace update failed -- rebuilding maps");
647 switch ((pid
= fork())) {
649 if (inplace
&& !rval
) {
650 execlp(MAP_UPDATE_PATH
, MAP_UPDATE
, passfile
,
651 yppasswd_domain
, "pushpw", NULL
);
653 execlp(MAP_UPDATE_PATH
, MAP_UPDATE
, passfile
,
654 yppasswd_domain
, NULL
);
656 yp_error("couldn't exec map update process: %s",
659 rename(passfile_hold
, passfile
);
663 yp_error("fork() failed: %s", strerror(errno
));
665 rename(passfile_hold
, passfile
);
669 unlink(passfile_hold
);
674 yp_error("update completed for user %s (uid %d) in %s:",
675 argp
->newpw
.pw_name
, argp
->newpw
.pw_uid
, passfile
);
678 yp_error("password changed");
681 yp_error("gecos changed ('%s' -> '%s')",
682 oldgecos
, argp
->newpw
.pw_gecos
);
685 yp_error("shell changed ('%s' -> '%s')",
686 oldshell
, argp
->newpw
.pw_shell
);
694 * Note that this function performs a little less sanity checking
695 * than the last one. Since only the superuser is allowed to use it,
696 * it is assumed that the caller knows what he's doing.
699 yppasswdproc_update_master_1_svc(master_yppasswd
*argp
, struct svc_req
*rqstp
)
708 char passfile_buf
[MAXPATHLEN
+ 2];
709 char passfile_hold_buf
[MAXPATHLEN
+ 2];
710 struct sockaddr_in
*rqhost
;
714 transp
= rqstp
->rq_xprt
;
717 * NO AF_INET CONNETCIONS ALLOWED!
719 rqhost
= svc_getcaller(transp
);
720 if (rqhost
->sin_family
!= AF_UNIX
) {
721 yp_error("Alert! %s/%d attempted to use superuser-only \
722 procedure!\n", inet_ntoa(rqhost
->sin_addr
), rqhost
->sin_port
);
723 svcerr_auth(transp
, AUTH_BADCRED
);
727 if (rqstp
->rq_cred
.oa_flavor
!= AUTH_SYS
) {
728 yp_error("caller didn't send proper credentials");
729 svcerr_auth(transp
, AUTH_BADCRED
);
733 if (__rpc_get_local_uid(transp
, &uid
) < 0) {
734 yp_error("caller didn't send proper credentials");
735 svcerr_auth(transp
, AUTH_BADCRED
);
740 yp_error("caller euid is %d, expecting 0 -- rejecting request",
742 svcerr_auth(rqstp
->rq_xprt
, AUTH_BADCRED
);
746 passfile
= passfile_default
;
748 key
.data
= argp
->newpw
.pw_name
;
749 key
.size
= strlen(argp
->newpw
.pw_name
);
752 * The superuser may add entries to the passwd maps if
753 * rpc.yppasswdd is started with the -a flag. Paranoia
754 * prevents me from allowing additions by default.
756 if ((rval
= yp_get_record(argp
->domain
, "master.passwd.byname",
757 &key
, &data
, 0)) != YP_TRUE
) {
758 if (rval
== YP_NOKEY
) {
759 yp_error("user %s not found in passwd database",
760 argp
->newpw
.pw_name
);
762 yp_error("notice: adding user %s to \
763 master.passwd database for domain %s", argp
->newpw
.pw_name
, argp
->domain
);
765 yp_error("restart rpc.yppasswdd with the -a flag to \
766 allow additions to be made to the password database");
768 yp_error("database access error: %s",
771 if (!allow_additions
)
775 /* Nul terminate, please. */
776 *((char *)data
.data
+ data
.size
) = '\0';
778 copy_yp_pass(data
.data
, 1, data
.size
);
782 * Perform a small bit of sanity checking.
784 if (validate_master(rval
== YP_TRUE
? &yp_password
:NULL
,&argp
->newpw
)){
785 yp_error("rejecting update attempt for %s: bad arguments",
786 argp
->newpw
.pw_name
);
791 * If the caller specified a domain other than our 'default'
792 * domain, change the path to master.passwd accordingly.
795 if (strcmp(argp
->domain
, yppasswd_domain
)) {
796 snprintf(passfile_buf
, sizeof(passfile_buf
),
797 "%s/%s/master.passwd", yp_dir
, argp
->domain
);
798 passfile
= (char *)&passfile_buf
;
802 * Create a filename to hold the original master.passwd
803 * so if our call to yppwupdate fails we can roll back
805 snprintf(passfile_hold_buf
, sizeof(passfile_hold_buf
),
806 "%s.hold", passfile
);
807 passfile_hold
= (char *)&passfile_hold_buf
;
809 if (pw_init(dirname(passfile
), passfile
)) {
810 yp_error("pw_init() failed");
813 if ((pfd
= pw_lock()) == -1) {
815 yp_error("pw_lock() failed");
818 if ((tfd
= pw_tmp(-1)) == -1) {
820 yp_error("pw_tmp() failed");
823 if (pw_copy(pfd
, tfd
, (struct passwd
*)&argp
->newpw
, NULL
) == -1) {
825 yp_error("pw_copy() failed");
828 if (rename(passfile
, passfile_hold
) == -1) {
830 yp_error("rename of %s to %s failed", passfile
,
834 if (strcmp(passfile
, _PATH_MASTERPASSWD
) == 0) {
836 * NIS server is exporting the system's master.passwd.
837 * Call pw_mkdb to rebuild passwd and the .db files
839 if (pw_mkdb(argp
->newpw
.pw_name
) == -1) {
841 yp_error("pw_mkdb() failed");
842 rename(passfile_hold
, passfile
);
847 * NIS server is exporting a private master.passwd.
848 * Rename tempfile into final location
850 if (rename(pw_tempname(), passfile
) == -1) {
852 yp_error("rename of %s to %s failed",
853 pw_tempname(), passfile
);
854 rename(passfile_hold
, passfile
);
861 if ((rval
= update_inplace((struct passwd
*)&argp
->newpw
,
863 yp_error("inplace update failed -- rebuilding maps");
867 switch ((pid
= fork())) {
869 if (inplace
&& !rval
) {
870 execlp(MAP_UPDATE_PATH
, MAP_UPDATE
, passfile
,
871 argp
->domain
, "pushpw", NULL
);
873 execlp(MAP_UPDATE_PATH
, MAP_UPDATE
, passfile
,
876 yp_error("couldn't exec map update process: %s",
879 rename(passfile_hold
, passfile
);
883 yp_error("fork() failed: %s", strerror(errno
));
885 rename(passfile_hold
, passfile
);
889 unlink(passfile_hold
);
893 yp_error("performed update of user %s (uid %d) domain %s",