[Freeswitch-svn] [commit] r6033 - in freeswitch/trunk: . src src/include src/include/private
Freeswitch SVN
mikej at freeswitch.org
Tue Oct 23 11:56:23 EDT 2007
Author: mikej
Date: Tue Oct 23 11:56:23 2007
New Revision: 6033
Modified:
freeswitch/trunk/configure.in
freeswitch/trunk/src/include/private/switch_core_pvt.h
freeswitch/trunk/src/include/switch_core.h
freeswitch/trunk/src/switch.c
freeswitch/trunk/src/switch_core.c
Log:
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
Modified: freeswitch/trunk/configure.in
==============================================================================
--- freeswitch/trunk/configure.in (original)
+++ freeswitch/trunk/configure.in Tue Oct 23 11:56:23 2007
@@ -170,7 +170,7 @@
# 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_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]))
Modified: freeswitch/trunk/src/include/private/switch_core_pvt.h
==============================================================================
--- freeswitch/trunk/src/include/private/switch_core_pvt.h (original)
+++ freeswitch/trunk/src/include/private/switch_core_pvt.h Tue Oct 23 11:56:23 2007
@@ -60,6 +60,19 @@
#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
Modified: freeswitch/trunk/src/include/switch_core.h
==============================================================================
--- freeswitch/trunk/src/include/switch_core.h (original)
+++ freeswitch/trunk/src/include/switch_core.h Tue Oct 23 11:56:23 2007
@@ -1414,6 +1414,18 @@
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
*/
Modified: freeswitch/trunk/src/switch.c
==============================================================================
--- freeswitch/trunk/src/switch.c (original)
+++ freeswitch/trunk/src/switch.c Tue Oct 23 11:56:23 2007
@@ -205,6 +205,8 @@
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 @@
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 @@
"\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 @@
}
}
#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 @@
}
#endif
if (argv[x] && !strcmp(argv[x], "-hp")) {
- set_high_priority();
+ high_prio++;
known_opt++;
}
@@ -389,6 +409,19 @@
#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;
Modified: freeswitch/trunk/src/switch_core.c
==============================================================================
--- freeswitch/trunk/src/switch_core.c (original)
+++ freeswitch/trunk/src/switch_core.c Tue Oct 23 11:56:23 2007
@@ -360,7 +360,19 @@
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 @@
}
#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;
}
More information about the Freeswitch-svn
mailing list