diff --git a/MANIFEST b/MANIFEST index 337ef58df..eee807803 100644 --- a/MANIFEST +++ b/MANIFEST @@ -111,7 +111,9 @@ lib/util/event.c lib/util/event_poll.c lib/util/event_select.c lib/util/fatal.c +lib/util/fchmodat.c lib/util/fnmatch.c +lib/util/fstatat.c lib/util/getaddrinfo.c lib/util/getcwd.c lib/util/getdelim.c diff --git a/config.h.in b/config.h.in index b54f8d4f8..06acdcae5 100644 --- a/config.h.in +++ b/config.h.in @@ -242,6 +242,9 @@ /* Define to 1 if you have the `faccessat' function. */ #undef HAVE_FACCESSAT +/* Define to 1 if you have the `fchmodat' function. */ +#undef HAVE_FCHMODAT + /* Define to 1 if your system has the F_CLOSEM fcntl. */ #undef HAVE_FCNTL_CLOSEM @@ -257,6 +260,9 @@ /* Define to 1 if you have the `fseeko' function. */ #undef HAVE_FSEEKO +/* Define to 1 if you have the `fstatat' function. */ +#undef HAVE_FSTATAT + /* Define to 1 if you have the `futime' function. */ #undef HAVE_FUTIME diff --git a/configure b/configure index 0f877228d..c9b2c8ddb 100755 --- a/configure +++ b/configure @@ -20508,6 +20508,58 @@ esac done +fi +done + +for ac_func in fchmodat +do : + ac_fn_c_check_func "$LINENO" "fchmodat" "ac_cv_func_fchmodat" +if test "x$ac_cv_func_fchmodat" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FCHMODAT 1 +_ACEOF + +else + + case " $LIBOBJS " in + *" fchmodat.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS fchmodat.$ac_objext" + ;; +esac + + + for _sym in sudo_fchmodat; do + COMPAT_EXP="${COMPAT_EXP}${_sym} +" + done + + +fi +done + +for ac_func in fstatat +do : + ac_fn_c_check_func "$LINENO" "fstatat" "ac_cv_func_fstatat" +if test "x$ac_cv_func_fstatat" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FSTATAT 1 +_ACEOF + +else + + case " $LIBOBJS " in + *" fstatat.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS fstatat.$ac_objext" + ;; +esac + + + for _sym in sudo_fstatat; do + COMPAT_EXP="${COMPAT_EXP}${_sym} +" + done + + fi done diff --git a/configure.ac b/configure.ac index cb0f14db7..7c83bedd2 100644 --- a/configure.ac +++ b/configure.ac @@ -2732,6 +2732,14 @@ AC_CHECK_FUNCS([unlinkat], [], [ AC_LIBOBJ(unlinkat) SUDO_APPEND_COMPAT_EXP(sudo_unlinkat) ]) +AC_CHECK_FUNCS([fchmodat], [], [ + AC_LIBOBJ(fchmodat) + SUDO_APPEND_COMPAT_EXP(sudo_fchmodat) +]) +AC_CHECK_FUNCS([fstatat], [], [ + AC_LIBOBJ(fstatat) + SUDO_APPEND_COMPAT_EXP(sudo_fstatat) +]) AC_CHECK_FUNCS([pipe2], [], [ AC_LIBOBJ(pipe2) SUDO_APPEND_COMPAT_EXP(sudo_pipe2) diff --git a/include/sudo_compat.h b/include/sudo_compat.h index da57c011d..9e07543d2 100644 --- a/include/sudo_compat.h +++ b/include/sudo_compat.h @@ -212,9 +212,12 @@ # define UTIME_NOW -2L # endif #endif -#if !defined(HAVE_OPENAT) || (!defined(HAVE_FUTIMENS) && !defined(HAVE_UTIMENSAT)) +#if !defined(HAVE_OPENAT) || (!defined(HAVE_FUTIMENS) && !defined(HAVE_UTIMENSAT)) || !defined(HAVE_FCHMODAT) || !defined(HAVE_FSTATAT) || !defined(HAVE_UNLINKAT) # ifndef AT_FDCWD -# define AT_FDCWD -100 +# define AT_FDCWD -100 +# endif +# ifndef AT_SYMLINK_NOFOLLOW +# define AT_SYMLINK_NOFOLLOW 0x02 # endif #endif @@ -385,6 +388,7 @@ int getdomainname(char *, size_t); */ struct passwd; +struct stat; struct timespec; #ifndef HAVE_CLOSEFROM @@ -412,6 +416,16 @@ __dso_public int sudo_utimensat(int fd, const char *file, const struct timespec # undef utimensat # define utimensat(_a, _b, _c, _d) sudo_utimensat((_a), (_b), (_c), (_d)) #endif /* HAVE_UTIMENSAT */ +#ifndef HAVE_FCHMODAT +__dso_public int sudo_fchmodat(int dfd, const char *path, mode_t mode, int flag); +# undef fchmodat +# define fchmodat(_a, _b, _c, _d) sudo_fchmodat((_a), (_b), (_c), (_d)) +#endif /* HAVE_FCHMODAT */ +#ifndef HAVE_FSTATAT +__dso_public int sudo_fstatat(int dfd, const char *path, struct stat *sb, int flag); +# undef fstatat +# define fstatat(_a, _b, _c, _d) sudo_fstatat((_a), (_b), (_c), (_d)) +#endif /* HAVE_FSTATAT */ #ifndef HAVE_FUTIMENS __dso_public int sudo_futimens(int fd, const struct timespec *times); # undef futimens diff --git a/lib/util/Makefile.in b/lib/util/Makefile.in index f7612ea2b..e9bc0872e 100644 --- a/lib/util/Makefile.in +++ b/lib/util/Makefile.in @@ -562,6 +562,14 @@ fatal.i: $(srcdir)/fatal.c $(incdir)/compat/getaddrinfo.h \ $(CC) -E -o $@ $(CPPFLAGS) $< fatal.plog: fatal.i rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/fatal.c --i-file $< --output-file $@ +fchmodat.lo: $(srcdir)/fchmodat.c $(incdir)/sudo_compat.h \ + $(top_builddir)/config.h + $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/fchmodat.c +fchmodat.i: $(srcdir)/fchmodat.c $(incdir)/sudo_compat.h \ + $(top_builddir)/config.h + $(CC) -E -o $@ $(CPPFLAGS) $< +fchmodat.plog: fchmodat.i + rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/fchmodat.c --i-file $< --output-file $@ fnm_test.lo: $(srcdir)/regress/fnmatch/fnm_test.c $(incdir)/compat/fnmatch.h \ $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \ $(incdir)/sudo_util.h $(top_builddir)/config.h @@ -582,6 +590,12 @@ fnmatch.i: $(srcdir)/fnmatch.c $(incdir)/compat/charclass.h \ $(CC) -E -o $@ $(CPPFLAGS) $< fnmatch.plog: fnmatch.i rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/fnmatch.c --i-file $< --output-file $@ +fstatat.lo: $(srcdir)/fstatat.c $(incdir)/sudo_compat.h $(top_builddir)/config.h + $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/fstatat.c +fstatat.i: $(srcdir)/fstatat.c $(incdir)/sudo_compat.h $(top_builddir)/config.h + $(CC) -E -o $@ $(CPPFLAGS) $< +fstatat.plog: fstatat.i + rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/fstatat.c --i-file $< --output-file $@ getaddrinfo.lo: $(srcdir)/getaddrinfo.c $(incdir)/compat/getaddrinfo.h \ $(incdir)/sudo_compat.h $(top_builddir)/config.h $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/getaddrinfo.c @@ -866,6 +880,12 @@ nanosleep.i: $(srcdir)/nanosleep.c $(incdir)/compat/stdbool.h \ $(CC) -E -o $@ $(CPPFLAGS) $< nanosleep.plog: nanosleep.i rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/nanosleep.c --i-file $< --output-file $@ +openat.lo: $(srcdir)/openat.c $(incdir)/sudo_compat.h $(top_builddir)/config.h + $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/openat.c +openat.i: $(srcdir)/openat.c $(incdir)/sudo_compat.h $(top_builddir)/config.h + $(CC) -E -o $@ $(CPPFLAGS) $< +openat.plog: openat.i + rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/openat.c --i-file $< --output-file $@ parse_gids_test.lo: $(srcdir)/regress/parse_gids/parse_gids_test.c \ $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \ $(incdir)/sudo_fatal.h $(incdir)/sudo_util.h \ @@ -1246,6 +1266,14 @@ ttysize.i: $(srcdir)/ttysize.c $(incdir)/compat/stdbool.h \ $(CC) -E -o $@ $(CPPFLAGS) $< ttysize.plog: ttysize.i rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/ttysize.c --i-file $< --output-file $@ +unlinkat.lo: $(srcdir)/unlinkat.c $(incdir)/sudo_compat.h \ + $(top_builddir)/config.h + $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/unlinkat.c +unlinkat.i: $(srcdir)/unlinkat.c $(incdir)/sudo_compat.h \ + $(top_builddir)/config.h + $(CC) -E -o $@ $(CPPFLAGS) $< +unlinkat.plog: unlinkat.i + rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/unlinkat.c --i-file $< --output-file $@ utimens.lo: $(srcdir)/utimens.c $(incdir)/compat/stdbool.h \ $(incdir)/sudo_compat.h $(incdir)/sudo_util.h \ $(top_builddir)/config.h diff --git a/lib/util/fchmodat.c b/lib/util/fchmodat.c new file mode 100644 index 000000000..8b4c44e29 --- /dev/null +++ b/lib/util/fchmodat.c @@ -0,0 +1,71 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2019 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. + */ + +/* + * This is an open source non-commercial project. Dear PVS-Studio, please check it. + * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + */ + +#include + +#include + +#include +#include +#include +#include +#include + +#include "sudo_compat.h" + +#ifndef HAVE_FCHMODAT +int +sudo_fchmodat(int dfd, const char *path, mode_t mode, int flag) +{ + int odfd, ret = -1; + + if (ISSET(flag, AT_SYMLINK_NOFOLLOW)) { + errno = ENOTSUP; + return -1; + } + + if (dfd == (int)AT_FDCWD) + return chmod(path, mode); + + /* Save cwd */ + if ((odfd = open(".", O_RDONLY)) == -1) + goto done; + + if (fchdir(dfd) == -1) + goto done; + + ret = chmod(path, mode); + + /* Restore cwd */ + if (fchdir(odfd) == -1) { + /* Should not happen */ + ret = -1; + } + +done: + if (odfd != -1) + close(odfd); + + return ret; +} +#endif /* HAVE_FCHMODAT */ diff --git a/lib/util/fstatat.c b/lib/util/fstatat.c new file mode 100644 index 000000000..36e02b625 --- /dev/null +++ b/lib/util/fstatat.c @@ -0,0 +1,72 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2019 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. + */ + +/* + * This is an open source non-commercial project. Dear PVS-Studio, please check it. + * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + */ + +#include + +#include + +#include +#include +#include +#include + +#include "sudo_compat.h" + +#ifndef HAVE_FSTATAT +int +sudo_fstatat(int dfd, const char *path, struct stat *sb, int flag) +{ + int odfd, ret = -1; + + if (dfd == (int)AT_FDCWD) { + if (ISSET(flag, AT_SYMLINK_NOFOLLOW)) + return lstat(path, sb); + else + return stat(path, sb); + } + + /* Save cwd */ + if ((odfd = open(".", O_RDONLY)) == -1) + goto done; + + if (fchdir(dfd) == -1) + goto done; + + if (ISSET(flag, AT_SYMLINK_NOFOLLOW)) + ret = lstat(path, sb); + else + ret = stat(path, sb); + + /* Restore cwd */ + if (fchdir(odfd) == -1) { + /* Should not happen */ + ret = -1; + } + +done: + if (odfd != -1) + close(odfd); + + return ret; +} +#endif /* HAVE_FSTATAT */ diff --git a/mkdep.pl b/mkdep.pl index 9f5c073cd..cfe5a2f9e 100755 --- a/mkdep.pl +++ b/mkdep.pl @@ -116,7 +116,7 @@ sub mkdep { # 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:\@DIGEST\@:digest.lo digest_openssl.lo digest_gcrypt.lo:; - $makefile =~ s:\@LTLIBOBJS\@:arc4random.lo arc4random_uniform.lo closefrom.lo fnmatch.lo getaddrinfo.lo getcwd.lo getentropy.lo getgrouplist.lo getdelim.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 nanosleep.lo pw_dup.lo reallocarray.lo sha2.lo sig2str.lo siglist.lo signame.lo snprintf.lo str2sig.lo strlcat.lo strlcpy.lo strndup.lo strnlen.lo strsignal.lo utimens.lo vsyslog.lo pipe2.lo:; + $makefile =~ s:\@LTLIBOBJS\@:arc4random.lo arc4random_uniform.lo closefrom.lo fchmodat.lo fstatat.lo fnmatch.lo getaddrinfo.lo getcwd.lo getentropy.lo getgrouplist.lo getdelim.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 nanosleep.lo openat.lo pipe2.lo pw_dup.lo reallocarray.lo sha2.lo sig2str.lo siglist.lo signame.lo snprintf.lo str2sig.lo strlcat.lo strlcpy.lo strndup.lo strnlen.lo strsignal.lo unlinkat.lo utimens.lo vsyslog.lo:; # Parse OBJS lines my %objs;