From 26ef017ec97c194d4ba5261d617e3e380cc967c6 Mon Sep 17 00:00:00 2001 From: Marko Kreen Date: Tue, 2 Apr 2013 23:01:09 +0300 Subject: [PATCH] socket: getpeercreds() - getpeereid() + pid 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 | 69 ++++++++++++++++++++++++++++++++++++++++++-------- usual/socket.h | 4 +++ 2 files changed, 63 insertions(+), 10 deletions(-) diff --git a/usual/socket.c b/usual/socket.c index 34b31dd..e0ab5d0 100644 --- a/usual/socket.c +++ b/usual/socket.c @@ -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 diff --git a/usual/socket.h b/usual/socket.h index 85c3e52..e53d211 100644 --- a/usual/socket.h +++ b/usual/socket.h @@ -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) -- 2.39.5