* ext/socket/extconf.rb: check struct cmsgcred.

* ext/socket/ancdata.c (anc_inspect_passcred_credentials): add
  "(ucred)".
  (anc_inspect_socket_creds): show struct cmsgcred too, for FreeBSD.



git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@22129 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
akr 2009-02-08 12:53:55 +00:00
parent c79dac1c3e
commit 411e9997d2
4 changed files with 97 additions and 29 deletions

View File

@ -1,3 +1,11 @@
Sun Feb 8 21:47:50 2009 Tanaka Akira <akr@fsij.org>
* ext/socket/extconf.rb: check struct cmsgcred.
* ext/socket/ancdata.c (anc_inspect_passcred_credentials): add
"(ucred)".
(anc_inspect_socket_creds): show struct cmsgcred too, for FreeBSD.
Sun Feb 8 21:05:35 2009 Tanaka Akira <akr@fsij.org> Sun Feb 8 21:05:35 2009 Tanaka Akira <akr@fsij.org>
* lib/drb/extservm.rb (DRb::ExtServManager#invoke_service_command): * lib/drb/extservm.rb (DRb::ExtServManager#invoke_service_command):

View File

@ -385,6 +385,7 @@ anc_inspect_passcred_credentials(int level, int type, VALUE data, VALUE ret)
struct ucred cred; struct ucred cred;
memcpy(&cred, RSTRING_PTR(data), sizeof(struct ucred)); memcpy(&cred, RSTRING_PTR(data), sizeof(struct ucred));
rb_str_catf(ret, " pid=%u uid=%u gid=%u", cred.pid, cred.uid, cred.gid); rb_str_catf(ret, " pid=%u uid=%u gid=%u", cred.pid, cred.uid, cred.gid);
rb_str_cat2(ret, " (ucred)");
return 0; return 0;
} }
else { else {
@ -393,38 +394,71 @@ anc_inspect_passcred_credentials(int level, int type, VALUE data, VALUE ret)
} }
#endif #endif
#if defined(SCM_CREDS) && defined(HAVE_TYPE_STRUCT_SOCKCRED) /* NetBSD */ #if defined(SCM_CREDS)
#define INSPECT_SCM_CREDS #define INSPECT_SCM_CREDS
static int static int
anc_inspect_socket_creds(int level, int type, VALUE data, VALUE ret) anc_inspect_socket_creds(int level, int type, VALUE data, VALUE ret)
{ {
int i; int i;
if (level == SOL_SOCKET && type == SCM_CREDS && if (level != SOL_SOCKET && type != SCM_CREDS)
RSTRING_LEN(data) >= SOCKCREDSIZE(0)) { return -1;
struct sockcred cred0, *cred;
memcpy(&cred0, RSTRING_PTR(data), SOCKCREDSIZE(0)); /*
if (RSTRING_LEN(data) != SOCKCREDSIZE(cred0.sc_ngroups)) { * FreeBSD has struct cmsgcred and struct sockcred.
return -1; * They use both SOL_SOCKET/SCM_CREDS in the ancillary message.
} * They are not ambiguous from the view of the caller
cred = (struct sockcred *)ALLOCA_N(char, SOCKCREDSIZE(cred0.sc_ngroups)); * because struct sockcred is sent if and only if the caller sets LOCAL_CREDS socket option.
memcpy(cred, RSTRING_PTR(data), SOCKCREDSIZE(cred0.sc_ngroups)); * But inspect method doesn't know it.
rb_str_catf(ret, " uid=%u", cred->sc_uid); * So they are ambiguous from the view of inspect.
rb_str_catf(ret, " euid=%u", cred->sc_euid); * This function distinguish them by the size of the ancillary message.
rb_str_catf(ret, " gid=%u", cred->sc_gid); * This heuristics works well except when sc_ngroups == CMGROUP_MAX.
rb_str_catf(ret, " egid=%u", cred->sc_egid); */
if (cred0.sc_ngroups) {
#if defined(HAVE_TYPE_STRUCT_CMSGCRED) /* FreeBSD */
if (RSTRING_LEN(data) == sizeof(struct cmsgcred)) {
struct cmsgcred cred;
memcpy(&cred, RSTRING_PTR(data), sizeof(struct cmsgcred));
rb_str_catf(ret, " pid=%u", cred.cmcred_pid);
rb_str_catf(ret, " uid=%u", cred.cmcred_uid);
rb_str_catf(ret, " euid=%u", cred.cmcred_euid);
rb_str_catf(ret, " gid=%u", cred.cmcred_gid);
if (cred.cmcred_ngroups) {
char *sep = "="; char *sep = "=";
rb_str_cat2(ret, " groups"); rb_str_cat2(ret, " groups");
for (i = 0; i < cred0.sc_ngroups; i++) { for (i = 0; i < cred.cmcred_ngroups; i++) {
rb_str_catf(ret, "%s%u", sep, cred->sc_groups[i]); rb_str_catf(ret, "%s%u", sep, cred.cmcred_groups[i]);
sep = ","; sep = ",";
} }
} }
rb_str_cat2(ret, " (cmsgcred)");
return 0; return 0;
} }
else { #endif
return -1; #if defined(HAVE_TYPE_STRUCT_SOCKCRED) /* FreeBSD, NetBSD */
if (RSTRING_LEN(data) >= SOCKCREDSIZE(0)) {
struct sockcred cred0, *cred;
memcpy(&cred0, RSTRING_PTR(data), SOCKCREDSIZE(0));
if (RSTRING_LEN(data) == SOCKCREDSIZE(cred0.sc_ngroups)) {
cred = (struct sockcred *)ALLOCA_N(char, SOCKCREDSIZE(cred0.sc_ngroups));
memcpy(cred, RSTRING_PTR(data), SOCKCREDSIZE(cred0.sc_ngroups));
rb_str_catf(ret, " uid=%u", cred->sc_uid);
rb_str_catf(ret, " euid=%u", cred->sc_euid);
rb_str_catf(ret, " gid=%u", cred->sc_gid);
rb_str_catf(ret, " egid=%u", cred->sc_egid);
if (cred0.sc_ngroups) {
char *sep = "=";
rb_str_cat2(ret, " groups");
for (i = 0; i < cred0.sc_ngroups; i++) {
rb_str_catf(ret, "%s%u", sep, cred->sc_groups[i]);
sep = ",";
}
}
rb_str_cat2(ret, " (sockcred)");
return 0;
}
} }
#endif
return -1;
} }
#endif #endif

View File

@ -309,6 +309,7 @@ have_type("struct in6_pktinfo", headers) {|src|
} }
have_type("struct sockcred", headers) have_type("struct sockcred", headers)
have_type("struct cmsgcred", headers)
$distcleanfiles << "constants.h" << "constdefs.*" $distcleanfiles << "constants.h" << "constdefs.*"

View File

@ -296,7 +296,7 @@ class TestUNIXSocket < Test::Unit::TestCase
} }
end end
def test_cred_linux def test_cred_ucred
return if /linux/ !~ RUBY_PLATFORM return if /linux/ !~ RUBY_PLATFORM
Dir.mktmpdir {|d| Dir.mktmpdir {|d|
sockpath = "#{d}/sock" sockpath = "#{d}/sock"
@ -306,15 +306,17 @@ class TestUNIXSocket < Test::Unit::TestCase
s.setsockopt(:SOCKET, :PASSCRED, 1) s.setsockopt(:SOCKET, :PASSCRED, 1)
c.print "a" c.print "a"
msg, cliend_ai, rflags, cred = s.recvmsg msg, cliend_ai, rflags, cred = s.recvmsg
inspect = cred.inspect
assert_equal("a", msg) assert_equal("a", msg)
assert_match(/ pid=#{$$} /, cred.inspect) assert_match(/ pid=#{$$} /, inspect)
assert_match(/ uid=#{Process.uid} /, cred.inspect) assert_match(/ uid=#{Process.uid} /, inspect)
assert_match(/ gid=#{Process.gid}>/, cred.inspect) assert_match(/ gid=#{Process.gid}>/, inspect)
assert_match(/ \(ucred\)/, inspect)
} }
end end
def test_cred_netbsd def test_cred_sockcred
return if /netbsd/ !~ RUBY_PLATFORM return if /netbsd|freebsd/ !~ RUBY_PLATFORM
Dir.mktmpdir {|d| Dir.mktmpdir {|d|
sockpath = "#{d}/sock" sockpath = "#{d}/sock"
serv = Socket.unix_server_socket(sockpath) serv = Socket.unix_server_socket(sockpath)
@ -324,10 +326,33 @@ class TestUNIXSocket < Test::Unit::TestCase
c.print "a" c.print "a"
msg, cliend_ai, rflags, cred = s.recvmsg msg, cliend_ai, rflags, cred = s.recvmsg
assert_equal("a", msg) assert_equal("a", msg)
assert_match(/ uid=#{Process.uid} /, cred.inspect) inspect = cred.inspect
assert_match(/ euid=#{Process.euid} /, cred.inspect) p inspect
assert_match(/ gid=#{Process.gid} /, cred.inspect) assert_match(/ uid=#{Process.uid} /, inspect)
assert_match(/ egid=#{Process.egid} /, cred.inspect) assert_match(/ euid=#{Process.euid} /, inspect)
assert_match(/ gid=#{Process.gid} /, inspect)
assert_match(/ egid=#{Process.egid} /, inspect)
assert_match(/ \(sockcred\)/, inspect)
}
end
def test_cred_cmsgcred
return if /freebsd/ !~ RUBY_PLATFORM
Dir.mktmpdir {|d|
sockpath = "#{d}/sock"
serv = Socket.unix_server_socket(sockpath)
c = Socket.unix(sockpath)
s, = serv.accept
c.sendmsg("a", 0, nil, [:SOCKET, Socket::SCM_CREDS, ""])
msg, cliend_ai, rflags, cred = s.recvmsg
assert_equal("a", msg)
inspect = cred.inspect
p inspect
assert_match(/ pid=#{$$} /, inspect)
assert_match(/ uid=#{Process.uid} /, inspect)
assert_match(/ euid=#{Process.euid} /, inspect)
assert_match(/ gid=#{Process.gid} /, inspect)
assert_match(/ \(cmsgcred\)/, inspect)
} }
end end