#include <pulsecore/llist.h>
#include <pulsecore/creds.h>
#include <pulsecore/core-util.h>
+#include <pulsecore/ipacl.h>
#include "protocol-native.h"
#ifdef HAVE_CREDS
char *auth_group;
#endif
+ pa_ip_acl *auth_ip_acl;
};
static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk);
static void command_get_autoload_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
+static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
[PA_COMMAND_ERROR] = NULL,
[PA_COMMAND_GET_AUTOLOAD_INFO] = command_get_autoload_info,
[PA_COMMAND_GET_AUTOLOAD_INFO_LIST] = command_get_autoload_info_list,
[PA_COMMAND_ADD_AUTOLOAD] = command_add_autoload,
- [PA_COMMAND_REMOVE_AUTOLOAD] = command_remove_autoload
+ [PA_COMMAND_REMOVE_AUTOLOAD] = command_remove_autoload,
+
+ [PA_COMMAND_MOVE_SINK_INPUT] = command_move_stream,
+ [PA_COMMAND_MOVE_SOURCE_OUTPUT] = command_move_stream
};
/* structure management */
}
#endif
- if (memcmp(c->protocol->auth_cookie, cookie, PA_NATIVE_COOKIE_LENGTH) == 0)
+ if (!success && memcmp(c->protocol->auth_cookie, cookie, PA_NATIVE_COOKIE_LENGTH) == 0)
success = 1;
if (!success) {
pa_tagstruct_put_usec(reply, latency);
pa_tagstruct_put_usec(reply, 0);
- pa_tagstruct_put_boolean(reply, pa_memblockq_is_readable(s->memblockq));
+ pa_tagstruct_put_boolean(reply, s->sink_input->state == PA_SINK_INPUT_RUNNING);
pa_tagstruct_put_timeval(reply, &tv);
pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq));
pa_pstream_send_tagstruct(c->pstream, reply);
}
+static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
+ struct connection *c = userdata;
+ uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX;
+ pa_sink_input *si = NULL;
+ pa_sink *sink = NULL;
+ const char *name = NULL;
+
+ assert(c);
+ assert(t);
+
+ if (pa_tagstruct_getu32(t, &idx) < 0 ||
+ pa_tagstruct_getu32(t, &idx_device) < 0 ||
+ pa_tagstruct_gets(t, &name) < 0 ||
+ !pa_tagstruct_eof(t)) {
+ protocol_error(c);
+ return;
+ }
+
+ CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
+ CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
+ CHECK_VALIDITY(c->pstream, idx_device != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID);
+
+ si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
+
+ if (idx_device != PA_INVALID_INDEX)
+ sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device);
+ else
+ sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1);
+
+ CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY);
+
+ if (pa_sink_input_move_to(si, sink, 0) < 0) {
+ pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
+ return;
+ }
+
+ pa_pstream_send_simple_ack(c->pstream, tag);
+}
+
/*** pstream callbacks ***/
static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
c = pa_xmalloc(sizeof(struct connection));
- c->authorized =!! p->public;
+ c->authorized = !!p->public;
+ if (!c->authorized && p->auth_ip_acl && pa_ip_acl_check(p->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) {
+ pa_log_info(__FILE__": Client authenticated by IP ACL.");
+ c->authorized = 1;
+ }
+
if (!c->authorized) {
struct timeval tv;
pa_gettimeofday(&tv);
static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_modargs *ma) {
pa_protocol_native *p;
int public = 0;
- assert(c && ma);
+ const char *acl;
+
+ assert(c);
+ assert(ma);
if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &public) < 0) {
pa_log(__FILE__": auth-anonymous= expects a boolean argument.");
p->module = m;
p->public = public;
p->server = NULL;
-
+ p->auth_ip_acl = NULL;
+
#ifdef HAVE_CREDS
{
int a = 1;
pa_log_info(__FILE__": Allowing access to group '%s'.", p->auth_group);
}
#endif
-
- if (load_key(p, pa_modargs_get_value(ma, "cookie", NULL)) < 0) {
- pa_xfree(p);
- return NULL;
+
+
+ if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) {
+
+ if (!(p->auth_ip_acl = pa_ip_acl_new(acl))) {
+ pa_log(__FILE__": Failed to parse IP ACL '%s'", acl);
+ goto fail;
+ }
}
+ if (load_key(p, pa_modargs_get_value(ma, "cookie", NULL)) < 0)
+ goto fail;
+
p->connections = pa_idxset_new(NULL, NULL);
assert(p->connections);
return p;
+
+fail:
+#ifdef HAVE_CREDS
+ pa_xfree(p->auth_group);
+#endif
+ if (p->auth_ip_acl)
+ pa_ip_acl_free(p->auth_ip_acl);
+ pa_xfree(p);
+ return NULL;
}
pa_protocol_native* pa_protocol_native_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma) {
if (p->auth_cookie_in_property)
pa_authkey_prop_unref(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME);
+ if (p->auth_ip_acl)
+ pa_ip_acl_free(p->auth_ip_acl);
+
#ifdef HAVE_CREDS
pa_xfree(p->auth_group);
#endif