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
55 static 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
pa_client_conf_new(void)74 pa_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
pa_client_conf_free(pa_client_conf * c)83 void 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
load_env(pa_client_conf * c)97 static 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
pa_client_conf_load(pa_client_conf * c,bool load_from_x11,bool load_from_env)129 void 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
pa_client_conf_load_cookie(pa_client_conf * c,uint8_t * cookie,size_t cookie_length)169 int 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
pa_client_conf_set_cookie_file_from_application(pa_client_conf * c,const char * cookie_file)234 void 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