Synology usage series 33 – Install MOTP and integrate with FreeRadius

MOTP stands for mobile one time password which provides one time password services.

Download and install otp server

  1. Login to DS as root
  2. mkdir -p /opt/usr/local/bin
  3. cd /opt/usr/local/bin
  4. Download otp server script

    # wget

  5. Install necessary library

    # ipkg install findutils
    # ipkg install md5deep
    # ipkg install bash

  6. Edit

    # vi /opt/usr/local/bin/

    Changes highlighted in red.

    # Mobile One Time Passwords (Mobile-OTP) for Java 2 Micro Edition, J2ME
    # written by Matthias Straub, Heilbronn, Germany, 2003
    # (c) 2003 by Matthias Straub
    # Version 1.05a
    # This program is free software; you can redistribute it and/or
    # modify it under the terms of the GNU Library General Public
    # License as published by the Free Software Foundation; either
    # version 2 of the License, or (at your option) any later version.
    # This software is distributed in the hope that it will be useful,
    # but WITHOUT ANY WARRANTY; without even the implied warranty of
    # Library General Public License for more details.
    # arguments:  $1 $2 $3 $4 $5
    # $1 - username
    # $2 - one-time-password that is to be checked 
    # $3 - init-secred from token (to init token: #**#)
    # $4 - user PIN
    # $5 - time difference between token and server in 10s of seconds (360 = 1 hour)
    # one-time-password must match md5(EPOCHTIME+SECRET+PIN)
    # version 1.04b, Feb. 2003
    # version 1.04c, Nov. 2008
    #  changed line 1 to ksh because of problems with todays bash an sh
    # version 1.05a, Jan. 2011
    #  changed back to bash and added in shopts line to ensure aliases handled
    #  correctly (bash is always available on any modern *nix unlike ksh)
    # ensure aliases are expanded by bash
    shopt -s expand_aliases
    if [ -e "`which md5 2>/dev/null`" ]
    	alias checksum=md5
    if [ -e "`which md5sum 2>/dev/null`" ]
    	alias checksum=md5sum
    alias checksum=md5deep
    if [ $have_md5 != "true" ]
    	echo "No md5 or md5sum available on server!"
    	exit 16
    function chop
    	num=`echo -n "$1" | wc -c | sed 's/ //g' `
    	nummin1=`expr $num "-" 1`
    	echo -n "$1" | cut -b 1-$nummin1 
    if [ ! $# -eq 5 ] ; then
    echo "USAGE: Username, OTP, Init-Secret, PIN, Offset"
    exit 14
    mkdir /opt/var/motp 2>/dev/null
    mkdir /opt/var/motp/cache 2>/dev/null
    mkdir /opt/var/motp/users 2>/dev/null
    chmod og-rxw /opt/var/motp 2>/dev/null || { echo "FAIL! Need write-access to /opt/var/motp"; exit 17; }
    chmod og-rxw /opt/var/motp/cache
    chmod og-rxw /opt/var/motp/users
    USERNAME=`echo -n "$1" | sed 's/[^0-9a-zA-Z._-]/X/g' `
    PASSWD=`echo -n "$2" | sed 's/[^0-9a-f]/0/g' `
    SECRET=`echo -n "$3" | sed 's/[^0-9a-f]/0/g' `
    PIN=`echo -n "$4" | sed 's/[^0-9]/0/g' `
    OFFSET=`echo -n "$5" | sed 's/[^0-9]/0/g' `
    EPOCHTIME=`date +%s` ; EPOCHTIME=`chop $EPOCHTIME`
    # delete old logins
    /opt/bin/find /opt/var/motp/cache -type f -cmin +5 | xargs rm 2>/dev/null
    if [ -e "/opt/var/motp/cache/$PASSWD" ]; then
    	echo "FAIL"
    	exit 15
    # account locked?
    if [ "`cat /opt/var/motp/users/$USERNAME 2>/dev/null`" == "8" ]; then
    	echo "FAIL"
    	exit 13
    EPOCHTIME=`expr $EPOCHTIME - 18`
    while [ $I -lt 36 ] ; do # 3 minutes before and after
    	OTP=`printf $EPOCHTIME$SECRET$PIN|checksum|cut -b 1-6`
    	if [ "$OTP" = "$PASSWD" ] ; then
    		/bin/touch /opt/var/motp/cache/$OTP || { echo "FAIL! Need write-access to /opt/var/motp" ; exit 17; }
    		echo "ACCEPT"
    		rm "/opt/var/motp/users/$USERNAME" 2>/dev/null
    		exit 0
    	I=`expr $I + 1`
    	EPOCHTIME=`expr $EPOCHTIME + 1`
    echo "FAIL"
    NUMFAILS=`cat "/opt/var/motp/users/$USERNAME" 2>/dev/null`
    if [ "$NUMFAILS" = "" ]; then
    NUMFAILS=`expr $NUMFAILS + 1`
    echo $NUMFAILS > "/opt/var/motp/users/$USERNAME"
    exit 11

    In case there is a newer version of this server script released in the future, here is the summary of changes:

    • line 1 should point to optware bash: /opt/bin/bash
    • The script will only looks for md5 and md5sum binary, however, we are using md5deep from optware instead. Add two lines to assign md5deep as checksum binary.
    • Add 10 to all error code, otherwise it will fail the FreeRadius server
    • Basically I’ve appended /opt to every path inside the script.
    • It need the find binary. We should use the binary provided by optware instead of using the system default binary.
  7. # chmod 755 /opt/usr/local/bin/

Download and setup Android motp client

Since I’ve an Android phone, I install the motp client to my phone.

  1. Download the android motp client ‘Mobile-OTP’ from url below

  2. Install the apk to the phone
  3. Run the Mobile-OTP.
  4. Input #**# and click ‘Calculate OTP’ button. An init-secret value will be generated. Copy the init-secret and paste it to somewhere, i.e. notepad.
  5. Input 1234 and click ‘Calculate OTP’ button again. An one time password will be generated.
  6. Now test the setup, SSH to the DiskStation as root and run the command as below:

    # /opt/usr/local/bin/ testuser [one-time-password] [Init-secret] 1234 0

    If you run the command fast enough, the script should return “ACCEPT”. If you got a “FAIL”, repeats again by generating a new one-time-password and execute the command again couple times until you got “ACCEPT”. Make sure the Init-secret and One-time-password is input correctly.

FreeRadius changes

  1. SSH to DS as root
  2. # cd /opt/etc/raddb
  3. # wget
  4. Edit /opt/etc/raddb/dictionary, add following line to the end of the file

    $INCLUDE dictionary.motp

  5. Although I don’t think this step is needed, but it is suggested by the official installation guide.
    # wget
  6. Add a test user by editing /opt/etc/raddb/users file. Add following lines to the end of the file.
    testuser Auth-Type = Accept
        Exec-Program-Wait = "/opt/usr/local/bin/ %{User-Name} %{User-Password} 123412341234 1234 0",
        Fall-Through = Yes,
        Reply-Message = "Hello, %{User-Name}"

    where 123412341234 is the init-secret and 1234 is the pin of the test user. Replace the value of init-secret with the one generated by the Android OTP client.

  7. Generate a new One-time-password using the Android OTP client (input 1234 and click ‘Calculate OTP’ button), then test the freeradius setup by executing the command below:

    # radtest testuser [one-time-password] localhost 0 [FreeRadius shared secret password]

    If success, you should got a response similar to below:

    rad_recv: Access-Accept packet from host port 1812, id=48, length=46
    Reply-Message = "Hello, testuser "

Now my services like OpenVPN and Squid accept OTP login 🙂


One thought

Leave a Reply

Your email address will not be published. Required fields are marked *