Bug #16787 » allow-dir.home-for-non-login-procs-v7.patch
| configure.ac | ||
|---|---|---|
|
AC_CHECK_FUNCS(ftruncate)
|
||
|
AC_CHECK_FUNCS(ftruncate64) # used for Win32 platform
|
||
|
AC_CHECK_FUNCS(getattrlist)
|
||
|
AC_CHECK_FUNCS(getcwd)
|
||
|
AC_CHECK_FUNCS(getgidx)
|
||
|
AC_CHECK_FUNCS(getgrnam)
|
||
|
AC_CHECK_FUNCS(getgrnam_r)
|
||
|
AC_CHECK_FUNCS(getgroups)
|
||
|
AC_CHECK_FUNCS(getlogin)
|
||
|
AC_CHECK_FUNCS(getlogin_r)
|
||
|
AC_CHECK_FUNCS(getpgid)
|
||
|
AC_CHECK_FUNCS(getpgrp)
|
||
|
AC_CHECK_FUNCS(getpriority)
|
||
|
AC_CHECK_FUNCS(getpwnam)
|
||
|
AC_CHECK_FUNCS(getpwnam_r)
|
||
|
AC_CHECK_FUNCS(getpwuid)
|
||
|
AC_CHECK_FUNCS(getpwuid_r)
|
||
|
AC_CHECK_FUNCS(getrandom)
|
||
|
AC_CHECK_FUNCS(getresgid)
|
||
|
AC_CHECK_FUNCS(getresuid)
|
||
|
AC_CHECK_FUNCS(getrlimit)
|
||
|
AC_CHECK_FUNCS(getsid)
|
||
|
AC_CHECK_FUNCS(gettimeofday) # for making ac_cv_func_gettimeofday
|
||
|
AC_CHECK_FUNCS(getuidx)
|
||
|
AC_CHECK_FUNCS(gmtime_r)
|
||
| file.c | ||
|---|---|---|
|
#ifndef _WIN32
|
||
|
VALUE
|
||
|
rb_default_home_dir(VALUE result)
|
||
|
{
|
||
|
const char *dir = getenv("HOME");
|
||
|
#if defined HAVE_PWD_H
|
||
|
if (!dir) {
|
||
|
const char *login = getlogin();
|
||
|
if (login) {
|
||
|
struct passwd *pw = getpwnam(login);
|
||
|
if (pw) {
|
||
|
copy_home_path(result, pw->pw_dir);
|
||
|
endpwent();
|
||
|
return result;
|
||
|
}
|
||
|
endpwent();
|
||
|
rb_raise(rb_eArgError, "couldn't find HOME for login `%s' -- expanding `~'",
|
||
|
login);
|
||
|
}
|
||
|
else {
|
||
|
rb_raise(rb_eArgError, "couldn't find login name -- expanding `~'");
|
||
|
}
|
||
|
/* We'll look up the user's default home dir in the password db by
|
||
|
* login name, if possible, and failing that will fall back to looking
|
||
|
* the information up by uid (as would be needed for processes that
|
||
|
* are not a descendant of login(1) or a work-alike).
|
||
|
*
|
||
|
* While the lookup by uid is more likely to succeed (since we always
|
||
|
* have a uid, but may or may not have a login name), we prefer first
|
||
|
* looking up by name to accommodate the possibility of multiple login
|
||
|
* names (each with its own record in the password database, so each
|
||
|
* with a potentially different home directory) being mapped to the
|
||
|
* same uid (as explicitly allowed for by POSIX; see getlogin(3posix)).
|
||
|
*/
|
||
|
VALUE login_name = rb_getlogin();
|
||
|
# if !defined(HAVE_GETPWUID_R) && !defined(HAVE_GETPWUID)
|
||
|
/* This is a corner case, but for backward compatibility reasons we
|
||
|
* want to emit this error if neither the lookup by login name nor
|
||
|
* lookup by getuid() has a chance of succeeding.
|
||
|
*/
|
||
|
if (NIL_P(login_name)) {
|
||
|
rb_raise(rb_eArgError, "couldn't find login name -- expanding `~'");
|
||
|
}
|
||
|
# endif
|
||
|
VALUE pw_dir = rb_getpwdirnam_for_login(login_name);
|
||
|
if (NIL_P(pw_dir)) {
|
||
|
pw_dir = rb_getpwdiruid();
|
||
|
if (NIL_P(pw_dir)) {
|
||
|
rb_raise(rb_eArgError, "couldn't find home for uid `%ld'", (long)getuid());
|
||
|
}
|
||
|
}
|
||
|
/* found it */
|
||
|
copy_home_path(result, RSTRING_PTR(pw_dir));
|
||
|
rb_str_resize(pw_dir, 0);
|
||
|
return result;
|
||
|
}
|
||
|
#endif
|
||
|
if (!dir) {
|
||
|
rb_raise(rb_eArgError, "couldn't find HOME environment -- expanding `~'");
|
||
|
}
|
||
|
return copy_home_path(result, dir);
|
||
|
}
|
||
| internal/process.h | ||
|---|---|---|
|
};
|
||
|
/* process.c */
|
||
|
rb_pid_t rb_fork_ruby(int *status);
|
||
|
void rb_last_status_clear(void);
|
||
|
static inline char **ARGVSTR2ARGV(VALUE argv_str);
|
||
|
static inline size_t ARGVSTR2ARGC(VALUE argv_str);
|
||
|
#ifdef HAVE_PWD_H
|
||
|
VALUE rb_getlogin(void);
|
||
|
VALUE rb_getpwdirnam_for_login(VALUE login); /* read as: "get pwd db home dir by username for login" */
|
||
|
VALUE rb_getpwdiruid(void); /* read as: "get pwd db home dir for getuid()" */
|
||
|
#endif
|
||
|
RUBY_SYMBOL_EXPORT_BEGIN
|
||
|
/* process.c (export) */
|
||
|
int rb_exec_async_signal_safe(const struct rb_execarg *e, char *errmsg, size_t errmsg_buflen);
|
||
|
rb_pid_t rb_fork_async_signal_safe(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALUE fds, char *errmsg, size_t errmsg_buflen);
|
||
|
VALUE rb_execarg_new(int argc, const VALUE *argv, int accept_shell, int allow_exc_opt);
|
||
|
struct rb_execarg *rb_execarg_get(VALUE execarg_obj); /* dangerous. needs GC guard. */
|
||
|
int rb_execarg_addopt(VALUE execarg_obj, VALUE key, VALUE val);
|
||
|
void rb_execarg_parent_start(VALUE execarg_obj);
|
||
| process.c | ||
|---|---|---|
|
static void check_gid_switch(void);
|
||
|
static int exec_async_signal_safe(const struct rb_execarg *, char *, size_t);
|
||
|
#if 1
|
||
|
#define p_uid_from_name p_uid_from_name
|
||
|
#define p_gid_from_name p_gid_from_name
|
||
|
#endif
|
||
|
#if defined(HAVE_UNISTD_H)
|
||
|
# if defined(HAVE_GETLOGIN_R)
|
||
|
# define USE_GETLOGIN_R 1
|
||
|
# define GETLOGIN_R_SIZE_DEFAULT 0x100
|
||
|
# define GETLOGIN_R_SIZE_LIMIT 0x1000
|
||
|
# if defined(_SC_LOGIN_NAME_MAX)
|
||
|
# define GETLOGIN_R_SIZE_INIT sysconf(_SC_LOGIN_NAME_MAX)
|
||
|
# else
|
||
|
# define GETLOGIN_R_SIZE_INIT GETLOGIN_R_SIZE_DEFAULT
|
||
|
# endif
|
||
|
# elif defined(HAVE_GETLOGIN)
|
||
|
# define USE_GETLOGIN 1
|
||
|
# endif
|
||
|
#endif
|
||
|
#if defined(HAVE_PWD_H)
|
||
|
# if defined(HAVE_GETPWNAM_R) && defined(_SC_GETPW_R_SIZE_MAX)
|
||
|
# if defined(HAVE_GETPWUID_R)
|
||
|
# define USE_GETPWUID_R 1
|
||
|
# elif defined(HAVE_GETPWUID)
|
||
|
# define USE_GETPWUID 1
|
||
|
# endif
|
||
|
# if defined(HAVE_GETPWNAM_R)
|
||
|
# define USE_GETPWNAM_R 1
|
||
|
# define GETPW_R_SIZE_INIT sysconf(_SC_GETPW_R_SIZE_MAX)
|
||
|
# elif defined(HAVE_GETPWNAM)
|
||
|
# define USE_GETPWNAM 1
|
||
|
# endif
|
||
|
# if defined(HAVE_GETPWNAM_R) || defined(HAVE_GETPWUID_R)
|
||
|
# define GETPW_R_SIZE_DEFAULT 0x1000
|
||
|
# define GETPW_R_SIZE_LIMIT 0x10000
|
||
|
# if defined(_SC_GETPW_R_SIZE_MAX)
|
||
|
# define GETPW_R_SIZE_INIT sysconf(_SC_GETPW_R_SIZE_MAX)
|
||
|
# else
|
||
|
# define GETPW_R_SIZE_INIT GETPW_R_SIZE_DEFAULT
|
||
|
# endif
|
||
|
# endif
|
||
|
# ifdef USE_GETPWNAM_R
|
||
|
# define PREPARE_GETPWNAM \
|
||
|
VALUE getpw_buf = 0
|
||
|
# define FINISH_GETPWNAM \
|
||
|
(getpw_buf ? (void)rb_str_resize(getpw_buf, 0) : (void)0)
|
||
|
# define OBJ2UID1(id) obj2uid((id), &getpw_buf)
|
||
|
# define OBJ2UID(id) obj2uid0(id)
|
||
| ... | ... | |
|
check_gid_switch(void)
|
||
|
{
|
||
|
if (under_gid_switch) {
|
||
|
rb_raise(rb_eRuntimeError, "can't handle GID while evaluating block given to Process::UID.switch method");
|
||
|
}
|
||
|
}
|
||
|
#if defined(HAVE_PWD_H)
|
||
|
/**
|
||
|
* Best-effort attempt to obtain the name of the login user, if any,
|
||
|
* associated with the process. Processes not descended from login(1) (or
|
||
|
* similar) may not have a logged-in user; returns Qnil in that case.
|
||
|
*/
|
||
|
VALUE
|
||
|
rb_getlogin(void)
|
||
|
{
|
||
|
#if ( !defined(USE_GETLOGIN_R) && !defined(USE_GETLOGIN) )
|
||
|
return Qnil;
|
||
|
#else
|
||
|
char MAYBE_UNUSED(*login) = NULL;
|
||
|
# ifdef USE_GETLOGIN_R
|
||
|
long loginsize = GETLOGIN_R_SIZE_INIT; /* maybe -1 */
|
||
|
if (loginsize < 0)
|
||
|
loginsize = GETLOGIN_R_SIZE_DEFAULT;
|
||
|
VALUE maybe_result = rb_str_buf_new(loginsize);
|
||
|
login = RSTRING_PTR(maybe_result);
|
||
|
loginsize = rb_str_capacity(maybe_result);
|
||
|
rb_str_set_len(maybe_result, loginsize);
|
||
|
int gle;
|
||
|
errno = 0;
|
||
|
while ((gle = getlogin_r(login, loginsize)) != 0) {
|
||
|
if (gle == ENOTTY || gle == ENXIO || gle == ENOENT) {
|
||
|
rb_str_resize(maybe_result, 0);
|
||
|
return Qnil;
|
||
|
}
|
||
|
if (gle != ERANGE || loginsize >= GETLOGIN_R_SIZE_LIMIT) {
|
||
|
rb_str_resize(maybe_result, 0);
|
||
|
rb_syserr_fail(gle, "getlogin_r");
|
||
|
}
|
||
|
rb_str_modify_expand(maybe_result, loginsize);
|
||
|
login = RSTRING_PTR(maybe_result);
|
||
|
loginsize = rb_str_capacity(maybe_result);
|
||
|
}
|
||
|
if (login == NULL) {
|
||
|
rb_str_resize(maybe_result, 0);
|
||
|
return Qnil;
|
||
|
}
|
||
|
return maybe_result;
|
||
|
# elif USE_GETLOGIN
|
||
|
errno = 0;
|
||
|
login = getlogin();
|
||
|
if (errno) {
|
||
|
if (errno == ENOTTY || errno == ENXIO || errno == ENOENT) {
|
||
|
return Qnil;
|
||
|
}
|
||
|
rb_syserr_fail(errno, "getlogin");
|
||
|
}
|
||
|
return login ? rb_str_new_cstr(login) : Qnil;
|
||
|
# endif
|
||
|
#endif
|
||
|
}
|
||
|
VALUE
|
||
|
rb_getpwdirnam_for_login(VALUE login_name)
|
||
|
{
|
||
|
#if ( !defined(USE_GETPWNAM_R) && !defined(USE_GETPWNAM) )
|
||
|
return Qnil;
|
||
|
#else
|
||
|
if (NIL_P(login_name)) {
|
||
|
/* nothing to do; no name with which to query the password database */
|
||
|
return Qnil;
|
||
|
}
|
||
|
char *login = RSTRING_PTR(login_name);
|
||
|
struct passwd *pwptr;
|
||
|
# ifdef USE_GETPWNAM_R
|
||
|
struct passwd pwdnm;
|
||
|
char *bufnm;
|
||
|
long bufsizenm = GETPW_R_SIZE_INIT; /* maybe -1 */
|
||
|
if (bufsizenm < 0)
|
||
|
bufsizenm = GETPW_R_SIZE_DEFAULT;
|
||
|
VALUE getpwnm_tmp = rb_str_tmp_new(bufsizenm);
|
||
|
bufnm = RSTRING_PTR(getpwnm_tmp);
|
||
|
bufsizenm = rb_str_capacity(getpwnm_tmp);
|
||
|
rb_str_set_len(getpwnm_tmp, bufsizenm);
|
||
|
int enm;
|
||
|
errno = 0;
|
||
|
while ((enm = getpwnam_r(login, &pwdnm, bufnm, bufsizenm, &pwptr)) != 0) {
|
||
|
if (enm == ENOENT || enm== ESRCH || enm == EBADF || enm == EPERM) {
|
||
|
/* not found; non-errors */
|
||
|
rb_str_resize(getpwnm_tmp, 0);
|
||
|
return Qnil;
|
||
|
}
|
||
|
if (enm != ERANGE || bufsizenm >= GETPW_R_SIZE_LIMIT) {
|
||
|
rb_str_resize(getpwnm_tmp, 0);
|
||
|
rb_syserr_fail(enm, "getpwnam_r");
|
||
|
}
|
||
|
rb_str_modify_expand(getpwnm_tmp, bufsizenm);
|
||
|
bufnm = RSTRING_PTR(getpwnm_tmp);
|
||
|
bufsizenm = rb_str_capacity(getpwnm_tmp);
|
||
|
}
|
||
|
if (pwptr == NULL) {
|
||
|
/* no record in the password database for the login name */
|
||
|
rb_str_resize(getpwnm_tmp, 0);
|
||
|
return Qnil;
|
||
|
}
|
||
|
/* found it */
|
||
|
VALUE result = rb_str_new_cstr(pwptr->pw_dir);
|
||
|
rb_str_resize(getpwnm_tmp, 0);
|
||
|
return result;
|
||
|
# elif USE_GETPWNAM
|
||
|
errno = 0;
|
||
|
pwptr = getpwnam(login);
|
||
|
if (pwptr) {
|
||
|
/* found it */
|
||
|
return rb_str_new_cstr(pwptr->pw_dir);
|
||
|
}
|
||
|
if (errno
|
||
|
/* avoid treating as errors errno values that indicate "not found" */
|
||
|
&& ( errno != ENOENT && errno != ESRCH && errno != EBADF && errno != EPERM)) {
|
||
|
rb_syserr_fail(errno, "getpwnam");
|
||
|
}
|
||
|
return Qnil; /* not found */
|
||
|
# endif
|
||
|
#endif
|
||
|
}
|
||
|
/**
|
||
|
* Look up the user's dflt home dir in the password db, by uid.
|
||
|
*/
|
||
|
VALUE
|
||
|
rb_getpwdiruid(void)
|
||
|
{
|
||
|
# if !defined(USE_GETPWUID_R) && !defined(USE_GETPWUID)
|
||
|
/* Should never happen... </famous-last-words> */
|
||
|
return Qnil;
|
||
|
# else
|
||
|
uid_t ruid = getuid();
|
||
|
struct passwd *pwptr;
|
||
|
# ifdef USE_GETPWUID_R
|
||
|
struct passwd pwdid;
|
||
|
char *bufid;
|
||
|
long bufsizeid = GETPW_R_SIZE_INIT; /* maybe -1 */
|
||
|
if (bufsizeid < 0)
|
||
|
bufsizeid = GETPW_R_SIZE_DEFAULT;
|
||
|
VALUE getpwid_tmp = rb_str_tmp_new(bufsizeid);
|
||
|
bufid = RSTRING_PTR(getpwid_tmp);
|
||
|
bufsizeid = rb_str_capacity(getpwid_tmp);
|
||
|
rb_str_set_len(getpwid_tmp, bufsizeid);
|
||
|
int eid;
|
||
|
errno = 0;
|
||
|
while ((eid = getpwuid_r(ruid, &pwdid, bufid, bufsizeid, &pwptr)) != 0) {
|
||
|
if (eid == ENOENT || eid== ESRCH || eid == EBADF || eid == EPERM) {
|
||
|
/* not found; non-errors */
|
||
|
rb_str_resize(getpwid_tmp, 0);
|
||
|
return Qnil;
|
||
|
}
|
||
|
if (eid != ERANGE || bufsizeid >= GETPW_R_SIZE_LIMIT) {
|
||
|
rb_str_resize(getpwid_tmp, 0);
|
||
|
rb_syserr_fail(eid, "getpwuid_r");
|
||
|
}
|
||
|
rb_str_modify_expand(getpwid_tmp, bufsizeid);
|
||
|
bufid = RSTRING_PTR(getpwid_tmp);
|
||
|
bufsizeid = rb_str_capacity(getpwid_tmp);
|
||
|
}
|
||
|
if (pwptr == NULL) {
|
||
|
/* no record in the password database for the uid */
|
||
|
rb_str_resize(getpwid_tmp, 0);
|
||
|
return Qnil;
|
||
|
}
|
||
|
/* found it */
|
||
|
VALUE result = rb_str_new_cstr(pwptr->pw_dir);
|
||
|
rb_str_resize(getpwid_tmp, 0);
|
||
|
return result;
|
||
|
# elif defined(USE_GETPWUID)
|
||
|
errno = 0;
|
||
|
pwptr = getpwuid(ruid);
|
||
|
if (pwptr) {
|
||
|
/* found it */
|
||
|
return rb_str_new_cstr(pwptr->pw_dir);
|
||
|
}
|
||
|
if (errno
|
||
|
/* avoid treating as errors errno values that indicate "not found" */
|
||
|
&& ( errno == ENOENT || errno == ESRCH || errno == EBADF || errno == EPERM)) {
|
||
|
rb_syserr_fail(errno, "getpwuid");
|
||
|
}
|
||
|
return Qnil; /* not found */
|
||
|
# endif
|
||
|
#endif /* !defined(USE_GETPWUID_R) && !defined(USE_GETPWUID) */
|
||
|
}
|
||
|
#endif /* HAVE_PWD_H */
|
||
|
/*********************************************************************
|
||
|
* Document-class: Process::Sys
|
||
|
*
|
||
|
* The Process::Sys module contains UID and GID
|
||
|
* functions which provide direct bindings to the system calls of the
|
||
|
* same names instead of the more-portable versions of the same
|
||
|
* functionality found in the Process,
|
||
|
* Process::UID, and Process::GID modules.
|
||