#!/bin/sh
#######################################################################
# copyright (C) 2015-2016 by NetApp.  All Rights Reserved.
#
#######################################################################

prog_name="netapp_security_config_check"

# smf field separator to ensure predictable parsing
ngsh_fs="X;X"
ngsh_prefix="set -showallfields true -showseparator \"$ngsh_fs\";rows 0"
ngsh_prefix_count=2  # these prefix commands output additional lines to skip

######################
#
# Helper routines
#
# This routnes help in ngsh CLI processing
# and are taken from config_common/netapp_sufficiency_lif_checker
#
#####################

############################################################
# String manipulation functions
############################################################

#
# Output a message - general purpose
# input: string
# output: string
#
msg()
{
    echo "$1"

}

#
# Convert to uppercase
# input: string
# output: string
#
toupper()
{
    echo "$1" | tr "[:lower:]" "[:upper:]"
}

# Remove the first item from a list that uses X;X field separators
# input: variable name to place first item
#        variable name to place remainder of list
#        list with X;X separators
# return: 0 not empty
#         1 empty
# side effect: first element is stored in 1st param
#              list with first element popped off is stored in 2nd param
pop()
{
    local itemname=$1
    local listname=$2
    local list="$3"
    local tmpitem
    local tmplist
    local retval

    # tmpitem gets the first item by removing largest suffix of X;X*
    tmpitem="${list%%X;X*}"
    if [ "$tmpitem" ]; then
           retval=0
    else
           retval=1
    fi
    setvar $itemname "$tmpitem"

    # tmpitem gets the rest of the list without the first item
    #   by removing the smallest prefix of *X;X
    tmplist="${list#*X;X}"
    if [ "$tmplist" = "$list" ]; then
           setvar $listname ""
    else
           setvar $listname "$tmplist"
    fi

    return $retval
}

# Return whether a substring exists in a string
# input: string to search
#        substring to search for
# return: 0 found
#         1 not found
contains()
{
    local list="$1"
    local substring="$2"
    local retval

    result=`echo "$list" | sed -n "/$substring/p"`
    if [ -z $result ]; then
            retval=1
    else
            retval=0
    fi

    return $retval
}

# Print the items in a list that uses X;X field separators
# input: list with X;X separators
# output: items printed with space separators
print_to_list()
{
    local my_list="$1"
    local my_list2
    local item
    local first=1

    while [ 1 ]; do
           pop item my_list2 "$my_list"
           if [ $? -eq 1 ]; then
                  break
           fi
           my_list="$my_list2"

           if [ $first -eq 0 ]; then
                  printf " "
           else
                  first=0
           fi
           printf "%s" "$item"

    done
}

#
# Determine if a string list is empty
#   Note: Since this takes lists whose elements may include spaces, any
#         characters will make the list be not empty.
# input: string list
# return: 0 not empty
#         1 empty
empty_list()
{
    local str="$1"

    str=`echo "$str" | sed "s/X;X//g"`
    if [ "$str" ]; then
           return 0
    fi
    return 1
}

#
# Take the unique elements of each string and put them into a single string.
# Elements are separated by X;X
#
# input: string item to add
#        string list that item will be added to
# output: string list, without duplicates
#
str_union()
{
    local str1="$1"
    local list="$2"
    local combinedstring

    if [ "$list" ]; then
           combinedstring="$str1""X;X$list"
    else
           combinedstring="$str1"
    fi

    echo "$combinedstring" | tr -d "\r\n" | awk '
{
    str=$0;
    while ( length(str) != 0 ) {
        sep=match(str,"X;X");   # find separator
        if (sep==0) {
            # no separator, take the whole thing
            token=str
            str=""
        } else if (sep==1) {
            # separator is first, skip it
            str=substr(str, 4, length(str)-3);
            continue
        } else {
            # item is beginning of string up to separator
            token=substr(str, 1, sep-1);
            # remove item and separator from head of string
            str=substr(str, sep+3, length(str)-sep-2)
        }
        # output non-duplicates
        if (lif_array[token]!=1) {
            lif_array[token]=1;
            printf( "%sX;X", token )
        }
    }
}
'
}

#
# Run a ngsh command logging the command and it's output
# to a log file.
# This should be the only function that calls ngsh -c.
#
# input: command string, and potentially pid once we start
#        sending commands in parallel
# output: results of the command
#
ngsh_cmd()
{
    local command="$1"
    local output
    local status

    output=`ngsh -c $command`
    status=$?
    echo "$output"
    return $status
}

#
# Run an ngsh show command, and massage the output into a list,
# using the text from the specified column.
# Only suitable for handling output of show commands.
#
# input: command string, column number
# output: string list
ngsh_show()
{
    local maincommand="$1"
    local col=$2
    local command="$ngsh_prefix;$maincommand"

    if [ $col -gt 6 ]; then
           err_exit "ngsh_show supports only 6 columns, not $col."
    fi

    # output parsing is:
    #  skip first two lines: title and underline  (NR>2 conditional)
    #  skip line with how many entries were displayed
    #  skip columns containing only "-" (s!~/^-$/)
    #  replace any whitespace, CR, NL, and comma with a space (tr cmd)
    #  then squeeze out duplicate spaces (-s arg)
    ngsh_cmd "$command"  | awk -F $ngsh_fs -v col=$col -v skip=$ngsh_prefix_count '
! /entries were displayed/ {
    if (NR>2+skip) {
        if (col==1) {s=$1}
        else {
            if (col==2) {s=$2}
            else {
                if (col==3) {s=$3}
                else {
                    if (col==4) {s=$4}
                    else {
                        if (col==5) {s=$5}
                        else {
                            if (col==6) {s=$6}
                        }
                    }
                }
            }
        };
        if (s!~/^-$/) {
            printf( "%s ", s )
        }
    }
}' | tr -s "[:blank:]\r\n," "[ *]"
}

#
# Run an ngsh show command, and massage the output into a
# X;X separated list, using the text from the specified column.
# Only suitable for handling output of show commands.
#
# input: command string, column number
# output: string list with X;X separations
ngsh_show_to_list()
{
    local maincommand="$1"
    local col=$2
    local command="$ngsh_prefix;$maincommand"

    if [ $col -gt 6 ]; then
           err_exit "ngsh_show_to_list supports only 6 columns, not $col."
    fi

    # output parsing is:
    #  skip first two lines: title and underline  (NR>2 conditional)
    #  skip lines resulting from the prefix commands
    #  skip line with how many entries were displayed
    #  skip columns containing only "-" (s!~/^-$/)
    #  replace any commas with the separator (sed cmd)
    #  remove CR and NL (tr cmd)
    ngsh_cmd "$command" | awk -F $ngsh_fs -v col=$col -v skip=$ngsh_prefix_count '
! /entries were displayed/ {
    if (NR>2+skip) {
        if (col==1) {s=$1}
        else {
            if (col==2) {s=$2}
            else {
                if (col==3) {s=$3}
                else {
                    if (col==4) {s=$4}
                    else {
                        if (col==5) {s=$5}
                        else {
                            if (col==6) {s=$6}
                        }
                    }
                }
            }
        };
        if (s!~/^-$/) {
            printf( "%sX;X", s )
        }
    }
}' | sed "s/,/X;X/g" | tr -d "\r\n"
}

#######
# BEGIN
# check for if SSLv3 is enabled, throw the below warning.
#######

echo "${prog_name} script begin";

output=`ngsh_show "system services web show -fields sslv3-enabled" 1`

if [ "${output%?}" = "true" ]; then
    msg ""
    msg ""
    msg "WARNING: protocol SSLv3 is currently enabled in web configuration. ";
    msg "This protocol is considered insecure and will be disabled when you ";
    msg "upgrade to DATA ONTAP 9.0.0. ";
    msg "If the client interfaces to Data ONTAP have any of the TLS protocols enabled, ";
    msg "for example, TLSv1, TLSv1.1, TLSv1.2, no further action is required. ";
    msg "Otherwise, atleast one of the TLS protocols should be available at the ";
    msg "client interfaces to ensure connectivity. ";
    msg "To view the web services configuration, run the command:";
    msg "system services web show";
    msg ""
    msg ""
    exit
fi

ldap_list=`ngsh_show_to_list "vserver services name-service ldap show -client-enabled true -fields client-config" 2`
empty_list "$ldap_list"
if [ $? -eq 1 ]; then
    exit 0
fi

while [ 1 ]; do
    pop item my_list "$ldap_list"

    if [ $? -eq 1 ]; then
	    break
    fi

    ldap_list="$my_list"
    ldap_conf_out=`ngsh_show "vserver services name-service ldap client show -client-config $item -fields allow-ssl" 3`

    if [ "${ldap_conf_out%?}" = "true" ]; then
		msg ""
		msg ""
		msg "WARNING: protocol SSLv3 is currently enabled in LDAP client configuration. ";
		msg "This protocol is considered insecure and will be disabled when you ";
		msg "upgrade to DATA ONTAP 9.0.0. ";
		msg "If the LDAP server has any of the TLS protocols enabled, ";
		msg "for example, TLSv1, TLSv1.1, TLSv1.2, no further action is required. ";
		msg "Otherwise, atleast one of the TLS protocols should be available at the ";
		msg "server to ensure connectivity. ";
		msg "To view the LDAP client configuration, run the command: ";
		msg "vserver services name-service ldap client show -client-config $item";
		msg ""
		msg ""
		exit
	fi
done

echo "${prog_name} script end";
