From 5fde5b4d4abeb795f71101d1fd3524f8a27971eb Mon Sep 17 00:00:00 2001 From: Andre Date: Sun, 9 Apr 2006 19:30:21 +0200 Subject: [PATCH] para_server/para_audiod: new option --group Used to set the GID at startup. This patch also reformats server.ggo and audiod.ggo to make them more readable. --- audiod.c | 21 +--- audiod.ggo | 167 ++++++++++++++++++------- daemon.c | 39 ++++-- daemon.h | 2 +- server.c | 12 +- server.ggo | 349 ++++++++++++++++++++++++++++++++++++++++++++++++----- 6 files changed, 484 insertions(+), 106 deletions(-) diff --git a/audiod.c b/audiod.c index 72da56d1..7029ea91 100644 --- a/audiod.c +++ b/audiod.c @@ -268,17 +268,7 @@ void para_log(int ll, const char* fmt,...) if (ll < conf.loglevel_arg) return; - if (!logfile && conf.logfile_given) - logfile = open_log(conf.logfile_arg); - if (!logfile && conf.daemon_given) - return; - if (!logfile) { - if (ll < WARNING) - outfd = stdout; - else - outfd = stderr; - } else - outfd = logfile; + outfd = logfile? logfile : stderr; time(&t1); tm = localtime(&t1); strftime(str, MAXLINE, "%b %d %H:%M:%S", tm); @@ -1656,19 +1646,20 @@ int __noreturn main(int argc, char *argv[]) valid_fd_012(); hostname = para_hostname(); cmdline_parser(argc, argv, &conf); - para_drop_privileges(conf.user_arg); + para_drop_privileges(conf.user_arg, conf.group_arg); cf = configfile_exists(); if (cf) { if (cmdline_parser_configfile(cf, &conf, 0, 0, 0)) { - fprintf(stderr, "parse error in config file\n"); + PARA_EMERG_LOG("%s", "parse error in config file\n"); exit(EXIT_FAILURE); } } + if (conf.logfile_given) + logfile = open_log(conf.logfile_arg); log_welcome("para_audiod", conf.loglevel_arg); i = init_stream_io(); if (i < 0) { - fprintf(stderr, "init stream io error: %s\n", - PARA_STRERROR(-i)); + PARA_EMERG_LOG("init stream io error: %s\n", PARA_STRERROR(-i)); exit(EXIT_FAILURE); } server_uptime(UPTIME_SET); diff --git a/audiod.ggo b/audiod.ggo index 8b0249c1..5e89e6a4 100644 --- a/audiod.ggo +++ b/audiod.ggo @@ -1,61 +1,140 @@ section "general options" -option "user" u "run as user 'name'. Read the output of 'para_server -h' for a detailed information on this option." string typestr="name" optional -option "loglevel" l "set loglevel (0-6)" int typestr="level" default="4" optional -option "daemon" d "run as background daemon" flag off -option "force" F "force startup even if socket exits" flag off -option "logfile" L "(default=stdout/stderr)" string typestr="filename" optional -option "mode" m "mode to use on startup (on/off/sb)" string typestr="mode" default="on" optional -option "socket" s "well-known socket to listen on (default=/var/paraslash/audiod_sock.)" string typestr="filename" optional +#~~~~~~~~~~~~~~~~~~~~~~~~ + +option "user" u +#~~~~~~~~~~~~~~ + +"run as user 'name'. Read the output of +'para_server -h' for more information on this +option." + + string typestr="name" + optional + +option "group" g +#~~~~~~~~~~~~~~~ + +"set group id to 'group'. Read the output of +'para_server -h' for more information on this +option." + + string typestr="group" + optional + +option "loglevel" l +#~~~~~~~~~~~~~~~~~~ + +"set loglevel (0-6)" + + int typestr="level" + default="4" + optional + +option "daemon" d +#~~~~~~~~~~~~~~~~ + +"run as background daemon" + + flag off + + +option "force" F +#~~~~~~~~~~~~~~~ + +"force startup even if +socket exists" + + flag off + +option "logfile" L +#~~~~~~~~~~~~~~~~~ + +"(default=stdout/stderr)" + + string typestr="filename" + optional + +option "mode" m +#~~~~~~~~~~~~~~ + +"mode to use on startup (on/off/sb)" + + string typestr="mode" + default="on" + optional + +option "socket" s + +"well-known socket to listen on +(default=/var/paraslash/audiod_sock.)" + + string typestr="filename" + optional option "user_allow" - +#~~~~~~~~~~~~~~~~~~~~ "allow this user to connect to para_audiod. May be specified multiple times. If not -specified at all, allow all users to +specified at all, all users are allowed to connect." -int typestr="uid" default="-1" optional multiple + int typestr="uid" + default="-1" + optional + multiple -section "stream i/o options." -################# -option "receiver" r "Select receiver. -May be given multiple times, once for each -supported audio format. receiver_spec -consists of an audio format and the receiver -name, separated by a colon, and any options -for that receiver, seperated by whitespace. -If any receiver options are present, the -whole receiver argument must be quoted. +section "stream i/o options." +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +option "receiver" r +#~~~~~~~~~~~~~~~~~~ + +"Select receiver. May be given multiple +times, once for each supported audio format. +'receiver_spec' consists of an audio format and +the receiver name, separated by a colon, and +any options for that receiver, seperated by +whitespace. If any receiver options are +present, the whole receiver argument must be +quoted. Example: -r 'mp3:http -i www.paraslash.org -p 8009' " -string typestr="receiver_spec" default="http" optional multiple + string typestr="receiver_spec" + default="http" + optional + multiple + -################# -option "no_default_filters" D "Configure filters manually. +option "no_default_filters" D +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If (and only if) this option is set, the ---filter options take effect. Otherwise, the -compiled-in default filters mp3dec (oggdec) -and wav are activated for mp3 (ogg) streams." +"Configure filters manually. If (and only +if) this option is set, the --filter options +take effect. Otherwise, the compiled-in +default filters mp3dec (oggdec) and wav are +activated for mp3 (ogg) streams." -flag off -################# + flag off -option "filter" f "Select filter(s) manually. -May be given multiple times. filter_spec -consists of an audio format, the name of the -filter, and any options for that filter. +option "filter" f +#~~~~~~~~~~~~~~~~ + +"Select filter(s) manually. May be given +multiple times. filter_spec consists of an +audio format, the name of the filter, and any +options for that filter. Examples: - -f mp3:mp3dec + -f 'mp3:mp3dec' -f 'mp3:compress --inertia 5 --damp 2' Note that these options are ignored by default, @@ -63,9 +142,9 @@ see --no_default_filters." string typestr="filter_spec" optional multiple -################# option "stream_write_cmd" w +#~~~~~~~~~~~~~~~~~~~~~~~~~~ "Specify stream writer. @@ -77,11 +156,13 @@ Each occurence of START_TIME() gets replaced at runtime by the stream start time announced by para_server, plus any offsets." -string typestr="format:command" optional multiple + string typestr="format:command" + optional + multiple -################# option "stream_delay" - +#~~~~~~~~~~~~~~~~~~~~~~ "Time to add to para_server's start_time. @@ -90,12 +171,16 @@ stream start time for stream_write_cmd if START_TIME() was given. Useful for syncronizing the audio output of clients." -int typestr="milliseconds" default="200" no - -################# + int typestr="milliseconds" + default="200" + optional option "stream_timeout" - +#~~~~~~~~~~~~~~~~~~~~~~~~ -"Deactivate slot if idle for that many seconds" +"Deactivate slot if idle for that many +seconds" -int typestr="seconds" default="30" optional + int typestr="seconds" + default="30" + optional diff --git a/daemon.c b/daemon.c index 616fd2c2..d3a43b9a 100644 --- a/daemon.c +++ b/daemon.c @@ -20,6 +20,11 @@ #include "para.h" #include "daemon.h" #include + +/* getgrnam() */ +#include +#include + #include "string.h" /** @@ -61,15 +66,17 @@ void daemon_init(void) * * Either calls exit() or returns a valid file handle. */ -/* might be called from para_log, so we must not use para_log */ FILE *open_log(const char *logfile_name) { FILE *logfile; if (!logfile_name) return NULL; - if (!(logfile = fopen(logfile_name, "a"))) + if (!(logfile = fopen(logfile_name, "a"))) { + PARA_EMERG_LOG("can not open %s, uid: %d\n", logfile_name, + getuid()); exit(EXIT_FAILURE); + } setlinebuf(logfile); return logfile; } @@ -101,20 +108,33 @@ void log_welcome(const char *whoami, int loglevel) /** * give up superuser privileges * - * This function returns immediately if not invoked with EUID zero. Otherwise, - * it tries to obtain the UID for the user specified by \a username and exits - * if this user was not found. On success, effective and real UID and the saved - * set-user-ID are all set to the UID of \a username. + * This function returns immediately if not invoked with EUID zero. Otherwise, + * it tries to obtain the GID of \a groupname and the UID of \a username. On + * success, effective and real GID/UID and the saved set-group-ID/set-user-ID + * are all set accordingly. On errors, an appropriate message is logged and exit() + * is called to terminate the process. * - * \sa getpwnam(3), getuid(2), setuid(2) + * \sa getpwnam(3), getuid(2), setuid(2), getgrnam(2), setgid(2) */ -void para_drop_privileges(const char *username) +void para_drop_privileges(const char *username, const char *groupname) { struct passwd *p; char *tmp; if (geteuid()) return; + if (groupname) { + struct group *g = getgrnam(groupname); + if (!g) { + PARA_EMERG_LOG("failed to get group %s\n", groupname); + exit(EXIT_FAILURE); + } + if (setgid(g->gr_gid) < 0) { + PARA_EMERG_LOG("failed to set group id %d (%s)\n", + g->gr_gid, strerror(errno)); + exit(EXIT_FAILURE); + } + } if (!username) { PARA_EMERG_LOG("%s", "root privileges, but no user option given\n"); exit(EXIT_FAILURE); @@ -126,7 +146,7 @@ void para_drop_privileges(const char *username) PARA_EMERG_LOG("%s", "no such user\n"); exit(EXIT_FAILURE); } - PARA_NOTICE_LOG("%s", "dropping root privileges\n"); + PARA_INFO_LOG("%s", "dropping root privileges\n"); setuid(p->pw_uid); PARA_DEBUG_LOG("uid: %d, euid: %d\n", getuid(), geteuid()); setuid(p->pw_uid); @@ -170,4 +190,3 @@ __malloc char *uptime_str(void) return make_message("%li:%02li:%02li", t / 86400, (t / 3600) % 24, (t / 60) % 60); } - diff --git a/daemon.h b/daemon.h index 11035b50..e1b8149a 100644 --- a/daemon.h +++ b/daemon.h @@ -5,7 +5,7 @@ void daemon_init(void); FILE *open_log(const char *logfile_name); void close_log(FILE* logfile); void log_welcome(const char *whoami, int loglevel); -void para_drop_privileges(const char *username); +void para_drop_privileges(const char *username, const char *groupname); /** used for server_uptime() */ enum uptime {UPTIME_SET, UPTIME_GET}; time_t server_uptime(enum uptime set_or_get); diff --git a/server.c b/server.c index 8f050096..bcb43a20 100644 --- a/server.c +++ b/server.c @@ -135,15 +135,7 @@ void para_log(int ll, const char* fmt,...) if (ll < conf.loglevel_arg) return; - if (!logfile) { - if (ll < WARNING) - outfd = stdout; - else - outfd = stderr; - } else - outfd = logfile; - if (conf.daemon_given && !logfile) - return; + outfd = logfile? logfile : stderr; time(&t1); tm = localtime(&t1); strftime(str, MAXLINE, "%b %d %H:%M:%S", tm); @@ -348,7 +340,7 @@ static unsigned do_inits(int argc, char **argv) init_random_seed(); /* parse command line options */ cmdline_parser(argc, argv, &conf); - para_drop_privileges(conf.user_arg); + para_drop_privileges(conf.user_arg, conf.group_arg); /* parse config file, open log and set defaults */ parse_config(0); log_welcome("para_server", conf.loglevel_arg); diff --git a/server.ggo b/server.ggo index dd4e91ac..c524009f 100644 --- a/server.ggo +++ b/server.ggo @@ -1,44 +1,335 @@ section "General options" -option "loglevel" l "set loglevel (0-6)" int typestr="level" default="4" optional -option "port" p "port to listen on" int typestr="portnumber" default="2990" optional -option "daemon" d "run as background daemon" flag off -option "user" u "run as user 'name'. para_server does not need any special privileges. If started as root (EUID == 0) this option must be given at the command line (not in the configuration file) so that para_server can drop the root privileges right after parsing the command line options, but before parsing the configuration file. In this case, real/effective/saved UID are all set to the UID of 'username'. As the configuration file is read afterwards, those options that have a default value depending on the UID (e.g. the home directory for the configuration file) are computed by using the uid of 'username'. This option has no effect if para_server ist started as a non-root user (i.e. EUID != 0)" string typestr="name" optional +#~~~~~~~~~~~~~~~~~~~~~~~~ + +option "loglevel" l +#~~~~~~~~~~~~~~~~~~ + +"set loglevel (0-6)" + + int typestr="level" + default="4" + optional + +option "port" p +#~~~~~~~~~~~~~~ + +"listening port" + + int typestr="portnumber" + default="2990" + optional + +option "daemon" d +#~~~~~~~~~~~~~~~~ + +"run as background daemon" + + flag off + +option "user" u +#~~~~~~~~~~~~~~ + +"run as user 'name'. para_server does not +need any special privileges. If started as +root (EUID == 0) this option must be given at +the command line (not in the configuration +file) so that para_server can drop the root +privileges right after parsing the command +line options, but before parsing the +configuration file. In this case, +real/effective/saved UID are all set to the +UID of 'username'. As the configuration file +is read afterwards, those options that have a +default value depending on the UID (e.g. the +directory for the configuration file) are +computed by using the uid of 'username'. +This option has no effect if para_server is +started as a non-root user (i.e. EUID != 0)" + + string typestr="name" + optional + + +option "group" g +#~~~~~~~~~~~~~~~ + +"set group id to according to 'group'. This +option is silently ignored if EUID != 0. +Otherwise, real/effective GID and the saved +set-group ID are all set to the GID given by +'group'. Must not be given in the config file." + + string typestr="groupname" + optional + + section "Configuration files" -option "logfile" L "(default=stdout/stderr)" string typestr="filename" optional -option "config_file" c "(default='~/.paraslash/server.conf'" string typestr="filename" optional -option "user_list" - "(default='~/.paraslash/server.users')" string typestr="filename" optional +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +option "logfile" L +#~~~~~~~~~~~~~~~~~ + +"(default=stdout/stderr)" + + string typestr="filename" + optional + +option "config_file" c +#~~~~~~~~~~~~~~~~~~~~~ + +"(default='~/.paraslash/server.conf'" + + string typestr="filename" + optional + +option "user_list" - +#~~~~~~~~~~~~~~~~~~~ + +"(default='~/.paraslash/server.users')" + + string typestr="filename" + optional + + section "audio file sender" -option "autoplay" a "start playing on startup" flag off -option "announce_time" A "Delay betweeen announcing the stream and sending data" int typestr="milliseconds" default="300" optional -option "selector" S "(default=random)" string typestr="name" optional +#~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +option "autoplay" a +#~~~~~~~~~~~~~~~~~~ + +"start playing on startup" + + flag off + +option "announce_time" A +#~~~~~~~~~~~~~~~~~~~~~~~ + +"Delay betweeen announcing the stream and sending data" + + int typestr="milliseconds" + default="300" + optional + + +option "selector" S +#~~~~~~~~~~~~~~~~~~ + +"(default=random)" + + string typestr="name" + optional + + section "mysql selector:" -option "mysql_host" - "mysql server" string default="localhost" optional -option "mysql_port" - "where mysql is listening" int default="3306" optional -option "mysql_user" - "default value: username from /etc/passwd" string optional -option "mysql_passwd" - "(required)" string optional -option "mysql_database" - "name of mysql database" string default="paraslash" optional -option "mysql_audio_file_dir" - "dir to search for audio files (required)" string optional -option "mysql_default_score" - "scoring rule to use if stream definition does not contain explicit score definition" string default="(LASTPLAYED() / 1440 - 1000 / (LASTPLAYED() + 1) - sqrt(NUMPLAYED()))" optional +#~~~~~~~~~~~~~~~~~~~~~~~~ + + +option "mysql_host" - +#~~~~~~~~~~~~~~~~~~~~ + +"mysql server" + + string typestr="ip or hostname" + default="localhost" + optional + +option "mysql_port" - +#~~~~~~~~~~~~~~~~~~~~ + +"where mysql is listening" + + int typestr="portnumber" + default="3306" + optional + + +option "mysql_user" - +#~~~~~~~~~~~~~~~~~~~~ + +"default value: username from /etc/passwd" + + string typestr="username" + optional + +option "mysql_passwd" - +#~~~~~~~~~~~~~~~~~~~~~~ + +"(required)" + + string + optional + +option "mysql_database" - +#~~~~~~~~~~~~~~~~~~~~~~~~ + +"name of mysql database" + + string + default="paraslash" + optional + +option "mysql_audio_file_dir" - +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +"dir to search for audio files (required)" + + string typestr="dirname" + optional + +option "mysql_default_score" - +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +"scoring rule to use if stream definition +does not contain explicit score definition" + + string + default="(LASTPLAYED() / 1440 - 1000 / (LASTPLAYED() + 1) - sqrt(NUMPLAYED()))" + optional + + + section "random selector" -option "random_dir" - "dir to search for audio files" string default="/home/music" optional +#~~~~~~~~~~~~~~~~~~~~~~~~ + + +option "random_dir" - +#~~~~~~~~~~~~~~~~~~~~ + +"dir to search for audio files" + string typestr="dirname" + default="/home/music" + optional + + + section "http sender" -option "http_port" - "tcp port for http streaming" int typestr="portnumber" default="8000" optional -option "http_default_deny" - "deny connections from hosts which are not explicitly allowed" flag off -option "http_access" - "Add given host/network to access control list (whitelist if http_default_deny was given, blacklist otherwise) before opening the tcp port. This option can be given multiple times. Example: '192.168.0.0/24' whitelists/blacklists the 256 hosts 192.168.0.x" string typestr="a.b.c.d/n" optional multiple -option "http_no_autostart" - "do not open tcp port on server startup" flag off -option "http_max_clients" - "maximal simultaneous connections, non-positive value means unlimited" int typestr="number" default="-1" optional +#~~~~~~~~~~~~~~~~~~~~ + + +option "http_port" - +#~~~~~~~~~~~~~~~~~~~ + +"tcp port for http streaming" + + int typestr="portnumber" + default="8000" + optional + +option "http_default_deny" - +#~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +"deny connections from hosts which are not +explicitly allowed" + + flag off + +option "http_access" - +#~~~~~~~~~~~~~~~~~~~~~ + +"Add given host/network to access control +list (whitelist if http_default_deny was +given, blacklist otherwise) before opening +the tcp port. This option can be given +multiple times. Example: '192.168.0.0/24' +whitelists/blacklists the 256 hosts +192.168.0.x" + + string typestr="a.b.c.d/n" + optional + multiple + +option "http_no_autostart" - +#~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +"do not open tcp port on server startup" + + flag off + +option "http_max_clients" - +#~~~~~~~~~~~~~~~~~~~~~~~~~~ + +"maximal simultaneous connections, +non-positive value means unlimited" + + int typestr="number" + default="-1" + optional + + + section "dccp sender" -option "dccp_port" - "port for dccp streaming" int typestr="portnumber" default="5001" optional +#~~~~~~~~~~~~~~~~~~~~ + + +option "dccp_port" - +#~~~~~~~~~~~~~~~~~~~ + +"port for dccp streaming" + + int typestr="portnumber" + default="5001" + optional + + + section "ortp sender" -option "ortp_target" - "Add given host/port to the list of targets. This option can be given multiple times. Example: '224.0.1.38:1500' instructs the ortp sender to send to udp port 1500 on host 224.0.1.38 (unassigned ip in the Local Network Control Block 224.0.0/24). This is useful for LAN-streaming." string typestr="a.b.c.d:p" optional multiple -option "ortp_no_autostart" - "do not start to send automatically" flag off -option "ortp_default_port" - "default udp port if not specified" int typestr="portnumber" default="1500" optional -option "ortp_header_interval" H "time between extra header sends" int typestr="milliseconds" default="2000" optional -option "ortp_jitter_compensation" j "non-zero values enable ortp's adaptive jitter compensation" int typestr="milliseconds" default="400" optional +#~~~~~~~~~~~~~~~~~~~~ + +option "ortp_target" - +#~~~~~~~~~~~~~~~~~~~~~ + +"Add given host/port to the list of targets. +This option can be given multiple times. +Example: '224.0.1.38:1500' instructs the ortp +sender to send to udp port 1500 on host +224.0.1.38 (unassigned ip in the Local +Network Control Block 224.0.0/24). This is +useful for LAN-streaming." + + string typestr="a.b.c.d:p" + optional + multiple + +option "ortp_no_autostart" - +#~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +"do not start to send automatically" + + flag off + +option "ortp_default_port" - +#~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +"default udp port if not specified" + + int typestr="portnumber" + default="1500" + optional + +option "ortp_header_interval" H +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +"time between extra header sends" + + int typestr="milliseconds" + default="2000" + optional + +option "ortp_jitter_compensation" j +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +"non-zero values enable ortp's adaptive +jitter compensation" + + int typestr="milliseconds" + default="400" + optional -- 2.39.5