add -u and -g command line args to set user and group.
properly handle portability for mlockall and setrlimit Tested on linux, Freebsd, solaris, mac. FSCORE-47 git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@6033 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
parent
20380ea307
commit
b382c0a41f
55
configure.in
55
configure.in
|
@ -170,7 +170,7 @@ AC_SUBST(DYNAMIC_LIB_EXTEN)
|
|||
# Checks for header files.
|
||||
AC_HEADER_DIRENT
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS([sys/types.h])
|
||||
AC_CHECK_HEADERS([sys/types.h sys/resource.h sched.h])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
|
@ -185,6 +185,59 @@ AC_FUNC_MALLOC
|
|||
AC_TYPE_SIGNAL
|
||||
AC_FUNC_STRFTIME
|
||||
AC_CHECK_FUNCS([gethostname vasprintf mmap mlock mlockall usleep])
|
||||
AC_CHECK_FUNCS([sched_setscheduler setpriority setrlimit setgroups initgroups])
|
||||
|
||||
AC_CHECK_DECL([RLIMIT_MEMLOCK],
|
||||
[AC_DEFINE([HAVE_RLIMIT_MEMLOCK],[1],[RLIMIT_MEMLOCK constant for setrlimit])],,
|
||||
[#ifdef HAVE_SYS_RESOURCE_H
|
||||
#include <sys/resource.h>
|
||||
#endif])
|
||||
|
||||
AC_CHECK_DECL([SCHED_RR],
|
||||
[AC_DEFINE([HAVE_SCHED_RR],[1],[SCHED_RR constant for sched_setscheduler])],,
|
||||
[#ifdef HAVE_SCHED_H
|
||||
#include <sched.h>
|
||||
#endif])
|
||||
|
||||
#
|
||||
# use mlockall only on linux (for now; if available)
|
||||
#
|
||||
if test "x${ac_cv_func_mlockall}" = "xyes"; then
|
||||
AC_MSG_CHECKING([whether to use mlockall])
|
||||
case "$host" in
|
||||
*-linux-*)
|
||||
AC_DEFINE([USE_MLOCKALL],[1],[Enable mlockall support])
|
||||
AC_MSG_RESULT([yes])
|
||||
USE_MLOCKALL=yes
|
||||
;;
|
||||
*-freebsd*)
|
||||
AC_MSG_RESULT([no, broken for non-root users])
|
||||
;;
|
||||
*)
|
||||
AC_MSG_RESULT([no])
|
||||
;;
|
||||
esac
|
||||
|
||||
#
|
||||
# setrlimit prerequisites
|
||||
#
|
||||
if test "x${USE_MLOCKALL}" = "xyes" -a \
|
||||
"x${ac_cv_func_setrlimit}" = "xyes" -a \
|
||||
"x${ac_cv_have_decl_RLIMIT_MEMLOCK}" = "xyes"
|
||||
then
|
||||
AC_DEFINE([USE_SETRLIMIT],[1],[Use setrlimit to disable mlock limit for non-root users])
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# sched_setcheduler + round-robin scheduler prerequisites
|
||||
#
|
||||
if test "x${ac_cv_func_sched_setscheduler}" = "xyes" -a \
|
||||
"x${ac_cv_have_decl_SCHED_RR}" = "xyes"
|
||||
then
|
||||
AC_DEFINE([USE_SCHED_SETSCHEDULER],[1],[Enable round-robin scheduler using sched_setscheduler])
|
||||
fi
|
||||
|
||||
|
||||
AC_C_BIGENDIAN(AC_DEFINE([SWITCH_BYTE_ORDER],__BIG_ENDIAN,[Big Endian]),AC_DEFINE([SWITCH_BYTE_ORDER],__LITTLE_ENDIAN,[Little Endian]))
|
||||
|
||||
|
|
|
@ -60,6 +60,19 @@ typedef apr_os_thread_t switch_thread_id_t;
|
|||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
/* setuid, setgid */
|
||||
#include <unistd.h>
|
||||
|
||||
/* getgrnam, getpwnam */
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#ifdef HAVE_SYS_RESOURCE_H
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* #define DEBUG_ALLOC */
|
||||
#define DO_EVENTS
|
||||
|
||||
|
|
|
@ -1413,6 +1413,18 @@ SWITCH_DECLARE(switch_status_t) switch_core_management_exec(char *relative_oid,
|
|||
*/
|
||||
SWITCH_DECLARE(int32_t) set_high_priority(void);
|
||||
|
||||
/*!
|
||||
\brief Change user and/or group of the running process
|
||||
\long Several possible combinations:
|
||||
- user only (group NULL): switch to user and his primary group (and supplementary groups, if supported)
|
||||
- user and group: switch to user and specified group (only)
|
||||
- group only (user NULL): switch group only
|
||||
\param user name of the user to switch to (or NULL)
|
||||
\param group name of the group to switch to (or NULL)
|
||||
\return 0 on success, -1 otherwise
|
||||
*/
|
||||
SWITCH_DECLARE(int32_t) change_user_group(const char *user, const char *group);
|
||||
|
||||
/*!
|
||||
\brief Run endlessly until the system is shutdown
|
||||
\param bg divert console to the background
|
||||
|
|
35
src/switch.c
35
src/switch.c
|
@ -205,6 +205,8 @@ int main(int argc, char *argv[])
|
|||
const char *err = NULL; /* error value for return from freeswitch initialization */
|
||||
#ifndef WIN32
|
||||
int nf = 0; /* TRUE if we are running in nofork mode */
|
||||
char *runas_user = NULL;
|
||||
char *runas_group = NULL;
|
||||
#endif
|
||||
int nc = 0; /* TRUE if we are running in noconsole mode */
|
||||
FILE *f; /* file handle to the pid file */
|
||||
|
@ -214,6 +216,7 @@ int main(int argc, char *argv[])
|
|||
char *usageDesc;
|
||||
int alt_dirs = 0;
|
||||
int known_opt;
|
||||
int high_prio = 0;
|
||||
switch_core_flag_t flags = SCF_USE_SQL;
|
||||
|
||||
#ifdef WIN32
|
||||
|
@ -229,6 +232,8 @@ int main(int argc, char *argv[])
|
|||
"\t-uninstall -- remove freeswitch as a service\n"
|
||||
#else
|
||||
"\t-nf -- no forking\n"
|
||||
"\t-u [user] -- specify user to switch to\n"
|
||||
"\t-g [group] -- specify group to switch to\n"
|
||||
#endif
|
||||
"\t-help -- this message\n"
|
||||
"\t-hp -- enable high priority settings\n"
|
||||
|
@ -280,6 +285,21 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
}
|
||||
#else
|
||||
if (argv[x] && !strcmp(argv[x], "-u")) {
|
||||
x++;
|
||||
if (argv[x] && strlen(argv[x])) {
|
||||
runas_user = argv[x];
|
||||
}
|
||||
known_opt++;
|
||||
}
|
||||
|
||||
if (argv[x] && !strcmp(argv[x], "-g")) {
|
||||
x++;
|
||||
if (argv[x] && strlen(argv[x])) {
|
||||
runas_group = argv[x];
|
||||
}
|
||||
known_opt++;
|
||||
}
|
||||
|
||||
if (argv[x] && !strcmp(argv[x], "-nf")) {
|
||||
nf++;
|
||||
|
@ -287,7 +307,7 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
#endif
|
||||
if (argv[x] && !strcmp(argv[x], "-hp")) {
|
||||
set_high_priority();
|
||||
high_prio++;
|
||||
known_opt++;
|
||||
}
|
||||
|
||||
|
@ -389,6 +409,19 @@ int main(int argc, char *argv[])
|
|||
#endif
|
||||
}
|
||||
|
||||
if (high_prio) {
|
||||
set_high_priority();
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
if (runas_user || runas_group) {
|
||||
if(change_user_group(runas_user, runas_group) < 0) {
|
||||
fprintf(stderr, "Failed to switch user / group\n" );
|
||||
return 255;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (switch_core_init_and_modload(nc ? lfile : NULL, flags, &err) != SWITCH_STATUS_SUCCESS) {
|
||||
fprintf(stderr, "Cannot Initilize [%s]\n", err);
|
||||
return 255;
|
||||
|
|
|
@ -360,7 +360,19 @@ SWITCH_DECLARE(void) switch_core_set_globals(void)
|
|||
|
||||
SWITCH_DECLARE(int32_t) set_high_priority(void)
|
||||
{
|
||||
#ifdef __linux__
|
||||
#ifdef WIN32
|
||||
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
|
||||
#else
|
||||
|
||||
#ifdef USE_SETRLIMIT
|
||||
struct rlimit lim = { RLIM_INFINITY, RLIM_INFINITY };
|
||||
#endif
|
||||
|
||||
#ifdef USE_SCHED_SETSCHEDULER
|
||||
/*
|
||||
* Try to use a round-robin scheduler
|
||||
* with a fallback if that does not work
|
||||
*/
|
||||
struct sched_param sched = { 0 };
|
||||
sched.sched_priority = 1;
|
||||
if (sched_setscheduler(0, SCHED_RR, &sched)) {
|
||||
|
@ -371,19 +383,126 @@ SWITCH_DECLARE(int32_t) set_high_priority(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
|
||||
#ifdef HAVE_SETPRIORITY
|
||||
/*
|
||||
* setpriority() works on FreeBSD (6.2), nice() doesn't
|
||||
*/
|
||||
if (setpriority(PRIO_PROCESS, getpid(), -10) < 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not set nice level\n");
|
||||
}
|
||||
#else
|
||||
if(nice(-10)!= -10) {
|
||||
if (nice(-10) != -10) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not set nice level\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#define USE_MLOCKALL
|
||||
#ifdef HAVE_MLOCKALL
|
||||
#ifdef USE_SETRLIMIT
|
||||
/*
|
||||
* The amount of memory which can be mlocked is limited for non-root users.
|
||||
* FS will segfault (= hitting the limit) soon after mlockall has been called
|
||||
* and we've switched to a different user.
|
||||
* So let's try to remove the mlock limit here...
|
||||
*/
|
||||
if (setrlimit(RLIMIT_MEMLOCK, &lim) < 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT,
|
||||
"Failed to disable memlock limit, application may crash if run as non-root user!\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_MLOCKALL
|
||||
/*
|
||||
* Pin memory pages to RAM to prevent being swapped to disk
|
||||
*/
|
||||
mlockall(MCL_CURRENT | MCL_FUTURE);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(int32_t) change_user_group(const char *user, const char *group)
|
||||
{
|
||||
#ifndef WIN32
|
||||
uid_t runas_uid = 0;
|
||||
gid_t runas_gid = 0;
|
||||
struct passwd *runas_pw = NULL;
|
||||
|
||||
if (user) {
|
||||
/*
|
||||
* Lookup user information in the system's db
|
||||
*/
|
||||
runas_pw = getpwnam( user );
|
||||
if (!runas_pw) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unknown user \"%s\"\n", user);
|
||||
return -1;
|
||||
}
|
||||
runas_uid = runas_pw->pw_uid;
|
||||
}
|
||||
|
||||
if (group) {
|
||||
struct group *gr = NULL;
|
||||
|
||||
/*
|
||||
* Lookup group information in the system's db
|
||||
*/
|
||||
gr = getgrnam( group );
|
||||
if (!gr) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unknown group \"%s\"\n", group);
|
||||
return -1;
|
||||
}
|
||||
runas_gid = gr->gr_gid;
|
||||
}
|
||||
|
||||
if (runas_uid) {
|
||||
#ifdef HAVE_SETGROUPS
|
||||
/*
|
||||
* Drop all group memberships prior to changing anything
|
||||
* or else we're going to inherit the parent's list of groups
|
||||
* (which is not what we want...)
|
||||
*/
|
||||
if (setgroups(0, NULL) < 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to drop group access list\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
if (runas_gid) {
|
||||
/*
|
||||
* A group has been passed, switch to it
|
||||
* (without loading the user's other groups)
|
||||
*/
|
||||
if (setgid(runas_gid) < 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to change gid!\n");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* No group has been passed, use the user's primary group in this case
|
||||
*/
|
||||
if (setgid(runas_pw->pw_gid) < 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to change gid!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_INITGROUPS
|
||||
/*
|
||||
* Set all the other groups the user is a member of
|
||||
* (This can be really useful for fine-grained access control)
|
||||
*/
|
||||
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");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally drop all privileges by switching to the new userid
|
||||
*/
|
||||
if (setuid(runas_uid) < 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to change uid!\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue