FS-8195 Compatibility with Solaris 11 process privileges

Now the daemon manages its privileges correctly, so that -rp, -u,
-g and -lp can be supported, also in a Solaris zone.

Also fixed a problem that switch_log_printf() was used before the
logger was initialized, so the messages were sent to nowhere.
This commit is contained in:
Stanislav Sinyagin 2015-09-22 09:01:07 +00:00
parent 2184af8ea6
commit 9461ed1335
4 changed files with 108 additions and 21 deletions

View File

@ -834,6 +834,12 @@ AC_HEADER_DIRENT
AC_HEADER_STDC AC_HEADER_STDC
AC_CHECK_HEADERS([sys/types.h sys/resource.h sched.h wchar.h sys/filio.h sys/ioctl.h sys/prctl.h sys/select.h netdb.h execinfo.h sys/time.h]) AC_CHECK_HEADERS([sys/types.h sys/resource.h sched.h wchar.h sys/filio.h sys/ioctl.h sys/prctl.h sys/select.h netdb.h execinfo.h sys/time.h])
# Solaris 11 privilege management
AS_CASE([$host],
[*-*-solaris2.11], [AC_CHECK_HEADER([priv.h], [AC_DEFINE([SOLARIS_PRIVILEGES],[1],[Solaris 11 privilege management])])]
)
if test x"$ac_cv_header_wchar_h" = xyes; then if test x"$ac_cv_header_wchar_h" = xyes; then
HAVE_WCHAR_H_DEFINE=1 HAVE_WCHAR_H_DEFINE=1
else else

View File

@ -2243,6 +2243,12 @@ SWITCH_DECLARE(switch_core_flag_t) switch_core_flags(void);
*/ */
SWITCH_DECLARE(switch_status_t) switch_core_management_exec(char *relative_oid, switch_management_action_t action, char *data, switch_size_t datalen); SWITCH_DECLARE(switch_status_t) switch_core_management_exec(char *relative_oid, switch_management_action_t action, char *data, switch_size_t datalen);
/*!
\brief Switch on the privilege awareness for the process and request required privileges
\return 0 on success
*/
SWITCH_DECLARE(int32_t) switch_core_set_process_privileges(void);
/*! /*!
\brief Set the maximum priority the process can obtain \brief Set the maximum priority the process can obtain

View File

@ -1089,6 +1089,10 @@ int main(int argc, char *argv[])
reincarnate_protect(reincarnate_reexec ? argv : NULL); reincarnate_protect(reincarnate_reexec ? argv : NULL);
#endif #endif
if (switch_core_set_process_privileges() < 0) {
return 255;
}
switch (priority) { switch (priority) {
case 2: case 2:
set_realtime_priority(); set_realtime_priority();

View File

@ -53,7 +53,9 @@
#ifdef HAVE_SYS_PRCTL_H #ifdef HAVE_SYS_PRCTL_H
#include <sys/prctl.h> #include <sys/prctl.h>
#endif #endif
#ifdef SOLARIS_PRIVILEGES
#include <priv.h>
#endif
SWITCH_DECLARE_DATA switch_directories SWITCH_GLOBAL_dirs = { 0 }; SWITCH_DECLARE_DATA switch_directories SWITCH_GLOBAL_dirs = { 0 };
SWITCH_DECLARE_DATA switch_filenames SWITCH_GLOBAL_filenames = { 0 }; SWITCH_DECLARE_DATA switch_filenames SWITCH_GLOBAL_filenames = { 0 };
@ -888,20 +890,54 @@ SWITCH_DECLARE(void) switch_core_set_globals(void)
} }
SWITCH_DECLARE(int32_t) switch_core_set_process_privileges(void)
{
#ifdef SOLARIS_PRIVILEGES
priv_set_t *basicset;
/* make the process privilege-aware */
setpflags(PRIV_AWARE, 1);
/* reset the privileges to basic */
basicset = priv_str_to_set("basic", ",", NULL);
if (setppriv(PRIV_SET, PRIV_EFFECTIVE, basicset) != 0) {
fprintf(stderr, "ERROR: Failed to acquire basic privileges (%s)\n", strerror(errno));
}
/* we need high-resolution clock, and this requires a non-basic privilege */
if (priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_CLOCK_HIGHRES, NULL) < 0) {
fprintf(stderr, "ERROR: Failed to acquire proc_clock_highres privilege (%s)\n", strerror(errno));
return -1;
}
/* need this for setrlimit */
if (priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_SYS_RESOURCE, NULL) < 0) {
fprintf(stderr, "ERROR: Failed to acquire sys_resource privilege (%s)\n", strerror(errno));
return -1;
}
/* we need to read directories belonging to other uid */
if (priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_SEARCH, NULL) < 0) {
fprintf(stderr, "ERROR: Failed to acquire file_dac_search privilege (%s)\n", strerror(errno));
return -1;
}
#endif
return 0;
}
SWITCH_DECLARE(int32_t) set_low_priority(void) SWITCH_DECLARE(int32_t) set_low_priority(void)
{ {
#ifdef WIN32 #ifdef WIN32
SetPriorityClass(GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS); SetPriorityClass(GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS);
#else #else
#ifdef USE_SCHED_SETSCHEDULER #if defined(USE_SCHED_SETSCHEDULER) && ! defined(SOLARIS_PRIVILEGES)
/* /*
* Try to use a normal scheduler * Try to use a normal scheduler
*/ */
struct sched_param sched = { 0 }; struct sched_param sched = { 0 };
sched.sched_priority = 0; sched.sched_priority = 0;
if (sched_setscheduler(0, SCHED_OTHER, &sched)) { if (sched_setscheduler(0, SCHED_OTHER, &sched) < 0) {
fprintf(stderr, "ERROR: Failed to set SCHED_OTHER scheduler (%s)\n", strerror(errno));
return -1; return -1;
} }
#endif #endif
@ -911,12 +947,12 @@ SWITCH_DECLARE(int32_t) set_low_priority(void)
* setpriority() works on FreeBSD (6.2), nice() doesn't * setpriority() works on FreeBSD (6.2), nice() doesn't
*/ */
if (setpriority(PRIO_PROCESS, getpid(), 19) < 0) { if (setpriority(PRIO_PROCESS, getpid(), 19) < 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not set nice level\n"); fprintf(stderr, "ERROR: Could not set nice level\n");
return -1; return -1;
} }
#else #else
if (nice(19) != 19) { if (nice(19) != 19) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not set nice level\n"); fprintf(stderr, "ERROR: Could not set nice level\n");
return -1; return -1;
} }
#endif #endif
@ -937,32 +973,60 @@ SWITCH_DECLARE(int32_t) set_realtime_priority(void)
*/ */
struct sched_param sched = { 0 }; struct sched_param sched = { 0 };
sched.sched_priority = SWITCH_PRI_LOW; sched.sched_priority = SWITCH_PRI_LOW;
if (sched_setscheduler(0, SCHED_FIFO, &sched)) { #endif
#ifdef SOLARIS_PRIVILEGES
/* request the privileges to elevate the priority */
if (priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_PRIOCNTL, NULL) < 0) {
fprintf(stderr, "WARN: Failed to acquire proc_priocntl privilege (%s)\n", strerror(errno));
} else {
if (sched_setscheduler(0, SCHED_FIFO, &sched) < 0) {
fprintf(stderr, "ERROR: Failed to set SCHED_FIFO scheduler (%s)\n", strerror(errno));
} else {
return 0;
}
}
if (priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_PRIOUP, NULL) < 0) {
fprintf(stderr, "ERROR: Failed to acquire proc_prioup privilege (%s)\n", strerror(errno));
return -1;
} else {
if (setpriority(PRIO_PROCESS, 0, -10) < 0) {
fprintf(stderr, "ERROR: Could not set nice level\n");
return -1;
}
}
return 0;
#else
#ifdef USE_SCHED_SETSCHEDULER
if (sched_setscheduler(0, SCHED_FIFO, &sched) < 0) {
fprintf(stderr, "ERROR: Failed to set SCHED_FIFO scheduler (%s)\n", strerror(errno));
sched.sched_priority = 0; sched.sched_priority = 0;
if (sched_setscheduler(0, SCHED_OTHER, &sched)) { if (sched_setscheduler(0, SCHED_OTHER, &sched) < 0 ) {
fprintf(stderr, "ERROR: Failed to set SCHED_OTHER scheduler (%s)\n", strerror(errno));
return -1; return -1;
} }
} }
#endif #endif
#ifdef HAVE_SETPRIORITY #ifdef HAVE_SETPRIORITY
/* /*
* setpriority() works on FreeBSD (6.2), nice() doesn't * setpriority() works on FreeBSD (6.2), nice() doesn't
*/ */
if (setpriority(PRIO_PROCESS, getpid(), -10) < 0) { if (setpriority(PRIO_PROCESS, getpid(), -10) < 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not set nice level\n"); fprintf(stderr, "ERROR: Could not set nice level\n");
return -1; return -1;
} }
#else #else
if (nice(-10) != -10) { if (nice(-10) != -10) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not set nice level\n"); fprintf(stderr, "ERROR: Could not set nice level\n");
return -1; return -1;
} }
#endif #endif
#endif #endif
return 0; return 0;
#endif
} }
SWITCH_DECLARE(uint32_t) switch_core_cpu_count(void) SWITCH_DECLARE(uint32_t) switch_core_cpu_count(void)
@ -1006,7 +1070,7 @@ SWITCH_DECLARE(int32_t) change_user_group(const char *user, const char *group)
*/ */
runas_pw = getpwnam(user); runas_pw = getpwnam(user);
if (!runas_pw) { if (!runas_pw) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unknown user \"%s\"\n", user); fprintf(stderr, "ERROR: Unknown user \"%s\"\n", user);
return -1; return -1;
} }
runas_uid = runas_pw->pw_uid; runas_uid = runas_pw->pw_uid;
@ -1020,7 +1084,7 @@ SWITCH_DECLARE(int32_t) change_user_group(const char *user, const char *group)
*/ */
gr = getgrnam(group); gr = getgrnam(group);
if (!gr) { if (!gr) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unknown group \"%s\"\n", group); fprintf(stderr, "ERROR: Unknown group \"%s\"\n", group);
return -1; return -1;
} }
runas_gid = gr->gr_gid; runas_gid = gr->gr_gid;
@ -1032,6 +1096,13 @@ SWITCH_DECLARE(int32_t) change_user_group(const char *user, const char *group)
} }
if (runas_uid) { if (runas_uid) {
#ifdef SOLARIS_PRIVILEGES
/* request the privilege to set the UID */
if (priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_SETID, NULL) < 0) {
fprintf(stderr, "ERROR: Failed to acquire proc_setid privilege (%s)\n", strerror(errno));
return -1;
}
#endif
#ifdef HAVE_SETGROUPS #ifdef HAVE_SETGROUPS
/* /*
* Drop all group memberships prior to changing anything * Drop all group memberships prior to changing anything
@ -1039,7 +1110,7 @@ SWITCH_DECLARE(int32_t) change_user_group(const char *user, const char *group)
* (which is not what we want...) * (which is not what we want...)
*/ */
if (setgroups(0, NULL) < 0) { if (setgroups(0, NULL) < 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to drop group access list\n"); fprintf(stderr, "ERROR: Failed to drop group access list\n");
return -1; return -1;
} }
#endif #endif
@ -1049,7 +1120,7 @@ SWITCH_DECLARE(int32_t) change_user_group(const char *user, const char *group)
* (without loading the user's other groups) * (without loading the user's other groups)
*/ */
if (setgid(runas_gid) < 0) { if (setgid(runas_gid) < 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to change gid!\n"); fprintf(stderr, "ERROR: Failed to change gid!\n");
return -1; return -1;
} }
} else { } else {
@ -1057,7 +1128,7 @@ SWITCH_DECLARE(int32_t) change_user_group(const char *user, const char *group)
* No group has been passed, use the user's primary group in this case * No group has been passed, use the user's primary group in this case
*/ */
if (setgid(runas_pw->pw_gid) < 0) { if (setgid(runas_pw->pw_gid) < 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to change gid!\n"); fprintf(stderr, "ERROR: Failed to change gid!\n");
return -1; return -1;
} }
#ifdef HAVE_INITGROUPS #ifdef HAVE_INITGROUPS
@ -1066,7 +1137,7 @@ SWITCH_DECLARE(int32_t) change_user_group(const char *user, const char *group)
* (This can be really useful for fine-grained access control) * (This can be really useful for fine-grained access control)
*/ */
if (initgroups(runas_pw->pw_name, runas_pw->pw_gid) < 0) { if (initgroups(runas_pw->pw_name, runas_pw->pw_gid) < 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to set group access list for user\n"); fprintf(stderr, "ERROR: Failed to set group access list for user\n");
return -1; return -1;
} }
#endif #endif
@ -1076,12 +1147,12 @@ SWITCH_DECLARE(int32_t) change_user_group(const char *user, const char *group)
* Finally drop all privileges by switching to the new userid * Finally drop all privileges by switching to the new userid
*/ */
if (setuid(runas_uid) < 0) { if (setuid(runas_uid) < 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to change uid!\n"); fprintf(stderr, "ERROR: Failed to change uid!\n");
return -1; return -1;
} }
#ifdef HAVE_SYS_PRCTL_H #ifdef HAVE_SYS_PRCTL_H
if (prctl(PR_SET_DUMPABLE, 1) < 0) { if (prctl(PR_SET_DUMPABLE, 1) < 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to enable core dumps!\n"); fprintf(stderr, "ERROR: Failed to enable core dumps!\n");
return -1; return -1;
} }
#endif #endif