aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--ext/socket/basicsocket.c37
-rw-r--r--ext/socket/extconf.rb2
-rw-r--r--test/socket/test_unix.rb14
4 files changed, 59 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 38114ac882..f1f62449bc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+Wed Feb 11 10:16:34 2009 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: check getpeereid.
+
+ * ext/socket/basicsocket.c (bsock_getpeereid): new method.
+
Wed Feb 11 09:58:59 2009 Tanaka Akira <akr@fsij.org>
* ext/socket/lib/socket.rb (Socket::UDPSource#inspect): fix variable
diff --git a/ext/socket/basicsocket.c b/ext/socket/basicsocket.c
index 88f8b1ba67..b818ffa82f 100644
--- a/ext/socket/basicsocket.c
+++ b/ext/socket/basicsocket.c
@@ -363,6 +363,42 @@ bsock_getpeername(VALUE sock)
/*
* call-seq:
+ * basicsocket.getpeereid => [euid, egid]
+ *
+ * Returns the user and group on the peer of the UNIX socket.
+ * The result is a two element array which contains the effective uid and the effective gid.
+ *
+ * Socket.unix_server_loop("/tmp/sock") {|s|
+ * p s.getpeereid #=> [1000, 1000]
+ * }
+ *
+ */
+static VALUE
+bsock_getpeereid(VALUE self)
+{
+#if defined(HAVE_GETPEEREID)
+ rb_io_t *fptr;
+ uid_t euid;
+ gid_t egid;
+ GetOpenFile(self, fptr);
+ if (getpeereid(fptr->fd, &euid, &egid) == -1)
+ rb_sys_fail("getpeereid");
+ return rb_assoc_new(UIDT2NUM(euid), GIDT2NUM(egid));
+#elif defined(SO_PEERCRED) /* GNU/Linux */
+ rb_io_t *fptr;
+ struct ucred cred;
+ socklen_t len = sizeof(cred);
+ GetOpenFile(self, fptr);
+ if (getsockopt(fptr->fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) == -1)
+ rb_sys_fail("getsockopt(SO_PEERCRED)");
+ return rb_assoc_new(UIDT2NUM(cred.uid), GIDT2NUM(cred.gid));
+#else
+ rb_notimplement();
+#endif
+}
+
+/*
+ * call-seq:
* bsock.local_address => addrinfo
*
* Returns an Addrinfo object for local address obtained by getsockname.
@@ -646,6 +682,7 @@ Init_basicsocket(void)
rb_define_method(rb_cBasicSocket, "getsockopt", bsock_getsockopt, 2);
rb_define_method(rb_cBasicSocket, "getsockname", bsock_getsockname, 0);
rb_define_method(rb_cBasicSocket, "getpeername", bsock_getpeername, 0);
+ rb_define_method(rb_cBasicSocket, "getpeereid", bsock_getpeereid, 0);
rb_define_method(rb_cBasicSocket, "local_address", bsock_local_address, 0);
rb_define_method(rb_cBasicSocket, "remote_address", bsock_remote_address, 0);
rb_define_method(rb_cBasicSocket, "send", bsock_send, -1);
diff --git a/ext/socket/extconf.rb b/ext/socket/extconf.rb
index f3f4529902..921a0eeeee 100644
--- a/ext/socket/extconf.rb
+++ b/ext/socket/extconf.rb
@@ -314,6 +314,8 @@ have_type("struct in6_pktinfo", headers) {|src|
have_type("struct sockcred", headers)
have_type("struct cmsgcred", headers)
+have_func("getpeereid")
+
$distcleanfiles << "constants.h" << "constdefs.*"
if have_func(test_func)
diff --git a/test/socket/test_unix.rb b/test/socket/test_unix.rb
index feeef08108..61b55c5a5d 100644
--- a/test/socket/test_unix.rb
+++ b/test/socket/test_unix.rb
@@ -384,4 +384,18 @@ class TestUNIXSocket < Test::Unit::TestCase
}
end
+ def test_getpeereid
+ Dir.mktmpdir {|d|
+ path = "#{d}/sock"
+ serv = Socket.unix_server_socket(path)
+ c = Socket.unix(path)
+ s, = serv.accept
+ begin
+ assert_equal([Process.euid, Process.egid], c.getpeereid)
+ assert_equal([Process.euid, Process.egid], s.getpeereid)
+ rescue NotImplementedError
+ end
+ }
+ end
+
end if defined?(UNIXSocket) && /cygwin/ !~ RUBY_PLATFORM