diff --git a/ChangeLog b/ChangeLog index c90b21e2ee8208..4e8fa65845b690 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Tue Oct 9 17:13:27 2012 Nobuyoshi Nakada + + * process.c (rb_execarg_addopt, rb_execarg_run_options): add :uid and + :gid options. [ruby-core:47414] [Feature #6975] + Tue Oct 9 14:36:11 2012 Koichi Sasada * iseq.c (iseq_free): fix memory leak. diff --git a/internal.h b/internal.h index 3a2331a867ae10..e538de4404f91d 100644 --- a/internal.h +++ b/internal.h @@ -203,9 +203,13 @@ struct rb_execarg { unsigned chdir_given : 1; unsigned new_pgroup_given : 1; unsigned new_pgroup_flag : 1; + unsigned uid_given : 1; + unsigned gid_given : 1; rb_pid_t pgroup_pgid; /* asis(-1), new pgroup(0), specified pgroup (0uid_given) { + rb_raise(rb_eArgError, "uid option specified twice"); + } + check_uid_switch(); + { + PREPARE_GETPWNAM; + eargp->uid = OBJ2UID(val); + eargp->uid_given = 1; + } +#else + rb_raise(rb_eNotImpError, + "uid option is unimplemented on this machine"); +#endif + } + else if (id == rb_intern("gid")) { +#ifdef HAVE_SETGID + if (eargp->gid_given) { + rb_raise(rb_eArgError, "gid option specified twice"); + } + check_gid_switch(); + { + PREPARE_GETGRNAM; + eargp->gid = OBJ2GID(val); + eargp->gid_given = 1; + } +#else + rb_raise(rb_eNotImpError, + "gid option is unimplemented on this machine"); +#endif + } else { return ST_STOP; } @@ -2875,6 +2956,23 @@ rb_execarg_run_options(const struct rb_execarg *eargp, struct rb_execarg *sargp, } } +#ifdef HAVE_SETGID + if (eargp->gid_given) { + if (setgid(eargp->gid) < 0) { + ERRMSG("setgid"); + return -1; + } + } +#endif +#ifdef HAVE_SETUID + if (eargp->uid_given) { + if (setuid(eargp->uid) < 0) { + ERRMSG("setuid"); + return -1; + } + } +#endif + if (sargp) { VALUE ary = sargp->fd_dup2; if (ary != Qfalse) { @@ -4581,22 +4679,7 @@ check_gid_switch(void) * Process::UID, and Process::GID modules. */ -#if 1 -#define p_uid_from_name p_uid_from_name -#define p_gid_from_name p_gid_from_name -#endif - #if defined(HAVE_PWD_H) -# ifdef HAVE_GETPWNAM_R -# define PREPARE_GETPWNAM \ - long getpw_buf_len = sysconf(_SC_GETPW_R_SIZE_MAX); \ - char *getpw_buf = ALLOCA_N(char, (getpw_buf_len < 0 ? (getpw_buf_len = 4096) : getpw_buf_len)); -# define OBJ2UID(id) obj2uid((id), getpw_buf, getpw_buf_len) -# else -# define PREPARE_GETPWNAM /* do nothing */ -# define OBJ2UID(id) obj2uid((id)) -# endif - static rb_uid_t obj2uid(VALUE id # ifdef HAVE_GETPWNAM_R @@ -4642,26 +4725,9 @@ p_uid_from_name(VALUE self, VALUE id) return UIDT2NUM(OBJ2UID(id)); } # endif -#else -# define PREPARE_GETPWNAM /* do nothing */ -# define OBJ2UID(id) NUM2UIDT(id) -# ifdef p_uid_from_name -# undef p_uid_from_name -# define p_uid_from_name rb_f_notimplement -# endif #endif #if defined(HAVE_GRP_H) -# ifdef HAVE_GETGRNAM_R -# define PREPARE_GETGRNAM \ - long getgr_buf_len = sysconf(_SC_GETGR_R_SIZE_MAX); \ - char *getgr_buf = ALLOCA_N(char, (getgr_buf_len < 0 ? (getgr_buf_len = 4096) : getgr_buf_len)); -# define OBJ2GID(id) obj2gid((id), getgr_buf, getgr_buf_len) -# else -# define PREPARE_GETGRNAM /* do nothing */ -# define OBJ2GID(id) obj2gid((id)) -# endif - static rb_gid_t obj2gid(VALUE id # ifdef HAVE_GETGRNAM_R @@ -4707,13 +4773,6 @@ p_gid_from_name(VALUE self, VALUE id) return GIDT2NUM(OBJ2GID(id)); } # endif -#else -# define PREPARE_GETGRNAM /* do nothing */ -# define OBJ2GID(id) NUM2GIDT(id) -# ifdef p_gid_from_name -# undef p_gid_from_name -# define p_gid_from_name rb_f_notimplement -# endif #endif #if defined HAVE_SETUID diff --git a/test/ruby/test_process.rb b/test/ruby/test_process.rb index 134797c2ad018f..e8c4cfa7d9344b 100644 --- a/test/ruby/test_process.rb +++ b/test/ruby/test_process.rb @@ -1478,6 +1478,50 @@ def test_execopts_new_pgroup assert_nothing_raised { IO.popen([*TRUECOMMAND, :new_pgroup=>true]) {} } end + def test_execopts_uid + feature6975 = '[ruby-core:47414]' + + [30000, [ENV["USER"], Process.uid]].each do |user, uid| + assert_nothing_raised(feature6975) do + begin + system(*TRUECOMMAND, uid: user) + rescue Errno::EPERM, NotImplementedError + end + end + + uid = "#{uid || user}" + assert_nothing_raised(feature6975) do + begin + u = IO.popen([RUBY, "-e", "print Process.uid", uid: user], &:read) + assert_equal(uid, u, feature6975) + rescue Errno::EPERM, NotImplementedError + end + end + end + end + + def test_execopts_gid + feature6975 = '[ruby-core:47414]' + + [30000, *Process.groups.map {|g| g = Etc.getgrgid(g); [g.name, g.gid]}].each do |group, gid| + assert_nothing_raised(feature6975) do + begin + system(*TRUECOMMAND, gid: group) + rescue Errno::EPERM, NotImplementedError + end + end + + gid = "#{gid || group}" + assert_nothing_raised(feature6975) do + begin + g = IO.popen([RUBY, "-e", "print Process.gid", gid: group], &:read) + assert_equal(gid, g, feature6975) + rescue Errno::EPERM, NotImplementedError + end + end + end + end + def test_sigpipe system(RUBY, "-e", "") with_pipe {|r, w|