From 14a9b80afbb0bddc216462b72156f14e032e1b5e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Nov 2007 01:30:40 +0000 Subject: - Check process name when dealing with PID files - Add new PA_STREAM_FIX_CHANNELS, FIX_RATE, FIX_FORMAT, DONT_MOVE, VARIABLE_RATES to pa_sream_flags_t adn implement it - Expose those flags in pacat - Add notifications about device suspend/resume to the protocol and expose them in libpulse - Allow changing of buffer_attr during playback - allow disabling for remixing globally - hookup polkit support git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2067 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/daemon-conf.c | 24 ++++--- src/daemon/daemon-conf.h | 3 +- src/daemon/daemon.conf.in | 1 + src/daemon/main.c | 169 +++++++++++++++++++++++++++++++++++----------- 4 files changed, 146 insertions(+), 51 deletions(-) (limited to 'src/daemon') diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index 3d63891c..c98c0218 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -71,6 +71,7 @@ static const pa_daemon_conf default_conf = { .log_target = PA_LOG_SYSLOG, .log_level = PA_LOG_NOTICE, .resample_method = PA_RESAMPLER_AUTO, + .disable_remixing = FALSE, .config_file = NULL, .use_pid_file = TRUE, .system_instance = FALSE, @@ -410,6 +411,7 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { { "default-fragments", parse_fragments, NULL }, { "default-fragment-size-msec", parse_fragment_size_msec, NULL }, { "nice-level", parse_nice_level, NULL }, + { "disable-remixing", pa_config_parse_bool, NULL }, #ifdef HAVE_SYS_RESOURCE_H { "rlimit-as", parse_rlimit, NULL }, { "rlimit-core", parse_rlimit, NULL }, @@ -458,33 +460,34 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { table[22].data = c; table[23].data = c; table[24].data = c; + table[25].data = &c->disable_remixing; #ifdef HAVE_SYS_RESOURCE_H - table[25].data = &c->rlimit_as; - table[26].data = &c->rlimit_core; - table[27].data = &c->rlimit_data; - table[28].data = &c->rlimit_fsize; - table[29].data = &c->rlimit_nofile; - table[30].data = &c->rlimit_stack; + table[26].data = &c->rlimit_as; + table[27].data = &c->rlimit_core; + table[28].data = &c->rlimit_data; + table[29].data = &c->rlimit_fsize; + table[30].data = &c->rlimit_nofile; + table[31].data = &c->rlimit_stack; #ifdef RLIMIT_NPROC - table[31].data = &c->rlimit_nproc; + table[32].data = &c->rlimit_nproc; #endif #ifdef RLIMIT_MEMLOCK #ifndef RLIMIT_NPROC #error "Houston, we have a numbering problem!" #endif - table[32].data = &c->rlimit_memlock; + table[33].data = &c->rlimit_memlock; #endif #ifdef RLIMIT_NICE #ifndef RLIMIT_MEMLOCK #error "Houston, we have a numbering problem!" #endif - table[33].data = &c->rlimit_nice; + table[34].data = &c->rlimit_nice; #endif #ifdef RLIMIT_RTPRIO #ifndef RLIMIT_NICE #error "Houston, we have a numbering problem!" #endif - table[34].data = &c->rlimit_rtprio; + table[35].data = &c->rlimit_rtprio; #endif #endif @@ -563,6 +566,7 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) { pa_strbuf_printf(s, "log-target = %s\n", c->auto_log_target ? "auto" : (c->log_target == PA_LOG_SYSLOG ? "syslog" : "stderr")); pa_strbuf_printf(s, "log-level = %s\n", log_level_to_string[c->log_level]); pa_strbuf_printf(s, "resample-method = %s\n", pa_resample_method_to_string(c->resample_method)); + pa_strbuf_printf(s, "disable-remixing = %s\n", pa_yes_no(c->disable_remixing)); pa_strbuf_printf(s, "default-sample-format = %s\n", pa_sample_format_to_string(c->default_sample_spec.format)); pa_strbuf_printf(s, "default-sample-rate = %u\n", c->default_sample_spec.rate); pa_strbuf_printf(s, "default-sample-channels = %u\n", c->default_sample_spec.channels); diff --git a/src/daemon/daemon-conf.h b/src/daemon/daemon-conf.h index b8930bd7..3dcafbfe 100644 --- a/src/daemon/daemon-conf.h +++ b/src/daemon/daemon-conf.h @@ -64,7 +64,8 @@ typedef struct pa_daemon_conf { use_pid_file, system_instance, no_cpu_limit, - disable_shm; + disable_shm, + disable_remixing; int exit_idle_time, module_idle_time, scache_idle_time, diff --git a/src/daemon/daemon.conf.in b/src/daemon/daemon.conf.in index 8d224e82..d664962e 100644 --- a/src/daemon/daemon.conf.in +++ b/src/daemon/daemon.conf.in @@ -46,6 +46,7 @@ ; log-level = notice ; resample-method = speex-float-3 +; disable-remixing = no ; no-cpu-limit = no diff --git a/src/daemon/main.c b/src/daemon/main.c index 051c323e..236819e1 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -94,6 +94,7 @@ #include "dumpmodules.h" #include "caps.h" #include "ltdl-bind-now.h" +#include "polkit.h" #ifdef HAVE_LIBWRAP /* Only one instance of these variables */ @@ -281,17 +282,21 @@ static int create_runtime_dir(void) { #ifdef HAVE_SYS_RESOURCE_H -static void set_one_rlimit(const pa_rlimit *r, int resource, const char *name) { +static int set_one_rlimit(const pa_rlimit *r, int resource, const char *name) { struct rlimit rl; pa_assert(r); if (!r->is_set) - return; + return 0; rl.rlim_cur = rl.rlim_max = r->value; - if (setrlimit(resource, &rl) < 0) + if (setrlimit(resource, &rl) < 0) { pa_log_warn("setrlimit(%s, (%u, %u)) failed: %s", name, (unsigned) r->value, (unsigned) r->value, pa_cstrerror(errno)); + return -1; + } + + return 0; } static void set_all_rlimits(const pa_daemon_conf *conf) { @@ -324,9 +329,10 @@ int main(int argc, char *argv[]) { char *s; int r = 0, retval = 1, d = 0; int daemon_pipe[2] = { -1, -1 }; - int suid_root, real_root; + pa_bool_t suid_root, real_root; int valid_pid_file = 0; gid_t gid = (gid_t) -1; + pa_bool_t allow_realtime, allow_high_priority; #ifdef OS_IS_WIN32 pa_time_event *timer; @@ -357,8 +363,8 @@ int main(int argc, char *argv[]) { real_root = getuid() == 0; suid_root = !real_root && geteuid() == 0; #else - real_root = 0; - suid_root = 0; + real_root = FALSE; + suid_root = FALSE; #endif if (suid_root) { @@ -377,29 +383,12 @@ int main(int argc, char *argv[]) { * is just too risky tun let PA run as root all the time. */ } - setlocale(LC_ALL, ""); - - if (suid_root && (pa_own_uid_in_group(PA_REALTIME_GROUP, &gid) <= 0)) { - pa_log_info("Warning: Called SUID root, but not in group '"PA_REALTIME_GROUP"'. " - "For enabling real-time scheduling please become a member of '"PA_REALTIME_GROUP"' , or increase the RLIMIT_RTPRIO user limit."); - pa_drop_caps(); - pa_drop_root(); - suid_root = real_root = 0; - } - - LTDL_SET_PRELOADED_SYMBOLS(); - - pa_ltdl_init(); - -#ifdef OS_IS_WIN32 - { - WSADATA data; - WSAStartup(MAKEWORD(2, 0), &data); - } -#endif - - pa_random_seed(); + /* At this point, we are a normal user, possibly with CAP_NICE if + * we were started SUID. If we are started as normal root, than we + * still are normal root. */ + setlocale(LC_ALL, ""); + pa_log_set_maximal_level(PA_LOG_INFO); pa_log_set_ident("pulseaudio"); conf = pa_daemon_conf_new(); @@ -411,24 +400,123 @@ int main(int argc, char *argv[]) { goto finish; if (pa_cmdline_parse(conf, argc, argv, &d) < 0) { - pa_log("failed to parse command line."); + pa_log("Failed to parse command line."); goto finish; } pa_log_set_maximal_level(conf->log_level); pa_log_set_target(conf->auto_log_target ? PA_LOG_STDERR : conf->log_target, NULL); + if (suid_root) { + /* Ok, we're suid root, so let's better not enable high prio + * or RT by default */ + + allow_high_priority = allow_realtime = FALSE; + +#ifdef HAVE_POLKIT + if (conf->high_priority) { + if (pa_polkit_check("org.pulseaudio.acquire-high-priority") > 0) { + pa_log_info("PolicyKit grants us acquire-high-priority privilige."); + allow_high_priority = TRUE; + } else + pa_log_info("PolicyKit refuses acquire-high-priority privilige."); + } + + if (conf->realtime_scheduling) { + if (pa_polkit_check("org.pulseaudio.acquire-real-time") > 0) { + pa_log_info("PolicyKit grants us acquire-real-time privilige."); + allow_realtime = TRUE; + } else + pa_log_info("PolicyKit refuses acquire-real-time privilige."); + } +#endif + + if ((conf->high_priority || conf->realtime_scheduling) && pa_own_uid_in_group(PA_REALTIME_GROUP, &gid) > 0) { + pa_log_info("We're in the group '"PA_REALTIME_GROUP"', allowing real-time and high-priority scheduling."); + allow_realtime = conf->realtime_scheduling; + allow_high_priority = conf->high_priority; + } + + if (!allow_high_priority && !allow_realtime) { + + /* OK, there's no further need to keep CAP_NICE. Hence + * let's give it up early */ + + pa_drop_caps(); + pa_drop_root(); + suid_root = real_root = FALSE; + + if (conf->high_priority || conf->realtime_scheduling) + pa_log_notice("Called SUID root and real-time/high-priority scheduling was requested in the configuration. However, we lack the necessary priviliges:\n" + "We are not in group '"PA_REALTIME_GROUP"' and PolicyKit refuse to grant us priviliges. Dropping SUID again.\n" + "For enabling real-time scheduling please acquire the appropriate PolicyKit priviliges, or become a member of '"PA_REALTIME_GROUP"', or increase the RLIMIT_NICE/RLIMIT_RTPRIO resource limits for this user."); + } + + } else { + + /* OK, we're a normal user, so let's allow the user evrything + * he asks for, it's now the kernel's job to enforce limits, + * not ours anymore */ + allow_high_priority = allow_realtime = TRUE; + } + + if (conf->high_priority && !allow_high_priority) { + pa_log_info("High-priority scheduling enabled in configuration but now allowed by policy. Disabling forcibly."); + conf->high_priority = FALSE; + } + + if (conf->realtime_scheduling && !allow_realtime) { + pa_log_info("Real-time scheduling enabled in configuration but now allowed by policy. Disabling forcibly."); + conf->realtime_scheduling = FALSE; + } + if (conf->high_priority && conf->cmd == PA_CMD_DAEMON) pa_raise_priority(conf->nice_level); - if (suid_root && (conf->cmd != PA_CMD_DAEMON || !conf->realtime_scheduling)) { - pa_drop_caps(); - pa_drop_root(); + if (suid_root) { + pa_bool_t drop; + + drop = conf->cmd != PA_CMD_DAEMON || !conf->realtime_scheduling; + +#ifdef RLIMIT_RTPRIO + if (!drop) { + + /* At this point we still have CAP_NICE if we were loaded + * SUID root. If possible let's acquire RLIMIT_RTPRIO + * instead and give CAP_NICE up. */ + + const pa_rlimit rl = { 9, TRUE }; + + if (set_one_rlimit(&rl, RLIMIT_RTPRIO, "RLIMIT_RTPRIO") >= 0) { + pa_log_info("Successfully increased RLIMIT_RTPRIO, giving up CAP_NICE."); + drop = TRUE; + } else + pa_log_warn("RLIMIT_RTPRIO failed: %s", pa_cstrerror(errno)); + } +#endif + + if (drop) { + pa_drop_caps(); + pa_drop_root(); + suid_root = real_root = FALSE; + } } + LTDL_SET_PRELOADED_SYMBOLS(); + pa_ltdl_init(); + if (conf->dl_search_path) lt_dlsetsearchpath(conf->dl_search_path); +#ifdef OS_IS_WIN32 + { + WSADATA data; + WSAStartup(MAKEWORD(2, 0), &data); + } +#endif + + pa_random_seed(); + switch (conf->cmd) { case PA_CMD_DUMP_MODULES: pa_dump_modules(conf, argc-d, argv+d); @@ -466,10 +554,10 @@ int main(int argc, char *argv[]) { case PA_CMD_CHECK: { pid_t pid; - if (pa_pid_file_check_running(&pid) < 0) { - pa_log_info("daemon not running"); - } else { - pa_log_info("daemon running as PID %u", pid); + if (pa_pid_file_check_running(&pid, "pulseaudio") < 0) + pa_log_info("Daemon not running"); + else { + pa_log_info("Daemon running as PID %u", pid); retval = 0; } @@ -478,8 +566,8 @@ int main(int argc, char *argv[]) { } case PA_CMD_KILL: - if (pa_pid_file_kill(SIGINT, NULL) < 0) - pa_log("failed to kill daemon."); + if (pa_pid_file_kill(SIGINT, NULL, "pulseaudio") < 0) + pa_log("Failed to kill daemon."); else retval = 0; @@ -496,9 +584,9 @@ int main(int argc, char *argv[]) { pa_assert(conf->cmd == PA_CMD_DAEMON); } - if (real_root && !conf->system_instance) { + if (real_root && !conf->system_instance) pa_log_warn("This program is not intended to be run as root (unless --system is specified)."); - } else if (!real_root && conf->system_instance) { + else if (!real_root && conf->system_instance) { pa_log("Root priviliges required."); goto finish; } @@ -645,6 +733,7 @@ int main(int argc, char *argv[]) { c->resample_method = conf->resample_method; c->realtime_priority = conf->realtime_priority; c->realtime_scheduling = !!conf->realtime_scheduling; + c->disable_remixing = !!conf->disable_remixing; pa_assert_se(pa_signal_init(pa_mainloop_get_api(mainloop)) == 0); pa_signal_new(SIGINT, signal_callback, c); -- cgit