153a5a1b3Sopenharmony_ci/***
253a5a1b3Sopenharmony_ci  This file is part of PulseAudio.
353a5a1b3Sopenharmony_ci
453a5a1b3Sopenharmony_ci  Copyright 2004-2006 Lennart Poettering
553a5a1b3Sopenharmony_ci  Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
653a5a1b3Sopenharmony_ci
753a5a1b3Sopenharmony_ci  PulseAudio is free software; you can redistribute it and/or modify
853a5a1b3Sopenharmony_ci  it under the terms of the GNU Lesser General Public License as published
953a5a1b3Sopenharmony_ci  by the Free Software Foundation; either version 2.1 of the License,
1053a5a1b3Sopenharmony_ci  or (at your option) any later version.
1153a5a1b3Sopenharmony_ci
1253a5a1b3Sopenharmony_ci  PulseAudio is distributed in the hope that it will be useful, but
1353a5a1b3Sopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1453a5a1b3Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1553a5a1b3Sopenharmony_ci  General Public License for more details.
1653a5a1b3Sopenharmony_ci
1753a5a1b3Sopenharmony_ci  You should have received a copy of the GNU Lesser General Public License
1853a5a1b3Sopenharmony_ci  along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
1953a5a1b3Sopenharmony_ci***/
2053a5a1b3Sopenharmony_ci
2153a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H
2253a5a1b3Sopenharmony_ci#include <config.h>
2353a5a1b3Sopenharmony_ci#endif
2453a5a1b3Sopenharmony_ci
2553a5a1b3Sopenharmony_ci#include <stdlib.h>
2653a5a1b3Sopenharmony_ci#include <unistd.h>
2753a5a1b3Sopenharmony_ci#include <errno.h>
2853a5a1b3Sopenharmony_ci
2953a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h>
3053a5a1b3Sopenharmony_ci
3153a5a1b3Sopenharmony_ci#include <pulsecore/i18n.h>
3253a5a1b3Sopenharmony_ci#include <pulsecore/macro.h>
3353a5a1b3Sopenharmony_ci#include <pulsecore/core-error.h>
3453a5a1b3Sopenharmony_ci#include <pulsecore/log.h>
3553a5a1b3Sopenharmony_ci#include <pulsecore/conf-parser.h>
3653a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h>
3753a5a1b3Sopenharmony_ci#include <pulsecore/authkey.h>
3853a5a1b3Sopenharmony_ci
3953a5a1b3Sopenharmony_ci#include "client-conf.h"
4053a5a1b3Sopenharmony_ci
4153a5a1b3Sopenharmony_ci#ifdef HAVE_X11
4253a5a1b3Sopenharmony_ci#include <pulse/client-conf-x11.h>
4353a5a1b3Sopenharmony_ci#endif
4453a5a1b3Sopenharmony_ci
4553a5a1b3Sopenharmony_ci#define DEFAULT_CLIENT_CONFIG_FILE PA_DEFAULT_CONFIG_DIR PA_PATH_SEP "client.conf"
4653a5a1b3Sopenharmony_ci#define DEFAULT_CLIENT_CONFIG_FILE_USER "client.conf"
4753a5a1b3Sopenharmony_ci
4853a5a1b3Sopenharmony_ci#define ENV_CLIENT_CONFIG_FILE "PULSE_CLIENTCONFIG"
4953a5a1b3Sopenharmony_ci#define ENV_DEFAULT_SINK "PULSE_SINK"
5053a5a1b3Sopenharmony_ci#define ENV_DEFAULT_SOURCE "PULSE_SOURCE"
5153a5a1b3Sopenharmony_ci#define ENV_DEFAULT_SERVER "PULSE_SERVER"
5253a5a1b3Sopenharmony_ci#define ENV_DAEMON_BINARY "PULSE_BINARY"
5353a5a1b3Sopenharmony_ci#define ENV_COOKIE_FILE "PULSE_COOKIE"
5453a5a1b3Sopenharmony_ci
5553a5a1b3Sopenharmony_cistatic const pa_client_conf default_conf = {
5653a5a1b3Sopenharmony_ci    .daemon_binary = NULL,
5753a5a1b3Sopenharmony_ci    .extra_arguments = NULL,
5853a5a1b3Sopenharmony_ci    .default_sink = NULL,
5953a5a1b3Sopenharmony_ci    .default_source = NULL,
6053a5a1b3Sopenharmony_ci    .default_server = NULL,
6153a5a1b3Sopenharmony_ci    .default_dbus_server = NULL,
6253a5a1b3Sopenharmony_ci    .cookie_file_from_env = NULL,
6353a5a1b3Sopenharmony_ci    .cookie_from_x11_valid = false,
6453a5a1b3Sopenharmony_ci    .cookie_file_from_application = NULL,
6553a5a1b3Sopenharmony_ci    .cookie_file_from_client_conf = NULL,
6653a5a1b3Sopenharmony_ci    .autospawn = true,
6753a5a1b3Sopenharmony_ci    .disable_shm = false,
6853a5a1b3Sopenharmony_ci    .disable_memfd = false,
6953a5a1b3Sopenharmony_ci    .shm_size = 0,
7053a5a1b3Sopenharmony_ci    .auto_connect_localhost = false,
7153a5a1b3Sopenharmony_ci    .auto_connect_display = false
7253a5a1b3Sopenharmony_ci};
7353a5a1b3Sopenharmony_ci
7453a5a1b3Sopenharmony_cipa_client_conf *pa_client_conf_new(void) {
7553a5a1b3Sopenharmony_ci    pa_client_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf));
7653a5a1b3Sopenharmony_ci
7753a5a1b3Sopenharmony_ci    c->daemon_binary = pa_xstrdup(PA_BINARY);
7853a5a1b3Sopenharmony_ci    c->extra_arguments = pa_xstrdup("--log-target=syslog");
7953a5a1b3Sopenharmony_ci
8053a5a1b3Sopenharmony_ci    return c;
8153a5a1b3Sopenharmony_ci}
8253a5a1b3Sopenharmony_ci
8353a5a1b3Sopenharmony_civoid pa_client_conf_free(pa_client_conf *c) {
8453a5a1b3Sopenharmony_ci    pa_assert(c);
8553a5a1b3Sopenharmony_ci    pa_xfree(c->daemon_binary);
8653a5a1b3Sopenharmony_ci    pa_xfree(c->extra_arguments);
8753a5a1b3Sopenharmony_ci    pa_xfree(c->default_sink);
8853a5a1b3Sopenharmony_ci    pa_xfree(c->default_source);
8953a5a1b3Sopenharmony_ci    pa_xfree(c->default_server);
9053a5a1b3Sopenharmony_ci    pa_xfree(c->default_dbus_server);
9153a5a1b3Sopenharmony_ci    pa_xfree(c->cookie_file_from_env);
9253a5a1b3Sopenharmony_ci    pa_xfree(c->cookie_file_from_application);
9353a5a1b3Sopenharmony_ci    pa_xfree(c->cookie_file_from_client_conf);
9453a5a1b3Sopenharmony_ci    pa_xfree(c);
9553a5a1b3Sopenharmony_ci}
9653a5a1b3Sopenharmony_ci
9753a5a1b3Sopenharmony_cistatic void load_env(pa_client_conf *c) {
9853a5a1b3Sopenharmony_ci    char *e;
9953a5a1b3Sopenharmony_ci
10053a5a1b3Sopenharmony_ci    if ((e = getenv(ENV_DEFAULT_SINK))) {
10153a5a1b3Sopenharmony_ci        pa_xfree(c->default_sink);
10253a5a1b3Sopenharmony_ci        c->default_sink = pa_xstrdup(e);
10353a5a1b3Sopenharmony_ci    }
10453a5a1b3Sopenharmony_ci
10553a5a1b3Sopenharmony_ci    if ((e = getenv(ENV_DEFAULT_SOURCE))) {
10653a5a1b3Sopenharmony_ci        pa_xfree(c->default_source);
10753a5a1b3Sopenharmony_ci        c->default_source = pa_xstrdup(e);
10853a5a1b3Sopenharmony_ci    }
10953a5a1b3Sopenharmony_ci
11053a5a1b3Sopenharmony_ci    if ((e = getenv(ENV_DEFAULT_SERVER))) {
11153a5a1b3Sopenharmony_ci        pa_xfree(c->default_server);
11253a5a1b3Sopenharmony_ci        c->default_server = pa_xstrdup(e);
11353a5a1b3Sopenharmony_ci
11453a5a1b3Sopenharmony_ci        /* We disable autospawning automatically if a specific server was set */
11553a5a1b3Sopenharmony_ci        c->autospawn = false;
11653a5a1b3Sopenharmony_ci    }
11753a5a1b3Sopenharmony_ci
11853a5a1b3Sopenharmony_ci    if ((e = getenv(ENV_DAEMON_BINARY))) {
11953a5a1b3Sopenharmony_ci        pa_xfree(c->daemon_binary);
12053a5a1b3Sopenharmony_ci        c->daemon_binary = pa_xstrdup(e);
12153a5a1b3Sopenharmony_ci    }
12253a5a1b3Sopenharmony_ci
12353a5a1b3Sopenharmony_ci    if ((e = getenv(ENV_COOKIE_FILE)) && *e) {
12453a5a1b3Sopenharmony_ci        pa_xfree(c->cookie_file_from_env);
12553a5a1b3Sopenharmony_ci        c->cookie_file_from_env = pa_xstrdup(e);
12653a5a1b3Sopenharmony_ci    }
12753a5a1b3Sopenharmony_ci}
12853a5a1b3Sopenharmony_ci
12953a5a1b3Sopenharmony_civoid pa_client_conf_load(pa_client_conf *c, bool load_from_x11, bool load_from_env) {
13053a5a1b3Sopenharmony_ci    FILE *f = NULL;
13153a5a1b3Sopenharmony_ci    char *fn = NULL;
13253a5a1b3Sopenharmony_ci
13353a5a1b3Sopenharmony_ci    /* Prepare the configuration parse table */
13453a5a1b3Sopenharmony_ci    pa_config_item table[] = {
13553a5a1b3Sopenharmony_ci        { "daemon-binary",          pa_config_parse_string,   &c->daemon_binary, NULL },
13653a5a1b3Sopenharmony_ci        { "extra-arguments",        pa_config_parse_string,   &c->extra_arguments, NULL },
13753a5a1b3Sopenharmony_ci        { "default-sink",           pa_config_parse_string,   &c->default_sink, NULL },
13853a5a1b3Sopenharmony_ci        { "default-source",         pa_config_parse_string,   &c->default_source, NULL },
13953a5a1b3Sopenharmony_ci        { "default-server",         pa_config_parse_string,   &c->default_server, NULL },
14053a5a1b3Sopenharmony_ci        { "default-dbus-server",    pa_config_parse_string,   &c->default_dbus_server, NULL },
14153a5a1b3Sopenharmony_ci        { "autospawn",              pa_config_parse_bool,     &c->autospawn, NULL },
14253a5a1b3Sopenharmony_ci        { "cookie-file",            pa_config_parse_string,   &c->cookie_file_from_client_conf, NULL },
14353a5a1b3Sopenharmony_ci        { "disable-shm",            pa_config_parse_bool,     &c->disable_shm, NULL },
14453a5a1b3Sopenharmony_ci        { "enable-shm",             pa_config_parse_not_bool, &c->disable_shm, NULL },
14553a5a1b3Sopenharmony_ci        { "enable-memfd",           pa_config_parse_not_bool, &c->disable_memfd, NULL },
14653a5a1b3Sopenharmony_ci        { "shm-size-bytes",         pa_config_parse_size,     &c->shm_size, NULL },
14753a5a1b3Sopenharmony_ci        { "auto-connect-localhost", pa_config_parse_bool,     &c->auto_connect_localhost, NULL },
14853a5a1b3Sopenharmony_ci        { "auto-connect-display",   pa_config_parse_bool,     &c->auto_connect_display, NULL },
14953a5a1b3Sopenharmony_ci        { NULL,                     NULL,                     NULL, NULL },
15053a5a1b3Sopenharmony_ci    };
15153a5a1b3Sopenharmony_ci
15253a5a1b3Sopenharmony_ci    f = pa_open_config_file(DEFAULT_CLIENT_CONFIG_FILE, DEFAULT_CLIENT_CONFIG_FILE_USER, ENV_CLIENT_CONFIG_FILE, &fn);
15353a5a1b3Sopenharmony_ci    if (f) {
15453a5a1b3Sopenharmony_ci        pa_config_parse(fn, f, table, NULL, true, NULL);
15553a5a1b3Sopenharmony_ci        pa_xfree(fn);
15653a5a1b3Sopenharmony_ci        fclose(f);
15753a5a1b3Sopenharmony_ci    }
15853a5a1b3Sopenharmony_ci
15953a5a1b3Sopenharmony_ci    if (load_from_x11) {
16053a5a1b3Sopenharmony_ci#ifdef HAVE_X11
16153a5a1b3Sopenharmony_ci        pa_client_conf_from_x11(c);
16253a5a1b3Sopenharmony_ci#endif
16353a5a1b3Sopenharmony_ci    }
16453a5a1b3Sopenharmony_ci
16553a5a1b3Sopenharmony_ci    if (load_from_env)
16653a5a1b3Sopenharmony_ci        load_env(c);
16753a5a1b3Sopenharmony_ci}
16853a5a1b3Sopenharmony_ci
16953a5a1b3Sopenharmony_ciint pa_client_conf_load_cookie(pa_client_conf *c, uint8_t *cookie, size_t cookie_length) {
17053a5a1b3Sopenharmony_ci    int r;
17153a5a1b3Sopenharmony_ci    char *fallback_path;
17253a5a1b3Sopenharmony_ci
17353a5a1b3Sopenharmony_ci    pa_assert(c);
17453a5a1b3Sopenharmony_ci    pa_assert(cookie);
17553a5a1b3Sopenharmony_ci    pa_assert(cookie_length > 0);
17653a5a1b3Sopenharmony_ci
17753a5a1b3Sopenharmony_ci    if (c->cookie_file_from_env) {
17853a5a1b3Sopenharmony_ci        r = pa_authkey_load(c->cookie_file_from_env, true, cookie, cookie_length);
17953a5a1b3Sopenharmony_ci        if (r >= 0)
18053a5a1b3Sopenharmony_ci            return 0;
18153a5a1b3Sopenharmony_ci
18253a5a1b3Sopenharmony_ci        pa_log_warn("Failed to load cookie from %s (configured with environment variable PULSE_COOKIE): %s",
18353a5a1b3Sopenharmony_ci                    c->cookie_file_from_env, pa_cstrerror(errno));
18453a5a1b3Sopenharmony_ci    }
18553a5a1b3Sopenharmony_ci
18653a5a1b3Sopenharmony_ci    if (c->cookie_from_x11_valid) {
18753a5a1b3Sopenharmony_ci        if (cookie_length == sizeof(c->cookie_from_x11)) {
18853a5a1b3Sopenharmony_ci            memcpy(cookie, c->cookie_from_x11, cookie_length);
18953a5a1b3Sopenharmony_ci            return 0;
19053a5a1b3Sopenharmony_ci        }
19153a5a1b3Sopenharmony_ci
19253a5a1b3Sopenharmony_ci        pa_log_warn("Failed to load cookie from X11 root window property PULSE_COOKIE: size mismatch.");
19353a5a1b3Sopenharmony_ci    }
19453a5a1b3Sopenharmony_ci
19553a5a1b3Sopenharmony_ci    if (c->cookie_file_from_application) {
19653a5a1b3Sopenharmony_ci        r = pa_authkey_load(c->cookie_file_from_application, true, cookie, cookie_length);
19753a5a1b3Sopenharmony_ci        if (r >= 0)
19853a5a1b3Sopenharmony_ci            return 0;
19953a5a1b3Sopenharmony_ci
20053a5a1b3Sopenharmony_ci        pa_log_warn("Failed to load cookie from %s (configured by the application): %s", c->cookie_file_from_application,
20153a5a1b3Sopenharmony_ci                    pa_cstrerror(errno));
20253a5a1b3Sopenharmony_ci    }
20353a5a1b3Sopenharmony_ci
20453a5a1b3Sopenharmony_ci    if (c->cookie_file_from_client_conf) {
20553a5a1b3Sopenharmony_ci        r = pa_authkey_load(c->cookie_file_from_client_conf, true, cookie, cookie_length);
20653a5a1b3Sopenharmony_ci        if (r >= 0)
20753a5a1b3Sopenharmony_ci            return 0;
20853a5a1b3Sopenharmony_ci
20953a5a1b3Sopenharmony_ci        pa_log_warn("Failed to load cookie from %s (configured in client.conf): %s", c->cookie_file_from_client_conf,
21053a5a1b3Sopenharmony_ci                    pa_cstrerror(errno));
21153a5a1b3Sopenharmony_ci    }
21253a5a1b3Sopenharmony_ci
21353a5a1b3Sopenharmony_ci    r = pa_authkey_load(PA_NATIVE_COOKIE_FILE, false, cookie, cookie_length);
21453a5a1b3Sopenharmony_ci    if (r >= 0)
21553a5a1b3Sopenharmony_ci        return 0;
21653a5a1b3Sopenharmony_ci
21753a5a1b3Sopenharmony_ci    if (pa_append_to_home_dir(PA_NATIVE_COOKIE_FILE_FALLBACK, &fallback_path) >= 0) {
21853a5a1b3Sopenharmony_ci        r = pa_authkey_load(fallback_path, false, cookie, cookie_length);
21953a5a1b3Sopenharmony_ci        pa_xfree(fallback_path);
22053a5a1b3Sopenharmony_ci        if (r >= 0)
22153a5a1b3Sopenharmony_ci            return 0;
22253a5a1b3Sopenharmony_ci    }
22353a5a1b3Sopenharmony_ci
22453a5a1b3Sopenharmony_ci    r = pa_authkey_load(PA_NATIVE_COOKIE_FILE, true, cookie, cookie_length);
22553a5a1b3Sopenharmony_ci    if (r >= 0)
22653a5a1b3Sopenharmony_ci        return 0;
22753a5a1b3Sopenharmony_ci
22853a5a1b3Sopenharmony_ci    pa_log("Failed to load cookie file from %s: %s", PA_NATIVE_COOKIE_FILE, pa_cstrerror(errno));
22953a5a1b3Sopenharmony_ci    memset(cookie, 0, cookie_length);
23053a5a1b3Sopenharmony_ci
23153a5a1b3Sopenharmony_ci    return -1;
23253a5a1b3Sopenharmony_ci}
23353a5a1b3Sopenharmony_ci
23453a5a1b3Sopenharmony_civoid pa_client_conf_set_cookie_file_from_application(pa_client_conf *c, const char *cookie_file) {
23553a5a1b3Sopenharmony_ci    pa_assert(c);
23653a5a1b3Sopenharmony_ci    pa_assert(!cookie_file || *cookie_file);
23753a5a1b3Sopenharmony_ci
23853a5a1b3Sopenharmony_ci    pa_xfree(c->cookie_file_from_application);
23953a5a1b3Sopenharmony_ci    c->cookie_file_from_application = pa_xstrdup(cookie_file);
24053a5a1b3Sopenharmony_ci}
241