Location: PHPKode > scripts > Multi-OTP PHP class > multiotp.cli.header.php
<?php

/*********************************************************************
 *
 * MultiOTP PHP CLI header - Strong two-factor authentication PHP class
 * http://www.multiotp.net
 *
 * Donation are always welcome! Please check http://www.multiotp.net
 * and you will find the magic button ;-)
 *
 * If the name of this file is multiotp.php, it means that it is already
 * the result of the merge of the two files multiotp.cli.header.php and
 * multiotp.class.php
 *
 * The MultiOTP PHP CLI header is simply merged with the MultiOTP PHP
 * class in order to provide an authentication command line script.
 *
 * This script can be used as an external authentication provider with at
 * least the following RADIUS servers:
 *  - TekRADIUS, a free Radius server for Windows with MS-SQL backend
 *    (http:/www.tekradius.com)
 *  - TekRADIUS LT, a free Radius server for Windows with SQLite backend
 *    (http:/www.tekradius.com)
 *  - FreeRADIUS, a free Radius server implementation for Linux
 *    and *nix environments (http://freeradius.org)
 *
 * For Windows, you can also use the multiotp.exe file provided, which is
 * an embedded PHP interpreter together with the result of the merge.
 *
 *
 * LICENCE
 *
 *   Copyright (c) 2010, SysCo systemes de communication sa
 *   SysCo (tm) is a trademark of SysCo systemes de communication sa
 *   (http://www.sysco.ch)
 *   All rights reserved.
 * 
 *   This file is part of the MultiOTP PHP class
 *
 *   MultiOTP PHP class is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU Lesser General Public License as
 *   published by the Free Software Foundation, either version 3 of the License,
 *   or (at your option) any later version.
 * 
 *   MultiOTP PHP class is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU Lesser General Public License for more details.
 * 
 *   You should have received a copy of the GNU Lesser General Public
 *   License along with MultiOTP PHP class.
 *   If not, see <http://www.gnu.org/licenses/>.
 *
 *
 * @author: SysCo/al
 * @since CreationDate: 2010-06-08
 * @copyright (c) 2010 by SysCo systemes de communication sa
 * @version $LastChangedRevision: 3.0.0 $
 * @version $LastChangedDate: 2010-09-02 $
 * @version $LastChangedBy: SysCo/al $
 * @link $HeadURL: multiotp.cli.header.php $
 * @link http://www.multiotp.net
 * @link hide@address.com
 * Language: PHP 4.4.4 or higher
 *
 *
 * Command line usage
 *
 *   Type multiotp -help to have the full description of the options,
 *    and have a look at the readme.txt file for enhanced explanations
 *
 *
 * Return codes
 *
 *   0 OK: Token accepted
 *  11 INFO: User successfully created or updated
 *  12 INFO: User successfully deleted
 *  13 INFO: User PIN code successfully changed
 *  14 INFO: Token has been resynchronized successfully
 *  15 INFO: XML tokens definition file successfully imported
 *  19 INFO: Requested operation successfully done
 *  21 ERROR: User doesn't exist
 *  22 ERROR: User already exists
 *  23 ERROR: Invalid algorithm
 *  24 ERROR: User locked (too many tries)
 *  25 ERROR: User delayed (too many tries, but still a hope in a few minutes)
 *  26 ERROR: The time based token has already been used
 *  27 ERROR: Resynchronization of the token has failed
 *  28 ERROR: Unable to write the changes in the file
 *  29 ERROR: Token doesn't exist
 *  30 ERROR: At least one parameter is missing
 *  31 ERROR: XML tokens definition file doesn't exist
 *  32 ERROR: XML tokens definition file not successfully imported
 *  99 ERROR: Authentication failed (and other possible unknown errors)
 *
 *
 * Radius integration examples
 *
 *   Example 1 (TekRADIUS or TekRADIUS LT under Windows)
 *
 *     TekRADIUS supports a Default Username to be used when a matching user
 *     profile cannot be found for an incoming RADIUS authentication request.
 *     So a quick and easy way is to create in the TekRADIUS Manager a User
 *     named 'Default' that belongs to the existing 'Default' Group.
 *     Then add to this Default user the following attribute :
 *     Check  External-Executable  C:\multitop\multiotp.exe %ietf|1% %ietf|2%
 *
 *
 *   Example 2 (FreeRADIUS under Linux)
 *
 *     Define a DEFAULT entry in the /etc/freeradius/users file like this:
 *     DEFAULT Auth-Type = Accept
 *     Exec-Program-Wait = "/usr/local/bin/multiotp.php %{User-Name} %{User-Password}",
 *     Fall-Through = Yes,
 *     Reply-Message = "Hello, %{User-Name}"
 *
 *
 * External files created
 *
 *   Users database files in the subfolder called users
 *   Tokens database files in the subfolder called tokens
 *
 *
 * External file needed
 *
 *   Users database files in the subfolder called users
 *   Tokens database files in the subfolder called tokens
 *
 *
 * Special issues
 *
 *   If you need specific developements concerning strong authentication,
 *   do not hesistate to contact us per email at hide@address.com
 *
 *
 * Users feedbacks and comments
 *
 * 2010-08-20 BirdNet, C. Christophi
 *   Documentation enhancement proposal for the TekRADIUS part, thanks !
 *
 *
 * Change Log
 *
 *   2010-09-02 3.0.0  SysCo/al Adding tokens handling support, including importing XML tokens definition file
 *                              Enhanced flat database file format (multiotp is still compatible with old formats)
 *                              Internal method SetDataReadFlag renamed to SetUserDataReadFlag
 *                              Internal method GetDataReadFlag renamed to GetUserDataReadFlag
 *   2010-08-21 2.0.4  SysCo/al Enhancement in order to use an alternate php "compiler" for Windows command line
 *                              Documentation enhancement
 *   2010-08-18 2.0.3  SysCo/al Minor notice fix, define timezone if not defined (for embedded command line)
 *                              If user doesn't exist, do not create the related flat file after a check
 *   2010-07-21 2.0.2  SysCo/al Fix to create correctly the folders "uaers" and "log" if needed
 *   2010-07-19 2.0.1  SysCo/al Adding more information in the help text
 *   2010-07-19 2.0.0  SysCo/al New design using a class and a cli header stub
 *   2010-06-15 1.1.5  SysCo/al Adding OATH/TOTP support
 *   2010-06-15 1.1.4  SysCo/al Project renamed to multiotp to avoid overlapping
 *   2010-06-08 1.1.3  SysCo/al Typo in script folder detection
 *   2010-06-08 1.1.2  SysCo/al Typo in variable name
 *   2010-06-08 1.1.1  SysCo/al Status bar during resynchronization
 *   2010-06-08 1.1.0  SysCo/al Fix in the example, distribution not compressed
 *   2010-06-07 1.0.0  SysCo/al Initial implementation
 *
 *********************************************************************/

 
// Trick to have mostly the correct timezone in embedded command line version
// and to avoid error messages when using time functions

if (function_exists("date_default_timezone_get"))
{
    $actual_timezone = @date_default_timezone_get();
    if (function_exists("date_default_timezone_set"))
    {
        @date_default_timezone_set($actual_timezone);
    }
}


// Be sure that STDIN, STDOUT and STDERR are defined correctly for command line edition
if (!defined('STDIN'))
{
    define(STDIN, fopen('php://stdin', 'r'));
}
if (!defined('STDOUT'))
{
    define(STDOUT, fopen('php://stdout', 'w'));
}
if (!defined('STDERR'))
{
    define(STDERR, fopen('php://stderr', 'w'));
}


// Create a new Multiotp object
// The log and users subfolders are set by default under the folder of the script
$multiotp = new Multiotp();


// Set a specific encryption key for the tokens and users files
$multiotp->SetEncryptionKey('DefaultCliEncryptionKey');

// Initialize some variables
$command           = "check";
$display_help      = FALSE;
$display_status    = FALSE;
$prefix_pin        = FALSE;
$crlf              = chr(13).chr(10);
$result            = 99; // Unknown error
$token_id_creation = FALSE;

 
// Extract all parameters
$param_count = 0;
$all_args = array();

for ($arg_loop=1; $arg_loop <= $_SERVER["argc"]-1; $arg_loop++)
{
    if ("-check" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $command = "check";
    }
    elseif ("-create" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $command = "create";
    }
    elseif ("-debug" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $multiotp->EnableVerboseLog();
    }
    elseif ("-delete" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $command = "delete";
    }
    elseif ("-help" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $command = "help";
    }
    elseif ("-import-xml" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $command = "import-xml";
    }
    elseif ("-log" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $multiotp->EnableLog();
    }
    elseif ("-no-prefix-pin" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $prefix_pin = FALSE;
    }
    elseif ("-prefix-pin" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $prefix_pin = TRUE;
    }
    elseif ("-resync" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $command = "resync";
    }
    elseif ("-status" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $display_status = TRUE;
    }
    elseif ("-token-id" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $token_id_creation = TRUE;
    }
    elseif ("-update" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $command = "update";
    }
    elseif ("-update-pin" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $command = "update-pin";
    }
    elseif (("-version" == strtolower($_SERVER["argv"][$arg_loop])) || ("-v" == strtolower($_SERVER["argv"][$arg_loop])))
    {
        $command = "version";
    }
    else
    {
        $param_count++;
        $all_args[$param_count] = $_SERVER["argv"][$arg_loop];
    }
}

// Be sure that inexistant parameters are empty
for ($i = ($param_count+1); $i <= 20; $i++)
{
    $all_args[$i] = "";
}

// if not enough parameters, display help
if (($param_count < 1) && ($command != "version"))
{    $command = "help";
}

switch ($command)
{
    case "version":
        echo "multiotp ".$multiotp->GetVersion()." (".$multiotp->GetDate().")".$crlf;
        $result = 19;
        break;
    case "check";
        if  ($param_count < 2)
        {
            $result = 30; // ERROR: At least one parameter is missing
        }
        elseif (!$multiotp->ReadUserData($all_args[1]))
        {
            $result = 22; // ERROR: user doesn't exist.
        }
        else
        {
            $result = $multiotp->CheckToken($all_args[2]); // Result provided by the MultiOTP class
        }
        break;
    case "create":
    case "update":
        if (("create" == $command) && $multiotp->ReadUserData($all_args[1], TRUE))
        {
            $result = 22; // ERROR: user already exists.
        }
        elseif (("update" == $command) && (!$multiotp->ReadUserData($all_args[1])))
        {
            $result = 21; // ERROR: user doesn't exist.
        }
        elseif  ($param_count < 3)
        {
            $result = 30; // ERROR: At least one parameter is missing
        }
        else
        {
            $multiotp->SetUser($all_args[1]);
            $multiotp->SetUserPrefixPin($prefix_pin?1:0);
            
            if ($token_id_creation)
            {
                $key_id = $all_args[2];
                if (!$multiotp->ReadTokenData($key_id))
                {
                    $result = 29; // ERROR: token doesn't exist.
                }
                else
                {
                    $multiotp->SetUserKeyId($key_id);
                    if (!$multiotp->SetUserAlgorithm($multiotp->GetTokenAlgorithm()))
                    {
                        $result = 23; // ERROR: invalid algorithm
                    }
                    else
                    {
                        $multiotp->SetUserTokenSeed($multiotp->GetTokenSeed());
                        $multiotp->SetUserTokenNumberOfDigits($multiotp->GetTokenNumberOfDigits());
                        $multiotp->SetUserTokenTimeInterval($multiotp->GetTokenTimeInterval());
                        $multiotp->SetUserTokenLastEvent($multiotp->GetTokenLastEvent());
                        
                        $multiotp->SetUserPin($all_args[3]);
                        
                        if ($multiotp->WriteUserData())
                        {
                            $result = 11; // INFO: user successfully created or updated
                        }
                        else
                        {
                            $result = 28; // ERROR: Unable to write the changes in the file
                        }
                    }
                }
            }
            elseif (!$multiotp->SetUserAlgorithm($all_args[2]))
            {
                $result = 23; // ERROR: invalid algorithm
            }
            else
            {
                $multiotp->SetUserTokenSeed($all_args[3]);
                
                if  ($param_count < 4)
                {
                    $result = 30; // ERROR: At least one parameter is missing
                }
                else
                {
                    $multiotp->SetUserPin($all_args[4]);
                    if ("" == $all_args[5])
                    {
                        $all_args[5] = 6; // Default numnber of digits is set to 6
                    }
                    $multiotp->SetUserTokenNumberOfDigits($all_args[5]);
                    switch (strtoupper($all_args[2]))
                    {
                        // This is the time interval for mOTP
                        case "MOTP":
                            if ("" == $all_args[6])
                            {
                                $all_args[6] = 10; // Default windows value interval for mOTP
                            }
                            $multiotp->SetUserTokenTimeInterval($all_args[6]);
                            break;
                        // This is the time interval for TOTP
                        case "TOTP":
                            if ("" == $all_args[6])
                            {
                                $all_args[6] = 30; // Default windows value interval for TOTP
                            }
                            $multiotp->SetUserTokenTimeInterval($all_args[6]);
                            break;
                        // This is the next event for HOTP
                        case "HOTP":
                        default:
                            if ("" == $all_args[6])
                            {
                                $all_args[6] = 0; // Default next event
                            }
                            $multiotp->SetUserTokenLastEvent($all_args[6]-1);
                            // -1 because we are saving the last event in the user file database
                            break;
                    }
                    if ($multiotp->WriteUserData())
                    {
                        $result = 11; // INFO: user successfully created or updated
                    }
                    else
                    {
                        $result = 28; // ERROR: Unable to write the changes in the file
                    }
                }
            }
        }
        break;
    case "delete":
        $multiotp->SetUser($all_args[1]);
        if (!$multiotp->DeleteUser())
        {
            $result = 21; // ERROR: user doesn't exist.
        }
        else
        {
            $result = 12; // INFO: user successfully deleted.
        }
        break;
    case "resync":
        if  ($param_count < 3)
        {
            $result = 30; // ERROR: At least one parameter is missing
        }
        elseif (!$multiotp->ReadUserData($all_args[1]))
        {
            $result = 22; // ERROR: user doesn't exist.
        }
        else
        {
            $result = $multiotp->CheckToken($all_args[2], $all_args[3], $display_status); // Result provided by the MultiOTP class
        }
        break;
    case "update-pin":
        if  ($param_count < 2)
        {
            $result = 30; // ERROR: At least one parameter is missing
        }
        elseif (!$multiotp->ReadUserData($all_args[1]))
        {
            $result = 21; // ERROR: user doesn't exist.
        }
        else
        {
            $multiotp->SetUserPin($all_args[2]);
            if ($multiotp->WriteUserData())
            {
                $result = 13; // INFO: pin successfully changed
            }
        }
        break;
    case "import-xml":
        if (!file_exists($all_args[1]))
        {
            $result = 31; // ERROR: XML tokens definition file doesn't exist.
        }
        else
        {
            if ($multiotp->ImportTokensFromXml($all_args[1]))
            {
                $result = 15; // INFO: XML tokens definition file successfully imported
            }
            else
            {
                $result = 32; // ERROR: XML tokens definition file not successfully imported.
            }
        }
        break;
    default: // help or others
        echo "multiotp ".$multiotp->GetVersion()." (".$multiotp->GetDate().")".$crlf;
        echo $multiotp->GetCopyright().$crlf;
        echo $multiotp->GetWebsite().$crlf;
        echo $crlf;
        echo "multiotp will check if the token of a user is correct, based on a specified".$crlf;
        echo "algorithm (currently Mobile-OTP (http://motp.sf.net), OATH/HOTP (RFC 4226) ".$crlf;
		echo "and OATH/TOTP (HOTPTimeBased RFC 4226 extension) are implemented).".$crlf;
        echo $crlf;
        echo "If you are using the command line tool for Windows, be sure that the file".$crlf;
        echo "multiotp.php is not present in the directory, otherwise conflict may appears.".$crlf;
        echo $crlf;
        echo "If a token is locked (return code 24), you can resync the token to unlock.".$crlf;
        echo $crlf;
        echo "It will return 0 for a correct token, or an error code (11-99) otherwise.".$crlf;
        echo $crlf;
        echo "Return codes:".$crlf;
        
        reset($multiotp->_errors_text);
        while(list($key, $value) = each($multiotp->_errors_text))
        {
            echo substr('  '.$key,-2)." ".$value.$crlf;
        }
        echo $crlf;
        echo "Usage:".$crlf;
        echo " multiotp [-log] -import-xml xml_tokens_definition_file.xml".$crlf;
        echo " multiotp [-log] -create [-prefix-pin] user algo seed pin digits [pos|interval]".$crlf;
        echo " multiotp [-log] -create -token-id [-prefix-pin] user token-id pin".$crlf;
        echo " multiotp [-log] -resync [-status] user token1 token2 (two consecutive tokens)".$crlf;
        echo " multiotp [-log] -update-pin user pin".$crlf;
        echo " multiotp [-log] user token".$crlf;
        echo " multiotp -delete user".$crlf;
        echo $crlf;
        echo " token-id: id of the previously imported token to attribute to the user".$crlf;
        echo " user:     name of the user (should be the account name)".$crlf;
        echo " algo:     available algorithms are mOTP, HOTP and TOTP".$crlf;
        echo " seed:     hexadecimal seed of the token".$crlf;
        echo " pin:      private pin code of the user".$crlf;
        echo " digits:   number of digits given by the token".$crlf;
        echo " pos:      for HOTP algorithm, position of the next awaited event".$crlf;
        echo " interval: for mOTP and TOTP algorithms, token interval time in seconds".$crlf;
        echo $crlf;
        echo "Options:".$crlf;
        echo " -help        Display this help page".$crlf;
        echo " -version     Display the current version".$crlf;
        echo " -prefix-pin  The pin and the token must be typed merged by the user".$crlf;
        echo "              (if you pin is 1234 and your token displays 5556677,".$crlf;
        echo "               you will have to type 1234556677)".$crlf;
        echo " -status      Display a status bar during resynchronization".$crlf;
        echo " -log         Log operation in the log file (in the \log subdirectory)".$crlf;
        echo " -debug       Enhanced log information and code result on screen".$crlf;
        echo $crlf;
        echo "Examples:".$crlf;
        echo " multiotp -log -debug -import-xml tokens.xml".$crlf;
        echo " multiotp -log -create jimmy mOTP 004f5a158bca13984d349a7f23 1234 6 10".$crlf;
        echo " multiotp -create -prefix-pin alan TOTP 3683453456769abc3452 2233 6 60".$crlf;
        echo " multiotp -create -prefix-pin anna TOTP 56821bac24fbd2343393 4455 6 30".$crlf;
        echo " multiotp -create -prefix-pin john HOTP 31323334353637383930 5678 6 137".$crlf;
        echo " multiotp -create -token-id -prefix-pin rick 2010090201901 2345".$crlf;
        echo " multiotp -resync john 5678456789 5678345231".$crlf;
        echo " multiotp -resync -status anna 4455487352 4455983513".$crlf;
        echo " multiotp -update-pin alan 4417".$crlf;
        echo " multiotp -log -debug jimmy ea2315".$crlf;
        echo " multiotp -log anna 546078".$crlf;
        echo " multiotp john 5678124578".$crlf;
        echo $crlf;
        echo "When used with TekRADIUS (http://www.tekradius.com) the External-Executable".$crlf;
        echo "must be called like this: C:\multitop\multiotp.exe %ietf|1% %ietf|2%".$crlf;
        echo $crlf;
        break;
}
if ($multiotp->GetVerboseFlag())
{
    echo $result;
    if (isset($multiotp->_errors_text[$result]))
    {
        echo " ".$multiotp->_errors_text[$result];
    }
}
exit($result);

?>
Return current item: Multi-OTP PHP class