summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2005-08-14 00:47:37 +0000
committerLennart Poettering <lennart@poettering.net>2005-08-14 00:47:37 +0000
commit843f5fba386f9787c1562ce02bea42bfdfc09898 (patch)
tree2d6d0005902c91cca1acd161f1eb54558fead62d
parent8b5cd6ffd9137b14b7ed678f10a551e3911e4a40 (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.c4
-rw-r--r--avahi-daemon/avahi-daemon.conf9
-rw-r--r--avahi-daemon/main.c182
-rw-r--r--docs/TODO4
-rw-r--r--man/avahi-daemon.8.xml.in23
-rw-r--r--man/avahi-daemon.conf.5.xml.in38
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;
}
diff --git a/docs/TODO b/docs/TODO
index 6f7446a..aeca215 100644
--- a/docs/TODO
+++ b/docs/TODO
@@ -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 &lt;@PACKAGE_BUGREPORT@&gt;; avahi is
available from <url href="@PACKAGE_URL@"/></p>