[Tarantool-patches] [PATCH 3/3] lua/pwd: workaround the systemd bug

Cyrill Gorcunov gorcunov at gmail.com
Thu Sep 17 16:51:21 MSK 2020


There is a bug in systemd-209 source code: it returns
ENOENT when no more entries in a password database left.

Later the issue been fixed but we still meet the systems
where it hits. The problem affects getpwent/getgrent calls
only thus we can expect them to return the buggy error code
to skip.

Notes:

1) See systemd's commit where issue been fixed

   | commit 06202b9e659e5cc72aeecc5200155b7c012fccbc
   | Author: Yu Watanabe <watanabe.yu+github at gmail.com>
   | Date:   Sun Jul 15 23:00:00 2018 +0900
   |
   |     nss: do not modify errno when NSS_STATUS_NOTFOUND or NSS_STATUS_SUCCESS

2) Another option is to call getpwall on Tarantool startup
   unconditionally where we could simply ignore any errors. This
   is a very bad choise since traversig a password database might
   introduce significant lags if backend does some network activiy
   or have expired caches. Thus drop getpwall() unconditional call
   run it iif a user does an explicit request.

Fixes #5034

Signed-off-by: Cyrill Gorcunov <gorcunov at gmail.com>
---
 src/lua/pwd.lua | 52 +++++++++++++++++++++++++++++++++++++------------
 1 file changed, 40 insertions(+), 12 deletions(-)

diff --git a/src/lua/pwd.lua b/src/lua/pwd.lua
index 31cfbd8bf..907eb5a8e 100644
--- a/src/lua/pwd.lua
+++ b/src/lua/pwd.lua
@@ -196,6 +196,44 @@ local function getpw(uid)
     return pwtotable(pw, gr)
 end
 
+--
+-- systemd v209 sets errno is set to ENOENT in
+-- _nss_systemd_getpwent_r and _nss_systemd_getgrent_r
+-- when there are no more entries to enumerate.
+--
+-- This is a bug which has been fixed later in
+-- systemd code but we have to deal with buggy
+-- systems thus ignore such error if appears.
+--
+-- See the reference for details
+-- https://github.com/systemd/systemd/issues/9585
+--
+-- This issue affects getpwent/getgrent calls only
+-- thus provide own wrappings to keep workaround
+-- in one place and do not affect any other calls
+-- where ENOENT might become a valid error case.
+--
+-- Initially we observed this issue on Fedora 29
+-- when a password database is traversed for the
+-- first time.
+local function getpwent()
+    errno(0)
+    local pw = ffi.C.getpwent()
+    if pw == nil and errno() == errno.ENOENT then
+        errno(0)
+    end
+    return pw
+end
+
+local function getgrent()
+    errno(0)
+    local gr = ffi.C.getgrent()
+    if gr == nil and errno() == errno.ENOENT then
+        errno(0)
+    end
+    return gr
+end
+
 local function getpwall()
     ffi.C.setpwent()
     local pws = {}
@@ -203,8 +241,7 @@ local function getpwall()
     -- of a getpwent() current entry to a first one on CentOS 6
     -- and FreeBSD 12.
     while true do
-        errno(0)
-        local pw = ffi.C.getpwent()
+        local pw = getpwent()
         if pw == nil then
             pwgrcheck('getpwall', pw)
             break
@@ -223,8 +260,7 @@ local function getgrall()
     -- of a getgrent() current entry to a first one on CentOS 6
     -- and FreeBSD 12.
     while true do
-        errno(0)
-        local gr = ffi.C.getgrent()
+        local gr = getgrent()
         if gr == nil then
             pwgrcheck('getgrall', gr)
             break
@@ -237,14 +273,6 @@ end
 
 -- }}}
 
--- Workaround pwd.getpwall() issue on Fedora 29: successful
--- getgrent() call that should normally return NULL and preserve
--- errno, set it to ENOENT due to systemd-nss issue [1] when a
--- password database is traversed first time.
---
--- [1]: https://github.com/systemd/systemd/issues/9585
-pcall(getpwall)
-
 return {
     getpw = getpw,
     getgr = getgr,
-- 
2.26.2



More information about the Tarantool-patches mailing list