#!/bin/sh

# 
# Copyright 1999-2006 University of Chicago
# 
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# 
# http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# 

#
# grid-mapfile-add-entry
#

prefix="${GLOBUS_LOCATION-/usr}"
exec_prefix="/usr"
sbindir="/usr/sbin"
bindir="/usr/bin"
includedir="${prefix}/include/globus"
datarootdir="${prefix}/share"
datadir="/usr/share"
libexecdir="${datadir}/globus"
sysconfdir="/etc"
sharedstatedir="/var/lib"
localstatedir="/var"

PROGRAM_NAME=`echo $0 | sed 's|.*/||g'`
PROGRAM_VERSION="10.15"

VERSION="10.15"
PACKAGE="globus_gss_assist"

DIRT_TIMESTAMP="1436979015"
DIRT_BRANCH_ID="85"


short_usage="$PROGRAM_NAME -dn DN -ln LN 
[-help] [-d] [-f mapfile FILE]"

long_usage() {
    cat >&2 <<EOF

${short_usage}

    $PROGRAM_NAME adds an entry to a Grid mapfile.

    Options:
      -help, -usage           Displays help
      -version                Displays version
      -dn DN                  Distinguished Name (DN) to add. Remember to 
                              quote the DN if it contains spaces.
      -ln LN1 [LN2...]        Local login name(s) to map DN to
      -dryrun, -d             Shows what would be done but will not add the entry
      -mapfile FILE, -f FILE  Path of Grid map file to be used

EOF
}

##############################################
Cleanup()
{

if [ -f $CONSISTENCY_CHECK ]
then
	rm $CONSISTENCY_CHECK
fi

if [ -f $GRID_MAP_FILE_COPY ]
then
	rm $GRID_MAP_FILE_COPY
fi

if [ -f $EXISTING_DN_ENTRIES ]
then
	rm $EXISTING_DN_ENTRIES
fi

if [ -f $NEW_GRID_MAP_FILE ] ; then
        rm $NEW_GRID_MAP_FILE
fi


chmod 644 $GRID_MAP_FILE
if [ $? -ne 0 ]
then
	echo "ERROR: Could not change mode of $GRID_MAP_FILE back to 644" >&2
    exit 1
fi


}
##############################################

# Main Logic

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

# Parse command line arguments

globus_args_option_error()
{
    cat 1>&2 <<-EOF
	ERROR: option $1 : $2

	Syntax : ${short_usage}

	Use -help to display full usage.
	EOF
    exit 1
}

while [ -n "$1" ]; do
    case "$1" in
	-help | -h | --help | -usage | --usage)
	    long_usage
	    exit 0
	    ;;
        -version|--version)
            if [ "X${PROGRAM_NAME}" != "X" -a \
                  "X${PROGRAM_VERSION}" != "X" ]; then
                echo "${PROGRAM_NAME}: ${PROGRAM_VERSION}"
            elif [ "X${PACKAGE}" != "X" -a \
                   "X${VERSION}" != "X" ]; then
                echo "${PACKAGE}: ${VERSION}"
            else
                echo "No version information available."
            fi
            exit 0
            ;;
        -versions|--versions)
            __AT__=@
            if [ -n "${PACKAGE}" -a -n "${VERSION}" -a \
                 -n "${DIRT_TIMESTAMP}" -a -n "${DIRT_BRANCH_ID}" -a \
                 "X${DIRT_TIMESTAMP}" != "X${__AT__}DIRT_TIMESTAMP${__AT__}" -a \
                 "X${DIRT_BRANCH_ID}" != "X${__AT__}DIRT_BRANCH_ID${__AT__}" ];
            then
                echo "${PACKAGE}: ${VERSION} (${DIRT_TIMESTAMP}-${DIRT_BRANCH_ID})"
            else
                echo "No DiRT information available."
            fi
            exit 0;
            ;;
        -dn) 
	    shift
            if [ $# -ge 1 ] ; then
		dn=$1
                shift
	    else
                globus_args_option_error "-dn" "needs a DN argument"
	    fi
        ;;
        -ln )
            shift
            if [ $# -ge 1 ] ; then
		ln=$1
		shift
		if [ $# -ge 1 ] ; then
		    while test "`echo $1 | cut -c 1`" != "-" ; do
			ln=$ln" "$1
			shift
			if [ $# -eq 0 ] ; then
			    break
			fi
		    done
		fi
	    else
                globus_args_option_error "-ln" "needs a list of user login names"
		exit 1
	    fi
	    ;;
        -d | -dryrun )
	    ECHO_DRYRUN=echo
	    shift
	    ;;
        -f | -mapfile )
	    opt=$1
	    shift
	    GRID_MAP_FILE=$1
	    shift
	    ;;
        * )
	    globus_args_option_error "$1" "unrecognized option"
	    ;;
    esac
done

if [ "$ln" = "" ] || [ "$dn" = "" ]; then
    cat 1>&2 <<-EOF
	Syntax : ${short_usage}

	Use -help to display full usage.

	EOF
    exit 1
fi


secure_tmpdir="`dirname \"${GRID_MAP_FILE}\"`"

if test ! \( -r "${secure_tmpdir}" -a -w "${secure_tmpdir}" \) ; then
    echo "ERROR: This script requires read/write permissions in ${secure_tmpdir}" >&2
    exit 1
fi 

GRID_MAP_FILE_COPY=${secure_tmpdir}/.mapfile.copy.$$
NEW_GRID_MAP_FILE=${secure_tmpdir}/.new_mapfile.$$
CONSISTENCY_CHECK=${secure_tmpdir}/.consistency_check.$$
EXISTING_DN_ENTRIES=${secure_tmpdir}/.existing_dn_entries.$$

trap Cleanup 1 2 3 6 9 13 15

# Verify mapfile existance

echo "Modifying $GRID_MAP_FILE ..."
if [ ! -f $GRID_MAP_FILE ] ; then
    echo "$GRID_MAP_FILE does not exist... Attempting to create $GRID_MAP_FILE"
    touch $GRID_MAP_FILE
    if [ $? -ne 0 ] ; then
        echo "ERROR: Could not create $GRID_MAP_FILE" >&2
        exit 1
    fi

    chmod 644 $GRID_MAP_FILE
    if [ $? -ne 0 ] ; then
        echo "ERROR: Could not set proper access mode of $GRID_MAP_FILE" >&2
        exit 1
    fi
else
    if [ ! -r $GRID_MAP_FILE ] ; then
        globus_args_option_error "$opt" "\"${GRID_MAP_FILE}\" is not readable."
        exit 1
    fi

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

if [ -z "$ln" -o -z "$dn" ] ; then
    echo "Both the -dn and the -ln arguments must be provided"
    cat 1>&2 <<-eof
	syntax : ${short_usage}

	use -help to display full usage.

	eof
    exit 1
fi

# Make a copy of production map file for comparison to original later

cp $GRID_MAP_FILE $GRID_MAP_FILE_COPY
if [ $? -ne 0 ] ; then
    echo "ERROR: Could not make a copy of $GRID_MAP_FILE" >&2
    Cleanup
    exit 1
fi

# Change mode of existing map file to read only (logical UNIX lock)

chmod 400 $GRID_MAP_FILE
if [ $? -ne 0 ] ; then
    echo "ERROR: Could not change mode of $GRID_MAP_FILE" >&2
    Cleanup
    exit 1
fi


$ECHO_DRYRUN "Verifying that Local Name(s)=($ln) are legitimate local accounts."

for name in $ln ; do
    $ECHO_DRYRUN "Checking ln(s)=$name"
    idres=`id $name 2>&1`
    if  [ "$?" -eq 0 ] ; then
        $ECHO_DRYRUN "Local Name=$name does exist"
    else
        echo "entry not added because the LN(s) is/are not legitimate"
        $ECHO_DRYRUN "Local Name=$name does *NOT* exist"
        $ECHO_DRYRUN "Entry *NOT* added"
        $ECHO_DRYRUN "Result: $idres"
        Cleanup
        exit 1
    fi
done

$ECHO_DRYRUN "Local Name(s)=($ln) is/are valid. Requested entry will be added."

touch $NEW_GRID_MAP_FILE            
chmod 644 $NEW_GRID_MAP_FILE
if [ $? -ne 0 ] ; then
    echo "ERROR: Could not set proper access mode of $NEW_GRID_MAP_FILE" >&2
    Cleanup
    exit 1
fi

updated_existing_dn="false"

while read line || test ! -z "${line}" ; do
    # 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"
            Cleanup
            exit 1
        fi
        existing_dn=`echo $line | cut -f2 -d\"`
    else
        # No double quote delimitor on DN
        existing_dn=`echo $line | sed -e 's/\([^    ]*\)[   ]*.*/\1/'`
    fi

    if test ! "$dn" = "$existing_dn" ; then
        echo $line >> $NEW_GRID_MAP_FILE
    else
        for name in $ln ; do
            if test -z "`echo \"$line\" | grep \"\<$name\>\"`"; then
                line="$line,$name"
                added_map="$added_map $name"
            else
                omitted_map="$omitted_map $name"
            fi
        done
        echo $line >> $NEW_GRID_MAP_FILE
        updated_existing_dn="$line"
    fi
done < $GRID_MAP_FILE_COPY


# Verify that no changes to original map file
# during the execution of this program

diff $GRID_MAP_FILE_COPY $GRID_MAP_FILE > $CONSISTENCY_CHECK
if  [ -s $CONSISTENCY_CHECK ] ; then
    echo "ERROR: $GRID_MAP_FILE has changed since this program started" >&2
    echo "No changes will be made." >&2
    Cleanup
    exit 1
else
    # Restore proper permissions to original grid map file
    chmod 644 $GRID_MAP_FILE
    if [ $? -ne 0 ] ; then
        echo "ERROR: Could not change mode of $GRID_MAP_FILE" >&2
        Cleanup
        exit 1
    fi

    cp $GRID_MAP_FILE_COPY $GRID_MAP_FILE.old
    if [ $? -ne 0 ] ; then
        echo "ERROR: Could not create a copy of $GRID_MAP_FILE" >&2
        Cleanup
        exit 1
    fi
fi

if [ "$updated_existing_dn" = "false" ]; then
    # format new entry of dn and ln 
    new_ln_entry=`echo $ln | sed -e 's/ /,/g'`
    new_mapfile_entry="\"$dn\" $new_ln_entry"
    # Append new entry to original grid map file
    $ECHO_DRYRUN "Appending new entry $new_mapfile_entry"
    if [ "$ECHO_DRYRUN" = "echo" ] ; then
        echo "Since ( dryrun, -d ) option was used no actions were carried out"
        Cleanup
        exit 0
    fi

    echo $new_mapfile_entry >> $GRID_MAP_FILE
    if [ $? -ne 0 ] ; then
        echo "ERROR: Could not add new entry to $GRID_MAP_FILE" >&2
        Cleanup
        exit 1
    else
        echo "New entry:"
        echo "$new_mapfile_entry"
        echo "(1) entry added"
    fi
else
    echo "DN $dn already exists."

    $ECHO_DRYRUN "Updating entry to $updated_existing_dn"
    if [ "$ECHO_DRYRUN" = "echo" ] ; then
        echo "Since ( dryrun, -d ) option was used no actions were carried out"
        Cleanup
        exit 0
    fi

    mv $NEW_GRID_MAP_FILE $GRID_MAP_FILE

    if [ $? -ne 0 ] ; then
        echo "ERROR: Could not create a new $GRID_MAP_FILE" >&2
        Cleanup
    else
        if test -n "$added_map" ; then
            if test -n "$omitted_map" ; then
                omitted_map=", already present and ignored:$omitted_map"
            fi
            echo "(added mappings:$added_map$omitted_map)"
            echo "Updated entry:"
            echo "$updated_existing_dn"
            echo "(1) entry modified"
        else
            echo "No changes were made - already present and ignored:$omitted_map"
        fi
    fi
fi

cp $GRID_MAP_FILE_COPY $GRID_MAP_FILE.old
if [ $? -ne 0 ] ; then
    echo "ERROR: Could not create a copy of $GRID_MAP_FILE" >&2
    Cleanup
    exit 1
fi

Cleanup

exit 0

