RCR: UNIX credentials

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.

unix-credentials.patch (4.7 KB)

Hi,

···

In message “RCR: UNIX credentials” on 04/05/19, Guillaume Marcais guslist@free.fr writes:

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.

I like the idea. But I don’t want to merge it if it’s Linux
specific. Any idea?

						matz.

In article 1084926982.2388.130.camel@comp,
Guillaume Marcais guslist@free.fr writes:

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.

I surveyed the feature sometime ago.
Unfortunately it is not so portable.

  1. SCM_CREDS and getpeerid.

There are 2 kind of interfaces.
SCM_CREDS: a client must send a credential explicitly.
getpeerid: a client doesn’t need to send a credential.

  1. getpeerid

As far as I know, following system has getpeerid or similar.

FreeBSD 4.6 (LOCAL_PEERCRED, [base] Log of /head/lib/libc/gen/getpeereid.3)
OpenBSD 3.0 (http://www.openbsd.org/cgi-bin/man.cgi?query=getpeereid&sektion=2)
Linux (socket(7): getsockopt SO_PEERCRED)
MacOS X (man page getpeereid section 3)

DJB recommends getpeerid.
http://cr.yp.to/docs/secureipc.html

  1. SCM_CREDS

As far as I know, following system has SCM_CREDS or similar.
However, credential information varies on each system.

FreeBSD 3.0 (recvmsg(2): SCM_CREDS: pid, uid, euid, gid, supp groups)
NetBSD 1.4.0 (unix(4): LOCAL_CREDS, SCM_CREDS: uid, euid, gid, egid, supp groups: http://www.netbsd.org/Changes/changes-1.4.html)
OpenBSD 2.5 (SCM_CREDS: uid, euid, gid, egid, supp groups)
Linux (unix(7): SCM_CREDENTIALS: pid, uid, gid)

  1. send_io/recv_io may be usable for authentication.

See: Secure UNIX Programming FAQ
4.4) How do I authenticate a non-parent process?
http://www.whitefang.com/sup/secure-faq.html

···


Tanaka Akira

Two ideas.

  1. This works fine too:
    class UNIXSocket
    def getpeercredentials
    getsockopt(Socket::SOL_SOCKET, Socket::SO_PEERCRED).unpack(“i3”)
    end
    end

No need for C code. Tested on Linux. A web search tells me that the
SO_PEERCRED option is supported on the BSD family as well. The closest
thing to a BSD machine I have is a MacOS X box, which doesn’t support
it. Can anybody try this piece of code on *BSD?

  1. There seems to be a similar mechanism as the Linux one to pass this
    information as ancillary data and *BSD, with the SCM_CREDS cmsg type
    and struct cmsgcred. But once again, Apple is failing on me: the
    definition of struct cmsgcred is surrounded by #ifndef APPLE
    #endif.

The advantage of sending ancillary data compared to getsockopt is that
you can send you euid and egid instead of uid and gid.

Guillaume.

···

Le 18 mai 04, à 23:20, Yukihiro Matsumoto a écrit :

I like the idea. But I don’t want to merge it if it’s Linux
specific. Any idea?

So, should we implement a UNIXSocket#getpeerid method, using getpeerid()
or SO_PEERCRED, depending on what’s available? The way of doing things
with getpeerid seems more natural than SCM_CREDS.

I’ll resumit an RCR.

Guillaume.

···

On Wed, 2004-05-19 at 10:16, Tanaka Akira wrote:

In article 1084926982.2388.130.camel@comp,
Guillaume Marcais guslist@free.fr writes:

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.

I surveyed the feature sometime ago.
Unfortunately it is not so portable.

  1. SCM_CREDS and getpeerid.

There are 2 kind of interfaces.
SCM_CREDS: a client must send a credential explicitly.
getpeerid: a client doesn’t need to send a credential.

  1. getpeerid

As far as I know, following system has getpeerid or similar.

FreeBSD 4.6 (LOCAL_PEERCRED, http://www.freebsd.org/cgi/cvsweb.cgi/src/lib/libc/gen/getpeereid.3)
OpenBSD 3.0 (http://www.openbsd.org/cgi-bin/man.cgi?query=getpeereid&sektion=2)
Linux (socket(7): getsockopt SO_PEERCRED)
MacOS X (man page getpeereid section 3)

DJB recommends getpeerid.
http://cr.yp.to/docs/secureipc.html

  1. SCM_CREDS

As far as I know, following system has SCM_CREDS or similar.
However, credential information varies on each system.

FreeBSD 3.0 (recvmsg(2): SCM_CREDS: pid, uid, euid, gid, supp groups)
NetBSD 1.4.0 (unix(4): LOCAL_CREDS, SCM_CREDS: uid, euid, gid, egid, supp groups: Significant changes from NetBSD 1.3 to 1.4)
OpenBSD 2.5 (SCM_CREDS: uid, euid, gid, egid, supp groups)
Linux (unix(7): SCM_CREDENTIALS: pid, uid, gid)

  1. send_io/recv_io may be usable for authentication.

See: Secure UNIX Programming FAQ
4.4) How do I authenticate a non-parent process?
http://www.whitefang.com/sup/secure-faq.html

Tanaka Akira

According to David Wheeler[1] this is a Linux-only thing.

Also, the Unix Network Programming book says there’s no portable way of
doing that (but shows how to do it on FreeBSD, using SCM_CREDS IIRC).

Best regards,
Andre

[1]Sockets and Network Connections

···

On Wed, 2004-05-19 at 07:04, Guillaume Marcais wrote:

  1. This works fine too:
    class UNIXSocket
    def getpeercredentials
    getsockopt(Socket::SOL_SOCKET, Socket::SO_PEERCRED).unpack(“i3”)
    end
    end

No need for C code. Tested on Linux. A web search tells me that the
SO_PEERCRED option is supported on the BSD family as well.


design, v.: What you regret not doing later on.

it. Can anybody try this piece of code on *BSD?

obsd% ruby -vrsocket -e 'p Socket::SO_PEERCRED'
ruby 1.9.0 (2004-04-30) [sparc-openbsd3.5]
-e:1: uninitialized constant Socket::SO_PEERCRED (NameError)
obsd%

Guy Decoux

In article 1084992082.2388.184.camel@comp,
Guillaume Marcais guslist@free.fr writes:

So, should we implement a UNIXSocket#getpeerid method, using getpeerid()

Oops. It’s getpeereid, not getpeerid.

···


Tanaka Akira

obsd% ruby -vrsocket -e 'p Socket::SO_PEERCRED'
ruby 1.9.0 (2004-04-30) [sparc-openbsd3.5]

I've forgotten to say : look at src/backend/libpq/hba.c in the PostgreSQL
distribution (7.4.x)

Guy Decoux