diff --git a/bin/named/os.c b/bin/named/os.c index e984b4b6d4..56792190d6 100644 --- a/bin/named/os.c +++ b/bin/named/os.c @@ -63,7 +63,7 @@ static struct passwd *runas_pw = NULL; static bool done_setuid = false; static int dfd[2] = { -1, -1 }; -#ifdef HAVE_SYS_CAPABILITY_H +#if HAVE_LIBCAP static bool non_root = false; static bool non_root_caps = false; @@ -249,7 +249,137 @@ linux_keepcaps(void) { } } -#endif /* HAVE_SYS_CAPABILITY_H */ +#endif /* HAVE_LIBCAP */ + +/* + * First define compatibility shims if {set,get}res{uid,gid} are not available + */ + +#if !HAVE_GETRESGID +static int +getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid) { + *rgid = -1; + *egid = getegid(); + *sgid = -1; + + return (0); +} +#endif /* !HAVE_GETRESGID */ + +#if !HAVE_SETRESGID +static int +setresgid(gid_t rgid, gid_t egid, gid_t sgid) { + REQUIRE(rgid == -1); + REQUIRE(sgid == -1); + +#if HAVE_SETREGID + return (setregid(rgid, egid)); +#else /* HAVE_SETREGID */ + return (setegid(egid)); +#endif /* HAVE_SETREGID */ +} +#endif /* !HAVE_SETRESGID */ + +#if !HAVE_GETRESUID +static int +getresuid(uid_t *ruid, uid_t *euid, uid_t *suid) { + *rgid = -1; + *egid = geteuid(); + *sgid = -1; + + return (0); +} +#endif /* !HAVE_GETRESUID */ + +#if !HAVE_SETRESUID +static int +setresuid(uid_t ruid, uid_t euid, uid_t suid) { + REQUIRE(rgid == -1); + REQUIRE(sgid == -1); + +#if HAVE_SETREGID + return (setregid(rgid, egid)); +#else /* HAVE_SETREGID */ + return (setegid(egid)); +#endif /* HAVE_SETREGID */ +} +#endif /* !HAVE_SETRESUID */ + +static int +set_effective_gid(gid_t gid) { + gid_t oldgid; + + if (getresgid(&(gid_t){ 0 }, &oldgid, &(gid_t){ 0 }) == -1) { + return (-1); + } + + if (oldgid == gid) { + return (0); + } + + if (setresgid(-1, gid, -1) == -1) { + return (-1); + } + + if (getresgid(&(gid_t){ 0 }, &oldgid, &(gid_t){ 0 }) == -1) { + return (-1); + } + + if (oldgid != gid) { + return (-1); + } + + return (0); +} + +static int +set_effective_uid(uid_t uid) { + uid_t olduid; + + if (getresuid(&(uid_t){ 0 }, &olduid, &(uid_t){ 0 }) == -1) { + return (-1); + } + + if (olduid == uid) { + return (0); + } + + if (setresuid(-1, uid, -1) == -1) { + return (-1); + } + + if (getresuid(&(uid_t){ 0 }, &olduid, &(uid_t){ 0 }) == -1) { + return (-1); + } + + if (olduid != uid) { + return (-1); + } + + /* Success */ + return (0); +} + +static void +setperms(uid_t uid, gid_t gid) { + char strbuf[ISC_STRERRORSIZE]; + + /* + * Drop the gid privilege first, because in some cases the gid privilege + * cannot be dropped after the uid privilege has been dropped. + */ + if (set_effective_gid(gid) == -1) { + strerror_r(errno, strbuf, sizeof(strbuf)); + named_main_earlywarning("unable to set effective gid to %d: %s", + gid, strbuf); + } + + if (set_effective_uid(uid) == -1) { + strerror_r(errno, strbuf, sizeof(strbuf)); + named_main_earlywarning("unable to set effective uid to %d: %s", + uid, strbuf); + } +} static void setup_syslog(const char *progname) { @@ -265,9 +395,9 @@ setup_syslog(const char *progname) { void named_os_init(const char *progname) { setup_syslog(progname); -#ifdef HAVE_SYS_CAPABILITY_H +#if HAVE_LIBCAP linux_initialprivs(); -#endif /* ifdef HAVE_SYS_CAPABILITY_H */ +#endif /* HAVE_LIBCAP */ #ifdef SIGXFSZ signal(SIGXFSZ, SIG_IGN); #endif /* ifdef SIGXFSZ */ @@ -460,7 +590,7 @@ named_os_changeuser(void) { named_main_earlyfatal("setuid(): %s", strbuf); } -#if defined(HAVE_SYS_CAPABILITY_H) +#if HAVE_LIBCAP /* * Restore the ability of named to drop core after the setuid() * call has disabled it. @@ -472,7 +602,7 @@ named_os_changeuser(void) { } linux_minprivs(); -#endif /* if defined(HAVE_SYS_CAPABILITY_H) */ +#endif /* HAVE_LIBCAP */ } uid_t @@ -506,11 +636,11 @@ named_os_adjustnofile(void) { void named_os_minprivs(void) { -#if defined(HAVE_SYS_CAPABILITY_H) +#if HAVE_LIBCAP linux_keepcaps(); named_os_changeuser(); linux_minprivs(); -#endif /* if defined(HAVE_SYS_CAPABILITY_H) */ +#endif /* HAVE_LIBCAP */ } static int @@ -630,56 +760,6 @@ error: return (-1); } -#if !HAVE_SYS_CAPABILITY_H -static void -setperms(uid_t uid, gid_t gid) { -#if defined(HAVE_SETEGID) || defined(HAVE_SETRESGID) - char strbuf[ISC_STRERRORSIZE]; -#endif /* if defined(HAVE_SETEGID) || defined(HAVE_SETRESGID) */ -#if !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID) - gid_t oldgid, tmpg; -#endif /* if !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID) */ -#if !defined(HAVE_SETEUID) && defined(HAVE_SETRESUID) - uid_t olduid, tmpu; -#endif /* if !defined(HAVE_SETEUID) && defined(HAVE_SETRESUID) */ -#if defined(HAVE_SETEGID) - if (getegid() != gid && setegid(gid) == -1) { - strerror_r(errno, strbuf, sizeof(strbuf)); - named_main_earlywarning("unable to set effective " - "gid to %ld: %s", - (long)gid, strbuf); - } -#elif defined(HAVE_SETRESGID) - if (getresgid(&tmpg, &oldgid, &tmpg) == -1 || oldgid != gid) { - if (setresgid(-1, gid, -1) == -1) { - strerror_r(errno, strbuf, sizeof(strbuf)); - named_main_earlywarning("unable to set effective " - "gid to %d: %s", - gid, strbuf); - } - } -#endif /* if defined(HAVE_SETEGID) */ - -#if defined(HAVE_SETEUID) - if (geteuid() != uid && seteuid(uid) == -1) { - strerror_r(errno, strbuf, sizeof(strbuf)); - named_main_earlywarning("unable to set effective " - "uid to %ld: %s", - (long)uid, strbuf); - } -#elif defined(HAVE_SETRESUID) - if (getresuid(&tmpu, &olduid, &tmpu) == -1 || olduid != uid) { - if (setresuid(-1, uid, -1) == -1) { - strerror_r(errno, strbuf, sizeof(strbuf)); - named_main_earlywarning("unable to set effective " - "uid to %d: %s", - uid, strbuf); - } - } -#endif /* if defined(HAVE_SETEUID) */ -} -#endif /* !HAVE_SYS_CAPABILITY_H */ - FILE * named_os_openfile(const char *filename, mode_t mode, bool switch_user) { char strbuf[ISC_STRERRORSIZE], *f; @@ -705,19 +785,17 @@ named_os_openfile(const char *filename, mode_t mode, bool switch_user) { if (switch_user && runas_pw != NULL) { uid_t olduid = getuid(); gid_t oldgid = getgid(); -#if HAVE_SYS_CAPABILITY_H - REQUIRE(olduid == runas_pw->pw_uid); - REQUIRE(oldgid == runas_pw->pw_gid); -#else /* HAVE_SYS_CAPABILITY_H */ - /* Set UID/GID to the one we'll be running with eventually */ + + /* + * Set UID/GID to the one we'll be running with + * eventually. + */ setperms(runas_pw->pw_uid, runas_pw->pw_gid); -#endif + fd = safe_open(filename, mode, false); -#if !HAVE_SYS_CAPABILITY_H /* Restore UID/GID to previous uid/gid */ setperms(olduid, oldgid); -#endif if (fd == -1) { fd = safe_open(filename, mode, false); diff --git a/configure.ac b/configure.ac index 63b907cca7..2f36c47adc 100644 --- a/configure.ac +++ b/configure.ac @@ -351,10 +351,10 @@ AS_CASE([$host], AC_CHECK_FUNCS([sysctlbyname]) # -# Older versions of HP/UX don't define seteuid() and setegid() +# Check for uid/gid setting variants # -AC_CHECK_FUNCS([seteuid setresuid]) -AC_CHECK_FUNCS([setegid setresgid]) +AC_CHECK_FUNCS([setresuid setreuid getresuid]) +AC_CHECK_FUNCS([setresgid setregid getresgid]) AC_TYPE_SIZE_T AC_TYPE_SSIZE_T @@ -1050,32 +1050,10 @@ case "$enable_chroot" in ;; esac -LIBCAP_LIBS="" -AC_MSG_CHECKING([whether to enable Linux capabilities]) - -# [pairwise: --enable-linux-caps, --disable-linux-caps] -AC_ARG_ENABLE([linux-caps], - [AS_HELP_STRING([--disable-linux-caps], - [disable Linux capabilities])], - [], - [AS_CASE([$host], - [*-linux*],[enable_linux_caps=yes], - [enable_linux_caps=no])]) - -AS_IF([test "$enable_linux_caps" = "yes"], - [AC_MSG_RESULT([yes]) - AC_CHECK_HEADERS([sys/capability.h], - [], - [AC_MSG_ERROR(m4_normalize([sys/capability.h header is required for Linux capabilities support. - Either install libcap or use --disable-linux-caps.]))]) - AX_SAVE_FLAGS([cap]) - AC_SEARCH_LIBS([cap_set_proc], [cap], - [LIBCAP_LIBS="$ac_cv_search_cap_set_proc"], - [AC_MSG_ERROR(m4_normalize([libcap is required for Linux capabilities support. - Either install libcap or use --disable-linux-caps.]))]) - AX_RESTORE_FLAGS([cap])], - [AC_MSG_RESULT([no])]) -AC_SUBST([LIBCAP_LIBS]) +AS_CASE([$host], + [*-linux*], + [PKG_CHECK_MODULES([LIBCAP], [libcap], + [AC_DEFINE([HAVE_LIBCAP], [1], [Define to 1 if libcap was found])])]) case "$host" in *-solaris*)