diff options
author | Lennart Poettering <lennart@poettering.net> | 2005-08-14 00:47:37 +0000 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2005-08-14 00:47:37 +0000 |
commit | 843f5fba386f9787c1562ce02bea42bfdfc09898 (patch) | |
tree | 2d6d0005902c91cca1acd161f1eb54558fead62d | |
parent | 8b5cd6ffd9137b14b7ed678f10a551e3911e4a40 (diff) |
* add resource limit enforcement to the daemon
* add ne options --no-rlimits, --no-drop-root, --syslog and --debug
git-svn-id: file:///home/lennart/svn/public/avahi/trunk@311 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe
-rw-r--r-- | avahi-core/iface.c | 4 | ||||
-rw-r--r-- | avahi-daemon/avahi-daemon.conf | 9 | ||||
-rw-r--r-- | avahi-daemon/main.c | 182 | ||||
-rw-r--r-- | docs/TODO | 4 | ||||
-rw-r--r-- | man/avahi-daemon.8.xml.in | 23 | ||||
-rw-r--r-- | man/avahi-daemon.conf.5.xml.in | 38 |
6 files changed, 233 insertions, 27 deletions
diff --git a/avahi-core/iface.c b/avahi-core/iface.c index 81b8375..3d90657 100644 --- a/avahi-core/iface.c +++ b/avahi-core/iface.c @@ -344,7 +344,7 @@ static void netlink_callback(AvahiNetlink *nl, struct nlmsghdr *n, void* userdat AvahiHwInterface *hw; struct rtattr *a = NULL; size_t l; - + if (ifinfomsg->ifi_family != AF_UNSPEC) return; @@ -507,7 +507,7 @@ static void netlink_callback(AvahiNetlink *nl, struct nlmsghdr *n, void* userdat m->list = LIST_ADDR; } else { m->list = LIST_DONE; - avahi_log_debug("Enumeration complete"); + avahi_log_debug("Networ interface enumeration completed"); } } else if (n->nlmsg_type == NLMSG_ERROR && (n->nlmsg_seq == m->query_link_seq || n->nlmsg_seq == m->query_addr_seq)) { diff --git a/avahi-daemon/avahi-daemon.conf b/avahi-daemon/avahi-daemon.conf index eb485d6..f3f81f7 100644 --- a/avahi-daemon/avahi-daemon.conf +++ b/avahi-daemon/avahi-daemon.conf @@ -18,3 +18,12 @@ publish-domain=yes [reflector] enable-reflector=no reflect-ipv=no + +[rlimits] +#rlimit-as= +rlimit-core=0 +rlimit-data=4194304 +rlimit-fsize=0 +rlimit-nofile=15 +rlimit-stack=4194304 +rlimit-nproc=1 diff --git a/avahi-daemon/main.c b/avahi-daemon/main.c index a29ad9f..843ee2b 100644 --- a/avahi-daemon/main.c +++ b/avahi-daemon/main.c @@ -36,6 +36,8 @@ #include <fcntl.h> #include <time.h> #include <stdlib.h> +#include <sys/time.h> +#include <sys/resource.h> #include <libdaemon/dfork.h> #include <libdaemon/dsignal.h> @@ -67,11 +69,22 @@ typedef struct { AvahiServerConfig server_config; DaemonCommand command; gboolean daemonize; + gboolean use_syslog; gchar *config_file; gboolean enable_dbus; gboolean drop_root; gboolean publish_resolv_conf; gchar ** publish_dns_servers; + gboolean no_rlimits; + gboolean debug; + + gboolean rlimit_as_set, rlimit_core_set, rlimit_data_set, rlimit_fsize_set, rlimit_nofile_set, rlimit_stack_set; + rlim_t rlimit_as, rlimit_core, rlimit_data, rlimit_fsize, rlimit_nofile, rlimit_stack; + +#ifdef RLIMIT_NPROC + gboolean rlimit_nproc_set; + rlim_t rlimit_nproc; +#endif } DaemonConfig; #define RESOLV_CONF "/etc/resolv.conf" @@ -216,36 +229,55 @@ static void server_callback(AvahiServer *s, AvahiServerState state, void *userda static void help(FILE *f, const gchar *argv0) { fprintf(f, "%s [options]\n" - " -h --help Show this help\n" - " -D --daemonize Daemonize after startup\n" - " -k --kill Kill a running daemon\n" - " -r --reload Request a running daemon to reload static services\n" - " -c --check Return 0 if a daemon is already running\n" - " -V --version Show version\n" - " -f --file=FILE Load the specified configuration file instead of\n" - " "AVAHI_CONFIG_FILE"\n", + " -h --help Show this help\n" + " -D --daemonize Daemonize after startup (implies -s)\n" + " -s --syslog Write log messages to syslog(3) instead of STDERR\n" + " -k --kill Kill a running daemon\n" + " -r --reload Request a running daemon to reload static services\n" + " -c --check Return 0 if a daemon is already running\n" + " -V --version Show version\n" + " -f --file=FILE Load the specified configuration file instead of\n" + " "AVAHI_CONFIG_FILE"\n" + " --no-rlimits Don't enforce resource limits\n" + " --no-drop-root Don't drop priviliges\n" + " --debug Increase verbosity\n", argv0); } + static gint parse_command_line(DaemonConfig *c, int argc, char *argv[]) { gint o; + + enum { + OPTION_NO_RLIMITS = 256, + OPTION_NO_DROP_ROOT, + OPTION_DEBUG + }; static const struct option const long_options[] = { - { "help", no_argument, NULL, 'h' }, - { "daemonize", no_argument, NULL, 'D' }, - { "kill", no_argument, NULL, 'k' }, - { "version", no_argument, NULL, 'V' }, - { "file", required_argument, NULL, 'f' }, - { "reload", no_argument, NULL, 'r' }, - { "check", no_argument, NULL, 'c' }, + { "help", no_argument, NULL, 'h' }, + { "daemonize", no_argument, NULL, 'D' }, + { "kill", no_argument, NULL, 'k' }, + { "version", no_argument, NULL, 'V' }, + { "file", required_argument, NULL, 'f' }, + { "reload", no_argument, NULL, 'r' }, + { "check", no_argument, NULL, 'c' }, + { "syslog", no_argument, NULL, 's' }, + { "no-rlimits", no_argument, NULL, OPTION_NO_RLIMITS }, + { "no-drop-root", no_argument, NULL, OPTION_NO_DROP_ROOT }, + { "debug", no_argument, NULL, OPTION_DEBUG }, + { NULL, 0, NULL, 0 } }; g_assert(c); opterr = 0; - while ((o = getopt_long(argc, argv, "hDkVf:rc", long_options, NULL)) >= 0) { + while ((o = getopt_long(argc, argv, "hDkVf:rcs", long_options, NULL)) >= 0) { switch(o) { + case 's': + c->use_syslog = TRUE; + break; case 'h': c->command = DAEMON_HELP; break; @@ -268,6 +300,15 @@ static gint parse_command_line(DaemonConfig *c, int argc, char *argv[]) { case 'c': c->command = DAEMON_CHECK; break; + case OPTION_NO_RLIMITS: + c->no_rlimits = TRUE; + break; + case OPTION_NO_DROP_ROOT: + c->drop_root = FALSE; + break; + case OPTION_DEBUG: + c->debug = TRUE; + break; default: fprintf(stderr, "Invalid command line argument: %c\n", o); return -1; @@ -407,6 +448,50 @@ static gint load_config_file(DaemonConfig *c) { g_strfreev(keys); keys = NULL; + } else if (g_strcasecmp(*g, "rlimits") == 0) { + gchar **k; + + keys = g_key_file_get_keys(f, *g, NULL, NULL); + + for (k = keys; *k; k++) { + + v = g_key_file_get_string(f, *g, *k, NULL); + + if (g_strcasecmp(*k, "rlimit-as") == 0) { + c->rlimit_as_set = TRUE; + c->rlimit_as = atoi(v); + } else if (g_strcasecmp(*k, "rlimit-core") == 0) { + c->rlimit_core_set = TRUE; + c->rlimit_core = atoi(v); + } else if (g_strcasecmp(*k, "rlimit-data") == 0) { + c->rlimit_data_set = TRUE; + c->rlimit_data = atoi(v); + } else if (g_strcasecmp(*k, "rlimit-fsize") == 0) { + c->rlimit_fsize_set = TRUE; + c->rlimit_fsize = atoi(v); + } else if (g_strcasecmp(*k, "rlimit-nofile") == 0) { + c->rlimit_nofile_set = TRUE; + c->rlimit_nofile = atoi(v); + } else if (g_strcasecmp(*k, "rlimit-stack") == 0) { + c->rlimit_stack_set = TRUE; + c->rlimit_stack = atoi(v); +#ifdef RLIMIT_NPROC + } else if (g_strcasecmp(*k, "rlimit-nproc") == 0) { + c->rlimit_nproc_set = TRUE; + c->rlimit_nproc = atoi(v); +#endif + } else { + fprintf(stderr, "Invalid configuration key \"%s\" in group \"%s\"\n", *k, *g); + goto finish; + } + + g_free(v); + v = NULL; + } + + g_strfreev(keys); + keys = NULL; + } else { fprintf(stderr, "Invalid configuration file group \"%s\".\n", *g); goto finish; @@ -443,6 +528,9 @@ static void log_function(AvahiLogLevel level, const gchar *txt) { g_assert(level < AVAHI_LOG_LEVEL_MAX); g_assert(txt); + if (!config.debug && level == AVAHI_LOG_DEBUG) + return; + daemon_log(log_level_map[level], "%s", txt); } @@ -695,7 +783,39 @@ fail: if (reset_umask) umask(u); return r; +} + +static void set_one_rlimit(int resource, rlim_t limit, const gchar *name) { + struct rlimit rl; + rl.rlim_cur = rl.rlim_max = limit; + if (setrlimit(resource, &rl) < 0) + avahi_log_warn("setrlimit(%s, {%u, %u}) failed: %s", name, (unsigned) limit, (unsigned) limit, strerror(errno)); +} + +static void enforce_rlimits(void) { + + if (config.rlimit_as_set) + set_one_rlimit(RLIMIT_AS, config.rlimit_as, "RLIMIT_AS"); + if (config.rlimit_core_set) + set_one_rlimit(RLIMIT_CORE, config.rlimit_core, "RLIMIT_CORE"); + if (config.rlimit_data_set) + set_one_rlimit(RLIMIT_DATA, config.rlimit_data, "RLIMIT_DATA"); + if (config.rlimit_fsize_set) + set_one_rlimit(RLIMIT_FSIZE, config.rlimit_fsize, "RLIMIT_FSIZE"); + if (config.rlimit_nofile_set) + set_one_rlimit(RLIMIT_NOFILE, config.rlimit_nofile, "RLIMIT_NOFILE"); + if (config.rlimit_stack_set) + set_one_rlimit(RLIMIT_STACK, config.rlimit_stack, "RLIMIT_STACK"); +#ifdef RLIMIT_NPROC + if (config.rlimit_nproc_set) + set_one_rlimit(RLIMIT_NPROC, config.rlimit_nproc, "RLIMIT_NPROC"); +#endif + +#ifdef RLIMIT_MEMLOCK + /* We don't need locked memory */ + set_one_rlimit(RLIMIT_MEMLOCK, 0, "RLIMIT_MEMLOCK"); +#endif } #define RANDOM_DEVICE "/dev/urandom" @@ -736,7 +856,20 @@ int main(int argc, char *argv[]) { config.drop_root = TRUE; config.publish_dns_servers = NULL; config.publish_resolv_conf = FALSE; - + config.use_syslog = FALSE; + config.no_rlimits = FALSE; + config.debug = FALSE; + + config.rlimit_as_set = FALSE; + config.rlimit_core_set = FALSE; + config.rlimit_data_set = FALSE; + config.rlimit_fsize_set = FALSE; + config.rlimit_nofile_set = FALSE; + config.rlimit_stack_set = FALSE; +#ifdef RLIMIT_NPROC + config.rlimit_nproc_set = FALSE; +#endif + if ((argv0 = strrchr(argv[0], '/'))) argv0++; else @@ -776,7 +909,7 @@ int main(int argc, char *argv[]) { else if (config.command == DAEMON_RUN) { pid_t pid; - if (getuid() != 0) { + if (getuid() != 0 && config.drop_root) { avahi_log_error("This program is intended to be run as root."); goto finish; } @@ -810,10 +943,8 @@ int main(int argc, char *argv[]) { /* Child */ } - - printf("%s "PACKAGE_VERSION" starting up.\n", argv0); - - chdir("/"); + if (config.use_syslog || config.daemonize) + daemon_log_use = DAEMON_LOG_SYSLOG; if (make_runtime_dir() < 0) goto finish; @@ -832,6 +963,13 @@ int main(int argc, char *argv[]) { } else wrote_pid_file = TRUE; + if (!config.no_rlimits) + enforce_rlimits(); + + chdir("/"); + + avahi_log_info("%s "PACKAGE_VERSION" starting up.\n", argv0); + if (run_server(&config) == 0) r = 0; } @@ -1,7 +1,7 @@ todo: -* drop glib +* drop glib from avahi-daemon * allow srv port == 0 -* deal with no local interface +* deal with no local interface ? * release! later: diff --git a/man/avahi-daemon.8.xml.in b/man/avahi-daemon.8.xml.in index 93002ec..ce8ab81 100644 --- a/man/avahi-daemon.8.xml.in +++ b/man/avahi-daemon.8.xml.in @@ -65,9 +65,29 @@ <option> <p><opt>-D | --daemonize</opt></p> - <optdesc><p>Daemonize after startup and redirect log messages to syslog.</p></optdesc> + <optdesc><p>Daemonize after startup. Implies <opt>--syslog</opt></p></optdesc> </option> + <option> + <p><opt>-s | --syslog</opt></p> + <optdesc><p>Log to syslog instead of STDERR. Implied by <opt>--daemonize</opt></p></optdesc> + </option> + + <option> + <p><opt>--debug</opt></p> + <optdesc><p>Increase verbosity to debug level</p></optdesc> + </option> + + <option> + <p><opt>--no-rlimits</opt></p> + <optdesc><p>Don't enforce resource limits as specified in the configuration file. (See <manref section="2" name="setrlimit"/> for more information)</p></optdesc> + </option> + + <option> + <p><opt>--no-drop-root</opt></p> + <optdesc><p>Don't drop root priviliges after startup and don't require daemon to be started as root. We recommend not to use this option.</p></optdesc> + </option> + <option> <p><opt>-k | --kill</opt></p> <optdesc><p>Kill an already running avahi-daemon. (equivalent to sending a SIGTERM)</p></optdesc> @@ -100,6 +120,7 @@ <optdesc><p>Show version information </p></optdesc> </option> + </options> diff --git a/man/avahi-daemon.conf.5.xml.in b/man/avahi-daemon.conf.5.xml.in index 45fdf9f..cac0717 100644 --- a/man/avahi-daemon.conf.5.xml.in +++ b/man/avahi-daemon.conf.5.xml.in @@ -173,6 +173,44 @@ </option> </section> + <section name="Section [rlimits]"> + <p>This section is used to define system resource limits for the + daemon. See <manref section="2" name="setrlimit"/> for more + information. If any of the options is not specified in the configuration + file, avahi-daemon does not change it from the system + defaults.</p> + + + <option> + <p><opt>rlimit-as=</opt> Value in bytes for RLIMIT_AS (maximum size of the process's virtual memory). Sensible values are heavily system dependent.</p> + </option> + + <option> + <p><opt>rlimit-core=</opt> Value in bytes for RLIMIT_CORE (maximum core file size). Unless you want to debug avahi-daemon, it is safe to set this to 0.</p> + </option> + + <option> + <p><opt>rlimit-data=</opt> Value in bytes for RLIMIT_DATA (maximum size of the process's data segment). Sensible values are heavily system dependent.</p> + </option> + + <option> + <p><opt>rlimit-fsize=</opt> Value for RLIMIT_FSIZE (maximum size of files the process may create). Since avahi-daemon shouldn't write any files to disk, it is safe to set this to 0.</p> + </option> + + <option> + <p><opt>rlimit-nofile=</opt> Value for RLIMIT_NOFILE (open file descriptors). avahi-daemon shouldn't need more than 15 to 20 open file descriptors concurrently.</p> + </option> + + <option> + <p><opt>rlimit-stack=</opt> Value in bytes for RLIMIT_STACK (maximum size of the process stack). Sensible values are heavily system dependent.</p> + </option> + + <option> + <p><opt>rlimit-nproc=</opt> Value for RLIMIT_NPROC (number of process of user). Since only a single avahi-daemon process is usually running you can set this safely to 1.</p> + </option> + + </section> + <section name="Authors"> <p>The avahi developers <@PACKAGE_BUGREPORT@>; avahi is available from <url href="@PACKAGE_URL@"/></p> |