summaryrefslogtreecommitdiffstats
path: root/login-utils/vipw.c
diff options
context:
space:
mode:
authorSami Kerola2012-02-29 14:09:56 +0100
committerSami Kerola2012-03-18 14:28:04 +0100
commit46b6bcca5f0c3fbc232da753f970e74c2b55012e (patch)
treedf2bafc887108ea67977bf6f3339a68fa633c9b7 /login-utils/vipw.c
parentsetpwnam: use xmkstemp() and lckpwdf() (diff)
downloadkernel-qcow2-util-linux-46b6bcca5f0c3fbc232da753f970e74c2b55012e.tar.gz
kernel-qcow2-util-linux-46b6bcca5f0c3fbc232da753f970e74c2b55012e.tar.xz
kernel-qcow2-util-linux-46b6bcca5f0c3fbc232da753f970e74c2b55012e.zip
vipw: use xmkstemp() and lckpwdf()
Get rid private locking schema and use libc instead. Signed-off-by: Sami Kerola <kerolasa@iki.fi>
Diffstat (limited to 'login-utils/vipw.c')
-rw-r--r--login-utils/vipw.c100
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) {