Projects
Eulaceura:Factory
rubygem-netrc
_service:obs_scm:rubygem-netrc-0.11.0-augment-D...
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:obs_scm:rubygem-netrc-0.11.0-augment-Dir-home-to-read-password-database-by-uid.patch of Package rubygem-netrc
From 9add816290f4805942ba6afa09d69088c1570dcd Mon Sep 17 00:00:00 2001 From: "Alan D. Salewski" <salewski@att.net> Date: Mon, 13 Apr 2020 01:44:38 -0400 Subject: [PATCH] fixes #50: augment Dir.home to read password database by uid The `Dir.home` module present in versions of Ruby 2.x through the latest (2.7.1, released 2020-03-31) is unable 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) On a Unix-like OS, when the $HOME environment variable is not set, one might expect that Ruby would attempt to obtain the user's home directory from the password database. And in fact, it does try to do so. But the mechanism it uses only works for (grand)children of `login(1)`. In particular, it uses `getlogin(3)` to obtain the username, with the intent to then obtain the user's password record (and its `pw_dir` member) by looking it up by name (`getpwnam(3)`). That `getlogin()` call fails, of course, because there is no logged-in user for the process. This change preserves the base level reliance on `Dir.home`, but augments it by catching the error it throws in the above scenario and then using the Ruby stdlib wrappers for `getuid(1)` and `getpwuid(3)` to obtain the user's record from the password database. This works reliably and the same regardless of whether or not the process is a (grand)child of login. This change should be forward compatible with future versions of Ruby should the `Dir.home` module adapt the approach we use here. In such a case, the module would cease to throw the exception that it does currently, and this augmenting code will not be executed. This change also simplifies the `test_missing_environment` unit test. This issue surfaced when integration tests were first setup for the `Netrc` project on GitHub Actions. The process that runs the unit tests there is not a (grand)child of login(1), so fails on the unit tests that exercise the "what to do when $HOME is unset" logic. --- lib/netrc.rb | 26 +++++++++++++++++ test/test_netrc.rb | 70 ++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 87 insertions(+), 9 deletions(-) diff --git a/lib/netrc.rb b/lib/netrc.rb index 5e012bd..41352f0 100644 --- a/lib/netrc.rb +++ b/lib/netrc.rb @@ -23,6 +23,32 @@ def self.home_path (home && File.readable?(home)) ? home : Dir.pwd rescue ArgumentError + + unless WINDOWS + # Ruby 2.5.x through 2.7.1 (and probably other versions) raises an + # ArgumentError when the 'HOME' env var is not set and the process is + # not a subprocess of a login session. That is, it tries to navigate + # into the password database using the username obtained from + # getlogin(), whichs will return NULL in such a circumstance. It would + # be better if it instead tried to do it via the UID obtained from + # getuid(), which always succeeds. Nevertheless, we'll work around the + # problem by doing that ourselves here. + begin + require 'etc' + rescue LoadError + warn "HOME is not set, and the 'etc' module not available; using pwd as home\n" + return Dir.pwd + end + + passwd_record = Etc.getpwuid(Process.uid); + unless passwd_record + warn "Record for uid #{Process.uid} not found in the password database; using pwd as home\n" + return Dir.pwd + end + + return passwd_record.dir + end + return Dir.pwd end diff --git a/test/test_netrc.rb b/test/test_netrc.rb index a30e4c4..94c41cc 100644 --- a/test/test_netrc.rb +++ b/test/test_netrc.rb @@ -16,6 +16,38 @@ def teardown Dir.glob('data/*.netrc').each{|f| File.chmod(0644, f)} end + # Helper for obtaining a value for the user's home directory from the + # password database (querying it by uid), else falling back on using the + # pwd. This is analogous to what the Netrc.home_path method does on + # Unix-like systems when neither 'NETRC' nor 'HOME' are defined, if the + # process is not a child (or grandchild) of a login session, or if the + # user's actual home directory is not readable for some reason. + # + def fallback_homedir_else_pwd + begin + require 'etc' + rescue LoadError + # Without the 'Etc' module we are unable to query the password database + return Dir.pwd + end + + # Note that Process.uid returns the value of getuid() which (on Linux) may + # be different from the value of /proc/self/loginuid (e.g., for a process + # that is not a (grand)child of a login process). That is important here + # because we should be able to obtain the record from the password + # database, even if Ruby's built-in 'Dir.home' cannot (because it uses + # getlogin() and fails in that scenario, at least through Ruby 2.7.1). + # + passwd_record = Etc.getpwuid(Process.uid) + unless passwd_record + return Dir.pwd # Record for uid not available for some reason + end + + return passwd_record.dir if File.readable?(passwd_record.dir) + + return Dir.pwd + end + def test_parse_empty pre, items = Netrc.parse(Netrc.lex([])) assert_equal("", pre) @@ -197,20 +229,40 @@ def test_encrypted_roundtrip end end + # The precedence order for finding the user's netrc file is the first + # /readable/ name from the following list: + # + # 1. Use NETRC, if set + # 2. Use "$HOME/.netrc", if HOME is set + # 3. Use Dir.home, if possible (only works where getlogin() is non-NULL) + # 4. (MS Windows only) Combine HOMEDRIVE and HOMEPATH, if both are set + # 5. (MS Windows only) Use USERPROFILE, if set + # 6. (Non-MS Windows only) Use pw_dir field from password database, if available + # 7. Dir.pwd (is not checked for readability) + # + # This test exercises the behavior when none of the above listed environment + # variables are present and/or set. + # def test_missing_environment - nil_home = nil - ENV["HOME"], nil_home = nil_home, ENV["HOME"] - # If user's home directory can be obtained via getpwnam(3) AND is - # readable, then the $HOME environment variable is not considered for - # building the Netrc default_path, and no fallback directory is - # referenced. - dflt_dir = Dir.respond_to?(:home) && File.readable?(Dir.home) \ - ? Dir.home : Dir.pwd + envkeys = %w(NETRC HOME HOMEDRIVE HOMEPATH USERPROFILE) + envhold = {} + + envkeys.each do |ekey| + if ENV.has_key?(ekey) + envhold[ekey] = ENV[ekey] + ENV.delete(ekey) + end + end + + dflt_dir = self.fallback_homedir_else_pwd assert_equal File.join(dflt_dir, '.netrc'), Netrc.default_path ensure - ENV["HOME"], nil_home = nil_home, ENV["HOME"] + # ENV obj is not really a hash; use poor man's manual merge!(...) + envhold.each do |holdkey, holdval| + ENV[holdkey] = holdval + end end def test_netrc_environment_variable
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2