mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-30 14:07:59 +00:00
Refactor the privilege dropping
On Linux, the libcap is now mandatory. It makes things simpler for us. System without {set,get}res{uid,gid} now have compatibility shim using setreuid/setregid or seteuid/setegid to setup effective UID/GID, so the same code can be called all the time (including on Linux).
This commit is contained in:
210
bin/named/os.c
210
bin/named/os.c
@@ -63,7 +63,7 @@ static struct passwd *runas_pw = NULL;
|
|||||||
static bool done_setuid = false;
|
static bool done_setuid = false;
|
||||||
static int dfd[2] = { -1, -1 };
|
static int dfd[2] = { -1, -1 };
|
||||||
|
|
||||||
#ifdef HAVE_SYS_CAPABILITY_H
|
#if HAVE_LIBCAP
|
||||||
|
|
||||||
static bool non_root = false;
|
static bool non_root = false;
|
||||||
static bool non_root_caps = 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
|
static void
|
||||||
setup_syslog(const char *progname) {
|
setup_syslog(const char *progname) {
|
||||||
@@ -265,9 +395,9 @@ setup_syslog(const char *progname) {
|
|||||||
void
|
void
|
||||||
named_os_init(const char *progname) {
|
named_os_init(const char *progname) {
|
||||||
setup_syslog(progname);
|
setup_syslog(progname);
|
||||||
#ifdef HAVE_SYS_CAPABILITY_H
|
#if HAVE_LIBCAP
|
||||||
linux_initialprivs();
|
linux_initialprivs();
|
||||||
#endif /* ifdef HAVE_SYS_CAPABILITY_H */
|
#endif /* HAVE_LIBCAP */
|
||||||
#ifdef SIGXFSZ
|
#ifdef SIGXFSZ
|
||||||
signal(SIGXFSZ, SIG_IGN);
|
signal(SIGXFSZ, SIG_IGN);
|
||||||
#endif /* ifdef SIGXFSZ */
|
#endif /* ifdef SIGXFSZ */
|
||||||
@@ -460,7 +590,7 @@ named_os_changeuser(void) {
|
|||||||
named_main_earlyfatal("setuid(): %s", strbuf);
|
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()
|
* Restore the ability of named to drop core after the setuid()
|
||||||
* call has disabled it.
|
* call has disabled it.
|
||||||
@@ -472,7 +602,7 @@ named_os_changeuser(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
linux_minprivs();
|
linux_minprivs();
|
||||||
#endif /* if defined(HAVE_SYS_CAPABILITY_H) */
|
#endif /* HAVE_LIBCAP */
|
||||||
}
|
}
|
||||||
|
|
||||||
uid_t
|
uid_t
|
||||||
@@ -506,11 +636,11 @@ named_os_adjustnofile(void) {
|
|||||||
|
|
||||||
void
|
void
|
||||||
named_os_minprivs(void) {
|
named_os_minprivs(void) {
|
||||||
#if defined(HAVE_SYS_CAPABILITY_H)
|
#if HAVE_LIBCAP
|
||||||
linux_keepcaps();
|
linux_keepcaps();
|
||||||
named_os_changeuser();
|
named_os_changeuser();
|
||||||
linux_minprivs();
|
linux_minprivs();
|
||||||
#endif /* if defined(HAVE_SYS_CAPABILITY_H) */
|
#endif /* HAVE_LIBCAP */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -630,56 +760,6 @@ error:
|
|||||||
return (-1);
|
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 *
|
FILE *
|
||||||
named_os_openfile(const char *filename, mode_t mode, bool switch_user) {
|
named_os_openfile(const char *filename, mode_t mode, bool switch_user) {
|
||||||
char strbuf[ISC_STRERRORSIZE], *f;
|
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) {
|
if (switch_user && runas_pw != NULL) {
|
||||||
uid_t olduid = getuid();
|
uid_t olduid = getuid();
|
||||||
gid_t oldgid = getgid();
|
gid_t oldgid = getgid();
|
||||||
#if HAVE_SYS_CAPABILITY_H
|
|
||||||
REQUIRE(olduid == runas_pw->pw_uid);
|
/*
|
||||||
REQUIRE(oldgid == runas_pw->pw_gid);
|
* Set UID/GID to the one we'll be running with
|
||||||
#else /* HAVE_SYS_CAPABILITY_H */
|
* eventually.
|
||||||
/* Set UID/GID to the one we'll be running with eventually */
|
*/
|
||||||
setperms(runas_pw->pw_uid, runas_pw->pw_gid);
|
setperms(runas_pw->pw_uid, runas_pw->pw_gid);
|
||||||
#endif
|
|
||||||
fd = safe_open(filename, mode, false);
|
fd = safe_open(filename, mode, false);
|
||||||
|
|
||||||
#if !HAVE_SYS_CAPABILITY_H
|
|
||||||
/* Restore UID/GID to previous uid/gid */
|
/* Restore UID/GID to previous uid/gid */
|
||||||
setperms(olduid, oldgid);
|
setperms(olduid, oldgid);
|
||||||
#endif
|
|
||||||
|
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
fd = safe_open(filename, mode, false);
|
fd = safe_open(filename, mode, false);
|
||||||
|
36
configure.ac
36
configure.ac
@@ -351,10 +351,10 @@ AS_CASE([$host],
|
|||||||
AC_CHECK_FUNCS([sysctlbyname])
|
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([setresuid setreuid getresuid])
|
||||||
AC_CHECK_FUNCS([setegid setresgid])
|
AC_CHECK_FUNCS([setresgid setregid getresgid])
|
||||||
|
|
||||||
AC_TYPE_SIZE_T
|
AC_TYPE_SIZE_T
|
||||||
AC_TYPE_SSIZE_T
|
AC_TYPE_SSIZE_T
|
||||||
@@ -1050,32 +1050,10 @@ case "$enable_chroot" in
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
LIBCAP_LIBS=""
|
AS_CASE([$host],
|
||||||
AC_MSG_CHECKING([whether to enable Linux capabilities])
|
[*-linux*],
|
||||||
|
[PKG_CHECK_MODULES([LIBCAP], [libcap],
|
||||||
# [pairwise: --enable-linux-caps, --disable-linux-caps]
|
[AC_DEFINE([HAVE_LIBCAP], [1], [Define to 1 if libcap was found])])])
|
||||||
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])
|
|
||||||
|
|
||||||
case "$host" in
|
case "$host" in
|
||||||
*-solaris*)
|
*-solaris*)
|
||||||
|
Reference in New Issue
Block a user