G
Guillaume Marcais
--=-LH2RX20AHG69TpQAZ+qL
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
To get a feel before submitting a real RCR:
Abstract:
Add calls to UNIXSocket to pass around the UNIX credentials (i.e. pid,
uid and gid).
Problem:
There is no way, that I know of, within Ruby to find out which process
is connected at the other end of a UNIX socket.
Ex:
[gus@comp unix_credentials]$ irb
irb(main):001:0> require 'socket'
=> true
irb(main):002:0> s = UNIXServer.new('unixtest')
=> #<UNIXServer:unixtest>
irb(main):003:0> t = s.accept
=> #<UNIXSocket:0x4396d330>
irb(main):004:0> t.peeraddr
=> ["AF_UNIX", ""] # Doesn't tell you anything!
Proposal:
I propose the addition of two methods, send_credentials and
recv_credentils to pass through a UNIX socket the process id, user id
and group id.
Analysis:
The Linux system provide a mechanism to send UNIX credentials as
ancilary data (the same way as you can pass file descriptors,
implemented in Ruby as send_io). Other UNIX implementation I believe
offer similar mechanism.
One difference with just sending this data directly through the UNIX
socket (for example as a Mashalled array containing the pid, uid and
gid) is that the system does some checks on the values send (unless you
are root and are allowed to lie).
Implementation:
The attached patch implements it. It has been tested on Linux 2.4 only.
It is heavily inspired by the implementation of send_io. Usage example:
server:
irb(main):001:0> require 'socket'
=> true
irb(main):002:0> s = UNIXServer.new('unixtest')
=> #<UNIXServer:unixtest>
irb(main):003:0> t = s.accept
=> #<UNIXSocket:0x4bf81330>
irb(main):004:0> t.recv_credentials
=> [1933, 501, 501]
client:
irb(main):001:0> require 'socket'
=> true
irb(main):002:0> s = UNIXSocket.new("unixtest")
=> #<UNIXSocket:unixtest>
irb(main):003:0> s.send_credentials
=> nil
irb(main):004:0> Process.pid
=> 1933
Guillaume.
--=-LH2RX20AHG69TpQAZ+qL
Content-Disposition: attachment; filename=unix-credentials.patch
Content-Transfer-Encoding: quoted-printable
Content-Type: text/x-diff; charset=ISO-8859-1
--- ruby/ext/socket/socket.c Mon Apr 5 03:45:22 2004
+++ ruby-1.8.1-unix-credentials/ext/socket/socket.c Tue May 18 20:10:14 200=
4
@@ -1656,6 +1656,163 @@
}
=20
static VALUE
+unix_send_credentials(argc, argv, sock)
+ int argc;
+ VALUE *argv, sock;
+{
+#if defined(HAVE_SENDMSG) && (defined(HAVE_ST_MSG_CONTROL) || defined(HAVE=
_ST_MSG_ACCRIGHTS)) && defined(SCM_CREDENTIALS)
+ OpenFile *fptr;
+ int pid, uid, gid;
+ struct msghdr msg;
+ struct iovec vec[1];
+ char buf[1];
+ int len;
+ struct ucred *creds;
+#if defined(HAVE_ST_MSG_CONTROL)
+ char ancillary[CMSG_SPACE(sizeof(struct ucred))];
+ struct cmsghdr *cmsg;
+#else
+ struct ucred creds_data;
+#endif
+ =20
+ GetOpenFile(sock, fptr);
+
+ rb_scan_args(argc, argv, "03", &pid, &uid, &gid);
+
+ /* Linux and Solaris doesn't work if msg_iov is NULL. */
+ buf[0] =3D '\0';
+ vec[0].iov_base =3D buf;
+ vec[0].iov_len =3D 1;
+ msg.msg_iov =3D vec;
+ msg.msg_iovlen =3D 1;
+ =20
+ msg.msg_name =3D NULL;
+ msg.msg_namelen =3D 0;
+#if defined(HAVE_ST_MSG_CONTROL) =20
+ msg.msg_control =3D ancillary;
+ msg.msg_controllen =3D sizeof(ancillary);
+ msg.msg_flags =3D 0;
+ cmsg =3D CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_len =3D CMSG_LEN(sizeof(struct ucred));
+ cmsg->cmsg_level =3D SOL_SOCKET;
+ cmsg->cmsg_type =3D SCM_CREDENTIALS;
+ creds =3D (struct ucred *)CMSG_DATA(cmsg);
+ msg.msg_controllen =3D cmsg->cmsg_len;
+#else
+ creds =3D &creds_data;
+ msg.msg_accrights =3D (caddr_t)creds;
+ msg.msg_accrightslen =3D sizeof(struct ucred);
+#endif
+
+ if (FIXNUM_P(pid)) {
+ creds->pid =3D FIX2INT(pid);
+ } else if (NIL_P(pid)) {
+ creds->pid =3D getpid();
+ } else {
+ rb_raise(rb_eTypeError, "FixNum");
+ }
+ if (FIXNUM_P(uid)) {
+ creds->uid =3D FIX2INT(uid);
+ } else if (NIL_P(uid)) {
+ creds->uid =3D getuid();
+ } else {
+ rb_raise(rb_eTypeError, "FixNum");
+ }
+ if (FIXNUM_P(gid)) {
+ creds->gid =3D FIX2INT(gid);
+ } else if (NIL_P(gid)) {
+ creds->gid =3D getgid();
+ } else {
+ rb_raise(rb_eTypeError, "FixNum");
+ }
+ =20
+ if ((len =3D sendmsg(fileno(fptr->f), &msg, 0)) =3D=3D -1)
+ rb_sys_fail("sendmsg(2)");
+ =20
+ return Qnil;
+#else=20
+ rb_notimplement();
+ return Qnil; /* not reached */
+#endif
+}
+
+
+static VALUE
+unix_recv_credentials(sock)
+ VALUE sock;
+{
+#if defined(HAVE_RECVMSG) && (defined(HAVE_ST_MSG_CONTROL) || defined(HAVE=
_ST_MSG_ACCRIGHTS)) && defined(SCM_CREDENTIALS)
+ OpenFile *fptr;
+ struct msghdr msg;
+ struct iovec vec;
+ char data_buf[1], control_buf[1024];
+ int len, true;
+ struct ucred *creds;
+#if defined(HAVE_ST_MSG_CONTROL)
+ struct cmsghdr *cmsg;
+#endif
+ =20
+ GetOpenFile(sock, fptr);
+ =20
+ thread_read_select(fileno(fptr->f));
+
+ true =3D 1;
+ if(setsockopt(fileno(fptr->f), SOL_SOCKET, SO_PASSCRED,=20
+ &true, sizeof(int)) < 0) {
+ rb_raise(rb_eSocket, "UNIX credentials cannot be received");
+ }
+
+ msg.msg_name =3D NULL;
+ msg.msg_namelen =3D 0;
+ vec.iov_base =3D data_buf;
+ vec.iov_len =3D sizeof(data_buf);
+ msg.msg_iov =3D &vec;
+ msg.msg_iovlen =3D 1;
+ msg.msg_control =3D control_buf;
+ msg.msg_controllen =3D sizeof(control_buf);
+ msg.msg_flags =3D 0;
+ =20
+#if !defined(HAVE_ST_MSG_CONTROL)
+ msg.msg_accrights =3D (caddr_t)creds;
+ msg.msg_accrightslen =3D sizeof(struct ucred);
+#endif
+ =20
+ if ((len =3D recvmsg(fileno(fptr->f), &msg, 0)) =3D=3D -1)
+ rb_sys_fail("recvmsg(2)");
+ =20
+
+#if defined(HAVE_ST_MSG_CONTROL)
+ for(cmsg =3D CMSG_FIRSTHDR(&msg);
+ cmsg !=3D NULL;
+ cmsg =3D CMSG_NXTHDR(&msg, cmsg)) {
+ if(cmsg->cmsg_level =3D=3D SOL_SOCKET=20
+ && cmsg->cmsg_type =3D=3D SCM_CREDENTIALS) {
+ creds =3D (struct ucred *)CMSG_DATA(cmsg);
+ break;
+ }
+ }
+#endif
+ =20
+ if(
+#if defined(HAVE_ST_MSG_CONTROL)
+ cmsg =3D=3D NULL
+#else =20
+ msg.msg_accrightslen !=3D sizeof(struct ucred)
+#endif =20
+ ) {
+ rb_raise(rb_eSocket, "Credential were not passed");
+ }
+ =20
+ return rb_ary_new3(3, INT2FIX(creds->pid), INT2FIX(creds->uid),
+ INT2FIX(creds->gid));
+
+#else
+ rb_notimplement();
+ return Qnil; /* not reached */
+#endif
+}
+
+static VALUE
unix_accept(sock)
VALUE sock;
{
@@ -2468,6 +2625,9 @@
rb_define_method(rb_cUNIXSocket, "recvfrom", unix_recvfrom, -1);
rb_define_method(rb_cUNIXSocket, "send_io", unix_send_io, 1);
rb_define_method(rb_cUNIXSocket, "recv_io", unix_recv_io, -1);
+ rb_define_method(rb_cUNIXSocket, "send_credentials", unix_send_credent=
ials, -1);
+ rb_define_method(rb_cUNIXSocket, "recv_credentials", unix_recv_credent=
ials, 0);
+
rb_define_singleton_method(rb_cUNIXSocket, "socketpair", unix_s_socket=
pair, -1);
rb_define_singleton_method(rb_cUNIXSocket, "pair", unix_s_socketpair, =
-1);
=20
--=-LH2RX20AHG69TpQAZ+qL--
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
To get a feel before submitting a real RCR:
Abstract:
Add calls to UNIXSocket to pass around the UNIX credentials (i.e. pid,
uid and gid).
Problem:
There is no way, that I know of, within Ruby to find out which process
is connected at the other end of a UNIX socket.
Ex:
[gus@comp unix_credentials]$ irb
irb(main):001:0> require 'socket'
=> true
irb(main):002:0> s = UNIXServer.new('unixtest')
=> #<UNIXServer:unixtest>
irb(main):003:0> t = s.accept
=> #<UNIXSocket:0x4396d330>
irb(main):004:0> t.peeraddr
=> ["AF_UNIX", ""] # Doesn't tell you anything!
Proposal:
I propose the addition of two methods, send_credentials and
recv_credentils to pass through a UNIX socket the process id, user id
and group id.
Analysis:
The Linux system provide a mechanism to send UNIX credentials as
ancilary data (the same way as you can pass file descriptors,
implemented in Ruby as send_io). Other UNIX implementation I believe
offer similar mechanism.
One difference with just sending this data directly through the UNIX
socket (for example as a Mashalled array containing the pid, uid and
gid) is that the system does some checks on the values send (unless you
are root and are allowed to lie).
Implementation:
The attached patch implements it. It has been tested on Linux 2.4 only.
It is heavily inspired by the implementation of send_io. Usage example:
server:
irb(main):001:0> require 'socket'
=> true
irb(main):002:0> s = UNIXServer.new('unixtest')
=> #<UNIXServer:unixtest>
irb(main):003:0> t = s.accept
=> #<UNIXSocket:0x4bf81330>
irb(main):004:0> t.recv_credentials
=> [1933, 501, 501]
client:
irb(main):001:0> require 'socket'
=> true
irb(main):002:0> s = UNIXSocket.new("unixtest")
=> #<UNIXSocket:unixtest>
irb(main):003:0> s.send_credentials
=> nil
irb(main):004:0> Process.pid
=> 1933
Guillaume.
--=-LH2RX20AHG69TpQAZ+qL
Content-Disposition: attachment; filename=unix-credentials.patch
Content-Transfer-Encoding: quoted-printable
Content-Type: text/x-diff; charset=ISO-8859-1
--- ruby/ext/socket/socket.c Mon Apr 5 03:45:22 2004
+++ ruby-1.8.1-unix-credentials/ext/socket/socket.c Tue May 18 20:10:14 200=
4
@@ -1656,6 +1656,163 @@
}
=20
static VALUE
+unix_send_credentials(argc, argv, sock)
+ int argc;
+ VALUE *argv, sock;
+{
+#if defined(HAVE_SENDMSG) && (defined(HAVE_ST_MSG_CONTROL) || defined(HAVE=
_ST_MSG_ACCRIGHTS)) && defined(SCM_CREDENTIALS)
+ OpenFile *fptr;
+ int pid, uid, gid;
+ struct msghdr msg;
+ struct iovec vec[1];
+ char buf[1];
+ int len;
+ struct ucred *creds;
+#if defined(HAVE_ST_MSG_CONTROL)
+ char ancillary[CMSG_SPACE(sizeof(struct ucred))];
+ struct cmsghdr *cmsg;
+#else
+ struct ucred creds_data;
+#endif
+ =20
+ GetOpenFile(sock, fptr);
+
+ rb_scan_args(argc, argv, "03", &pid, &uid, &gid);
+
+ /* Linux and Solaris doesn't work if msg_iov is NULL. */
+ buf[0] =3D '\0';
+ vec[0].iov_base =3D buf;
+ vec[0].iov_len =3D 1;
+ msg.msg_iov =3D vec;
+ msg.msg_iovlen =3D 1;
+ =20
+ msg.msg_name =3D NULL;
+ msg.msg_namelen =3D 0;
+#if defined(HAVE_ST_MSG_CONTROL) =20
+ msg.msg_control =3D ancillary;
+ msg.msg_controllen =3D sizeof(ancillary);
+ msg.msg_flags =3D 0;
+ cmsg =3D CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_len =3D CMSG_LEN(sizeof(struct ucred));
+ cmsg->cmsg_level =3D SOL_SOCKET;
+ cmsg->cmsg_type =3D SCM_CREDENTIALS;
+ creds =3D (struct ucred *)CMSG_DATA(cmsg);
+ msg.msg_controllen =3D cmsg->cmsg_len;
+#else
+ creds =3D &creds_data;
+ msg.msg_accrights =3D (caddr_t)creds;
+ msg.msg_accrightslen =3D sizeof(struct ucred);
+#endif
+
+ if (FIXNUM_P(pid)) {
+ creds->pid =3D FIX2INT(pid);
+ } else if (NIL_P(pid)) {
+ creds->pid =3D getpid();
+ } else {
+ rb_raise(rb_eTypeError, "FixNum");
+ }
+ if (FIXNUM_P(uid)) {
+ creds->uid =3D FIX2INT(uid);
+ } else if (NIL_P(uid)) {
+ creds->uid =3D getuid();
+ } else {
+ rb_raise(rb_eTypeError, "FixNum");
+ }
+ if (FIXNUM_P(gid)) {
+ creds->gid =3D FIX2INT(gid);
+ } else if (NIL_P(gid)) {
+ creds->gid =3D getgid();
+ } else {
+ rb_raise(rb_eTypeError, "FixNum");
+ }
+ =20
+ if ((len =3D sendmsg(fileno(fptr->f), &msg, 0)) =3D=3D -1)
+ rb_sys_fail("sendmsg(2)");
+ =20
+ return Qnil;
+#else=20
+ rb_notimplement();
+ return Qnil; /* not reached */
+#endif
+}
+
+
+static VALUE
+unix_recv_credentials(sock)
+ VALUE sock;
+{
+#if defined(HAVE_RECVMSG) && (defined(HAVE_ST_MSG_CONTROL) || defined(HAVE=
_ST_MSG_ACCRIGHTS)) && defined(SCM_CREDENTIALS)
+ OpenFile *fptr;
+ struct msghdr msg;
+ struct iovec vec;
+ char data_buf[1], control_buf[1024];
+ int len, true;
+ struct ucred *creds;
+#if defined(HAVE_ST_MSG_CONTROL)
+ struct cmsghdr *cmsg;
+#endif
+ =20
+ GetOpenFile(sock, fptr);
+ =20
+ thread_read_select(fileno(fptr->f));
+
+ true =3D 1;
+ if(setsockopt(fileno(fptr->f), SOL_SOCKET, SO_PASSCRED,=20
+ &true, sizeof(int)) < 0) {
+ rb_raise(rb_eSocket, "UNIX credentials cannot be received");
+ }
+
+ msg.msg_name =3D NULL;
+ msg.msg_namelen =3D 0;
+ vec.iov_base =3D data_buf;
+ vec.iov_len =3D sizeof(data_buf);
+ msg.msg_iov =3D &vec;
+ msg.msg_iovlen =3D 1;
+ msg.msg_control =3D control_buf;
+ msg.msg_controllen =3D sizeof(control_buf);
+ msg.msg_flags =3D 0;
+ =20
+#if !defined(HAVE_ST_MSG_CONTROL)
+ msg.msg_accrights =3D (caddr_t)creds;
+ msg.msg_accrightslen =3D sizeof(struct ucred);
+#endif
+ =20
+ if ((len =3D recvmsg(fileno(fptr->f), &msg, 0)) =3D=3D -1)
+ rb_sys_fail("recvmsg(2)");
+ =20
+
+#if defined(HAVE_ST_MSG_CONTROL)
+ for(cmsg =3D CMSG_FIRSTHDR(&msg);
+ cmsg !=3D NULL;
+ cmsg =3D CMSG_NXTHDR(&msg, cmsg)) {
+ if(cmsg->cmsg_level =3D=3D SOL_SOCKET=20
+ && cmsg->cmsg_type =3D=3D SCM_CREDENTIALS) {
+ creds =3D (struct ucred *)CMSG_DATA(cmsg);
+ break;
+ }
+ }
+#endif
+ =20
+ if(
+#if defined(HAVE_ST_MSG_CONTROL)
+ cmsg =3D=3D NULL
+#else =20
+ msg.msg_accrightslen !=3D sizeof(struct ucred)
+#endif =20
+ ) {
+ rb_raise(rb_eSocket, "Credential were not passed");
+ }
+ =20
+ return rb_ary_new3(3, INT2FIX(creds->pid), INT2FIX(creds->uid),
+ INT2FIX(creds->gid));
+
+#else
+ rb_notimplement();
+ return Qnil; /* not reached */
+#endif
+}
+
+static VALUE
unix_accept(sock)
VALUE sock;
{
@@ -2468,6 +2625,9 @@
rb_define_method(rb_cUNIXSocket, "recvfrom", unix_recvfrom, -1);
rb_define_method(rb_cUNIXSocket, "send_io", unix_send_io, 1);
rb_define_method(rb_cUNIXSocket, "recv_io", unix_recv_io, -1);
+ rb_define_method(rb_cUNIXSocket, "send_credentials", unix_send_credent=
ials, -1);
+ rb_define_method(rb_cUNIXSocket, "recv_credentials", unix_recv_credent=
ials, 0);
+
rb_define_singleton_method(rb_cUNIXSocket, "socketpair", unix_s_socket=
pair, -1);
rb_define_singleton_method(rb_cUNIXSocket, "pair", unix_s_socketpair, =
-1);
=20
--=-LH2RX20AHG69TpQAZ+qL--