--Boundary-00 6mvEdRcvmhGl70 Content-Type: Multipart/Mixed; boundaryoundary-00 6mvEdRcvmhGl70" --Boundary-00 6mvEdRcvmhGl70 Content-Type: text/plain; charset so-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 il, :rgid il, :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 6mvEdRcvmhGl70 Content-Type: text/x-diff; charset so-8859-1"; name uby-sock-cred-02.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename uby-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 <ucred.h> +#elif defined(HAVE_GETPEEREID) +#include <sys/types.h> +#include <unistd.h> +#endif + #if defined(__vms) #include <tcp.h> #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 NIXSocket.new("/path/to/socket") + * puts "Peer uid is #{s.peer_cred[:uid]}" + * + * # Server example + * require 'socket' + * s NIXServer.new("/path/to/socket") + * ns .accept + * puts "Peer uid is #{ns.peer_cred[:uid]}" + * + */ + static VALUE +bsock_peer_cred(sock) + VALUE sock; +{ + char buf[1024]; + socklen_t len izeof buf; + OpenFile *fptr; + VALUE kuid, kgid, kruid, krgid, keuid, kegid, ahash, hashval; +/* int uid, gid, ruid, rgid, euid, egid; + uid id uid gid uid gid 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 b_str_intern(rb_str_new2("uid")); + kgid b_str_intern(rb_str_new2("gid")); + kruid b_str_intern(rb_str_new2("ruid")); + krgid b_str_intern(rb_str_new2("rgid")); + keuid b_str_intern(rb_str_new2("euid")); + kegid b_str_intern(rb_str_new2("egid")); + + ahash b_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 alloc(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 b_hash_aref(ahash, kuid)) Qnil) + rb_raise(rb_eSocket, "Invalid credentials: uid is nil"); + + if ((hashval b_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 b_define_class("IPSocket", rb_cBasicSocket); rb_define_global_const("IPsocket", rb_cIPSocket); rb_define_method(rb_cIPSocket, "addr", ip_addr, 0); --Boundary-00 6mvEdRcvmhGl70-- --Boundary-00 6mvEdRcvmhGl70--