#!/bin/sh

## THIS CODE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
## WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

## Script for user authenticatication against POP3/IMAP servers, to be
## used in zmailer. Username passed to the script in command line must
## be combined from a user identifier, "%" and a domain name:
## 
##   USER%DOMAIN
## 
## The username is mapped into a POP3/IMAP server and real account name
## according to $MAILVAR/rauth.hosts. The syntax of the file is:
##
##   [user@][host|domain|.domain-tree]  [protocol][:[account@]host]
##
## To avoid autodetection, define there the protocol to be used with
## particular host or domain. Use "pop3" and "imap" or secure
## incarnations of them: "spop3" and "simap", if your fetchmail accepts
## "--plugin" paremeter and openssl suite is available:
## 
##   imap-server.domain                 imap
##   pop3-server.domain                 pop3
##   imap-or-pop3-server.domain
##   .imap-in-the-entire.domain         imap
##   secure-imap-server.domain          simap
##   secure-imap-or-pop3-server.domain  sauto
##
## The domain or even the entire domain tree can be re-mapped to
## authenticate users with a single host:
##
##   domain1                            imap:imap-server
##   .the-domain-and-subdomains         pop3:pop3-server
##   domain2                            :imap-or-pop3-server
##   
## You may also specify and re-map user names:
##
##   user@imap-or-pop3-server.domain
##   user1@domain                       imap:imap-server
##   user2@.the-domain-and-subdomains   pop3:account2@pop3-server
##
## The user name and the destination POP3/IMAP server can be re-mapped
## separately:
##
##   user3@domain                       :account3@imap-or-pop3-server
##   @domain                            pop3:@pop3-server
##   @.the-domain-and-subdomains        imap:account4@
##
## The password is read from the standard input by the fetchmail program.
## The script returns exit status 0 if the destination account can be
## entered with "fetchmail -c" and the password.
## 
## Protocol autodetection and secure connections require fetchmail >=
## 5.0.0. Use awk >= 3.0 to ignore case of the configuration data and
## the input.
##
## <Artur.Urbanowicz@man.lublin.pl>, 1999


### check if ZCONFIG variable is set from smtpserver
if [ "$ZCONFIG" = "" ] ; then
  echo -n "server configuration error"
  exit 1
fi

### check if zmailer configuration file exists and is readable
if [ ! -f $ZCONFIG ] ; then
  echo -n "server configuration error"
  exit 1
fi

### the default location of the fetchmail program and its plugin for SSL
FETCHMAIL="/usr/bin/fetchmail"
FETCHMAIL_SSL_PLUGIN="${0}-ssl-plugin"

### read the zmailer's configuration
. $ZCONFIG || exit 1

### guess the location of the configuration file
if [ "$RAUTH_HOSTS" = "" ]; then
  RAUTH_HOSTS="$MAILVAR/rauth.hosts"
fi

### check if the fetchmail program and the configuration file exist
if [ ! -x $FETCHMAIL -o ! -f $RAUTH_HOSTS ] ; then
  echo -n "server configuration error"
  exit 1
fi

### read and test the command-line argument
USER=`  echo $1 | awk -F[%!@] '{ print $1 }'`
DOMAIN=`echo $1 | awk -F[%!@] '{ print $2 }'`
TEST=`  echo $1 | awk -F[%!@] '{ print $3 }'`
if [ "$USER" = "" -o "$DOMAIN" = "" -o "$TEST" != "" ] ; then
  echo -n "user name must be entered in form: USER%DOMAIN"
  exit 1
fi

### re-map the username to the protocol, server and real account
RAUTH_SPEC=`
  awk -v user=$USER -v domain=$DOMAIN -v default="auto" '
    BEGIN{ IGNORECASE=1; u=tolower(user); d=tolower(domain) }
    /^[^#]/{ a[tolower($1)] = $2 != "" ? $2 : default }
    END{ if( (s=a[u"@"d]) || (s=a[u"@."d]) || (s=a["."d]) ) { print s; exit 1 }
         do{ if( (s=a[u"@"d]) || (s=a[d]) ) { print s; exit 1 }
         }while( d && sub("^\.?[^.]*","",d) )
         if( s=a[u"@"] ) { print s; exit 1 }
    }' $RAUTH_HOSTS 2>/dev/null
`
if [ $? != 1 -o "$RAUTH_SPEC" = "" ] ; then
  echo -n "user \"$USER%$DOMAIN\" is not allowed here"
  exit 1
fi

### parse the result
RAUTH_PROT=`echo $RAUTH_SPEC | awk -F[:] -v default=auto '
  { print $1 ? $1 : default }'`
RAUTH_USER=`echo $RAUTH_SPEC | awk -F[:] -v default=$USER '
  { n=index($2,"@"); print (n>1) ? substr($2,1,n-1) : default }'`
RAUTH_HOST=`echo $RAUTH_SPEC | awk -F[:] -v default=$DOMAIN '
  { n=index($2,"@"); print (h=substr($2,n+1)) ? h : default }'`

### add the SSL plugin directive to the fetchmail parameters if needed
if [ -x $FETCHMAIL_SSL_PLUGIN ] ; then
  case $RAUTH_PROT in
    spop3)
      FETCHMAIL_OPTS="--plugin $FETCHMAIL_SSL_PLUGIN"
      RAUTH_PROT="pop3"
      ;;
    simap)
      FETCHMAIL_OPTS="--plugin $FETCHMAIL_SSL_PLUGIN"
      RAUTH_PROT="imap"
      ;;
    ssl|sauto)
      FETCHMAIL_OPTS="--plugin $FETCHMAIL_SSL_PLUGIN"
      RAUTH_PROT="auto"
  esac
fi

### set the command-line parameters for fetchmail
case $RAUTH_PROT in
  auto|pop3|imap)
    FETCHMAIL_OPTS="$FETCHMAIL_OPTS -p $RAUTH_PROT"
    ;;
  *)
    echo -n "server configuration error"
    exit 1
    ;;
esac

### run fetchmail to check the password on the remote server
$FETCHMAIL -f /dev/null -i /dev/null $FETCHMAIL_OPTS -c \
           -u $RAUTH_USER $RAUTH_HOST >> /dev/null 2>&1

### return the exit status and the explanation
STATUS=$?
case "$STATUS" in
 0|1)   echo -n authentication successful
        exit 0
        ;;
   2)   echo -n could not connect to host \"$RAUTH_HOST\" 
        ;;
 3|4)   echo -n authentication failed, status $STATUS
        ;;
   *)   echo -n authentication data error, status $STATUS
        ;;
esac
exit $STATUS
