From: "James F. Hranicky" Date: 2006-07-14T04:04:13+09:00 Subject: Re: Patch for Unix socket peer credentials --Boundary-00=_nkptEwVYyvzyFVX Content-Type: Multipart/Mixed; boundary="Boundary-00=_nkptEwVYyvzyFVX" --Boundary-00=_nkptEwVYyvzyFVX Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Content-Disposition: inline On Tuesday 11 July 2006 00:10, Tanaka Akira wrote: > In article <200607101352.16804.jfh@cise.ufl.edu>, > > I think it's good enough. Ok. I changed it to a struct, and made it a method of BasicSock: ruby -rsocket -e 'p UNIXServer.new(ARGV.shift).accept.peer_cred' /tmp/sock # Here's the patch. The method should throw an error if any of the system calls fail or if (uid < 0 || gid < 0). Questions or comments welcome. Jim --Boundary-00=_nkptEwVYyvzyFVX Content-Type: text/x-diff; charset="iso-8859-1"; name="ruby-sock-cred.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="ruby-sock-cred.patch" diff -ur ruby-1.8.5-preview1/ext/socket/extconf.rb ruby-1.8.5-preview1.mod/ext/socket/extconf.rb --- ruby-1.8.5-preview1/ext/socket/extconf.rb 2006-06-06 22:40:22.000000000 -0400 +++ ruby-1.8.5-preview1.mod/ext/socket/extconf.rb 2006-07-11 16:51:55.717600000 -0400 @@ -226,6 +226,20 @@ EOS end +if have_library("c", "getpeerucred") + $defs << "-DHAVE_GETPEERUCRED " +else + puts "no getpeerucred" +end + +if have_library("c", "getpeereid") + $defs << "-DHAVE_GETPEEREID " +end + +if have_macro("SO_PEERCRED", "sys/socket.h") + $defs << "-DHAVE_SO_PEERCRED " +end + case with_config("lookup-order-hack", "UNSPEC") when "INET" $defs << "-DLOOKUP_ORDER_HACK_INET" diff -ur ruby-1.8.5-preview1/ext/socket/socket.c ruby-1.8.5-preview1.mod/ext/socket/socket.c --- ruby-1.8.5-preview1/ext/socket/socket.c 2006-06-21 16:19:07.000000000 -0400 +++ ruby-1.8.5-preview1.mod/ext/socket/socket.c 2006-07-13 14:58:17.499317000 -0400 @@ -71,6 +71,13 @@ #endif #include "sockport.h" +#if defined(HAVE_GETPEERUCRED) +#include +#elif defined(HAVE_GETPEEREID) +#include +#include +#endif + #if defined(__vms) #include #endif @@ -89,6 +96,7 @@ VALUE rb_cSocket; static VALUE rb_eSocket; +static VALUE sSockCred; #ifdef SOCKS VALUE rb_cSOCKSSocket; @@ -1643,6 +1651,101 @@ return ipaddr((struct sockaddr*)&addr); } +/* + * Document-method: peer_cred + * call-seq: socket.peer_cred => s + * s.uid => ruid || euid + * s.gid => rgid || egid + * s.ruid => ruid + * s.euid => euid + * s.rgid => rgid + * s.egid => egid + * } + * + * Returns a struct containing the credentials of the peer socket for + * Unix domain stream sockets + * + * === Example + * # Client example + * require 'socket' + * s = UNIXSocket.new("/path/to/socket") + * puts "Peer uid is #{s.peer_cred.uid}" + * + * # Server example + * require 'socket' + * s = UNIXServer.new("/path/to/socket") + * ns = s.accept + * puts "Peer uid is #{ns.peer_cred.uid}" + * + */ + +static VALUE +unix_peer_cred(sock) + VALUE sock; +{ + char buf[1024]; + socklen_t len = sizeof buf; + OpenFile *fptr; + int uid, gid, ruid, rgid, euid, egid; + uid = gid = ruid = rgid = euid = egid = -1; + +#if defined(HAVE_GETPEERUCRED) + ucred_t *creds; +#elif defined(HAVE_SO_PEERCRED) + struct ucred creds; +#else + rb_raise(rb_eSocket, "peer_cred not implemented on this platform"); +#endif + + GetOpenFile(sock, fptr); + +#if defined(HAVE_GETPEERUCRED) + if ((creds = malloc(ucred_size())) == NULL) + rb_sys_fail("malloc"); + + if (getpeerucred(fileno(fptr->f), &creds) < 0) + rb_sys_fail("getpeerucred(2)"); + + uid = ucred_getruid(creds); + gid = ucred_getrgid(creds); + ruid = ucred_getruid(creds); + rgid = ucred_getrgid(creds); + euid = ucred_geteuid(creds); + egid = ucred_getegid(creds); + + ucred_free(creds); + +#elif defined(HAVE_SO_PEERCRED) + + if (getsockopt(fileno(fptr->f), SOL_SOCKET, SO_PEERCRED, &creds, &len) < 0) + rb_sys_fail("getsockopt"); + + uid = creds.uid; + gid = creds.gid; + euid = creds.uid; + egid = creds.gid; + +#elif defined(HAVE_GETPEEREID) + if (getpeereid(fileno(fptr->f), &euid, &egid) < 0) + rb_sys_fail("getpeereid"); + + uid = euid; + gid = egid; + +#endif + + if (uid < 0 || gid < 0) + rb_raise(rb_eSocket, "Invalid credentials: uid %d, gid %d", uid, gid); + + return rb_struct_new(sSockCred, INT2FIX(uid), + INT2FIX(gid), + INT2FIX(ruid), + INT2FIX(rgid), + INT2FIX(euid), + INT2FIX(egid), + 0); +} + static VALUE ip_recvfrom(argc, argv, sock) int argc; @@ -3864,6 +3967,10 @@ rb_define_method(rb_cBasicSocket, "recv", bsock_recv, -1); rb_define_method(rb_cBasicSocket, "recv_nonblock", bsock_recv_nonblock, -1); + rb_global_variable(&sSockCred); + sSockCred = rb_struct_define("SockCred", "uid", "gid", "ruid", "rgid", "euid", "egid", NULL); + rb_define_method(rb_cBasicSocket, "peer_cred", unix_peer_cred, 0); + rb_cIPSocket = rb_define_class("IPSocket", rb_cBasicSocket); rb_define_global_const("IPsocket", rb_cIPSocket); rb_define_method(rb_cIPSocket, "addr", ip_addr, 0); --Boundary-00=_nkptEwVYyvzyFVX-- --Boundary-00=_nkptEwVYyvzyFVX--