Send and receive Unix creds.
authorfredrik <fredrik@959494ce-11ee-0310-bf91-de5d638817bd>
Wed, 11 Apr 2007 13:28:13 +0000 (13:28 +0000)
committerfredrik <fredrik@959494ce-11ee-0310-bf91-de5d638817bd>
Wed, 11 Apr 2007 13:28:13 +0000 (13:28 +0000)
git-svn-id: svn+ssh://svn.dolda2000.com/srv/svn/repos/src/doldaconnect@896 959494ce-11ee-0310-bf91-de5d638817bd

daemon/net.c
daemon/net.h
lib/uilib.c

index 16c7bbb..d90146d 100644 (file)
@@ -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)
            {
index 7d63981..f9b7a29 100644 (file)
@@ -20,6 +20,7 @@
 #define _NET_H
 
 #include <sys/socket.h>
+#include <sys/un.h>
 
 #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
index 034c823..65215b7 100644 (file)
@@ -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);
 }