LinuxQuestions.org
Help answer threads with 0 replies.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices



Reply
 
Search this Thread
Old 10-03-2010, 09:03 AM   #1
frater
Member
 
Registered: Jul 2008
Posts: 106

Rep: Reputation: 23
relaying SMTP-server using authentication on a remote server using IMAP


I was given the assignment to enable our outgoing SMTP-server to be used for SMTP-clients not within our subnet. This SMTP-server is already relaying for all our customers using their source IP as a credential. A normal ISP's outgoing SMTP-server.

SMTP using a login and password on port 587 is something Sendmail supports.

After some investigating I found out that SASL was the way to go. A SASL service needs to be installed and sendmail can be configured to use that. SASL itself can be configured to use LDAP and some other methods, but I chose for the method 'rimap' (remote IMAP).

SASL would then issue a login to an IMAP-server and login to it and if the IMAP-server would allow it then it would give the Mail Agent (sendmail) that same answer.

This was almost what I wanted. On our net we have several servers and there's no way to configure sasl to use more than 1 IMAP-server. That's why I wrote a little shell script which behaves as an IMAP-server and would then find out which server it had to go to. If that server turns out to be one of ours it would login using IMAP and ask it there.

It finds out the IP of the IMAP-server by doing some A-record lookups. It will try mail.<domain>, pop.<domain> and then <domain>. If this doesn't result into an IP within our subnet it will fail.

I used xinetd to listen to port 143.
Configuring sasl & sendmail is not within the scope of this thread, but if someone needs some help...

feedback and comments about security are appreciated.

cat /etc/xinetd.d/imap
Code:
service imap
{
  socket_type = stream
  server = /usr/local/sbin/imap
  only_from = localhost
  protocol = tcp
  user = root
  group = root
  wait = no
  disable = no
  log_on_success = HOST DURATION EXIT
  log_on_failure = HOST
}
# cat /usr/local/sbin/imap
Code:
#!/bin/bash
export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin

PASSFILE=/var/log/imap.passwd
LOGFILE=/var/log/imap.log

export TTL=3600
export SERVER=
FAILED_ALLOWED=50

CURSECONDS=`date +%s`
ISODAY=`date '+%Y%m%d'`
TABCHAR=`echo -e '\t'`

CLIENT=saslauthd
LOGGING=1
DEBUG=1

write_log () {
  [ ${LOGGING} = 0 ] || echo "`date '+%b %d %H:%M'` imapd $*" >>${LOGFILE}
}

login_success () {
  write_log "${CLIENT} OK LOGIN completed."
  echo "${CLIENT} OK LOGIN completed."
  exit 0
}
login_failed () {
  write_log "${CLIENT} NO Login failed."
  echo "${CLIENT} NO Login failed."
  exit 1
}

no_login () {
  write_log "${CLIENT} NO Login command."
  echo "${CLIENT} OK."
  exit 0
}

check_domain () {
  TTL=3600
  SERVER=`host -tA "$1." | grep -o 'has address .*' | awk '{print $3}'`
  [ -z "${SERVER}" ] && return 1
  [ -z "`which dig 2>/dev/null`" ] || TTL=`dig $1 | grep -A10 'ANSWER SECTION' | grep -B10 'AUTHORITY SECTION' | grep "IN${TABCHAR}A" | head -n1 | awk '{print $2}' | tr -cd '[0-9]'`
  [ -z ${TTL} ] && TTL=3600
  [ ${DEBUG} = 0 ] || write_log "Server found using domain $1.: ${SERVER} (${TTL})"
  return 0
}

if [ -z "`which nc 2>/dev/null`" ] ; then
  write_log "nc (netcat) is not installed."
  echo "imap NO netcat (nc) installed"
  exit 1
fi

trap "" 2 3 24

echo "* OK IMAP4rev1" ; read -t 120

if [ "$REPLY" ]; then
  [ ${DEBUG} -gt 1 ] && write_log "RAW input: '`echo "${REPLY}" | tr -cd '[ -~]'`'"
  echo "${REPLY}" | grep -qi "LOGIN " || no_login

  CLIENT=`echo "${REPLY}"   | awk '{print $1}'`
  EMAIL=`echo "${REPLY}"    | awk '{print $3}' | tr -cd '[#-~]'`
  PASSWORD=`echo "${REPLY}" | awk '{print $4}' | tr -cd '[#-~]'`

  if ! echo "${EMAIL}" | grep -q '@' ; then
    write_log "Email: \"${EMAIL}\""
    login_failed
  fi

  PASSWORD64="`echo -n "${PASSWORD}" | base64`"
  [ ${DEBUG} -gt 1 ] && write_log "Email: \"${EMAIL}\" Password: \"${PASSWORD64}\""

  [ -f ${PASSFILE} ]        || touch ${PASSFILE}
  [ -f ${PASSFILE}.failed ] || touch ${PASSFILE}.failed
  PASSLINE="`grep "^${EMAIL}" ${PASSFILE}`"

  if [ ! -z "${PASSLINE}" ] ; then
    TIME=`echo "${PASSLINE}" | awk '{print $2}'`
    if [ ${CURSECONDS} -lt ${TIME} ] ; then
      PASSRESULT=`echo "${PASSLINE}" | awk '{print $3}'`
      if [ "${PASSRESULT}" == "${PASSWORD64}" ] ; then
        [ ${DEBUG} = 0 ] || write_log "Email: \"${EMAIL}\" authenticated from cache"
        login_success
      fi
    fi
  fi

  # Check if someone authenticated today
  OCCURENCE=0
  FAILLINE="`grep "^${ISODAY} ${EMAIL}" ${PASSFILE}.failed`"
  if [ ! -z "${FAILLINE}" ] ; then
    OCCURENCE=`echo "${FAILLINE}" | awk '{print $3}' | tr -cd '[0-9]'`
    if [ ${OCCURENCE} -gt ${FAILED_ALLOWED} ] ; then
      sleep 5
      # If someone has already succesfully authenticated, don't do a new lookup but just fail
      # It's already an exceptional situation which can in worst case take 24 hours
      if [ ! -z "${PASSLINE}" ] ; then
        OCCURENCE=$(( ${OCCURENCE} + 1 ))
        sed -i -e "s/^${ISODAY} ${EMAIL}.*/${ISODAY} ${EMAIL} ${OCCURENCE} ${PASSWORD}/" ${PASSFILE}.failed
        login_failed
      fi
    fi
  fi

  DOMAIN=`echo "${EMAIL}" | awk -F@ '{print $2}'`
  echo "${DOMAIN}" | grep -q '\.' || login_failed

  if ! check_domain "mail.${DOMAIN}"  ; then
    if ! check_domain "pop.${DOMAIN}"  ; then
      check_domain "${DOMAIN}"
    fi
  fi
  [ -z "${SERVER}" ] && login_failed

  # Only for our servers
  if ! echo "${SERVER}" | grep -q "89\.250\.1[789]" ; then
    write_log "Foreign address: \"${EMAIL}\" wanted to authenticate (${SERVER})"
    login_failed
  fi

  TIME_VALID=$(( ${CURSECONDS} + ${TTL}  ))

  # if imaplogin ${SERVER} ${EMAIL} ${PASSWORD} >/dev/null ; then
  if echo -e "${CLIENT} LOGIN \"${EMAIL}\" \"${PASSWORD}\"" | nc -i2 ${SERVER} 143 | grep -q "${CLIENT} OK" ; then
    if grep -q "^${EMAIL}" ${PASSFILE} ; then
      sed -i -e "s/^${EMAIL}.*/${EMAIL} ${TIME_VALID} ${PASSWORD64} ${SERVER} ${REMOTE_HOST}/" ${PASSFILE}
    else
      echo "${EMAIL} ${TIME_VALID} ${PASSWORD64} ${SERVER} ${REMOTE_HOST}" >>${PASSFILE}
    fi
    login_success
  else
    if grep "^${ISODAY} ${EMAIL}" ${PASSFILE}.failed ; then
      OCCURENCE=$(( ${OCCURENCE} + 1 ))
      sed -i -e "s/^${ISODAY} ${EMAIL}.*/${ISODAY} ${EMAIL} ${OCCURENCE} ${PASSWORD}/" ${PASSFILE}.failed
    else
      echo "${ISODAY} ${EMAIL} 1 ${PASSWORD}" >>${PASSFILE}.failed
    fi
    login_failed
  fi
fi
login_failed

Last edited by frater; 10-07-2010 at 08:21 AM. Reason: update code: logging should not reveal passwords, especially for foreign servers
 
Old 10-03-2010, 09:23 AM   #2
acid_kewpie
Moderator
 
Registered: Jun 2001
Location: UK
Distribution: Gentoo, RHEL, Fedora, Centos
Posts: 43,415

Rep: Reputation: 1968Reputation: 1968Reputation: 1968Reputation: 1968Reputation: 1968Reputation: 1968Reputation: 1968Reputation: 1968Reputation: 1968Reputation: 1968Reputation: 1968
Why not just enable SMTP authentication?? This seems really strange and OTT from what I understand of your situation.
 
Old 10-04-2010, 02:55 AM   #3
frater
Member
 
Registered: Jul 2008
Posts: 106

Original Poster
Rep: Reputation: 23
Quote:
Originally Posted by acid_kewpie View Post
Why not just enable SMTP authentication?? This seems really strange and OTT from what I understand of your situation.
I am using SMTP-authentication on Sendmail (should also work with Exim4 and Postfix).
It authenticates using Cyrus-SASL which is already builtin for sendmail.
http://www.falkotimme.com/howtos/sendmail_smtp_auth_tls

sasl supports several methods and will pass the result to the MTA.
The method I'm using is rimap (remote IMAP) which already is being used (I can only assume).

What I wrote is a fake IMAP-server which enables me to authenticate to more than 1 IMAP-server.
It will take the realm of the email-address (the domain) and then authenticates to that server.

Last edited by frater; 10-04-2010 at 06:15 AM.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Server configuration for small office server, which smtp, pop imap server and backup whitelinux Linux - Server 4 04-06-2010 12:26 PM
SMTP authentication error and server could not connected in postfix server Ravinder Singh Thakur Linux - Server 1 11-02-2009 11:22 AM
Exim4 won't let me send email relaying it to ISPs SMTP server spaceuser Linux - Server 2 09-19-2009 07:10 AM
Relaying mails through auth-SMTP server ? nileshgr Linux - Server 2 05-26-2008 12:14 AM
SMTP server responds: Relaying denied, proper authentication required SaRS AeOL Linux - Newbie 2 04-28-2008 05:52 PM


All times are GMT -5. The time now is 08:18 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration