File 42-null_usersfile_okay.patch of Package oath-toolkit

From f69897e6e8b3881b9e470a384cefc41a851b2475 Mon Sep 17 00:00:00 2001
From: Luna <luna.dragon@suse.com>
Date: Mon, 9 Sep 2024 19:14:08 +0530
Subject: [PATCH 2/2] pam_oath: add null_usersfile_okay parameter to pam_oath

Co-authored-by: Jan Zerebecki <jzerebecki@suse.com>
Co-authored-by: Miika Alikirri <miika.alikirri@suse.com>
---
 pam_oath/README     | 10 ++++++++++
 pam_oath/pam_oath.c | 32 ++++++++++++++++++++++++++++++++
 2 files changed, 42 insertions(+)

diff --git a/pam_oath/README b/pam_oath/README
index 9a8e7366..3c7da052 100644
--- a/pam_oath/README
+++ b/pam_oath/README
@@ -77,6 +77,7 @@ jas@mocca:~$ su
 [pam_oath.c:parse_cfg(127)] alwaysok=1
 [pam_oath.c:parse_cfg(128)] try_first_pass=0
 [pam_oath.c:parse_cfg(129)] use_first_pass=0
+[pam_oath.c:parse_cfg(129)] no_usersfile_okay=0
 [pam_oath.c:parse_cfg(130)] usersfile=/etc/users.oath
 [pam_oath.c:parse_cfg(131)] digits=0
 [pam_oath.c:parse_cfg(132)] window=20
@@ -144,6 +145,7 @@ jas@mocca:~$ su
 [pam_oath.c:parse_cfg(127)] alwaysok=1
 [pam_oath.c:parse_cfg(128)] try_first_pass=0
 [pam_oath.c:parse_cfg(129)] use_first_pass=0
+[pam_oath.c:parse_cfg(129)] no_usersfile_okay=0
 [pam_oath.c:parse_cfg(130)] usersfile=/etc/users.oath
 [pam_oath.c:parse_cfg(131)] digits=6
 [pam_oath.c:parse_cfg(132)] window=20
@@ -176,6 +178,7 @@ jas@mocca:~$ su
 [pam_oath.c:parse_cfg(127)] alwaysok=1
 [pam_oath.c:parse_cfg(128)] try_first_pass=0
 [pam_oath.c:parse_cfg(129)] use_first_pass=0
+[pam_oath.c:parse_cfg(129)] no_usersfile_okay=0
 [pam_oath.c:parse_cfg(130)] usersfile=/etc/users.oath
 [pam_oath.c:parse_cfg(131)] digits=6
 [pam_oath.c:parse_cfg(132)] window=20
@@ -213,6 +216,13 @@ List of all parameters
                     never prompt the user - if no password is
                     available or the password is not appropriate, the
                     user will be denied access.
+  "no_usersfile_okay": The argument no_usersfile_okay forces the module
+                      to act as if the user is not present in the config,
+                      if the config file does not exist. This has
+                      security implications only use if you know what you
+                      are doing. E.g.  if the file is in a mount like home
+                      and that fails to be mounted, then this will succeed
+                      even if the OTP if configured for that user.
 
   "usersfile": Specify filename where credentials are stored, for
                example "/etc/users.oath". The placeholder values
diff --git a/pam_oath/pam_oath.c b/pam_oath/pam_oath.c
index 25eb83e6..72712b53 100644
--- a/pam_oath/pam_oath.c
+++ b/pam_oath/pam_oath.c
@@ -26,6 +26,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#include <libgen.h>
 #include <ctype.h>
 #include <pwd.h>
 #include <unistd.h>
@@ -72,6 +73,7 @@ struct cfg
   int alwaysok;
   int try_first_pass;
   int use_first_pass;
+  int no_usersfile_okay;
   char *usersfile;
   unsigned digits;
   unsigned window;
@@ -86,6 +88,7 @@ parse_cfg (int flags, int argc, const char **argv, struct cfg *cfg)
   cfg->alwaysok = 0;
   cfg->try_first_pass = 0;
   cfg->use_first_pass = 0;
+  cfg->no_usersfile_okay = 0;
   cfg->usersfile = NULL;
   cfg->digits = -1;
   cfg->window = 5;
@@ -100,6 +103,8 @@ parse_cfg (int flags, int argc, const char **argv, struct cfg *cfg)
 	cfg->try_first_pass = 1;
       if (strcmp (argv[i], "use_first_pass") == 0)
 	cfg->use_first_pass = 1;
+      if (strcmp (argv[i], "no_usersfile_okay") == 0)
+	cfg->no_usersfile_okay = 1;
       if (strncmp (argv[i], "usersfile=", 10) == 0)
 	cfg->usersfile = (char *) argv[i] + 10;
       if (strncmp (argv[i], "digits=", 7) == 0)
@@ -126,6 +131,7 @@ parse_cfg (int flags, int argc, const char **argv, struct cfg *cfg)
       D (("alwaysok=%d", cfg->alwaysok));
       D (("try_first_pass=%d", cfg->try_first_pass));
       D (("use_first_pass=%d", cfg->use_first_pass));
+      D (("no_usersfile_okay=%d", cfg->no_usersfile_okay));
       D (("usersfile=%s", cfg->usersfile ? cfg->usersfile : "(null)"));
       D (("digits=%d", cfg->digits));
       D (("window=%d", cfg->window));
@@ -292,6 +298,32 @@ pam_sm_authenticate (pam_handle_t *pamh,
     }
   DBG (("usersfile is %s", usersfile));
 
+  if (cfg.no_usersfile_okay)
+    {
+      char *ucopy, *base;
+      ucopy = strdup (usersfile);
+      base = dirname (ucopy);
+
+      /* make sure that the base dir exists so we are sure that, for example,
+         the user home directory is mounted. */
+      rc = access (base, F_OK);
+      free (ucopy);
+      if (rc != 0)
+	{
+	  DBG (("Basepath of file cannot be accessed '%s'", usersfile));
+	  retval = PAM_AUTH_ERR;
+	  goto done;
+	}
+
+      if (access (usersfile, F_OK) != 0)
+	{
+	  DBG (("no_usersfile_okay set and no userfile was found, authenticating..."));
+	  retval = PAM_SUCCESS;
+	  goto done;
+	}
+    }
+
+
   // quick check to skip unconfigured users before prompting for password
   {
     time_t last_otp;
-- 
GitLab

openSUSE Build Service is sponsored by