#!/bin/bash

# Usage: uowireless login|logout|edit
# Return values:
# 0 for succesfull log-in
# 1 for server authorization failure
# 2 for (probably internal) error

## This program is controlled by the following environment variables:

# VISUAL, EDITOR determine the program used for credential file editing.
# TMPDIR determines the directory in which temporary files are created.
# WIRELESS_META_PW, if set, is the password used for the encrypted credential file.

# If WIRELESS_META_PW is not set, the script will prompt the user for
# a password.  Similarly, if TMPDIR is not set, the user will be
# prompted before editing a file.

## Additionally, these parameters are likely to need editing:

NETNAME="uowireless"
#Comment this line out to use plain-text file!
ENCRYPTED_CREDENTIALS="${HOME}/.wireless-encrypted"
CYPHER='des3'
CREDFILE="${HOME}/.wireless-password"
DEFAULT_EDITOR="vi"

# This script attempts to use the encrypted file first, then falls
# back to the plaintext if ENCRYPTED_CREDENTIALS is undefined, or the
# file is not readable

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

# Note: To use the encrypted credential file option, create the file
# by running "uowireless edit".  Or, create it as you previously would
# have done, and then encrypt it with the following command 

# openssl enc -des3 -salt -in <plaintext_file> -out <encrypted file>

#(Then delete the plaintext file.)  You could use a secure remove
#program, but if you're that worried, you probably shouldn't be using
#this at all: All the sensitive information is held in ordinary RAM
#and could be swapped to disk or otherwise exposed.  Caveat haxxor.

# Copyright (C) 2004 Eric W. Anderson.  Released under the GNU General
# Public License (GPL), either version 2 of the License, or (at your
# option) any later version, available from:
# http://www.fsf.org/licenses/gpl.html

## Note: Requires CVS version of wget for post support! 
##   cvs -d :pserver:cvs@sunsite.dk:/pack/anoncvs login
##   CVS password:  cvs 
##   cvs -d :pserver:cvs@sunsite.dk:/pack/anoncvs checkout wget
##
## To compile for Mac OS X in a fink-y way:
##
##   ./configure --with-ssl --prefix=/sw
##   make
##   sudo make install

## Alter as needed

# Log-in options

LOGIN_URL='https://uowireless.uoregon.edu/cgi-bin/authenticate'
LOGOUT_URL='https://uowireless.uoregon.edu/cgi-bin/logout'
WGET=`which wget`

#landmarks not used, yet.
INTERNAL_LANDMARK='uowireless.uoregon.edu'
EXTERNAL_LANDMARKS=( 'www.google.com' 'c.root-servers.net' 'd.root-servers.net' 'e.root-servers.net' )

# Screen-scraping regexps
LOGIN_GOOD="SUCCESSFUL"
LOGIN_BAD="FAILURE"

LOGOUT_GOOD="SUCCESSFUL"
LOGOUT_BAD="FAILURE"

## Don't alter below here

happy_exit(){
    if [ -z $1 ]; then
        exitval=0
    else 
        exitval=$1
    fi
    
    if [ -n "${TMPFILES}" ]; then
        rm $TMPFILES
    fi
    
    exit ${exitval}
}

get_passwd(){
    if [ -z "$WIRELESS_META_PW" ]; then
        echo -n "Enter credential file password: "
         #Save terminal state, stop echo
        stty_orig=$(stty -g)
        $(stty -echo)
        read WIRELESS_META_PW
         #restore terminal
        $(stty ${stty_orig})
        echo ""
    fi
}

reasonable_tmpdir(){
    #Set TMPDIR if none
    PREFERRED_TMP="${HOME}/tmp"
    if [ -z "${TMPDIR}" ] ; then
        echo 1>&2 "You have no TMPDIR environment variable set.  To avoid this dialogue in the future, set one!"
        echo -n 1>&2 "May we try ${PREFERRED_TMP}? (y/n) "
        read use_pref
        if [ "${use_pref}" != "y" ]; then
            echo 1>&2 "You must set a TMPDIR specificying where you want your temporary file to be made, then!"
             happy_exit 2
        fi
        TMPDIR=${PREFERRED_TMP}
    fi
    #Verify that it's OK
    if [ ! -d ${TMPDIR} ]; then
        echo 1>&2  "Temp dir \"${TMPDIR}\" does not exist or is not a dir."
        happy_exit 2
    fi
    if [ ! -O ${TMPDIR} ]; then
        echo 1>&2  "Temp dir \"${TMPDIR}\" is not owned by you."
        happy_exit 2
    fi
    if [ ! -w ${TMPDIR} ]; then
        echo 1>&2  "Temp dir \"${TMPDIR}\" is not writeable by you." 
        happy_exit 2
    fi
    if [ ! -x ${TMPDIR} ]; then
        echo 1>&2  "Temp dir \"${TMPDIR}\" is not executable by you." 
        happy_exit 2
    fi
    if [ -L ${TMPDIR} ]; then
        echo 1>&2  "Temp dir \"${TMPDIR}\" is a symbolic link."
        happy_exit 2
    fi
    if [ -S ${TMPDIR} ]; then
        echo 1>&2  "Temp dir \"${TMPDIR}\" is a socket."
        happy_exit 2
    fi    
}

SCRIPTNAME=$0
usage(){
    USAGE="Usage: $SCRIPTNAME login|logout|edit\n
 Return values:\n
 \t0 for succesfull log-in\n
 \t1 for server authorization failure\n
 \t2 for (probably internal) error\n
 A bad meta-password currently manifests as 2"
    echo 1>&2  -e $USAGE
}

case $1 in
    "login")
        OPERATION_URL=${LOGIN_URL}
        OPERATION_GOOD=${LOGIN_GOOD}
        OPERATION_BAD=${LOGIN_BAD}
        OPERATION="log-in"
        ;;
    "logout")
        OPERATION_URL=${LOGOUT_URL}
        OPERATION_GOOD=${LOGOUT_GOOD}
        OPERATION_BAD=${LOGOUT_BAD}
        OPERATION="log-out"
        ;;
    "edit")
        reasonable_tmpdir;
        SECURE_MASK=0177
        oldmask=$(umask)
        umask ${SECURE_MASK}
        EDIT_FILE=`mktemp -t` || happy_exit 2
        umask ${oldmask}
        # Check edit file safety
        if [ ! -O ${EDIT_FILE} ] || [ ! -f ${EDIT_FILE} ] || [ ! -r ${EDIT_FILE} ] || [ ! -w ${EDIT_FILE} ]; then
            echo 1>&2 "Temp fil ${EDIT_FILE} has incorrect permissions"
            echo 1>&1 "Aborting.  (not deleting)"
            happy_exit 2
        fi
        TMPFILES="${TMPFILES} ${EDIT_FILE}"
        get_passwd
        if [ -e ${ENCRYPTED_CREDENTIALS} ]; then 
            #decrypt
            $(echo ${WIRELESS_META_PW} | openssl enc -d -${CYPHER} -in ${ENCRYPTED_CREDENTIALS} -out ${EDIT_FILE} -pass stdin>/dev/null 2>&1)
            if [ $? != 0 ] ; then
                echo 1>&2 "Decryption failed.  Bad password?"
                echo 1>&2 "If you forgot the password, delete ${ENCRYPTED_CREDENTIALS}."                
                happy_exit 2
            fi
        else
            echo "#File formar:" > ${EDIT_FILE}
            echo "#Netname username password" >> ${EDIT_FILE}
        fi
        
        #Choose editor: $VISUAL > $EDITOR > our default
        EDITWITH=${VISUAL}
        [ -n "${EDITWITH}" ] || EDITWITH=${EDITOR}
        [ -n "${EDITWITH}" ] || EDITWITH=${DEFAULT_EDITOR}
        
        #edit
        ${EDITWITH} ${EDIT_FILE}

        #encrypt
        $(echo ${WIRELESS_META_PW} | openssl enc -e -salt -${CYPHER} -in ${EDIT_FILE} -out ${ENCRYPTED_CREDENTIALS} -pass stdin>/dev/null 2>&1)
        happy_exit 0
        ;;
    * )
        usage
        happy_exit 2
        ;;
esac

READCOMMAND="cat ${CREDFILE}"

if [ ! -r ${CREDFILE} ] && [ ! -r ${ENCRYPTED_CREDENTIALS} ] ; then
    echo -e 1>&2 "ERROR:\tNeither the plain-text nor encrypted  credential file is readable!"
    happy_exit 2
fi

if [ x${ENCRYPTED_CREDENTIALS} != "x" ]; then
    if [ -r ${ENCRYPTED_CREDENTIALS} ]; then
        get_passwd
        READCOMMAND="echo ${WIRELESS_META_PW} | openssl enc -d -${CYPHER} -in ${ENCRYPTED_CREDENTIALS} -pass stdin"
    else
        echo -e 1>&2 "WARNING:\tThe variable ENCRYPTED_CREDENTIALS is defined, but"
        echo -e 1>&2 "\t\tthe file ${ENCRYPTED_CREDENTIALS} does not exist or is not readable!"
        echo -e 1>&2 "\t\tFalling back to plain-text file ${CREDFILE}."
    fi  
fi


#USERNAME=$(awk "BEGIN {FS=\"[[:space:]+]\"}; /^${NETNAME}/ {print \$2}" < ${CREDFILE})
#PASSWORD=$(awk "BEGIN {FS=\"[[:space:]+]\"}; /^${NETNAME}/ {print \$3}" < ${CREDFILE})
USERNAME=$(eval ${READCOMMAND} 2>/dev/null | awk "BEGIN {FS=\"[[:space:]+]\"}; /^${NETNAME}/ {print \$2}")
PASSWORD=$(eval ${READCOMMAND} 2>/dev/null | awk "BEGIN {FS=\"[[:space:]+]\"}; /^${NETNAME}/ {print \$3}")

#echo ${READCOMMAND}
#foo=$(eval ${READCOMMAND})
#echo -r $foo



## Pre-check - wget version
WGET_VERSION=`${WGET} --version | awk 'BEGIN {FS="[[:space:]+]|+"}; /GNU Wget/ {print $3}'`

case ${WGET_VERSION} in
    1.9)
        ;;
    *)
        echo 1>&2 "Version ${WGET_VERSION} of wget is unknown and may not support post."
        echo 1>&2 "Upgrade wget to at least 1.9 (in CVS as of 23 Jun 2004), or fix this script."
        happy_exit 2
        ;;
esac

AUTH_FILE=`mktemp` || happy_exit 2
TMPFILES="${TMPFILES} ${AUTH_FILE}"
OUT_FILE=`mktemp`|| happy_exit 2
TMPFILES="${TMPFILES} ${OUT_FILE}"
${WGET} --post-data="username=${USERNAME}&password=${PASSWORD}"  ${OPERATION_URL} -O ${AUTH_FILE} >/dev/null 2> ${OUT_FILE}

# First check for success - did WGET get *SOMETHING*
EXITCODE=$?
if [ $EXITCODE -ne 0 ]; then
    echo 1>&2 "Error: ${WGET} exited with value ${EXITCODE}"
    happy_exit 2
fi

# Second check: What does the server say?

#If we're good, we're done
grep -e "${OPERATION_GOOD}" ${AUTH_FILE} 2>&1 1>/dev/null
if [ $? -eq 0 ]; then
     happy_exit 0
fi

#Otherwise, maybe we were rejected
grep -e "${OPERATION_BAD}" ${AUTH_FILE} 2>&1 1>/dev/null
if [ $? -eq 0 ]; then
    echo 1>&2 "${OPERATION}rejected."
    happy_exit 1
fi

# Clean up
echo 1>&2 "Server response not understood"
happy_exit 2