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 <errno.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 
29 #ifdef HAVE_NETINET_IN_H
30 #include <netinet/in.h>
31 #endif
32 
33 #include <pulse/xmalloc.h>
34 
35 #include <pulsecore/core-error.h>
36 #include <pulsecore/module.h>
37 #include <pulsecore/socket.h>
38 #include <pulsecore/socket-server.h>
39 #include <pulsecore/socket-util.h>
40 #include <pulsecore/core-util.h>
41 #include <pulsecore/modargs.h>
42 #include <pulsecore/log.h>
43 #include <pulsecore/native-common.h>
44 #include <pulsecore/creds.h>
45 #include <pulsecore/arpa-inet.h>
46 
47 #ifdef USE_TCP_SOCKETS
48 #define SOCKET_DESCRIPTION "(TCP sockets)"
49 #define SOCKET_USAGE "port=<TCP port number> listen=<address to listen on>"
50 #else
51 #define SOCKET_DESCRIPTION "(UNIX sockets)"
52 #define SOCKET_USAGE "socket=<path to UNIX socket>"
53 #endif
54 
55 #if defined(USE_PROTOCOL_SIMPLE)
56 #  include <pulsecore/protocol-simple.h>
57 #  define TCPWRAP_SERVICE "pulseaudio-simple"
58 #  define IPV4_PORT 4711
59 #  define UNIX_SOCKET "simple"
60 #  define MODULE_ARGUMENTS "rate", "format", "channels", "sink", "source", "playback", "record",
61 
62   PA_MODULE_DESCRIPTION("Simple protocol "SOCKET_DESCRIPTION);
63   PA_MODULE_USAGE("rate=<sample rate> "
64                   "format=<sample format> "
65                   "channels=<number of channels> "
66                   "sink=<sink to connect to> "
67                   "source=<source to connect to> "
68                   "playback=<enable playback?> "
69                   "record=<enable record?> "
70                   SOCKET_USAGE);
71 #elif defined(USE_PROTOCOL_CLI)
72 #  include <pulsecore/protocol-cli.h>
73 #  define TCPWRAP_SERVICE "pulseaudio-cli"
74 #  define IPV4_PORT 4712
75 #  define UNIX_SOCKET "cli"
76 #  define MODULE_ARGUMENTS
77 
78   PA_MODULE_DESCRIPTION("Command line interface protocol "SOCKET_DESCRIPTION);
79   PA_MODULE_USAGE(SOCKET_USAGE);
80 #elif defined(USE_PROTOCOL_HTTP)
81 #  include <pulsecore/protocol-http.h>
82 #  define TCPWRAP_SERVICE "pulseaudio-http"
83 #  define IPV4_PORT 4714
84 #  define UNIX_SOCKET "http"
85 #  define MODULE_ARGUMENTS
86 
87   PA_MODULE_DESCRIPTION("HTTP "SOCKET_DESCRIPTION);
88   PA_MODULE_USAGE(SOCKET_USAGE);
89 #elif defined(USE_PROTOCOL_NATIVE)
90 #  include <pulsecore/protocol-native.h>
91 #  define TCPWRAP_SERVICE "pulseaudio-native"
92 #  define IPV4_PORT PA_NATIVE_DEFAULT_PORT
93 #  define UNIX_SOCKET PA_NATIVE_DEFAULT_UNIX_SOCKET
94 #  define MODULE_ARGUMENTS_COMMON "cookie", "auth-cookie", "auth-cookie-enabled", "auth-anonymous",
95 
96 #  if defined(HAVE_CREDS) && !defined(USE_TCP_SOCKETS)
97 #    define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-group", "auth-group-enable", "srbchannel",
98 #    define AUTH_USAGE "auth-group=<system group to allow access> auth-group-enable=<enable auth by UNIX group?> "
99 #    define SRB_USAGE "srbchannel=<enable shared ringbuffer communication channel?> "
100 #  elif defined(USE_TCP_SOCKETS)
101 #    define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-ip-acl",
102 #    define AUTH_USAGE "auth-ip-acl=<IP address ACL to allow access> "
103 #    define SRB_USAGE
104 #  else
105 #    define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON
106 #    define AUTH_USAGE
107 #    define SRB_USAGE
108 #    endif
109 
110   PA_MODULE_DESCRIPTION("Native protocol "SOCKET_DESCRIPTION);
111   PA_MODULE_USAGE("auth-anonymous=<don't check for cookies?> "
112                   "auth-cookie=<path to cookie file> "
113                   "auth-cookie-enabled=<enable cookie authentication?> "
114                   AUTH_USAGE
115                   SRB_USAGE
116                   SOCKET_USAGE);
117 #elif defined(USE_PROTOCOL_ESOUND)
118 #  include <pulsecore/protocol-esound.h>
119 #  include <pulsecore/esound.h>
120 #  define TCPWRAP_SERVICE "esound"
121 #  define IPV4_PORT ESD_DEFAULT_PORT
122 #  define MODULE_ARGUMENTS_COMMON "sink", "source", "auth-anonymous", "cookie", "auth-cookie", "auth-cookie-enabled",
123 
124 #  if defined(USE_TCP_SOCKETS)
125 #    define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-ip-acl",
126 #    define AUTH_USAGE "auth-ip-acl=<IP address ACL to allow access> "
127 #  else
128 #    define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON
129 #    define AUTH_USAGE
130 #  endif
131 
132   PA_MODULE_DESCRIPTION("ESOUND protocol "SOCKET_DESCRIPTION);
133   PA_MODULE_USAGE("sink=<sink to connect to> "
134                   "source=<source to connect to> "
135                   "auth-anonymous=<don't verify cookies?> "
136                   "auth-cookie=<path to cookie file> "
137                   "auth-cookie-enabled=<enable cookie authentication?> "
138                   AUTH_USAGE
139                   SOCKET_USAGE);
140 #else
141 #  error "Broken build system"
142 #endif
143 
144 PA_MODULE_LOAD_ONCE(false);
145 PA_MODULE_AUTHOR("Lennart Poettering");
146 PA_MODULE_VERSION(PACKAGE_VERSION);
147 
148 static const char* const valid_modargs[] = {
149     MODULE_ARGUMENTS
150 #if defined(USE_TCP_SOCKETS)
151     "port",
152     "listen",
153 #else
154     "socket",
155 #endif
156     NULL
157 };
158 
159 struct userdata {
160     pa_module *module;
161 
162 #if defined(USE_PROTOCOL_SIMPLE)
163     pa_simple_protocol *simple_protocol;
164     pa_simple_options *simple_options;
165 #elif defined(USE_PROTOCOL_CLI)
166     pa_cli_protocol *cli_protocol;
167 #elif defined(USE_PROTOCOL_HTTP)
168     pa_http_protocol *http_protocol;
169 #elif defined(USE_PROTOCOL_NATIVE)
170     pa_native_protocol *native_protocol;
171     pa_native_options *native_options;
172 #else
173     pa_esound_protocol *esound_protocol;
174     pa_esound_options *esound_options;
175 #endif
176 
177 #if defined(USE_TCP_SOCKETS)
178     pa_socket_server *socket_server_ipv4;
179 #  ifdef HAVE_IPV6
180     pa_socket_server *socket_server_ipv6;
181 #  endif
182 #else
183     pa_socket_server *socket_server_unix;
184     char *socket_path;
185 #endif
186 };
187 
socket_server_on_connection_cb(pa_socket_server*s, pa_iochannel *io, void *userdata)188 static void socket_server_on_connection_cb(pa_socket_server*s, pa_iochannel *io, void *userdata) {
189     struct userdata *u = userdata;
190 
191     pa_assert(s);
192     pa_assert(io);
193     pa_assert(u);
194 
195 #if defined(USE_PROTOCOL_SIMPLE)
196     pa_simple_protocol_connect(u->simple_protocol, io, u->simple_options);
197 #elif defined(USE_PROTOCOL_CLI)
198     pa_cli_protocol_connect(u->cli_protocol, io, u->module);
199 #elif defined(USE_PROTOCOL_HTTP)
200     pa_http_protocol_connect(u->http_protocol, io, u->module);
201 #elif defined(USE_PROTOCOL_NATIVE)
202     pa_native_protocol_connect(u->native_protocol, io, u->native_options);
203 #else
204     pa_esound_protocol_connect(u->esound_protocol, io, u->esound_options);
205 #endif
206 }
207 
pa__init(pa_module*m)208 int pa__init(pa_module*m) {
209     pa_modargs *ma = NULL;
210     struct userdata *u = NULL;
211 
212 #if defined(USE_TCP_SOCKETS)
213     uint32_t port = IPV4_PORT;
214     bool port_fallback = true;
215     const char *listen_on;
216 #else
217     int r;
218 #endif
219 
220 #if defined(USE_PROTOCOL_NATIVE) || defined(USE_PROTOCOL_HTTP)
221     char t[256];
222 #endif
223 
224     pa_assert(m);
225 
226     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
227         pa_log("Failed to parse module arguments");
228         goto fail;
229     }
230 
231     m->userdata = u = pa_xnew0(struct userdata, 1);
232     u->module = m;
233 
234 #if defined(USE_PROTOCOL_SIMPLE)
235     u->simple_protocol = pa_simple_protocol_get(m->core);
236 
237     u->simple_options = pa_simple_options_new();
238     if (pa_simple_options_parse(u->simple_options, m->core, ma) < 0)
239         goto fail;
240     u->simple_options->module = m;
241 #elif defined(USE_PROTOCOL_CLI)
242     u->cli_protocol = pa_cli_protocol_get(m->core);
243 #elif defined(USE_PROTOCOL_HTTP)
244     u->http_protocol = pa_http_protocol_get(m->core);
245 #elif defined(USE_PROTOCOL_NATIVE)
246     u->native_protocol = pa_native_protocol_get(m->core);
247 
248     u->native_options = pa_native_options_new();
249     if (pa_native_options_parse(u->native_options, m->core, ma) < 0)
250         goto fail;
251     u->native_options->module = m;
252 #else
253     u->esound_protocol = pa_esound_protocol_get(m->core);
254 
255     u->esound_options = pa_esound_options_new();
256     if (pa_esound_options_parse(u->esound_options, m->core, ma) < 0)
257         goto fail;
258     u->esound_options->module = m;
259 #endif
260 
261 #if defined(USE_TCP_SOCKETS)
262 
263     if (pa_in_system_mode() || pa_modargs_get_value(ma, "port", NULL))
264         port_fallback = false;
265 
266     if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port < 1 || port > 0xFFFF) {
267         pa_log("port= expects a numerical argument between 1 and 65535.");
268         goto fail;
269     }
270 
271     listen_on = pa_modargs_get_value(ma, "listen", NULL);
272 
273     if (listen_on) {
274 #  ifdef HAVE_IPV6
275         u->socket_server_ipv6 = pa_socket_server_new_ipv6_string(m->core->mainloop, listen_on, (uint16_t) port, port_fallback, TCPWRAP_SERVICE);
276 #  endif
277         u->socket_server_ipv4 = pa_socket_server_new_ipv4_string(m->core->mainloop, listen_on, (uint16_t) port, port_fallback, TCPWRAP_SERVICE);
278     } else {
279 #  ifdef HAVE_IPV6
280         u->socket_server_ipv6 = pa_socket_server_new_ipv6_any(m->core->mainloop, (uint16_t) port, port_fallback, TCPWRAP_SERVICE);
281 #  endif
282         u->socket_server_ipv4 = pa_socket_server_new_ipv4_any(m->core->mainloop, (uint16_t) port, port_fallback, TCPWRAP_SERVICE);
283     }
284 
285 #  ifdef HAVE_IPV6
286     if (!u->socket_server_ipv4 && !u->socket_server_ipv6)
287 #  else
288     if (!u->socket_server_ipv4)
289 #  endif
290         goto fail;
291 
292     if (u->socket_server_ipv4)
293         pa_socket_server_set_callback(u->socket_server_ipv4, socket_server_on_connection_cb, u);
294 #  ifdef HAVE_IPV6
295     if (u->socket_server_ipv6)
296         pa_socket_server_set_callback(u->socket_server_ipv6, socket_server_on_connection_cb, u);
297 #  endif
298 
299 #else
300 
301 #  if defined(USE_PROTOCOL_ESOUND)
302 
303     /* Windows doesn't support getuid(), so we ignore the per-user Esound socket compile flag.
304      * Moreover, Esound Unix sockets haven't been supported on Windows historically. */
305 #    if defined(USE_PER_USER_ESOUND_SOCKET) && !defined(OS_IS_WIN32)
306     u->socket_path = pa_sprintf_malloc("/tmp/.esd-%lu/socket", (unsigned long) getuid());
307 #    else
308     u->socket_path = pa_xstrdup("/tmp/.esd/socket");
309 #    endif
310 
311     /* This socket doesn't reside in our own runtime dir but in
312      * /tmp/.esd/, hence we have to create the dir first */
313 
314     if (pa_make_secure_parent_dir(u->socket_path, pa_in_system_mode() ? 0755U : 0700U, (uid_t)-1, (gid_t)-1, false) < 0) {
315         pa_log("Failed to create socket directory '%s': %s\n", u->socket_path, pa_cstrerror(errno));
316         goto fail;
317     }
318 
319 #  else
320     if (!(u->socket_path = pa_runtime_path(pa_modargs_get_value(ma, "socket", UNIX_SOCKET)))) {
321         pa_log("Failed to generate socket path.");
322         goto fail;
323     }
324 #  endif
325 
326     if ((r = pa_unix_socket_remove_stale(u->socket_path)) < 0) {
327         pa_log("Failed to remove stale UNIX socket '%s': %s", u->socket_path, pa_cstrerror(errno));
328         goto fail;
329     } else if (r > 0)
330         pa_log_info("Removed stale UNIX socket '%s'.", u->socket_path);
331 
332     if (!(u->socket_server_unix = pa_socket_server_new_unix(m->core->mainloop, u->socket_path)))
333         goto fail;
334 
335     pa_socket_server_set_callback(u->socket_server_unix, socket_server_on_connection_cb, u);
336 
337 #endif
338 
339 #if defined(USE_PROTOCOL_NATIVE)
340 #  if defined(USE_TCP_SOCKETS)
341     if (u->socket_server_ipv4)
342         if (pa_socket_server_get_address(u->socket_server_ipv4, t, sizeof(t)))
343             pa_native_protocol_add_server_string(u->native_protocol, t);
344 
345 #    ifdef HAVE_IPV6
346     if (u->socket_server_ipv6)
347         if (pa_socket_server_get_address(u->socket_server_ipv6, t, sizeof(t)))
348             pa_native_protocol_add_server_string(u->native_protocol, t);
349 #    endif
350 #  else
351     if (pa_socket_server_get_address(u->socket_server_unix, t, sizeof(t)))
352         pa_native_protocol_add_server_string(u->native_protocol, t);
353 
354 #  endif
355 #endif
356 
357 #if defined(USE_PROTOCOL_HTTP)
358 #if defined(USE_TCP_SOCKETS)
359     if (u->socket_server_ipv4)
360         if (pa_socket_server_get_address(u->socket_server_ipv4, t, sizeof(t)))
361             pa_http_protocol_add_server_string(u->http_protocol, t);
362 
363 #ifdef HAVE_IPV6
364     if (u->socket_server_ipv6)
365         if (pa_socket_server_get_address(u->socket_server_ipv6, t, sizeof(t)))
366             pa_http_protocol_add_server_string(u->http_protocol, t);
367 #endif /* HAVE_IPV6 */
368 #else /* USE_TCP_SOCKETS */
369     if (pa_socket_server_get_address(u->socket_server_unix, t, sizeof(t)))
370         pa_http_protocol_add_server_string(u->http_protocol, t);
371 
372 #endif /* USE_TCP_SOCKETS */
373 #endif /* USE_PROTOCOL_HTTP */
374 
375     if (ma)
376         pa_modargs_free(ma);
377 
378     return 0;
379 
380 fail:
381 
382     if (ma)
383         pa_modargs_free(ma);
384 
385     pa__done(m);
386 
387     return -1;
388 }
389 
pa__done(pa_module*m)390 void pa__done(pa_module*m) {
391     struct userdata *u;
392 
393     pa_assert(m);
394 
395     if (!(u = m->userdata))
396         return;
397 
398 #if defined(USE_PROTOCOL_SIMPLE)
399     if (u->simple_protocol) {
400         pa_simple_protocol_disconnect(u->simple_protocol, u->module);
401         pa_simple_protocol_unref(u->simple_protocol);
402     }
403     if (u->simple_options)
404         pa_simple_options_unref(u->simple_options);
405 #elif defined(USE_PROTOCOL_CLI)
406     if (u->cli_protocol) {
407         pa_cli_protocol_disconnect(u->cli_protocol, u->module);
408         pa_cli_protocol_unref(u->cli_protocol);
409     }
410 #elif defined(USE_PROTOCOL_HTTP)
411     if (u->http_protocol) {
412         char t[256];
413 
414 #if defined(USE_TCP_SOCKETS)
415         if (u->socket_server_ipv4)
416             if (pa_socket_server_get_address(u->socket_server_ipv4, t, sizeof(t)))
417                 pa_http_protocol_remove_server_string(u->http_protocol, t);
418 
419 #ifdef HAVE_IPV6
420         if (u->socket_server_ipv6)
421             if (pa_socket_server_get_address(u->socket_server_ipv6, t, sizeof(t)))
422                 pa_http_protocol_remove_server_string(u->http_protocol, t);
423 #endif /* HAVE_IPV6 */
424 #else /* USE_TCP_SOCKETS */
425         if (u->socket_server_unix)
426             if (pa_socket_server_get_address(u->socket_server_unix, t, sizeof(t)))
427                 pa_http_protocol_remove_server_string(u->http_protocol, t);
428 #endif /* USE_PROTOCOL_HTTP */
429 
430         pa_http_protocol_disconnect(u->http_protocol, u->module);
431         pa_http_protocol_unref(u->http_protocol);
432     }
433 #elif defined(USE_PROTOCOL_NATIVE)
434     if (u->native_protocol) {
435 
436         char t[256];
437 
438 #  if defined(USE_TCP_SOCKETS)
439         if (u->socket_server_ipv4)
440             if (pa_socket_server_get_address(u->socket_server_ipv4, t, sizeof(t)))
441                 pa_native_protocol_remove_server_string(u->native_protocol, t);
442 
443 #    ifdef HAVE_IPV6
444         if (u->socket_server_ipv6)
445             if (pa_socket_server_get_address(u->socket_server_ipv6, t, sizeof(t)))
446                 pa_native_protocol_remove_server_string(u->native_protocol, t);
447 #    endif
448 #  else
449         if (u->socket_server_unix)
450             if (pa_socket_server_get_address(u->socket_server_unix, t, sizeof(t)))
451                 pa_native_protocol_remove_server_string(u->native_protocol, t);
452 #  endif
453 
454         pa_native_protocol_disconnect(u->native_protocol, u->module);
455         pa_native_protocol_unref(u->native_protocol);
456     }
457     if (u->native_options)
458         pa_native_options_unref(u->native_options);
459 #else
460     if (u->esound_protocol) {
461         pa_esound_protocol_disconnect(u->esound_protocol, u->module);
462         pa_esound_protocol_unref(u->esound_protocol);
463     }
464     if (u->esound_options)
465         pa_esound_options_unref(u->esound_options);
466 #endif
467 
468 #if defined(USE_TCP_SOCKETS)
469     if (u->socket_server_ipv4)
470         pa_socket_server_unref(u->socket_server_ipv4);
471 #  ifdef HAVE_IPV6
472     if (u->socket_server_ipv6)
473         pa_socket_server_unref(u->socket_server_ipv6);
474 #  endif
475 #else
476     if (u->socket_server_unix)
477         pa_socket_server_unref(u->socket_server_unix);
478 
479 # if defined(USE_PROTOCOL_ESOUND) && !defined(USE_PER_USER_ESOUND_SOCKET)
480     if (u->socket_path) {
481         char *p = pa_parent_dir(u->socket_path);
482         rmdir(p);
483         pa_xfree(p);
484     }
485 # endif
486 
487     pa_xfree(u->socket_path);
488 #endif
489 
490     pa_xfree(u);
491 }
492