Commit 5b19adfa82b49bdb9b46c857b618c181f238290b

Guillem Jover 2010-12-17T10:50:56

Add getpeereid function

diff --git a/Makefile b/Makefile
index fc4b9fd..4aa64ef 100644
--- a/Makefile
+++ b/Makefile
@@ -26,6 +26,7 @@ LIB_SRCS := \
 	err.c \
 	fgetln.c \
 	flopen.c \
+	getpeereid.c \
 	heapsort.c \
 	humanize_number.c \
 	dehumanize_number.c \
@@ -84,6 +85,7 @@ LIB_MANS := \
 	strlcat.3 \
 	fgetln.3 \
 	flopen.3 \
+	getpeereid.3 \
 	readpassphrase.3 \
 	reallocf.3 \
 	humanize_number.3 \
diff --git a/Versions b/Versions
index f2df70c..7c9437e 100644
--- a/Versions
+++ b/Versions
@@ -67,5 +67,6 @@ LIBBSD_0.2 {
 
 LIBBSD_0.3 {
     reallocf;
+    getpeereid;
 } LIBBSD_0.2;
 
diff --git a/include/bsd/unistd.h b/include/bsd/unistd.h
index f9f7874..2a22fbc 100644
--- a/include/bsd/unistd.h
+++ b/include/bsd/unistd.h
@@ -39,6 +39,8 @@ mode_t getmode(const void *set, mode_t mode);
 void *setmode(const char *mode_str);
 
 void setproctitle(const char *fmt, ...);
+
+int getpeereid(int s, uid_t *euid, gid_t *egid);
 __END_DECLS
 
 #endif
diff --git a/src/getpeereid.3 b/src/getpeereid.3
new file mode 100644
index 0000000..66ae6c2
--- /dev/null
+++ b/src/getpeereid.3
@@ -0,0 +1,138 @@
+.\"
+.\" Copyright (c) 2001 Dima Dorfman.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 15, 2001
+.Dt GETPEEREID 3
+.Os
+.Sh NAME
+.Nm getpeereid
+.Nd get the effective credentials of a UNIX-domain peer
+.Sh LIBRARY
+.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd)
+.Lb libbsd
+.Sh SYNOPSIS
+.In sys/types.h
+.In unistd.h
+.Ft int
+.Fn getpeereid "int s" "uid_t *euid" "gid_t *egid"
+.Sh DESCRIPTION
+The
+.Fn getpeereid
+function returns the effective user and group IDs of the
+peer connected to a
+.Ux Ns -domain
+socket.
+The argument
+.Fa s
+must be a
+.Ux Ns -domain
+socket
+.Pq Xr unix 4
+of type
+.Dv SOCK_STREAM
+on which either
+.Xr connect 2
+or
+.Xr listen 2
+have been called.
+The effective used ID is placed in
+.Fa euid ,
+and the effective group ID in
+.Fa egid .
+.Pp
+The credentials returned to the
+.Xr listen 2
+caller are those of its peer at the time it called
+.Xr connect 2 ;
+the credentials returned to the
+.Xr connect 2
+caller are those of its peer at the time it called
+.Xr listen 2 .
+This mechanism is reliable; there is no way for either side to influence
+the credentials returned to its peer except by calling the appropriate
+system call (i.e., either
+.Xr connect 2
+or
+.Xr listen 2 )
+under different effective credentials.
+.Pp
+One common use of this routine is for a
+.Ux Ns -domain
+server
+to verify the credentials of its client.
+Likewise, the client can verify the credentials of the server.
+.Sh IMPLEMENTATION NOTES
+On
+.Fx ,
+.Fn getpeereid
+is implemented in terms of the
+.Dv LOCAL_PEERCRED
+.Xr unix 4
+socket option.
+.Sh RETURN VALUES
+.Rv -std getpeereid
+.Sh ERRORS
+The
+.Fn getpeereid
+function
+fails if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The argument
+.Fa s
+is not a valid descriptor.
+.It Bq Er ENOTSOCK
+The argument
+.Fa s
+is a file, not a socket.
+.It Bq Er ENOTCONN
+The argument
+.Fa s
+does not refer to a socket on which
+.Xr connect 2
+or
+.Xr listen 2
+have been called.
+.It Bq Er EINVAL
+The argument
+.Fa s
+does not refer to a socket of type
+.Dv SOCK_STREAM ,
+or the kernel returned invalid data.
+.El
+.Sh SEE ALSO
+.Xr connect 2 ,
+.Xr getpeername 2 ,
+.Xr getsockname 2 ,
+.Xr getsockopt 2 ,
+.Xr listen 2 ,
+.Xr unix 4
+.Sh HISTORY
+The
+.Fn getpeereid
+function appeared in
+.Fx 4.6 .
diff --git a/src/getpeereid.c b/src/getpeereid.c
new file mode 100644
index 0000000..8990357
--- /dev/null
+++ b/src/getpeereid.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright © 2010 Guillem Jover
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+#if defined(SO_PEERCRED)
+/* Linux and OpenBSD */
+int
+getpeereid(int s, uid_t *euid, gid_t *egid)
+{
+/* XXX: This should be autodetected at build time instead. */
+#if defined(__linux__)
+	struct ucred cred;
+#elif defined(__OpenBSD__)
+	struct sockpeercred cred;
+#endif
+	socklen_t credlen = sizeof(cred);
+	int ret;
+
+	ret = getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cred, &credlen);
+	if (ret != 0)
+		return ret;
+
+	*euid = cred.uid;
+	*egid = cred.gid;
+
+	return 0;
+}
+#elif defined(LOCAL_PEERCRED)
+/* FreeBSD */
+#include <sys/ucred.h>
+
+int
+getpeereid(int s, uid_t *euid, gid_t *egid)
+{
+	struct xucred cred;
+	socklen_t credlen = sizeof(cred);
+	int ret;
+
+	ret = getsockopt(s, 0, LOCAL_PEERCRED, &cred, &credlen);
+	if (ret != 0)
+		return ret;
+	if (cred.cr_version != XUCRED_VERSION)
+		return EINVAL;
+
+	*euid = cred.cr_uid;
+	*egid = cred.cr_gid;
+
+	return 0;
+}
+#elif defined(LOCAL_PEEREID)
+/* NetBSD */
+int
+getpeereid(int s, uid_t *euid, gid_t *egid)
+{
+	struct unpcbid cred;
+	socklen_t credlen = sizeof(cred);
+	int ret;
+
+	ret = getsockopt(s, 0, LOCAL_PEEREID, &cred, &credlen);
+	if (ret != 0)
+		return ret;
+
+	*euid = cred.unp_euid;
+	*egid = cred.unp_egid;
+
+	return 0;
+}
+#elif defined(__sun)
+/* Solaris */
+int
+getpeereid(int s, uid_t *euid, gid_t *egid)
+{
+	ucred_t cred_inst;
+	ucred_t *cred = &cred_inst;
+	int ret;
+
+	ret = getpeerucred(s, &cred);
+	if (ret != 0)
+		return ret;
+
+	*euid = ucred_geteuid(cred);
+	if (*euid < 0)
+		return -1;
+	*egid = ucred_getegid(cred);
+	if (*egid < 0)
+		return -1;
+
+	return 0;
+}
+#else
+#warning "This platform needs an implementation of getpeereid()"
+int
+getpeereid(int s, uid_t *euid, gid_t *egid)
+{
+	*euid = geteuid();
+	*egid = getegid();
+
+	return 0;
+}
+#endif