From 4f9cd362850d5c6f67ce125ca00b4e33c68c2da6 Mon Sep 17 00:00:00 2001
From: Matthew Harmsen <mharmsen@redhat.com>
Date: Wed, 22 Aug 2012 20:05:18 -0700
Subject: [PATCH] Verify symbolic links

* TRAC Ticket #301 - Need to modify init scripts to verify needed
  symlinks in an instance
---
 base/setup/scripts/functions |  308 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 307 insertions(+), 1 deletion(-)

diff --git a/base/setup/scripts/functions b/base/setup/scripts/functions
index 516bf32..579b76b 100644
--- a/base/setup/scripts/functions
+++ b/base/setup/scripts/functions
@@ -154,7 +154,7 @@ usage_systemd()
     echo -n "|try-restart"
     echo -n "|reload"
     echo -n "|status} "
-    echo -n "subsytem-type "
+    echo -n "subsystem-type "
     echo -n "[instance-name]"
     echo
     echo
@@ -738,6 +738,305 @@ display_instance_status()
     return $rv
 }
 
+fix_symlinks()
+{
+    # declare -p symlinks
+    path="${1}"
+    user="${2}"
+    group="${3}"
+
+    # process key/value pairs in the associative array
+    for key in "${!symlinks[@]}"
+    do
+        symlink="${path}/${key}"
+        if [ -e ${symlink} ]; then
+            if [ -h ${symlink} ]; then
+                target=`readlink ${symlink}`
+                if [ -e ${target} ]; then
+                    # Verify that the target to which the
+                    # symlink points is the expected target!
+                    if [ ${target} == ${symlinks[${key}]} ]; then
+                        # Check that symlink is fully resolvable!
+                        if [ ! `readlink -qe ${symlink}` ]; then
+                            # Issue an ERROR that the target to which the
+                            # symbolic link points is NOT fully resolvable!
+                            echo "ERROR:  '${symlink}' -> '${target}'"
+                            echo "        which is NOT fully resolvable!"
+                            return 1
+                        else
+                            # ALWAYS run 'chown' on '${symlink}'
+                            # NOTE:  Ignore 'chown' errors.
+                            chown -h ${user}:${group} ${symlink}
+                            # echo "SUCCESS:  '${symlink}' -> '${target}'"
+                        fi
+                    else
+                        # Issue an ERROR that the symbolic link does NOT
+                        # point to the expected target and return an error!
+                        echo "ERROR:  '${symlink}' -> '${target}'"
+                        echo "        INSTEAD of '${symlinks[${key}]}'!"
+                        return 1
+                    fi
+                else
+                    # Issue an ERROR that the target to which the
+                    # symbolic link points does NOT exist and return an error!
+                    echo "ERROR:  '${symlink}' -> '${target}'"
+                    echo "        which does NOT exist!"
+                    return 1
+                fi
+            elif [ -f ${symlink} ]; then
+                # Issue a WARNING that the administrator may have replaced
+                # the symbolic link with a file for debugging purposes.
+                echo "WARNING:  '${symlink}' exists but is NOT a symbolic link!"
+            else
+                # Issue a ERROR that the symbolic link has been replaced
+                # by something unusable (such as a directory).
+                echo "ERROR:  '${symlink}' exists but is NOT a symbolic link!"
+            fi
+        else
+            # This symbolic link does not exist; attempt to create it.
+            echo "WARNING:  '${symlink}' does NOT currently exist!"
+            echo "          Attempting to create '${symlink}' . . ."
+            target=${symlinks[${key}]}
+            if [ -e ${target} ]; then
+                # Check that the target is fully resolvable!
+                if [ ! `readlink -qe ${target}` ]; then
+                    # Issue an ERROR that the target to which the
+                    # symbolic link points is NOT fully resolvable!
+                    echo "ERROR:  '${symlink}' will NOT be created because"
+                    echo "        the '${target}' to which it must point"
+                    echo "        is NOT fully resolvable!"
+                    return 1
+                else
+                    # Attempt to create the symlink and chown it.
+                    # NOTE:  Ignore 'chown' errors.
+                    ln -s ${target} ${symlink}
+                    rv=$?
+                    if [ $rv -eq 0 ]; then
+                        chown -h ${user}:${group} ${symlink}
+                        echo "SUCCESS:  Created '${symlink}' -> '${target}'"
+                    else
+                        echo "ERROR:  Failed to create '{symlink}'!"
+                        return 1
+                    fi
+                fi
+            else
+                # Issue an ERROR that NEITHER the symbolic link NOR the
+                # target to which the symbolic link points exist and
+                # return an error!
+                echo "ERROR:  Neither '${symlink}' nor '${target}' exist!"
+                return 1
+            fi
+        fi
+    done
+
+    return 0
+}
+
+# Detect and correct any missing or incorrect symlinks.
+#
+#     Use the following command to locate PKI 'instance' symlinks:
+#
+#        find ${PKI_INSTANCE_PATH} -type l | sort | xargs file
+#
+verify_symlinks()
+{
+    declare -A apache_symlinks
+    declare -A perl_symlinks
+    declare -A base_symlinks
+    declare -A root_symlinks
+    declare -A common_jar_symlinks
+    declare -A webapps_jar_symlinks
+    declare -A systemd_symlinks
+
+    # Dogtag 9 Conditional Variables
+    if [ ${ARCHITECTURE} == "x86_64" ]; then
+        jni_dir="/usr/lib64/java"
+    else
+        jni_dir="/usr/lib/java"
+    fi
+    if   [ ${PKI_SUBSYSTEM_TYPE} == "ca" ]; then
+        pki_systemd_link="pki-cad@${PKI_INSTANCE_ID}.service"
+        pki_systemd_service="pki-cad@.service"
+    elif [ ${PKI_SUBSYSTEM_TYPE} == "kra" ]; then
+        pki_systemd_link="pki-krad@${PKI_INSTANCE_ID}.service"
+        pki_systemd_service="pki-krad@.service"
+    elif [ ${PKI_SUBSYSTEM_TYPE} == "ocsp" ]; then
+        pki_systemd_link="pki-ocspd@${PKI_INSTANCE_ID}.service"
+        pki_systemd_service="pki-ocspd@.service"
+    elif [ ${PKI_SUBSYSTEM_TYPE} == "ra" ]; then
+        pki_systemd_link="pki-rad@${PKI_INSTANCE_ID}.service"
+        pki_systemd_service="pki-rad@.service"
+    elif [ ${PKI_SUBSYSTEM_TYPE} == "tks" ]; then
+        pki_systemd_link="pki-tksd@${PKI_INSTANCE_ID}.service"
+        pki_systemd_service="pki-tksd@.service"
+    elif [ ${PKI_SUBSYSTEM_TYPE} == "tps" ]; then
+        pki_systemd_link="pki-tpsd@${PKI_INSTANCE_ID}.service"
+        pki_systemd_service="pki-tpsd@.service"
+    fi
+
+    # Dogtag 9 Symbolic Link Target Variables
+    perl_dir="/usr/share/pki/${PKI_SUBSYSTEM_TYPE}/lib/perl"
+    java_dir="/usr/share/java"
+    pki_java_dir="${java_dir}/pki"
+    # resteasy_java_dir="${java_dir}/resteasy"
+    pki_run_dir="/var/run/pki/${PKI_SUBSYSTEM_TYPE}"
+    sbin_dir="/usr/sbin"
+    systemd_dir="/lib/systemd/system"
+
+    # Dogtag 9 Symbolic Link Variables
+    pki_docroot_dir="${PKI_INSTANCE_PATH}/docroot"
+    pki_perl_dir="${PKI_INSTANCE_PATH}/lib"
+    pki_common_jar_dir="${PKI_INSTANCE_PATH}/common/lib"
+    pki_log_dir="/var/log/${PKI_INSTANCE_ID}"
+    pki_cfg_dir="/etc/${PKI_INSTANCE_ID}"
+    # pki_registry_dir="/etc/sysconfig/pki/${PKI_SUBSYSTEM_TYPE}/${PKI_INSTANCE_ID}"
+    pki_systemd_dir="/etc/systemd/system/pki-cad.target.wants"
+    pki_webapps_jar_dir="${PKI_INSTANCE_PATH}/webapps/${PKI_SUBSYSTEM_TYPE}/WEB-INF/lib"
+
+    # '${PKI_INSTANCE_PATH}' symlinks
+    apache_symlinks=(
+        [conf]=${pki_cfg_dir}
+        [logs]=${pki_log_dir}
+        [run]=${pki_run_dir})
+
+    base_symlinks=(
+        [conf]=${pki_cfg_dir}
+        [logs]=${pki_log_dir})
+
+    # '${PKI_INSTANCE_PATH}' symlinks (root:root ownership)
+    root_symlinks[${PKI_INSTANCE_ID}]=${sbin_dir}/tomcat6-sysd
+
+    # '${pki_perl_dir}' symlinks
+    perl_symlinks[perl]=${perl_dir}
+
+    # '${pki_common_jar_dir}' symlinks
+    common_jar_symlinks=(
+        [apache-commons-logging.jar]=${java_dir}/apache-commons-logging.jar
+        [jss4.jar]=${jni_dir}/jss4.jar
+        [tomcatjss.jar]=${java_dir}/tomcatjss.jar)
+
+    # '${pki_webapps_jar_dir}' symlinks
+    webapps_jar_symlinks=(
+        [apache-commons-collections.jar]=${java_dir}/apache-commons-collections.jar
+        [apache-commons-lang.jar]=${java_dir}/apache-commons-lang.jar
+        [ldapjdk.jar]=${java_dir}/ldapjdk.jar
+        [osutil.jar]=${jni_dir}/osutil.jar
+        [${PKI_INSTANCE_ID}.jar]=${pki_java_dir}/${PKI_INSTANCE_ID}.jar
+        [pki-certsrv.jar]=${pki_java_dir}/pki-certsrv.jar
+        [pki-cms.jar]=${pki_java_dir}/pki-cms.jar
+        [pki-cmsbundle.jar]=${pki_java_dir}/pki-cmsbundle.jar
+        [pki-cmscore.jar]=${pki_java_dir}/pki-cmscore.jar
+        [pki-cmsutil.jar]=${pki_java_dir}/pki-cmsutil.jar
+        [pki-nsutil.jar]=${pki_java_dir}/pki-nsutil.jar
+        [symkey.jar]=${jni_dir}/symkey.jar
+        [velocity.jar]=${java_dir}/velocity.jar
+        [xerces-j2.jar]=${java_dir}/xerces-j2.jar
+        [xml-commons-apis.jar]=${java_dir}/xml-commons-apis.jar
+        [xml-commons-resolver.jar]=${java_dir}/xml-commons-resolver.jar)
+
+    # '${pki_systemd_dir}' symlinks
+    systemd_symlinks[${pki_systemd_link}]=${systemd_dir}/${pki_systemd_service}
+
+    # Detect and correct PKI subsystem 'instance' symbolic links
+    #
+    #     (1) convert the specified associative array into a string
+    #     (2) create a new global 'symlinks' associative array from this
+    #         specified string which will be used by the "fix_symlinks()"
+    #         subroutine
+    #     (3) call "fix_symlinks()" with the appropriate arguments to
+    #         detect and correct this specified associative array;
+    #         "fix_symlinks()" returns 0 on success and 1 on failure
+    #
+    if   [ "${PKI_SUBSYSTEM_TYPE}" == "ra"   ]  ||
+         [ "${PKI_SUBSYSTEM_TYPE}" == "tps"  ]
+    then
+        # Detect and correct 'apache_symlinks'
+        apache_symlinks_string=$(declare -p apache_symlinks)
+        eval "declare -A symlinks=${apache_symlinks_string#*=}"
+        fix_symlinks ${PKI_INSTANCE_PATH} ${PKI_USER} ${PKI_GROUP}
+        rv=$?
+        if [ $rv -ne 0 ]; then
+            return $rv
+        fi
+
+        # Detect and correct 'perl_symlinks'
+        perl_symlinks_string=$(declare -p perl_symlinks)
+        eval "declare -A symlinks=${perl_symlinks_string#*=}"
+        fix_symlinks ${pki_perl_dir} ${PKI_USER} ${PKI_GROUP}
+        rv=$?
+        if [ $rv -ne 0 ]; then
+            return $rv
+        fi
+
+        if [ "${PKI_SUBSYSTEM_TYPE}" == "tps"  ]; then
+            # ALWAYS recreate this "convenience" link and 'chown' it
+            # NOTE:  Ignore 'chown' errors.
+            cd ${pki_docroot_dir} ;
+            ln -s tokendb tus ;
+            rv=$?
+            if [ $rv -eq 0 ]; then
+                chown -h ${PKI_USER}:${PKI_GROUP} tus
+                # echo "SUCCESS:  Created 'tus' -> 'tokendb'"
+            else
+                echo "ERROR:  Failed to create 'tus' -> 'tokendb' convenience"
+                echo "        symbolic link for '${PKI_INSTANCE_ID}'!"
+                return 1
+            fi
+        fi
+    elif [ "${PKI_SUBSYSTEM_TYPE}" == "ca"   ]  ||
+         [ "${PKI_SUBSYSTEM_TYPE}" == "kra"  ]  ||
+         [ "${PKI_SUBSYSTEM_TYPE}" == "ocsp" ]  ||
+         [ "${PKI_SUBSYSTEM_TYPE}" == "tks"  ]
+    then
+        # Detect and correct 'base_symlinks'
+        base_symlinks_string=$(declare -p base_symlinks)
+        eval "declare -A symlinks=${base_symlinks_string#*=}"
+        fix_symlinks ${PKI_INSTANCE_PATH} ${PKI_USER} ${PKI_GROUP}
+        rv=$?
+        if [ $rv -ne 0 ]; then
+            return $rv
+        fi
+
+        # Detect and correct 'root_symlinks'
+        root_symlinks_string=$(declare -p root_symlinks)
+        eval "declare -A symlinks=${root_symlinks_string#*=}"
+        fix_symlinks ${PKI_INSTANCE_PATH} "root" "root"
+        rv=$?
+        if [ $rv -ne 0 ]; then
+            return $rv
+        fi
+
+        # Detect and correct 'common_jar_symlinks'
+        common_jar_symlinks_string=$(declare -p common_jar_symlinks)
+        eval "declare -A symlinks=${common_jar_symlinks_string#*=}"
+        fix_symlinks ${pki_common_jar_dir} ${PKI_USER} ${PKI_GROUP}
+        rv=$?
+        if [ $rv -ne 0 ]; then
+            return $rv
+        fi
+
+        # Detect and correct 'webapps_jar_symlinks'
+        webapps_jar_symlinks_string=$(declare -p webapps_jar_symlinks)
+        eval "declare -A symlinks=${webapps_jar_symlinks_string#*=}"
+        fix_symlinks ${pki_webapps_jar_dir} ${PKI_USER} ${PKI_GROUP}
+        rv=$?
+        if [ $rv -ne 0 ]; then
+            return $rv
+        fi
+
+        # Detect and correct 'systemd_symlinks'
+        systemd_symlinks_string=$(declare -p systemd_symlinks)
+        eval "declare -A symlinks=${systemd_symlinks_string#*=}"
+        fix_symlinks ${pki_systemd_dir} ${PKI_USER} ${PKI_GROUP}
+        rv=$?
+        if [ $rv -ne 0 ]; then
+            return $rv
+        fi
+    fi
+
+    return 0
+}
+
 start_instance()
 {
     rv=0
@@ -746,6 +1045,13 @@ start_instance()
         rm -f ${RESTART_SERVER}
     fi
 
+    # Verify symbolic links (detecting and correcting them if possible)
+    verify_symlinks
+    rv=$?
+    if [ $rv -ne 0 ] ; then
+        return $rv
+    fi
+
     # Invoke the initscript for this instance
     case $PKI_SUBSYSTEM_TYPE in
         ca|kra|ocsp|tks)
-- 
1.7.10.4

