diff --git a/doc/man/pam_start.3.xml b/doc/man/pam_start.3.xml
index 50a65a4..1d544e6 100644
--- a/doc/man/pam_start.3.xml
+++ b/doc/man/pam_start.3.xml
@@ -12,6 +12,7 @@
 
   <refnamediv id="pam_start-name">
     <refname>pam_start</refname>
+    <refname>pam_start_confdir</refname>
     <refpurpose>initialization of PAM transaction</refpurpose>
   </refnamediv>
 
@@ -27,6 +28,14 @@
         <paramdef>const struct pam_conv *<parameter>pam_conversation</parameter></paramdef>
         <paramdef>pam_handle_t **<parameter>pamh</parameter></paramdef>
       </funcprototype>
+      <funcprototype>
+        <funcdef>int <function>pam_start_confdir</function></funcdef>
+        <paramdef>const char *<parameter>service_name</parameter></paramdef>
+        <paramdef>const char *<parameter>user</parameter></paramdef>
+        <paramdef>const struct pam_conv *<parameter>pam_conversation</parameter></paramdef>
+        <paramdef>const char *<parameter>confdir</parameter></paramdef>
+        <paramdef>pam_handle_t **<parameter>pamh</parameter></paramdef>
+      </funcprototype>
     </funcsynopsis>
   </refsynopsisdiv>
 
@@ -87,6 +96,17 @@
       same time as long as <function>pam_end</function> was not called on
       it before.
     </para>
+
+    <para>
+      The <function>pam_start_confdir</function> function behaves
+      like the <function>pam_start</function> function but it also
+      allows setting <emphasis>confdir</emphasis> argument with
+      a path to a directory to override the default
+      (<filename>/etc/pam.d</filename>) path for service policy
+      files. If the <emphasis>confdir</emphasis> is NULL, the function
+      works exactly the same as <function>pam_start</function>.
+    </para>
+
   </refsect1>
   <refsect1 id="pam_start-return_values">
     <title>RETURN VALUES</title>
@@ -111,7 +131,7 @@
         <term>PAM_SUCCESS</term>
         <listitem>
            <para>
-             Transaction was successful created.
+             Transaction was successfully started.
           </para>
         </listitem>
       </varlistentry>
diff --git a/libpam/Makefile.am b/libpam/Makefile.am
index 9d5c844..bd3dc5d 100644
--- a/libpam/Makefile.am
+++ b/libpam/Makefile.am
@@ -25,7 +25,7 @@ include_HEADERS = include/security/_pam_compat.h \
 noinst_HEADERS = pam_prelude.h pam_private.h pam_tokens.h \
 		pam_modutil_private.h include/pam_cc_compat.h
 
-libpam_la_LDFLAGS = -no-undefined -version-info 84:2:84
+libpam_la_LDFLAGS = -no-undefined -version-info 85:1:85
 libpam_la_LIBADD = @LIBAUDIT@ $(LIBPRELUDE_LIBS) $(ECONF_LIBS) @LIBDL@
 
 if HAVE_VERSIONING
diff --git a/libpam/include/security/pam_appl.h b/libpam/include/security/pam_appl.h
index d4172c6..cf97a49 100644
--- a/libpam/include/security/pam_appl.h
+++ b/libpam/include/security/pam_appl.h
@@ -24,6 +24,11 @@ pam_start(const char *service_name, const char *user,
 	  const struct pam_conv *pam_conversation,
 	  pam_handle_t **pamh);
 
+extern int PAM_NONNULL((1,3,5))
+pam_start_confdir(const char *service_name, const char *user,
+		  const struct pam_conv *pam_conversation,
+		  const char *confdir, pam_handle_t **pamh);
+
 extern int PAM_NONNULL((1))
 pam_end(pam_handle_t *pamh, int pam_status);
 
diff --git a/libpam/libpam.map b/libpam/libpam.map
index 74fb55b..c9690a9 100644
--- a/libpam/libpam.map
+++ b/libpam/libpam.map
@@ -77,3 +77,8 @@ LIBPAM_MODUTIL_1.3.2 {
   global:
     pam_modutil_search_key;
 } LIBPAM_MODUTIL_1.1.9;
+
+LIBPAM_1.4 {
+  global:
+    pam_start_confdir;
+} LIBPAM_1.0;
diff --git a/libpam/pam_handlers.c b/libpam/pam_handlers.c
index 8e513da..5dff58c 100644
--- a/libpam/pam_handlers.c
+++ b/libpam/pam_handlers.c
@@ -285,7 +285,7 @@ _pam_open_config_file(pam_handle_t *pamh
                                , PAM_CONFIG_DIST2_DF
 #endif
     };
-    char *p;
+    char *p = NULL;
     FILE *f;
     size_t i;
 
@@ -296,14 +296,21 @@ _pam_open_config_file(pam_handle_t *pamh
 	    pam_syslog(pamh, LOG_CRIT, "strdup failed");
 	    return PAM_BUF_ERR;
 	}
+    } else if (pamh->confdir != NULL) {
+        if (asprintf (&p, "%s/%s", pamh->confdir, service) < 0) {
+	    pam_syslog(pamh, LOG_CRIT, "asprintf failed");
+	    return PAM_BUF_ERR;
+	}
+    }
 
-	f = fopen(service, "r");
+    if (p != NULL) {
+	D(("opening %s", p));
+	f = fopen(p, "r");
 	if (f != NULL) {
 	    *path = p;
 	    *file = f;
 	    return PAM_SUCCESS;
 	}
-
 	_pam_drop(p);
 	return PAM_ABORT;
     }
@@ -313,6 +320,7 @@ _pam_open_config_file(pam_handle_t *pamh
 	    pam_syslog(pamh, LOG_CRIT, "asprintf failed");
 	    return PAM_BUF_ERR;
 	}
+
 	D(("opening %s", p));
 	f = fopen(p, "r");
 	if (f != NULL) {
@@ -438,7 +446,8 @@ int _pam_init_handlers(pam_handle_t *pamh)
 	struct stat test_d;
 
 	/* Is there a PAM_CONFIG_D directory? */
-	if ((stat(PAM_CONFIG_D, &test_d) == 0 && S_ISDIR(test_d.st_mode)) ||
+	if (pamh->confdir != NULL ||
+	    (stat(PAM_CONFIG_D, &test_d) == 0 && S_ISDIR(test_d.st_mode)) ||
 	    (stat(PAM_CONFIG_DIST_D, &test_d) == 0 && S_ISDIR(test_d.st_mode))
 #ifdef PAM_CONFIG_DIST2_D
 	    || (stat(PAM_CONFIG_DIST2_D, &test_d) == 0
@@ -471,7 +480,8 @@ int _pam_init_handlers(pam_handle_t *pamh)
 #ifdef PAM_READ_BOTH_CONFS
 		D(("checking %s", PAM_CONFIG));
 
-		if ((f = fopen(PAM_CONFIG,"r")) != NULL) {
+		if (pamh->confdir == NULL
+		    && (f = fopen(PAM_CONFIG,"r")) != NULL) {
 		    retval = _pam_parse_conf_file(pamh, f, NULL, PAM_T_ANY, 0, 1);
 		    fclose(f);
 		} else
diff --git a/libpam/pam_private.h b/libpam/pam_private.h
index ed02bb0..69d2ef4 100644
--- a/libpam/pam_private.h
+++ b/libpam/pam_private.h
@@ -178,6 +178,7 @@ struct pam_handle {
     int audit_state;             /* keep track of reported audit messages */
 #endif
     int authtok_verified;
+    char *confdir;
 };
 
 /* Values for select arg to _pam_dispatch() */
diff --git a/libpam/pam_start.c b/libpam/pam_start.c
index e27c64b..59d0622 100644
--- a/libpam/pam_start.c
+++ b/libpam/pam_start.c
@@ -15,10 +15,11 @@
 #include <string.h>
 #include <syslog.h>
 
-int pam_start (
+static int _pam_start_internal (
     const char *service_name,
     const char *user,
     const struct pam_conv *pam_conversation,
+    const char *confdir,
     pam_handle_t **pamh)
 {
     D(("called pam_start: [%s] [%s] [%p] [%p]"
@@ -80,6 +81,18 @@ int pam_start (
     } else
 	(*pamh)->user = NULL;
 
+    if (confdir) {
+	if (((*pamh)->confdir = _pam_strdup(confdir)) == NULL) {
+	    pam_syslog(*pamh, LOG_CRIT,
+		       "pam_start: _pam_strdup failed for confdir");
+	    _pam_drop((*pamh)->service_name);
+	    _pam_drop((*pamh)->user);
+	    _pam_drop(*pamh);
+	    return (PAM_BUF_ERR);
+	}
+    } else
+	(*pamh)->confdir = NULL;
+
     (*pamh)->tty = NULL;
     (*pamh)->prompt = NULL;              /* prompt for pam_get_user() */
     (*pamh)->ruser = NULL;
@@ -140,3 +153,24 @@ int pam_start (
 
     return PAM_SUCCESS;
 }
+
+int pam_start_confdir (
+    const char *service_name,
+    const char *user,
+    const struct pam_conv *pam_conversation,
+    const char *confdir,
+    pam_handle_t **pamh)
+{
+    return _pam_start_internal(service_name, user, pam_conversation,
+			       confdir, pamh);
+}
+
+int pam_start (
+    const char *service_name,
+    const char *user,
+    const struct pam_conv *pam_conversation,
+    pam_handle_t **pamh)
+{
+    return _pam_start_internal(service_name, user, pam_conversation,
+			       NULL, pamh);
+}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index c44a2ee..5b0e78d 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -12,7 +12,7 @@ TESTS = tst-pam_start tst-pam_end tst-pam_fail_delay tst-pam_open_session \
 	tst-pam_close_session tst-pam_acct_mgmt tst-pam_authenticate \
 	tst-pam_chauthtok tst-pam_setcred tst-pam_get_item tst-pam_set_item \
 	tst-pam_getenvlist tst-pam_get_user tst-pam_set_data \
-	tst-pam_mkargv
+	tst-pam_mkargv tst-pam_start_confdir
 
 check_PROGRAMS = ${TESTS} tst-dlopen
 
diff --git a/tests/confdir b/tests/confdir
new file mode 100644
index 0000000..3883c86
--- /dev/null
+++ b/tests/confdir
@@ -0,0 +1 @@
+# This is an empty pam service file for tst-pam_start_confdir
diff --git a/tests/tst-pam_start_confdir.c b/tests/tst-pam_start_confdir.c
new file mode 100644
index 0000000..e40b6e7
--- /dev/null
+++ b/tests/tst-pam_start_confdir.c
@@ -0,0 +1,99 @@
+/*
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions.  (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <security/pam_appl.h>
+
+
+int
+main (void)
+{
+  const char *service = "confdir";
+  const char *xservice = "nonexistent-service";
+  const char *user = "root";
+  const char *confdir;
+  const char *xconfdir = "/nonexistent-confdir";
+  struct pam_conv conv;
+  pam_handle_t *pamh;
+  int retval;
+
+  confdir = getenv("srcdir");
+
+  if (confdir == NULL)
+    {
+      fprintf (stderr, "Error: srcdir not set\n");
+      return 1;
+    }
+
+  /* 1: check with valid arguments */
+  retval = pam_start_confdir (service, user, &conv, confdir, &pamh);
+  if (retval != PAM_SUCCESS)
+    {
+      fprintf (stderr, "pam_start_confdir (%s, %s, &conv, %s, &pamh) returned %d\n",
+	       service, user, confdir, retval);
+      return 1;
+    }
+  else if (pamh == NULL)
+    {
+      fprintf (stderr, "pam_start_confdir (%s, %s, &conv, %s, &pamh) returned NULL for pamh\n",
+	       service, user, confdir);
+      return 1;
+    }
+
+  /* 2: check with invalid service */
+  retval = pam_start_confdir (xservice, user, &conv, confdir, &pamh);
+  if (retval == PAM_SUCCESS)
+    {
+      fprintf (stderr, "pam_start_confdir (%s, %s, &conv, %s, &pamh) incorrectly succeeded\n",
+	       xservice, user, confdir);
+      return 1;
+    }
+
+  /* 3: check with invalid confdir */
+  retval = pam_start_confdir (service, user, &conv, xconfdir, &pamh);
+  if (retval == PAM_SUCCESS)
+    {
+      fprintf (stderr, "pam_start_confdir (%s, %s, &conv, %s, &pamh) incorrectly succeeded\n",
+	       service, user, xconfdir);
+      return 1;
+    }
+
+  return 0;
+}
