From: Todd C. Miller Date: Mon, 2 Mar 2015 20:58:50 +0000 (-0700) Subject: Use futimens() and utimensat() instead of futimes() and utimes(). X-Git-Tag: SUDO_1_8_13^2~20 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ee72cba9372930d44e5163dd2f450d70edf734e2;p=sudo Use futimens() and utimensat() instead of futimes() and utimes(). --- diff --git a/MANIFEST b/MANIFEST index aeee9d1b2..69063841e 100644 --- a/MANIFEST +++ b/MANIFEST @@ -93,6 +93,7 @@ lib/util/getgrouplist.c lib/util/gethostname.c lib/util/getline.c lib/util/getopt_long.c +lib/util/gettime.c lib/util/gidlist.c lib/util/glob.c lib/util/inet_ntop.c @@ -170,7 +171,7 @@ lib/util/sudo_dso.c lib/util/term.c lib/util/ttysize.c lib/util/util.exp.in -lib/util/utimes.c +lib/util/utimens.c lib/zlib/Makefile.in lib/zlib/adler32.c lib/zlib/compress.c @@ -257,7 +258,6 @@ plugins/sudoers/find_path.c plugins/sudoers/getdate.c plugins/sudoers/getdate.y plugins/sudoers/getspwuid.c -plugins/sudoers/gettime.c plugins/sudoers/goodpath.c plugins/sudoers/gram.c plugins/sudoers/gram.h diff --git a/config.h.in b/config.h.in index ef1282c04..f7dcb7844 100644 --- a/config.h.in +++ b/config.h.in @@ -244,6 +244,9 @@ /* Define to 1 if you have the `futime' function. */ #undef HAVE_FUTIME +/* Define to 1 if you have the `futimens' function. */ +#undef HAVE_FUTIMENS + /* Define to 1 if you have the `futimes' function. */ #undef HAVE_FUTIMES @@ -826,6 +829,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_UTIL_H +/* Define to 1 if you have the `utimensat' function. */ +#undef HAVE_UTIMENSAT + /* Define to 1 if you have the `utimes' function. */ #undef HAVE_UTIMES diff --git a/configure b/configure index 6687cefe9..f00428d97 100755 --- a/configure +++ b/configure @@ -18939,54 +18939,74 @@ done fi done -for ac_func in utimes +for ac_func in utimensat do : - ac_fn_c_check_func "$LINENO" "utimes" "ac_cv_func_utimes" -if test "x$ac_cv_func_utimes" = xyes; then : + ac_fn_c_check_func "$LINENO" "utimensat" "ac_cv_func_utimensat" +if test "x$ac_cv_func_utimensat" = xyes; then : cat >>confdefs.h <<_ACEOF -#define HAVE_UTIMES 1 +#define HAVE_UTIMENSAT 1 _ACEOF - for ac_func in futimes futimesat +else + + case " $LIBOBJS " in + *" utimens.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS utimens.$ac_objext" + ;; +esac + + + for _sym in sudo_utimensat; do + COMPAT_EXP="${COMPAT_EXP}${_sym} +" + done + + for ac_func in utimes do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + ac_fn_c_check_func "$LINENO" "utimes" "ac_cv_func_utimes" +if test "x$ac_cv_func_utimes" = xyes; then : cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +#define HAVE_UTIMES 1 _ACEOF - break + +fi +done + + fi done +for ac_func in futimens +do : + ac_fn_c_check_func "$LINENO" "futimens" "ac_cv_func_futimens" +if test "x$ac_cv_func_futimens" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FUTIMENS 1 +_ACEOF else case " $LIBOBJS " in - *" utimes.$ac_objext "* ) ;; - *) LIBOBJS="$LIBOBJS utimes.$ac_objext" + *" utimens.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS utimens.$ac_objext" ;; esac - for _sym in sudo_utimes; do + for _sym in sudo_futimens; do COMPAT_EXP="${COMPAT_EXP}${_sym} " done - for ac_func in futime + for ac_func in futimes futimesat futime do : - ac_fn_c_check_func "$LINENO" "futime" "ac_cv_func_futime" -if test "x$ac_cv_func_futime" = xyes; then : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF -#define HAVE_FUTIME 1 +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF - - for _sym in sudo_futimes; do - COMPAT_EXP="${COMPAT_EXP}${_sym} -" - done - + break fi done @@ -19295,7 +19315,7 @@ if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : $as_echo "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h - SUDOERS_LIBS="${SUDOERS_LIBS} -lrt" + LIBS="${LIBS} -lrt" fi diff --git a/configure.ac b/configure.ac index 00f262d3e..d975058d6 100644 --- a/configure.ac +++ b/configure.ac @@ -2495,12 +2495,15 @@ AC_INCLUDES_DEFAULT ], [ AC_CHECK_FUNCS([sysinfo], [AC_CHECK_HEADERS([sys/systeminfo.h])]) ]) -AC_CHECK_FUNCS([utimes], [ - AC_CHECK_FUNCS([futimes futimesat], [break]) -], [ - AC_LIBOBJ(utimes) - SUDO_APPEND_COMPAT_EXP(sudo_utimes) - AC_CHECK_FUNCS([futime], [SUDO_APPEND_COMPAT_EXP(sudo_futimes)]) +AC_CHECK_FUNCS([utimensat], [], [ + AC_LIBOBJ(utimens) + SUDO_APPEND_COMPAT_EXP(sudo_utimensat) + AC_CHECK_FUNCS([utimes]) +]) +AC_CHECK_FUNCS([futimens], [], [ + AC_LIBOBJ(utimens) + SUDO_APPEND_COMPAT_EXP(sudo_futimens) + AC_CHECK_FUNCS([futimes futimesat futime], [break]) ]) SUDO_FUNC_FNMATCH([AC_DEFINE(HAVE_FNMATCH)], [ AC_LIBOBJ(fnmatch) @@ -2536,7 +2539,7 @@ AC_CHECK_FUNCS([clock_gettime], [], [ # On Solaris, clock_gettime is in librt AC_CHECK_LIB(rt, clock_gettime, [ AC_DEFINE(HAVE_CLOCK_GETTIME) - SUDOERS_LIBS="${SUDOERS_LIBS} -lrt" + LIBS="${LIBS} -lrt" ]) ]) AC_CHECK_FUNCS([getopt_long], [], [ diff --git a/include/sudo_compat.h b/include/sudo_compat.h index c112783d6..dba659634 100644 --- a/include/sudo_compat.h +++ b/include/sudo_compat.h @@ -189,6 +189,19 @@ # define S_IRWXU 0000700 /* rwx for owner */ #endif /* S_IRWXU */ +/* For futimens() and utimensat() emulation. */ +#if !defined(HAVE_FUTIMENS) && !defined(HAVE_UTIMENSAT) +# ifndef UTIME_OMIT +# define UTIME_OMIT -1L +# endif +# ifndef UTIME_NOW +# define UTIME_NOW -2L +# endif +# ifndef AT_FDCWD +# define AT_FDCWD -100 +# endif +#endif + /* * These should be defined in but not everyone has them. */ @@ -276,14 +289,6 @@ typedef struct sigaction sigaction_t; # define HAVE_DIRFD #endif -/* - * Define futimes() in terms of futimesat() if needed. - */ -#if !defined(HAVE_FUTIMES) && defined(HAVE_FUTIMESAT) -# define futimes(_f, _tv) futimesat(_f, NULL, _tv) -# define HAVE_FUTIMES -#endif - #if !defined(HAVE_KILLPG) && !defined(killpg) # define killpg(s) kill(-(s)) #endif @@ -386,16 +391,16 @@ __dso_public ssize_t sudo_getline(char **bufp, size_t *bufsizep, FILE *fp); # undef getline # define getline(_a, _b, _c) sudo_getline((_a), (_b), (_c)) #endif /* HAVE_GETLINE */ -#ifndef HAVE_UTIMES -__dso_public int sudo_utimes(const char *file, const struct timeval *times); -# undef utimes -# define utimes(_a, _b) sudo_utimes((_a), (_b)) -#endif /* HAVE_UTIMES */ -#ifdef HAVE_FUTIME -__dso_public int sudo_futimes(int fd, const struct timeval *times); -# undef futimes -# define futimes(_a, _b) sudo_futimes((_a), (_b)) -#endif /* HAVE_FUTIME */ +#ifndef HAVE_UTIMENSAT +__dso_public int sudo_utimensat(int fd, const char *file, const struct timespec *times, int flag); +# undef utimensat +# define utimensat(_a, _b, _c, _d) sudo_utimensat((_a), (_b), (_c), (_d)) +#endif /* HAVE_UTIMENSAT */ +#ifndef HAVE_FUTIMENS +__dso_public int sudo_futimens(int fd, const struct timespec *times); +# undef futimens +# define futimens(_a, _b) sudo_futimens((_a), (_b)) +#endif /* HAVE_FUTIMENS */ #if !defined(HAVE_SNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF) __dso_public int sudo_snprintf(char *str, size_t n, char const *fmt, ...) __printflike(3, 4); # undef snprintf diff --git a/include/sudo_util.h b/include/sudo_util.h index 3237c9e7d..71402c3ff 100644 --- a/include/sudo_util.h +++ b/include/sudo_util.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2014 Todd C. Miller + * Copyright (c) 2013-2015 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -104,24 +104,32 @@ #endif /* - * Macros to extract ctime and mtime as timevals. + * The timespec version of st_mtime may vary on different platforms. */ -#ifdef HAVE_ST_MTIM -# ifdef HAVE_ST__TIM -# define ctim_get(_x, _y) TIMESPEC_TO_TIMEVAL((_y), &(_x)->st_ctim.st__tim) -# define mtim_get(_x, _y) TIMESPEC_TO_TIMEVAL((_y), &(_x)->st_mtim.st__tim) +#if defined(HAVE_ST_MTIM) +# if defined(HAVE_ST__TIM) +# define SUDO_ST_MTIM st_mtim.st__tim # else -# define ctim_get(_x, _y) TIMESPEC_TO_TIMEVAL((_y), &(_x)->st_ctim) -# define mtim_get(_x, _y) TIMESPEC_TO_TIMEVAL((_y), &(_x)->st_mtim) +# define SUDO_ST_MTIM st_mtim # endif -#else -# ifdef HAVE_ST_MTIMESPEC -# define ctim_get(_x, _y) TIMESPEC_TO_TIMEVAL((_y), &(_x)->st_ctimespec) -# define mtim_get(_x, _y) TIMESPEC_TO_TIMEVAL((_y), &(_x)->st_mtimespec) +#elif defined(HAVE_ST_MTIMESPEC) +# define SUDO_ST_MTIM st_mtimespec +#endif + +/* + * Macro to extract mtime as timespec. + * If there is no way to set the timestamp using nanosecond precision, + * we only fetch microsecond precision. Otherwise there is a mismatch + * between the timestamp we read and the one we wrote. + */ +#if defined(SUDO_ST_MTIM) +# if defined(HAVE_FUTIMENS) && defined(HAVE_UTIMENSAT) +# define mtim_get(_x, _y) ((_y) = (_x)->SUDO_ST_MTIM) # else -# define ctim_get(_x, _y) do { (_y)->tv_sec = (_x)->st_ctime; (_y)->tv_usec = 0; } while (0) -# define mtim_get(_x, _y) do { (_y)->tv_sec = (_x)->st_mtime; (_y)->tv_usec = 0; } while (0) -# endif /* HAVE_ST_MTIMESPEC */ +# define mtim_get(_x, _y) do { (_y).tv_sec = (_x)->SUDO_ST_MTIM.tv_sec; (_y).tv_nsec = ((_x)->SUDO_ST_MTIM.tv_nsec / 1000) * 1000; } while (0) +# endif +#else +# define mtim_get(_x, _y) do { (_y).tv_sec = (_x)->st_mtime; (_y).tv_nsec = 0; } while (0) #endif /* HAVE_ST_MTIM */ /* @@ -148,6 +156,12 @@ __dso_public int aix_setauthdb_v1(char *user); __dso_public char *sudo_gethostname_v1(void); #define sudo_gethostname() sudo_gethostname_v1() +/* gettime.c */ +__dso_public int sudo_gettime_mono_v1(struct timespec *ts); +#define sudo_gettime_mono(_a) sudo_gettime_mono_v1((_a)) +__dso_public int sudo_gettime_real_v1(struct timespec *ts); +#define sudo_gettime_real(_a) sudo_gettime_real_v1((_a)) + /* gidlist.c */ __dso_public int sudo_parse_gids_v1(const char *gidstr, const gid_t *basegid, GETGROUPS_T **gidsp); #define sudo_parse_gids(_a, _b, _c) sudo_parse_gids_v1((_a), (_b), (_c)) diff --git a/lib/util/Makefile.in b/lib/util/Makefile.in index 909588960..2117aee67 100644 --- a/lib/util/Makefile.in +++ b/lib/util/Makefile.in @@ -96,10 +96,10 @@ DEVEL = @DEVEL@ SHELL = @SHELL@ -LTOBJS = alloc.lo event.lo fatal.lo key_val.lo gethostname.lo gidlist.lo \ - lbuf.lo locking.lo parseln.lo progname.lo secure_path.lo setgroups.lo \ - strtobool.lo strtoid.lo strtomode.lo sudo_conf.lo sudo_debug.lo \ - sudo_dso.lo term.lo ttysize.lo @COMMON_OBJS@ @LTLIBOBJS@ +LTOBJS = alloc.lo event.lo fatal.lo key_val.lo gethostname.lo gettime.lo \ + gidlist.lo lbuf.lo locking.lo parseln.lo progname.lo secure_path.lo \ + setgroups.lo strtobool.lo strtoid.lo strtomode.lo sudo_conf.lo \ + sudo_debug.lo sudo_dso.lo term.lo ttysize.lo @COMMON_OBJS@ @LTLIBOBJS@ ATOFOO_TEST_OBJS = atofoo_test.lo locale_stub.lo @@ -375,6 +375,11 @@ getopt_long.lo: $(srcdir)/getopt_long.c $(incdir)/compat/getopt.h \ $(incdir)/sudo_compat.h $(incdir)/sudo_fatal.h \ $(top_builddir)/config.h $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/getopt_long.c +gettime.lo: $(srcdir)/gettime.c $(incdir)/compat/stdbool.h \ + $(incdir)/compat/timespec.h $(incdir)/sudo_compat.h \ + $(incdir)/sudo_debug.h $(incdir)/sudo_queue.h \ + $(incdir)/sudo_util.h $(top_builddir)/config.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/gettime.c gidlist.lo: $(srcdir)/gidlist.c $(incdir)/compat/stdbool.h \ $(incdir)/sudo_alloc.h $(incdir)/sudo_compat.h \ $(incdir)/sudo_debug.h $(incdir)/sudo_fatal.h \ @@ -530,6 +535,7 @@ ttysize.lo: $(srcdir)/ttysize.c $(incdir)/compat/stdbool.h \ $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \ $(top_builddir)/config.h $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/ttysize.c -utimes.lo: $(srcdir)/utimes.c $(incdir)/compat/utime.h $(incdir)/sudo_compat.h \ - $(top_builddir)/config.h - $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/utimes.c +utimens.lo: $(srcdir)/utimens.c $(incdir)/compat/timespec.h \ + $(incdir)/compat/utime.h $(incdir)/sudo_compat.h \ + $(top_builddir)/config.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/utimens.c diff --git a/plugins/sudoers/gettime.c b/lib/util/gettime.c similarity index 87% rename from plugins/sudoers/gettime.c rename to lib/util/gettime.c index 1c9a77d2e..04676f50a 100644 --- a/plugins/sudoers/gettime.c +++ b/lib/util/gettime.c @@ -44,7 +44,9 @@ # include #endif -#include "sudoers.h" +#include "sudo_compat.h" +#include "sudo_debug.h" +#include "sudo_util.h" /* On Linux, CLOCK_MONOTONIC does not run while suspended. */ #if defined(CLOCK_BOOTTIME) @@ -55,9 +57,9 @@ #if defined(HAVE_CLOCK_GETTIME) int -sudo_gettime_real(struct timespec *ts) +sudo_gettime_real_v1(struct timespec *ts) { - debug_decl(sudo_gettime_real, SUDOERS_DEBUG_UTIL) + debug_decl(sudo_gettime_real, SUDO_DEBUG_UTIL) if (clock_gettime(CLOCK_REALTIME, ts) == -1) { struct timeval tv; @@ -72,10 +74,10 @@ sudo_gettime_real(struct timespec *ts) } #else int -sudo_gettime_real(struct timespec *ts) +sudo_gettime_real_v1(struct timespec *ts) { struct timeval tv; - debug_decl(sudo_gettime_real, SUDOERS_DEBUG_UTIL) + debug_decl(sudo_gettime_real, SUDO_DEBUG_UTIL) if (gettimeofday(&tv, NULL) == -1) debug_return_int(-1); @@ -86,10 +88,10 @@ sudo_gettime_real(struct timespec *ts) #if defined(HAVE_CLOCK_GETTIME) && defined(SUDO_CLOCK_MONOTONIC) int -sudo_gettime_mono(struct timespec *ts) +sudo_gettime_mono_v1(struct timespec *ts) { static int has_monoclock = -1; - debug_decl(sudo_gettime_mono, SUDOERS_DEBUG_UTIL) + debug_decl(sudo_gettime_mono, SUDO_DEBUG_UTIL) /* Check whether the kernel/libc actually supports CLOCK_MONOTONIC. */ # ifdef _SC_MONOTONIC_CLOCK @@ -108,11 +110,11 @@ sudo_gettime_mono(struct timespec *ts) } #elif defined(__MACH__) int -sudo_gettime_mono(struct timespec *ts) +sudo_gettime_mono_v1(struct timespec *ts) { uint64_t abstime, nsec; static mach_timebase_info_data_t timebase_info; - debug_decl(sudo_gettime_mono, SUDOERS_DEBUG_UTIL) + debug_decl(sudo_gettime_mono, SUDO_DEBUG_UTIL) if (timebase_info.denom == 0) (void) mach_timebase_info(&timebase_info); @@ -124,7 +126,7 @@ sudo_gettime_mono(struct timespec *ts) } #else int -sudo_gettime_mono(struct timespec *ts) +sudo_gettime_mono_v1(struct timespec *ts) { /* No monotonic clock available, use wall clock. */ return sudo_gettime_real(ts); diff --git a/lib/util/util.exp.in b/lib/util/util.exp.in index 170ebdd6f..55b21e67b 100644 --- a/lib/util/util.exp.in +++ b/lib/util/util.exp.in @@ -66,6 +66,8 @@ sudo_fatal_nodebug_v1 sudo_fatalx_nodebug_v1 sudo_get_ttysize_v1 sudo_gethostname_v1 +sudo_gettime_mono_v1 +sudo_gettime_real_v1 sudo_lbuf_append_quoted_v1 sudo_lbuf_append_v1 sudo_lbuf_destroy_v1 diff --git a/lib/util/utimens.c b/lib/util/utimens.c new file mode 100644 index 000000000..b2eac19b6 --- /dev/null +++ b/lib/util/utimens.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2015 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#if !defined(HAVE_FUTIMENS) || !defined(HAVE_UTIMENSAT) + +#include +#include +#include +#include +#include +#ifdef TIME_WITH_SYS_TIME +# include +#endif +#ifndef HAVE_STRUCT_TIMESPEC +# include "compat/timespec.h" +#endif +#ifdef HAVE_UTIME_H +# include +#else +# include "compat/utime.h" +#endif + +#include "sudo_compat.h" + +#if !defined(HAVE_FUTIMES) && defined(HAVE_FUTIMESAT) +# define futimes(_f, _tv) futimesat(_f, NULL, _tv) +# define HAVE_FUTIMES +#endif + +#if defined(HAVE_ST_MTIM) +# ifdef HAVE_ST__TIM +# define ATIME_TO_TIMEVAL(_x, _y) TIMESPEC_TO_TIMEVAL((_x), &(_y)->st_atim.st__tim) +# define MTIME_TO_TIMEVAL(_x, _y) TIMESPEC_TO_TIMEVAL((_x), &(_y)->st_mtim.st__tim) +# else +# define ATIME_TO_TIMEVAL(_x, _y) TIMESPEC_TO_TIMEVAL((_x), &(_y)->st_atim) +# define MTIME_TO_TIMEVAL(_x, _y) TIMESPEC_TO_TIMEVAL((_x), &(_y)->st_mtim) +# endif +#elif defined(HAVE_ST_MTIMESPEC) +# define ATIME_TO_TIMEVAL(_x, _y) TIMESPEC_TO_TIMEVAL((_x), &(_y)->st_atimespec) +# define MTIME_TO_TIMEVAL(_x, _y) TIMESPEC_TO_TIMEVAL((_x), &(_y)->st_mtimespec) +#else +# define ATIME_TO_TIMEVAL(_x, _y) do { (_x)->tv_sec = (_y)->st_atime; (_x)->tv_usec = 0; } while (0) +# define MTIME_TO_TIMEVAL(_x, _y) do { (_x)->tv_sec = (_y)->st_mtime; (_x)->tv_usec = 0; } while (0) +#endif /* HAVE_ST_MTIM */ + +/* + * Convert the pair of timespec structs passed to futimens() / utimensat() + * to a pair of timeval structs, handling UTIME_OMIT and UTIME_NOW. + * Returns 0 on success and -1 on failure (setting errno). + */ +static int +utimens_ts_to_tv(int fd, const char *file, const struct timespec *ts, + struct timeval *tv) +{ + TIMESPEC_TO_TIMEVAL(&tv[0], &ts[0]); + TIMESPEC_TO_TIMEVAL(&tv[1], &ts[1]); + if (ts[0].tv_nsec == UTIME_OMIT || ts[1].tv_nsec == UTIME_OMIT) { + struct stat sb; + + if (fd != -1) { + /* For futimens() */ + if (fstat(fd, &sb) == -1) + return -1; + } else { + /* For utimensat() */ + if (stat(file, &sb) == -1) + return -1; + } + if (ts[0].tv_nsec == UTIME_OMIT) + ATIME_TO_TIMEVAL(&tv[0], &sb); + if (ts[1].tv_nsec == UTIME_OMIT) + MTIME_TO_TIMEVAL(&tv[1], &sb); + } + if (ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW) { + struct timeval now; + + if (gettimeofday(&now, NULL) == -1) + return -1; + if (ts[0].tv_nsec == UTIME_NOW) + tv[0] = now; + if (ts[1].tv_nsec == UTIME_NOW) + tv[1] = now; + } + return 0; +} + +#if defined(HAVE_FUTIMES) +/* + * Emulate futimens() via futimes() + */ +int +sudo_futimens(int fd, const struct timespec *ts) +{ + struct timeval tv[2], *times = NULL; + + if (ts != NULL) { + if (utimens_ts_to_tv(fd, NULL, ts, tv) == -1) + return -1; + times = tv; + } + return futimes(fd, times); +} +#elif defined(HAVE_FUTIME) +/* + * Emulate futimens() via futime() + */ +int +sudo_futimens(int fd, const struct timeval *ts) +{ + struct utimbuf utb, *times = NULL; + + if (ts != NULL) { + struct timeval tv[2]; + + if (utimens_ts_to_tv(fd, NULL, ts, tv) == -1) + return -1; + utb.actime = (time_t)(tv[0].tv_sec + tv[0].tv_usec / 1000000); + utb.modtime = (time_t)(tv[1].tv_sec + tv[1].tv_usec / 1000000); + times = &utb; + } + return futime(fd, times); +} +#else +/* + * Nothing to do but fail. + */ +int +sudo_futimens(int fd, const struct timeval *ts) +{ + errno = ENOSYS; + return -1; +} +#endif /* HAVE_FUTIMES */ + +#if defined(HAVE_UTIMES) +/* + * Emulate utimensat() via utimes() + */ +int +sudo_utimensat(int fd, const char *file, const struct timespec *ts, int flag) +{ + struct timeval tv[2], *times = NULL; + + if (fd != AT_FDCWD || flag != 0) { + errno = ENOTSUP; + return -1; + } + + if (ts != NULL) { + if (utimens_ts_to_tv(-1, file, ts, tv) == -1) + return -1; + times = tv; + } + return utimes(file, times); +} +#else +/* + * Emulate utimensat() via utime() + */ +int +sudo_utimensat(int fd, const char *file, const struct timespec *ts, int flag) +{ + struct utimbuf utb, *times = NULL; + + if (fd != AT_FDCWD || flag != 0) { + errno = ENOTSUP; + return -1; + } + + if (ts != NULL) { + struct timeval tv[2]; + + if (utimens_ts_to_tv(-1, file, ts, tv) == -1) + return -1; + utb.actime = (time_t)(tv[0].tv_sec + tv[0].tv_usec / 1000000); + utb.modtime = (time_t)(tv[1].tv_sec + tv[1].tv_usec / 1000000); + times = &utb; + } + return utime(file, times); +} +#endif /* !HAVE_UTIMES */ + +#endif /* !HAVE_FUTIMENS && !HAVE_UTIMENSAT */ diff --git a/lib/util/utimes.c b/lib/util/utimes.c deleted file mode 100644 index 41045610a..000000000 --- a/lib/util/utimes.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2004-2005, 2007, 2010-2011, 2013, 2014 - * Todd C. Miller - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include - -#if !defined(HAVE_UTIMES) || (!defined(HAVE_FUTIMES) && !defined(HAVE_FUTIMESAT)) - -#include -#include -#include -#ifdef TIME_WITH_SYS_TIME -# include -#endif - -#ifdef HAVE_UTIME_H -# include -#else -# include "compat/utime.h" -#endif - -#include "sudo_compat.h" - -#ifndef HAVE_UTIMES -/* - * Emulate utimes() via utime() - */ -int -sudo_utimes(const char *file, const struct timeval *times) -{ - if (times != NULL) { - struct utimbuf utb; - - utb.actime = (time_t)(times[0].tv_sec + times[0].tv_usec / 1000000); - utb.modtime = (time_t)(times[1].tv_sec + times[1].tv_usec / 1000000); - return utime(file, &utb); - } else - return utime(file, NULL); -} -#endif /* !HAVE_UTIMES */ - -#ifdef HAVE_FUTIME -/* - * Emulate futimes() via futime() - */ -int -sudo_futimes(int fd, const struct timeval *times) -{ - if (times != NULL) { - struct utimbuf utb; - - utb.actime = (time_t)(times[0].tv_sec + times[0].tv_usec / 1000000); - utb.modtime = (time_t)(times[1].tv_sec + times[1].tv_usec / 1000000); - return futime(fd, &utb); - } else - return futime(fd, NULL); -} -#endif /* HAVE_FUTIME */ - -#endif /* !HAVE_UTIMES || (!HAVE_FUTIMES && !HAVE_FUTIMESAT) */ diff --git a/mkdep.pl b/mkdep.pl index e7af9f0f4..a08069ff4 100755 --- a/mkdep.pl +++ b/mkdep.pl @@ -70,7 +70,7 @@ sub mkdep { $makefile =~ s:\@SUDOERS_OBJS\@:bsm_audit.lo linux_audit.lo ldap.lo solaris_audit.lo sssd.lo:; # XXX - fill in AUTH_OBJS from contents of the auth dir instead $makefile =~ s:\@AUTH_OBJS\@:afs.lo aix_auth.lo bsdauth.lo dce.lo fwtk.lo getspwuid.lo kerb5.lo pam.lo passwd.lo rfc1938.lo secureware.lo securid5.lo sia.lo:; - $makefile =~ s:\@LTLIBOBJS\@:closefrom.lo fnmatch.lo getaddrinfo.lo getcwd.lo getgrouplist.lo getline.lo getopt_long.lo glob.lo inet_ntop_lo inet_pton.lo isblank.lo memrchr.lo memset_s.lo mksiglist.lo mksigname.lo mktemp.lo pw_dup.lo sha2.lo sig2str.lo siglist.lo signame.lo snprintf.lo strlcat.lo strlcpy.lo strsignal.lo strtonum.lo utimes.lo:; + $makefile =~ s:\@LTLIBOBJS\@:closefrom.lo fnmatch.lo getaddrinfo.lo getcwd.lo getgrouplist.lo getline.lo getopt_long.lo glob.lo inet_ntop_lo inet_pton.lo isblank.lo memrchr.lo memset_s.lo mksiglist.lo mksigname.lo mktemp.lo pw_dup.lo sha2.lo sig2str.lo siglist.lo signame.lo snprintf.lo strlcat.lo strlcpy.lo strsignal.lo strtonum.lo utimens.lo:; # Parse OBJS lines my %objs; diff --git a/plugins/sudoers/Makefile.in b/plugins/sudoers/Makefile.in index 4e132325e..0e40ec2af 100644 --- a/plugins/sudoers/Makefile.in +++ b/plugins/sudoers/Makefile.in @@ -143,7 +143,7 @@ LIBPARSESUDOERS_OBJS = alias.lo audit.lo base64.lo defaults.lo hexchar.lo \ toke_util.lo SUDOERS_OBJS = $(AUTH_OBJS) boottime.lo check.lo env.lo find_path.lo \ - gettime.lo goodpath.lo group_plugin.lo interfaces.lo iolog.lo \ + goodpath.lo group_plugin.lo interfaces.lo iolog.lo \ iolog_path.lo locale.lo logging.lo logwrap.lo parse.lo \ policy.lo prompt.lo set_perms.lo sudo_nss.lo sudoers.lo \ timestamp.lo @SUDOERS_OBJS@ @@ -654,16 +654,6 @@ getspwuid.lo: $(srcdir)/getspwuid.c $(devdir)/def_data.h \ $(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \ $(top_builddir)/config.h $(top_builddir)/pathnames.h $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/getspwuid.c -gettime.lo: $(srcdir)/gettime.c $(devdir)/def_data.h \ - $(incdir)/compat/stdbool.h $(incdir)/compat/timespec.h \ - $(incdir)/sudo_alloc.h $(incdir)/sudo_compat.h \ - $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \ - $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \ - $(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \ - $(incdir)/sudo_util.h $(srcdir)/defaults.h $(srcdir)/logging.h \ - $(srcdir)/sudo_nss.h $(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \ - $(top_builddir)/config.h $(top_builddir)/pathnames.h - $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/gettime.c goodpath.lo: $(srcdir)/goodpath.c $(devdir)/def_data.h \ $(incdir)/compat/stdbool.h $(incdir)/sudo_alloc.h \ $(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \ @@ -1091,14 +1081,14 @@ tsgetgrpw.o: $(srcdir)/tsgetgrpw.c $(devdir)/def_data.h \ $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/tsgetgrpw.c visudo.o: $(srcdir)/visudo.c $(devdir)/def_data.h $(devdir)/gram.h \ $(incdir)/compat/getopt.h $(incdir)/compat/stdbool.h \ - $(incdir)/sudo_alloc.h $(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \ - $(incdir)/sudo_debug.h $(incdir)/sudo_fatal.h \ - $(incdir)/sudo_gettext.h $(incdir)/sudo_plugin.h \ - $(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(srcdir)/defaults.h \ - $(srcdir)/logging.h $(srcdir)/parse.h $(srcdir)/redblack.h \ - $(srcdir)/sudo_nss.h $(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \ - $(srcdir)/sudoers_version.h $(top_builddir)/config.h \ - $(top_builddir)/pathnames.h + $(incdir)/compat/timespec.h $(incdir)/sudo_alloc.h \ + $(incdir)/sudo_compat.h $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \ + $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \ + $(srcdir)/defaults.h $(srcdir)/logging.h $(srcdir)/parse.h \ + $(srcdir)/redblack.h $(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \ + $(srcdir)/sudoers_debug.h $(srcdir)/sudoers_version.h \ + $(top_builddir)/config.h $(top_builddir)/pathnames.h $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/visudo.c visudo_json.o: $(srcdir)/visudo_json.c $(devdir)/def_data.h $(devdir)/gram.h \ $(incdir)/compat/stdbool.h $(incdir)/sudo_alloc.h \ diff --git a/plugins/sudoers/boottime.c b/plugins/sudoers/boottime.c index fd5625cdd..ed3664419 100644 --- a/plugins/sudoers/boottime.c +++ b/plugins/sudoers/boottime.c @@ -59,13 +59,13 @@ #include "sudoers.h" /* - * Fill in a struct timeval with the time the system booted. + * Fill in a struct timespec with the time the system booted. * Returns 1 on success and 0 on failure. */ #if defined(__linux__) bool -get_boottime(struct timeval *tv) +get_boottime(struct timespec *ts) { char *line = NULL; size_t linesize = 0; @@ -81,8 +81,8 @@ get_boottime(struct timeval *tv) if (strncmp(line, "btime ", 6) == 0) { long long llval = strtonum(line + 6, 1, LLONG_MAX, NULL); if (llval > 0) { - tv->tv_sec = (time_t)llval; - tv->tv_usec = 0; + ts->tv_sec = (time_t)llval; + ts->tv_nsec = 0; found = true; break; } @@ -98,17 +98,20 @@ get_boottime(struct timeval *tv) #elif defined(HAVE_SYSCTL) && defined(KERN_BOOTTIME) bool -get_boottime(struct timeval *tv) +get_boottime(struct timespec *ts) { size_t size; int mib[2]; + struct timeval tv; debug_decl(get_boottime, SUDOERS_DEBUG_UTIL) mib[0] = CTL_KERN; mib[1] = KERN_BOOTTIME; - size = sizeof(*tv); - if (sysctl(mib, 2, tv, &size, NULL, 0) != -1) + size = sizeof(tv); + if (sysctl(mib, 2, &tv, &size, NULL, 0) != -1) { + TIMEVAL_TO_TIMESPEC(&tv, ts); debug_return_bool(true); + } debug_return_bool(false); } @@ -116,7 +119,7 @@ get_boottime(struct timeval *tv) #elif defined(HAVE_GETUTXID) bool -get_boottime(struct timeval *tv) +get_boottime(struct timespec *ts) { struct utmpx *ut, key; debug_decl(get_boottime, SUDOERS_DEBUG_UTIL) @@ -124,10 +127,8 @@ get_boottime(struct timeval *tv) memset(&key, 0, sizeof(key)); key.ut_type = BOOT_TIME; setutxent(); - if ((ut = getutxid(&key)) != NULL) { - tv->tv_sec = ut->ut_tv.tv_sec; - tv->tv_usec = ut->ut_tv.tv_usec; - } + if ((ut = getutxid(&key)) != NULL) + TIMEVAL_TO_TIMESPEC(&ut->ut_tv, ts); endutxent(); debug_return_bool(ut != NULL); } @@ -135,7 +136,7 @@ get_boottime(struct timeval *tv) #elif defined(HAVE_GETUTID) bool -get_boottime(struct timeval *tv) +get_boottime(struct timespec *ts) { struct utmp *ut, key; debug_decl(get_boottime, SUDOERS_DEBUG_UTIL) @@ -144,8 +145,8 @@ get_boottime(struct timeval *tv) key.ut_type = BOOT_TIME; setutent(); if ((ut = getutid(&key)) != NULL) { - tv->tv_sec = ut->ut_time; - tv->tv_usec = 0; + ts->tv_sec = ut->ut_time; + ts->tv_nsec = 0; } endutent(); debug_return_bool(ut != NULL); @@ -154,7 +155,7 @@ get_boottime(struct timeval *tv) #else bool -get_boottime(struct timeval *tv) +get_boottime(struct timespec *ts) { debug_decl(get_boottime, SUDOERS_DEBUG_UTIL) debug_return_bool(false); diff --git a/plugins/sudoers/sudoers.h b/plugins/sudoers/sudoers.h index af0b79a82..1d659b5d5 100644 --- a/plugins/sudoers/sudoers.h +++ b/plugins/sudoers/sudoers.h @@ -239,10 +239,6 @@ char *expand_prompt(const char *old_prompt, const char *auth_user); void remove_timestamp(bool); bool set_lectured(void); -/* gettime.c */ -int sudo_gettime_real(struct timespec *ts); -int sudo_gettime_mono(struct timespec *ts); - /* sudo_auth.c */ bool sudo_auth_needs_end_session(void); int verify_user(struct passwd *pw, char *prompt, int validated); @@ -315,7 +311,7 @@ void sudo_setspent(void); char *get_timestr(time_t, int); /* boottime.c */ -bool get_boottime(struct timeval *); +bool get_boottime(struct timespec *); /* iolog.c */ bool io_nextid(char *iolog_dir, char *iolog_dir_fallback, char sessid[7]); diff --git a/plugins/sudoers/timestamp.c b/plugins/sudoers/timestamp.c index a94cd3762..f64e6eb86 100644 --- a/plugins/sudoers/timestamp.c +++ b/plugins/sudoers/timestamp.c @@ -444,10 +444,10 @@ timestamp_status(struct passwd *pw) /* Ignore and clear time stamp file if mtime predates boot time. */ if (fstat(fd, &sb) == 0) { - struct timeval boottime, mtime; + struct timespec boottime, mtime; - mtim_get(&sb, &mtime); - if (get_boottime(&boottime) && sudo_timevalcmp(&mtime, &boottime, <)) { + mtim_get(&sb, mtime); + if (get_boottime(&boottime) && sudo_timespeccmp(&mtime, &boottime, <)) { ignore_result(ftruncate(fd, (off_t)0)); status = TS_MISSING; goto done; diff --git a/plugins/sudoers/visudo.c b/plugins/sudoers/visudo.c index 4a27a3731..2502bfe36 100644 --- a/plugins/sudoers/visudo.c +++ b/plugins/sudoers/visudo.c @@ -70,6 +70,9 @@ #ifdef TIME_WITH_SYS_TIME # include #endif +#ifndef HAVE_STRUCT_TIMESPEC +# include "compat/timespec.h" +#endif #include "sudoers.h" #include "parse.h" @@ -321,8 +324,8 @@ edit_sudoers(struct sudoersfile *sp, char *editor, char *args, int lineno) char *cp; /* scratch char pointer */ char buf[PATH_MAX*2]; /* buffer used for copying files */ char linestr[64]; /* string version of lineno */ - struct timeval tv, times[2]; /* time before and after edit */ - struct timeval orig_mtim; /* starting mtime of sudoers file */ + struct timespec ts, times[2]; /* time before and after edit */ + struct timespec orig_mtim; /* starting mtime of sudoers file */ off_t orig_size; /* starting size of sudoers file */ ssize_t nread; /* number of bytes read */ struct stat sb; /* stat buffer */ @@ -332,7 +335,7 @@ edit_sudoers(struct sudoersfile *sp, char *editor, char *args, int lineno) if (fstat(sp->fd, &sb) == -1) sudo_fatal(U_("unable to stat %s"), sp->path); orig_size = sb.st_size; - mtim_get(&sb, &orig_mtim); + mtim_get(&sb, orig_mtim); /* Create the temp file if needed and set timestamp. */ if (sp->tpath == NULL) { @@ -358,8 +361,8 @@ edit_sudoers(struct sudoersfile *sp, char *editor, char *args, int lineno) (void) close(tfd); } times[0].tv_sec = times[1].tv_sec = orig_mtim.tv_sec; - times[0].tv_usec = times[1].tv_usec = orig_mtim.tv_usec; - (void) utimes(sp->tpath, times); + times[0].tv_nsec = times[1].tv_nsec = orig_mtim.tv_nsec; + (void) utimensat(AT_FDCWD, sp->tpath, times, 0); /* Does the editor support +lineno? */ if (lineno > 0) @@ -429,13 +432,13 @@ edit_sudoers(struct sudoersfile *sp, char *editor, char *args, int lineno) * XPG4 specifies that vi's exit value is a function of the * number of errors during editing (?!?!). */ - if (gettimeofday(×[0], NULL) == -1) { + if (sudo_gettime_real(×[0]) == -1) { sudo_warn(U_("unable to read the clock")); goto done; } if (run_command(editor, av) != -1) { - if (gettimeofday(×[1], NULL) == -1) { + if (sudo_gettime_real(×[1]) == -1) { sudo_warn(U_("unable to read the clock")); goto done; } @@ -460,13 +463,13 @@ edit_sudoers(struct sudoersfile *sp, char *editor, char *args, int lineno) /* Set modified bit if the user changed the file. */ modified = true; - mtim_get(&sb, &tv); - if (orig_size == sb.st_size && sudo_timevalcmp(&orig_mtim, &tv, ==)) { + mtim_get(&sb, ts); + if (orig_size == sb.st_size && sudo_timespeccmp(&orig_mtim, &ts, ==)) { /* * If mtime and size match but the user spent no measurable * time in the editor we can't tell if the file was changed. */ - if (sudo_timevalcmp(×[0], ×[1], !=)) + if (sudo_timespeccmp(×[0], ×[1], !=)) modified = false; } diff --git a/src/Makefile.in b/src/Makefile.in index 6dbf1f2cf..f0a8d6fa0 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -349,12 +349,12 @@ sudo.o: $(srcdir)/sudo.c $(incdir)/compat/stdbool.h $(incdir)/sudo_alloc.h \ $(top_builddir)/pathnames.h ./sudo_usage.h $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/sudo.c sudo_edit.o: $(srcdir)/sudo_edit.c $(incdir)/compat/stdbool.h \ - $(incdir)/sudo_alloc.h $(incdir)/sudo_compat.h \ - $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \ - $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \ - $(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(srcdir)/sudo.h \ - $(srcdir)/sudo_exec.h $(top_builddir)/config.h \ - $(top_builddir)/pathnames.h + $(incdir)/compat/timespec.h $(incdir)/sudo_alloc.h \ + $(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \ + $(incdir)/sudo_debug.h $(incdir)/sudo_fatal.h \ + $(incdir)/sudo_gettext.h $(incdir)/sudo_queue.h \ + $(incdir)/sudo_util.h $(srcdir)/sudo.h $(srcdir)/sudo_exec.h \ + $(top_builddir)/config.h $(top_builddir)/pathnames.h $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/sudo_edit.c sudo_noexec.lo: $(srcdir)/sudo_noexec.c $(incdir)/sudo_compat.h \ $(top_builddir)/config.h diff --git a/src/sesh.c b/src/sesh.c index 78eab84b4..ec10ec4e8 100644 --- a/src/sesh.c +++ b/src/sesh.c @@ -121,7 +121,7 @@ sesh_sudoedit(int argc, char *argv[]) int fd_src, fd_dst, i, oflags_dst, post, ret = SESH_ERR_FAILURE; ssize_t nread, nwritten; struct stat sb; - struct timeval times[2]; + struct timespec times[2]; char buf[BUFSIZ]; debug_decl(sesh_sudoedit, SUDO_DEBUG_EDIT) @@ -206,14 +206,13 @@ sesh_sudoedit(int argc, char *argv[]) if (fd_src == -1 || fstat(fd_src, &sb) != 0) memset(&sb, 0, sizeof(sb)); /* Make mtime on temp file match src. */ - mtim_get(&sb, ×[0]); + mtim_get(&sb, times[0]); times[1].tv_sec = times[0].tv_sec; - times[1].tv_usec = times[0].tv_usec; -#if defined(HAVE_FUTIMES) || defined(HAVE_FUTIME) - (void) futimes(fd_dst, times); -#else - (void) utimes(path_dst, times); -#endif + times[1].tv_nsec = times[0].tv_nsec; + if (futimens(fd_dst, times) == -1) { + if (utimensat(AT_FDCWD, path_dst, times, 0) == -1) + sudo_warn("%s", path_dst); + } } close(fd_dst); } diff --git a/src/sudo_edit.c b/src/sudo_edit.c index be71fb501..d3cd22b51 100644 --- a/src/sudo_edit.c +++ b/src/sudo_edit.c @@ -48,6 +48,9 @@ #ifdef TIME_WITH_SYS_TIME # include #endif +#ifndef HAVE_STRUCT_TIMESPEC +# include "compat/timespec.h" +#endif #ifdef HAVE_SELINUX # include #endif @@ -63,7 +66,7 @@ struct tempfile { char *tfile; char *ofile; - struct timeval omtim; + struct timespec omtim; off_t osize; }; @@ -174,7 +177,7 @@ sudo_edit_create_tfiles(struct command_details *command_details, int i, j, tfd, ofd, rc; char buf[BUFSIZ]; ssize_t nwritten, nread; - struct timeval times[2]; + struct timespec times[2]; struct stat sb; debug_decl(sudo_edit_create_tfiles, SUDO_DEBUG_EDIT) @@ -207,7 +210,7 @@ sudo_edit_create_tfiles(struct command_details *command_details, } tf[j].ofile = files[i]; tf[j].osize = sb.st_size; - mtim_get(&sb, &tf[j].omtim); + mtim_get(&sb, tf[j].omtim); sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, "seteuid(%u)", user_details.uid); if (seteuid(user_details.uid) != 0) @@ -239,19 +242,18 @@ sudo_edit_create_tfiles(struct command_details *command_details, * We always update the stashed mtime because the time * resolution of the filesystem the temporary file is on may * not match that of the filesystem where the file to be edited - * resides. It is OK if futimes() fails since we only use the + * resides. It is OK if futimens() fails since we only use the * info to determine whether or not a file has been modified. */ times[0].tv_sec = times[1].tv_sec = tf[j].omtim.tv_sec; - times[0].tv_usec = times[1].tv_usec = tf[j].omtim.tv_usec; -#if defined(HAVE_FUTIMES) || defined(HAVE_FUTIME) - (void) futimes(tfd, times); -#else - (void) utimes(tf[j].tfile, times); -#endif + times[0].tv_nsec = times[1].tv_nsec = tf[j].omtim.tv_nsec; + if (futimens(tfd, times) == -1) { + if (utimensat(AT_FDCWD, tf[j].tfile, times, 0) == -1) + sudo_warn("%s", tf[j].tfile); + } rc = fstat(tfd, &sb); if (!rc) - mtim_get(&sb, &tf[j].omtim); + mtim_get(&sb, tf[j].omtim); close(tfd); j++; } @@ -264,12 +266,12 @@ sudo_edit_create_tfiles(struct command_details *command_details, */ static int sudo_edit_copy_tfiles(struct command_details *command_details, - struct tempfile *tf, int nfiles, struct timeval *times) + struct tempfile *tf, int nfiles, struct timespec *times) { int i, tfd, ofd, rc, errors = 0; char buf[BUFSIZ]; ssize_t nwritten, nread; - struct timeval tv; + struct timespec ts; struct stat sb; debug_decl(sudo_edit_copy_tfiles, SUDO_DEBUG_EDIT) @@ -298,13 +300,13 @@ sudo_edit_copy_tfiles(struct command_details *command_details, errors++; continue; } - mtim_get(&sb, &tv); - if (tf[i].osize == sb.st_size && sudo_timevalcmp(&tf[i].omtim, &tv, ==)) { + mtim_get(&sb, ts); + if (tf[i].osize == sb.st_size && sudo_timespeccmp(&tf[i].omtim, &ts, ==)) { /* * If mtime and size match but the user spent no measurable * time in the editor we can't tell if the file was changed. */ - if (sudo_timevalcmp(×[0], ×[1], !=)) { + if (sudo_timespeccmp(×[0], ×[1], !=)) { sudo_warnx(U_("%s unchanged"), tf[i].ofile); unlink(tf[i].tfile); close(tfd); @@ -387,7 +389,7 @@ selinux_edit_create_tfiles(struct command_details *command_details, if (stat(ofile, &sb) == -1) memset(&sb, 0, sizeof(sb)); /* new file */ tf[i].osize = sb.st_size; - mtim_get(&sb, &tf[i].omtim); + mtim_get(&sb, tf[i].omtim); /* * The temp file must be created by the sesh helper, * which uses O_EXCL | O_NOFOLLOW to make this safe. @@ -442,12 +444,12 @@ selinux_edit_create_tfiles(struct command_details *command_details, static int selinux_edit_copy_tfiles(struct command_details *command_details, - struct tempfile *tf, int nfiles, struct timeval *times) + struct tempfile *tf, int nfiles, struct timespec *times) { char **sesh_args, **sesh_ap; int i, rc, sesh_nargs, rval = 1; struct command_details saved_command_details; - struct timeval tv; + struct timespec ts; struct stat sb; debug_decl(selinux_edit_copy_tfiles, SUDO_DEBUG_EDIT) @@ -473,13 +475,13 @@ selinux_edit_copy_tfiles(struct command_details *command_details, /* Construct args for sesh -e 1 */ for (i = 0; i < nfiles; i++) { if (stat(tf[i].tfile, &sb) == 0) { - mtim_get(&sb, &tv); - if (tf[i].osize == sb.st_size && sudo_timevalcmp(&tf[i].omtim, &tv, ==)) { + mtim_get(&sb, ts); + if (tf[i].osize == sb.st_size && sudo_timespeccmp(&tf[i].omtim, &ts, ==)) { /* * If mtime and size match but the user spent no measurable * time in the editor we can't tell if the file was changed. */ - if (sudo_timevalcmp(×[0], ×[1], !=)) { + if (sudo_timespeccmp(×[0], ×[1], !=)) { sudo_warnx(U_("%s unchanged"), tf[i].ofile); unlink(tf[i].tfile); continue; @@ -537,7 +539,7 @@ sudo_edit(struct command_details *command_details) char **nargv = NULL, **ap, **files = NULL; int errors, i, ac, nargc, rval; int editor_argc = 0, nfiles = 0; - struct timeval times[2]; + struct timespec times[2]; struct tempfile *tf = NULL; debug_decl(sudo_edit, SUDO_DEBUG_EDIT) @@ -600,7 +602,7 @@ sudo_edit(struct command_details *command_details) * Run the editor with the invoking user's creds, * keeping track of the time spent in the editor. */ - if (gettimeofday(×[0], NULL) == -1) { + if (sudo_gettime_real(×[0]) == -1) { sudo_warn(U_("unable to read the clock")); goto cleanup; } @@ -613,7 +615,7 @@ sudo_edit(struct command_details *command_details) command_details->groups = user_details.groups; command_details->argv = nargv; rval = run_command(command_details); - if (gettimeofday(×[1], NULL) == -1) { + if (sudo_gettime_real(×[1]) == -1) { sudo_warn(U_("unable to read the clock")); goto cleanup; }