The file descriptors are read from the iochannel just like the creds are. So instead of passing just creds (and creds_valid), we now pass the entire pa_ancil struct. Signed-off-by: David Henningsson <david.henningsson at canonical.com> --- src/modules/module-tunnel.c | 4 ++-- src/pulse/context.c | 4 ++-- src/pulsecore/iochannel.c | 42 +++++++++++++++++++++++++++++++---------- src/pulsecore/iochannel.h | 2 +- src/pulsecore/pdispatch.c | 26 ++++++++++++++++++++----- src/pulsecore/pdispatch.h | 4 +++- src/pulsecore/protocol-native.c | 4 ++-- src/pulsecore/pstream.c | 24 ++++++++++++++++------- src/pulsecore/pstream.h | 2 +- 9 files changed, 81 insertions(+), 31 deletions(-) diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index f0f0e31..193d091 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -1780,14 +1780,14 @@ static void pstream_die_callback(pa_pstream *p, void *userdata) { } /* Called from main context */ -static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) { +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_ancil *ancil, void *userdata) { struct userdata *u = userdata; pa_assert(p); pa_assert(packet); pa_assert(u); - if (pa_pdispatch_run(u->pdispatch, packet, creds, u) < 0) { + if (pa_pdispatch_run(u->pdispatch, packet, ancil, u) < 0) { pa_log("Invalid packet"); pa_module_unload_request(u->module, true); return; diff --git a/src/pulse/context.c b/src/pulse/context.c index ce19d91..f3adf4c 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -323,7 +323,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, const pa_creds *creds, void *userdata) { +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_ancil *ancil, void *userdata) { pa_context *c = userdata; pa_assert(p); @@ -332,7 +332,7 @@ static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_c pa_context_ref(c); - if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) + if (pa_pdispatch_run(c->pdispatch, packet, ancil, c) < 0) pa_context_fail(c, PA_ERR_PROTOCOL); pa_context_unref(c); diff --git a/src/pulsecore/iochannel.c b/src/pulsecore/iochannel.c index dce6734..4f9eca7 100644 --- a/src/pulsecore/iochannel.c +++ b/src/pulsecore/iochannel.c @@ -348,21 +348,26 @@ ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l return r; } -ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_creds *creds, bool *creds_valid) { +ssize_t pa_iochannel_read_with_ancil(pa_iochannel*io, void*data, size_t l, pa_ancil *ancil) { ssize_t r; struct msghdr mh; struct iovec iov; union { struct cmsghdr hdr; - uint8_t data[CMSG_SPACE(sizeof(struct ucred))]; + uint8_t data[CMSG_SPACE(sizeof(struct ucred)) + CMSG_SPACE(sizeof(int) * MAX_ANCIL_FDS)]; } cmsg; pa_assert(io); pa_assert(data); pa_assert(l); pa_assert(io->ifd >= 0); - pa_assert(creds); - pa_assert(creds_valid); + pa_assert(ancil); + + if (io->ifd_type > 0) { + ancil->creds_valid = false; + ancil->nfd = 0; + return pa_iochannel_read(io, data, l); + } pa_zero(iov); iov.iov_base = data; @@ -378,19 +383,31 @@ ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_cr if ((r = recvmsg(io->ifd, &mh, 0)) >= 0) { struct cmsghdr *cmh; - *creds_valid = false; + ancil->creds_valid = false; + ancil->nfd = 0; for (cmh = CMSG_FIRSTHDR(&mh); cmh; cmh = CMSG_NXTHDR(&mh, cmh)) { - if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_CREDENTIALS) { + if (cmh->cmsg_level != SOL_SOCKET) + continue; + + if (cmh->cmsg_type == SCM_CREDENTIALS) { struct ucred u; pa_assert(cmh->cmsg_len == CMSG_LEN(sizeof(struct ucred))); memcpy(&u, CMSG_DATA(cmh), sizeof(struct ucred)); - creds->gid = u.gid; - creds->uid = u.uid; - *creds_valid = true; - break; + ancil->creds.gid = u.gid; + ancil->creds.uid = u.uid; + ancil->creds_valid = true; + } + else if (cmh->cmsg_type == SCM_RIGHTS) { + int nfd = (cmh->cmsg_len - CMSG_LEN(0)) / sizeof(int); + if (nfd > MAX_ANCIL_FDS) { + pa_log("Trying to receive too many file descriptors!"); + continue; + } + memcpy(ancil->fds, CMSG_DATA(cmh), nfd * sizeof(int)); + ancil->nfd = nfd; } } @@ -398,6 +415,11 @@ ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_cr enable_events(io); } + if (r == -1 && errno == ENOTSOCK) { + io->ifd_type = 1; + return pa_iochannel_read_with_ancil(io, data, l, ancil); + } + return r; } diff --git a/src/pulsecore/iochannel.h b/src/pulsecore/iochannel.h index e95f46f..4da8902 100644 --- a/src/pulsecore/iochannel.h +++ b/src/pulsecore/iochannel.h @@ -58,7 +58,7 @@ bool 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, const pa_creds *ucred); -ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_creds *ucred, bool *creds_valid); +ssize_t pa_iochannel_read_with_ancil(pa_iochannel*io, void*data, size_t l, pa_ancil *ancil); #endif bool pa_iochannel_is_readable(pa_iochannel*io); diff --git a/src/pulsecore/pdispatch.c b/src/pulsecore/pdispatch.c index 1766d6d..483ce6b 100644 --- a/src/pulsecore/pdispatch.c +++ b/src/pulsecore/pdispatch.c @@ -216,7 +216,7 @@ struct pa_pdispatch { PA_LLIST_HEAD(struct reply_info, replies); pa_pdispatch_drain_cb_t drain_callback; void *drain_userdata; - const pa_creds *creds; + const pa_ancil *ancil; bool use_rtclock; }; @@ -286,7 +286,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, const pa_creds *creds, void *userdata) { +int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const pa_ancil *ancil, void *userdata) { uint32_t tag, command; pa_tagstruct *ts = NULL; int ret = -1; @@ -320,7 +320,7 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const pa_creds *creds, } #endif - pd->creds = creds; + pd->ancil = ancil; if (command == PA_COMMAND_ERROR || command == PA_COMMAND_REPLY) { struct reply_info *r; @@ -344,7 +344,7 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const pa_creds *creds, ret = 0; finish: - pd->creds = NULL; + pd->ancil = NULL; if (ts) pa_tagstruct_free(ts); @@ -437,5 +437,21 @@ const pa_creds * pa_pdispatch_creds(pa_pdispatch *pd) { pa_assert(pd); pa_assert(PA_REFCNT_VALUE(pd) >= 1); - return pd->creds; + if (pd->ancil && pd->ancil->creds_valid) + return &pd->ancil->creds; + return NULL; +} + +const int * pa_pdispatch_fds(pa_pdispatch *pd, int *nfd) { + pa_assert(pd); + pa_assert(PA_REFCNT_VALUE(pd) >= 1); + pa_assert(nfd); + + if (pd->ancil) { + *nfd = pd->ancil->nfd; + return pd->ancil->fds; + } + + *nfd = 0; + return NULL; } diff --git a/src/pulsecore/pdispatch.h b/src/pulsecore/pdispatch.h index 797ddca..038f90d 100644 --- a/src/pulsecore/pdispatch.h +++ b/src/pulsecore/pdispatch.h @@ -41,7 +41,7 @@ pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *m, bool use_rtclock, const pa_pd 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, const pa_creds *creds, void *userdata); +int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*p, const pa_ancil *ancil, void *userdata); void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_cb_t callback, void *userdata, pa_free_cb_t free_cb); @@ -54,4 +54,6 @@ void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata); const pa_creds * pa_pdispatch_creds(pa_pdispatch *pd); +const int * pa_pdispatch_fds(pa_pdispatch *pd, int *nfd); + #endif diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 606bf25..7262944 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -4816,14 +4816,14 @@ static void command_set_port_latency_offset(pa_pdispatch *pd, uint32_t command, /*** pstream callbacks ***/ -static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) { +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_ancil *ancil, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); pa_assert(p); pa_assert(packet); pa_native_connection_assert_ref(c); - if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) { + if (pa_pdispatch_run(c->pdispatch, packet, ancil, c) < 0) { pa_log("invalid packet."); native_connection_unlink(c); } diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c index 2c1444f..a3afed5 100644 --- a/src/pulsecore/pstream.c +++ b/src/pulsecore/pstream.c @@ -165,8 +165,9 @@ struct pa_pstream { pa_mempool *mempool; #ifdef HAVE_CREDS - pa_creds read_creds, write_creds; - bool read_creds_valid, send_creds_now; + pa_ancil read_ancil; + pa_creds write_creds; + bool send_creds_now; #endif }; @@ -646,12 +647,20 @@ static int do_read(pa_pstream *p) { #ifdef HAVE_CREDS { - bool b = 0; + pa_ancil b; - if ((r = pa_iochannel_read_with_creds(p->io, d, l, &p->read_creds, &b)) <= 0) + if ((r = pa_iochannel_read_with_ancil(p->io, d, l, &b)) <= 0) goto fail; - p->read_creds_valid = p->read_creds_valid || b; + if (b.creds_valid) { + p->read_ancil.creds_valid = true; + p->read_ancil.creds = b.creds; + } + if (b.nfd > 0) { + pa_assert(b.nfd <= MAX_ANCIL_FDS); + p->read_ancil.nfd = b.nfd; + memcpy(p->read_ancil.fds, b.fds, sizeof(int) * b.nfd); + } } #else if ((r = pa_iochannel_read(p->io, d, l)) <= 0) @@ -799,7 +808,7 @@ static int do_read(pa_pstream *p) { if (p->receive_packet_callback) #ifdef HAVE_CREDS - p->receive_packet_callback(p, p->read.packet, p->read_creds_valid ? &p->read_creds : NULL, p->receive_packet_callback_userdata); + p->receive_packet_callback(p, p->read.packet, &p->read_ancil, p->receive_packet_callback_userdata); #else p->receive_packet_callback(p, p->read.packet, NULL, p->receive_packet_callback_userdata); #endif @@ -860,7 +869,8 @@ frame_done: p->read.data = NULL; #ifdef HAVE_CREDS - p->read_creds_valid = false; + p->read_ancil.creds_valid = false; + p->read_ancil.nfd = 0; #endif return 0; diff --git a/src/pulsecore/pstream.h b/src/pulsecore/pstream.h index deb2bc3..9316d92 100644 --- a/src/pulsecore/pstream.h +++ b/src/pulsecore/pstream.h @@ -37,7 +37,7 @@ typedef struct pa_pstream pa_pstream; -typedef void (*pa_pstream_packet_cb_t)(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata); +typedef void (*pa_pstream_packet_cb_t)(pa_pstream *p, pa_packet *packet, const pa_ancil *ancil, 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); typedef void (*pa_pstream_block_id_cb_t)(pa_pstream *p, uint32_t block_id, void *userdata); -- 1.9.1