Index: configure.in
===================================================================
--- configure.in	(revision 6011)
+++ configure.in	(working copy)
@@ -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,7 +185,21 @@
 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])
+
+
 AC_C_BIGENDIAN(AC_DEFINE([SWITCH_BYTE_ORDER],__BIG_ENDIAN,[Big Endian]),AC_DEFINE([SWITCH_BYTE_ORDER],__LITTLE_ENDIAN,[Little Endian]))
 
 # Checks for integer size
Index: src/switch.c
===================================================================
--- src/switch.c	(revision 6011)
+++ src/switch.c	(working copy)
@@ -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
@@ -238,7 +241,9 @@
 		"\t-conf [confdir]  -- specify an alternate config dir\n"
 		"\t-log [logdir]    -- specify an alternate log dir\n"
 		"\t-db [dbdir]      -- specify an alternate db dir\n"
-		"\t-scripts [scriptsdir]      -- specify an alternate scripts dir\n";
+		"\t-scripts [scriptsdir]      -- specify an alternate scripts dir\n"
+		"\t-u [user]        -- specify user to switch to\n"
+		"\t-g [group]       -- specify group to switch to\n";
 
 	for (x = 1; x < argc; x++) {
 		known_opt = 0;
@@ -279,15 +284,31 @@
 				exit(0);
 			}
 		}
+
 #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++;
 			known_opt++;
 		}
 #endif
 		if (argv[x] && !strcmp(argv[x], "-hp")) {
-			set_high_priority();
+			high_prio++;
 			known_opt++;
 		}
 
@@ -389,6 +410,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;
Index: src/include/switch_core.h
===================================================================
--- src/include/switch_core.h	(revision 6011)
+++ src/include/switch_core.h	(working copy)
@@ -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
 */
Index: src/include/private/switch_core_pvt.h
===================================================================
--- src/include/private/switch_core_pvt.h	(revision 6011)
+++ src/include/private/switch_core_pvt.h	(working copy)
@@ -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
 
Index: src/switch_core.c
===================================================================
--- src/switch_core.c	(revision 6011)
+++ src/switch_core.c	(working copy)
@@ -358,9 +358,27 @@
 }
 
 
+/*
+ * Note:
+ *   mlockall()'ed freeswitch dies on FreeBSD-6.2
+ *   (probably hitting system-wide limit)
+ */
+#if defined(HAVE_MLOCKALL) && defined(__linux__)
+#define USE_MLOCKALL
+
+#if defined(HAVE_SETRLIMIT) && defined(HAVE_RLIMIT_MEMLOCK)
+#define REMOVE_MEMLOCK_LIMIT
+#endif
+#endif
+
+
 SWITCH_DECLARE(int32_t) set_high_priority(void)
 {
-#ifdef __linux__
+#ifndef WIN32
+#ifdef REMOVE_MEMLOCK_LIMIT
+	struct rlimit lim = { RLIM_INFINITY, RLIM_INFINITY };
+#endif
+#if defined(HAVE_SCHED_SETSCHEDULER) && defined(HAVE_SCHED_RR)
 	struct sched_param sched = { 0 };
 	sched.sched_priority = 1;
 	if (sched_setscheduler(0, SCHED_RR, &sched)) {
@@ -370,24 +388,103 @@
 		}
 	}
 #endif
-
-#ifdef WIN32
-	SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
+/*
+ * setpriority() works on FreeBSD (6.2), nice() doesn't
+ */
+#ifdef HAVE_SETPRIORITY
+	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_MLOCKALL
+#ifdef REMOVE_MEMLOCK_LIMIT
+	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
 	mlockall(MCL_CURRENT | MCL_FUTURE);
 #endif
+
+#else	/* WIN32 */
+	SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
 #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) {
+		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;
+
+		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 */
+		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) {
+			if (setgid(runas_gid) < 0) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to change gid!\n");
+				return -1;
+			}
+		} else {
+			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
+			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
+		}
+
+		if (setuid(runas_uid) < 0) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to change uid!\n");
+			return -1;
+		}
+	}
+#else /* WIN32 */
+	/*
+		MikeJ: WIN32 related code goes here...
+		and don't forget to remove/change the WIN32 if(n)defs in switch.c!
+	*/
+#endif
+	return 0;
+}
+
 SWITCH_DECLARE(void) switch_core_runtime_loop(int bg)
 {
 #ifdef WIN32
