From 9e5f2b29cf819c9f79113bf3ae7edcb484d8ee14 Mon Sep 17 00:00:00 2001 From: fredrik Date: Wed, 11 Apr 2007 13:28:13 +0000 Subject: [PATCH] Send and receive Unix creds. git-svn-id: svn+ssh://svn.dolda2000.com/srv/svn/repos/src/doldaconnect@896 959494ce-11ee-0310-bf91-de5d638817bd --- daemon/net.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- daemon/net.h | 2 ++ lib/uilib.c | 53 ++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 112 insertions(+), 9 deletions(-) diff --git a/daemon/net.c b/daemon/net.c index 16c7bbb..d90146d 100644 --- a/daemon/net.c +++ b/daemon/net.c @@ -183,6 +183,7 @@ static struct socket *newsock(int type) new->close = 0; new->remote = NULL; new->remotelen = 0; + memset(&new->ucred, 0, sizeof(new->ucred)); switch(type) { case SOCK_STREAM: @@ -346,11 +347,38 @@ void *sockgetinbuf(struct socket *sk, size_t *size) return(NULL); } +static void recvcmsg(struct socket *sk, struct msghdr *msg) +{ + struct cmsghdr *cmsg; + struct ucred *cred; + + for(cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) + { + if((cmsg->cmsg_level == SOL_SOCKET) && (cmsg->cmsg_type == SCM_CREDENTIALS)) + { + if(sk->ucred.pid == 0) + { + cred = (struct ucred *)CMSG_DATA(cmsg); + memcpy(&sk->ucred, cred, sizeof(*cred)); + flog(LOG_INFO, "received Unix creds: pid %i, uid %i, gid %i", cred->pid, cred->uid, cred->gid); + } + } + } +} + static void sockrecv(struct socket *sk) { int ret, inq; struct dgrambuf *dbuf; + struct msghdr msg; + char cbuf[65536]; + struct iovec bufvec; + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = &bufvec; + msg.msg_iovlen = 1; + msg.msg_control = cbuf; + msg.msg_controllen = sizeof(cbuf); switch(sk->type) { case SOCK_STREAM: @@ -370,7 +398,12 @@ static void sockrecv(struct socket *sk) if(inq > 65536) inq = 65536; sizebuf(&sk->inbuf.s.buf, &sk->inbuf.s.bufsize, sk->inbuf.s.datasize + inq, 1, 1); + /* ret = read(sk->fd, sk->inbuf.s.buf + sk->inbuf.s.datasize, inq); + */ + bufvec.iov_base = sk->inbuf.s.buf + sk->inbuf.s.datasize; + bufvec.iov_len = inq; + ret = recvmsg(sk->fd, &msg, 0); if(ret < 0) { if((errno == EINTR) || (errno == EAGAIN)) @@ -380,6 +413,10 @@ static void sockrecv(struct socket *sk) closesock(sk); return; } + if(msg.msg_flags & MSG_CTRUNC) + flog(LOG_DEBUG, "ancillary data was truncated"); + else + recvcmsg(sk, &msg); if(ret == 0) { if(sk->errcb != NULL) @@ -392,6 +429,7 @@ static void sockrecv(struct socket *sk) sk->readcb(sk, sk->data); break; case SOCK_DGRAM: +#if defined(HAVE_LINUX_SOCKIOS_H) && defined(SIOCINQ) if(ioctl(sk->fd, SIOCINQ, &inq)) { /* I don't really know what could go wrong here, so let's @@ -399,10 +437,21 @@ static void sockrecv(struct socket *sk) flog(LOG_WARNING, "SIOCINQ return %s on socket %i", strerror(errno), sk->fd); return; } +#else + inq = 65536; +#endif dbuf = smalloc(sizeof(*dbuf)); dbuf->data = smalloc(inq); dbuf->addr = smalloc(dbuf->addrlen = sizeof(struct sockaddr_storage)); + /* ret = recvfrom(sk->fd, dbuf->data, inq, 0, dbuf->addr, &dbuf->addrlen); + */ + msg.msg_name = dbuf->addr; + msg.msg_namelen = dbuf->addrlen; + bufvec.iov_base = dbuf->data; + bufvec.iov_len = inq; + ret = recvmsg(sk->fd, &msg, 0); + dbuf->addrlen = msg.msg_namelen; if(ret < 0) { free(dbuf->addr); @@ -415,6 +464,10 @@ static void sockrecv(struct socket *sk) closesock(sk); return; } + if(msg.msg_flags & MSG_CTRUNC) + flog(LOG_DEBUG, "ancillary data was truncated"); + else + recvcmsg(sk, &msg); /* On UDP/IPv[46], ret == 0 doesn't mean EOF (since UDP can't * have EOF), but rather an empty packet. I don't know if any * other potential DGRAM protocols might have an EOF @@ -758,6 +811,15 @@ struct socket *netcsconn(struct sockaddr *addr, socklen_t addrlen, void (*func)( return(NULL); } +static void acceptunix(struct socket *sk) +{ + int buf; + + buf = 1; + if(setsockopt(sk->fd, SOL_SOCKET, SO_PASSCRED, &buf, sizeof(buf)) < 0) + flog(LOG_WARNING, "could not enable SO_PASSCRED on Unix socket %i: %s", sk->fd, strerror(errno)); +} + int pollsocks(int timeout) { int i, num, ret; @@ -825,9 +887,11 @@ int pollsocks(int timeout) newsk->state = SOCK_EST; memcpy(newsk->remote = smalloc(sslen), &ss, sslen); newsk->remotelen = sslen; - putsock(newsk); + if(ss.ss_family == PF_UNIX) + acceptunix(newsk); if(sk->acceptcb != NULL) sk->acceptcb(sk, newsk, sk->data); + putsock(newsk); } if(pfds[i].revents & POLLERR) { diff --git a/daemon/net.h b/daemon/net.h index 7d63981..f9b7a29 100644 --- a/daemon/net.h +++ b/daemon/net.h @@ -20,6 +20,7 @@ #define _NET_H #include +#include #define SOCK_LST 0 /* Listening */ #define SOCK_SYN 1 /* Connecting */ @@ -54,6 +55,7 @@ struct socket int close; struct sockaddr *remote; socklen_t remotelen; + struct ucred ucred; union { struct diff --git a/lib/uilib.c b/lib/uilib.c index 034c823..65215b7 100644 --- a/lib/uilib.c +++ b/lib/uilib.c @@ -96,8 +96,12 @@ static int state = -1; static int fd = -1; static iconv_t ichandle; static int resetreader = 1; -static char *dchostname = NULL; static struct addrinfo *hostlist = NULL, *curhost = NULL; +struct { + char *hostname; + int family; + int sentcreds; +} servinfo; static struct dc_response *makeresp(void) { @@ -276,9 +280,9 @@ void dc_disconnect(void) while((resp = dc_getresp()) != NULL) dc_freeresp(resp); dc_uimisc_disconnected(); - if(dchostname != NULL) - free(dchostname); - dchostname = NULL; + if(servinfo.hostname != NULL) + free(servinfo.hostname); + memset(&servinfo, 0, sizeof(servinfo)); } void dc_freeresp(struct dc_response *resp) @@ -532,7 +536,8 @@ int dc_handleread(void) } } if(curhost->ai_canonname != NULL) - dchostname = sstrdup(curhost->ai_canonname); + servinfo.hostname = sstrdup(curhost->ai_canonname); + servinfo.family = curhost->ai_family; state = 1; resetreader = 1; break; @@ -744,17 +749,48 @@ int dc_handleread(void) return(0); } +static void mkcreds(struct msghdr *msg) +{ + struct ucred *ucred; + static char buf[CMSG_SPACE(sizeof(*ucred))]; + struct cmsghdr *cmsg; + + msg->msg_control = buf; + msg->msg_controllen = sizeof(buf); + cmsg = CMSG_FIRSTHDR(msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_CREDENTIALS; + cmsg->cmsg_len = CMSG_LEN(sizeof(*ucred)); + ucred = (struct ucred *)CMSG_DATA(cmsg); + ucred->pid = getpid(); + ucred->uid = getuid(); + ucred->gid = getgid(); + msg->msg_controllen = cmsg->cmsg_len; +} + int dc_handlewrite(void) { int ret; int errnobak; + struct msghdr msg; + struct iovec bufvec; switch(state) { case 1: if(queue->buflen > 0) { - ret = send(fd, queue->buf, queue->buflen, MSG_NOSIGNAL | MSG_DONTWAIT); + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = &bufvec; + msg.msg_iovlen = 1; + bufvec.iov_base = queue->buf; + bufvec.iov_len = queue->buflen; + if((servinfo.family == PF_UNIX) && !servinfo.sentcreds) + { + mkcreds(&msg); + servinfo.sentcreds = 1; + } + ret = sendmsg(fd, &msg, MSG_NOSIGNAL | MSG_DONTWAIT); if(ret < 0) { if((errno == EAGAIN) || (errno == EINTR)) @@ -1108,7 +1144,8 @@ int dc_connect(char *host) fd = -1; } else { if(curhost->ai_canonname != NULL) - dchostname = sstrdup(curhost->ai_canonname); + servinfo.hostname = sstrdup(curhost->ai_canonname); + servinfo.family = curhost->ai_family; state = 1; break; } @@ -1190,5 +1227,5 @@ void dc_freeires(struct dc_intresp *ires) const char *dc_gethostname(void) { - return(dchostname); + return(servinfo.hostname); } -- 2.11.0