From: Christian Göttsche Date: Tue, 28 Feb 2023 15:35:05 +0000 (+0100) Subject: Add wrapper for write(2) X-Git-Tag: 4.14.0-rc3~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=969549fdf0cd43b46c778a7854c053af19248711;p=thirdparty%2Fshadow.git Add wrapper for write(2) write(2) may not write the complete given buffer. Add a wrapper to avoid short writes. --- diff --git a/lib/Makefile.am b/lib/Makefile.am index 5d76205cf..c8d6dd5fb 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -66,7 +66,8 @@ libshadow_la_SOURCES = \ shadowio.c \ shadowio.h \ shadowmem.c \ - spawn.c + spawn.c \ + write_full.c if WITH_TCB libshadow_la_SOURCES += tcbfuncs.c tcbfuncs.h diff --git a/lib/commonio.c b/lib/commonio.c index 0e66c8dda..73fdb3a16 100644 --- a/lib/commonio.c +++ b/lib/commonio.c @@ -140,7 +140,7 @@ static int do_lock_file (const char *file, const char *lock, bool log) pid = getpid (); snprintf (buf, sizeof buf, "%lu", (unsigned long) pid); len = (ssize_t) strlen (buf) + 1; - if (write (fd, buf, (size_t) len) != len) { + if (write_full (fd, buf, (size_t) len) != len) { if (log) { (void) fprintf (shadow_logfd, "%s: %s file write error: %s\n", diff --git a/lib/prototypes.h b/lib/prototypes.h index a13383410..d20abf3e3 100644 --- a/lib/prototypes.h +++ b/lib/prototypes.h @@ -526,6 +526,9 @@ extern unsigned long active_sessions_count(const char *name, /* valid.c */ extern bool valid (const char *, const struct passwd *); +/* write_full.c */ +extern ssize_t write_full(int fd, const void *buf, size_t count); + /* xgetpwnam.c */ extern /*@null@*/ /*@only@*/struct passwd *xgetpwnam (const char *); /* xprefix_getpwnam.c */ diff --git a/lib/write_full.c b/lib/write_full.c new file mode 100644 index 000000000..cde52fbfd --- /dev/null +++ b/lib/write_full.c @@ -0,0 +1,52 @@ +/* + * SPDX-FileCopyrightText: 2023, Christian Göttsche + * + * SPDX-License-Identifier: BSD-3-Clause + */ + + +#include + +#ident "$Id$" + +#include "prototypes.h" + +#include +#include + + +/* + * write_full - write entire buffer + * + * Write up to count bytes from the buffer starting at buf to the + * file referred to by the file descriptor fd. + * Retry in case of a short write. + * + * Returns the number of bytes written on success, -1 on error. + */ +ssize_t write_full(int fd, const void *buf, size_t count) { + ssize_t written = 0; + + while (count > 0) { + ssize_t res; + + res = write(fd, buf, count); + if (res < 0) { + if (errno == EINTR) { + continue; + } + + return res; + } + + if (res == 0) { + break; + } + + written += res; + buf = (const unsigned char*)buf + res; + count -= res; + } + + return written; +} diff --git a/libmisc/copydir.c b/libmisc/copydir.c index d04ddc599..cc1a30d29 100644 --- a/libmisc/copydir.c +++ b/libmisc/copydir.c @@ -740,42 +740,6 @@ static int copy_special (const struct path_info *src, const struct path_info *ds return err; } -/* - * full_write - write entire buffer - * - * Write up to count bytes from the buffer starting at buf to the - * file referred to by the file descriptor fd. - * Retry in case of a short write. - * - * Returns the number of bytes written on success, -1 on error. - */ -static ssize_t full_write(int fd, const void *buf, size_t count) { - ssize_t written = 0; - - while (count > 0) { - ssize_t res; - - res = write(fd, buf, count); - if (res < 0) { - if (errno == EINTR) { - continue; - } - - return res; - } - - if (res == 0) { - break; - } - - written += res; - buf = (const unsigned char*)buf + res; - count -= res; - } - - return written; -} - /* * copy_file - copy a file * @@ -852,7 +816,7 @@ static int copy_file (const struct path_info *src, const struct path_info *dst, break; } - if (full_write (ofd, buf, cnt) < 0) { + if (write_full (ofd, buf, cnt) < 0) { (void) close (ofd); (void) close (ifd); return -1; diff --git a/libmisc/failure.c b/libmisc/failure.c index df8614a24..6fc575c12 100644 --- a/libmisc/failure.c +++ b/libmisc/failure.c @@ -17,6 +17,7 @@ #include "defines.h" #include "faillog.h" #include "failure.h" +#include "prototypes.h" #define YEAR (365L*DAY) /* * failure - make failure entry @@ -85,7 +86,7 @@ void failure (uid_t uid, const char *tty, struct faillog *fl) */ if ( (lseek (fd, offset_uid, SEEK_SET) != offset_uid) - || (write (fd, fl, sizeof *fl) != (ssize_t) sizeof *fl) + || (write_full (fd, fl, sizeof *fl) != (ssize_t) sizeof *fl) || (close (fd) != 0)) { SYSLOG ((LOG_WARN, "Can't write faillog entry for UID %lu in %s.", @@ -184,7 +185,7 @@ int failcheck (uid_t uid, struct faillog *fl, bool failed) fail.fail_cnt = 0; if ( (lseek (fd, offset_uid, SEEK_SET) != offset_uid) - || (write (fd, &fail, sizeof fail) != (ssize_t) sizeof fail) + || (write_full (fd, &fail, sizeof fail) != (ssize_t) sizeof fail) || (close (fd) != 0)) { SYSLOG ((LOG_WARN, "Can't reset faillog entry for UID %lu in %s.", diff --git a/libmisc/idmapping.c b/libmisc/idmapping.c index 46bb814d5..ae8c4b93a 100644 --- a/libmisc/idmapping.c +++ b/libmisc/idmapping.c @@ -215,7 +215,7 @@ void write_mapping(int proc_dir_fd, int ranges, const struct map_range *mappings log_get_progname(), map_file, strerror(errno)); exit(EXIT_FAILURE); } - if (write(fd, buf, pos - buf) != (pos - buf)) { + if (write_full(fd, buf, pos - buf) != (pos - buf)) { fprintf(log_get_logfd(), _("%s: write to %s failed: %s\n"), log_get_progname(), map_file, strerror(errno)); exit(EXIT_FAILURE); diff --git a/libmisc/log.c b/libmisc/log.c index ab94f330c..cc38d6dc5 100644 --- a/libmisc/log.c +++ b/libmisc/log.c @@ -82,7 +82,7 @@ void dolastlog ( strncpy (newlog.ll_host, host, sizeof (newlog.ll_host) - 1); #endif if ( (lseek (fd, offset, SEEK_SET) != offset) - || (write (fd, &newlog, sizeof newlog) != (ssize_t) sizeof newlog) + || (write_full (fd, &newlog, sizeof newlog) != (ssize_t) sizeof newlog) || (close (fd) != 0)) { SYSLOG ((LOG_WARN, "Can't write lastlog entry for UID %lu in %s.", diff --git a/libmisc/utmp.c b/libmisc/utmp.c index e5e79cffc..7c7da6971 100644 --- a/libmisc/utmp.c +++ b/libmisc/utmp.c @@ -97,7 +97,7 @@ static void failtmp (const char *username, const struct utmp *failent) * Append the new failure record and close the log file. */ - if ( (write (fd, failent, sizeof *failent) != (ssize_t) sizeof *failent) + if ( (write_full (fd, failent, sizeof *failent) != (ssize_t) sizeof *failent) || (close (fd) != 0)) { SYSLOG ((LOG_WARN, "Can't append failure of user %s to %s.", @@ -194,7 +194,7 @@ static void updwtmp (const char *filename, const struct utmp *ut) fd = open (filename, O_APPEND | O_WRONLY, 0); if (fd >= 0) { - write (fd, ut, sizeof (*ut)); + write_full (fd, ut, sizeof (*ut)); close (fd); } } diff --git a/src/login.c b/src/login.c index b712cf445..b5562923a 100644 --- a/src/login.c +++ b/src/login.c @@ -400,7 +400,7 @@ static void exit_handler (unused int sig) static void alarm_handler (unused int sig) { - write (STDERR_FILENO, tmsg, strlen (tmsg)); + write_full (STDERR_FILENO, tmsg, strlen (tmsg)); signal(SIGALRM, exit_handler); alarm(2); } diff --git a/src/su.c b/src/su.c index 628ef4e4c..84b924689 100644 --- a/src/su.c +++ b/src/su.c @@ -164,9 +164,9 @@ static void kill_child (int unused(s)) { if (0 != pid_child) { (void) kill (-pid_child, SIGKILL); - (void) write (STDERR_FILENO, kill_msg, strlen (kill_msg)); + (void) write_full (STDERR_FILENO, kill_msg, strlen (kill_msg)); } else { - (void) write (STDERR_FILENO, wait_msg, strlen (wait_msg)); + (void) write_full (STDERR_FILENO, wait_msg, strlen (wait_msg)); } _exit (255); } diff --git a/src/useradd.c b/src/useradd.c index d6766426b..5b601e018 100644 --- a/src/useradd.c +++ b/src/useradd.c @@ -2067,7 +2067,7 @@ static void faillog_reset (uid_t uid) return; } if ( (lseek (fd, offset_uid, SEEK_SET) != offset_uid) - || (write (fd, &fl, sizeof (fl)) != (ssize_t) sizeof (fl)) + || (write_full (fd, &fl, sizeof (fl)) != (ssize_t) sizeof (fl)) || (fsync (fd) != 0)) { fprintf (stderr, _("%s: failed to reset the faillog entry of UID %lu: %s\n"), @@ -2112,7 +2112,7 @@ static void lastlog_reset (uid_t uid) return; } if ( (lseek (fd, offset_uid, SEEK_SET) != offset_uid) - || (write (fd, &ll, sizeof (ll)) != (ssize_t) sizeof (ll)) + || (write_full (fd, &ll, sizeof (ll)) != (ssize_t) sizeof (ll)) || (fsync (fd) != 0)) { fprintf (stderr, _("%s: failed to reset the lastlog entry of UID %lu: %s\n"), diff --git a/src/usermod.c b/src/usermod.c index bf01881ac..9e8968025 100644 --- a/src/usermod.c +++ b/src/usermod.c @@ -1941,7 +1941,7 @@ static void update_lastlog (void) && (read (fd, &ll, sizeof ll) == (ssize_t) sizeof ll)) { /* Copy the old entry to its new location */ if ( (lseek (fd, off_newuid, SEEK_SET) != off_newuid) - || (write (fd, &ll, sizeof ll) != (ssize_t) sizeof ll) + || (write_full (fd, &ll, sizeof ll) != (ssize_t) sizeof ll) || (fsync (fd) != 0)) { fprintf (stderr, _("%s: failed to copy the lastlog entry of user %lu to user %lu: %s\n"), @@ -1957,7 +1957,7 @@ static void update_lastlog (void) /* Reset the new uid's lastlog entry */ memzero (&ll, sizeof (ll)); if ( (lseek (fd, off_newuid, SEEK_SET) != off_newuid) - || (write (fd, &ll, sizeof ll) != (ssize_t) sizeof ll) + || (write_full (fd, &ll, sizeof ll) != (ssize_t) sizeof ll) || (fsync (fd) != 0)) { fprintf (stderr, _("%s: failed to copy the lastlog entry of user %lu to user %lu: %s\n"), @@ -2001,7 +2001,7 @@ static void update_faillog (void) && (read (fd, &fl, sizeof fl) == (ssize_t) sizeof fl)) { /* Copy the old entry to its new location */ if ( (lseek (fd, off_newuid, SEEK_SET) != off_newuid) - || (write (fd, &fl, sizeof fl) != (ssize_t) sizeof fl) + || (write_full (fd, &fl, sizeof fl) != (ssize_t) sizeof fl) || (fsync (fd) != 0)) { fprintf (stderr, _("%s: failed to copy the faillog entry of user %lu to user %lu: %s\n"), @@ -2017,7 +2017,7 @@ static void update_faillog (void) /* Reset the new uid's faillog entry */ memzero (&fl, sizeof (fl)); if ( (lseek (fd, off_newuid, SEEK_SET) != off_newuid) - || (write (fd, &fl, sizeof fl) != (ssize_t) sizeof fl)) { + || (write_full (fd, &fl, sizeof fl) != (ssize_t) sizeof fl)) { fprintf (stderr, _("%s: failed to copy the faillog entry of user %lu to user %lu: %s\n"), Prog, (unsigned long) user_id, (unsigned long) user_newid, strerror (errno));