diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/modules/module-tunnel.c | 4 | ||||
| -rw-r--r-- | src/polyp/context.c | 6 | ||||
| -rw-r--r-- | src/polyp/subscribe.c | 6 | ||||
| -rw-r--r-- | src/polypcore/iochannel.c | 130 | ||||
| -rw-r--r-- | src/polypcore/iochannel.h | 11 | ||||
| -rw-r--r-- | src/polypcore/pdispatch.c | 21 | ||||
| -rw-r--r-- | src/polypcore/pdispatch.h | 6 | ||||
| -rw-r--r-- | src/polypcore/protocol-native.c | 93 | ||||
| -rw-r--r-- | src/polypcore/pstream-util.c | 4 | ||||
| -rw-r--r-- | src/polypcore/pstream-util.h | 4 | ||||
| -rw-r--r-- | src/polypcore/pstream.c | 134 | ||||
| -rw-r--r-- | src/polypcore/pstream.h | 14 | 
12 files changed, 342 insertions, 91 deletions
diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index df9c51fb..70bded6c 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -431,11 +431,11 @@ static void pstream_die_callback(pa_pstream *p, void *userdata) {  } -static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *userdata) { +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const void*creds, void *userdata) {      struct userdata *u = userdata;      assert(p && packet && u); -    if (pa_pdispatch_run(u->pdispatch, packet, u) < 0) { +    if (pa_pdispatch_run(u->pdispatch, packet, creds, u) < 0) {          pa_log(__FILE__": invalid packet");          die(u);      } diff --git a/src/polyp/context.c b/src/polyp/context.c index 8e999225..59079cb0 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -267,7 +267,7 @@ static void pstream_die_callback(pa_pstream *p, void *userdata) {      pa_context_fail(c, PA_ERR_CONNECTIONTERMINATED);  } -static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *userdata) { +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const void *creds, void *userdata) {      pa_context *c = userdata;      assert(p); @@ -276,7 +276,7 @@ static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *user      pa_context_ref(c); -    if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) +    if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0)          pa_context_fail(c, PA_ERR_PROTOCOL);      pa_context_unref(c); @@ -401,7 +401,7 @@ static void setup_context(pa_context *c, pa_iochannel *io) {      t = pa_tagstruct_command(c, PA_COMMAND_AUTH, &tag);      pa_tagstruct_put_arbitrary(t, c->conf->cookie, sizeof(c->conf->cookie)); -    pa_pstream_send_tagstruct(c->pstream, t); +    pa_pstream_send_tagstruct_with_creds(c->pstream, t, 1);      pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c);      pa_context_set_state(c, PA_CONTEXT_AUTHORIZING); diff --git a/src/polyp/subscribe.c b/src/polyp/subscribe.c index a4eadbc6..110d4e52 100644 --- a/src/polyp/subscribe.c +++ b/src/polyp/subscribe.c @@ -36,7 +36,7 @@  void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) {      pa_context *c = userdata;      pa_subscription_event_type_t e; -    uint32_t index; +    uint32_t idx;      assert(pd);      assert(command == PA_COMMAND_SUBSCRIBE_EVENT); @@ -46,14 +46,14 @@ void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSE      pa_context_ref(c);      if (pa_tagstruct_getu32(t, &e) < 0 || -        pa_tagstruct_getu32(t, &index) < 0 || +        pa_tagstruct_getu32(t, &idx) < 0 ||          !pa_tagstruct_eof(t)) {          pa_context_fail(c, PA_ERR_PROTOCOL);          goto finish;      }      if (c->subscribe_callback) -        c->subscribe_callback(c, e, index, c->subscribe_userdata); +        c->subscribe_callback(c, e, idx, c->subscribe_userdata);  finish:      pa_context_unref(c); diff --git a/src/polypcore/iochannel.c b/src/polypcore/iochannel.c index 89b061c2..ea0ac988 100644 --- a/src/polypcore/iochannel.c +++ b/src/polypcore/iochannel.c @@ -27,12 +27,14 @@  #include <assert.h>  #include <fcntl.h>  #include <unistd.h> +#include <errno.h>  #include "winsock.h"  #include <polypcore/util.h>  #include <polypcore/socket-util.h>  #include <polypcore/xmalloc.h> +#include <polypcore/log.h>  #include "iochannel.h" @@ -242,6 +244,134 @@ ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) {      return r;  } +#ifdef SCM_CREDENTIALS + +int pa_iochannel_creds_supported(pa_iochannel *io) { +    struct sockaddr_un sa; +    socklen_t l; +     +    assert(io); +    assert(io->ifd >= 0); +    assert(io->ofd == io->ifd); + +    l = sizeof(sa); +     +    if (getsockname(io->ifd, (struct sockaddr*) &sa, &l) < 0) +        return 0; + +    return sa.sun_family == AF_UNIX; +} + +int pa_iochannel_creds_enable(pa_iochannel *io) { +    int t = 1; + +    assert(io); +    assert(io->ifd >= 0); +     +    if (setsockopt(io->ifd, SOL_SOCKET, SO_PASSCRED, &t, sizeof(t)) < 0) { +        pa_log_error("setsockopt(SOL_SOCKET, SO_PASSCRED): %s", strerror(errno)); +        return -1; +    } + +    return 0; +} + +ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l) { +    ssize_t r; +    struct msghdr mh; +    struct iovec iov; +    uint8_t cmsg_data[CMSG_SPACE(sizeof(struct ucred))]; +    struct ucred *ucred; +    struct cmsghdr *cmsg; +     +    assert(io); +    assert(data); +    assert(l); +    assert(io->ofd >= 0); + +    memset(&iov, 0, sizeof(iov)); +    iov.iov_base = (void*) data; +    iov.iov_len = l; + +    memset(cmsg_data, 0, sizeof(cmsg_data)); +    cmsg = (struct cmsghdr*)  cmsg_data; +    cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred)); +    cmsg->cmsg_level = SOL_SOCKET; +    cmsg->cmsg_type = SCM_CREDENTIALS; + +    ucred = (struct ucred*) CMSG_DATA(cmsg); +    ucred->pid = getpid(); +    ucred->uid = getuid(); +    ucred->gid = getgid(); +     +    memset(&mh, 0, sizeof(mh)); +    mh.msg_name = NULL; +    mh.msg_namelen = 0; +    mh.msg_iov = &iov; +    mh.msg_iovlen = 1; +    mh.msg_control = cmsg_data; +    mh.msg_controllen = sizeof(cmsg_data); +    mh.msg_flags = 0; + +    if ((r = sendmsg(io->ofd, &mh, MSG_NOSIGNAL)) >= 0) { +        io->writable = 0; +        enable_mainloop_sources(io); +    } + +    return r; +} + +ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, struct ucred *ucred, int *creds_valid) { +    ssize_t r; +    struct msghdr mh; +    struct iovec iov; +    uint8_t cmsg_data[CMSG_SPACE(sizeof(struct ucred))]; +     +    assert(io); +    assert(data); +    assert(l); +    assert(io->ifd >= 0); +    assert(ucred); +    assert(creds_valid); + +    memset(&iov, 0, sizeof(iov)); +    iov.iov_base = data; +    iov.iov_len = l; + +    memset(cmsg_data, 0, sizeof(cmsg_data)); + +    memset(&mh, 0, sizeof(mh)); +    mh.msg_name = NULL; +    mh.msg_namelen = 0; +    mh.msg_iov = &iov; +    mh.msg_iovlen = 1; +    mh.msg_control = cmsg_data; +    mh.msg_controllen = sizeof(cmsg_data); +    mh.msg_flags = 0; + +    if ((r = recvmsg(io->ifd, &mh, MSG_NOSIGNAL)) >= 0) { +        struct cmsghdr *cmsg; + +        *creds_valid = 0; +     +        for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) { +             +            if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) { +                assert(cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))); +                memcpy(ucred, CMSG_DATA(cmsg), sizeof(struct ucred)); +                *creds_valid = 1; +                break; +            } +        } + +        io->readable = 0; +        enable_mainloop_sources(io); +    } +     +    return r; +} +#endif +  void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t _callback, void *userdata) {      assert(io); diff --git a/src/polypcore/iochannel.h b/src/polypcore/iochannel.h index 977fe2c3..617ce086 100644 --- a/src/polypcore/iochannel.h +++ b/src/polypcore/iochannel.h @@ -23,6 +23,9 @@  ***/  #include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +  #include <polyp/mainloop-api.h>  /* A wrapper around UNIX file descriptors for attaching them to the a @@ -48,6 +51,14 @@ void pa_iochannel_free(pa_iochannel*io);  ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l);  ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l); +#ifdef SCM_CREDENTIALS +int pa_iochannel_creds_supported(pa_iochannel *io); +int pa_iochannel_creds_enable(pa_iochannel *io); + +ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l); +ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, struct ucred *ucred, int *creds_valid); +#endif +  int pa_iochannel_is_readable(pa_iochannel*io);  int pa_iochannel_is_writable(pa_iochannel*io);  int pa_iochannel_is_hungup(pa_iochannel*io); diff --git a/src/polypcore/pdispatch.c b/src/polypcore/pdispatch.c index 56a21bd6..a4e58f8c 100644 --- a/src/polypcore/pdispatch.c +++ b/src/polypcore/pdispatch.c @@ -109,6 +109,7 @@ struct pa_pdispatch {      PA_LLIST_HEAD(struct reply_info, replies);      pa_pdispatch_drain_callback drain_callback;      void *drain_userdata; +    const void *creds;  };  static void reply_info_free(struct reply_info *r) { @@ -136,7 +137,8 @@ pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, const pa_pdispatch_cb_      PA_LLIST_HEAD_INIT(pa_reply_info, pd->replies);      pd->drain_callback = NULL;      pd->drain_userdata = NULL; - +    pd->creds = NULL; +          return pd;  } @@ -171,7 +173,7 @@ static void run_action(pa_pdispatch *pd, struct reply_info *r, uint32_t command,      pa_pdispatch_unref(pd);  } -int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, void *userdata) { +int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const void *creds, void *userdata) {      uint32_t tag, command;      pa_tagstruct *ts = NULL;      int ret = -1; @@ -188,18 +190,20 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, void *userdata) {      if (pa_tagstruct_getu32(ts, &command) < 0 ||          pa_tagstruct_getu32(ts, &tag) < 0)          goto finish; - +      #ifdef DEBUG_OPCODES  {      char t[256];      char const *p;      if (!(p = command_names[command]))          snprintf((char*) (p = t), sizeof(t), "%u", command); -         +          pa_log(__FILE__": Recieved opcode <%s>", p);  }  #endif +    pd->creds = creds; +      if (command == PA_COMMAND_ERROR || command == PA_COMMAND_REPLY) {          struct reply_info *r; @@ -222,6 +226,8 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, void *userdata) {      ret = 0;  finish: +    pd->creds = NULL; +          if (ts)          pa_tagstruct_free(ts); @@ -295,3 +301,10 @@ pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd) {      pd->ref++;      return pd;  } + +const void * pa_pdispatch_creds(pa_pdispatch *pd) { +    assert(pd); +    assert(pd->ref >= 1); +     +    return pd->creds; +} diff --git a/src/polypcore/pdispatch.h b/src/polypcore/pdispatch.h index 31533d57..aa898abf 100644 --- a/src/polypcore/pdispatch.h +++ b/src/polypcore/pdispatch.h @@ -30,21 +30,23 @@  typedef struct pa_pdispatch pa_pdispatch;  typedef void (*pa_pdispatch_cb_t)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +typedef void (*pa_pdispatch_drain_callback)(pa_pdispatch *pd, void *userdata);  pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *m, const pa_pdispatch_cb_t*table, unsigned entries);  void pa_pdispatch_unref(pa_pdispatch *pd);  pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd); -int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*p, void *userdata); +int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*p, const void*creds, void *userdata);  void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_cb_t callback, void *userdata);  int pa_pdispatch_is_pending(pa_pdispatch *pd); -typedef void (*pa_pdispatch_drain_callback)(pa_pdispatch *pd, void *userdata);  void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, pa_pdispatch_drain_callback callback, void *userdata);  /* Remove all reply slots with the give userdata parameter */  void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata); +const void * pa_pdispatch_creds(pa_pdispatch *pd); +  #endif diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index 52eaed4f..0fb9339b 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -27,6 +27,7 @@  #include <stdio.h>  #include <assert.h>  #include <stdlib.h> +#include <unistd.h>  #include <polypcore/native-common.h>  #include <polypcore/packet.h> @@ -357,7 +358,7 @@ static struct playback_stream* playback_stream_new(      pa_cvolume *volume,      uint32_t syncid) { -    struct playback_stream *s, *sync; +    struct playback_stream *s, *ssync;      pa_sink_input *sink_input;      pa_memblock *silence;      uint32_t idx; @@ -366,17 +367,17 @@ static struct playback_stream* playback_stream_new(      assert(c && sink && ss && name && maxlength);      /* Find syncid group */ -    for (sync = pa_idxset_first(c->output_streams, &idx); sync; sync = pa_idxset_next(c->output_streams, &idx)) { +    for (ssync = pa_idxset_first(c->output_streams, &idx); ssync; ssync = pa_idxset_next(c->output_streams, &idx)) { -        if (sync->type != PLAYBACK_STREAM) +        if (ssync->type != PLAYBACK_STREAM)              continue; -        if (sync->syncid == syncid) +        if (ssync->syncid == syncid)              break;      }      /* Synced streams must connect to the same sink */ -    if (sync && sync->sink_input->sink != sink) +    if (ssync && ssync->sink_input->sink != sink)          return NULL;      if (!(sink_input = pa_sink_input_new(sink, __FILE__, name, ss, map, 0, -1))) @@ -397,16 +398,16 @@ static struct playback_stream* playback_stream_new(      s->sink_input->owner = c->protocol->module;      s->sink_input->client = c->client; -    if (sync) { +    if (ssync) {          /* Sync id found, now find head of list */ -        PA_LLIST_FIND_HEAD(struct playback_stream, sync, &sync); +        PA_LLIST_FIND_HEAD(struct playback_stream, ssync, &ssync);          /* Prepend ourselves */ -        PA_LLIST_PREPEND(struct playback_stream, sync, s); +        PA_LLIST_PREPEND(struct playback_stream, ssync, s);          /* Set our start index to the current read index of the other grozp member(s) */ -        assert(sync->next); -        start_index = pa_memblockq_get_read_index(sync->next->memblockq); +        assert(ssync->next); +        start_index = pa_memblockq_get_read_index(ssync->next->memblockq);      } else {          /* This ia a new sync group */          PA_LLIST_INIT(struct playback_stream, s); @@ -871,8 +872,29 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t      }      if (!c->authorized) { -        if (memcmp(c->protocol->auth_cookie, cookie, PA_NATIVE_COOKIE_LENGTH) != 0) { -            pa_log(__FILE__": Denied access to client with invalid authorization key."); +        int success = 0; +         +#ifdef SCM_CREDENTIALS +        const struct ucred *ucred = pa_pdispatch_creds(pd); + +        if (ucred) { +            if (ucred->uid == getuid())  +                success = 1; +                 +            pa_log_info(__FILE__": Got credentials: pid=%lu uid=%lu gid=%lu auth=%i", +                        (unsigned long) ucred->pid, +                        (unsigned long) ucred->uid, +                        (unsigned long) ucred->gid, +                        success); + +        } +#endif + +        if (memcmp(c->protocol->auth_cookie, cookie, PA_NATIVE_COOKIE_LENGTH) == 0) +            success = 1; + +        if (!success) { +            pa_log_warn(__FILE__": Denied access to client with invalid authorization data.");              pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS);              return;          } @@ -1589,7 +1611,7 @@ static void command_cork_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_      struct connection *c = userdata;      uint32_t idx;      int b; -    struct playback_stream *s, *sync; +    struct playback_stream *s, *ssync;      assert(c && t);      if (pa_tagstruct_getu32(t, &idx) < 0 || @@ -1609,14 +1631,14 @@ static void command_cork_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_      pa_memblockq_prebuf_force(s->memblockq);      /* Do the same for all other members in the sync group */ -    for (sync = s->prev; sync; sync = sync->prev) { -        pa_sink_input_cork(sync->sink_input, b); -        pa_memblockq_prebuf_force(sync->memblockq); +    for (ssync = s->prev; ssync; ssync = ssync->prev) { +        pa_sink_input_cork(ssync->sink_input, b); +        pa_memblockq_prebuf_force(ssync->memblockq);      } -    for (sync = s->next; sync; sync = sync->next) { -        pa_sink_input_cork(sync->sink_input, b); -        pa_memblockq_prebuf_force(sync->memblockq); +    for (ssync = s->next; ssync; ssync = ssync->next) { +        pa_sink_input_cork(ssync->sink_input, b); +        pa_memblockq_prebuf_force(ssync->memblockq);      }      pa_pstream_send_simple_ack(c->pstream, tag); @@ -1625,7 +1647,7 @@ static void command_cork_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_  static void command_flush_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {      struct connection *c = userdata;      uint32_t idx; -    struct playback_stream *s, *sync; +    struct playback_stream *s, *ssync;      assert(c && t);      if (pa_tagstruct_getu32(t, &idx) < 0 || @@ -1644,25 +1666,25 @@ static void command_flush_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC      s->underrun = 0;      /* Do the same for all other members in the sync group */ -    for (sync = s->prev; sync; sync = sync->prev) { -        pa_memblockq_flush(sync->memblockq); -        sync->underrun = 0; +    for (ssync = s->prev; ssync; ssync = ssync->prev) { +        pa_memblockq_flush(ssync->memblockq); +        ssync->underrun = 0;      } -    for (sync = s->next; sync; sync = sync->next) { -        pa_memblockq_flush(sync->memblockq); -        sync->underrun = 0; +    for (ssync = s->next; ssync; ssync = ssync->next) { +        pa_memblockq_flush(ssync->memblockq); +        ssync->underrun = 0;      }      pa_pstream_send_simple_ack(c->pstream, tag);      pa_sink_notify(s->sink_input->sink);      request_bytes(s); -    for (sync = s->prev; sync; sync = sync->prev) -        request_bytes(sync); +    for (ssync = s->prev; ssync; ssync = ssync->prev) +        request_bytes(ssync); -    for (sync = s->next; sync; sync = sync->next) -        request_bytes(sync); +    for (ssync = s->next; ssync; ssync = ssync->next) +        request_bytes(ssync);  }  static void command_trigger_or_prebuf_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { @@ -2017,11 +2039,11 @@ static void command_get_autoload_info_list(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC  /*** pstream callbacks ***/ -static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *userdata) { +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const void *creds, void *userdata) {      struct connection *c = userdata;      assert(p && packet && packet->data && c); -    if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { +    if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) {          pa_log(__FILE__": invalid packet.");          connection_free(c);      } @@ -2183,6 +2205,13 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo      c->subscription = NULL;      pa_idxset_put(p->connections, c, NULL); + + +#ifdef SCM_CREDENTIALS +    if (pa_iochannel_creds_supported(io)) +        pa_iochannel_creds_enable(io); +     +#endif  }  /*** module entry points ***/ diff --git a/src/polypcore/pstream-util.c b/src/polypcore/pstream-util.c index 62986456..bd1d1a87 100644 --- a/src/polypcore/pstream-util.c +++ b/src/polypcore/pstream-util.c @@ -29,7 +29,7 @@  #include "pstream-util.h" -void pa_pstream_send_tagstruct(pa_pstream *p, pa_tagstruct *t) { +void pa_pstream_send_tagstruct_with_creds(pa_pstream *p, pa_tagstruct *t, int creds) {      size_t length;      uint8_t *data;      pa_packet *packet; @@ -40,7 +40,7 @@ void pa_pstream_send_tagstruct(pa_pstream *p, pa_tagstruct *t) {      assert(data && length);      packet = pa_packet_new_dynamic(data, length);      assert(packet); -    pa_pstream_send_packet(p, packet); +    pa_pstream_send_packet(p, packet, creds);      pa_packet_unref(packet);  } diff --git a/src/polypcore/pstream-util.h b/src/polypcore/pstream-util.h index c400c6d8..f2677a44 100644 --- a/src/polypcore/pstream-util.h +++ b/src/polypcore/pstream-util.h @@ -27,7 +27,9 @@  #include <polypcore/tagstruct.h>  /* The tagstruct is freed!*/ -void pa_pstream_send_tagstruct(pa_pstream *p, pa_tagstruct *t); +void pa_pstream_send_tagstruct_with_creds(pa_pstream *p, pa_tagstruct *t, int creds); + +#define pa_pstream_send_tagstruct(p, t) pa_pstream_send_tagstruct_with_creds((p), (t), 0)  void pa_pstream_send_error(pa_pstream *p, uint32_t tag, uint32_t error);  void pa_pstream_send_simple_ack(pa_pstream *p, uint32_t tag); diff --git a/src/polypcore/pstream.c b/src/polypcore/pstream.c index b1e8bd06..b93dca08 100644 --- a/src/polypcore/pstream.c +++ b/src/polypcore/pstream.c @@ -65,6 +65,9 @@ struct item_info {      /* packet info */      pa_packet *packet; +#ifdef SCM_CREDENTIALS +    int with_creds; +#endif  };  struct pa_pstream { @@ -76,8 +79,6 @@ struct pa_pstream {      pa_queue *send_queue;      int dead; -    void (*die_callback) (pa_pstream *p, void *userdata); -    void *die_callback_userdata;      struct {          struct item_info* current; @@ -94,16 +95,25 @@ struct pa_pstream {          size_t index;      } read; -    void (*recieve_packet_callback) (pa_pstream *p, pa_packet *packet, void *userdata); +    pa_pstream_packet_cb_t recieve_packet_callback;      void *recieve_packet_callback_userdata; -    void (*recieve_memblock_callback) (pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata); +    pa_pstream_memblock_cb_t recieve_memblock_callback;      void *recieve_memblock_callback_userdata; -    void (*drain_callback)(pa_pstream *p, void *userdata); -    void *drain_userdata; +    pa_pstream_notify_cb_t drain_callback; +    void *drain_callback_userdata; + +    pa_pstream_notify_cb_t die_callback; +    void *die_callback_userdata;      pa_memblock_stat *memblock_stat; + +#ifdef SCM_CREDENTIALS +    int send_creds_now; +    struct ucred ucred; +    int creds_valid; +#endif  };  static int do_write(pa_pstream *p); @@ -170,8 +180,6 @@ pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_memblock_sta      pa_iochannel_set_callback(io, io_callback, p);      p->dead = 0; -    p->die_callback = NULL; -    p->die_callback_userdata = NULL;      p->mainloop = m;      p->defer_event = m->defer_new(m, defer_callback, p); @@ -194,13 +202,20 @@ pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_memblock_sta      p->recieve_memblock_callback_userdata = NULL;      p->drain_callback = NULL; -    p->drain_userdata = NULL; +    p->drain_callback_userdata = NULL; + +    p->die_callback = NULL; +    p->die_callback_userdata = NULL;      p->memblock_stat = s;      pa_iochannel_socket_set_rcvbuf(io, 1024*8);  -    pa_iochannel_socket_set_sndbuf(io, 1024*8);  +    pa_iochannel_socket_set_sndbuf(io, 1024*8); +#ifdef SCM_CREDENTIALS +    p->send_creds_now = 0; +    p->creds_valid = 0; +#endif      return p;  } @@ -239,7 +254,7 @@ static void pstream_free(pa_pstream *p) {      pa_xfree(p);  } -void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet) { +void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, int with_creds) {      struct item_info *i;      assert(p && packet && p->ref >= 1); @@ -251,6 +266,9 @@ void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet) {      i = pa_xnew(struct item_info, 1);      i->type = PA_PSTREAM_ITEM_PACKET;      i->packet = pa_packet_ref(packet); +#ifdef SCM_CREDENTIALS +    i->with_creds = with_creds; +#endif      pa_queue_push(p->send_queue, i);      p->mainloop->defer_enable(p->defer_event, 1); @@ -278,20 +296,6 @@ void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa      p->mainloop->defer_enable(p->defer_event, 1);  } -void pa_pstream_set_recieve_packet_callback(pa_pstream *p, void (*callback) (pa_pstream *p, pa_packet *packet, void *userdata), void *userdata) { -    assert(p && callback); - -    p->recieve_packet_callback = callback; -    p->recieve_packet_callback_userdata = userdata; -} - -void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, void (*callback) (pa_pstream *p, uint32_t channel, int64_t delta, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata), void *userdata) { -    assert(p && callback); - -    p->recieve_memblock_callback = callback; -    p->recieve_memblock_callback_userdata = userdata; -} -  static void prepare_next_write_item(pa_pstream *p) {      assert(p); @@ -310,6 +314,11 @@ static void prepare_next_write_item(pa_pstream *p) {          p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = 0;          p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO] = 0;          p->write.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK] = 0; + +#ifdef SCM_CREDENTIALS +        p->send_creds_now = 1; +#endif +              } else {          assert(p->write.current->type == PA_PSTREAM_ITEM_MEMBLOCK && p->write.current->chunk.memblock);          p->write.data = (uint8_t*) p->write.current->chunk.memblock->data + p->write.current->chunk.index; @@ -318,6 +327,10 @@ static void prepare_next_write_item(pa_pstream *p) {          p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = htonl((uint32_t) (((uint64_t) p->write.current->offset) >> 32));          p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO] = htonl((uint32_t) ((uint64_t) p->write.current->offset));          p->write.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK] = htonl(p->write.current->seek_mode); + +#ifdef SCM_CREDENTIALS +        p->send_creds_now = 1; +#endif      }  } @@ -343,6 +356,16 @@ static int do_write(pa_pstream *p) {          l = ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE);      } +#ifdef SCM_CREDENTIALS +    if (p->send_creds_now) { + +        if ((r = pa_iochannel_write_with_creds(p->io, d, l)) < 0) +            return -1; + +        p->send_creds_now = 0; +    } else +#endif +      if ((r = pa_iochannel_write(p->io, d, l)) < 0)          return -1; @@ -354,7 +377,7 @@ static int do_write(pa_pstream *p) {          p->write.current = NULL;          if (p->drain_callback && !pa_pstream_is_pending(p)) -            p->drain_callback(p, p->drain_userdata); +            p->drain_callback(p, p->drain_callback_userdata);      }      return 0; @@ -375,8 +398,19 @@ static int do_read(pa_pstream *p) {          l = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE);      } +#ifdef SCM_CREDENTIALS +    { +        int b; +         +        if ((r = pa_iochannel_read_with_creds(p->io, d, l, &p->ucred, &b)) <= 0) +            return -1; + +        p->creds_valid = p->creds_valid || b; +    } +#else      if ((r = pa_iochannel_read(p->io, d, l)) <= 0)          return -1; +#endif      p->read.index += r; @@ -453,40 +487,66 @@ static int do_read(pa_pstream *p) {                  assert(p->read.packet);                  if (p->recieve_packet_callback) -                    p->recieve_packet_callback(p, p->read.packet, p->recieve_packet_callback_userdata); +#ifdef SCM_CREDENTIALS                     +                    p->recieve_packet_callback(p, p->read.packet, p->creds_valid ? &p->ucred : NULL, p->recieve_packet_callback_userdata); +#else +                    p->recieve_packet_callback(p, p->read.packet, NULL, p->recieve_packet_callback_userdata); +#endif                  pa_packet_unref(p->read.packet);                  p->read.packet = NULL;              }              p->read.index = 0; +#ifdef SCM_CREDENTIALS +            p->creds_valid = 0; +#endif          }      }      return 0;     } -void pa_pstream_set_die_callback(pa_pstream *p, void (*callback)(pa_pstream *p, void *userdata), void *userdata) { -    assert(p && callback); -    p->die_callback = callback; +void pa_pstream_set_die_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata) { +    assert(p); +    assert(p->ref >= 1); + +    p->die_callback = cb;      p->die_callback_userdata = userdata;  } -int pa_pstream_is_pending(pa_pstream *p) { + +void pa_pstream_set_drain_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata) {      assert(p); +    assert(p->ref >= 1); -    if (p->dead) -        return 0; +    p->drain_callback = cb; +    p->drain_callback_userdata = userdata; +} -    return p->write.current || !pa_queue_is_empty(p->send_queue); +void pa_pstream_set_recieve_packet_callback(pa_pstream *p, pa_pstream_packet_cb_t cb, void *userdata) { +    assert(p); +    assert(p->ref >= 1); + +    p->recieve_packet_callback = cb; +    p->recieve_packet_callback_userdata = userdata;  } -void pa_pstream_set_drain_callback(pa_pstream *p, void (*cb)(pa_pstream *p, void *userdata), void *userdata) { +void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, pa_pstream_memblock_cb_t cb, void *userdata) {      assert(p);      assert(p->ref >= 1); -    p->drain_callback = cb; -    p->drain_userdata = userdata; +    p->recieve_memblock_callback = cb; +    p->recieve_memblock_callback_userdata = userdata; +} + +int pa_pstream_is_pending(pa_pstream *p) { +    assert(p); + +    if (p->dead) +        return 0; + +    return p->write.current || !pa_queue_is_empty(p->send_queue);  }  void pa_pstream_unref(pa_pstream*p) { diff --git a/src/polypcore/pstream.h b/src/polypcore/pstream.h index 741ba9b5..feb1b151 100644 --- a/src/polypcore/pstream.h +++ b/src/polypcore/pstream.h @@ -33,18 +33,22 @@  typedef struct pa_pstream pa_pstream; +typedef void (*pa_pstream_packet_cb_t)(pa_pstream *p, pa_packet *packet, const void *creds, void *userdata); +typedef void (*pa_pstream_memblock_cb_t)(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata); +typedef void (*pa_pstream_notify_cb_t)(pa_pstream *p, void *userdata); +  pa_pstream* pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_memblock_stat *s);  void pa_pstream_unref(pa_pstream*p);  pa_pstream* pa_pstream_ref(pa_pstream*p); -void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet); +void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, int with_creds);  void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk); -void pa_pstream_set_recieve_packet_callback(pa_pstream *p, void (*callback) (pa_pstream *p, pa_packet *packet, void *userdata), void *userdata); -void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, void (*callback) (pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata), void *userdata); -void pa_pstream_set_drain_callback(pa_pstream *p, void (*cb)(pa_pstream *p, void *userdata), void *userdata); +void pa_pstream_set_recieve_packet_callback(pa_pstream *p, pa_pstream_packet_cb_t cb, void *userdata); +void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, pa_pstream_memblock_cb_t cb, void *userdata); +void pa_pstream_set_drain_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata); -void pa_pstream_set_die_callback(pa_pstream *p, void (*callback)(pa_pstream *p, void *userdata), void *userdata); +void pa_pstream_set_die_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata);  int pa_pstream_is_pending(pa_pstream *p);  | 
