diff src/lib/network.c @ 14233:80688ab1ea3d

Extends struct net_unix_cred with pid field and modifies net_getunixcred() to fill it in if possible. Depends: none
author Timo Sirainen <tss@iki.fi>
date Sat, 19 May 2012 22:40:08 +0300
parents ba770cba5598
children fbb1ecb9b888
line wrap: on
line diff
--- a/src/lib/network.c	Sat May 19 22:28:19 2012 +0300
+++ b/src/lib/network.c	Sat May 19 22:40:08 2012 +0300
@@ -13,8 +13,10 @@
 #include <ctype.h>
 #include <sys/un.h>
 #include <netinet/tcp.h>
-#ifdef HAVE_UCRED_H
+#if defined(HAVE_UCRED_H)
 #  include <ucred.h> /* for getpeerucred() */
+#elif defined(HAVE_SYS_UCRED_H)
+#  include <sys/ucred.h> /* for FreeBSD struct xucred */
 #endif
 
 union sockaddr_union {
@@ -694,16 +696,14 @@
 
 int net_getunixcred(int fd, struct net_unix_cred *cred_r)
 {
-#if defined(HAVE_GETPEEREID)
-	/* OSX 10.4+, FreeBSD 4.6+, OpenBSD 3.0+, NetBSD 5.0+ */
-	if (getpeereid(fd, &cred_r->uid, &cred_r->gid) < 0) {
-		i_error("getpeereid() failed: %m");
-		return -1;
-	}
-	return 0;
-#elif defined(SO_PEERCRED)
+#if defined(SO_PEERCRED)
+# if defined(HAVE_STRUCT_SOCKPEERCRED)
+	/* OpenBSD (may also provide getpeereid, but we also want pid) */
+	struct sockpeercred ucred;
+# else
 	/* Linux */
 	struct ucred ucred;
+# endif
 	socklen_t len = sizeof(ucred);
 
 	if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0) {
@@ -712,6 +712,48 @@
 	}
 	cred_r->uid = ucred.uid;
 	cred_r->gid = ucred.gid;
+	cred_r->pid = ucred.pid;
+	return 0;
+#elif defined(LOCAL_PEEREID)
+	/* NetBSD (may also provide getpeereid, but we also want pid) */
+	struct unpcbid ucred;
+	socklen_t len = sizeof(ucred);
+
+	if (getsockopt(s, 0, LOCAL_PEEREID, &ucred, &len) < 0) {
+		i_error("getsockopt(LOCAL_PEEREID) failed: %m");
+		return -1;
+	}
+	
+	cred_r->uid = ucred.unp_euid;
+	cred_r->gid = ucred.unp_egid;
+	cred_r->pid = ucred.unp_pid;
+	return 0;
+#elif defined(HAVE_GETPEEREID)
+	/* OSX 10.4+, FreeBSD 4.6+, OpenBSD 3.0+, NetBSD 5.0+ */
+	if (getpeereid(fd, &cred_r->uid, &cred_r->gid) < 0) {
+		i_error("getpeereid() failed: %m");
+		return -1;
+	}
+	cred_r->pid = (pid_t)-1;
+	return 0;
+#elif defined(LOCAL_PEERCRED)
+	/* Older FreeBSD */
+	struct xucred ucred;
+	socklen_t len = sizeof(ucred);
+
+	if (getsockopt(fd, 0, LOCAL_PEERCRED, &ucred, &len) < 0) {
+		i_error("getsockopt(LOCAL_PEERCRED) failed: %m");
+		return -1;
+	}
+
+	if (ucred.cr_version != XUCRED_VERSION) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	cred_r->uid = ucred.cr_uid;
+	cred_r->gid = ucred.cr_gid;
+	cred_r->pid = (pid_t)-1;
 	return 0;
 #elif defined(HAVE_GETPEERUCRED)
 	/* Solaris */
@@ -723,6 +765,7 @@
 	}
 	cred_r->uid = ucred_geteuid(ucred);
 	cred_r->gid = ucred_getrgid(ucred);
+	cred_r->pid = ucred_getpid(ucred);
 	ucred_free(ucred);
 
 	if (cred_r->uid == (uid_t)-1 ||