--Boundary-006mvEdRcvmhGl70
Content-Type: Multipart/Mixed;
  boundaryoundary-006mvEdRcvmhGl70"

--Boundary-006mvEdRcvmhGl70
Content-Type: text/plain;
  charsetso-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
   {:ruidil, :rgidil, :uid1, :gid1, :euid1, :egid1}

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-006mvEdRcvmhGl70
Content-Type: text/x-diff;
  charsetso-8859-1";
  nameuby-sock-cred-02.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filenameuby-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-006mvEdRcvmhGl70--
--Boundary-006mvEdRcvmhGl70--