#!/bin/sh

uid=`sed -ne "/^$USER/s/[^:]*:[^:]*:\([^:]*\):.*/\1/p" /etc/passwd`

# Do our best to deal with systems integrated with LDAP/NIS/etc:
if [ -z "$uid" -a -n "$UID" ]; then
    uid="$UID" # bash appears to set the UID variable?
fi
if [ -z "$uid" ]; then
    uid=606 # lame
fi

tk4base=/tmp/tkt${uid}
tk5base=FILE:/tmp/krb5cc_u${uid}
alt_tk5base=FILE:/tmp/mykrb5cc_${uid}

if [ ."`uname -s`" = ."Darwin" ]; then
    export RUNNING_ON_DARWIN=yes
fi

# We need these exported someplaces, and if a subfunction exports
# them, they will remain exported in the surrounding world, so we may
# as well just export them globally to avoid confusion.
export KRB5CCNAME KRBTKFILE

standardize_tkfiles () {
    if [ "$RUNNING_ON_DARWIN" = "yes" ]; then
        ## We're on an OSX box. Tickets are SHM-based, so there are no
        ## files to move around.
	return
    fi

    ## If KRBTKFILE does not begin with tk4base, rename any tickets it may
    ## point to, and reset KRBTKFILE.
    case "$KRBTKFILE" in
        "$tk4base"*) ;;
        *)
	    if [ -r "$KRBTKFILE" ]; then
	        mv "$KRBTKFILE"     "$tk4base"
	        mv "$KRBTKFILE".shm "$tk4base".shm >/dev/null 2>&1
	    fi ;;
    esac

    ## Ditto KRB5CCNAME/tk5base.
    case "$KRB5CCNAME" in
        "$tk5base"*) ;;
        "$alt_tk5base"*) ;;
        *)
	    KRB5FILE=`echo "$KRB5CCNAME" | sed -e 's/FILE://'`
	    NEWKRB5FILE=`echo "$tk5base" | sed -e 's/FILE://'`
	    if [ -r "$KRB5FILE" ]; then
	        mv "$KRB5FILE" "$NEWKRB5FILE"
	    fi ;;
    esac
}

#### On OSX 10.3 (Tiger), "klist -A" output looks like this:
## Superessive$ klist -A
## Kerberos 5 ticket cache: 'API:0'
## Default Principal: nocturne@CSAIL.MIT.EDU
## Valid Starting     Expires            Service Principal
## 03/29/06 12:47:00  03/29/06 22:47:00  krbtgt/CSAIL.MIT.EDU@CSAIL.MIT.EDU
##         renew until 04/05/06 13:47:00
## 03/29/06 12:47:03  03/29/06 22:47:00  krbtgt/ATHENA.MIT.EDU@CSAIL.MIT.EDU
##         renew until 04/05/06 13:47:00
## 
## -------------------------------------------------------------------------------
## Kerberos 5 ticket cache: 'API:Initial default ccache'
## Default Principal: nocturne@ATHENA.MIT.EDU
## Valid Starting     Expires            Service Principal
## 03/31/06 12:12:46  03/31/06 22:12:46  krbtgt/ATHENA.MIT.EDU@ATHENA.MIT.EDU
##         renew until 04/07/06 13:12:46
## 03/31/06 12:15:39  03/31/06 22:12:46  afs/athena.mit.edu@ATHENA.MIT.EDU
##         renew until 04/07/06 13:12:46
## 
## Kerberos 4 ticket cache: 'Initial default ccache'
## Default Principal: nocturne@ATHENA.MIT.EDU
## Issued             Expires            Service Principal
## 03/31/06 12:12:46  03/31/06 22:12:46  krbtgt.ATHENA.MIT.EDU@ATHENA.MIT.EDU

darwin_sub1 () {
    sed -e "s/^Kerberos 5 ticket cache: 'API:\([^']*\)'\$/\1/"
}


darwin_ccname_for () {
    # Accepts a kerberos principal name as an argument.
    # If the system ccache has a ticketfile for that principal,
    # outputs the string FOO which could then either be passed to
    # "kswitch -c FOO", or used when setting KRB5CCNAME to "API:FOO".

    # (Note that as of OSX 10.4.1, kswitch strips off any leading
    # "API:" from its -c argument before processing.)

    princname="$1"

    ## regexp-escape any forward slashes
    rxprincname="`echo "$princname" | sed -e 's/\//\\\\\//'`"

    ccname="`klist -A \
              | awk 'BEGIN {cachename=""}
                    /^Kerberos 5 ticket cache:/ {cachename=$0}
                    /^Kerberos 4 ticket cache:/ {cachename=""}
                    /^Default Principal: '"$rxprincname"'$/ {
                        if (cachename != "") print cachename }'`"

    ccname="`echo "$ccname" | darwin_sub1`"

    [ -n "$ccname" ] && echo "$ccname"
}

have_valid_tix_for () {
    if [ "$RUNNING_ON_DARWIN" = "yes" ]; then
        darwin_ccname="`darwin_ccname_for "$newprinc"`"
        if [ -z "$darwin_ccname" ]; then
            return 1 # failure: no tickets currently cached
        else
            # tickets are cached. May or may not be valid.
            tixloc="API:$darwin_ccname"
        fi
    else
        tixloc=${tk5base}${postfix}
    fi

    ## At one point, there was much grossness surrounding which flag
    ## "klist" needed for silent ticket-validity testing. In
    ## particular, Athena 8.1 systems used "klist -t", while most
    ## other Kerberos builds used "klist -s". Hopefully, "klist -t" is
    ## now quite dead.
    klisttest="-s"

    if env KRB5CCNAME="$tixloc" klist ${klisttest}; then
        return 0
    else
        return 1
    fi
}

export_var () {
    varname="$1"

    varval="`eval echo \\\$"${varname}"`"
    case `basename "$SHELL"` in
	sh|ksh*|zsh*|bash*)
            echo "${varname}='${varval}' ;"
            echo "export ${varname} ;"
	    ;;
	tcsh*|csh*)
	    echo "setenv ${varname} '${varval}' ;"
	    ;;
    esac
}

echoexport_new_vars () {
    if [ "$RUNNING_ON_DARWIN" != "yes" ]; then
        export_var KRBTKFILE
    fi
    export_var KRB5CCNAME

    case `basename "$SHELL"` in
	sh|ksh*|zsh*|bash*)
		echo 'PS1="\\'"h${prompttail}"'$ "'
	      ;;
	tcsh*|csh*)
		if [ ! -z "$mailfrob" ]; then
		    echo "${mailfrob} ;"
		fi
                newprompt="%m${prompttail} "
		echo "set prompt = '${newprompt}'"
	      ;;
    esac
}

update_var_vals () {
    # updates env vars KRBTKFILE/KRB5CCNAME as necessary

    if [ "$RUNNING_ON_DARWIN" != "yes" ]; then
        KRBTKFILE=${tk4base}${postfix}
        KRB5CCNAME=${tk5base}${postfix}
    else
        ## On OSX, we don't know which API/SHM slot will be used for
        ## the new tix. Also, no KRBTKFILE usage.
        ccname="`darwin_ccname_for "$newprinc"`"
        if [ -n "$ccname" ]; then
            KRB5CCNAME="API:$ccname"
        fi
    fi

    if [ "${newprinc}" = "NULL" ]; then
	KRBTKFILE="/dev/null"
	KRB5CCNAME="FILE:/dev/null"
    fi
}

get_princ_flags() {
    princ="$1"

    case "$princ" in
	*@ATHENA.MIT.EDU)
	    echo "-f"
	    return ;;
    esac
}
    

switch_to_principal () {

    if [ "$newprinc" = "NULL" -o "$newprinc" = "NONE" ] \
       || have_valid_tix_for "$newprinc"; then
        : do nothing
    else
        # get tickets

        if [ "$RUNNING_ON_DARWIN" != "yes" ]; then
            KRBTKFILE=${tk4base}${postfix}
            KRB5CCNAME=${tk5base}${postfix}
        fi

	update_var_vals
	KINIT_FLAGS="`get_princ_flags $newprinc`"
        if kinit $KINIT_FLAGS "$newprinc" >&2; then
	    : success
        else
	    # kinit failed. Bail.
	    echo 'echo "tkswap: kinit failed."'
            exit 1
        fi
    fi

    update_var_vals
    echoexport_new_vars
}

standardize_tkfiles

switchto="$1"
mailfrob=""

if [ -z "$NOCTURNE_LOCALE" ]; then
    echo "Error in ${0}: NOCTURNE_LOCALE not set." >&2
    exit 1
fi
case "$NOCTURNE_LOCALE" in
 athena) thisprinc=nocturne@ATHENA.MIT.EDU
	 otherprinc=nocturne@CSAIL.MIT.EDU
	 otherpost=".csail"
	 case "$switchto" in
		athena|normal) switchto=normal
			mailfrob="unsetenv MAILHOST"
		    ;;
		csail) switchto=other
			mailfrob="setenv MAILHOST cambridge.cygnus.com"
		    ;;
	 esac ;;

 csail)  thisprinc=nocturne@CSAIL.MIT.EDU
         otherprinc=nocturne@ATHENA.MIT.EDU
	 otherpost=".ath"
	 case "$switchto" in
		athena) switchto=other
			mailfrob="setenv MAILHOST po7.mit.edu"
		    ;;
		csail|normal) switchto=normal
			mailfrob="setenv MAILHOST cambridge.cygnus.com"
		    ;;
	 esac ;;

 akamai)
	thisprinc=emumpowe@CORP.AKAMAI.COM
	otherprinc=nocturne@ATHENA.MIT.EDU
	otherpost=".ath"
	 case "$switchto" in
		akamai|normal) switchto=normal ;;
		athena)        switchto=other
                   # rpc.gssd is kind of stupid and will look at any
                   # of my krb5cc* files when trying to do nfsv4 krb
                   # auth, so use a different name.
                   tk5base=${alt_tk5base}
                   ;;
	 esac ;;
 *)      echo "Error in $0: unknown NOCTURNE_LOCALE value" \
		" '${NOCTURNE_LOCALE}'" >&2
	 exit 1 ;;
esac

case "$switchto" in
   normal) newprinc="${thisprinc}"
	   postfix=""
	   case `basename "$SHELL"` in
	       tcsh*|csh*) prompttail='%' ;;
	       *)          prompttail=''  ;;
	   esac
	;;
   other)  newprinc="${otherprinc}"
	   postfix="${otherpost}"
	   prompttail='>'
	;;
   root)   newprinc="nocturne/root@ATHENA.MIT.EDU"
	   postfix=".root"
	   prompttail='#'
	;;
   null)   newprinc="NULL"
	   postfix=".null"
	   prompttail='<>'
	;;
   extra)  newprinc="nocturne/extra@ATHENA.MIT.EDU"
	   postfix=".extra"
	   prompttail=';'
	;;
   tmp)    newprinc="NONE"
	   postfix=".tmp"
	   prompttail='><'
	;;
   *)      echo "${0} invoked erroneously, unknown arg '$switchto'" >&2
	   exit 1
        ;;
esac

switch_to_principal "$newprinc" "$postfix" "$prompttail"
