diff --git a/libpam/Makefile.am b/libpam/Makefile.am
index 638bb5c..875031e 100644
--- a/libpam/Makefile.am
+++ b/libpam/Makefile.am
@@ -38,4 +38,4 @@ libpam_la_SOURCES = pam_account.c pam_auth.c pam_data.c pam_delay.c \
 	pam_modutil_cleanup.c pam_modutil_getpwnam.c pam_modutil_ioloop.c \
 	pam_modutil_getgrgid.c pam_modutil_getpwuid.c pam_modutil_getgrnam.c \
 	pam_modutil_getspnam.c pam_modutil_getlogin.c pam_modutil_ingroup.c \
-	pam_modutil_priv.c pam_modutil_sanitize.c
+	pam_modutil_priv.c pam_modutil_sanitize.c pam_modutil_searchkey.c
diff --git a/libpam/include/security/pam_modutil.h b/libpam/include/security/pam_modutil.h
index 4ce8c55..3a6aec6 100644
--- a/libpam/include/security/pam_modutil.h
+++ b/libpam/include/security/pam_modutil.h
@@ -142,6 +142,12 @@ pam_modutil_sanitize_helper_fds(pam_handle_t *pamh,
 				enum pam_modutil_redirect_fd redirect_stdout,
 				enum pam_modutil_redirect_fd redirect_stderr);
 
+/* lookup a value for key in login.defs file or similar key value format */
+extern char * PAM_NONNULL((1,2,3))
+pam_modutil_search_key(pam_handle_t *pamh,
+		       const char *file_name,
+		       const char *key);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/libpam/libpam.map b/libpam/libpam.map
index d6835b4..74fb55b 100644
--- a/libpam/libpam.map
+++ b/libpam/libpam.map
@@ -72,3 +72,8 @@ LIBPAM_MODUTIL_1.1.9 {
   global:
     pam_modutil_sanitize_helper_fds;
 } LIBPAM_MODUTIL_1.1.3;
+
+LIBPAM_MODUTIL_1.3.2 {
+  global:
+    pam_modutil_search_key;
+} LIBPAM_MODUTIL_1.1.9;
diff --git a/libpam/pam_modutil_searchkey.c b/libpam/pam_modutil_searchkey.c
new file mode 100644
index 0000000..338b44f
--- /dev/null
+++ b/libpam/pam_modutil_searchkey.c
@@ -0,0 +1,91 @@
+/*
+ * This file implements the following functions:
+ *   pam_modutil_search_key:
+ *     lookup a value for key in login.defs file or similar key value format
+ */
+
+#include "config.h"
+
+#include "pam_private.h"
+#include "pam_modutil_private.h"
+#include <security/pam_ext.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#define BUF_SIZE 8192
+
+/* lookup a value for key in login.defs file or similar key value format */
+char *
+pam_modutil_search_key(pam_handle_t *pamh UNUSED,
+		       const char *file_name,
+		       const char *key)
+{
+	FILE *fp;
+	char *buf = NULL;
+	size_t buflen = 0;
+	char *retval = NULL;
+
+	fp = fopen(file_name, "r");
+	if (NULL == fp)
+		return NULL;
+
+	while (!feof(fp)) {
+		char *tmp, *cp;
+#if defined(HAVE_GETLINE)
+		ssize_t n = getline(&buf, &buflen, fp);
+#elif defined (HAVE_GETDELIM)
+		ssize_t n = getdelim(&buf, &buflen, '\n', fp);
+#else
+		ssize_t n;
+
+		if (buf == NULL) {
+			buflen = BUF_SIZE;
+			buf = malloc(buflen);
+			if (buf == NULL) {
+				fclose(fp);
+				return NULL;
+			}
+		}
+		buf[0] = '\0';
+		if (fgets(buf, buflen - 1, fp) == NULL)
+			break;
+		else if (buf != NULL)
+			n = strlen(buf);
+		else
+			n = 0;
+#endif /* HAVE_GETLINE / HAVE_GETDELIM */
+		cp = buf;
+
+		if (n < 1)
+			break;
+		if (cp[n - 1] == '\n')
+			cp[n - 1] = '\0';
+
+		tmp = strchr(cp, '#');  /* remove comments */
+		if (tmp)
+			*tmp = '\0';
+		while (isspace((int)*cp))    /* remove spaces and tabs */
+			++cp;
+		if (*cp == '\0')        /* ignore empty lines */
+			continue;
+
+		tmp = strsep (&cp, " \t=");
+		if (cp != NULL)
+			while (isspace((int)*cp) || *cp == '=')
+				++cp;
+		else
+			cp = "";
+
+		if (strcasecmp(tmp, key) == 0) {
+			retval = strdup(cp);
+			break;
+		}
+	}
+	fclose(fp);
+
+	free(buf);
+
+	return retval;
+}
diff --git a/modules/pam_faildelay/pam_faildelay.c b/modules/pam_faildelay/pam_faildelay.c
index 7ea8f83..215074b 100644
--- a/modules/pam_faildelay/pam_faildelay.c
+++ b/modules/pam_faildelay/pam_faildelay.c
@@ -75,81 +75,10 @@
 
 #include <security/pam_modules.h>
 #include <security/pam_ext.h>
+#include <security/pam_modutil.h>
 
-
-#define BUF_SIZE 8192
 #define LOGIN_DEFS "/etc/login.defs"
 
-static char *
-search_key (const char *filename)
-{
-  FILE *fp;
-  char *buf = NULL;
-  size_t buflen = 0;
-  char *retval = NULL;
-
-  fp = fopen (filename, "r");
-  if (NULL == fp)
-    return NULL;
-
-  while (!feof (fp))
-    {
-      char *tmp, *cp;
-#if defined(HAVE_GETLINE)
-      ssize_t n = getline (&buf, &buflen, fp);
-#elif defined (HAVE_GETDELIM)
-      ssize_t n = getdelim (&buf, &buflen, '\n', fp);
-#else
-      ssize_t n;
-
-      if (buf == NULL)
-        {
-          buflen = BUF_SIZE;
-          buf = malloc (buflen);
-        }
-      buf[0] = '\0';
-      if (fgets (buf, buflen - 1, fp) == NULL)
-        break;
-      else if (buf != NULL)
-        n = strlen (buf);
-      else
-        n = 0;
-#endif /* HAVE_GETLINE / HAVE_GETDELIM */
-      cp = buf;
-
-      if (n < 1)
-        break;
-
-      tmp = strchr (cp, '#');  /* remove comments */
-      if (tmp)
-        *tmp = '\0';
-      while (isspace ((int)*cp))    /* remove spaces and tabs */
-        ++cp;
-      if (*cp == '\0')        /* ignore empty lines */
-        continue;
-
-      if (cp[strlen (cp) - 1] == '\n')
-        cp[strlen (cp) - 1] = '\0';
-
-      tmp = strsep (&cp, " \t=");
-      if (cp != NULL)
-        while (isspace ((int)*cp) || *cp == '=')
-          ++cp;
-
-      if (strcasecmp (tmp, "FAIL_DELAY") == 0)
-        {
-          retval = strdup (cp);
-          break;
-        }
-    }
-  fclose (fp);
-
-  free (buf);
-
-  return retval;
-}
-
-
 /* --- authentication management functions (only) --- */
 
 int pam_sm_authenticate(pam_handle_t *pamh, int flags UNUSED,
@@ -171,7 +100,7 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags UNUSED,
     if (delay == -1)
       {
 	char *endptr;
-	char *val = search_key (LOGIN_DEFS);
+	char *val = pam_modutil_search_key (pamh, LOGIN_DEFS, "FAIL_DELAY");
 	const char *val_orig = val;
 
 	if (val == NULL)
diff --git a/modules/pam_umask/pam_umask.c b/modules/pam_umask/pam_umask.c
index ab49064..3dcc5b1 100644
--- a/modules/pam_umask/pam_umask.c
+++ b/modules/pam_umask/pam_umask.c
@@ -56,7 +56,6 @@
 #include <security/pam_modutil.h>
 #include <security/pam_ext.h>
 
-#define BUF_SIZE 4096
 #define LOGIN_DEFS "/etc/login.defs"
 #define LOGIN_CONF "/etc/default/login"
 
@@ -86,81 +85,8 @@ parse_option (const pam_handle_t *pamh, const char *argv, options_t *options)
     pam_syslog (pamh, LOG_ERR, "Unknown option: `%s'", argv);
 }
 
-static char *
-search_key (const char *filename)
-{
-  FILE *fp;
-  char *buf = NULL;
-  size_t buflen = 0;
-  char *retval = NULL;
-
-  fp = fopen (filename, "r");
-  if (NULL == fp)
-    return NULL;
-
-  while (!feof (fp))
-    {
-      char *tmp, *cp;
-#if defined(HAVE_GETLINE)
-      ssize_t n = getline (&buf, &buflen, fp);
-#elif defined (HAVE_GETDELIM)
-      ssize_t n = getdelim (&buf, &buflen, '\n', fp);
-#else
-      ssize_t n;
-
-      if (buf == NULL)
-        {
-          buflen = BUF_SIZE;
-          buf = malloc (buflen);
-	  if (buf == NULL) {
-	    fclose (fp);
-	    return NULL;
-	  }
-        }
-      buf[0] = '\0';
-      if (fgets (buf, buflen - 1, fp) == NULL)
-	break;
-      else if (buf != NULL)
-        n = strlen (buf);
-      else
-        n = 0;
-#endif /* HAVE_GETLINE / HAVE_GETDELIM */
-      cp = buf;
-
-      if (n < 1)
-        break;
-
-      tmp = strchr (cp, '#');  /* remove comments */
-      if (tmp)
-        *tmp = '\0';
-      while (isspace ((int)*cp))    /* remove spaces and tabs */
-        ++cp;
-      if (*cp == '\0')        /* ignore empty lines */
-        continue;
-
-      if (cp[strlen (cp) - 1] == '\n')
-        cp[strlen (cp) - 1] = '\0';
-
-      tmp = strsep (&cp, " \t=");
-      if (cp != NULL)
-        while (isspace ((int)*cp) || *cp == '=')
-          ++cp;
-
-      if (strcasecmp (tmp, "UMASK") == 0)
-	{
-	  retval = strdup (cp);
-	  break;
-	}
-    }
-  fclose (fp);
-
-  free (buf);
-
-  return retval;
-}
-
 static int
-get_options (const pam_handle_t *pamh, options_t *options,
+get_options (pam_handle_t *pamh, options_t *options,
 	     int argc, const char **argv)
 {
   memset (options, 0, sizeof (options_t));
@@ -169,9 +95,9 @@ get_options (const pam_handle_t *pamh, options_t *options,
     parse_option (pamh, *argv, options);
 
   if (options->umask == NULL)
-    options->umask = search_key (LOGIN_DEFS);
+    options->umask = pam_modutil_search_key (pamh, LOGIN_DEFS, "UMASK");
   if (options->umask == NULL)
-    options->umask = search_key (LOGIN_CONF);
+    options->umask = pam_modutil_search_key (pamh, LOGIN_CONF, "UMASK");
 
   return 0;
 }
diff --git a/modules/pam_unix/support.c b/modules/pam_unix/support.c
index ea5594d..7585150 100644
--- a/modules/pam_unix/support.c
+++ b/modules/pam_unix/support.c
@@ -31,80 +31,6 @@
 #include "support.h"
 #include "passverify.h"
 
-static char *
-search_key (const char *key, const char *filename)
-{
-  FILE *fp;
-  char *buf = NULL;
-  size_t buflen = 0;
-  char *retval = NULL;
-
-  fp = fopen (filename, "r");
-  if (NULL == fp)
-    return NULL;
-
-  while (!feof (fp))
-    {
-      char *tmp, *cp;
-#if defined(HAVE_GETLINE)
-      ssize_t n = getline (&buf, &buflen, fp);
-#elif defined (HAVE_GETDELIM)
-      ssize_t n = getdelim (&buf, &buflen, '\n', fp);
-#else
-      ssize_t n;
-
-      if (buf == NULL)
-        {
-          buflen = BUF_SIZE;
-          buf = malloc (buflen);
-	  if (buf == NULL) {
-	    fclose (fp);
-	    return NULL;
-	  }
-        }
-      buf[0] = '\0';
-      if (fgets (buf, buflen - 1, fp) == NULL)
-        break;
-      else if (buf != NULL)
-        n = strlen (buf);
-      else
-        n = 0;
-#endif /* HAVE_GETLINE / HAVE_GETDELIM */
-      cp = buf;
-
-      if (n < 1)
-        break;
-
-      tmp = strchr (cp, '#');  /* remove comments */
-      if (tmp)
-        *tmp = '\0';
-      while (isspace ((int)*cp))    /* remove spaces and tabs */
-        ++cp;
-      if (*cp == '\0')        /* ignore empty lines */
-        continue;
-
-      if (cp[strlen (cp) - 1] == '\n')
-        cp[strlen (cp) - 1] = '\0';
-
-      tmp = strsep (&cp, " \t=");
-      if (cp != NULL)
-        while (isspace ((int)*cp) || *cp == '=')
-          ++cp;
-
-      if (strcasecmp (tmp, key) == 0)
-        {
-          retval = strdup (cp);
-          break;
-        }
-    }
-  fclose (fp);
-
-  free (buf);
-
-  return retval;
-}
-
-
 /* this is a front-end for module-application conversations */
 
 int _make_remark(pam_handle_t * pamh, unsigned long long ctrl,
@@ -154,7 +80,7 @@ unsigned long long _set_ctrl(pam_handle_t *pamh, int flags, int *remember,
 	}
 
 	/* preset encryption method with value from /etc/login.defs */
-	val = search_key ("ENCRYPT_METHOD", LOGIN_DEFS);
+	val = pam_modutil_search_key(pamh, LOGIN_DEFS, "ENCRYPT_METHOD");
 	if (val) {
 	  for (j = 0; j < UNIX_CTRLS_; ++j) {
 	    if (unix_args[j].token && unix_args[j].is_hash_algo
@@ -172,7 +98,7 @@ unsigned long long _set_ctrl(pam_handle_t *pamh, int flags, int *remember,
 
 	  /* read number of rounds for crypt algo */
 	  if (rounds && (on(UNIX_SHA256_PASS, ctrl) || on(UNIX_SHA512_PASS, ctrl))) {
-	    val=search_key ("SHA_CRYPT_MAX_ROUNDS", LOGIN_DEFS);
+	    val = pam_modutil_search_key(pamh, LOGIN_DEFS, "SHA_CRYPT_MAX_ROUNDS");
 
 	    if (val) {
 	      *rounds = strtol(val, NULL, 10);
