From 53418442752be6aaf99462e43d6abfb94d99fabb Mon Sep 17 00:00:00 2001
From: Matthew Harmsen <mharmsen@redhat.com>
Date: Mon, 15 Jun 2015 16:22:40 -0600
Subject: [PATCH] add pkiuser to nfast group

- PKI TRAC Ticket #1415 - nCipher HSM: Add 'pkiuser' to 'nfast' group
---
 .../python/pki/server/deployment/pkiconfig.py      |  6 ++
 .../python/pki/server/deployment/pkihelper.py      | 87 ++++++++++++++++++++++
 .../python/pki/server/deployment/pkimessages.py    |  1 +
 .../server/deployment/scriptlets/initialization.py |  2 +
 4 files changed, 96 insertions(+)

diff --git a/base/server/python/pki/server/deployment/pkiconfig.py b/base/server/python/pki/server/deployment/pkiconfig.py
index 003d143..5ffed76 100644
--- a/base/server/python/pki/server/deployment/pkiconfig.py
+++ b/base/server/python/pki/server/deployment/pkiconfig.py
@@ -169,6 +169,12 @@ pki_log_name = None
 pki_log_level = None
 pki_console_log_level = None
 
+# PKI HSM Constants
+PKI_HSM_LUNASA_LIB = "/usr/safenet/lunaclient/lib/libCryptoki2_64.so"
+PKI_HSM_NCIPHER_EXE = "/opt/nfast/sbin/init.d-ncipher"
+PKI_HSM_NCIPHER_LIB = "/opt/nfast/toolkits/pkcs11/libcknfast.so"
+PKI_HSM_NCIPHER_GROUP = "nfast"
+
 # PKI Selinux Constants and parameters
 PKI_INSTANCE_SELINUX_CONTEXT = "pki_tomcat_var_lib_t"
 PKI_LOG_SELINUX_CONTEXT = "pki_tomcat_log_t"
diff --git a/base/server/python/pki/server/deployment/pkihelper.py b/base/server/python/pki/server/deployment/pkihelper.py
index 0363b08..1f4fb3e 100644
--- a/base/server/python/pki/server/deployment/pkihelper.py
+++ b/base/server/python/pki/server/deployment/pkihelper.py
@@ -307,6 +307,46 @@ class Identity:
                 raise
             return None
 
+    def group_exists(self, pki_group):
+        try:
+            _ = getgrnam(pki_group)[1]
+            return True
+        except KeyError as exc:
+            return False
+
+    def user_exists(self, pki_user):
+        try:
+            _ = getpwnam(pki_user)[1]
+            return True
+        except KeyError as exc:
+            return False
+
+    def is_user_a_member_of_group(self, pki_user, pki_group):
+        if self.group_exists(pki_group) and self.user_exists(pki_user):
+            # Check to see if pki_user is a member of this pki_group
+            if pki_user in getgrnam(pki_group)[3]:
+                return True
+            else:
+                return False
+
+    def add_user_to_group(self, pki_user, pki_group):
+        if not self.is_user_a_member_of_group(pki_user, pki_group):
+            command = ["usermod", "-a", "-G", pki_group, pki_user]
+            try:
+                # Execute this "usermod" command.
+                with open(os.devnull, "w") as fnull:
+                    subprocess.check_call(command, stdout=fnull, stderr=fnull,
+                                          close_fds=True)
+            except subprocess.CalledProcessError as exc:
+                config.pki_log.error(log.PKI_SUBPROCESS_ERROR_1, exc,
+                                     extra=config.PKI_INDENTATION_LEVEL_2)
+                raise
+            except OSError as exc:
+                config.pki_log.error(log.PKI_OSERROR_1, exc,
+                                     extra=config.PKI_INDENTATION_LEVEL_2)
+                raise
+        return
+
 
 class Namespace:
     """PKI Deployment Namespace Class"""
@@ -2152,6 +2192,52 @@ class Password:
         return token_pwd
 
 
+class HSM:
+    """PKI Deployment HSM class"""
+
+    def __init__(self, deployer):
+        self.mdict = deployer.mdict
+        self.identity = deployer.identity
+        self.file = deployer.file
+
+    def initialize(self):
+        if config.str2bool(self.mdict['pki_hsm_enable']):
+            if (self.mdict['pki_hsm_libfile'] == config.PKI_HSM_NCIPHER_LIB):
+                self.initialize_ncipher()
+        return
+
+    def initialize_ncipher(self):
+        if (self.file.exists(config.PKI_HSM_NCIPHER_EXE) and
+            self.file.exists(config.PKI_HSM_NCIPHER_LIB) and
+            self.identity.group_exists(config.PKI_HSM_NCIPHER_GROUP)):
+            # Check if 'pki_user' is a member of the default "nCipher" group
+            if not self.identity.is_user_a_member_of_group(
+                self.mdict['pki_user'], config.PKI_HSM_NCIPHER_GROUP):
+                # Make 'pki_user' a member of the default "nCipher" group
+                self.identity.add_user_to_group(self.mdict['pki_user'],
+                                                config.PKI_HSM_NCIPHER_GROUP)
+                # Restart this "nCipher" HSM
+                self.restart_ncipher()
+        return
+
+    def restart_ncipher(self, critical_failure=True):
+        try:
+            command = [config.PKI_HSM_NCIPHER_EXE, "restart"]
+
+            # Display this "nCipher" HSM command
+            config.pki_log.info(
+                log.PKIHELPER_NCIPHER_RESTART_1, ' '.join(command),
+                extra=config.PKI_INDENTATION_LEVEL_2)
+            # Execute this "nCipher" HSM command
+            subprocess.check_call(command)
+        except subprocess.CalledProcessError as exc:
+            config.pki_log.error(log.PKI_SUBPROCESS_ERROR_1, exc,
+                                 extra=config.PKI_INDENTATION_LEVEL_2)
+            if critical_failure:
+                raise
+        return
+
+
 class Certutil:
     """PKI Deployment NSS 'certutil' Class"""
 
@@ -4406,6 +4492,7 @@ class PKIDeployer:
         self.symlink = Symlink(self)
         self.war = War(self)
         self.password = Password(self)
+        self.hsm = HSM(self)
         self.certutil = Certutil(self)
         self.modutil = Modutil(self)
         self.pk12util = PK12util(self)
diff --git a/base/server/python/pki/server/deployment/pkimessages.py b/base/server/python/pki/server/deployment/pkimessages.py
index 5d357dd..dd6ba41 100644
--- a/base/server/python/pki/server/deployment/pkimessages.py
+++ b/base/server/python/pki/server/deployment/pkimessages.py
@@ -246,6 +246,7 @@ PKIHELPER_NAMESPACE_COLLISION_2 = \
     "PKI instance '%s' would produce a namespace collision with '%s'!"
 PKIHELPER_NAMESPACE_RESERVED_NAME_2 = \
     "PKI instance '%s' is already a reserved name under '%s'!"
+PKIHELPER_NCIPHER_RESTART_1 = "executing '%s'"
 PKIHELPER_NOISE_FILE_2 = \
     "generating noise file called '%s' and filling it with '%d' random bytes"
 PKIHELPER_PASSWORD_CONF_1 = "generating '%s'"
diff --git a/base/server/python/pki/server/deployment/scriptlets/initialization.py b/base/server/python/pki/server/deployment/scriptlets/initialization.py
index c209bf9c..9545c4d 100644
--- a/base/server/python/pki/server/deployment/scriptlets/initialization.py
+++ b/base/server/python/pki/server/deployment/scriptlets/initialization.py
@@ -42,6 +42,8 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
         # ALWAYS establish 'uid' and 'gid'
         deployer.identity.set_uid(deployer.mdict['pki_user'])
         deployer.identity.set_gid(deployer.mdict['pki_group'])
+        # ALWAYS initialize HSMs (when and if present)
+        deployer.hsm.initialize()
         if config.str2bool(deployer.mdict['pki_skip_installation']):
             config.pki_log.info(log.SKIP_INITIALIZATION_SPAWN_1, __name__,
                                 extra=config.PKI_INDENTATION_LEVEL_1)
-- 
1.8.3.1

