diff options
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | ext/socket/basicsocket.c | 37 | ||||
-rw-r--r-- | ext/socket/extconf.rb | 2 | ||||
-rw-r--r-- | test/socket/test_unix.rb | 14 |
4 files changed, 59 insertions, 0 deletions
@@ -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 |