From: "James F. Hranicky" Date: 2006-07-20T02:40:33+09:00 Subject: Re: Patch for Unix socket peer credentials --Boundary-00=_J6mvEdRcvmhGl70 Content-Type: Multipart/Mixed; boundary="Boundary-00=_J6mvEdRcvmhGl70" --Boundary-00=_J6mvEdRcvmhGl70 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Content-Disposition: inline On Tuesday 18 July 2006 15:52, Eric Hodel wrote: > > + if (uid < 0 || gid < 0) > > + rb_raise(rb_eSocket, "Invalid credentials: uid %d, gid % > > d", uid, gid); > > Negative UID and GID are valid on some operating systems. Are negative values allowed on Linux? AFAICT, if the credentials aren't available on Linux, say when I check a TCPServer socket's credentials after accepting a connection from another host, the system call returns 0 but sets the uid & gid to -1: ruby -rsocket -e 'p TCPServer.new(ARGV.shift).accept.peer_cred' 5670 {:ruid=>nil, :rgid=>nil, :uid=>-1, :gid=>-1, :euid=>-1, :egid=>-1} If negative values are allowed, I really don't know what to do, otherwise, I can raise an exception. I can also just leave it to the user to raise an execption if e.g. Etc.getpwuid(creds[:uid]) fails. Attached is the latest patch. Questions/comments welcome. Jim --Boundary-00=_J6mvEdRcvmhGl70 Content-Type: text/x-diff; charset="iso-8859-1"; name="ruby-sock-cred-02.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="ruby-sock-cred-02.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 Tue Jun 6 22:40:22 2006 +++ ruby-1.8.5-preview1.mod/ext/socket/extconf.rb Wed Jul 19 12:23:10 2006 @@ -226,6 +226,13 @@ EOS end +have_func("getpeerucred") +have_func("getpeereid") + +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 Wed Jun 21 16:19:07 2006 +++ ruby-1.8.5-preview1.mod/ext/socket/socket.c Wed Jul 19 10:51:42 2006 @@ -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 @@ -1643,7 +1650,121 @@ return ipaddr((struct sockaddr*)&addr); } +/* + * Document-method: peer_cred + * call-seq: socket.peer_cred => hash + * hash[:uid] => ruid || euid + * hash[:gid] => rgid || egid + * hash[:ruid] => ruid + * hash[:euid] => euid + * hash[:rgid] => rgid + * hash[:egid] => egid + * } + * + * Returns a hash 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 +bsock_peer_cred(sock) + VALUE sock; +{ + char buf[1024]; + socklen_t len = sizeof buf; + OpenFile *fptr; + VALUE kuid, kgid, kruid, krgid, keuid, kegid, ahash, hashval; +/* 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; +#elif defined(HAVE_GETPEEREID) + int euid, egid; +#else + rb_raise(rb_eSocket, "peer_cred not implemented on this platform"); +#endif + + GetOpenFile(sock, fptr); + + kuid = rb_str_intern(rb_str_new2("uid")); + kgid = rb_str_intern(rb_str_new2("gid")); + kruid = rb_str_intern(rb_str_new2("ruid")); + krgid = rb_str_intern(rb_str_new2("rgid")); + keuid = rb_str_intern(rb_str_new2("euid")); + kegid = rb_str_intern(rb_str_new2("egid")); + + ahash = rb_hash_new(); + + rb_hash_aset(ahash, kuid, Qnil); + rb_hash_aset(ahash, kgid, Qnil); + rb_hash_aset(ahash, kruid, Qnil); + rb_hash_aset(ahash, krgid, Qnil); + rb_hash_aset(ahash, keuid, Qnil); + rb_hash_aset(ahash, kegid, Qnil); + +#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)"); + + rb_hash_aset(ahash, kuid, INT2FIX(ucred_getruid(creds))); + rb_hash_aset(ahash, kgid, INT2FIX(ucred_getrgid(creds))); + rb_hash_aset(ahash, kruid, INT2FIX(ucred_getruid(creds))); + rb_hash_aset(ahash, krgid, INT2FIX(ucred_getrgid(creds))); + rb_hash_aset(ahash, keuid, INT2FIX(ucred_geteuid(creds))); + rb_hash_aset(ahash, kegid, INT2FIX(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"); + + rb_hash_aset(ahash, kuid, INT2FIX(creds.uid)); + rb_hash_aset(ahash, kgid, INT2FIX(creds.gid)); + rb_hash_aset(ahash, keuid, INT2FIX(creds.uid)); + rb_hash_aset(ahash, kegid, INT2FIX(creds.gid)); + +#elif defined(HAVE_GETPEEREID) + if (getpeereid(fileno(fptr->f), &euid, &egid) < 0) + rb_sys_fail("getpeereid"); + + rb_hash_aset(ahash, kuid, INT2FIX(euid)); + rb_hash_aset(ahash, kgid, INT2FIX(egid)); + rb_hash_aset(ahash, keuid, INT2FIX(euid)); + rb_hash_aset(ahash, kegid, INT2FIX(egid)); + +#endif + + if ((hashval = rb_hash_aref(ahash, kuid)) == Qnil) + rb_raise(rb_eSocket, "Invalid credentials: uid is nil"); + + if ((hashval = rb_hash_aref(ahash, kgid)) == Qnil) + rb_raise(rb_eSocket, "Invalid credentials: gid is nil"); + + return ahash; + +} + +static VALUE ip_recvfrom(argc, argv, sock) int argc; VALUE *argv; @@ -3864,6 +3985,8 @@ rb_define_method(rb_cBasicSocket, "recv", bsock_recv, -1); rb_define_method(rb_cBasicSocket, "recv_nonblock", bsock_recv_nonblock, -1); + rb_define_method(rb_cBasicSocket, "peer_cred", bsock_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=_J6mvEdRcvmhGl70-- --Boundary-00=_J6mvEdRcvmhGl70--