Freeradius authentication using module exec source code

จาก Wiki Opensource
				FreeRADIUS v2.X
				FreeRADIUS v3.X
			   External authentication module
				    using exec
				       and
				    my modules 
				      myimap
				    imap-auth
				     my-auth

				 Example test case
			       authentication method: 
			  shadow and webservice (default)
			      mail,ldap,ssh (options)

				post authentication: 
				allow all (default)
			   allow selected users (options)


			       updated: 20/02/2562

			  Written by Wiboon Warasittichai
			Work at Prince of Songkla University


Note:

FreeRADIUS 3.0 config files are in /etc/freeradius/3.0/
	clients.conf
	mods-enabled/psuradius
	myusers
	sites-available/default

"/etc/freeradius/sites-available/default"

# my updated 2562-02-20
authorize {
...
	#unix

	#
	#  Read the 'users' file
	###     files
	my-log-authen
	myimap
...
}

authenticate {
        Auth-Type imap-auth {
                imap-auth {
                        userlock = 1
                }

        if (userlock) {
                update reply {
                        Reply-Message := "PREBLACKLIST"
                }
                my-log-authen-preblacklist
                reject
        }
        if (notfound) {
                update reply {
                        Reply-Message := "USER AUTHEN FAIL"
                }
                my-log-authen-fail
                reject
        }
        }
        #
...
}

preacct {
	preprocess

	# my append update for pGina no attribute Framed-IP-Address
	if (NAS-IP-Address != 127.0.0.1) {	
		update request {
			Framed-IP-Address = "%{NAS-IP-Address}"
		}
	}

...
	#
	#  Read the 'acct_users' file
	#files
}

}

accounting {
...
	detail
	my-log-account
...
}

post-auth {
        my-auth
        if (updated) {
                update reply {
                        Reply-Message := "BLACKLIST"
                }
                my-log-authen-blacklist
                reject
        }
        if (notfound) {
                update reply {
                        Reply-Message := "NOTALLOW"
                }
                my-log-authen-notallow
                reject
        }
        if (ok) {
                update reply {
                        Reply-Message := "PASS"
                }
                my-log-authen-pass
        }
        #
...
	#exec
...
}


/etc/freeradius/modules/psuradius

# updated by WIBOON 2561-07-26

exec my-log-account {
     wait = no
     program = "/bin/sh /etc/freeradius/log-radius-account.sh %l %{Packet-Src-IP-Address}"
     input_pairs = request
} 

exec my-log-authen {
     wait = no
     program = "/bin/sh /etc/freeradius/log-radius-authen.sh %l %{Packet-Src-IP-Address}"
     input_pairs = request
}

exec my-log-authen-preblacklist {
     wait = no
     program = "/bin/sh /etc/freeradius/log-radius-authen-preblacklist.sh %l %{Packet-Src-IP-Address}"
     input_pairs = request
}

exec my-log-authen-blacklist {
     wait = no
     program = "/bin/sh /etc/freeradius/log-radius-authen-blacklist.sh %l %{Packet-Src-IP-Address}"
     input_pairs = request
}

exec my-log-authen-notallow {
     wait = no
     program = "/bin/sh /etc/freeradius/log-radius-authen-notallow.sh %l %{Packet-Src-IP-Address}"
     input_pairs = request
}

exec my-log-authen-fail {
     wait = no
     program = "/bin/sh /etc/freeradius/log-radius-authen-fail.sh %l %{Packet-Src-IP-Address}"
     input_pairs = request
}

exec my-log-authen-pass {
     wait = no
     program = "/bin/sh /etc/freeradius/log-radius-authen-pass.sh %l %{Packet-Src-IP-Address}"
     input_pairs = request
}

exec my-auth {
        program = "/bin/sh /etc/freeradius/my-authen.sh %l %{Packet-Src-IP-Address}"
        wait = yes
        input_pairs = request
        packet_type = Access-Accept
}

exec imap-auth {
        program = "/bin/sh /etc/freeradius/imap-authen.sh %{Packet-Dst-IP-Address} %{Packet-Src-IP-Address}"
	wait = yes
	input_pairs = request
}

files myimap  {
    usersfile = ${confdir}/myusers
}


/etc/freeradius/myusers

# updated by WIBOON 2556-02-02
DEFAULT Auth-Type := imap-auth


/etc/freeradius/imap-authen.sh

#!/bin/bash
#
# updated by WIPAT 2555-03-08
# updated by WIBOON 2559-11-02 added comments for clear.
#
# exit 0 is valid ; exit > 0 is invalid

CHECK_PREBLACKLIST="YES"
PREBLACKLIST_FILE="/etc/freeradius/preblacklist.txt"
#
#set default to 1.linux account and 2.PSU Passport web service.
#
# AUTHEN_SHADOW mean using linux account on this server.
AUTHEN_SHADOW="YES"
# AUTHEN_AD_LDAP mean using php-ldap method (LDAPS) in user authentication.
# must registered server IP to Computer Center.
AUTHEN_AD_LDAP="NO"
# AUTHEN_PSU_PASSPORT mean using web service method in user authentication.
AUTHEN_PSU_PASSPORT="YES"
# Others.
AUTHEN_PSU_MAIL="NO"
DEFAULT_PSU_MAIL_SERVER="mail.psu.ac.th"
AUTHEN_MAIL="NO"
DEFAULT_MAIL_SERVER="gmail.com"
AUTHEN_LDAP="NO" # PSU LDAP only (Simple LDAP)
AUTHEN_SSH="NO"
SSH_SERVER="server.domain"

NAME=$(echo ${USER_NAME} | cut -d'"' -f2)
if [ "${CHECK_PREBLACKLIST}" = "YES" ] ; then
  if [ -s ${PREBLACKLIST_FILE} ] ; then
    OUTPUT=$(grep "^${NAME}\$" ${PREBLACKLIST_FILE})
    if [ -n "${OUTPUT}" ] ; then
      echo "userlock"
      exit 6
    fi
  fi
fi
PASSWORD=$(echo ${USER_PASSWORD} | cut -d'"' -f 2-|sed "s/\"$//")
KEY="false"
MYKEY=""
if [ "${AUTHEN_SHADOW}" = "YES" ] ; then
  KEY=$(/bin/sh /etc/freeradius/check-shadow.sh "${NAME}" "${PASSWORD}")
  MYKEY=$(echo $KEY|grep -i -w "true")
  if [ -n "${MYKEY}" ] ; then
    echo "found shadow"
    exit 0
  fi
fi
# 2557-10-31 Added a php script to check LDAPS on Microsoft AD or OpenLDAP
if [ "${AUTHEN_AD_LDAP}" = "YES" ] ; then
  USER=$(echo ${NAME} | cut -d'@' -f1)
  KEY=$(/usr/bin/php /etc/freeradius/check-ad-ldap.php ${USER} ${PASSWORD} 127.0.0.1)
  MYKEY=$(echo $KEY|grep -i "true")
  if [ -n "${MYKEY}" ] ; then
    echo "found ldap"
    exit 0
  fi
fi
if [ "${AUTHEN_PSU_PASSPORT}" = "YES" ] ; then
  USER=$(echo ${NAME} | cut -d'@' -f1)
  KEY=$(/usr/bin/php /etc/freeradius/soap-authen.php ${USER} ${PASSWORD} $1 $2)
  MYKEY=$(echo ${KEY}|grep -i "true")
  if [ -n "${MYKEY}" ] ; then
    echo "found psu passport"
    exit 0
  fi
fi
if [ "${AUTHEN_PSU_MAIL}" = "YES" ] ; then
  IS_EMAIL=$(echo ${NAME}|grep "@")
  if [ -n "${IS_EMAIL}" ] ; then
    USER=$(echo ${NAME} | cut -d'@' -f1)
    DOMAIN=$(echo ${NAME} | cut -d'@' -f2)
  else
    USER=${NAME}
    DOMAIN=${DEFAULT_PSU_MAIL_SERVER}
  fi
  case ${DOMAIN} in
  psu.ac.th) 
    HOST="mail.psu.ac.th" 
    MYSCRIPT="/usr/bin/expect /etc/freeradius/check-imap.exp" ;;
  mail.psu.ac.th) 
    HOST="mail.psu.ac.th" 
    MYSCRIPT="/usr/bin/expect /etc/freeradius/check-imap.exp" ;;
  eng.psu.ac.th) 
    HOST="mail.eng.psu.ac.th:995" 
    MYSCRIPT="/usr/bin/expect /etc/freeradius/check-pop3s-gmail.exp" ;;
  pharmacy.psu.ac.th) 
    HOST="mail.pharmacy.psu.ac.th" 
    MYSCRIPT="/usr/bin/expect /etc/freeradius/check-imap.exp" ;;
  pn.psu.ac.th) 
    HOST="bunga.pn.psu.ac.th" 
    MYSCRIPT="/usr/bin/expect /etc/freeradius/check-imap.exp" ;;
  esac
  KEY=$(${MYSCRIPT} ${HOST} "${USER}" "${PASSWORD}")
  MYKEY=$(echo $KEY|grep -i -w "true")
  if [ -n "${MYKEY}" ] ; then
    echo "found psu mail"
    exit 0
  fi
fi
if [ "${AUTHEN_MAIL}" = "YES" ] ; then
  IS_EMAIL=$(echo ${NAME}|grep "@")
  if [ -n "${IS_EMAIL}" ] ; then
    USER=$(echo ${NAME} | cut -d'@' -f1)
    DOMAIN=$(echo ${NAME} | cut -d'@' -f2)
  else
    USER=${NAME}
    DOMAIN=${DEFAULT_MAIL_SERVER}
  fi
  case ${DOMAIN} in
  gmail.com) 
    HOST="pop.gmail.com:995" 
    USER=${NAME}
    MYSCRIPT="/usr/bin/expect /etc/freeradius/check-pop3s-gmail.exp" ;;
  hotmail.com) 
    HOST="pop3.live.com:995" 
    USER=${NAME}
    MYSCRIPT="/usr/bin/expect /etc/freeradius/check-pop3s-hotmail.exp" ;;
  live.com) 
    HOST="pop3.live.com:995" 
    USER=${NAME}
    MYSCRIPT="/usr/bin/expect /etc/freeradius/check-pop3s-hotmail.exp" ;;
  yahoo.com) 
    HOST="pop.mail.yahoo.com:995" 
    USER=${NAME}
    MYSCRIPT="/usr/bin/expect /etc/freeradius/check-pop3s-gmail.exp" ;;
  *)
    HOST=${DOMAIN} 
    MYSCRIPT="/usr/bin/expect /etc/freeradius/check-pop3.exp" ;;
  esac
  KEY=$(${MYSCRIPT} ${HOST} "${USER}" "${PASSWORD}")
  MYKEY=$(echo $KEY|grep -i -w "true")
  if [ -n "${MYKEY}" ] ; then
    echo "found mail"
    exit 0
  fi
fi
if [ "${AUTHEN_LDAP}" = "YES" ] ; then
  KEY=$(/bin/sh /etc/freeradius/check-ldap.sh "${NAME}" "${PASSWORD}")
  MYKEY=$(echo $KEY|grep -i -w "true")
  if [ -n "${MYKEY}" ] ; then
    echo "found ldap"
    exit 0
  fi
fi
if [ "${AUTHEN_SSH}" = "YES" ] ; then
  KEY=$(/usr/bin/expect /etc/freeradius/check-ssh.exp ${SSH_SERVER} "${NAME}" "${PASSWORD}")
  MYKEY=$(echo $KEY|grep -i -w "true")
  if [ -n "${MYKEY}" ] ; then
    echo "found ssh"
    exit 0
  fi
fi
echo "notfound"
exit 7
#


/etc/freeradius/my-authen.sh

#!/bin/bash
#
# updates by WIPAT 2554-09-01
# updates by WIBOON 2556-02-22
#
# exit 0 is valid ; exit > 0 is invalid

CHECK_BLACKLIST="YES"
BLACKLIST_FILE="/etc/freeradius/blacklist.txt"
ALL_PASS="YES"
CHECK_VIPLIST="NO"
VIP_FILE="/etc/freeradius/viplist.txt"
CHECK_PSU_STAFF="NO"
CHECK_PSU_STUDENT="NO"

export LANG=en.US
MYDIR="/var/log/freeradius/myauthen"
if [ ! -d ${MYDIR} ] ; then
  mkdir -p ${MYDIR}
fi
TODAY=$(date "+%Y%m%d")
MYFILE="${MYDIR}/${TODAY}"
if [ ! -e ${MYFILE} ] ; then
  touch ${MYFILE}
fi
MYTIME=$(echo $1|awk '{print strftime("%Y%m%d:%H:%M:%S",$1)}')
MYUSER=$(echo $USER_NAME | cut -d'"' -f2)
#uncomment to debug
#printenv > /tmp/exec-program-wait
if [ "${CHECK_BLACKLIST}" = "YES" ] ; then
  if [ -s ${BLACKLIST_FILE} ] ; then
    OUTPUT=$(grep "^${MYUSER}\$" ${BLACKLIST_FILE})
    if [ -n "${OUTPUT}" ] ; then
      echo "blacklist"
      exit 9
    fi
  fi
fi
if [ "${ALL_PASS}" = "YES" ] ; then
  exit 0
fi 
if [ "${CHECK_VIPLIST}" = "YES" ] ; then
  if [ -s ${VIP_FILE} ] ; then
    OUTPUT=$(grep "^${MYUSER}\$" ${VIP_FILE})
    if [ -n "${OUTPUT}" ] ; then
      echo "viplist allow"
      exit 0
    fi
  fi
fi
if [ "${CHECK_PSU_STAFF}" = "YES" ] ; then
  OUTPUT=$(echo "${MYUSER}"|grep "@")
  if [ -z "${OUTPUT}" ] ; then
    OUTPUT=$(echo "${MYUSER}"|grep "^[[:digit:]]")
    if [ -z "${OUTPUT}" ] ; then
      echo "psu_staff allow"
      exit 0
    fi
  else
    OUTPUT=$(echo "${MYUSER}"|grep "psu.ac.th")
    if [ -n "${OUTPUT}" ] ; then
      echo "psu_staff allow"
      exit 0
    fi
  fi
fi
if [ "${CHECK_PSU_STUDENT}" = "YES" ] ; then
  OUTPUT=$(echo "${MYUSER}"|grep "@")
  if [ -z "${OUTPUT}" ] ; then
    MYSTUDENT="....."
#    MYSTUDENT="..105"
    OUTPUT=$(echo "${MYUSER}"|grep "^${MYSTUDENT}")
    if [ -n "${OUTPUT}" ] ; then
      echo "psu_student allow"
      exit 0
    fi
  fi
fi
echo "not allow"
exit 7
#


/etc/freeradius/log-radius-account.sh

#!/bin/bash
#
# updated by WIPAT 2554-11-11
# updated by WIBOON 2561-07-26

export LANG=en.US
MYDIR="/var/log/freeradius/myaccount"
if [ ! -d ${MYDIR} ] ; then
  mkdir -p ${MYDIR}
fi
TODAY=$(date "+%Y%m%d")
MYFILE="${MYDIR}/${TODAY}"
if [ ! -e ${MYDIR} ] ; then
  touch ${MYDIR}
fi
MYTIME=$(echo $1|awk '{print strftime("%Y%m%d:%H:%M:%S",$1)}')
echo "${MYTIME};${USER_NAME};$2;$1;${ACCT_UNIQUE_SESSION_ID};${ACCT_STATUS_TYPE};${ACCT_SESSION_TIME};${FRAMED_IP_ADDRESS};${CALLING_STATION_ID};${NAS_IP_ADDRESS};${CALLED_STATION_ID}" >> ${MYFILE}


/etc/freeradius/log-radius-authen-blacklist.sh

#!/bin/bash

# updated by WIPAT 2554-01-31
# updated by WIBOON 2556-02-22

export LANG=en.US
MYDIR="/var/log/freeradius/myauthen"
if [ ! -d ${MYDIR} ] ; then
  mkdir -p ${MYDIR}
fi
TODAY=$(date "+%Y%m%d")
MYFILE="${MYDIR}/${TODAY}"
if [ ! -e ${MYFILE} ] ; then
  touch ${MYFILE}
fi
# Old method
#MYTIME=$(echo $1|awk '{print strftime("%Y%m%d:%H:%M:%S",$1)}')
#echo "${MYTIME};${USER_NAME};$2;$1;BLACKLIST" >> ${MYFILE}

# New method
# ${MYFILE}.${USER_NAME}.$1 from log-radius-authen.sh
echo "BLACKLIST" | paste -d ';' ${MYFILE}.${USER_NAME}.$1 - >> ${MYFILE}
rm -f ${MYFILE}.${USER_NAME}.$1
#


/etc/freeradius/log-radius-authen-notallow.sh

#!/bin/bash

# updated by WIPAT 2554-01-31
# updated by WIBOON 2556-02-22

export LANG=en.US
MYDIR="/var/log/freeradius/myauthen"
if [ ! -d ${MYDIR} ] ; then
  mkdir -p ${MYDIR}
fi
TODAY=$(date "+%Y%m%d")
MYFILE="${MYDIR}/${TODAY}"
if [ ! -e ${MYFILE} ] ; then
  touch ${MYFILE}
fi
# Old method
#MYTIME=$(echo $1|awk '{print strftime("%Y%m%d:%H:%M:%S",$1)}')
#echo "${MYTIME};${USER_NAME};$2;$1;NOTALLOW" >> ${MYFILE}

# New method
# ${MYFILE}.${USER_NAME}.$1 from log-radius-authen.sh
echo "NOTALLOW" | paste -d ';' ${MYFILE}.${USER_NAME}.$1 - >> ${MYFILE}
rm -f ${MYFILE}.${USER_NAME}.$1
#


/etc/freeradius/log-radius-authen-preblacklist.sh

#!/bin/bash

# updated by WIPAT 2554-01-31
# updated by WIBOON 2556-02-22

export LANG=en.US
MYDIR="/var/log/freeradius/myauthen"
if [ ! -d ${MYDIR} ] ; then
  mkdir -p ${MYDIR}
fi
TODAY=$(date "+%Y%m%d")
MYFILE="${MYDIR}/${TODAY}"
if [ ! -e ${MYFILE} ] ; then
  touch ${MYFILE}
fi
# Old method
#MYTIME=$(echo $1|awk '{print strftime("%Y%m%d:%H:%M:%S",$1)}')
#echo "${MYTIME};${USER_NAME};$2;$1;PREBLACKLIST" >> ${MYFILE}

# New method
# ${MYFILE}.${USER_NAME}.$1 from log-radius-authen.sh
echo "PREBLACKLIST" | paste -d ';' ${MYFILE}.${USER_NAME}.$1 - >> ${MYFILE}
rm -f ${MYFILE}.${USER_NAME}.$1
#


/etc/freeradius/log-radius-authen-fail.sh

#!/bin/bash

# updated by WIPAT 2554-01-31
# updated by WIBOON 2556-02-22

export LANG=en.US
MYDIR="/var/log/freeradius/myauthen"
if [ ! -d ${MYDIR} ] ; then
  mkdir -p ${MYDIR}
fi
TODAY=$(date "+%Y%m%d")
MYFILE="${MYDIR}/${TODAY}"
if [ ! -e ${MYFILE} ] ; then
  touch ${MYFILE}
fi
# Old method
#MYTIME=$(echo $1|awk '{print strftime("%Y%m%d:%H:%M:%S",$1)}')
#echo "${MYTIME};${USER_NAME};$2;$1;FAIL" >> ${MYFILE}

# New method
# ${MYFILE}.${USER_NAME}.$1 from log-radius-authen.sh
echo "FAIL" | paste -d ';' ${MYFILE}.${USER_NAME}.$1 - >> ${MYFILE}
rm -f ${MYFILE}.${USER_NAME}.$1
#


/etc/freeradius/log-radius-authen.sh

#!/bin/bash

# updated by WIPAT 2554-01-31
# updated by WIBOON 2556-02-24

export LANG=en.US
MYDIR="/var/log/freeradius/myauthen"
if [ ! -d ${MYDIR} ] ; then
  mkdir -p ${MYDIR}
fi
TODAY=$(date "+%Y%m%d")
MYFILE="${MYDIR}/${TODAY}.${USER_NAME}.$1"
if [ ! -e ${MYFILE} ] ; then
  touch ${MYFILE}
fi
MYTIME=$(echo $1|awk '{print strftime("%Y%m%d:%H:%M:%S",$1)}')
echo "${MYTIME};${USER_NAME};$2;$1;CHECK_IN;${CALLING_STATION_ID};${NAS_IP_ADDRESS};${CALLED_STATION_ID}" >> ${MYFILE}


/etc/freeradius/log-radius-authen-pass.sh

#!/bin/bash

# updated by WIBOON 2556-02-24

export LANG=en.US
MYDIR="/var/log/freeradius/myauthen"
if [ ! -d ${MYDIR} ] ; then
  mkdir -p ${MYDIR}
fi
TODAY=$(date "+%Y%m%d")
MYFILE="${MYDIR}/${TODAY}"
if [ ! -e ${MYFILE} ] ; then
  touch ${MYFILE}
fi

# New method
# ${MYFILE}.${USER_NAME}.$1 from log-radius-authen.sh
echo "PASS" | paste -d ';' ${MYFILE}.${USER_NAME}.$1 - >> ${MYFILE}
rm -f ${MYFILE}.${USER_NAME}.$1


Example setting test case:

imap-authen.sh: Allow shadow and psu passport
my-authen.sh: Allow selected users in viplist.txt
/etc/freeradius/preblacklist.txt 
susan

/etc/freeradius/blacklist.txt 
bob

/etc/freeradius/viplist.txt 
mama
john

Example log output /var/log/freeradius/myauthen/yyyymmdd:
Line 1:20130130:21:49:54;"susan";127.0.0.1;1359557394;CHECK_IN;;127.0.1.1;;PREBLACKLIST
Line 2:20130130:21:50:11;"bob";127.0.0.1;1359557411;CHECK_IN;;127.0.1.1;;BLACKLIST
Line 3:20130130:21:55:14;"john";127.0.0.1;1359557714;CHECK_IN;;127.0.1.1;;PASS
Line 4:20130130:21:57:20;"john";127.0.0.1;1359557840;CHECK_IN;;127.0.1.1;;FAIL
Line 5:20130130:21:58:42;"johny";127.0.0.1;1359557922;CHECK_IN;;127.0.1.1;;FAIL
Line 6:20130130:21:59:11;"mama";127.0.0.1;1359557951;CHECK_IN;;127.0.1.1;;PASS
Line 7:20130130:22:08:24;"chalie";127.0.0.1;1359558504;CHECK_IN;;127.0.1.1;;NOTALLOW

Meaning:
Line 1: login is not OK (username included in preblacklist.txt, ignored to check password)
Line 2: login is not OK (password is correct but username included in blacklist.txt)
Line 3: login is OK (password is correct and username included in viplist.txt)
Line 4: login is not OK (password is incorrect)
Line 5: login is not OK (username is incorrect)
Line 6: login is OK (password is correct and username included in viplist.txt)
Line 7: login is not OK (password is correct but username not included in viplist.txt)


Return value	
#
#  The return value of the program run determines the result
#  of the exec instance call as follows:
#  (See doc/configurable_failover for details)
#
#  < 0 : fail      the module failed
#  = 0 : ok        the module succeeded
#  = 1 : reject    the module rejected the user
#  = 2 : fail      the module failed
#  = 3 : ok        the module succeeded
#  = 4 : handled   the module has done everything to handle the request
#  = 5 : invalid   the user's configuration entry was invalid
#  = 6 : userlock  the user was locked out
#  = 7 : notfound  the user was not found
#  = 8 : noop      the module did nothing
#  = 9 : updated   the module updated information in the request
#  > 9 : fail      the module failed
#