socket: getpeercreds() - getpeereid() + pid
authorMarko Kreen <markokr@gmail.com>
Tue, 2 Apr 2013 20:01:09 +0000 (23:01 +0300)
committerMarko Kreen <markokr@gmail.com>
Tue, 2 Apr 2013 20:01:09 +0000 (23:01 +0300)
Most OSes have also way to get pid of unix socket peer.

Provide generic API for fetching it.

Make compat getpeereid() wrap it, so all compat goo
is in one place.

usual/socket.c
usual/socket.h

index 34b31dd2cd1a5177f8a7d06212dfe170eba9c6bd..e0ab5d070792e1d21d661bf72ab211a81ef1952c 100644 (file)
@@ -184,38 +184,87 @@ const char *sa2str(const struct sockaddr *sa, char *dst, int dstlen)
 
 #ifndef HAVE_GETPEEREID
 /*
- * Get other side's uid for UNIX socket.
- *
- * Standardise on getpeereid() from BSDs.
+ * Get other side's uid and git for UNIX socket.
  */
 int getpeereid(int fd, uid_t *uid_p, gid_t *gid_p)
 {
-#ifdef SO_PEERCRED
-       struct ucred cred;
+       pid_t pid;
+       return getpeercreds(fd, uid_p, gid_p, &pid);
+}
+#endif
+
+/*
+ * Get uid, gid and pid of unix socket peer.
+ *
+ * Pid may not be availalbe on some OSes.
+ * It's set to 0 then.
+ */
+int getpeercreds(int fd, uid_t *uid_p, gid_t *gid_p, pid_t *pid_p)
+{
+       /* What a mess */
+
+#if defined(SO_PEERCRED)
+
+#ifdef HAVE_SYS_UCRED_H
+       struct sockpeercred cred;       /* openbsd */
+#else
+       struct ucred cred;              /* linux */
+#endif
        socklen_t len = sizeof(cred);
        if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) >= 0) {
                *uid_p = cred.uid;
                *gid_p = cred.gid;
+               *pid_p = cred.pid;
                return 0;
        }
-#else /* !SO_PEERCRED */
-#ifdef HAVE_GETPEERUCRED
+       return -1;
+#elif defined(HAVE_GETPEERUCRED)
+       /* solaris */
        ucred_t *cred = NULL;
        if (getpeerucred(fd, &cred) >= 0) {
                *uid_p = ucred_geteuid(cred);
                *gid_p = ucred_getegid(cred);
+               *pid_p = ucred_getpid(cred);
                ucred_free(cred);
                if ((int)*uid_p == -1 || (int)*gid_p == -1)
                        return -1;
                return 0;
        }
+       return -1;
+#elif defined(LOCAL_PEEREID)
+       /* netbsd */
+       struct unpcbid cred;
+       socklen_t len = sizeof(cred);
+       if (getsockopt(fd, 0, LOCAL_PEEREID, &cred, &len) < 0)
+               return -1;
+       *uid_p = cred.unp_euid;
+       *gid_p = cred.unp_egid;
+       *pid_p = cred.unp_pid;
+       return 0;
+#elif defined(HAVE_GETPEEREID)
+       /* generic bsd; no pid */
+       *pid_p = 0;
+       return getpeereid(fd, uid_p, gid_p);
+#elif defined(LOCAL_PEERCRED)
+       /* old freebsd, osx; no pid */
+       struct xucred cred;
+       socklen_t len = sizeof(cred);
+       if (getsockopt(fd, 0, LOCAL_PEERCRED, &cred, &len) < 0)
+               return -1;
+       if (cred.cr_version != XUCRED_VERSION) {
+               errno = EIO;
+               return -1;
+       }
+       *uid_p = cred.cr_uid;
+       *gid_p = cred.cr_gid;
+       *pid_p = 0;
+       return 0;
 #else
+       /* no implementation */
        errno = ENOSYS;
-#endif /* HAVE_GETPEERUCRED */
-#endif /* !SO_PEERCRED */
        return -1;
-}
 #endif
+}
 
 
 #ifndef HAVE_POLL
index 85c3e52869b3c0d00ef3a37193ce2a71bc918b40..e53d211237b03d08d05e4d40aa4c39fe01f4eea5 100644 (file)
@@ -124,6 +124,10 @@ int inet_pton(int af, const char *src, void *dst);
 int getpeereid(int fd, uid_t *uid_p, gid_t *gid_p);
 #endif
 
+#define getpeercreds(a,b,c,d) usual_getpeercreds(a,b,c,d)
+/** Get info of UNIX socket peer */
+int getpeercreds(int fd, uid_t *uid_p, gid_t *gid_p, pid_t *pid_p);
+
 #if !defined(HAVE_POLL)
 #define POLLIN         (1 << 0)
 #define POLLOUT                (1 << 1)