summaryrefslogtreecommitdiffstats
path: root/src/polypcore/iochannel.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/polypcore/iochannel.c')
-rw-r--r--src/polypcore/iochannel.c130
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);