/***
This file is part of PulseAudio.
Copyright 2004-2006 Lennart Poettering
Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of the License,
or (at your option) any later version.
PulseAudio is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <pulse/xmalloc.h>
#include <pulsecore/i18n.h>
#include <pulsecore/macro.h>
#include <pulsecore/core-error.h>
#include <pulsecore/log.h>
#include <pulsecore/conf-parser.h>
#include <pulsecore/core-util.h>
#include <pulsecore/authkey.h>
#include "client-conf.h"
#ifdef HAVE_X11
#include <pulse/client-conf-x11.h>
#endif
#define DEFAULT_CLIENT_CONFIG_FILE PA_DEFAULT_CONFIG_DIR PA_PATH_SEP "client.conf"
#define DEFAULT_CLIENT_CONFIG_FILE_USER "client.conf"
#define ENV_CLIENT_CONFIG_FILE "PULSE_CLIENTCONFIG"
#define ENV_DEFAULT_SINK "PULSE_SINK"
#define ENV_DEFAULT_SOURCE "PULSE_SOURCE"
#define ENV_DEFAULT_SERVER "PULSE_SERVER"
#define ENV_DAEMON_BINARY "PULSE_BINARY"
#define ENV_COOKIE_FILE "PULSE_COOKIE"
static const pa_client_conf default_conf = {
.daemon_binary = NULL,
.extra_arguments = NULL,
.default_sink = NULL,
.default_source = NULL,
.default_server = NULL,
.default_dbus_server = NULL,
.cookie_file_from_env = NULL,
.cookie_from_x11_valid = false,
.cookie_file_from_application = NULL,
.cookie_file_from_client_conf = NULL,
.autospawn = true,
.disable_shm = false,
.disable_memfd = false,
.shm_size = 0,
.auto_connect_localhost = false,
.auto_connect_display = false
};
pa_client_conf *pa_client_conf_new(void) {
pa_client_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf));
c->daemon_binary = pa_xstrdup(PA_BINARY);
c->extra_arguments = pa_xstrdup("--log-target=syslog");
return c;
}
void pa_client_conf_free(pa_client_conf *c) {
pa_assert(c);
pa_xfree(c->daemon_binary);
pa_xfree(c->extra_arguments);
pa_xfree(c->default_sink);
pa_xfree(c->default_source);
pa_xfree(c->default_server);
pa_xfree(c->default_dbus_server);
pa_xfree(c->cookie_file_from_env);
pa_xfree(c->cookie_file_from_application);
pa_xfree(c->cookie_file_from_client_conf);
pa_xfree(c);
}
static void load_env(pa_client_conf *c) {
char *e;
if ((e = getenv(ENV_DEFAULT_SINK))) {
pa_xfree(c->default_sink);
c->default_sink = pa_xstrdup(e);
}
if ((e = getenv(ENV_DEFAULT_SOURCE))) {
pa_xfree(c->default_source);
c->default_source = pa_xstrdup(e);
}
if ((e = getenv(ENV_DEFAULT_SERVER))) {
pa_xfree(c->default_server);
c->default_server = pa_xstrdup(e);
/* We disable autospawning automatically if a specific server was set */
c->autospawn = false;
}
if ((e = getenv(ENV_DAEMON_BINARY))) {
pa_xfree(c->daemon_binary);
c->daemon_binary = pa_xstrdup(e);
}
if ((e = getenv(ENV_COOKIE_FILE)) && *e) {
pa_xfree(c->cookie_file_from_env);
c->cookie_file_from_env = pa_xstrdup(e);
}
}
void pa_client_conf_load(pa_client_conf *c, bool load_from_x11, bool load_from_env) {
FILE *f = NULL;
char *fn = NULL;
/* Prepare the configuration parse table */
pa_config_item table[] = {
{ "daemon-binary", pa_config_parse_string, &c->daemon_binary, NULL },
{ "extra-arguments", pa_config_parse_string, &c->extra_arguments, NULL },
{ "default-sink", pa_config_parse_string, &c->default_sink, NULL },
{ "default-source", pa_config_parse_string, &c->default_source, NULL },
{ "default-server", pa_config_parse_string, &c->default_server, NULL },
{ "default-dbus-server", pa_config_parse_string, &c->default_dbus_server, NULL },
{ "autospawn", pa_config_parse_bool, &c->autospawn, NULL },
{ "allow-autospawn-for-root", pa_config_parse_bool, &c->allow_autospawn_for_root, NULL },
{ "cookie-file", pa_config_parse_string, &c->cookie_file_from_client_conf, NULL },
{ "disable-shm", pa_config_parse_bool, &c->disable_shm, NULL },
{ "enable-shm", pa_config_parse_not_bool, &c->disable_shm, NULL },
{ "enable-memfd", pa_config_parse_not_bool, &c->disable_memfd, NULL },
{ "shm-size-bytes", pa_config_parse_size, &c->shm_size, NULL },
{ "auto-connect-localhost", pa_config_parse_bool, &c->auto_connect_localhost, NULL },
{ "auto-connect-display", pa_config_parse_bool, &c->auto_connect_display, NULL },
{ NULL, NULL, NULL, NULL },
};
f = pa_open_config_file(DEFAULT_CLIENT_CONFIG_FILE, DEFAULT_CLIENT_CONFIG_FILE_USER, ENV_CLIENT_CONFIG_FILE, &fn);
if (f) {
pa_config_parse(fn, f, table, NULL, true, NULL);
pa_xfree(fn);
fclose(f);
}
if (load_from_x11) {
#ifdef HAVE_X11
pa_client_conf_from_x11(c);
#endif
}
if (load_from_env)
load_env(c);
}
int pa_client_conf_load_cookie(pa_client_conf *c, uint8_t *cookie, size_t cookie_length) {
int r;
char *fallback_path;
pa_assert(c);
pa_assert(cookie);
pa_assert(cookie_length > 0);
if (c->cookie_file_from_env) {
r = pa_authkey_load(c->cookie_file_from_env, true, cookie, cookie_length);
if (r >= 0)
return 0;
pa_log_warn("Failed to load cookie from %s (configured with environment variable PULSE_COOKIE): %s",
c->cookie_file_from_env, pa_cstrerror(errno));
}
if (c->cookie_from_x11_valid) {
if (cookie_length == sizeof(c->cookie_from_x11)) {
memcpy(cookie, c->cookie_from_x11, cookie_length);
return 0;
}
pa_log_warn("Failed to load cookie from X11 root window property PULSE_COOKIE: size mismatch.");
}
if (c->cookie_file_from_application) {
r = pa_authkey_load(c->cookie_file_from_application, true, cookie, cookie_length);
if (r >= 0)
return 0;
pa_log_warn("Failed to load cookie from %s (configured by the application): %s", c->cookie_file_from_application,
pa_cstrerror(errno));
}
if (c->cookie_file_from_client_conf) {
r = pa_authkey_load(c->cookie_file_from_client_conf, true, cookie, cookie_length);
if (r >= 0)
return 0;
pa_log_warn("Failed to load cookie from %s (configured in client.conf): %s", c->cookie_file_from_client_conf,
pa_cstrerror(errno));
}
r = pa_authkey_load(PA_NATIVE_COOKIE_FILE, false, cookie, cookie_length);
if (r >= 0)
return 0;
if (pa_append_to_home_dir(PA_NATIVE_COOKIE_FILE_FALLBACK, &fallback_path) >= 0) {
r = pa_authkey_load(fallback_path, false, cookie, cookie_length);
pa_xfree(fallback_path);
if (r >= 0)
return 0;
}
r = pa_authkey_load(PA_NATIVE_COOKIE_FILE, true, cookie, cookie_length);
if (r >= 0)
return 0;
pa_log("Failed to load cookie file from %s: %s", PA_NATIVE_COOKIE_FILE, pa_cstrerror(errno));
memset(cookie, 0, cookie_length);
return -1;
}
void pa_client_conf_set_cookie_file_from_application(pa_client_conf *c, const char *cookie_file) {
pa_assert(c);
pa_assert(!cookie_file || *cookie_file);
pa_xfree(c->cookie_file_from_application);
c->cookie_file_from_application = pa_xstrdup(cookie_file);
}