Steve Smith
2004-Aug-06 14:57 UTC
[icecast-dev] [PATCH] Configurable privileges and chroot jail
Hi,
This patch (against the current CVS tree) is intended to add secure
configuration to icecast 'out of the box'. It adds two configuration
directives, 'icecast_user' and 'chroot_dir'. These are intended
to be
used together to reduce the privileges icecast runs under to the
minimum necessary. When this is enabled and run as root icecast will
enter the specified chroot jail and drop privileges to the user
specified.
The chroot_dir option will probably not work if --enable-fsstd is
specified, although I haven't actually tried it.
I would appreciate any comments and suggestions.
Cheers,
Steve
** Patch follows **
Index: conf/icecast.conf.dist.in
==================================================================RCS file:
/cvsroot/icecast/conf/icecast.conf.dist.in,v
retrieving revision 1.1
diff -b -u -r1.1 icecast.conf.dist.in
--- conf/icecast.conf.dist.in 1999/12/11 04:11:02 1.1
+++ conf/icecast.conf.dist.in 2001/04/24 01:32:55
@@ -21,6 +21,31 @@
rp_email kirk@enterprise.space
server_url http://www.icecast.org/
+######################### Server Privileges ###################################
+# Some options to increase security of unattended servers.
+#
+# If the server is run automatically on boot, then the chances are it is
+# running as root. This is unnecessary, and a bad thing, because if there is a
+# security vunerability in the server, then an attacker can gain control of
+# your system. If the option "icecast_user" is set, then these
privileges will
+# be dropped in favour of the user specified.
+#
+# If you set the "chroot_dir" option, then early in startup the
icecast server
+# will change it's root ('/') directory to the one specified. The
advantage
+# of this scheme is that should there be a vunerability in the server then the
+# damage an attacker can do is limited to this directory. Once the new root
+# is in effect, the server will only be able to access files below this
+# directory, so any files the server needs to access should be in this area.
+# The options 'staticdir', 'templatedir' and 'logdir'
should be specified
+# as relative to this root (ie. '/etc' instead of
'/usr/local/icecast/etc'
+# if the chroot dir is '/usr/local/icecast'.
+#
+# Both of these options will fail if the server is not run as root.
+###############################################################################
+
+# icecast_user icecast
+# chroot_dir @prefix@
+
########################### Server Limits
######################################
# These describe the maximum number of simultaneous connections allowed.
# When reached, the server will refuse access.
Index: src/commands.c
==================================================================RCS file:
/cvsroot/icecast/src/commands.c,v
retrieving revision 1.26
diff -b -u -r1.26 commands.c
--- src/commands.c 2000/11/01 21:32:35 1.26
+++ src/commands.c 2001/04/24 01:32:56
@@ -297,6 +297,8 @@
{ "client_password", string_e, "<unimplemented>
Client password", NULL },
{ "admin_password", string_e, "The remote admin
password", NULL },
{ "oper_password", string_e, "Operator
Password", NULL },
+ { "chroot_dir", string_e, "Dir to chroot
to", NULL},
+ { "icecast_user", string_e, "User to drop
privileges to", NULL},
{ "touch_freq", integer_e, "Touch frequency",
NULL },
{ "max_clients", integer_e, "Highest number of
client connectons", NULL },
{ "max_sources", integer_e, "Highest number of
source connections", NULL },
@@ -396,6 +398,8 @@
configfile_settings[x++].setting = &info.client_pass;
configfile_settings[x++].setting = &info.remote_admin_pass;
configfile_settings[x++].setting = &info.oper_pass;
+ configfile_settings[x++].setting = &info.chroot_dir;
+ configfile_settings[x++].setting = &info.icecast_user;
configfile_settings[x++].setting = &info.touch_freq;
configfile_settings[x++].setting = &info.max_clients;
configfile_settings[x++].setting = &info.max_sources;
Index: src/icetypes.h
==================================================================RCS file:
/cvsroot/icecast/src/icetypes.h,v
retrieving revision 1.14
diff -b -u -r1.14 icetypes.h
--- src/icetypes.h 2000/07/05 19:51:14 1.14
+++ src/icetypes.h 2001/04/24 01:32:57
@@ -265,6 +265,9 @@
char *logdir;
char *templatedir;
+ char* chroot_dir;
+ char* icecast_user;
+
/* Encoder stuff */
avl_tree *sources; /* Source array */
unsigned long int num_sources; /* Encoders connected */
Index: src/main.c
==================================================================RCS file:
/cvsroot/icecast/src/main.c,v
retrieving revision 1.18
diff -b -u -r1.18 main.c
--- src/main.c 2000/07/27 07:04:15 1.18
+++ src/main.c 2001/04/24 01:32:57
@@ -46,6 +46,9 @@
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/types.h>
#ifndef _WIN32
#include <sys/socket.h>
@@ -164,6 +167,9 @@
/* Initialize some platform dependant network stuff */
initialize_network ();
+ /* Drop to unprivileged user if defined. */
+ drop_privileges();
+
/* Initialize the interpreter (if configured) */
interpreter_init ();
@@ -231,6 +237,80 @@
#endif
}
+void drop_privileges()
+{
+#ifdef _WIN32
+ return;
+#else
+ struct passwd *pwd;
+ uid_t uid, cuid;
+ gid_t gid;
+
+ if (info.icecast_user != 0) {
+ pwd = getpwnam(info.icecast_user);
+ if (!pwd) {
+ write_log (LOG_DEFAULT, "ERROR: icecast_user %s
doesn't exist",
+ info.icecast_user);
+ clean_shutdown (&info);
+ }
+
+ /* These will get clobbered during the chroot, so save them */
+ uid = pwd->pw_uid;
+ gid = pwd->pw_gid;
+
+ cuid = getuid();
+ if (cuid != 0 && uid != cuid) {
+ write_log (LOG_DEFAULT, "ERROR: Don't have
privileges to "
+ "change to icecast_user %s",
info.icecast_user);
+ clean_shutdown (&info);
+ }
+
+ if (setgid(gid) < 0 ||
+ initgroups(info.icecast_user, gid) < 0)
+ {
+ write_log (LOG_DEFAULT, "ERROR: Failed to change
to "
+ "icecast_user %s: %s",
info.icecast_user, strerror(errno));
+ clean_shutdown (&info);
+ }
+ xa_debug(1, "Initialised groups for %s",
info.icecast_user);
+ }
+
+
+ if (info.chroot_dir != 0) {
+ /* Only root can do this */
+ if (cuid != 0) {
+ write_log (LOG_DEFAULT, "ERROR: Don't have
privileges to "
+ "chroot to %s", info.chroot_dir);
+ clean_shutdown (&info);
+ }
+
+ /* Set root dir and climb in */
+ if (chroot(info.chroot_dir) < 0) {
+ write_log (LOG_DEFAULT, "ERROR: Failed to chroot
to %s: %s",
+ info.chroot_dir,strerror(errno));
+ clean_shutdown (&info);
+ }
+ if (chdir("/") < 0) {
+ write_log (LOG_DEFAULT, "ERROR: Failed to enter
jail: %s",
+ strerror(errno));
+ clean_shutdown (&info);
+ }
+
+ xa_debug(1, "Entered jail %s", info.chroot_dir);
+ }
+
+ if (info.icecast_user != 0) {
+ if (setuid(uid) < 0) {
+ write_log (LOG_DEFAULT, "ERROR: Failed to change
to "
+ "icecast_user %s: %s",
info.icecast_user, strerror(errno));
+ clean_shutdown (&info);
+ }
+ xa_debug(1, "Dropped privileges to user %s",
info.icecast_user);
+ }
+#endif
+}
+
+
/* Print header, select the console mode, and start the main server loop. */
void
startup_mode()
@@ -544,7 +624,7 @@
directory_server_t *ds;
int i;
avl_traverser trav = {0};
- static main_shutting_down = 0;
+ static int main_shutting_down = 0;
thread_library_lock ();
if (!main_shutting_down)
Index: src/main.h
==================================================================RCS file:
/cvsroot/icecast/src/main.h,v
retrieving revision 1.4
diff -b -u -r1.4 main.h
--- src/main.h 2000/05/25 16:00:15 1.4
+++ src/main.h 2001/04/24 01:32:57
@@ -27,6 +27,7 @@
void setup_defaults();
void setup_signal_traps();
void allocate_resources();
+void drop_privileges();
void startup_mode();
void clean_shutdown(server_info_t *info);
void usage();
--- >8 ----
List archives: http://www.xiph.org/archives/
icecast project homepage: http://www.icecast.org/
To unsubscribe from this list, send a message to
'icecast-dev-request@xiph.org'
containing only the word 'unsubscribe' in the body. No subject is
needed.
Unsubscribe messages sent to the list will be ignored/filtered.
