1/*** 2 This file is part of PulseAudio. 3 4 Copyright 2004-2006 Lennart Poettering 5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB 6 7 PulseAudio is free software; you can redistribute it and/or modify 8 it under the terms of the GNU Lesser General Public License as published 9 by the Free Software Foundation; either version 2.1 of the License, 10 or (at your option) any later version. 11 12 PulseAudio is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 General Public License for more details. 16 17 You should have received a copy of the GNU Lesser General Public License 18 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 19***/ 20 21#ifdef HAVE_CONFIG_H 22#include <config.h> 23#endif 24 25#include <stdlib.h> 26#include <unistd.h> 27#include <errno.h> 28 29#include <pulse/xmalloc.h> 30 31#include <pulsecore/i18n.h> 32#include <pulsecore/macro.h> 33#include <pulsecore/core-error.h> 34#include <pulsecore/log.h> 35#include <pulsecore/conf-parser.h> 36#include <pulsecore/core-util.h> 37#include <pulsecore/authkey.h> 38 39#include "client-conf.h" 40 41#ifdef HAVE_X11 42#include <pulse/client-conf-x11.h> 43#endif 44 45#define DEFAULT_CLIENT_CONFIG_FILE PA_DEFAULT_CONFIG_DIR PA_PATH_SEP "client.conf" 46#define DEFAULT_CLIENT_CONFIG_FILE_USER "client.conf" 47 48#define ENV_CLIENT_CONFIG_FILE "PULSE_CLIENTCONFIG" 49#define ENV_DEFAULT_SINK "PULSE_SINK" 50#define ENV_DEFAULT_SOURCE "PULSE_SOURCE" 51#define ENV_DEFAULT_SERVER "PULSE_SERVER" 52#define ENV_DAEMON_BINARY "PULSE_BINARY" 53#define ENV_COOKIE_FILE "PULSE_COOKIE" 54 55static const pa_client_conf default_conf = { 56 .daemon_binary = NULL, 57 .extra_arguments = NULL, 58 .default_sink = NULL, 59 .default_source = NULL, 60 .default_server = NULL, 61 .default_dbus_server = NULL, 62 .cookie_file_from_env = NULL, 63 .cookie_from_x11_valid = false, 64 .cookie_file_from_application = NULL, 65 .cookie_file_from_client_conf = NULL, 66 .autospawn = true, 67 .disable_shm = false, 68 .disable_memfd = false, 69 .shm_size = 0, 70 .auto_connect_localhost = false, 71 .auto_connect_display = false 72}; 73 74pa_client_conf *pa_client_conf_new(void) { 75 pa_client_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); 76 77 c->daemon_binary = pa_xstrdup(PA_BINARY); 78 c->extra_arguments = pa_xstrdup("--log-target=syslog"); 79 80 return c; 81} 82 83void pa_client_conf_free(pa_client_conf *c) { 84 pa_assert(c); 85 pa_xfree(c->daemon_binary); 86 pa_xfree(c->extra_arguments); 87 pa_xfree(c->default_sink); 88 pa_xfree(c->default_source); 89 pa_xfree(c->default_server); 90 pa_xfree(c->default_dbus_server); 91 pa_xfree(c->cookie_file_from_env); 92 pa_xfree(c->cookie_file_from_application); 93 pa_xfree(c->cookie_file_from_client_conf); 94 pa_xfree(c); 95} 96 97static void load_env(pa_client_conf *c) { 98 char *e; 99 100 if ((e = getenv(ENV_DEFAULT_SINK))) { 101 pa_xfree(c->default_sink); 102 c->default_sink = pa_xstrdup(e); 103 } 104 105 if ((e = getenv(ENV_DEFAULT_SOURCE))) { 106 pa_xfree(c->default_source); 107 c->default_source = pa_xstrdup(e); 108 } 109 110 if ((e = getenv(ENV_DEFAULT_SERVER))) { 111 pa_xfree(c->default_server); 112 c->default_server = pa_xstrdup(e); 113 114 /* We disable autospawning automatically if a specific server was set */ 115 c->autospawn = false; 116 } 117 118 if ((e = getenv(ENV_DAEMON_BINARY))) { 119 pa_xfree(c->daemon_binary); 120 c->daemon_binary = pa_xstrdup(e); 121 } 122 123 if ((e = getenv(ENV_COOKIE_FILE)) && *e) { 124 pa_xfree(c->cookie_file_from_env); 125 c->cookie_file_from_env = pa_xstrdup(e); 126 } 127} 128 129void pa_client_conf_load(pa_client_conf *c, bool load_from_x11, bool load_from_env) { 130 FILE *f = NULL; 131 char *fn = NULL; 132 133 /* Prepare the configuration parse table */ 134 pa_config_item table[] = { 135 { "daemon-binary", pa_config_parse_string, &c->daemon_binary, NULL }, 136 { "extra-arguments", pa_config_parse_string, &c->extra_arguments, NULL }, 137 { "default-sink", pa_config_parse_string, &c->default_sink, NULL }, 138 { "default-source", pa_config_parse_string, &c->default_source, NULL }, 139 { "default-server", pa_config_parse_string, &c->default_server, NULL }, 140 { "default-dbus-server", pa_config_parse_string, &c->default_dbus_server, NULL }, 141 { "autospawn", pa_config_parse_bool, &c->autospawn, NULL }, 142 { "cookie-file", pa_config_parse_string, &c->cookie_file_from_client_conf, NULL }, 143 { "disable-shm", pa_config_parse_bool, &c->disable_shm, NULL }, 144 { "enable-shm", pa_config_parse_not_bool, &c->disable_shm, NULL }, 145 { "enable-memfd", pa_config_parse_not_bool, &c->disable_memfd, NULL }, 146 { "shm-size-bytes", pa_config_parse_size, &c->shm_size, NULL }, 147 { "auto-connect-localhost", pa_config_parse_bool, &c->auto_connect_localhost, NULL }, 148 { "auto-connect-display", pa_config_parse_bool, &c->auto_connect_display, NULL }, 149 { NULL, NULL, NULL, NULL }, 150 }; 151 152 f = pa_open_config_file(DEFAULT_CLIENT_CONFIG_FILE, DEFAULT_CLIENT_CONFIG_FILE_USER, ENV_CLIENT_CONFIG_FILE, &fn); 153 if (f) { 154 pa_config_parse(fn, f, table, NULL, true, NULL); 155 pa_xfree(fn); 156 fclose(f); 157 } 158 159 if (load_from_x11) { 160#ifdef HAVE_X11 161 pa_client_conf_from_x11(c); 162#endif 163 } 164 165 if (load_from_env) 166 load_env(c); 167} 168 169int pa_client_conf_load_cookie(pa_client_conf *c, uint8_t *cookie, size_t cookie_length) { 170 int r; 171 char *fallback_path; 172 173 pa_assert(c); 174 pa_assert(cookie); 175 pa_assert(cookie_length > 0); 176 177 if (c->cookie_file_from_env) { 178 r = pa_authkey_load(c->cookie_file_from_env, true, cookie, cookie_length); 179 if (r >= 0) 180 return 0; 181 182 pa_log_warn("Failed to load cookie from %s (configured with environment variable PULSE_COOKIE): %s", 183 c->cookie_file_from_env, pa_cstrerror(errno)); 184 } 185 186 if (c->cookie_from_x11_valid) { 187 if (cookie_length == sizeof(c->cookie_from_x11)) { 188 memcpy(cookie, c->cookie_from_x11, cookie_length); 189 return 0; 190 } 191 192 pa_log_warn("Failed to load cookie from X11 root window property PULSE_COOKIE: size mismatch."); 193 } 194 195 if (c->cookie_file_from_application) { 196 r = pa_authkey_load(c->cookie_file_from_application, true, cookie, cookie_length); 197 if (r >= 0) 198 return 0; 199 200 pa_log_warn("Failed to load cookie from %s (configured by the application): %s", c->cookie_file_from_application, 201 pa_cstrerror(errno)); 202 } 203 204 if (c->cookie_file_from_client_conf) { 205 r = pa_authkey_load(c->cookie_file_from_client_conf, true, cookie, cookie_length); 206 if (r >= 0) 207 return 0; 208 209 pa_log_warn("Failed to load cookie from %s (configured in client.conf): %s", c->cookie_file_from_client_conf, 210 pa_cstrerror(errno)); 211 } 212 213 r = pa_authkey_load(PA_NATIVE_COOKIE_FILE, false, cookie, cookie_length); 214 if (r >= 0) 215 return 0; 216 217 if (pa_append_to_home_dir(PA_NATIVE_COOKIE_FILE_FALLBACK, &fallback_path) >= 0) { 218 r = pa_authkey_load(fallback_path, false, cookie, cookie_length); 219 pa_xfree(fallback_path); 220 if (r >= 0) 221 return 0; 222 } 223 224 r = pa_authkey_load(PA_NATIVE_COOKIE_FILE, true, cookie, cookie_length); 225 if (r >= 0) 226 return 0; 227 228 pa_log("Failed to load cookie file from %s: %s", PA_NATIVE_COOKIE_FILE, pa_cstrerror(errno)); 229 memset(cookie, 0, cookie_length); 230 231 return -1; 232} 233 234void pa_client_conf_set_cookie_file_from_application(pa_client_conf *c, const char *cookie_file) { 235 pa_assert(c); 236 pa_assert(!cookie_file || *cookie_file); 237 238 pa_xfree(c->cookie_file_from_application); 239 c->cookie_file_from_application = pa_xstrdup(cookie_file); 240} 241