mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-10 13:29:58 -05:00
* add new --system command line parameter to the daemon for running PulseAudio as system-wide instance
* add PA_ prefixes to all global #defines * modify auth-by-creds: define a new group "pulse-access" which is used for authentication * add proper privilige dropping when running in --system mode * create runtime directory once on startup and not by each module seperately git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1105 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
parent
9db70682d6
commit
9c87a65ce9
28 changed files with 403 additions and 135 deletions
|
|
@ -58,7 +58,8 @@ enum {
|
|||
ARG_RESAMPLE_METHOD,
|
||||
ARG_KILL,
|
||||
ARG_USE_PID_FILE,
|
||||
ARG_CHECK
|
||||
ARG_CHECK,
|
||||
ARG_SYSTEM
|
||||
};
|
||||
|
||||
/* Tabel for getopt_long() */
|
||||
|
|
@ -84,6 +85,7 @@ static struct option long_options[] = {
|
|||
{"kill", 0, 0, ARG_KILL},
|
||||
{"use-pid-file", 2, 0, ARG_USE_PID_FILE},
|
||||
{"check", 0, 0, ARG_CHECK},
|
||||
{"system", 2, 0, ARG_SYSTEM},
|
||||
{NULL, 0, 0, 0}
|
||||
};
|
||||
|
||||
|
|
@ -105,6 +107,7 @@ void pa_cmdline_help(const char *argv0) {
|
|||
" --check Check for a running daemon\n\n"
|
||||
|
||||
"OPTIONS:\n"
|
||||
" --system[=BOOL] Run as system-wide instance\n"
|
||||
" -D, --daemonize[=BOOL] Daemonize after startup\n"
|
||||
" --fail[=BOOL] Quit when startup fails\n"
|
||||
" --high-priority[=BOOL] Try to set high process priority\n"
|
||||
|
|
@ -276,6 +279,13 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d
|
|||
goto fail;
|
||||
}
|
||||
break;
|
||||
|
||||
case ARG_SYSTEM:
|
||||
if ((conf->system_instance = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
|
||||
pa_log(__FILE__": --system expects boolean argument");
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
|
|
|
|||
|
|
@ -39,23 +39,15 @@
|
|||
|
||||
#include "daemon-conf.h"
|
||||
|
||||
#ifndef DEFAULT_CONFIG_DIR
|
||||
# ifndef OS_IS_WIN32
|
||||
# define DEFAULT_CONFIG_DIR "/etc/pulse"
|
||||
# else
|
||||
# define DEFAULT_CONFIG_DIR "%PULSE_ROOT%"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef OS_IS_WIN32
|
||||
# define PATH_SEP "/"
|
||||
#else
|
||||
# define PATH_SEP "\\"
|
||||
#endif
|
||||
|
||||
#define DEFAULT_SCRIPT_FILE DEFAULT_CONFIG_DIR PATH_SEP "default.pa"
|
||||
#define DEFAULT_SCRIPT_FILE PA_DEFAULT_CONFIG_DIR PATH_SEP "default.pa"
|
||||
#define DEFAULT_SCRIPT_FILE_USER ".pulse" PATH_SEP "default.pa"
|
||||
#define DEFAULT_CONFIG_FILE DEFAULT_CONFIG_DIR PATH_SEP "daemon.conf"
|
||||
#define DEFAULT_CONFIG_FILE PA_DEFAULT_CONFIG_DIR PATH_SEP "daemon.conf"
|
||||
#define DEFAULT_CONFIG_FILE_USER ".pulse" PATH_SEP "daemon.conf"
|
||||
|
||||
#define ENV_SCRIPT_FILE "PULSE_SCRIPT"
|
||||
|
|
@ -79,7 +71,8 @@ static const pa_daemon_conf default_conf = {
|
|||
.log_level = PA_LOG_NOTICE,
|
||||
.resample_method = PA_RESAMPLER_SRC_SINC_FASTEST,
|
||||
.config_file = NULL,
|
||||
.use_pid_file = 1
|
||||
.use_pid_file = 1,
|
||||
.system_instance = 0
|
||||
};
|
||||
|
||||
pa_daemon_conf* pa_daemon_conf_new(void) {
|
||||
|
|
@ -89,9 +82,7 @@ pa_daemon_conf* pa_daemon_conf_new(void) {
|
|||
if ((f = pa_open_config_file(DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_USER, ENV_SCRIPT_FILE, &c->default_script_file, "r")))
|
||||
fclose(f);
|
||||
|
||||
#ifdef DLSEARCHPATH
|
||||
c->dl_search_path = pa_xstrdup(DLSEARCHPATH);
|
||||
#endif
|
||||
c->dl_search_path = pa_xstrdup(PA_DLSEARCHPATH);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
|
@ -212,6 +203,7 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
|
|||
{ "verbose", parse_log_level, NULL },
|
||||
{ "resample-method", parse_resample_method, NULL },
|
||||
{ "use-pid-file", pa_config_parse_bool, NULL },
|
||||
{ "system-instance", pa_config_parse_bool, NULL },
|
||||
{ NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
|
|
@ -229,6 +221,7 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
|
|||
table[11].data = c;
|
||||
table[12].data = c;
|
||||
table[13].data = &c->use_pid_file;
|
||||
table[14].data = &c->system_instance;
|
||||
|
||||
pa_xfree(c->config_file);
|
||||
c->config_file = NULL;
|
||||
|
|
@ -295,6 +288,7 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) {
|
|||
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, "use-pid-file = %i\n", c->use_pid_file);
|
||||
pa_strbuf_printf(s, "system-instance = %i\n", !!c->system_instance);
|
||||
|
||||
return pa_strbuf_tostring_free(s);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,8 @@ typedef struct pa_daemon_conf {
|
|||
module_idle_time,
|
||||
scache_idle_time,
|
||||
auto_log_target,
|
||||
use_pid_file;
|
||||
use_pid_file,
|
||||
system_instance;
|
||||
char *script_commands, *dl_search_path, *default_script_file;
|
||||
pa_log_target_t log_target;
|
||||
pa_log_level_t log_level;
|
||||
|
|
|
|||
|
|
@ -46,6 +46,9 @@
|
|||
## Unload autoloaded modules after being idle for this time
|
||||
; module-idle-time = 20
|
||||
|
||||
## Unload autoloaded sample cache entries after being idle for this time
|
||||
; scache-idle-time = 20
|
||||
|
||||
## The path were to look for dynamic shared objects (DSOs aka
|
||||
## plugins). You may specify more than one path seperated by
|
||||
## colons.
|
||||
|
|
@ -75,3 +78,6 @@
|
|||
## process per user, you better disable this option since it
|
||||
## effectively disables multiple instances.
|
||||
; use-pid-file = 1
|
||||
|
||||
## Run the daemon as system-wide instance, requires root priviliges
|
||||
; system-instance = 0
|
||||
|
|
|
|||
|
|
@ -37,6 +37,9 @@
|
|||
#include <unistd.h>
|
||||
#include <locale.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#include <liboil/liboil.h>
|
||||
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
|
|
@ -149,6 +152,104 @@ static void close_pipe(int p[2]) {
|
|||
p[0] = p[1] = -1;
|
||||
}
|
||||
|
||||
#define set_env(key, value) putenv(pa_sprintf_malloc("%s=%s", (key), (value)))
|
||||
|
||||
static int change_user(void) {
|
||||
struct passwd *pw;
|
||||
struct group * gr;
|
||||
int r;
|
||||
|
||||
if (!(pw = getpwnam(PA_SYSTEM_USER))) {
|
||||
pa_log(__FILE__": Failed to find user '%s'.", PA_SYSTEM_USER);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(gr = getgrnam(PA_SYSTEM_GROUP))) {
|
||||
pa_log(__FILE__": Failed to find group '%s'.", PA_SYSTEM_GROUP);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pa_log_info(__FILE__": Found user '%s' (UID %lu) and group '%s' (GID %lu).",
|
||||
PA_SYSTEM_USER, (unsigned long) pw->pw_uid,
|
||||
PA_SYSTEM_GROUP, (unsigned long) gr->gr_gid);
|
||||
|
||||
if (pw->pw_gid != gr->gr_gid) {
|
||||
pa_log(__FILE__": GID of user '%s' and of group '%s' don't match.", PA_SYSTEM_USER, PA_SYSTEM_GROUP);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strcmp(pw->pw_dir, PA_SYSTEM_RUNTIME_PATH) != 0)
|
||||
pa_log_warn(__FILE__": Warning: home directory of user '%s' is not '%s', ignoring.", PA_SYSTEM_USER, PA_SYSTEM_RUNTIME_PATH);
|
||||
|
||||
if (pa_make_secure_dir(PA_SYSTEM_RUNTIME_PATH, 0755, pw->pw_uid, gr->gr_gid) < 0) {
|
||||
pa_log(__FILE__": Failed to create '%s': %s", PA_SYSTEM_RUNTIME_PATH, pa_cstrerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (initgroups(PA_SYSTEM_USER, gr->gr_gid) != 0) {
|
||||
pa_log(__FILE__": Failed to change group list: %s", pa_cstrerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(HAVE_SETRESGID)
|
||||
r = setresgid(gr->gr_gid, gr->gr_gid, gr->gr_gid);
|
||||
#elif defined(HAVE_SETEGID)
|
||||
if ((r = setgid(gr->gr_gid)) >= 0)
|
||||
r = setegid(gr->gr_gid);
|
||||
#elif defined(HAVE_SETREGID)
|
||||
r = setregid(gr->gr_gid, gr->gr_gid);
|
||||
#else
|
||||
#error "No API to drop priviliges"
|
||||
#endif
|
||||
|
||||
if (r < 0) {
|
||||
pa_log(__FILE__": Failed to change GID: %s", pa_cstrerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(HAVE_SETRESUID)
|
||||
r = setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid);
|
||||
#elif defined(HAVE_SETEUID)
|
||||
if ((r = setuid(pw->pw_uid)) >= 0)
|
||||
r = seteuid(pw->pw_uid);
|
||||
#elif defined(HAVE_SETREUID)
|
||||
r = setreuid(pw->pw_uid, pw->pw_uid);
|
||||
#else
|
||||
#error "No API to drop priviliges"
|
||||
#endif
|
||||
|
||||
if (r < 0) {
|
||||
pa_log(__FILE__": Failed to change UID: %s", pa_cstrerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
set_env("USER", PA_SYSTEM_USER);
|
||||
set_env("LOGNAME", PA_SYSTEM_GROUP);
|
||||
set_env("HOME", PA_SYSTEM_RUNTIME_PATH);
|
||||
|
||||
/* Relevant for pa_runtime_path() */
|
||||
set_env("PULSE_RUNTIME_PATH", PA_SYSTEM_RUNTIME_PATH);
|
||||
|
||||
pa_log_info(__FILE__": Successfully dropped root privileges.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int create_runtime_dir(void) {
|
||||
char fn[PATH_MAX];
|
||||
|
||||
pa_runtime_path(NULL, fn, sizeof(fn));
|
||||
|
||||
if (pa_make_secure_dir(fn, 0700, getuid(), getgid()) < 0) {
|
||||
pa_log(__FILE__": Failed to create '%s': %s", fn, pa_cstrerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Relevant for pa_runtime_path() later on */
|
||||
set_env("PULSE_RUNTIME_PATH", fn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
pa_core *c;
|
||||
pa_strbuf *buf = NULL;
|
||||
|
|
@ -172,13 +273,14 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
setlocale(LC_ALL, "");
|
||||
|
||||
pa_limit_caps();
|
||||
if (getuid() != 0)
|
||||
pa_limit_caps();
|
||||
|
||||
#ifdef HAVE_GETUID
|
||||
suid_root = getuid() != 0 && geteuid() == 0;
|
||||
|
||||
if (suid_root && (pa_own_uid_in_group("realtime", &gid) <= 0 || gid >= 1000)) {
|
||||
pa_log_warn(__FILE__": WARNING: called SUID root, but not in group 'realtime'.");
|
||||
if (suid_root && (pa_own_uid_in_group(PA_REALTIME_GROUP, &gid) <= 0 || gid >= 1000)) {
|
||||
pa_log_warn(__FILE__": WARNING: called SUID root, but not in group '"PA_REALTIME_GROUP"'.");
|
||||
pa_drop_root();
|
||||
}
|
||||
#else
|
||||
|
|
@ -220,7 +322,8 @@ int main(int argc, char *argv[]) {
|
|||
if (conf->high_priority && conf->cmd == PA_CMD_DAEMON)
|
||||
pa_raise_priority();
|
||||
|
||||
pa_drop_caps();
|
||||
if (getuid() != 0)
|
||||
pa_drop_caps();
|
||||
|
||||
if (suid_root)
|
||||
pa_drop_root();
|
||||
|
|
@ -278,6 +381,14 @@ int main(int argc, char *argv[]) {
|
|||
assert(conf->cmd == PA_CMD_DAEMON);
|
||||
}
|
||||
|
||||
if (getuid() == 0 && !conf->system_instance) {
|
||||
pa_log(__FILE__": This program is not intended to be run as root (unless --system is specified).");
|
||||
goto finish;
|
||||
} else if (getuid() != 0 && conf->system_instance) {
|
||||
pa_log(__FILE__": Root priviliges required.");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (conf->daemonize) {
|
||||
pid_t child;
|
||||
int tty_fd;
|
||||
|
|
@ -362,6 +473,13 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
|
||||
chdir("/");
|
||||
umask(0022);
|
||||
|
||||
if (conf->system_instance) {
|
||||
if (change_user() < 0)
|
||||
goto finish;
|
||||
} else if (create_runtime_dir() < 0)
|
||||
goto finish;
|
||||
|
||||
if (conf->use_pid_file) {
|
||||
if (pa_pid_file_create() < 0) {
|
||||
|
|
@ -379,12 +497,13 @@ int main(int argc, char *argv[]) {
|
|||
#ifdef SIGPIPE
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
|
||||
mainloop = pa_mainloop_new();
|
||||
assert(mainloop);
|
||||
|
||||
c = pa_core_new(pa_mainloop_get_api(mainloop));
|
||||
assert(c);
|
||||
c->is_system_instance = !!conf->system_instance;
|
||||
|
||||
r = pa_signal_init(pa_mainloop_get_api(mainloop));
|
||||
assert(r == 0);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue