diff --git a/include/fileutils.h b/include/fileutils.h index 479ad15cf..2766b0d43 100644 --- a/include/fileutils.h +++ b/include/fileutils.h @@ -74,4 +74,6 @@ static inline struct dirent *xreaddir(DIR *dp) extern void close_all_fds(const int exclude[], size_t exsz); +int ul_copy_file(int from, int to); + #endif /* UTIL_LINUX_FILEUTILS */ diff --git a/lib/fileutils.c b/lib/fileutils.c index 003f890f9..9e0823d30 100644 --- a/lib/fileutils.c +++ b/lib/fileutils.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "c.h" #include "fileutils.h" @@ -246,3 +247,21 @@ char *stripoff_last_component(char *path) *p = '\0'; return p + 1; } + +/* Copies the contents of a file. Returns -1 on read error, -2 on write error. */ +int ul_copy_file(int from, int to) +{ + ssize_t nr, nw, off; + char buf[8 * 1024]; + + while ((nr = read(from, buf, sizeof(buf))) > 0) + for (off = 0; nr > 0; nr -= nw, off += nw) + if ((nw = write(to, buf + off, nr)) < 0) + return -2; + if (nr < 0) + return -1; +#ifdef HAVE_EXPLICIT_BZERO + explicit_bzero(buf, sizeof(buf)); +#endif + return 0; +} diff --git a/login-utils/vipw.c b/login-utils/vipw.c index 38953b7f5..a107259ae 100644 --- a/login-utils/vipw.c +++ b/login-utils/vipw.c @@ -88,23 +88,6 @@ static char *tmp_file; /* tmp file */ void pw_error (char *, int, int); -static void copyfile(int from, int to) -{ - int nr, nw, off; - char buf[8 * 1024]; - - while ((nr = read(from, buf, sizeof(buf))) > 0) - for (off = 0; nr > 0; nr -= nw, off += nw) - if ((nw = write(to, buf + off, nr)) < 0) - pw_error(tmp_file, 1, 1); - - if (nr < 0) - pw_error(orig_file, 1, 1); -#ifdef HAVE_EXPLICIT_BZERO - explicit_bzero(buf, sizeof(buf)); -#endif -} - static void pw_init(void) { struct rlimit rlim; @@ -139,14 +122,19 @@ static FILE * pw_tmpfile(int lockfd) { FILE *fd; char *tmpname = NULL; + int res; if ((fd = xfmkstemp(&tmpname, "/etc", ".vipw")) == NULL) { ulckpwdf(); err(EXIT_FAILURE, _("can't open temporary file")); } - copyfile(lockfd, fileno(fd)); tmp_file = tmpname; + res = ul_copy_file(lockfd, fileno(fd)); + if (res == -1) + pw_error(orig_file, 1, 1); + else if (res == -2) + pw_error(tmp_file, 1, 1); return fd; }