Freeradius authentication using module exec source code
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 #