diff options
Diffstat (limited to 'src/polypcore/iochannel.c')
| -rw-r--r-- | src/polypcore/iochannel.c | 130 | 
1 files changed, 130 insertions, 0 deletions
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);  | 
