]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
net_getunixcred() support for NetBSD <v5.0. Fixed also building with other NetBSDs.
authorTimo Sirainen <tss@iki.fi>
Thu, 11 Apr 2013 10:15:39 +0000 (13:15 +0300)
committerTimo Sirainen <tss@iki.fi>
Thu, 11 Apr 2013 10:15:39 +0000 (13:15 +0300)
Patch by Emmanuel Dreyfus

src/lib/net.c

index 2490cb37d1c1aeb2d219f67d50aff50d6e8e7448..754e5bd1aab8af0bdbc7977de95462eec386b6dd 100644 (file)
@@ -38,6 +38,10 @@ union sockaddr_union_unix {
 #  define SIZEOF_SOCKADDR(so) (sizeof(so.sin))
 #endif
 
+#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED) && !defined(HAVE_GETPEERUCRED) && defined(MSG_WAITALL) && defined(LOCAL_CREDS)
+#  define NEEDS_LOCAL_CREDS 1
+#endif
+
 bool net_ip_compare(const struct ip_addr *ip1, const struct ip_addr *ip2)
 {
        return net_ip_cmp(ip1, ip2) == 0;
@@ -303,6 +307,16 @@ int net_connect_unix(const char *path)
                return -1;
        }
 
+#ifdef NEEDS_LOCAL_CREDS
+       {
+               int on = 1;
+               if (setsockopt(fd, 0, LOCAL_CREDS, &on, sizeof on)) {
+                       i_error("setsockopt(LOCAL_CREDS) failed: %m");
+                       return -1;
+               }
+       }
+#endif
+
        return fd;
 }
 
@@ -458,6 +472,16 @@ int net_listen_unix(const char *path, int backlog)
                return -1;
        }
 
+#ifdef NEEDS_LOCAL_CREDS
+       {
+               int on = 1;
+               if (setsockopt(fd, 0, LOCAL_CREDS, &on, sizeof on)) {
+                       i_error("setsockopt(LOCAL_CREDS) failed: %m");
+                       return -1;
+               }
+       }
+#endif
+
        /* bind */
        if (bind(fd, &sa.sa, sizeof(sa)) < 0) {
                if (errno != EADDRINUSE)
@@ -721,7 +745,7 @@ int net_getunixcred(int fd, struct net_unix_cred *cred_r)
        struct unpcbid ucred;
        socklen_t len = sizeof(ucred);
 
-       if (getsockopt(s, 0, LOCAL_PEEREID, &ucred, &len) < 0) {
+       if (getsockopt(fd, 0, LOCAL_PEEREID, &ucred, &len) < 0) {
                i_error("getsockopt(LOCAL_PEEREID) failed: %m");
                return -1;
        }
@@ -776,6 +800,44 @@ int net_getunixcred(int fd, struct net_unix_cred *cred_r)
                return -1;
        }
        return 0;
+#elif NEEDS_LOCAL_CREDS
+       /* NetBSD < 5 */
+       int i, n, on;
+       struct iovec iov;
+       struct msghdr msg;
+       struct {
+               struct cmsghdr ch;
+               char buf[110];
+       } cdata;
+       struct sockcred *sc;
+
+       iov.iov_base = (char *)&on;
+       iov.iov_len = 1;
+
+       sc = (struct sockcred *)cdata.buf;
+       sc->sc_uid = sc->sc_euid = sc->sc_gid = sc->sc_egid = -1;
+       memset(&cdata.ch, 0, sizeof cdata.ch);
+
+       memset(&msg, 0, sizeof msg);
+
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+       msg.msg_control = &cdata;
+       msg.msg_controllen = sizeof(cdata.ch) + sizeof(cdata.buf);
+
+       for (i = 0; i < 10; i++) {
+               n = recvmsg(fd, &msg, MSG_WAITALL | MSG_PEEK);
+               if (n >= 0 || errno != EAGAIN)
+                       break;
+               usleep(100);
+       }
+       if (n < 0) {
+               i_error("recvmsg() failed: %m");
+               return -1;
+       }
+       cred_r->uid = sc->sc_euid;
+       cred_r->gid = sc->sc_egid;
+       return 0;
 #else
        errno = EINVAL;
        return -1;