#!/bin/bash -X

# From "http://fedoraproject.org/wiki/FCNewInit/Initscripts":
#
# Status Exit Codes
#
#  0 program is running or service is OK
#  1 program is dead and /var/run pid file exists
#  2 program is dead and /var/lock lock file exists
#  3 program is not running
#  4 program or service status is unknown
#  5-99 reserved for future LSB use
#  100-149 reserved for distribution use
#  150-199 reserved for application use
#  200-254 reserved
#
# Non-Status Exit Codes
#
#  0 action was successful
#  1 generic or unspecified error (current practice)
#  2 invalid or excess argument(s)
#  3 unimplemented feature (for example, "reload")
#  4 user had insufficient privilege
#  5 program is not installed
#  6 program is not configured
#  7 program is not running
#  8-99    reserved for future LSB use
#  100-149 reserved for distribution use
#  150-199 reserved for application use
#  200-254 reserved
#

# load default, system-wide, and user-specific PKI configuration and
# set NSS_DEFAULT_DB_TYPE.
. /usr/share/pki/scripts/config

default_error=0

if [ -f /etc/debian_version ]; then
    debian=true
    SYSCONFIG_PKI=/etc/dogtag
else
    debian=false
    SYSCONFIG_PKI=/etc/sysconfig/pki
fi

case $command in
    start)
        # 1 generic or unspecified error (current practice)
        default_error=1
        ;;
    status)
        # 4 program or service status is unknown
        default_error=4
        ;;
    *)
        # 2 invalid argument(s)
        default_error=2
        ;;
esac

# Enable nullglob, if set then shell pattern globs which do not match any
# file returns the empty string rather than the unmodified glob pattern.
shopt -s nullglob

OS=`uname -s`
ARCHITECTURE=`arch`

# Check to insure that this script's original invocation directory
# has not been deleted!

# shellcheck disable=SC2034
CWD=`/bin/pwd > /dev/null 2>&1`
if [ $? -ne 0 ] ; then
    echo "Cannot invoke '$PROG_NAME' from non-existent directory!"
    exit ${default_error}
fi


PKI_REGISTRY_ENTRY="${PKI_REGISTRY}/${pki_instance_id}/${pki_instance_id}"
PKI_SUBSYSTEMS=""

usage()
{
    echo -n "Usage: /usr/bin/pkidaemon "
    echo -n "<start"
    echo -n "|status> "
    echo -n "<instance-name>"
    echo
    echo
}

list_instances()
{
    echo
    for INSTANCE in $SYSCONFIG_PKI/tomcat/*; do
        if [ -d "${INSTANCE}" ] ; then
            instance_name=`basename ${INSTANCE}`
            echo "    $instance_name"
        fi
    done
    echo
}

get_subsystems()
{
    # Re-initialize PKI_SUBSYSTEMS for each instance
    PKI_SUBSYSTEMS=""
    for SUBSYSTEM in ca kra ocsp tks tps; do
        if [ -d ${PKI_INSTANCE_PATH}/conf/${SUBSYSTEM} ]; then
            if [ '${PKI_SUBSYSTEMS}' == "" ] ; then
                PKI_SUBSYSTEMS="${SUBSYSTEM}"
            else
                PKI_SUBSYSTEMS="${PKI_SUBSYSTEMS} ${SUBSYSTEM}"
            fi
        fi
    done
}

# Check arguments
if [ $# -lt 2 ] ; then
    #     [insufficient arguments]
    echo "$PROG_NAME:  Insufficient arguments!"
    echo
    usage
    echo "where valid instance names include:"
    list_instances
    exit 3
elif [ ${default_error} -eq 2 ] ; then
    # 2 invalid argument
    echo "$PROG_NAME:  Invalid arguments!"
    echo
    usage
    echo "where valid instance names include:"
    list_instances
    exit 2
elif [ $# -gt 2 ] ; then
    echo "$PROG_NAME:  Excess arguments!"
    echo
    usage
    echo "where valid instance names include:"
    list_instances
    if [ "${command}" != "status" ]; then
        # 2 excess arguments
        exit 2
    else
        # 4 program or service status is unknown
        exit 4
    fi
fi

if [ ! -f ${PKI_REGISTRY_ENTRY} ]; then
    echo -n "${pki_instance_id} is an invalid instance"
    echo

    if [ "${command}" != "status" ]; then
        # 5 program is not installed
        exit 5
    else
        # 4 program or service status is unknown
        exit 4
    fi
fi

check_pki_configuration_status()
{
    rv=0
    for SUBSYSTEM in ca kra ocsp tks tps; do
        if [ -d ${PKI_INSTANCE_PATH}/conf/${SUBSYSTEM} ]; then
            rv=`grep -c ^preop ${PKI_INSTANCE_PATH}/conf/${SUBSYSTEM}/CS.cfg`
            rv=`expr ${rv} + 0`
        fi
    done
    if [ $rv -ne 0 ] ; then
        echo "    '${PKI_INSTANCE_NAME}' must still be CONFIGURED!"
        echo "    (see /var/log/${PKI_INSTANCE_NAME}-install.log)"
        if [ "${command}" != "status" ]; then
            # 6 program is not configured
            rv=6
        else
            # 4 program or service status is unknown
            rv=4
        fi
    elif [ -f ${RESTART_SERVER} ] ; then
        echo -n "    Although '${PKI_INSTANCE_NAME}' has been CONFIGURED, "
        echo -n "it must still be RESTARTED!"
        echo
        if [ "${command}" != "status" ]; then
            # 1 generic or unspecified error (current practice)
            rv=1
        else
            # 4 program or service status is unknown
            rv=4
        fi
    fi

    return $rv
}

get_pki_status_definitions()
{
    PKI_SERVER_XML_CONF=${PKI_INSTANCE_PATH}/conf/server.xml
    get_pki_status_definitions_tomcat
    return $?
}

get_pki_status_definitions_tomcat()
{
    # establish well-known strings
    begin_pki_status_comment="<!-- DO NOT REMOVE - Begin PKI Status Definitions -->"
    begin_ca_status_comment="<!-- CA Status Definitions -->"
    begin_kra_status_comment="<!-- KRA Status Definitions -->"
    begin_ocsp_status_comment="<!-- OCSP Status Definitions -->"
    begin_tks_status_comment="<!-- TKS Status Definitions -->"
    begin_tps_status_comment="<!-- TPS Status Definitions -->"
    end_pki_status_comment="<!-- Begin DO NOT REMOVE - End PKI Status Definitions -->"
    total_ports=0
    unsecure_port_statement="Unsecure Port"
    secure_agent_port_statement="Secure Agent Port"
    secure_ee_port_statement="Secure EE Port"
    secure_ee_client_auth_port_statement="EE Client Auth Port"
    secure_admin_port_statement="Secure Admin Port"
    pki_console_port_statement="PKI Console Port"
    unsecure_url_statement="Unsecure URL"
    secure_url_statement="Secure URL"
    secure_agent_url_statement="Secure Agent URL"
    secure_ee_url_statement="Secure EE URL"
    secure_ee_client_auth_url_statement="EE Client Auth URL"
    secure_admin_url_statement="Secure Admin URL"
    pki_console_command_statement="PKI Console Command"
    tomcat_port_statement="Tomcat Port"
    unsecure_phone_home_statement="Unsecure PHONE HOME"
    secure_phone_home_statement="Secure PHONE HOME"

    # initialize looping variables
    pki_status_comment_found=0
    display_pki_ca_status_banner=0
    display_pki_kra_status_banner=0
    display_pki_ocsp_status_banner=0
    display_pki_tks_status_banner=0
    display_pki_tps_status_banner=0
    process_pki_ca_status=0
    process_pki_kra_status=0
    process_pki_ocsp_status=0
    process_pki_tks_status=0
    process_pki_tps_status=0

    # first check to see that an instance-specific "server.xml" file exists
    if [ ! -f ${PKI_SERVER_XML_CONF} ] ; then
        echo "File '${PKI_SERVER_XML_CONF}' does not exist!"
        exit ${default_error}
    fi

    # identify all PKI subsystems present within this PKI instance
    if [ -e ${PKI_INSTANCE_PATH}/ca ]; then
        display_pki_ca_status_banner=1
    fi
    if [ -e ${PKI_INSTANCE_PATH}/kra ]; then
        display_pki_kra_status_banner=1
    fi
    if [ -e ${PKI_INSTANCE_PATH}/ocsp ]; then
        display_pki_ocsp_status_banner=1
    fi
    if [ -e ${PKI_INSTANCE_PATH}/tks ]; then
        display_pki_tks_status_banner=1
    fi
    if [ -e ${PKI_INSTANCE_PATH}/tps ]; then
        display_pki_tps_status_banner=1
    fi

    # read this instance-specific "server.xml" file line-by-line
    # to obtain the current PKI Status Definitions
    exec < ${PKI_SERVER_XML_CONF}
    while read line; do
        # first look for the well-known end PKI Status comment
        # (to turn off processing)
        if [ "$line" == "$end_pki_status_comment" ] ; then
            # always turn off processing TPS status at this point
            process_pki_tps_status=0
            pki_status_comment_found=0
            break;
        fi

        # then look for the well-known begin PKI Status comment
        # (to turn on processing)
        if [ "$line" == "$begin_pki_status_comment" ] ; then
            pki_status_comment_found=1
        fi

        # once the well-known begin PKI Status comment has been found,
        # begin processing to obtain all of the PKI Status Definitions
        if [ $pki_status_comment_found -eq 1 ] ; then
            head=`echo "$line" | sed -e 's/^\([^=]*\)[ \t]*= .*$/\1/' -e 's/[ \t]*$//'`
            if   [ "$line" == "$begin_ca_status_comment" ] ; then
                 if [ $display_pki_ca_status_banner -eq 1 ] ; then
                     # print CA Status Definition banner
                     echo
                     echo "    [CA Status Definitions]"
                     # turn on processing CA status at this point
                     process_pki_ca_status=1
                 fi
            elif [ "$line" == "$begin_kra_status_comment" ] ; then
                 # always turn off processing CA status at this point
                 process_pki_ca_status=0
                 if [ $display_pki_kra_status_banner -eq 1 ] ; then
                     # print KRA Status Definition banner
                     echo
                     echo "    [KRA Status Definitions]"
                     # turn on processing KRA status at this point
                     process_pki_kra_status=1
                 fi
            elif [ "$line" == "$begin_ocsp_status_comment" ] ; then
                 # always turn off processing KRA status at this point
                 process_pki_kra_status=0
                 if [ $display_pki_ocsp_status_banner -eq 1 ] ; then
                     # print OCSP Status Definition banner
                     echo
                     echo "    [OCSP Status Definitions]"
                     # turn on processing OCSP status at this point
                     process_pki_ocsp_status=1
                 fi
            elif [ "$line" == "$begin_tks_status_comment" ] ; then
                 # always turn off processing OCSP status at this point
                 process_pki_ocsp_status=0
                 if [ $display_pki_tks_status_banner -eq 1 ] ; then
                     # print TKS Status Definition banner
                     echo
                     echo "    [TKS Status Definitions]"
                     # turn on processing TKS status at this point
                     process_pki_tks_status=1
                 fi
            elif [ "$line" == "$begin_tps_status_comment" ] ; then
                 # always turn off processing TKS status at this point
                 process_pki_tks_status=0
                 if [ $display_pki_tps_status_banner -eq 1 ] ; then
                     # print TPS Status Definition banner
                     echo
                     echo "    [TPS Status Definitions]"
                     # turn on processing TPS status at this point
                     process_pki_tps_status=1
                 fi
            elif [ $process_pki_ca_status -eq 1 ]    ||
                 [ $process_pki_kra_status -eq 1 ]   ||
                 [ $process_pki_ocsp_status -eq 1 ]  ||
                 [ $process_pki_tks_status -eq 1 ]   ||
                 [ $process_pki_tps_status -eq 1 ] ; then
                 # look for a PKI Status Definition and print it
                 if [ "$head" == "$unsecure_port_statement"     ]          ||
                    [ "$head" == "$secure_agent_port_statement" ]          ||
                    [ "$head" == "$secure_ee_port_statement"    ]          ||
                    [ "$head" == "$secure_admin_port_statement" ]          ||
                    [ "$head" == "$secure_ee_client_auth_port_statement" ] ||
                    [ "$head" == "$pki_console_port_statement"  ]          ||
                    [ "$head" == "$unsecure_url_statement"      ]          ||
                    [ "$head" == "$secure_url_statement"        ]          ||
                    [ "$head" == "$secure_agent_url_statement"  ]          ||
                    [ "$head" == "$secure_ee_url_statement"     ]          ||
                    [ "$head" == "$secure_admin_url_statement"  ]          ||
                    [ "$head" == "$secure_ee_client_auth_url_statement" ]  ||
                    [ "$head" == "$pki_console_command_statement"  ]       ||
                    [ "$head" == "$unsecure_phone_home_statement"  ]       ||
                    [ "$head" == "$secure_phone_home_statement"    ]       ||
                    [ "$head" == "$tomcat_port_statement"       ] ; then
                     echo "    $line"
                     total_ports=`expr ${total_ports} + 1`
                 fi
            fi
        fi
    done

    return 0;
}

get_pki_configuration_definitions()
{
    # Obtain the PKI Subsystem Type
    line=`grep -e '^[ \t]*cs.type[ \t]*=' ${PKI_SUBSYSTEM_CONFIGURATION_FILE}`
    pki_subsystem=`echo "${line}" | sed -e 's/^[^=]*=[ \t]*\(.*\)/\1/' -e 's/[ \t]*$//'`
    if [ "${line}" != "" ] ; then
        if  [ "${pki_subsystem}" != "CA"   ]  &&
            [ "${pki_subsystem}" != "KRA"  ]  &&
            [ "${pki_subsystem}" != "OCSP" ]  &&
            [ "${pki_subsystem}" != "TKS"  ]  &&
            [ "${pki_subsystem}" != "TPS"  ]
        then
            return ${default_error}
        fi
    else
        return ${default_error}
    fi

    # If "${pki_subsystem}" is a CA, KRA, OCSP, or TKS,
    # check to see if "${pki_subsystem}" is a "Clone"
    pki_clone=""
    if  [ "${pki_subsystem}" == "CA"   ]  ||
        [ "${pki_subsystem}" == "KRA"  ]  ||
        [ "${pki_subsystem}" == "OCSP" ]  ||
        [ "${pki_subsystem}" == "TKS"  ]
    then
        line=`grep -e '^[ \t]*subsystem.select[ \t]*=' ${PKI_SUBSYSTEM_CONFIGURATION_FILE}`
        if [ "${line}" != "" ] ; then
            pki_clone=`echo "${line}" | sed -e 's/^[^=]*[ \t]*=[ \t]*\(.*\)/\1/' -e 's/[ \t]*$//'`
            if [ "${pki_clone}" != "Clone" ] ; then
                # Reset "${pki_clone}" to be empty
                pki_clone=""
            fi
        else
            return ${default_error}
        fi
    fi

    # If "${pki_subsystem}" is a CA, and is NOT a "Clone", check to
    # see "${pki_subsystem}" is a "Root" or a "Subordinate" CA
    pki_hierarchy=""
    if    [ "${pki_subsystem}" == "CA" ]  &&
        [ "${pki_clone}" != "Clone"  ]
    then
        line=`grep -e '^[ \t]*hierarchy.select[ \t]*=' ${PKI_SUBSYSTEM_CONFIGURATION_FILE}`
        if [ "${line}" != "" ] ; then
            pki_hierarchy=`echo "${line}" | sed -e 's/^[^=]*[ \t]*=[ \t]*\(.*\)/\1/' -e 's/[ \t]*$//'`
        else
            return ${default_error}
        fi
    fi

    # If ${pki_subsystem} is a CA, check to
    # see if it is also a Security Domain
    pki_security_domain=""
    if    [ "${pki_subsystem}" == "CA" ] ; then
        line=`grep -e '^[ \t]*securitydomain.select[ \t]*=' ${PKI_SUBSYSTEM_CONFIGURATION_FILE}`
        if [ "${line}" != "" ] ; then
            pki_security_domain=`echo "${line}" | sed -e 's/^[^=]*[ \t]*=[ \t]*\(.*\)/\1/' -e 's/[ \t]*$//'`
            if [ "${pki_security_domain}" == "new" ] ; then
                # Set a fixed value for "${pki_security_domain}"
                pki_security_domain="(Security Domain)"
            else
                # Reset "${pki_security_domain}" to be empty
                pki_security_domain=""
            fi
        else
            return ${default_error}
        fi
    fi

    # If ${pki_subsystem} is a KRA or OCSP, check to see if
    # it is either a Stand-alone KRA or a Stand-alone OCSP
    #
    #     NOTE:  Ignore errors when the '<pki>.standalone' parameter
    #            is not present as this is most likely a legacy instance!
    #
    pki_standalone=""
    if  [ "${pki_subsystem}" == "KRA"  ] ; then
        line=`grep -e '^[ \t]*kra.standalone[ \t]*=' ${PKI_SUBSYSTEM_CONFIGURATION_FILE}`
        if [ "${line}" != "" ] ; then
            pki_standalone=`echo "${line}" | sed -e 's/^[^=]*[ \t]*=[ \t]*\(.*\)/\1/' -e 's/[ \t]*$//'`
            if [ "${pki_standalone}" == "true" ] ; then
                # Set a fixed value for "${pki_standalone}"
                pki_standalone="(Stand-alone)"
            else
                # Reset "${pki_standalone}" to be empty
                pki_standalone=""
            fi
        fi
    elif [ "${pki_subsystem}" == "OCSP" ] ; then
        line=`grep -e '^[ \t]*ocsp.standalone[ \t]*=' ${PKI_SUBSYSTEM_CONFIGURATION_FILE}`
        if [ "${line}" != "" ] ; then
            pki_standalone=`echo "${line}" | sed -e 's/^[^=]*[ \t]*=[ \t]*\(.*\)/\1/' -e 's/[ \t]*$//'`
            if [ "${pki_standalone}" == "true" ] ; then
                # Set a fixed value for "${pki_standalone}"
                pki_standalone="(Stand-alone)"
            else
                # Reset "${pki_standalone}" to be empty
                pki_standalone=""
            fi
        fi
    fi

    # Always obtain this PKI instance's "registered"
    # security domain information
    pki_security_domain_name=""
    pki_security_domain_hostname=""
    pki_security_domain_https_admin_port=""

    line=`grep -e '^[ \t]*securitydomain.name[ \t]*=' ${PKI_SUBSYSTEM_CONFIGURATION_FILE}`
    if [ "${line}" != "" ] ; then
        pki_security_domain_name=`echo "${line}" | sed -e 's/^[^=]*[ \t]*=[ \t]*\(.*\)/\1/' -e 's/[ \t]*$//'`
    else
        return ${default_error}
    fi

    line=`grep -e '^[ \t]*securitydomain.host[ \t]*=' ${PKI_SUBSYSTEM_CONFIGURATION_FILE}`
    if [ "${line}" != "" ] ; then
        pki_security_domain_hostname=`echo "${line}" | sed -e 's/^[^=]*[ \t]*=[ \t]*\(.*\)/\1/' -e 's/[ \t]*$//'`
    else
        return ${default_error}
    fi

    line=`grep -e '^[ \t]*securitydomain.httpsadminport[ \t]*=' ${PKI_SUBSYSTEM_CONFIGURATION_FILE}`
    if [ "${line}" != "" ] ; then
        pki_security_domain_https_admin_port=`echo "${line}" | sed -e 's/^[^=]*[ \t]*=[ \t]*\(.*\)/\1/' -e 's/[ \t]*$//'`
    else
        return ${default_error}
    fi

    # Compose the "PKI Instance Name" Status Line
    pki_instance_name="PKI Instance Name:   ${PKI_INSTANCE_NAME}"

    # Compose the "PKI Subsystem Type" Status Line
    header="PKI Subsystem Type: "
    if   [ "${pki_clone}" != "" ] ; then
        if [ "${pki_security_domain}" != "" ]; then
            # Possible Values:
            #
            #     "CA Clone (Security Domain)"
            #
            data="${pki_subsystem} ${pki_clone} ${pki_security_domain}"
        else
            # Possible Values:
            #
            #     "CA Clone"
            #     "KRA Clone"
            #     "OCSP Clone"
            #     "TKS Clone"
            #
            data="${pki_subsystem} ${pki_clone}"
        fi
    elif [ "${pki_hierarchy}" != "" ] ; then
        if [ "${pki_security_domain}" != "" ]; then
            # Possible Values:
            #
            #     "Root CA (Security Domain)"
            #     "Subordinate CA (Security Domain)"
            #
            data="${pki_hierarchy} ${pki_subsystem} ${pki_security_domain}"
        else
            # Possible Values:
            #
            #     "Root CA"
            #     "Subordinate CA"
            #
            data="${pki_hierarchy} ${pki_subsystem}"
        fi
    elif [ "${pki_standalone}" != "" ] ; then
        # Possible Values:
        #
        #     "KRA (Stand-alone)"
        #     "OCSP (Stand-alone)"
        #
        data="${pki_subsystem} ${pki_standalone}"
    else
        # Possible Values:
        #
        #     "KRA"
        #     "OCSP"
        #     "TKS"
        #     "TPS"
        #
        data="${pki_subsystem}"
    fi
    pki_subsystem_type="${header} ${data}"

    # Compose the "Registered PKI Security Domain Information" Status Line
    header="Name: "
    registered_pki_security_domain_name="${header} ${pki_security_domain_name}"

    header="URL:  "
    if  [ "${pki_security_domain_hostname}" != ""         ] &&
        [ "${pki_security_domain_https_admin_port}" != "" ]
    then
        data="https://${pki_security_domain_hostname}:${pki_security_domain_https_admin_port}"
    else
        return ${default_error}
    fi
    registered_pki_security_domain_url="${header} ${data}"

    # Print the "PKI Subsystem Type" Status Line
    echo
    echo "    [${pki_subsystem} Configuration Definitions]"
    echo "    ${pki_instance_name}"

    # Print the "PKI Subsystem Type" Status Line
    echo
    echo "    ${pki_subsystem_type}"

    # Print the "Registered PKI Security Domain Information" Status Line
    echo
    echo "    Registered PKI Security Domain Information:"
    echo "    =========================================================================="
    echo "    ${registered_pki_security_domain_name}"
    echo "    ${registered_pki_security_domain_url}"
    echo "    =========================================================================="

    return 0
}

display_configuration_information()
{
    result=0
    check_pki_configuration_status
    rv=$?
    if [ $rv -eq 0 ] ; then
        get_pki_status_definitions
        rv=$?
        if [ $rv -ne 0 ] ; then
            result=$rv
            echo
            echo "${PKI_INSTANCE_NAME} Status Definitions not found"
        else
            get_subsystems
            for SUBSYSTEM in ${PKI_SUBSYSTEMS}; do
                PKI_SUBSYSTEM_CONFIGURATION_FILE="${PKI_INSTANCE_PATH}/conf/${SUBSYSTEM}/CS.cfg"
                get_pki_configuration_definitions
                rv=$?
                if [ $rv -ne 0 ] ; then
                    result=$rv
                    echo
                    echo "${PKI_INSTANCE_NAME} Configuration Definitions not found for ${SUBSYSTEM}"
                fi
            done
        fi
    fi
    return $result
}

display_instance_status_systemd()
{
    echo -n "Status for ${PKI_INSTANCE_NAME}: "
    systemctl status "$PKI_SYSTEMD_TARGET@$PKI_INSTANCE_NAME.service" > /dev/null 2>&1
    rv=$?

    if [ $rv -eq 0 ] ; then
        echo "$PKI_INSTANCE_NAME is running .."
        display_configuration_information
    else
        echo "$PKI_INSTANCE_NAME is stopped"
    fi

    return $rv
}

backup_instance_configuration_files()
{
    declare -a pki_subsystems=('ca'
                               'kra'
                               'ocsp'
                               'tks'
                               'tps')

    # Utilize an identical timestamp on archives for each PKI subsystem
    # residing within the same instance to mark a common archival time
    timestamp=`date +%Y%m%d%H%M%S`

    # Automatically enable timestamped archives
    #
    #     NOTE:  To disable this feature for a particular PKI subsystem
    #            within an instance, edit that PKI subsystem's 'CS.cfg' file
    #            within the instance:
    #
    #            If the 'archive.configuration_file' parameter exists,
    #            change it to 'archive.configuration_file=false'.
    #
    #            However, if the 'archive.configuration_file' parameter does
    #            not exist, simply add 'archive.configuration_file=false'
    #            to the 'CS.cfg'.
    #
    #            In either case, it is unnecessary to restart the instance,
    #            as each instance's 'CS.cfg' file is always processed every
    #            time an instance is restarted.
    #
    backup_errors=0
    for pki in "${pki_subsystems[@]}"
    do
        config_dir=${PKI_INSTANCE_PATH}/conf/${pki}

        # Check to see if this PKI subsystem exists within this instance
        if [ ! -d ${config_dir} ] ; then
            continue
        fi

        # Compute uppercase representation of this PKI subsystem
        PKI=${pki^^}

        # Backup parameters
        pki_instance_configuration_file=${config_dir}/CS.cfg
        backup_file=${config_dir}/CS.cfg.bak
        saved_backup_file=${config_dir}/CS.cfg.bak.saved

        # Check for an empty 'CS.cfg'
        #
        #     NOTE:  'CS.cfg' is always a regular file
        #
        if [ ! -s ${pki_instance_configuration_file} ] ; then
            # Issue a warning that the 'CS.cfg' is empty
            echo "WARNING:  The '${pki_instance_configuration_file}' is empty!"
            echo "          ${PKI} backups will be discontinued until this"
            echo "          issue has been resolved!"
            ((backup_errors++))
            continue
        fi

        # Make certain that a previous attempt to backup 'CS.cfg' has not failed
        # (i. e. - 'CS.cfg.bak.saved' exists)
        #
        #     NOTE:  'CS.cfg.bak.saved' is always a regular file
        #
        if [ -f ${saved_backup_file} ] ; then
            # 'CS.cfg.bak.saved' is a regular file or a symlink
            echo "WARNING:  Since the file '${saved_backup_file}' exists, a"
            echo "          previous backup attempt has failed!  ${PKI} backups"
            echo "          will be discontinued until this issue has been resolved!"
            ((backup_errors++))
            continue
        fi

        # If present, compare 'CS.cfg' to 'CS.cfg.bak' to see if it is necessary
        # to backup 'CS.cfg'.  'CS.cfg.bak' may be a regular file, a
        # symlink, or a dangling symlink
        #
        #     NOTE:  'CS.cfg.bak' may be a regular file, a symlink, or a
        #            dangling symlink
        #
        if [ -f ${backup_file} ] ; then
            # 'CS.cfg.bak' is a regular file or a symlink
            cmp --silent ${pki_instance_configuration_file} ${backup_file}
            rv=$?
            if [ $rv -eq 0 ] ; then
                # 'CS.cfg' is identical to 'CS.cfg.bak';
                # no need to archive or backup 'CS.cfg'
                continue
            fi

            # Since it is known that the previous 'CS.cfg.bak' file exists, and
            # and it is either a symlink or a regular file, save the previous
            # 'CS.cfg.bak' to 'CS.cfg.bak.saved'
            #
            # NOTE:  If switching between simply creating backups to generating
            #        timestamped archives, the previous 'CS.cfg.bak' that
            #        existed as a regular file will NOT be archived!
            #
            if [ -h ${backup_file} ] ; then
                # 'CS.cfg.bak' is a symlink
                # (i. e. - copy the timestamped archive to a regular file)
                cp ${backup_file} ${saved_backup_file}

                # remove the 'CS.cfg.bak' symlink
                rm ${backup_file}
            else
                # 'CS.cfg.bak' is a regular file
                # (i. e. - simply rename the regular file)
                mv ${backup_file} ${saved_backup_file}
            fi
        elif [ -h ${backup_file} ] ; then
            # 'CS.cfg.bak' is a dangling symlink
            echo "WARNING:  The file '${backup_file}' is a dangling symlink"
            echo "          which suggests that the previous backup file has"
            echo "          been removed!  ${PKI} backups will be discontinued"
            echo "          until this issue has been resolved!"
            ((backup_errors++))
            continue
        fi

        # Check 'CS.cfg' for 'archive.configuration_file' parameter
        # to see if timestamped archives should be disabled
        archive_configuration_file="true"
        line=`grep -e '^[ \t]*archive.configuration_file[ \t]*=' ${pki_instance_configuration_file}`
        if [ "${line}" != "" ] ; then
            archive_configuration_file=`echo "${line}" | sed -e 's/^[^=]*[ \t]*=[ \t]*\(.*\)/\1/' -e 's/[ \t]*$//'`
        fi

        # Backup 'CS.cfg'
        if [ "${archive_configuration_file}" != "true" ] ; then
            # Always backup 'CS.cfg' to 'CS.cfg.bak'
            cp -b ${pki_instance_configuration_file} ${backup_file}
        else
            # Archive parameters
            archive_dir=${config_dir}/archives
            archived_file=${archive_dir}/CS.cfg.bak.${timestamp}

            # If not present, create an archives directory for this 'CS.cfg'
            if [ ! -d ${archive_dir} ] ; then
                mkdir -p ${archive_dir}
            fi

            # Archive 'CS.cfg' to 'CS.cfg.bak.${timestamp}'
            cp -a ${pki_instance_configuration_file} ${archived_file}
            if [ ! -s ${archived_file} ] ; then
                # Issue a warning that the archived backup failed
                echo "WARNING:  Failed to archive '${pki_instance_configuration_file}' to '${archived_file}'!"
                ((backup_errors++))
                continue
            fi

            # Always create 'CS.cfg.bak' by linking to this archived file
            ln -s ${archived_file} ${backup_file}
        fi

        # Check that a non-empty 'CS.cfg.bak' symlink or regular file exists
        if [ ! -s ${backup_file} ] ; then
            # Issue a warning that the backup failed
            echo "WARNING:  Failed to backup '${pki_instance_configuration_file}' to '${backup_file}'!"
            ((backup_errors++))
            continue
        fi

        # Since 'CS.cfg' was backed up successfully, remove 'CS.cfg.bak.saved'
        if [ -f ${saved_backup_file} ] ; then
            rm ${saved_backup_file}
        fi
    done

    if [ ${backup_errors} -ne 0 ]; then
        return 1
    fi

    return 0
}

start_instance()
{
    rv=0

    if [ -f ${RESTART_SERVER} ] ; then
        rm -f ${RESTART_SERVER}
    fi

    # Generate initial catalina.policy
    cat /usr/share/pki/server/conf/catalina.policy \
        /usr/share/tomcat/conf/catalina.policy > \
        /var/lib/pki/$PKI_INSTANCE_NAME/conf/catalina.policy

    echo >> /var/lib/pki/$PKI_INSTANCE_NAME/conf/catalina.policy
    echo >> /var/lib/pki/$PKI_INSTANCE_NAME/conf/catalina.policy

    cat /usr/share/pki/server/conf/pki.policy >> \
        /var/lib/pki/$PKI_INSTANCE_NAME/conf/catalina.policy

    # Add permissions for all JAR files in /var/lib/pki/$PKI_INSTANCE_NAME/common/lib
    for path in /var/lib/pki/$PKI_INSTANCE_NAME/common/lib/*; do

        cat >> /var/lib/pki/$PKI_INSTANCE_NAME/conf/catalina.policy << EOF

grant codeBase "file:$(realpath $path)" {
    permission java.security.AllPermission;
};
EOF
    done

    # Append custom.policy
    if [ -f /var/lib/pki/$PKI_INSTANCE_NAME/conf/custom.policy ]; then
        echo >> /var/lib/pki/$PKI_INSTANCE_NAME/conf/catalina.policy
        cat /var/lib/pki/$PKI_INSTANCE_NAME/conf/custom.policy >> \
            /var/lib/pki/$PKI_INSTANCE_NAME/conf/catalina.policy
    fi

    /usr/sbin/pki-server banner-validate -i "$PKI_INSTANCE_NAME" --silent
    rv=$?
    if [ $rv -ne 0 ]; then
        return $rv
    fi

    if [ "${PKI_SERVER_AUTO_ENABLE_SUBSYSTEMS}" = "true" ] ; then
        # enable all subsystems
        /usr/sbin/pki-server subsystem-enable -i "$PKI_INSTANCE_NAME" --all --silent
    fi

    # Always create a backup of each PKI subsystem's 'CS.cfg' file
    # within an instance.
    #
    # For every backup failure detected within a PKI subsystem within
    # an instance, a warning message will be issued, and an error code
    # of 1 will be returned.
    #
    # Note that until they have been resolved, every previous backup
    # failures of any PKI subsystem within an instance will also issue
    # a warning message and return an error code of 1.  Backups of that
    # particular instance's PKI subsystem will be suspended until this
    # error has been addressed.
    #
    # By default, unless they have been explicitly disabled,
    # a timestamped archive of each PKI subsystem's 'CS.cfg' file
    # within an instance will also be created. Note that a single
    # timestamp will be utlized across each PKI subsystem within
    # an instance for each invocation of this function.
    #
    # When enabled, any timestamped archive failures also issue a
    # warning message and return an error code of 1.
    #
    backup_instance_configuration_files
    return $?
}

start()
{
    error_rv=0
    rv=0
    config_errors=0
    errors=0

    # Source values associated with this particular PKI instance
    [ -f ${PKI_REGISTRY_ENTRY} ] &&
    . ${PKI_REGISTRY_ENTRY}

    start_instance
    rv=$?

    if [ $rv = 6 ] ; then
        # Since at least ONE configuration error exists, then there
        # is at least ONE unconfigured instance from the PKI point
        # of view.
        #
        # However, it must still be considered that the
        # instance is "running" from the point of view of other
        # OS programs such as 'chkconfig'.
        #
        # Therefore, ignore non-zero return codes resulting
        # from configuration errors.
        #

        config_errors=`expr $config_errors + 1`
        rv=0
    elif [ $rv != 0 ] ; then
        errors=`expr $errors + 1`
        error_rv=$rv
    fi

    return $rv
}

registry_status()
{
    error_rv=0
    rv=0
    errors=0

    # Source values associated with this particular PKI instance
    [ -f ${PKI_REGISTRY_ENTRY} ] &&
    . ${PKI_REGISTRY_ENTRY}

    display_instance_status_systemd
    rv=$?
    if [ $rv -ne 0 ] ; then
        errors=`expr $errors + 1`
        error_rv=$rv
    fi

    return $rv
}

