diff options
Diffstat (limited to 'login-utils/vipw.c')
-rw-r--r-- | login-utils/vipw.c | 100 |
1 files changed, 38 insertions, 62 deletions
diff --git a/login-utils/vipw.c b/login-utils/vipw.c index 992a3a306..765d11120 100644 --- a/login-utils/vipw.c +++ b/login-utils/vipw.c @@ -57,6 +57,7 @@ #include <fcntl.h> #include <paths.h> #include <pwd.h> +#include <shadow.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> @@ -71,6 +72,7 @@ #include <unistd.h> #include "c.h" +#include "fileutils.h" #include "nls.h" #include "setpwnam.h" #include "strutils.h" @@ -88,8 +90,7 @@ enum { }; int program; char orig_file[FILENAMELEN]; /* original file /etc/passwd or /etc/group */ -char tmp_file[FILENAMELEN]; /* tmp file */ -char tmptmp_file[FILENAMELEN]; /* very tmp file */ +char *tmp_file; /* tmp file */ void pw_error __P((char *, int, int)); @@ -137,55 +138,22 @@ static void pw_init(void) (void)umask(0); } -static int pw_lock(void) +static FILE * pw_tmpfile(int lockfd) { - int lockfd, fd, ret; - - /* - * If the password file doesn't exist, the system is hosed. Might as - * well try to build one. Set the close-on-exec bit so that users - * can't get at the encrypted passwords while editing. Open should - * allow flock'ing the file; see 4.4BSD. XXX - */ -#if 0 - /* flock()ing is superfluous here, with the ptmp/ptmptmp system. */ - if (flock(lockfd, LOCK_EX | LOCK_NB)) { - if (program == VIPW) - err(EXIT_FAILURE, _("cannot lock password file")); - else - err(EXIT_FAILURE, _("cannot lock group file")); - } -#endif - - if ((fd = open(tmptmp_file, O_WRONLY | O_CREAT, 0600)) == -1) - err(EXIT_FAILURE, _("%s: open failed"), tmptmp_file); - - ret = link(tmptmp_file, tmp_file); - (void)unlink(tmptmp_file); - if (ret == -1) { - if (errno == EEXIST) - errx(EXIT_FAILURE, - _("the %s file is busy (%s present)"), - program == VIPW ? "password" : "group", tmp_file); - else - err(EXIT_FAILURE, _("can't link %s"), tmp_file); - } - - lockfd = open(orig_file, O_RDONLY, 0); + FILE *fd; + char *tmpname = NULL; - if (lockfd < 0) { - warn("%s", orig_file); - unlink(tmp_file); - exit(EXIT_FAILURE); + if ((fd = xmkstemp(&tmpname)) == NULL) { + ulckpwdf(); + err(EXIT_FAILURE, _("can't open temporary file")); } - copyfile(lockfd, fd); - (void)close(lockfd); - (void)close(fd); - return 1; + copyfile(lockfd, fileno(fd)); + tmp_file = tmpname; + return fd; } -static void pw_unlock(void) +static void pw_write(void) { char tmp[FILENAMELEN + 4]; @@ -215,10 +183,11 @@ static void pw_unlock(void) if (rename(tmp_file, orig_file) == -1) { int errsv = errno; errx(EXIT_FAILURE, - ("can't unlock %s: %s (your changes are still in %s)"), + ("cannot write %s: %s (your changes are still in %s)"), orig_file, strerror(errsv), tmp_file); } unlink(tmp_file); + free(tmp_file); } static void pw_edit(int notsetuid) @@ -275,33 +244,49 @@ void pw_error(char *name, int err, int eval) } warnx(_("%s unchanged"), orig_file); unlink(tmp_file); + ulckpwdf(); exit(eval); } static void edit_file(int is_shadow) { struct stat begin, end; + int passwd_file, ch_ret; + FILE *tmp_fd; pw_init(); - pw_lock(); - if (stat(tmp_file, &begin)) + /* acquire exclusive lock */ + if (lckpwdf() < 0) + err(EXIT_FAILURE, _("cannot get lock")); + + passwd_file = open(orig_file, O_RDONLY, 0); + if (passwd_file < 0) + err(EXIT_FAILURE, "%s: %s", _("cannot open file"), orig_file); + tmp_fd = pw_tmpfile(passwd_file); + + if (fstat(fileno(tmp_fd), &begin)) pw_error(tmp_file, 1, 1); pw_edit(0); - if (stat(tmp_file, &end)) + if (fstat(fileno(tmp_fd), &end)) pw_error(tmp_file, 1, 1); if (begin.st_mtime == end.st_mtime) { warnx(_("no changes made")); pw_error((char *)NULL, 0, 0); } - /* see pw_lock() where we create the file with mode 600 */ + /* pw_tmpfile() will create the file with mode 600 */ if (!is_shadow) - chmod(tmp_file, 0644); + ch_ret = fchmod(fileno(tmp_fd), 0644); else - chmod(tmp_file, 0400); - pw_unlock(); + ch_ret = fchmod(fileno(tmp_fd), 0400); + if (ch_ret < 0) + err(EXIT_FAILURE, "%s: %s", _("cannot chmod file"), orig_file); + fclose(tmp_fd); + pw_write(); + close(passwd_file); + ulckpwdf(); } int main(int argc, char *argv[]) @@ -310,17 +295,12 @@ int main(int argc, char *argv[]) bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); - memset(tmp_file, '\0', FILENAMELEN); if (!strcmp(program_invocation_short_name, "vigr")) { program = VIGR; xstrncpy(orig_file, GROUP_FILE, sizeof(orig_file)); - xstrncpy(tmp_file, GTMP_FILE, sizeof(tmp_file)); - xstrncpy(tmptmp_file, GTMPTMP_FILE, sizeof(tmptmp_file)); } else { program = VIPW; xstrncpy(orig_file, PASSWD_FILE, sizeof(orig_file)); - xstrncpy(tmp_file, PTMP_FILE, sizeof(tmp_file)); - xstrncpy(tmptmp_file, PTMPTMP_FILE, sizeof(tmptmp_file)); } if ((argc > 1) && @@ -333,12 +313,8 @@ int main(int argc, char *argv[]) if (program == VIGR) { strncpy(orig_file, SGROUP_FILE, FILENAMELEN - 1); - strncpy(tmp_file, SGTMP_FILE, FILENAMELEN - 1); - strncpy(tmptmp_file, SGTMPTMP_FILE, FILENAMELEN - 1); } else { strncpy(orig_file, SHADOW_FILE, FILENAMELEN - 1); - strncpy(tmp_file, SPTMP_FILE, FILENAMELEN - 1); - strncpy(tmptmp_file, SPTMPTMP_FILE, FILENAMELEN - 1); } if (access(orig_file, F_OK) == 0) { |