1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/internal/process.h
Alan D. Salewski c15cddd1d5 Allow Dir.home to work for non-login procs when $HOME not set
Allow the 'Dir.home' method to reliably locate the user's home directory when
all three of the following are true at the same time:

    1. Ruby is running on a Unix-like OS
    2. The $HOME environment variable is not set
    3. The process is not a descendant of login(1) (or a work-alike)

The prior behavior was that the lookup could only work for login-descended
processes.

This is accomplished by looking up the user's record in the password database
by uid (getpwuid_r(3)) as a fallback to the lookup by name (getpwname_r(3))
which is still attempted first (based on the name, if any, returned by
getlogin_r(3)).

If getlogin_r(3), getpwnam_r(3), and/or getpwuid_r(3) is not available at
compile time, will fallback on using their respective non-*_r() variants:
getlogin(3), getpwnam(3), and/or getpwuid(3).

The rationale for attempting to do the lookup by name prior to doing it by uid
is 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 is explicitly allowed for by
POSIX; see getlogin(3posix)).

Preserves the existing behavior for login-descended processes, and adds the
new capability of having Dir.home being able to find the user's home directory
for non-login-descended processes.

Fixes [Bug #16787]

Related discussion:
    https://bugs.ruby-lang.org/issues/16787
    https://github.com/ruby/ruby/pull/3034
2020-05-23 23:16:28 +09:00

136 lines
4.4 KiB
C

#ifndef INTERNAL_PROCESS_H /*-*-C-*-vi:se ft=c:*/
#define INTERNAL_PROCESS_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @brief Internal header for Process.
*/
#include "ruby/internal/config.h" /* for rb_pid_t */
#include <stddef.h> /* for size_t */
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h> /* for mode_t */
#endif
#ifdef _WIN32
# include "ruby/win32.h" /* for mode_t */
#endif
#include "ruby/ruby.h" /* for VALUE */
#include "internal/imemo.h" /* for RB_IMEMO_TMPBUF_PTR */
#include "internal/warnings.h" /* for COMPILER_WARNING_PUSH */
#define RB_MAX_GROUPS (65536)
struct waitpid_state;
struct rb_execarg {
union {
struct {
VALUE shell_script;
} sh;
struct {
VALUE command_name;
VALUE command_abspath; /* full path string or nil */
VALUE argv_str;
VALUE argv_buf;
} cmd;
} invoke;
VALUE redirect_fds;
VALUE envp_str;
VALUE envp_buf;
VALUE dup2_tmpbuf;
unsigned use_shell : 1;
unsigned pgroup_given : 1;
unsigned umask_given : 1;
unsigned unsetenv_others_given : 1;
unsigned unsetenv_others_do : 1;
unsigned close_others_given : 1;
unsigned close_others_do : 1;
unsigned chdir_given : 1;
unsigned new_pgroup_given : 1;
unsigned new_pgroup_flag : 1;
unsigned uid_given : 1;
unsigned gid_given : 1;
unsigned exception : 1;
unsigned exception_given : 1;
struct waitpid_state *waitpid_state; /* for async process management */
rb_pid_t pgroup_pgid; /* asis(-1), new pgroup(0), specified pgroup (0<V). */
VALUE rlimit_limits; /* Qfalse or [[rtype, softlim, hardlim], ...] */
mode_t umask_mask;
rb_uid_t uid;
rb_gid_t gid;
int close_others_maxhint;
VALUE fd_dup2;
VALUE fd_close;
VALUE fd_open;
VALUE fd_dup2_child;
VALUE env_modification; /* Qfalse or [[k1,v1], ...] */
VALUE path_env;
VALUE chdir_dir;
};
/* 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);
void rb_execarg_parent_end(VALUE execarg_obj);
int rb_execarg_run_options(const struct rb_execarg *e, struct rb_execarg *s, char* errmsg, size_t errmsg_buflen);
VALUE rb_execarg_extract_options(VALUE execarg_obj, VALUE opthash);
void rb_execarg_setenv(VALUE execarg_obj, VALUE env);
RUBY_SYMBOL_EXPORT_END
/* argv_str contains extra two elements.
* The beginning one is for /bin/sh used by exec_with_sh.
* The last one for terminating NULL used by execve.
* See rb_exec_fillarg() in process.c. */
static inline char **
ARGVSTR2ARGV(VALUE argv_str)
{
char **buf = RB_IMEMO_TMPBUF_PTR(argv_str);
return &buf[1];
}
static inline size_t
ARGVSTR2ARGC(VALUE argv_str)
{
size_t i = 0;
char *const *p = ARGVSTR2ARGV(argv_str);
while (p[i++])
;
return i - 1;
}
#ifdef HAVE_WORKING_FORK
COMPILER_WARNING_PUSH
#if __has_warning("-Wdeprecated-declarations") || RBIMPL_COMPILER_IS(GCC)
COMPILER_WARNING_IGNORED(-Wdeprecated-declarations)
#endif
static inline rb_pid_t
rb_fork(void)
{
return fork();
}
COMPILER_WARNING_POP
#endif
#endif /* INTERNAL_PROCESS_H */