From 590f0ef90c24342609af8db0029d9ed3780974b6 Mon Sep 17 00:00:00 2001
From: Thierry Bordaz <tbordaz@redhat.com>
Date: Dec 12 2019 11:43:49 +0000
Subject: [PATCH 1/2] ignore audit-ci


---

diff --git a/src/cockpit/389-console/node_modules.mk b/src/cockpit/389-console/node_modules.mk
index e88b994..9c057f9 100644
--- a/src/cockpit/389-console/node_modules.mk
+++ b/src/cockpit/389-console/node_modules.mk
@@ -2,9 +2,9 @@ install: package.json
 	npm ci
 
 build-cockpit-plugin: webpack.config.js
-ifndef SKIP_AUDIT_CI
-	npm run audit-ci
-endif
+#ifndef SKIP_AUDIT_CI
+#	npm run audit-ci
+#endif
 	npm run build && cp -r dist cockpit_dist
 
 eslint-fix:

From 66f1abe0dee7c93bf908b3a7ce4f32b0c02559f4 Mon Sep 17 00:00:00 2001
From: Thierry Bordaz <tbordaz@redhat.com>
Date: Dec 19 2019 10:30:32 +0000
Subject: [PATCH 2/2] bz 1638875-11 : DS stores nss db password in keyring


---

diff --git a/Makefile.am b/Makefile.am
index 026687e..acb053c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -25,6 +25,7 @@ TSAN_CFLAGS = @tsan_cflags@
 UBSAN_CFLAGS = @ubsan_cflags@
 
 SYSTEMD_DEFINES = @systemd_defs@
+KEYRING_DEFINES = @keyring_defs@
 
 CMOCKA_INCLUDES = $(CMOCKA_CFLAGS)
 
@@ -147,7 +148,7 @@ AM_CFLAGS = $(DEBUG_CFLAGS) $(GCCSEC_CFLAGS) $(ASAN_CFLAGS) $(MSAN_CFLAGS) $(TSA
 AM_CXXFLAGS = $(DEBUG_CXXFLAGS) $(GCCSEC_CFLAGS) $(ASAN_CFLAGS) $(MSAN_CFLAGS) $(TSAN_CFLAGS) $(UBSAN_CFLAGS)
 # Flags for Directory Server
 # WARNING: This needs a clean up, because slap.h is a horrible mess and is publically exposed!
-DSPLUGIN_CPPFLAGS = $(DS_DEFINES) $(DS_INCLUDES) $(PATH_DEFINES) $(SYSTEMD_DEFINES) @openldap_inc@ $(NSS_CFLAGS) $(NSPR_INCLUDES) $(SYSTEMD_CFLAGS)
+DSPLUGIN_CPPFLAGS = $(DS_DEFINES) $(DS_INCLUDES) $(PATH_DEFINES) $(SYSTEMD_DEFINES) $(KEYRING_DEFINES) @openldap_inc@ $(NSS_CFLAGS) $(NSPR_INCLUDES) $(SYSTEMD_CFLAGS)
 # This should give access to internal headers only for tests!!!
 DSINTERNAL_CPPFLAGS = -I$(srcdir)/include/ldaputil
 # Flags for Datastructure Library
@@ -161,6 +162,7 @@ PROFILING_LINKS = @profiling_links@
 
 NSPR_LINK = $(NSPR_LIBS)
 NSS_LINK = $(NSS_LIBS)
+SVRCORE_LINK = @keyring_links@
 
 # with recent versions of openldap - if you link with both ldap_r and ldap, the
 # shared lib _fini for one will stomp on the other, and the program will crash
@@ -831,7 +833,8 @@ endif
 
 # For scripts that are "as is".
 dist_bin_SCRIPTS = ldap/admin/src/scripts/ds-replcheck \
-	ldap/admin/src/scripts/ds-logpipe.py
+	ldap/admin/src/scripts/ds-logpipe.py \
+	ldap/admin/src/scripts/ds-keyring.py
 
 dist_bin_SCRIPTS += ldap/admin/src/logconv.pl
 
@@ -1162,11 +1165,13 @@ libsvrcore_la_SOURCES = \
 	src/svrcore/src/std.c \
 	src/svrcore/src/systemd-ask-pass.c \
 	src/svrcore/src/std-systemd.c \
+	src/svrcore/src/keyring-ask-pass.c \
+	src/svrcore/src/std-keyring.c \
 	src/svrcore/src/user.c
 
 libsvrcore_la_LDFLAGS = $(AM_LDFLAGS)
 libsvrcore_la_CPPFLAGS = $(AM_CPPFLAGS) $(SVRCORE_INCLUDES) $(DSPLUGIN_CPPFLAGS)
-libsvrcore_la_LIBADD = $(NSS_LINK) $(NSPR_LINK)
+libsvrcore_la_LIBADD = $(NSS_LINK) $(NSPR_LINK) $(SVRCORE_LINK)
 
 #------------------------
 # libsds
@@ -2150,7 +2155,7 @@ ns_slapd_SOURCES = ldap/servers/slapd/abandon.c \
 
 ns_slapd_CPPFLAGS = $(AM_CPPFLAGS) $(DSPLUGIN_CPPFLAGS) $(SASL_CFLAGS) $(SVRCORE_INCLUDES)
 ns_slapd_LDADD = libslapd.la libldaputil.la libsvrcore.la $(LDAPSDK_LINK) $(NSS_LINK) $(LIBADD_DL) \
-	$(NSPR_LINK) $(SASL_LINK) $(LIBNSL) $(LIBSOCKET) $(THREADLIB) $(SYSTEMD_LIBS) $(EVENT_LINK)
+	$(NSPR_LINK) $(SASL_LINK) $(LIBNSL) $(LIBSOCKET) $(THREADLIB) $(SYSTEMD_LIBS) $(EVENT_LINK) $(SVRCORE_LINK)
 ns_slapd_DEPENDENCIES = libslapd.la libldaputil.la
 # We need to link ns-slapd with the C++ compiler on HP-UX since we load
 # some C++ shared libraries (such as icu).
@@ -2316,6 +2321,7 @@ fixupcmd = sed \
 	-e 's,@with_fhs_opt\@,@with_fhs_opt@,g' \
 	-e 's,@with_selinux\@,@with_selinux@,g' \
 	-e 's,@with_systemd\@,$(WITH_SYSTEMD),g' \
+	-e 's,@with_keyring\@,$(WITH_KEYRING),g' \
 	-e 's,@tmpfiles_d\@,$(tmpfiles_d),g' \
 	-e 's,@perlexec\@,@perlexec@,g' \
 	-e 's,@pythonexec\@,@pythonexec@,g' \
diff --git a/configure.ac b/configure.ac
index 982bae8..e98d608 100644
--- a/configure.ac
+++ b/configure.ac
@@ -253,6 +253,22 @@ fi
 AC_SUBST([profiling_defs])
 AC_SUBST([profiling_links])
 
+# Pull in profiling.
+AC_MSG_CHECKING(for --disable-keyring)
+AC_ARG_ENABLE(keyring, AS_HELP_STRING([--disable-keyring], [Disable keyring storage for sensitive data (default: no)]),
+              [], [ disable_keyring=no ])
+AC_MSG_RESULT($disable_keyring)
+if test "$disable_keyring" = yes ; then
+  keyring_links=""
+  keyring_defs=""
+else
+  AC_DEFINE([WITH_KEYRING], [1], [build svrcore to use keyring])
+  keyring_links="-lkeyutils"
+  keyring_defs="-DWITH_KEYRING"
+fi
+AC_SUBST([keyring_links])
+AC_SUBST([keyring_defs])
+
 # these enables are for optional or experimental features
 AC_MSG_CHECKING(for --enable-pam-passthru)
 AC_ARG_ENABLE(pam-passthru,
diff --git a/ldap/admin/src/scripts/ds-keyring.py b/ldap/admin/src/scripts/ds-keyring.py
new file mode 100755
index 0000000..db6cfe3
--- /dev/null
+++ b/ldap/admin/src/scripts/ds-keyring.py
@@ -0,0 +1,154 @@
+#!/usr/bin/env python3
+
+# Authors:
+#     Dinesh Prasanth M K <dmoluguw@redhat.com>
+#     Thierry Bordaz <tbordaz@redhat.com> for RHDS adaptations
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the Lesser GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright (C) 2019 Red Hat, Inc.
+# All rights reserved.
+
+
+"""
+Script that prompts user for password during server startup
+and store them on user's keyring
+"""
+
+import getopt
+import logging
+import os
+import subprocess
+import sys
+import re
+import pdb
+
+from lib389.keyring import Keyring
+
+logger = logging.getLogger(__name__)
+
+logging.basicConfig(format='%(levelname)s: %(message)s')
+
+# Create a instance of Keyring
+keyring = Keyring()
+
+
+def split_entries(entry):
+    return entry.split(',')
+
+
+def print_help():
+    print('Usage: ds-keyring <command> [<path_file>]')
+    print()
+    print('      <path_file>              Instance config file (i.e. dse.ldif)')
+    print('      <command>                Action to perform')
+    print()
+    print('      ds-keyring commands:')
+    print('      --get_key  <path_file>   Get value stored in keyring')
+    print('      --set_key  <path_file>   Set value stored in keyring')
+    print('      --clear                  Clear values stored in keyring')
+    print('      --help                   Show help message')
+    print()
+
+
+try:
+    opts, _ = getopt.getopt(sys.argv[1:], 's:g:ch', ['set_key=', 'get_key=', 'clear', 'help'])
+
+except getopt.GetoptError as e:
+    logger.error(e)
+    print_help()
+    sys.exit(1)
+
+for o, a in opts:
+
+    if o in ('-c', '--clear'):
+        keyring.clear_keyring()
+        sys.exit()
+
+    elif o in ('-h', '--help'):
+        print_help()
+        sys.exit()
+
+    elif o in ('-s', '--set_key'):
+        obj = re.compile('^.*/slapd-(.*)/.*$')
+        instance_name = obj.sub("\\1", a)
+        if not os.path.exists(a):
+            print('RHDS: dse.ldif does not exist for %s ' % instance_name)
+            sys.exit()
+
+        # Based on nsslapd-security parameter ('on', 'off', default 'off')
+        # If security is disabled, no need to care about NSS password
+        security_enabled = False
+        with open(a) as f:
+            datafile = f.readlines()
+            for line in datafile:
+                if 'nsslapd-security' in line.lower():
+                    security_val = line.split(':')[1].lower()
+                    security_val = re.sub(' +','', security_val)
+                    security_val = re.sub('\n','', security_val)
+                    if security_val == 'on':
+                         security_enabled = True
+                         break
+
+        if not security_enabled:
+            print('RHDS (%s): NSS password ignored - security is off' % instance_name)
+            sys.exit()
+
+        # Security is enabled
+        #
+        # If it exists a pin.txt file, this is fine. Admin accepts to use a clear text
+        # password stored in a local file.
+        #
+        # If not, then prompt the NSS password unless it already exist one in keyring
+        token = "Internal (Software) Token"
+
+        pin_file = "/etc/dirsrv/slapd-%s/pin.txt" % instance_name
+        if os.path.exists(pin_file):
+            print('RHDS (%s): Keyring is not used because it exists pin.txt' % instance_name)
+            pass
+        else:
+            # A RHDS key description looks like "Internal (Software) Token:master1:password"
+            key_name = "%s:%s:password" % (token, instance_name)
+            try:
+                key_id = keyring.get_key_id(key_name=key_name)
+                print('RHDS (%s): Initialization of NSS using a password stored in keyring' % instance_name)
+            except subprocess.CalledProcessError:
+                prompt = '[' + instance_name + '] Please provide the password for cert/key Database:'
+                cmd_ask_password = ['systemd-ask-password', prompt]
+                entered_pass = subprocess.check_output(cmd_ask_password)
+
+                keyring.put_password(key_name=key_name, password=entered_pass)
+                print('RHDS (%s): Prompted NSS password is now stored in keyring' % instance_name)
+                pass
+        sys.exit()
+
+    elif o in ('-g', '--get_key'):
+        obj = re.compile('^.*/slapd-(.*)/.*$')
+        instance_name = obj.sub("\\1", a)
+        token = "Internal (Software) Token"
+
+        # A RHDS key description looks like "Internal (Software) Token:master1:password"
+        key_name = "%s:%s:password" % (token, instance_name)
+        try:
+            key_id = keyring.get_key_id(key_name=key_name)
+            print('RHDS (%s): key desc %s ==> key ID %s' % (instance_name, key_name, key_id))
+        except subprocess.CalledProcessError:
+            print("RHDS (%s): key desc \"%s\" does not exist" % key_name)
+        sys.exit()
+
+    else:
+        logger.error('option %s not recognized', o)
+        print_help()
+        sys.exit(1)
diff --git a/ldap/servers/slapd/detach.c b/ldap/servers/slapd/detach.c
index d5c95a0..781d242 100644
--- a/ldap/servers/slapd/detach.c
+++ b/ldap/servers/slapd/detach.c
@@ -121,7 +121,7 @@ set_workingdir(void)
 }
 
 int
-detach(int slapd_exemode, int importexport_encrypt, int s_port, daemon_ports_t *ports_info)
+detach(int slapd_exemode, int importexport_encrypt, int s_port, daemon_ports_t *ports_info, char *nss_default_slot_token, char *keyring_nss_password)
 {
     int i, sd;
 
@@ -150,7 +150,7 @@ detach(int slapd_exemode, int importexport_encrypt, int s_port, daemon_ports_t *
         vattr_global_lock_create();
 
         /* call this right after the fork, but before closing stdin */
-        if (slapd_do_all_nss_ssl_init(slapd_exemode, importexport_encrypt, s_port, ports_info)) {
+        if (slapd_do_all_nss_ssl_init(slapd_exemode, importexport_encrypt, s_port, ports_info, nss_default_slot_token, keyring_nss_password)) {
             return 1;
         }
 
@@ -183,7 +183,7 @@ detach(int slapd_exemode, int importexport_encrypt, int s_port, daemon_ports_t *
          */
         vattr_global_lock_create();
 
-        if (slapd_do_all_nss_ssl_init(slapd_exemode, importexport_encrypt, s_port, ports_info)) {
+        if (slapd_do_all_nss_ssl_init(slapd_exemode, importexport_encrypt, s_port, ports_info, nss_default_slot_token, keyring_nss_password)) {
             return 1;
         }
         if (set_workingdir()) {
diff --git a/ldap/servers/slapd/main.c b/ldap/servers/slapd/main.c
index bebd3cf..83f7626 100644
--- a/ldap/servers/slapd/main.c
+++ b/ldap/servers/slapd/main.c
@@ -50,6 +50,7 @@ union semun
 #include <sys/utsname.h>
 #include <sys/systeminfo.h>
 #endif
+#define NEED_TOK_PBE /* see slap.h - defines tokPBE and ptokPBE */
 #include "slap.h"
 #include "slapi-plugin.h"
 #include "prinit.h"
@@ -59,6 +60,7 @@ union semun
 #include "getopt_ext.h"
 #include "fe.h"
 #include <nss.h>
+#include <keyutils.h>
 
 #ifdef LINUX
 /* For mallopt. Should be removed soon. */
@@ -508,11 +510,129 @@ write_start_pid_file(void)
     return -1;
 }
 
+static int
+keyring_get_password(char *configdir, char **nss_default_slot_token, char **keyring_nss_password)
+{
+    char pin_data[4096] = {0};
+    int ret = -1; /* by default it fails */
+    long keyid;
+    char *token = NULL;
+    char *serverId = NULL;
+    char key_type[] = "password";
+    char *keyring_key = NULL; /* concatenate of 'token:serverId:key_type */
+
+    if (configdir == NULL) {
+        slapi_log_err(SLAPI_LOG_ERR, "keyring_get_password", "No configdir\n");
+        goto cleanup;
+    }
+
+    if (keyring_nss_password == NULL) {
+        slapi_log_err(SLAPI_LOG_ERR, "keyring_get_password", "not possible to store retrieved password\n");
+        goto cleanup;
+    }
+    *keyring_nss_password = NULL;
+
+    if (nss_default_slot_token == NULL) {
+        slapi_log_err(SLAPI_LOG_ERR, "keyring_get_password", "not possible to store NSS default slot token\n");
+        goto cleanup;
+    }
+    *nss_default_slot_token = NULL;
+
+    /* Retrieve the default slot token: Internal (Software) Token */
+    token = slapi_ch_strdup(ptokPBE);
+    if (token == NULL) {
+        slapi_log_err(SLAPI_LOG_ERR, "keyring_get_password", "not possible to copy NSS default slot token: %s\n", ptokPBE);
+        goto cleanup;
+    }
+    /* ptokPBE contains tailing ' ' that we need to remove */
+    for (int i = (strlen(token) - 1); token[i] == ' '; i--) token[i] = '\0';
+
+    /* retrieve the serverId: /etc/dirsrv/slapd-<serverId> */
+    serverId = PL_strstr(configdir, "slapd-");
+    if (serverId) {
+        serverId = slapi_ch_strdup(serverId + PL_strlen("slapd-"));
+    } else {
+        slapi_log_err(SLAPI_LOG_ERR, "keyring_get_password", "not possible to retrieve serverID from %s (missing \"slapd-\")\n",
+                configdir);
+        goto cleanup;
+    }
+
+    /*
+     * Keyring stores key/pin pairs
+     *
+     * The format of the key is <default_slot_token>:<instance_serverId>:<key_type>
+     * for example:
+     *    <default_slot_token>: Internal (Software) Token
+     *    <instance_serverId>: master1
+     *    <key_type>: password
+     *
+     * svrcore is the framework used by DS to get the NSS password. So the pin retrieved
+     * from keyring is stored in a svrcore plugin: keyring plugin.
+     * 
+     * In svrcore the pin is stored/retrieved using the token of the NSS db default slot: 'Internal (Software) Token'.
+     * The NSS db default slot is created with this token (ptokPBE) during slapd_nss_init.
+     * When authenticating to NSS db (slapd_pk11_authenticate) it lookup the default slot
+     * and use the same token (ptokPBE) (without tailing spaces), to retrieve the pin (getPin svrcore)
+     */
+    keyring_key = slapi_ch_smprintf("%s:%s:%s", token, serverId, key_type);
+    if (keyring_key == NULL) {
+        slapi_log_err(SLAPI_LOG_ERR, "keyring_get_password", "Fail to create the keyring key (\"%s:%s:%s\")\n",
+                token, serverId, key_type);
+        goto cleanup;
+    }
+
+    /* retrieve the keyid from the key description
+     * there is no destination else it requires a Selinux
+     * module to grant Write right
+     */
+    keyid = keyctl_search(KEY_SPEC_USER_KEYRING, "user", keyring_key, 0 /* no destination */);
+    if (keyid != -1) {
+        long rc;
+
+        /* selinux permissive => EACCES */
+        rc = keyctl_read((key_serial_t) keyid, pin_data, sizeof (pin_data));
+
+        if (rc <= 0) {
+            slapi_log_err(SLAPI_LOG_ERR, "keyring_get_password", "Fail to read NSS database password pin_data=%s (%ld)\n", pin_data, rc);
+        } else if (rc > 0) {
+            slapi_log_err(SLAPI_LOG_ERR, "keyring_get_password", "pin_data=%s (%ld)\n", pin_data, rc);
+            pin_data[rc] = '\0';
+            if (pin_data[rc - 1] == '\n') {
+                /* in case of systemd-tty-ask-password-agent
+                 * the returned string ends with '\n'
+                 */
+                pin_data[rc - 1] = '\0';
+            }
+            *nss_default_slot_token = token;
+            *keyring_nss_password = slapi_ch_strdup(pin_data);
+            ret = 0;
+        }
+    } else {
+        slapi_log_err(SLAPI_LOG_INFO, "keyring_get_password", "Keyring does not contain NSS database password or access denied (rc=%ld)\n", keyid);
+    }
+
+cleanup:
+    if (token && ret) {
+        /* in case of failure (ret==-1) the token
+         * is NOT referenced by nss_default_slot_token. It can be freed
+         */
+        slapi_ch_free((void **) &token);
+    }
+    if (serverId) slapi_ch_free((void **) &serverId);
+    if (keyring_key) slapi_ch_free((void **) &keyring_key);
+
+    return ret;
+}
+
 int
 main(int argc, char **argv)
 {
     int return_value = 0;
     struct main_config mcfg = {0};
+	char *nss_default_slot_token = NULL; /* contains the "Internal (Software) Token" */
+	char *keyring_nss_password = NULL;   /* contains the password of the NSS db
+                                          * it is retrieved from keyring before detach
+                                          */
 
     /* Set a number of defaults */
     mcfg.slapd_exemode = SLAPD_EXEMODE_UNKNOWN;
@@ -786,6 +906,16 @@ main(int argc, char **argv)
         }
     }
 
+    /* check keyring only in case security was enabled */
+    if (slapdFrontendConfig->security) {
+        /* nss_default_slot_token and keyring_nss_password are retrieved before detach
+         * Then the are transmitted to the deamon that will use them to initialize security
+         */
+        if (keyring_get_password(slapdFrontendConfig->configdir, &nss_default_slot_token, &keyring_nss_password)) {
+            slapi_log_err(SLAPI_LOG_INFO, "main", "Password of NSS database not retrieved from keyring\n");
+        }
+    }
+
     /* Now, sockets are open, so we can safely change identity now */
     return_value = main_setuid(slapdFrontendConfig->localuser);
     if (0 != return_value) {
@@ -793,7 +923,6 @@ main(int argc, char **argv)
                       slapdFrontendConfig->localuser);
         exit(1);
     }
-
     /*
      * Detach ourselves from the terminal (unless running in debug mode).
      * We must detach before we start any threads since detach forks() on
@@ -801,7 +930,7 @@ main(int argc, char **argv)
      * Have to detach after ssl_init - the user may be prompted for the PIN
      * on the terminal, so it must be open.
      */
-    if (detach(mcfg.slapd_exemode, mcfg.importexport_encrypt, mcfg.s_port, &ports_info)) {
+    if (detach(mcfg.slapd_exemode, mcfg.importexport_encrypt, mcfg.s_port, &ports_info, nss_default_slot_token, keyring_nss_password)) {
         return_value = 1;
         goto cleanup;
     }
@@ -2841,7 +2970,7 @@ force_to_disable_security(const char *what, int *init_ssl, daemon_ports_t *ports
   modes (or just not detaching).
 */
 int
-slapd_do_all_nss_ssl_init(int slapd_exemode, int importexport_encrypt, int s_port, daemon_ports_t *ports_info)
+slapd_do_all_nss_ssl_init(int slapd_exemode, int importexport_encrypt, int s_port, daemon_ports_t *ports_info, char *nss_default_slot_token, char *keyring_nss_password)
 {
     /*
      * Initialise NSS once for the whole slapd process, whether SSL
@@ -2860,7 +2989,9 @@ slapd_do_all_nss_ssl_init(int slapd_exemode, int importexport_encrypt, int s_por
      * modules can assume NSS is available
      */
     if (slapd_nss_init((slapd_exemode == SLAPD_EXEMODE_SLAPD),
-                       (slapd_exemode != SLAPD_EXEMODE_REFERRAL) /* have config? */)) {
+                       (slapd_exemode != SLAPD_EXEMODE_REFERRAL) /* have config? */,
+					   nss_default_slot_token,
+					   keyring_nss_password)) {
         if (force_to_disable_security("NSS", &init_ssl, ports_info)) {
             return 1;
         }
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
index 75259e4..1627e74 100644
--- a/ldap/servers/slapd/proto-slap.h
+++ b/ldap/servers/slapd/proto-slap.h
@@ -629,7 +629,7 @@ void do_delete(Slapi_PBlock *pb);
 /*
  * detach.c
  */
-int detach(int slapd_exemode, int importexport_encrypt, int s_port, daemon_ports_t *ports_info);
+int detach(int slapd_exemode, int importexport_encrypt, int s_port, daemon_ports_t *ports_info, char *nss_default_slot_token, char *keyring_nss_password);
 void close_all_files(void);
 void raise_process_limits(void);
 
@@ -1088,7 +1088,7 @@ void do_search(Slapi_PBlock *pb);
 /*
  * ssl.c
  */
-int slapd_nss_init(int init_ssl, int config_available);
+int slapd_nss_init(int init_ssl, int config_available, char *nss_default_slot_token, char *keyring_nss_password);
 int slapd_ssl_init(void);
 int slapd_ssl_init2(PRFileDesc **fd, int startTLS);
 int slapd_security_library_is_initialized(void);
@@ -1503,7 +1503,7 @@ int32_t disk_get_info(char *dir, uint64_t *total_space, uint64_t *avail_space, u
 #if defined(hpux)
 void signal2sigaction(int s, void *a);
 #endif
-int slapd_do_all_nss_ssl_init(int slapd_exemode, int importexport_encrypt, int s_port, daemon_ports_t *ports_info);
+int slapd_do_all_nss_ssl_init(int slapd_exemode, int importexport_encrypt, int s_port, daemon_ports_t *ports_info, char *nss_default_slot_token, char *keyring_nss_password);
 
 /*
  * pagedresults.c
diff --git a/ldap/servers/slapd/ssl.c b/ldap/servers/slapd/ssl.c
index 6a07f1a..69ad198 100644
--- a/ldap/servers/slapd/ssl.c
+++ b/ldap/servers/slapd/ssl.c
@@ -62,6 +62,16 @@ static SSLVersionRange slapdNSSVersions;
    and use the same naming scheme
 */
 static char *dongle_file_name = NULL;
+static char *nss_token = NULL; /* contains the "Internal (Software) Token"
+                                * the value is set before detach()
+                                * to be used by the daemon to initialize security
+                                */
+static char *nss_password = NULL; /* contains the password of the NSS db that was
+                                   * stored in keyring.
+                                   * It was set before detach() (because of
+                                   * because of keyring access) to be used by the
+                                   * daemon to initialized security
+                                   */
 
 static int _security_library_initialized = 0;
 static int _ssl_listener_initialized = 0;
@@ -925,7 +935,7 @@ slapi_getSSLVersion_str(PRUint16 vnum, char *buf, size_t bufsize)
  * we do not need a prefix any more.
  */
 int
-slapd_nss_init(int init_ssl __attribute__((unused)), int config_available __attribute__((unused)))
+slapd_nss_init(int init_ssl __attribute__((unused)), int config_available __attribute__((unused)), char *nss_default_slot_token, char *keyring_nss_password)
 {
     SECStatus secStatus;
     PRErrorCode errorCode;
@@ -987,6 +997,12 @@ slapd_nss_init(int init_ssl __attribute__((unused)), int config_available __attr
 
     dongle_file_name = slapi_ch_smprintf("%s/pin.txt", certdir);
 
+    /* it consums the string */
+    nss_token = nss_default_slot_token;
+
+    /* it consums the string */
+    nss_password = keyring_nss_password;
+
     if (secStatus != SECSuccess) {
         errorCode = PR_GetError();
         slapd_SSL_error("NSS initialization failed (" SLAPI_COMPONENT_NAME_NSPR " error %d - %s): "
@@ -1068,12 +1084,27 @@ slapd_nss_init(int init_ssl __attribute__((unused)), int config_available __attr
     return rv;
 }
 
+/* Function used by svrcore plugins to log messages in DS logs */
+static void
+svrcore_log_err(char *fmt, char *arg1, char *arg2, char *arg3)
+{
+	slapi_log_err(SLAPI_LOG_ERR, "Security Initialization",
+                              fmt,
+			arg1 ? arg1 : "",
+			arg2 ? arg2 : "",
+			arg3 ? arg3 : "");
+}
+
 static int
 svrcore_setup(void)
 {
     PRErrorCode errorCode;
     int rv = 0;
-#ifdef WITH_SYSTEMD
+#ifdef WITH_KEYRING
+	SVRCOREStdKeyringPinObj *StdPinObj;
+    StdPinObj = (SVRCOREStdKeyringPinObj *)SVRCORE_GetRegisteredPinObj();
+
+#elif WITH_SYSTEMD
     SVRCOREStdSystemdPinObj *StdPinObj;
     StdPinObj = (SVRCOREStdSystemdPinObj *)SVRCORE_GetRegisteredPinObj();
 #else
@@ -1084,11 +1115,13 @@ svrcore_setup(void)
     if (StdPinObj) {
         return 0; /* already registered */
     }
-#ifdef WITH_SYSTEMD
+#ifdef WITH_KEYRING
+	if (SVRCORE_CreateStdKeyringPinObj(&StdPinObj, dongle_file_name, nss_token, nss_password, PR_TRUE, PR_TRUE, PR_TRUE /* Keyring */, 90, svrcore_log_err) != SVRCORE_Success) {
+#elif WITH_SYSTEMD
     if (SVRCORE_CreateStdSystemdPinObj(&StdPinObj, dongle_file_name, PR_TRUE, PR_TRUE, 90) != SVRCORE_Success) {
 #else
     if (SVRCORE_CreateStdPinObj(&StdPinObj, dongle_file_name, PR_TRUE) != SVRCORE_Success) {
-#endif
+#endif /* WITH_KEYRING */
         errorCode = PR_GetError();
         slapd_SSL_warn("Unable to create PinObj (" SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
                        errorCode, slapd_pr_strerror(errorCode));
diff --git a/rpm/389-ds-base.spec.in b/rpm/389-ds-base.spec.in
index 481d349..14a38d3 100644
--- a/rpm/389-ds-base.spec.in
+++ b/rpm/389-ds-base.spec.in
@@ -607,6 +607,7 @@ exit 0
 %{_mandir}/man1/dbscan.1.gz
 %{_bindir}/ds-replcheck
 %{_mandir}/man1/ds-replcheck.1.gz
+%{_bindir}/ds-keyring.py
 %{_bindir}/ds-logpipe.py
 %{_mandir}/man1/ds-logpipe.py.1.gz
 %{_bindir}/ldclt
diff --git a/src/lib389/lib389/keyring.py b/src/lib389/lib389/keyring.py
new file mode 100644
index 0000000..3c3bedf
--- /dev/null
+++ b/src/lib389/lib389/keyring.py
@@ -0,0 +1,108 @@
+# Authors:
+#     Dinesh Prasanth M K <dmoluguw@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the Lesser GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright (C) 2019 Red Hat, Inc.
+# All rights reserved.
+#
+
+
+"""
+Module that provides interface to access Kernel Keyring
+"""
+import subprocess
+
+
+class Keyring(object):
+    """
+    Utility class to deal with keyrings. This class is a simple wrapper
+    against the `keyutils` package. Defaults to user keyring `@u` and key
+    type `user`
+    """
+
+    def __init__(self, keyring='@u', key_type='user'):
+        self.keyring = keyring
+        self.key_type = key_type
+
+    def put_password(self, key_name, password):
+        """
+        Save a password to the keyring
+
+        :param key_name: Name of they key
+        :type key_name: str
+        :param password: Password value to be stored
+        :type password: bytearray
+        :return: Key ID, Error (if any)
+        :rtype: (bytearray, bytearray)
+        """
+
+        cmd = ['keyctl', 'padd', self.key_type, key_name, self.keyring]
+
+        p = subprocess.Popen(cmd,
+                             stdin=subprocess.PIPE,
+                             stdout=subprocess.PIPE,
+                             stderr=subprocess.STDOUT)
+
+        return p.communicate(input=password)
+
+    def get_key_id(self, key_name):
+        """
+        Retrieve key ID from the provided key name
+
+        :param key_name: Name of the key to search
+        :type key_name: str
+        :return: key_ID
+        :rtype: int
+        """
+
+        cmd = ['keyctl', 'search', self.keyring, self.key_type, key_name]
+
+        return subprocess.check_output(cmd).decode('utf-8').strip()
+
+    def get_password(self, key_name, output_format='raw'):
+        """
+        Retrieve password in the given format
+
+        :param key_name: The value of the key to be retrieved
+        :type key_name: str
+        :param output_format: Retrieval format: hex or raw (default)
+        :type output_format: str
+        :return: Value of the key in specified format
+        :rtype: str
+        """
+
+        if output_format.lower() == 'raw':
+            mode = 'pipe'
+        elif output_format.lower() == 'hex':
+            mode = 'read'
+        else:
+            raise AttributeError('output_format must be one of [\'raw\', \'hex\'].')
+
+        key_id = self.get_key_id(key_name)
+
+        cmd = ['keyctl', mode, key_id]
+
+        return subprocess.check_output(cmd).decode('utf-8')
+
+    def clear_keyring(self):
+        """
+        Clear the default keyring
+
+        :return: Return code
+        :rtype: int
+        """
+        cmd = ['keyctl', 'clear', self.keyring]
+        return subprocess.check_call(cmd)
diff --git a/src/svrcore/src/Makefile.am b/src/svrcore/src/Makefile.am
index f74dfab..1d03396 100644
--- a/src/svrcore/src/Makefile.am
+++ b/src/svrcore/src/Makefile.am
@@ -24,7 +24,9 @@ libsvrcore_la_SOURCES =	alt.c \
 			std.c \
 			systemd-ask-pass.c \
 			std-systemd.c \
+			keyring-ask-pass.c \
+			std-keyring.c \
 			user.c
 
-libsvrcore_la_LDFLAGS = -version-info 0:0:0 @NSS_LIBS@ @NSPR_LIBS@
+libsvrcore_la_LDFLAGS = -version-info 0:0:0 @NSS_LIBS@ @NSPR_LIBS@ -lkeyutils
 libsvrcore_la_CFLAGS = @NSS_CFLAGS@ @NSPR_CFLAGS@ @SYSTEMD_CFLAGS@
diff --git a/src/svrcore/src/keyring-ask-pass.c b/src/svrcore/src/keyring-ask-pass.c
new file mode 100644
index 0000000..084c6e3
--- /dev/null
+++ b/src/svrcore/src/keyring-ask-pass.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 1998 Netscape Communications Corporation.
+ * All Rights Reserved.
+ *
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+/*
+ * systemd-ask-pass.c - SVRCORE module for reading the PIN from systemd integrations.
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* For socket.h to work correct, we need to define __USE_GNU */
+#define _GNU_SOURCE 1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/uio.h>
+#include <time.h>
+#include <inttypes.h>
+#include <svrcore.h>
+#include <keyutils.h>
+
+
+#define PASS_MAX 256 * sizeof(char)
+#define NSEC_PER_USEC ((uint64_t) 1000ULL)
+#define USEC_PER_SEC ((uint64_t) 1000000ULL)
+
+struct SVRCOREKeyringPinObj
+{
+    SVRCOREPinObj base;
+	char *nss_token;
+	char *pin;
+    svrcore_log_err_t log_callback;
+    uint64_t timeout;
+};
+static const struct SVRCOREPinMethods vtable;
+
+SVRCOREError
+SVRCORE_CreateKeyringPinObj(SVRCOREKeyringPinObj **out, char *nss_token, char *nss_password, uint64_t timeout, svrcore_log_err_t log_callback)
+{
+#ifdef WITH_KEYRING
+
+    SVRCOREError err = SVRCORE_Success;
+    SVRCOREKeyringPinObj *obj = NULL;
+
+    do { // This is used like a "with" statement, to avoid a goto.
+        obj = (SVRCOREKeyringPinObj *)malloc(sizeof(SVRCOREKeyringPinObj));
+        if (obj == NULL) {
+            err = SVRCORE_NoMemory_Error;
+            break;
+        }
+
+        obj->base.methods = &vtable;
+		obj->nss_token = strdup(nss_token);
+		obj->pin = strdup(nss_password);
+        obj->log_callback = log_callback;
+        if (timeout == 0) {
+            obj->timeout = 90;
+        } else {
+            obj->timeout = timeout;
+        }
+
+    } while (0);
+
+    // If error, destrop it, and return err
+    if (err != SVRCORE_Success) {
+        SVRCORE_DestroyKeyringPinObj(obj);
+        obj = NULL;
+    }
+
+    *out = obj;
+    return err;
+#else // keyring
+    return SVRCORE_MissingFeature;
+#endif // keyring
+}
+
+static char *
+getPin(SVRCOREPinObj *obj, const char *token, PRBool retry)
+{
+    char *pin = NULL;
+    SVRCOREKeyringPinObj *kobj = (SVRCOREKeyringPinObj *) obj;
+    int max_retry = 10; /* used to validate the retrieved password */
+
+
+#ifdef WITH_KEYRING
+    if (!strcmp(token, kobj->nss_token)) {
+        pin = strdup(kobj->pin);
+    }
+
+    /* Attempt to create a Pin Storage object.  This checks the
+     * password.
+     */
+    do {
+        SVRCOREPk11PinStore *store;
+        SVRCOREError err;
+
+        err = SVRCORE_CreatePk11PinStore(&store, token, pin);
+        SVRCORE_DestroyPk11PinStore(store);
+
+        if (err == SVRCORE_Success) {
+            break;
+        } else if (err == SVRCORE_IncorrectPassword_Error) {
+            /* retry*/
+            max_retry--;
+        } else {
+            break;
+        }
+
+    } while(max_retry);
+
+    if ((max_retry == 0) && kobj->log_callback) {
+        /* The password retrieved from keyring is invalid
+         * It should be changed
+         */
+        kobj->log_callback("Keyring fails to check the NSS password: \"%s\"\n",
+					pin, 0, 0);
+        kobj->log_callback("You may try: keyctl search @u user \"%s\" --> <key_id>\n",
+					token, 0, 0);
+        kobj->log_callback("Then: keyctl unlink <key_id> @u\n",
+					0, 0, 0);
+        pin = NULL;
+    }
+
+    return pin;
+#else // Keyring
+    return NULL;
+#endif // Keyring
+}
+
+void
+SVRCORE_DestroyKeyringPinObj(SVRCOREKeyringPinObj *obj)
+{
+#ifdef WITH_KEYRING
+    if (obj) {
+		if (obj->nss_token) free(obj->nss_token);
+		if (obj->pin) free(obj->pin);
+        free(obj);
+    }
+#endif // Keyring
+}
+
+static void
+destroyObject(SVRCOREPinObj *obj)
+{
+    SVRCORE_DestroyKeyringPinObj((SVRCOREKeyringPinObj*)obj);
+}
+
+static const SVRCOREPinMethods vtable =
+{ 0, 0, destroyObject, getPin };
+
diff --git a/src/svrcore/src/std-keyring.c b/src/svrcore/src/std-keyring.c
new file mode 100644
index 0000000..80e4ffc
--- /dev/null
+++ b/src/svrcore/src/std-keyring.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 1998 Netscape Communications Corporation.
+ * All Rights Reserved.
+ *
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+/*
+ * std-keyring.c - Extension of the STD module to integrate file, tty and keyring
+ */
+
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <svrcore.h>
+#include <unistd.h>
+
+
+/* ------------------------------------------------------------ */
+/*
+ * SVRCOREStdKeyringPinObj implementation
+ */
+struct SVRCOREStdKeyringPinObj
+{
+    SVRCOREPinObj base;
+    SVRCORECachedPinObj *cache;
+    SVRCOREAltPinObj *alt;
+    SVRCOREFilePinObj *file;
+    SVRCOREUserPinObj *user;
+    SVRCOREAltPinObj *systemdalt;
+    SVRCORESystemdPinObj *systemd;
+	SVRCOREAltPinObj *keyringalt;
+	SVRCOREKeyringPinObj *keyring;
+	char *keyring_nss_token;
+	char *keyring_nss_password;
+	svrcore_log_err_t log_callback;
+
+    SVRCOREPinObj *top;
+};
+static const SVRCOREPinMethods vtable;
+
+/* ------------------------------------------------------------ */
+SVRCOREError
+SVRCORE_CreateStdKeyringPinObj(
+    SVRCOREStdKeyringPinObj **out,
+    const char *filename,  const char *nss_token, const char *nss_password, PRBool cachePINs,
+    PRBool systemdPINs, PRBool keyringPINs, uint64_t timeout, svrcore_log_err_t log_callback)
+{
+
+    SVRCOREError err = SVRCORE_Success;
+    SVRCOREStdKeyringPinObj *obj = 0;
+
+    do {
+        SVRCOREPinObj *top;
+
+        obj = (SVRCOREStdKeyringPinObj *)malloc(sizeof (SVRCOREStdKeyringPinObj));
+        if (!obj) { err = SVRCORE_NoMemory_Error; break; }
+
+        obj->base.methods = &vtable;
+
+        obj->cache = 0;
+        obj->alt = 0;
+        obj->file = 0;
+        obj->user = 0;
+        obj->systemdalt = 0;
+        obj->systemd = 0;
+		obj->keyringalt = 0;
+		obj->keyring = 0;
+		obj->keyring_nss_token = 0;
+		obj->keyring_nss_password = 0;
+		obj->log_callback = log_callback;
+
+        err = SVRCORE_CreateUserPinObj(&obj->user);
+        if (err) {
+            break;
+        }
+        // Automatically detect if we are on an interactive session or not
+
+#ifdef DEBUG
+        printf("std-keyring:create() -> interactive %d \n", isatty(fileno(stdin)));
+#endif
+
+        // During testing, we want to disable this sometimes ...
+        // SVRCORE_SetUserPinInteractive(obj->user, PR_FALSE);
+        SVRCORE_SetUserPinInteractive(obj->user, isatty(fileno(stdin)));
+
+        top = (SVRCOREPinObj*)obj->user;
+
+        /* If filename is provided, splice it into the chain */
+        if (filename)
+        {
+            err = SVRCORE_CreateFilePinObj(&obj->file, filename);
+            if (err) {
+                break;
+            }
+
+            err = SVRCORE_CreateAltPinObj(&obj->alt,
+                  (SVRCOREPinObj*)obj->file, top);
+            if (err) {
+                break;
+            }
+
+            top = (SVRCOREPinObj*)obj->alt;
+        }
+
+#ifdef WITH_SYSTEMD
+        if (systemdPINs) {
+            err = SVRCORE_CreateSystemdPinObj(&obj->systemd, timeout);
+            if (err) {
+                break;
+            }
+            // Now make a second "alt" object. If pin and user fail, we call systemd
+#ifdef DEBUG
+            printf("std-keyring:create() -> Creating systemd alt pin object \n");
+#endif
+            err = SVRCORE_CreateAltPinObj(&obj->systemdalt,
+                    top, (SVRCOREPinObj*)obj->systemd);
+            if (err) {
+                break;
+            }
+            top = (SVRCOREPinObj *)obj->systemdalt;
+        }
+#endif /* WITH_SYTEMD */
+
+		if (keyringPINs && nss_token && nss_password) {
+            /* Use of nss_token/nss_password (key/value pair) retrieved in keyring */
+			if (nss_token) {
+				obj->keyring_nss_token = strdup(nss_token);
+			}
+			if (nss_password) {
+				obj->keyring_nss_password = strdup(nss_password);
+			}
+			if (log_callback) log_callback("Keyring enabled: NSS password registered for slot token \"%s\"\n",
+					obj->keyring_nss_token, 0, 0);
+#ifdef DEBUG
+            printf("std-keyring:create() -> Creating keyring pin object \n");
+#endif
+            err = SVRCORE_CreateKeyringPinObj(&obj->keyring, obj->keyring_nss_token, obj->keyring_nss_password, timeout, log_callback);
+            if (err) {
+                break;
+            }
+            // Now make a second "alt" object. if keyring fails let's try in that order file/user/systemd
+            err = SVRCORE_CreateAltPinObj(&obj->keyringalt,
+                    (SVRCOREPinObj*)obj->keyring, top);
+            if (err) {
+                break;
+            }
+            top = (SVRCOREPinObj *)obj->keyringalt;
+        }
+
+        /* Create cache object if requested */
+        if (cachePINs)
+        {
+            err = SVRCORE_CreateCachedPinObj(&obj->cache, top);
+            if (err) {
+                break;
+            }
+
+            top = (SVRCOREPinObj*)obj->cache;
+        }
+
+        obj->top = top;
+    } while(0);
+
+    *out = obj;
+
+    if (err != SVRCORE_Success)
+    {
+        SVRCORE_DestroyStdKeyringPinObj(obj);
+        *out = NULL;
+    }
+
+    return err;
+}
+
+void
+SVRCORE_DestroyStdKeyringPinObj(
+  SVRCOREStdKeyringPinObj *obj)
+{
+#ifdef WITH_KEYRING
+    if (!obj) return;
+
+    if (obj->user) SVRCORE_DestroyUserPinObj(obj->user);
+    if (obj->file) SVRCORE_DestroyFilePinObj(obj->file);
+    if (obj->alt) SVRCORE_DestroyAltPinObj(obj->alt);
+    if (obj->cache) SVRCORE_DestroyCachedPinObj(obj->cache);
+    if (obj->systemd) SVRCORE_DestroySystemdPinObj(obj->systemd);
+    if (obj->systemdalt) SVRCORE_DestroyAltPinObj(obj->systemdalt);
+	if (obj->keyring) SVRCORE_DestroyKeyringPinObj(obj->keyring);
+	if (obj->keyringalt) SVRCORE_DestroyAltPinObj(obj->keyringalt);
+	if (obj->keyring_nss_token) free(obj->keyring_nss_token);
+	if (obj->keyring_nss_password) free(obj->keyring_nss_password);
+
+    free(obj);
+#endif // Keyring
+}
+
+/* ------------------------------------------------------------ */
+
+void
+SVRCORE_SetStdKeyringPinInteractive(SVRCOREStdKeyringPinObj *obj, PRBool i)
+{
+#ifdef WITH_KEYRING
+    SVRCORE_SetUserPinInteractive(obj->user, i);
+#endif // Systemd
+}
+
+/* ------------------------------------------------------------ */
+/*
+ * SVRCORE_StdKeyringPinGetPin
+ */
+SVRCOREError
+SVRCORE_StdKeyringPinGetPin(char **pin, SVRCOREStdKeyringPinObj *obj,
+  const char *nss_password)
+{
+#ifdef WITH_KEYRING
+#ifdef DEBUG
+    printf("std-keyring:stdkeyring-getpin() -> starting \n");
+#endif
+    /* Make sure caching is turned on */
+    if (!obj->cache)
+    {
+        *pin = 0;
+        return SVRCORE_NoSuchToken_Error;
+    }
+
+    return SVRCORE_CachedPinGetPin(pin, obj->cache, nss_password);
+#else // keyring
+    return SVRCORE_MissingFeature;
+#endif // keyring
+}
+
+/* ------------------------------------------------------------ */
+/*
+ * vtable methods
+ */
+static void
+destroyObject(SVRCOREPinObj *obj)
+{
+    SVRCORE_DestroyStdKeyringPinObj((SVRCOREStdKeyringPinObj*)obj);
+}
+
+static char *
+getPin(SVRCOREPinObj *pinObj, const char *tokenName, PRBool retry)
+{
+	char *pin = NULL;
+	char *fullToken;
+#ifdef DEBUG
+    printf("std-keyring:getpin() -> starting \n");
+#endif
+    SVRCOREStdKeyringPinObj *obj = (SVRCOREStdKeyringPinObj*)pinObj;
+	pin = SVRCORE_GetPin(obj->top, tokenName, retry);
+
+	return pin;
+}
+
+/*
+ * VTable
+ */
+static const SVRCOREPinMethods vtable =
+{ 0, 0, destroyObject, getPin };
+
diff --git a/src/svrcore/src/svrcore.h b/src/svrcore/src/svrcore.h
index ec91174..a13abc8 100644
--- a/src/svrcore/src/svrcore.h
+++ b/src/svrcore/src/svrcore.h
@@ -263,6 +263,37 @@ void
 SVRCORE_DestroyStdSystemdPinObj(SVRCOREStdSystemdPinObj *obj);
 
 /* ------------------------------------------------------------ */
+typedef void (*svrcore_log_err_t)(char *fmt, char *arg1, char *arg2, char *arg3);
+
+
+typedef struct SVRCOREKeyringPinObj SVRCOREKeyringPinObj;
+
+SVRCOREError
+SVRCORE_CreateKeyringPinObj(SVRCOREKeyringPinObj **out, char *nss_token, char *nss_password, uint64_t timeout, svrcore_log_err_t log_callback);
+
+void
+SVRCORE_DestroyKeyringPinObj(SVRCOREKeyringPinObj *obj);
+
+typedef struct SVRCOREStdKeyringPinObj SVRCOREStdKeyringPinObj;
+typedef void (*svrcore_log_err_t)(char *fmt, char *arg1, char *arg2, char *arg3);
+
+SVRCOREError
+SVRCORE_CreateStdKeyringPinObj(
+    SVRCOREStdKeyringPinObj **out,
+    const char *filename,  const char *nss_token, const char *nss_password, PRBool cachePINs,
+    PRBool systemdPINs, PRBool keyringPINs, uint64_t timeout, svrcore_log_err_t log_callback);
+
+void
+SVRCORE_SetStdKeyringPinInteractive(SVRCOREStdKeyringPinObj *obj, PRBool i);
+
+SVRCOREError
+SVRCORE_StdKeyringPinGetPin(char **pin, SVRCOREStdKeyringPinObj *obj,
+  const char *nss_password);
+
+void
+SVRCORE_DestroyStdKeyringPinObj(
+  SVRCOREStdKeyringPinObj *obj);
+/* ------------------------------------------------------------ */
 /*
  * Implements SVRCORESecurePinStore interface
  */
diff --git a/wrappers/ds_systemd_ask_password_acl.in b/wrappers/ds_systemd_ask_password_acl.in
index 59bffc5..af335ae 100644
--- a/wrappers/ds_systemd_ask_password_acl.in
+++ b/wrappers/ds_systemd_ask_password_acl.in
@@ -14,21 +14,28 @@
 # If we don't do this, we can't prompt for the password!
 # If you want this script to go away, fix the bugzilla so we don't need it!
 
+PHASE=${2:-pre}
 # Make sure we have the path to the dse.ldif
 if [ -z $1 ]
 then
-    echo "usage: ${0} /etc/dirsrv/slapd-<instance>/dse.ldif"
+    echo "usage: ${0} /etc/dirsrv/slapd-<instance>/dse.ldif [pre|post]"
     exit 1
 fi
 
 # Grep the user out
 
 DS_USER=`grep 'nsslapd-localuser: ' $1 | awk '{print $2}'`
+if [ "${PHASE}" = "pre" ]
+then
+        ACTION="-m u:${DS_USER}:rwx"
+else
+        ACTION="-x u:${DS_USER}"
+fi
 
 # Now apply the acl
 
 if [ -d /var/run/systemd/ask-password ]
 then
-    setfacl -m u:${DS_USER}:rwx /var/run/systemd/ask-password
+    echo setfacl ${ACTION} /var/run/systemd/ask-password
 fi
 
diff --git a/wrappers/systemd.template.service.in b/wrappers/systemd.template.service.in
index 3f2f23a..a5c201e 100644
--- a/wrappers/systemd.template.service.in
+++ b/wrappers/systemd.template.service.in
@@ -13,8 +13,11 @@ NotifyAccess=all
 EnvironmentFile=-@initconfigdir@/@package_name@
 EnvironmentFile=-@initconfigdir@/@package_name@-%i
 PIDFile=/run/@package_name@/slapd-%i.pid
-ExecStartPre=@libexecdir@/ds_systemd_ask_password_acl @instconfigdir@/slapd-%i/dse.ldif
+ExecStartPre=@libexecdir@/ds_systemd_ask_password_acl  @instconfigdir@/slapd-%i/dse.ldif pre
+ExecStartPost=@libexecdir@/ds_systemd_ask_password_acl @instconfigdir@/slapd-%i/dse.ldif post
+ExecStartPre=/usr/bin/ds-keyring.py --set_key @instconfigdir@/slapd-%i/dse.ldif
 ExecStart=@sbindir@/ns-slapd -D @instconfigdir@/slapd-%i -i /run/@package_name@/slapd-%i.pid
+KeyringMode=shared
 
 [Install]
 WantedBy=multi-user.target

