Hi there.

it might make sense to not put user credentials into a global
configuration file. similarly, ~/.ssh/authorized_keys is per-user.

the current usersfile argument only specifies one global path. this may
be extended allowing some magic substring, like "%h" to point to the
home directory of the user that tries to authenticate.

this will lock out users that do not provide a usersfile, an additional
"optional" flag may then bypass the authorization (but there might be a
better way).

please consider the attached commit.

thanks
felix

PS: plese cc, i'm not a subscriber
>From 65e46554c7ad85a6ad480303c93f4007f0bbe916 Mon Sep 17 00:00:00 2001
From: Felix Salfelder <[email protected]>
Date: Sat, 6 Dec 2014 16:07:44 +0100
Subject: [PATCH] private usersfile and optional flag

---
 pam_oath/pam_oath.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/pam_oath/pam_oath.c b/pam_oath/pam_oath.c
index 8a17327..d12f7cf 100644
--- a/pam_oath/pam_oath.c
+++ b/pam_oath/pam_oath.c
@@ -26,6 +26,7 @@
 #include <stdlib.h>
 #include <stdarg.h>
 #include <ctype.h>
+#include <pwd.h>
 
 /* Libtool defines PIC for shared objects */
 #ifndef PIC
@@ -69,6 +70,7 @@ struct cfg
   int alwaysok;
   int try_first_pass;
   int use_first_pass;
+  int optional;
   char *usersfile;
   unsigned digits;
   unsigned window;
@@ -83,6 +85,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->optional = 0;
   cfg->usersfile = NULL;
   cfg->digits = -1;
   cfg->window = 5;
@@ -91,6 +94,8 @@ parse_cfg (int flags, int argc, const char **argv, struct cfg *cfg)
     {
       if (strcmp (argv[i], "debug") == 0)
 	cfg->debug = 1;
+      if (strcmp (argv[i], "optional") == 0)
+	cfg->optional = 1;
       if (strcmp (argv[i], "alwaysok") == 0)
 	cfg->alwaysok = 1;
       if (strcmp (argv[i], "try_first_pass") == 0)
@@ -123,12 +128,45 @@ 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 (("optional=%d", cfg->optional));
       D (("usersfile=%s", cfg->usersfile ? cfg->usersfile : "(null)"));
       D (("digits=%d", cfg->digits));
       D (("window=%d", cfg->window));
     }
 }
 
+static char*
+prep_cfg (struct cfg *cfg, const char* user, char* scratch)
+{
+  char *hpos;
+  char *ret;
+  int size;
+  const struct passwd *pwent;
+  hpos = strstr(cfg->usersfile,"%h");
+
+  if(hpos)
+    {
+      if (cfg->debug)
+	D (("found %h for %s", user));
+      pwent = getpwnam(user);
+      if(!pwent) return NULL;
+      if(!pwent->pw_dir) return NULL;
+      if(!*pwent->pw_dir) return NULL;
+
+      size = strlen(cfg->usersfile) + strlen(pwent->pw_dir) - 1;
+      ret = (char*) malloc(size*sizeof(char));
+      strncpy(ret, cfg->usersfile, hpos-cfg->usersfile);
+      strcpy(ret+(hpos-cfg->usersfile), pwent->pw_dir);
+      strcpy(ret+(hpos-cfg->usersfile)+strlen(pwent->pw_dir), hpos+2);
+
+      cfg->usersfile = ret;
+      if(cfg->debug)
+	D (("usersfile=%s", cfg->usersfile));
+      return ret;
+    }
+  return NULL;
+}
+
 PAM_EXTERN int
 pam_sm_authenticate (pam_handle_t * pamh,
 		     int flags, int argc, const char **argv)
@@ -292,6 +330,21 @@ pam_sm_authenticate (pam_handle_t * pamh,
 
   {
     time_t last_otp;
+    char* scratch = NULL;
+    FILE* infh;
+
+    scratch = prep_cfg(&cfg, user, scratch);
+
+    if(cfg.optional)
+      {
+        infh = fopen (cfg.usersfile, "r");
+        if (!infh)
+	  {
+	    DBG (("optional usersfile does not exist, PAM_SUCCESS"));
+	    return PAM_SUCCESS;
+	  }
+        fclose (infh);
+      }
 
     rc = oath_authenticate_usersfile (cfg.usersfile,
 				      user,
@@ -299,6 +352,9 @@ pam_sm_authenticate (pam_handle_t * pamh,
     DBG (("authenticate rc %d (%s: %s) last otp %s", rc,
 	  oath_strerror_name (rc) ? oath_strerror_name (rc) : "UNKNOWN",
 	  oath_strerror (rc), ctime (&last_otp)));
+
+    if (scratch)
+      free(scratch);
   }
 
   if (rc != OATH_OK)
-- 
2.0.0

Reply via email to