about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--doc/nsssd-switch.html135
-rw-r--r--src/nsssd/nsssd-switch.c83
-rwxr-xr-x[l---------]src/tests/test-nsssd-switch.baseline8
-rw-r--r--[l---------]src/tests/test-nsssd-switch.c84
-rwxr-xr-xsrc/tests/test-nsssd-switch.wrapper6
-rwxr-xr-xsrc/tests/test-switch.wrapper6
7 files changed, 294 insertions, 29 deletions
diff --git a/.gitignore b/.gitignore
index 94f63b1..4fb2d9b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,4 +10,3 @@
 /nsssd-nslcd
 /nsssd-switch
 /test-*
-/.test-*
diff --git a/doc/nsssd-switch.html b/doc/nsssd-switch.html
index 9f5672c..bd6f63b 100644
--- a/doc/nsssd-switch.html
+++ b/doc/nsssd-switch.html
@@ -36,7 +36,7 @@ configuration on the command line.
 <h2> Interface </h2>
 
 <pre>
-     s6-ipcserver -l0 /run/service/nsssd/s nsssd-switch <em>bitfield1</em> <em>backend1...</em> "" <em>bitfield2</em> <em>backend2...</em> "" ...
+     s6-ipcserver -l0 /run/service/nsssd/s nsssd-switch [ -t <em>timeout</em> ] <em>bitfield1</em> <em>backend1...</em> "" <em>bitfield2</em> <em>backend2...</em> "" ...
 </pre>
 
 <p>
@@ -52,35 +52,132 @@ configuration on the command line.
 </pre>
 
 <ul>
- <li> <tt>nsssd-switch</tt>
+ <li> <tt>nsssd-switch</tt> is normally spawned by a super-server like
+<a href="//skarnet.org/software/s6/s6-ipcserver.html">s6-ipcserver</a>.
+There is one instance of <tt>nsssd-switch</tt> per client connection. </li>
+ <li> <tt>nsssd-switch</tt> interprets its command line as a script that
+configures all its backends. The script is a series of directives:
+  <ol>
+   <li> First a <em>bitfield</em> is read: it's a number between 0 and 7.
+This number determines how the backend will behave in case of failure. </li>
+   <li> Then a <em>backend</em> is read: it is a full command-line, terminated
+by an empty word. (In an <a href="//skarnet.org/software/execline/execlineb.html>execline</a>
+script, the <em>backend</em> is a block, without the empty word.) The command
+line is an implementation of the server side of the nsss protocol: for instance,
+<tt>nsssd-unix ""</tt> declares a Unix backend with user, group and shadow
+credentials in <tt>/etc/passwd</tt>, <tt>/etc/group</tt> and <tt>/etc/shadow</tt>.
+</li>
+  </ol> </li>
+ <li> <tt>nsssd-switch</tt> spawns all its declared backends. </li>
+ <li> It then reads queries from its client. It transmits every query to
+its backends, in the order given on the command line. A success means
+that the answer is immediately returned to the client, and no further
+backend is contacted. A failure can be handled in different ways, depending
+on the type of failure and on the <em>bitfield</em> associated to the
+<em>backend</em>. </li>
+ <li> <tt>nsssd-switch</tt> (and all the backends it spawned) exits when
+the client connection is closed, or in some cases, after a timeout. </li>
 </ul>
 
+<h2> Exit codes </h2>
 
-<h2> Notes </h2>
+<p>
+ These exit codes are not important because only the super-server can see them.
+</p>
+
+<ul>
+ <li> 0: normal exit or timeout while waiting for a client query </li>
+ <li> 100: wrong usage </li>
+ <li> 111: system call failed or timeout during a nsss protocol exchange </li>
+</ul>
+
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-t&nbsp;<em>timeout</em></tt>&nbsp;: enforce a limit of
+<em>timeout</em> milliseconds when communicating with a backend. If a
+backend fails to answer a query under <em>timeout</em> milliseconds,
+<tt>nsssd-switch</tt> will return a failure code to the client, and
+the backend will be considered permanently failed. The default is 0,
+meaning no such timeout - backends can take as much time as they want
+to answer queries. </li>
+</ul>
+
+<h2> Environment variables </h2>
 
 <p>
- nsssd-switch is not meant to be called directly; instead, it is expected to be run from
-a script as a part of a "nsssd"
-<a href="//skarnet.org/software/s6/localservice.html">local service</a>.
+ <tt>nsssd-switch</tt> can read a number <em>x</em> in the NSSSD_TIMEOUT
+environment variable. If this variable is present and valid, it means that
+<tt>nsssd-switch</tt> will die if <em>x</em> milliseconds elapse without
+the client reading or writing during a nsss protocol exchange, which usually
+means the client either is not speaking the protocol correctly or has become
+unresponsive. It is a safety measure to avoid having <tt>nsssd</tt> processes
+sticking around forever when a client is buggy.
+</p>
+
+<p>
+ Note that the NSSSD_TIMEOUT variable refers to a timeout during an exchange
+with the <em>client</em>, while the argument to the <tt>-t</tt> option refers
+to a timeout enforced on the <em>backends</em>.
 </p>
 
+<h2> Bitfields </h2>
+
 <p>
+ A <em>bitfield</em> is a value between 0 and 7, representing 3 bits. If a
+bit is 0, it means that the query resolution will <em>continue to the next
+backend</em> if the corresponding failure condition is triggered. If the
+bit is 1, it means that the failure will instantly be reported to the client
+and the query will not be transmitted to the next backend in the chain.
+</p>
+
+<ul>
+ <li> Bit 0: the backend is in a state of permanent failure: it failed to start,
+it crashed, or it timed out. </li>
+ <li> Bit 1: the backend answered the query with a failure. </li>
+ <li> Bit 2: the requested entry was not found in the backend's database. </li>
+</ul>
+
+<p>
+ So, for instance, a bitfield of 5 means: report failure to the client if the
+current backend is in a failed state or if a requested entry cannot be found.
+Proceed to the next backend if the current backend reports failure when
+processing a query.
+</p>
+
+<p>
+ This format allows the administrator to configure various fallback strategies.
+Note that in case of success, the requested data is immediately returned to the
+client. <tt>nsssd-switch</tt> does not provide the equivalent of the <tt>merge</tt>
+directive in <tt>/etc/nsswitch.conf</tt>.
+</p>
+
+<h2> Notes </h2>
+
+<ul>
+<li>
+ <tt>nsssd-switch</tt> is not meant to be called directly; instead, it is expected to be run from
+a script as a part of a "nsssd"
+<a href="//skarnet.org/software/s6/localservice.html">local service</a>.
+</li>
+
+<li>
  The <tt>examples/</tt> subdirectory of the nsss package provides examples
 on how to run such a service.
  The simplest way to do so, for testing purposes, is a command line such as:
-</p>
 <pre>s6-ipcserver -l0 /run/service/nsssd/s nsssd-switch 0 nsssd-unix "" </pre>
+</li>
 
-<p>
+<li>
 <tt>/run/service/nsssd/s</tt> is the default place where nsss's
 implementation of the <tt>pwd.h</tt>, <tt>grp.h</tt> and <tt>shadow.h</tt>
 functions expects the nsssd
 service to be. It can be changed at nsss build time by giving the
 <tt>--with-nsssd-socket=PATH</tt> option to configure.
-</p>
+</li>
 
-<p>
- nsssd-switch does not listen to the socket itself: it reads from its
+<li>
+ <tt>nsssd-switch</tt> does not listen to the socket itself: it reads from its
 standard input and writes to its standard output. It relies
 on a superserver such as
 <a href="//skarnet.org/software/s6/s6-ipcserver.html">s6-ipcserver</a>
@@ -88,18 +185,24 @@ to manage connections to the socket. An instance of nsssd-switch is run
 for every client connection.
 </p>
 
-<p>
+<li>
  If fine-grained authorizations are required (only allowing
 certain users and groups to connect to the service), the superserver
 can be configured to enforce them.
-</p>
+</li>
 
-<p>
- nsssd-switch does not need to run as root, provided it has all the
+<li>
+ <tt>nsssd-switch</tt> does not need to run as root, provided it has all the
 permissions needed by the backends it spawns.
 It is recommended to create a <em>nsss</em> user and group, dedicated to
 the nsssd service, and run the superserver as this user and group.
-</p>
+</li>
+
+<li>
+ <tt>nsssd-switch</tt> is limited to 8 backends. If you need more, you can
+chain another <tt>nsssd-switch</tt> invocation as the 8th backend,
+which gives you another batch of 8.
+</li>
 
 </body>
 </html>
diff --git a/src/nsssd/nsssd-switch.c b/src/nsssd/nsssd-switch.c
index 4906728..de670a7 100644
--- a/src/nsssd/nsssd-switch.c
+++ b/src/nsssd/nsssd-switch.c
@@ -18,7 +18,7 @@
 #define USAGE "nsssd-switch bitfield1 backend1... \"\" bitfield2 backend2... \"\""
 #define dieusage() strerr_dieusage(100, USAGE)
 
-#define MAX_BACKENDS 16
+#define MAX_BACKENDS 8
 
 static tain tto = TAIN_INFINITE_RELATIVE ;
 static stralloc storagesa = STRALLOC_ZERO ;
@@ -148,6 +148,11 @@ int nsssd_pwd_rewind (void *handle)
     }
     tain_add_g(&deadline, &tto) ;
     if (nsss_switch_pwd_rewind_g(&a->tab[i].handle, &deadline)) return 1 ;
+    if (errno == ETIMEDOUT)
+    {
+      nsss_switch_end(&a->tab[i].handle, NSSS_SWITCH_PWD | NSSS_SWITCH_GRP | NSSS_SWITCH_SHADOW) ;
+      a->tab[i].failed = 1 ;
+    }
     if (a->tab[i].flags & 2) return 0 ;
   }
   return 0 ;
@@ -168,6 +173,11 @@ int nsssd_pwd_get (void *handle, struct passwd *pw)
     storagesa.len = 0 ;
     errno = 0 ;
     if (nsss_switch_pwd_get_g(&a->tab[i].handle, pw, &storagesa, &deadline)) return 1 ;
+    if (errno == ETIMEDOUT)
+    {
+      nsss_switch_end(&a->tab[i].handle, NSSS_SWITCH_PWD | NSSS_SWITCH_GRP | NSSS_SWITCH_SHADOW) ;
+      a->tab[i].failed = 1 ;
+    }
     if (a->tab[i].flags & (errno ? 2 : 4)) return 0 ;
   }
   return 0 ;
@@ -188,6 +198,11 @@ int nsssd_pwd_getbyuid (void *handle, struct passwd *pw, uid_t uid)
     storagesa.len = 0 ;
     errno = 0 ;
     if (nsss_switch_pwd_getbyuid_g(&a->tab[i].handle, pw, &storagesa, uid, &deadline)) return 1 ;
+    if (errno == ETIMEDOUT)
+    {
+      nsss_switch_end(&a->tab[i].handle, NSSS_SWITCH_PWD | NSSS_SWITCH_GRP | NSSS_SWITCH_SHADOW) ;
+      a->tab[i].failed = 1 ;
+    }
     if (a->tab[i].flags & (errno ? 2 : 4)) return 0 ;
   }
   return 0 ;
@@ -208,6 +223,11 @@ int nsssd_pwd_getbyname (void *handle, struct passwd *pw, char const *name)
     storagesa.len = 0 ;
     errno = 0 ;
     if (nsss_switch_pwd_getbyname_g(&a->tab[i].handle, pw, &storagesa, name, &deadline)) return 1 ;
+    if (errno == ETIMEDOUT)
+    {
+      nsss_switch_end(&a->tab[i].handle, NSSS_SWITCH_PWD | NSSS_SWITCH_GRP | NSSS_SWITCH_SHADOW) ;
+      a->tab[i].failed = 1 ;
+    }
     if (a->tab[i].flags & (errno ? 2 : 4)) return 0 ;
   }
   return 0 ;
@@ -225,7 +245,12 @@ void nsssd_pwd_end (void *handle)
       else continue ;
     }
     tain_add_g(&deadline, &tto) ;
-    nsss_switch_pwd_end_g(&a->tab[i].handle, &deadline) ;
+    if (nsss_switch_pwd_end_g(&a->tab[i].handle, &deadline)) continue ;
+    if (errno == ETIMEDOUT)
+    {
+      nsss_switch_end(&a->tab[i].handle, NSSS_SWITCH_PWD | NSSS_SWITCH_GRP | NSSS_SWITCH_SHADOW) ;
+      a->tab[i].failed = 1 ;
+    }
   }
 }
 
@@ -248,6 +273,11 @@ int nsssd_grp_rewind (void *handle)
     }
     tain_add_g(&deadline, &tto) ;
     if (nsss_switch_grp_rewind_g(&a->tab[i].handle, &deadline)) return 1 ;
+    if (errno == ETIMEDOUT)
+    {
+      nsss_switch_end(&a->tab[i].handle, NSSS_SWITCH_PWD | NSSS_SWITCH_GRP | NSSS_SWITCH_SHADOW) ;
+      a->tab[i].failed = 1 ;
+    }
     if (a->tab[i].flags & 2) return 0 ;
   }
   return 0 ;
@@ -269,6 +299,11 @@ int nsssd_grp_get (void *handle, struct group *gr)
     genalloc_setlen(char *, &storagega, 0) ;
     errno = 0 ;
     if (nsss_switch_grp_get_g(&a->tab[i].handle, gr, &storagesa, &storagega, &deadline)) return 1 ;
+    if (errno == ETIMEDOUT)
+    {
+      nsss_switch_end(&a->tab[i].handle, NSSS_SWITCH_PWD | NSSS_SWITCH_GRP | NSSS_SWITCH_SHADOW) ;
+      a->tab[i].failed = 1 ;
+    }
     if (a->tab[i].flags & (errno ? 2 : 4)) return 0 ;
   }
   return 0 ;
@@ -290,6 +325,11 @@ int nsssd_grp_getbygid (void *handle, struct group *gr, gid_t gid)
     genalloc_setlen(char *, &storagega, 0) ;
     errno = 0 ;
     if (nsss_switch_grp_getbygid_g(&a->tab[i].handle, gr, &storagesa, &storagega, gid, &deadline)) return 1 ;
+    if (errno == ETIMEDOUT)
+    {
+      nsss_switch_end(&a->tab[i].handle, NSSS_SWITCH_PWD | NSSS_SWITCH_GRP | NSSS_SWITCH_SHADOW) ;
+      a->tab[i].failed = 1 ;
+    }
     if (a->tab[i].flags & (errno ? 2 : 4)) return 0 ;
   }
   return 0 ;
@@ -311,6 +351,11 @@ int nsssd_grp_getbyname (void *handle, struct group *gr, char const *name)
     genalloc_setlen(char *, &storagega, 0) ;
     errno = 0 ;
     if (nsss_switch_grp_getbyname_g(&a->tab[i].handle, gr, &storagesa, &storagega, name, &deadline)) return 1 ;
+    if (errno == ETIMEDOUT)
+    {
+      nsss_switch_end(&a->tab[i].handle, NSSS_SWITCH_PWD | NSSS_SWITCH_GRP | NSSS_SWITCH_SHADOW) ;
+      a->tab[i].failed = 1 ;
+    }
     if (a->tab[i].flags & (errno ? 2 : 4)) return 0 ;
   }
   return 0 ;
@@ -331,6 +376,11 @@ int nsssd_grp_getlist (void *handle, char const *user, gid_t *gids, size_t n, si
     storagesa.len = 0 ;
     errno = 0 ;
     if (nsss_switch_grp_getlist_g(&a->tab[i].handle, user, gids, n, r, &storagesa, &deadline)) return 1 ;
+    if (errno == ETIMEDOUT)
+    {
+      nsss_switch_end(&a->tab[i].handle, NSSS_SWITCH_PWD | NSSS_SWITCH_GRP | NSSS_SWITCH_SHADOW) ;
+      a->tab[i].failed = 1 ;
+    }
     if (a->tab[i].flags & (errno ? 2 : 4)) return 0 ;
   }
   return 0 ;
@@ -348,7 +398,12 @@ void nsssd_grp_end (void *handle)
       else continue ;
     }
     tain_add_g(&deadline, &tto) ;
-    nsss_switch_grp_end_g(&a->tab[i].handle, &deadline) ;
+    if (nsss_switch_grp_end_g(&a->tab[i].handle, &deadline)) continue ;
+    if (errno == ETIMEDOUT)
+    {
+      nsss_switch_end(&a->tab[i].handle, NSSS_SWITCH_PWD | NSSS_SWITCH_GRP | NSSS_SWITCH_SHADOW) ;
+      a->tab[i].failed = 1 ;
+    }
   }
 }
 
@@ -371,6 +426,11 @@ int nsssd_shadow_rewind (void *handle)
     }
     tain_add_g(&deadline, &tto) ;
     if (nsss_switch_shadow_rewind_g(&a->tab[i].handle, &deadline)) return 1 ;
+    if (errno == ETIMEDOUT)
+    {
+      nsss_switch_end(&a->tab[i].handle, NSSS_SWITCH_PWD | NSSS_SWITCH_GRP | NSSS_SWITCH_SHADOW) ;
+      a->tab[i].failed = 1 ;
+    }
     if (a->tab[i].flags & 2) return 0 ;
   }
   return 0 ;
@@ -391,6 +451,11 @@ int nsssd_shadow_get (void *handle, struct spwd *sp)
     storagesa.len = 0 ;
     errno = 0 ;
     if (nsss_switch_shadow_get_g(&a->tab[i].handle, sp, &storagesa, &deadline)) return 1 ;
+    if (errno == ETIMEDOUT)
+    {
+      nsss_switch_end(&a->tab[i].handle, NSSS_SWITCH_PWD | NSSS_SWITCH_GRP | NSSS_SWITCH_SHADOW) ;
+      a->tab[i].failed = 1 ;
+    }
     if (a->tab[i].flags & (errno ? 2 : 4)) return 0 ;
   }
   return 0 ;
@@ -411,6 +476,11 @@ int nsssd_shadow_getbyname (void *handle, struct spwd *sp, char const *name)
     storagesa.len = 0 ;
     errno = 0 ;
     if (nsss_switch_shadow_getbyname_g(&a->tab[i].handle, sp, &storagesa, name, &deadline)) return 1 ;
+    if (errno == ETIMEDOUT)
+    {
+      nsss_switch_end(&a->tab[i].handle, NSSS_SWITCH_PWD | NSSS_SWITCH_GRP | NSSS_SWITCH_SHADOW) ;
+      a->tab[i].failed = 1 ;
+    }
     if (a->tab[i].flags & (errno ? 2 : 4)) return 0 ;
   }
   return 0 ;
@@ -428,7 +498,12 @@ void nsssd_shadow_end (void *handle)
       else continue ;
     }
     tain_add_g(&deadline, &tto) ;
-    nsss_switch_pwd_end_g(&a->tab[i].handle, &deadline) ;
+    if (nsss_switch_pwd_end_g(&a->tab[i].handle, &deadline)) continue ;
+    if (errno == ETIMEDOUT)
+    {
+      nsss_switch_end(&a->tab[i].handle, NSSS_SWITCH_PWD | NSSS_SWITCH_GRP | NSSS_SWITCH_SHADOW) ;
+      a->tab[i].failed = 1 ;
+    }
   }
 }
 
diff --git a/src/tests/test-nsssd-switch.baseline b/src/tests/test-nsssd-switch.baseline
index 28f1c7a..31fba7e 120000..100755
--- a/src/tests/test-nsssd-switch.baseline
+++ b/src/tests/test-nsssd-switch.baseline
@@ -1 +1,7 @@
-test-switch.baseline
\ No newline at end of file
+#!/bin/sh -e
+
+cat /etc/passwd
+echo
+id -u root
+echo
+cat /etc/group
diff --git a/src/tests/test-nsssd-switch.c b/src/tests/test-nsssd-switch.c
index 08323c4..e4289e4 120000..100644
--- a/src/tests/test-nsssd-switch.c
+++ b/src/tests/test-nsssd-switch.c
@@ -1 +1,83 @@
-test-switch.c
\ No newline at end of file
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/buffer.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/lolstdio.h>
+#include <skalibs/tai.h>
+#include <nsss/pwd-def.h>
+#include <nsss/grp-def.h>
+#include <nsss/nsss-switch.h>
+
+#define S "./.test-nsssd-switch-socket"
+
+int main (void)
+{
+  nsss_switch_t a = NSSS_SWITCH_ZERO ;
+  stralloc sa = STRALLOC_ZERO ;
+  genalloc ga = GENALLOC_ZERO ;
+  tain deadline ;
+  PROG = "test-nsssd-switch" ;
+  tain_now_set_stopwatch_g() ;
+  tain_from_millisecs(&deadline, 10000) ;
+  tain_add_g(&deadline, &deadline) ;
+
+  if (!nsss_switch_start_g(&a, NSSS_SWITCH_PWD, S, &deadline))
+    strerr_diefu1sys(111, "nsss_switch_start") ;
+
+  for (;;)
+  {
+    struct passwd pw ;
+    errno = 0 ;
+    if (!nsss_switch_pwd_get_g(&a, &pw, &sa, &deadline)) break ;
+    lolprintf("%s:%s:%d:%d:%s:%s:%s\n", pw.pw_name, pw.pw_passwd, (int)pw.pw_uid, (int)pw.pw_gid, pw.pw_gecos, pw.pw_dir, pw.pw_shell) ;
+    sa.len = 0 ;
+  }
+  if (errno)
+    strerr_diefu1sys(111, "nsss_switch_pwd_get") ;
+  if (!nsss_switch_pwd_end_g(&a, &deadline))
+    strerr_diefu1sys(111, "nsss_switch_pwd_end") ;
+  lolprintf("\n") ;
+
+  {
+    struct passwd pw ;
+    if (!nsss_switch_pwd_getbyname_g(&a, &pw, &sa, "root", &deadline))
+      strerr_diefu1sys(111, "nsss_switch_pwd_getbyname") ;
+    lolprintf("%u\n\n", (unsigned int)pw.pw_uid) ;
+    sa.len = 0 ;
+  }
+
+  if (!nsss_switch_start_g(&a, NSSS_SWITCH_GRP, S, &deadline))
+    strerr_diefu1sys(111, "nsss_switch_start") ;
+  nsss_switch_end(&a, NSSS_SWITCH_PWD) ;
+  buffer_flush(buffer_1) ;
+
+  for (;;)
+  {
+    struct group gr ;
+    char **p ;
+    errno = 0 ;
+    if (!nsss_switch_grp_get_g(&a, &gr, &sa, &ga, &deadline)) break ;
+    p = gr.gr_mem ;
+    lolprintf("%s:%s:%d:", gr.gr_name, gr.gr_passwd, (int)gr.gr_gid) ;
+    buffer_flush(buffer_1) ;
+    if (*p)
+    {
+      while (*p) lolprintf("%s,", *p++) ;
+      buffer_unput(buffer_1, 1) ;
+    }
+    buffer_put(buffer_1, "\n", 1) ;
+    sa.len = 0 ;
+    genalloc_setlen(char *, &ga, 0) ;
+  }
+  if (errno)
+    strerr_diefu1sys(111, "nsss_switch_grp_get") ;
+  if (!nsss_switch_grp_end_g(&a, &deadline))
+    strerr_diefu1sys(111, "nsss_switch_grp_end") ;
+  nsss_switch_end(&a, NSSS_SWITCH_GRP) ;
+
+  buffer_flush(buffer_1) ;  
+  return 0 ;
+}
diff --git a/src/tests/test-nsssd-switch.wrapper b/src/tests/test-nsssd-switch.wrapper
index 8e05937..509bf18 100755
--- a/src/tests/test-nsssd-switch.wrapper
+++ b/src/tests/test-nsssd-switch.wrapper
@@ -1,13 +1,13 @@
 #!/bin/sh -e
 
-S=./.test-switch-socket
-F=./.test-switch-fifo
+S=./.test-nsssd-switch-socket
+F=./.test-nsssd-switch-fifo
 
 pid=0
 
 cleanup () {
   kill $pid
-  rm -f $S
+  rm -f ${S} ${S}.lock
 }
 
 mkfifo $F
diff --git a/src/tests/test-switch.wrapper b/src/tests/test-switch.wrapper
index 5117400..387595f 100755
--- a/src/tests/test-switch.wrapper
+++ b/src/tests/test-switch.wrapper
@@ -1,4 +1,4 @@
-#!/bin/sh -e
+#!/bin/sh -ex
 
 S=./.test-switch-socket
 F=./.test-switch-fifo
@@ -7,13 +7,13 @@ pid=0
 
 cleanup () {
   kill $pid
-  rm -f $S
+  rm -f ${S} ${S}.lock
 }
 
 mkfifo $F
 head -n 1 < $F >/dev/null &
 pid=$!
-s6-ipcserver -1 -- $S ./nsssd-unix > $F &
+s6-ipcserver -1 -- ${S} ./nsssd-unix > $F &
 wait $pid
 pid=$!
 rm -f $F