#!/bin/sh
#
# grid-mapfile-check-consistency
#

if test -z "${GLOBUS_LOCATION}"; then
    echo ""
    echo "ERROR: Please set GLOBUS_LOCATION to the Globus installation directory before"
    echo "running this script"
    echo ""
    exit 1
fi

. ${GLOBUS_LOCATION}/libexec/globus-script-initializer
globus_source ${GLOBUS_LOCATION}/libexec/globus-sh-tools.sh

PROGRAM_NAME=`echo $0 |${GLOBUS_SH_SED-sed} 's|.*/||g'`

PROGRAM_VERSION=`echo '$Revision: 1.7 $'| ${GLOBUS_SH_SED-sed} -e 's|\\$||g' -e 's|Revision: \(.*\)|\1|'`

VERSION="3.10"

PACKAGE="globus_gss_assist"

DIRT_TIMESTAMP="1086984764"
DIRT_BRANCH_ID="52"

short_usage="$PROGRAM_NAME [-help] [-mapfile FILE]"

long_usage() {
    ${GLOBUS_SH_CAT-cat} >&2 <<EOF

${short_usage}

    $PROGRAM_NAME checks the consistency of the Grid mapfile.

    Options:
      -help, -usage           Displays help
      -version                Displays version
      -mapfile FILE, -f FILE  Path of gridmap to be used

EOF
}

globus_source $libexecdir/globus-args-parser-header $@

##############################################

secconfdir="/etc/grid-security"
GRID_MAP_FILE=${secconfdir}/grid-mapfile
ECHO_DRYRUN=:

# Parse command line arguments

while [ -n "$1" ]; do
    case "$1" in
        -f | -mapfile )
	    opt=$1
	    shift
            if test $# -lt 1 ; then
                globus_args_option_error "$opt" "${opt} requires a argument"
            fi
	    GRID_MAP_FILE=$1
	    shift
	    ;;
			
        * )
	    globus_args_unrecognized_option "$1"
	    ;;
    esac

done

# check_perms
# $1 is a filename
# $2 is a binary representation of the permissions to be checked
#    ie ----rwxrwx ==> 0000111111
# returns true if none of the bits in $2 are set in $1's access mode
check_perms() {

    _file=$1
    _mask=$2

    _result=`(echo $_mask ; ${GLOBUS_SH_LS-ls} -l $_file ) | ${GLOBUS_SH_AWK-awk} '
    BEGIN {
        first=1;
        mask=0;
    }
    {
        if(first == 1) {
            mask=$1;
            first=0;
            next;
        }
        mode=substr($1, 1, 10);
        for(i = 1; i <= 10; i++) {
           if(substr(mode, i, 1) == "-") {
              newmode[i] = newmode[i] 0;
           } else
           {
              newmode[i] = newmode[i] 1;
           }
        }
        for(i = 1; i <= 10; i++) {
            maskbit=int(substr(mask, i, 1));
            if((maskbit == 1) && (newmode[i] == 1)) {
                print 0;
                exit;
            }
        }
        print 1;
    }'`

    return $_result;
}


#DONE - 1. Legal login names
#2. comma seprated login name list
#3. at least one login name
#DONE - 4. duplicate entries
#5. Each line contains some DN/Ln pair
#DONE - 6. Check for minimum of C=, O=, and CN= fields


# Verify mapfile existance

if [ ! -f $GRID_MAP_FILE ] ; then 
    globus_args_option_error "$opt" "\"${GRID_MAP_FILE}\" does not exist"
    exit 1
fi
  
if [ ! -r $GRID_MAP_FILE ] ; then
    globus_args_option_error "$opt" "\"${GRID_MAP_FILE}\" is not readable."
    exit 1
fi

if [ -O ${GRID_MAP_FILE} -a ! -w $GRID_MAP_FILE ] ; then
    globus_args_option_error "$opt" "\"${GRID_MAP_FILE}\" is not writeable."
    exit 1
fi

if check_perms ${GRID_MAP_FILE} "0000010010" ; then
    globus_args_option_error "$opt" "\"${GRID_MAP_FILE}\" is world writeable."
    exit 1
fi

RC=0

# Check for duplicate entries

duplicates=`${GLOBUS_SH_CAT-cat} $GRID_MAP_FILE | ${GLOBUS_SH_SORT-sort} | ${GLOBUS_SH_UNIQ-uniq} -d`
if [ -n "$duplicates" ] ; then
    echo "The following entry(s) is/are duplicated"
    echo "$duplicates"
    RC=1
fi


# Read Grid Map File for further processing

while read line || test ! -z "${line}" ; do
    
    line=`echo ${line} | ${GLOBUS_SH_SED-sed} -e 's/[	 ]*//'`

    # skip empty lines

    if test -z "${line}" ; then
        continue
    fi

    # Extract DN and LN fields

    # Check for double quote delimitor
    delim=`echo $line | cut -c1`
    if [ "X$delim" = "X\"" ]; then
        # DN is double quote delimited
        
        # Check for terminating double quote
        term_check=`echo $line | cut -c2- | grep \"`
        if [ -z "$term_check" ]; then
            echo "The following entry is missing a closing double quote"
            echo "$line"
            RC=1
        fi

        dn=`echo $line | cut -f2 -d\"`
        remaining_line=`echo $line | cut -f3- -d\"`

    else
        # No double quote delimitor on DN
        dn=`echo $line | ${GLOBUS_SH_SED-sed} -e 's/\([^	 ]*\)[	 ]*.*/\1/'`
        remaining_line=`echo $line | ${GLOBUS_SH_SED-sed} -e 's/[^	 ]*[	 ]*//'`
    fi

    if test -z "${dn}" ; then
        echo "The following entry is missing a DN"
        echo "$line"
        RC=1
    fi

    dn_entries=`${GLOBUS_SH_CAT-cat} <<EOF 
${dn_entries}
${dn}
EOF
`
    
    if test -z "${remaining_line}" ; then
        echo "The following entry is missing a local user name"
        echo "$line"
        RC=1
    fi

    ln_list=""

    while test ! -z "${remaining_line}" ; do
        ln_string=`echo $remaining_line | ${GLOBUS_SH_SED-sed} -e 's/\([^	 ,]*\).*/\1/'`

        if test -z "${ln_string}" ; then
            echo "The following entry has extra text at the end and may be malformed"
            echo "$line"
            RC=1
            break
        fi

        remaining_line=`echo $remaining_line | ${GLOBUS_SH_SED-sed} -e 's/[^	 ,]*[,	 ]*//'`
        ln_list="${ln_list} ${ln_string}"
    done

    # Check for existance of O=,CN= fields

    check_fields=`echo $line | ${GLOBUS_SH_GREP-grep} "O=" | ${GLOBUS_SH_GREP-grep} "CN="`
    if [ -z "$check_fields" ]
    then
        echo "Warning: The following entry is missing either a  O=, a CN= field or both"
        echo "$line"
        echo "This does not necessarily mean that the entry is wrong"
        echo "If it is indeed correct the CA issuing that certificate"
        echo "should take a look at the guide lines in"
        echo "http://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt"
    fi
    

    # Check for valid login names

    for name in $ln_list ; do
        ${libexecdir}/globus-is-local-user $name
        if [ "$?" -eq 1 ] ; then
            echo "The following entry contains an invalid login name"
            echo "$line"
            echo "The login name not found is: $name"
            RC=1
        fi                
    done

done < $GRID_MAP_FILE

# Check for duplicate DNs

duplicates=`echo "${dn_entries}" | ${GLOBUS_SH_SORT-sort} | ${GLOBUS_SH_UNIQ-uniq} -d`
if [ -n "$duplicates" ] ; then
    echo "The following DN(s) is/are duplicated"
    echo "$duplicates"
    RC=1
fi


exit $RC

