diff --git a/MANIFEST b/MANIFEST index c5f3d0696..879e83126 100644 --- a/MANIFEST +++ b/MANIFEST @@ -119,6 +119,7 @@ lib/util/mksigname.c lib/util/mksigname.h lib/util/mktemp.c lib/util/nanosleep.c +lib/util/openat.c lib/util/parseln.c lib/util/pipe2.c lib/util/progname.c @@ -195,6 +196,7 @@ lib/util/sudo_dso.c lib/util/term.c lib/util/ttyname_dev.c lib/util/ttysize.c +lib/util/unlinkat.c lib/util/util.exp.in lib/util/utimens.c lib/util/vsyslog.c diff --git a/config.h.in b/config.h.in index 9e8e14341..b54f8d4f8 100644 --- a/config.h.in +++ b/config.h.in @@ -861,6 +861,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H +/* Define to 1 if you have the `unlinkat' function. */ +#undef HAVE_UNLINKAT + /* Define to 1 if you have the `unsetenv' function. */ #undef HAVE_UNSETENV diff --git a/configure b/configure index 1d8c8cb41..62fd5aa41 100755 --- a/configure +++ b/configure @@ -2881,7 +2881,6 @@ as_fn_append ac_func_list " killpg" as_fn_append ac_func_list " nl_langinfo" as_fn_append ac_func_list " pread" as_fn_append ac_func_list " pwrite" -as_fn_append ac_func_list " openat" as_fn_append ac_func_list " faccessat" as_fn_append ac_func_list " wordexp" as_fn_append ac_func_list " getauxval" @@ -19211,8 +19210,6 @@ done - - case "$host_os" in hpux*) if test X"$ac_cv_func_pread" = X"yes"; then @@ -20444,6 +20441,58 @@ esac fi +fi +done + +for ac_func in openat +do : + ac_fn_c_check_func "$LINENO" "openat" "ac_cv_func_openat" +if test "x$ac_cv_func_openat" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_OPENAT 1 +_ACEOF + +else + + case " $LIBOBJS " in + *" openat.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS openat.$ac_objext" + ;; +esac + + + for _sym in sudo_openat; do + COMPAT_EXP="${COMPAT_EXP}${_sym} +" + done + + +fi +done + +for ac_func in unlinkat +do : + ac_fn_c_check_func "$LINENO" "unlinkat" "ac_cv_func_unlinkat" +if test "x$ac_cv_func_unlinkat" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_UNLINKAT 1 +_ACEOF + +else + + case " $LIBOBJS " in + *" unlinkat.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS unlinkat.$ac_objext" + ;; +esac + + + for _sym in sudo_unlinkat; do + COMPAT_EXP="${COMPAT_EXP}${_sym} +" + done + + fi done diff --git a/configure.ac b/configure.ac index 24f391b71..1752eb1ca 100644 --- a/configure.ac +++ b/configure.ac @@ -2506,7 +2506,7 @@ dnl dnl Function checks dnl AC_FUNC_GETGROUPS -AC_CHECK_FUNCS_ONCE([fexecve killpg nl_langinfo pread pwrite openat faccessat wordexp getauxval]) +AC_CHECK_FUNCS_ONCE([fexecve killpg nl_langinfo pread pwrite faccessat wordexp getauxval]) case "$host_os" in hpux*) if test X"$ac_cv_func_pread" = X"yes"; then @@ -2720,6 +2720,14 @@ AC_CHECK_FUNCS(nanosleep, [], [ SUDO_APPEND_COMPAT_EXP(sudo_nanosleep) ]) ]) +AC_CHECK_FUNCS([openat], [], [ + AC_LIBOBJ(openat) + SUDO_APPEND_COMPAT_EXP(sudo_openat) +]) +AC_CHECK_FUNCS([unlinkat], [], [ + AC_LIBOBJ(unlinkat) + SUDO_APPEND_COMPAT_EXP(sudo_unlinkat) +]) 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 8be6ebcf1..da57c011d 100644 --- a/include/sudo_compat.h +++ b/include/sudo_compat.h @@ -479,7 +479,12 @@ __dso_public int sudo_mkstemps(char *path, int slen); __dso_public int sudo_nanosleep(const struct timespec *timeout, struct timespec *remainder); #undef nanosleep # define nanosleep(_a, _b) sudo_nanosleep((_a), (_b)) -#endif +#endif /* HAVE_NANOSLEEP */ +#ifndef HAVE_OPENAT +__dso_public int sudo_openat(int dfd, const char *path, int flags, mode_t mode); +# undef openat +# define openat(_a, _b, _c, _d) sudo_openat((_a), (_b), (_c), (_d)) +#endif /* HAVE_OPENAT */ #ifndef HAVE_PW_DUP __dso_public struct passwd *sudo_pw_dup(const struct passwd *pw); # undef pw_dup @@ -530,5 +535,10 @@ __dso_public int sudo_pipe2(int fildes[2], int flags); # undef pipe2 # define pipe2(_a, _b) sudo_pipe2((_a), (_b)) #endif /* HAVE_PIPE2 */ +#ifndef HAVE_UNLINKAT +__dso_public int sudo_unlinkat(int dfd, const char *path, int flag); +# undef unlinkat +# define unlinkat(_a, _b, _c) sudo_unlinkat((_a), (_b), (_c)) +#endif /* HAVE_UNLINKAT */ #endif /* SUDO_COMPAT_H */ diff --git a/lib/util/openat.c b/lib/util/openat.c new file mode 100644 index 000000000..a8709fc84 --- /dev/null +++ b/lib/util/openat.c @@ -0,0 +1,65 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2015, 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 "sudo_compat.h" + +#ifndef HAVE_OPENAT +int +sudo_openat(int dfd, const char *path, int flags, mode_t mode) +{ + int fd, odfd; + + if (dfd == AT_FDCWD) + return open(path, flags, mode); + + /* Save cwd */ + if ((odfd = open(".", O_RDONLY)) == -1) + return -1; + + if (fchdir(dfd) == -1) { + close(odfd); + return -1; + } + + fd = open(path, flags, mode); + + /* Restore cwd */ + if (fchdir(odfd) == -1) { + /* Should not happen */ + if (fd != -1) { + close(fd); + fd = -1; + } + } + close(odfd); + + return fd; +} +#endif /* HAVE_OPENAT */ diff --git a/lib/util/unlinkat.c b/lib/util/unlinkat.c new file mode 100644 index 000000000..a86e145dd --- /dev/null +++ b/lib/util/unlinkat.c @@ -0,0 +1,62 @@ +/* + * 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 "sudo_compat.h" + +#ifndef HAVE_UNLINKAT +int +sudo_unlinkat(int dfd, const char *path, int flag) +{ + int odfd, ret; + + if (dfd == AT_FDCWD) + return unlink(path); + + /* Save cwd */ + if ((odfd = open(".", O_RDONLY)) == -1) + return -1; + + if (fchdir(dfd) == -1) { + close(odfd); + return -1; + } + + ret = unlink(path); + + /* Restore cwd */ + if (fchdir(odfd) == -1) { + /* Should not happen */ + ret = -1; + } + close(odfd); + + return ret; +} +#endif /* HAVE_UNLINKAT */ diff --git a/src/sudo_edit.c b/src/sudo_edit.c index 036b2f4e3..b5f00f243 100644 --- a/src/sudo_edit.c +++ b/src/sudo_edit.c @@ -262,37 +262,6 @@ sudo_edit_mktemp(const char *ofile, char **tfile) debug_return_int(tfd); } -#ifndef HAVE_OPENAT -static int -sudo_openat(int dfd, const char *path, int flags, mode_t mode) -{ - int fd, odfd; - debug_decl(sudo_openat, SUDO_DEBUG_EDIT) - - if (dfd == AT_FDCWD) - debug_return_int(open(path, flags, mode)); - - /* Save cwd */ - if ((odfd = open(".", O_RDONLY)) == -1) - debug_return_int(-1); - - if (fchdir(dfd) == -1) { - close(odfd); - debug_return_int(-1); - } - - fd = open(path, flags, mode); - - /* Restore cwd */ - if (fchdir(odfd) == -1) - sudo_fatal(U_("unable to restore current working directory")); - close(odfd); - - debug_return_int(fd); -} -#define openat sudo_openat -#endif /* HAVE_OPENAT */ - #ifdef O_NOFOLLOW static int sudo_edit_openat_nofollow(int dfd, char *path, int oflags, mode_t mode)