PHP Classes

File: multiotp.server.php

Recommend this page to a friend!
  Classes of André Liechti   multiOTP PHP class   multiotp.server.php   Download  
File: multiotp.server.php
Role: Application script
Content type: text/plain
Description: server component of the client/server feature
Class: multiOTP PHP class
Authenticate and manage OTP strong user tokens
Author: By
Last change: New release 5.9.7.1
FIX: Command line number of parameters detection corrected
ENH: It's now possible to define the number of digits for new created PIN
(multiotp -config default-pin-digits=n)
ENH: It's now possible to generate the HTML provisioning file by command line
(multiotp -htmlinfo username /full/path/to/username.html or
multiotp -htmlinfo /full/path/to/folder/ to generate files for all users)
ENH: Embedded Windows nginx edition updated to version 1.25.3
ENH: Embedded Windows internal tools updated (wget 1.21.4 and fart 1.99d)
ENH: Embedded Windows freeradius is now launched using NSSM (instead of SRVANY)
New release 5.9.7.0
FIX: Better Windows nginx configuration support (path backslashes replaced by slashes)
ENH: Embedded Windows nginx edition updated to version 1.24.0
ENH: Embedded Windows PHP edition updated to version 8.2.13
ENH: Better hardware/model detection
ENH: Documentation enhanced with instructions for RDWeb on Windows
ENH: Upgrade of some internal tools
ENH: Better internal configuration organization
New release 5.9.6.7
ENH: Documentation updated for "Configuring multiOTP with FreeRADIUS 3.x under Linux"
ENH: Without2FA tokens cannot be used for multi_account connection
ENH: Added documentation for SSH login with multiOTP
New release 5.9.6.5
FIX: Better Raspberry Pi support
FIX: ShowLog() method (used by -showlog option) was buggy
New release 5.9.6.1
FIX: Automated concurrent access for the same user with "Without2FA" token could corrupt the user file
FIX: Any files backend operation is now secured with explicit lock mechanism
ENH: Template updated to print bigger QRcode for "MOTP-XML" tokens
New release 5.9.5.7
FIX: Weekly anonymized stats date was not always updated
FIX: Adding -tokenslist command in CLI mode (mas missing)
FIX: Remove a debug line displaying sometimes "COMMDN:$command\n";
FIX: Some minor PHP notice corrections
ENH: Adding on-premises smsgateway (https://github.com/multiOTP/SMSGateway) as a new SMS provider
ENH: Better warning messages when CheckUserLdapPassword failed
ENH: Embedded documentation enhanced
ENH: Template updated to display correct information for WITHOUT2FA tokens
Date: 8 months ago
Size: 79,241 bytes
 

Contents

Class file image Download
<?php /** * @file multiotp.server.php * @brief web service for the multiOTP class. * * multiOTP web service - Strong two-factor authentication PHP class * https://www.multiotp.net * * Visit http://forum.multiotp.net/ for additional support. * * Donation are always welcome! Please check https://www.multiotp.net * and you will find the magic button ;-) * * The multiOTP web service is simply merged with the multiOTP PHP class * in order to provide the server part of the client/server solution. * * This file can be used with any web server supporting PHP as * script language, like the following web servers: * - nginx is a light one under Linux * (http://nginx.org/) * - Mongoose is a light one under Windows * (https://code.google.com/archive/p/mongoose/downloads) * - The Apache HTTP server is a very well known web server running under Linux and Windows * (http://httpd.apache.org/) * * * PHP 5.4.0 or higher is supported. * * @author Andre Liechti, SysCo systemes de communication sa, <info@multiotp.net> * @version 5.9.7.1 * @date 2023-12-03 * @since 2013-08-06 * @copyright (c) 2013-2023 SysCo systemes de communication sa * @copyright GNU Lesser General Public License * *//* * * LICENCE * * Copyright (c) 2010-2023 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/>. * * * Usage * * You will have to send an XML formatted content in the field named data * in a POSTed form. * * * Special issues * * If you need specific developments concerning strong authentication, * do not hesitate to contact us per email at info@multiotp.net. * * * Users feedbacks and comments * * 2017-02-09 Frank van der Aa, Vanboxtel BV (NL) * Thanks for your debug about lockedlistarray[], the new * GetDelayedUsersList() method and the delayed users display on the web GUI. * * 2013-07-25 Dominik Pretzsch from Last Squirrel IT * After some discussions with Dominik, integration of the * client/server support in the basic library * * * Change Log * * 2022-05-08 5.8.8.5 SysCo/al Scratchlist can be generated from the Web GUI * 2021-03-25 5.8.1.9 SysCo/al Cookie privacy (httponly and secure) are now handled in the application directly * Weak SSL ciphers disabled * 2021-02-12 5.8.1.0 SysCo/al Web GUI update * 2019-01-24 5.4.1.5 SysCo/al If any, clean specific NTP DHCP option at every reboot * 2019-01-07 5.4.1.1 SysCo/al Raspberry Pi 3B+ support * 2018-08-21 5.3.0.0 SysCo/al without2FA algorithm added * 2017-07-07 5.0.4.9 SysCo/al Code cleaning, possible web information added * 2017-05-29 5.0.4.5 SysCo/al Restore configuration added * Fixed configuration file directory under Windows * The file can now be included from another one that have already an instance * 2016-11-06 5.0.2.7 SysCo/al Better configuration file detection * 2016-11-04 5.0.2.6 SysCo/al Backup configuration added * 2016-10-16 5.0.2.5 SysCo/al New methods added for SOAP service * 2016-04-18 5.0.0.0 SysCo/al ForceNoDisplayLog() method called to avoid log on display * 2015-07-15 4.3.2.5 SysCo/al Admin password update has been fixed * 2015-06-10 4.3.2.3 SysCo/al Enhancements for the Dev(Talks): demo * 2015-06-09 4.3.2.2 SysCo/al More option available from the GUI, Dev Talks Edition * 2014-12-09 4.3.1.0 SysCo/al Speed improvement (apc options have been tuned) * 2014-11-04 4.3.0.0 SysCo/al Updated GUI * 2014-04-13 4.2.4.2 SysCo/al Version synchronization * 2014-03-30 4.2.4 SysCo/al Forum link added on the GUI, minor bug fixes * 2014-03-01 4.2.2 SysCo/al More options available from the GUI * 2014-01-20 4.1.1 SysCo/al Version synchronization * 2013-12-23 4.1.0 SysCo/al Adding basic web functionalities * 2013-08-30 4.0.7 SysCo/al Version synchronization * 2013-08-25 4.0.6 SysCo/al Enhanced default page * 2013-08-20 4.0.4 SysCo/al Initial release * *********************************************************************/ /////////////////////////////////////////////////////////////////////////// // For your convenience, the class file is directly integrated in this file /////////////////////////////////////////////////////////////////////////// if (!class_exists('Multiotp')) { require_once('multiotp.class.php'); } $multiotp_etc_dir = '/etc/multiotp'; $config_folder = $multiotp_etc_dir.'/config'; if (false === mb_strpos(getcwd(), '/')) { // if (!@file_exists($config_folder)) { $multiotp_etc_dir = ''; $config_folder = ''; } if (!isset($multiotp)) { $multiotp = new Multiotp('DefaultCliEncryptionKey', false, '', $config_folder); } $multiotp->ForceNoDisplayLog(); // No log on display as we are running a web server if ('' != $multiotp_etc_dir) { $multiotp->SetLogFolder('/var/log/multiotp/'); $multiotp->SetConfigFolder($multiotp_etc_dir.'/config/'); $multiotp->SetDdnsFolder($multiotp_etc_dir.'/ddns/'); $multiotp->SetDevicesFolder($multiotp_etc_dir.'/devices/'); $multiotp->SetGroupsFolder($multiotp_etc_dir.'/groups/'); $multiotp->SetTokensFolder($multiotp_etc_dir.'/tokens/'); $multiotp->SetUsersFolder($multiotp_etc_dir.'/users/'); $multiotp->SetCacheFolder('/tmp/cache/'); $multiotp->SetLinuxFileMode('0666'); } $multiotp->ReadConfigData(); $data = isset($_POST['data'])?$_POST['data']:''; $method = mb_substr(isset($_GET['method'])?$_GET['method']:(isset($_POST['method'])?$_POST['method']:''),0,255); $options = isset($_GET['options'])?$_GET['options']:(isset($_POST['options'])?$_POST['options']:''); $postdata = file_get_contents("php://input"); if (FALSE !== mb_strpos($data,'<multiOTP')) { $multiotp->XmlServer($data); exit(); } elseif ((FALSE !== mb_strpos($postdata,'<SOAP-ENV')) || (isset($_GET['soap'])) || (isset($_GET['wsdl']))) { /******************* ******************* *** SOAP SERVER *** ******************* ******************/ // Instantiate the SOAP server $soap_server = new soap_server(); $soap_service_name = "multiotp"; $soap_tns_namespace = 'https://www.multiotp.net/wsdl/multiotp/'; $soap_endpoint_url = false; $soap_schema_target_namespace = 'https://www.multiotp.net/wsdl/multiotp/'; $soap_openotp_namespace = 'urn:openotp'; // urn:openotp // Create the WSDL $soap_server->configureWSDL($soap_service_name, $soap_tns_namespace, $soap_endpoint_url); // Set the schema target namespace // $soap_server->wsdl->schemaTargetNamespace = $soap_schema_target_namespace; //Register openotpNormalLogin method $soap_server->register( 'openotpNormalLogin', // method name array('username' => 'xsd:string', // input parameters 'domain' => 'xsd:string', 'ldapPassword' => 'xsd:string', 'otpPassword' => 'xsd:string', 'client' => 'xsd:string', 'source' => 'xsd:string', 'settings' => 'xsd:string', 'options' => 'xsd:string'), array('code' => 'xsd:integer', // return value(s) 'message' => 'xsd:string', 'session' => 'xsd:string', 'data' => 'xsd:string', 'timeout' => 'xsd:integer', 'otpChallenge' => 'xsd:string', 'u2fChallenge' => 'xsd:string'), $soap_openotp_namespace, // namespace false, // soapaction: (use default) 'rpc', // style: rpc or document 'encoded', // use: encoded or literal 'This method is used to send an authentication request.'); // description: documentation for the method // Defined method function openotpNormalLogin($username, $domain, $ldapPassword, $otpPassword, $client, $source, $settings, $options) { global $multiotp; return $multiotp->SoapOpenotpNormalLogin($username, $domain, $ldapPassword, $otpPassword, $client, $source, $settings, $options); } //Register openotpSimpleLogin method $soap_server->register( 'openotpSimpleLogin', array('username' => 'xsd:string', 'domain' => 'xsd:string', 'anyPassword' => 'xsd:string', 'client' => 'xsd:string', 'source' => 'xsd:string', 'settings' => 'xsd:string'), array('code' => 'xsd:integer', 'message' => 'xsd:string', 'session' => 'xsd:string', 'data' => 'xsd:string', 'timeout' => 'xsd:integer'), $soap_openotp_namespace, false, 'rpc', 'encoded', 'This method is similar to openotpNormalLogin with only one generic password attribute.'); // Defined method function openotpSimpleLogin($username, $domain, $anyPassword, $client, $source, $settings) { global $multiotp; return $multiotp->SoapOpenotpSimpleLogin($username, $domain, $anyPassword, $client, $source, $settings); } //Register openotpLogin method $soap_server->register( 'openotpLogin', array('username' => 'xsd:string', // input parameters 'domain' => 'xsd:string', 'ldapPassword' => 'xsd:string', 'otpPassword' => 'xsd:string', 'client' => 'xsd:string', 'source' => 'xsd:string', 'settings' => 'xsd:string', 'options' => 'xsd:string'), array('code' => 'xsd:integer', 'message' => 'xsd:string', 'session' => 'xsd:string', 'data' => 'xsd:string', 'timeout' => 'xsd:integer'), $soap_openotp_namespace, false, 'rpc', 'encoded', 'This method is an alias of openotpNormalLogin. It ensures backward compatibility.'); // Defined method function openotpLogin($username, $domain, $ldapPassword, $otpPassword, $client, $source, $settings, $options) { global $multiotp; return $multiotp->SoapOpenotpNormalLogin($username, $domain, $ldapPassword, $otpPassword, $client, $source, $settings, $options); } //Register openotpChallenge method $soap_server->register( 'openotpChallenge', array('username' => 'xsd:string', 'domain' => 'xsd:string', 'session' => 'xsd:string', 'otpPassword' => 'xsd:string', 'u2fResponse' => 'xsd:string'), array('code' => 'xsd:integer', 'message' => 'xsd:string', 'data' => 'xsd:string'), $soap_openotp_namespace, false, 'rpc', 'encoded', 'This method is used when the openotpLogin returned a challenge (code 2). This is the second request to be sent containing the user one-time password.'); // Defined method function openotpChallenge($username, $domain, $session, $otpPassword) { global $multiotp; return $multiotp->SoapOpenotpChallenge($username, $domain, $session, $otpPassword); } //Register openotpStatus method $soap_server->register( 'openotpStatus', array(), array('status' => 'xsd:boolean', 'message' => 'xsd:string'), $soap_openotp_namespace, false, 'rpc', 'encoded', 'openotpStatus call'); // Defined method function openotpStatus() { global $multiotp; return $multiotp->SoapOpenotpStatus(); } $soap_server->service($postdata); exit(); } else { // Secure and httponly cookie parameters forced in the application $params = session_get_cookie_params(); $cookie_secure = (!$multiotp->IsDebugOption()) && (!$multiotp->IsDeveloperMode()); $cookie_httponly = true; session_set_cookie_params($params["lifetime"], $params["path"], $params["domain"], $cookie_secure, $cookie_httponly ); session_start(); $multiotp->SetHashSalt('AjaxH@shS@lt'); // Shared secret $hash_salt = $multiotp->GetHashSalt(); /**************************************** * WE REALLY DO NOT WANT TO BE CACHED !!! ****************************************/ header("Expires: " . gmdate("D, d M Y H:i:s") . " GMT"); header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); header("Cache-Control: no-store, no-cache, must-revalidate"); header("Cache-Control: post-check=0, pre-check=0", false); header("Pragma: no-cache"); $multiotp->SendWeeklyAnonymousStat(); if (isset($_FILES['upgrade_file']['tmp_name'])) { if ((isset($_SESSION['logged']) && $_SESSION['logged'])) { if (file_exists($_FILES['upgrade_file']['tmp_name']) && (UPLOAD_ERR_OK == $_FILES["upgrade_file"]["error"])) { $upgrade_file = $multiotp->ConvertToWindowsPathIfNeeded(sys_get_temp_dir()."/".date("YmdHis")."-".md5($_FILES['upgrade_file']['tmp_name']).".cfg"); move_uploaded_file($_FILES['upgrade_file']['tmp_name'], $upgrade_file); } } } if (isset($_FILES['config_file']['tmp_name'])) { if ((isset($_SESSION['logged']) && $_SESSION['logged'])) { if (file_exists($_FILES['config_file']['tmp_name']) && (UPLOAD_ERR_OK == $_FILES["config_file"]["error"])) { $config_file = $multiotp->GetConfigFolder().date("YmdHis")."-".md5($_FILES['config_file']['tmp_name']).".cfg"; if (move_uploaded_file($_FILES['config_file']['tmp_name'], $config_file)) { if ($multiotp->RestoreConfiguration(array('backup_file' => $config_file, 'restore_key' => (isset($_POST['restore_config_password'])?nullable_trim($_POST['restore_config_password']):'')))) { // Clean Devices foreach (explode("\t", $multiotp->GetDevicesList()) as $one_device) { if ('' != nullable_trim($one_device)) { $multiotp->DeleteDevice($one_device); } } $actual_folder = $multiotp->GetDevicesFolder(); $actual_filter = "*.db"; if (($actual_dir = opendir($actual_folder)) !== FALSE) { while(($actual_file_name = readdir($actual_dir)) !== FALSE) { if (fnmatch($actual_filter, $actual_file_name)) { $actual_file = $actual_folder.$actual_file_name; unlink($actual_file); } } } // Clean Groups foreach (explode("\t", $multiotp->GetGroupsList()) as $one_group) { if ('' != nullable_trim($one_group)) { $multiotp->DeleteGroup($one_group); } } $actual_folder = $multiotp->GetGroupsFolder(); $actual_filter = "*.db"; if (($actual_dir = opendir($actual_folder)) !== FALSE) { while(($actual_file_name = readdir($actual_dir)) !== FALSE) { if (fnmatch($actual_filter, $actual_file_name)) { $actual_file = $actual_folder.$actual_file_name; unlink($actual_file); } } } // Clean Tokens foreach (explode("\t", $multiotp->GetTokensList()) as $one_token) { if ('' != nullable_trim($one_token)) { $multiotp->DeleteToken($one_token); } } $actual_folder = $multiotp->GetTokensFolder(); $actual_filter = "*.db"; if (($actual_dir = opendir($actual_folder)) !== FALSE) { while(($actual_file_name = readdir($actual_dir)) !== FALSE) { if (fnmatch($actual_filter, $actual_file_name)) { $actual_file = $actual_folder.$actual_file_name; unlink($actual_file); } } } // Clean Users $user_array = $multiotp->GetNextUserArray(TRUE); while (FALSE !== $user_array) { if (isset($user_array['user'])) { $multiotp->DeleteUser($user_array['user']); } $user_array = $multiotp->GetNextUserArray(); } $actual_folder = $multiotp->GetUsersFolder(); $actual_filter = "*.db"; if (($actual_dir = opendir($actual_folder)) !== FALSE) { while(($actual_file_name = readdir($actual_dir)) !== FALSE) { if (fnmatch($actual_filter, $actual_file_name)) { $actual_file = $actual_folder.$actual_file_name; unlink($actual_file); } } } $multiotp->RestoreConfiguration(array('backup_file' => $config_file, 'restore_key' => (isset($_POST['restore_config_password'])?nullable_trim($_POST['restore_config_password']):''))); $_SESSION = array(); $_SESSION['logged'] = FALSE; $ajax_result = "false"; // $multiotp->ReadConfigData(); header('Location: '.(isset($_SERVER['HTTPS']) ? "https" : "http") . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]"); exit(); } // End of the restore is ok } // if move_uploaded_file if (file_exists($config_file)) { unlink($config_file); } } } } if (isset($_FILES['token_file']['tmp_name'])) { if ((isset($_SESSION['logged']) && $_SESSION['logged'])) { if (file_exists($_FILES['token_file']['tmp_name']) && (UPLOAD_ERR_OK == $_FILES["token_file"]["error"])) { $multiotp->ImportTokensFile($_FILES['token_file']['tmp_name'], $_FILES['token_file']['name'], isset($_POST['token_password'])?nullable_trim($_POST['token_password']):''); } } echo "DONE"; } elseif ('' == $method) { /********************* * Basic web server * *********************/ $actual_date = date('Y-m-d H:i:s'); $class_name = $multiotp->GetClassName(); $class_version = $multiotp->GetVersion(); $class_date = $multiotp->GetDate(); $rpi_serial = $multiotp->GetRaspberryPiSerialNumber(); $rpi_info = (('' != $rpi_serial)?"<br />\n Raspberry Pi serial number: ".$rpi_serial."\n ":''); $server_software = (isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'].', ' : '')."PHP/".phpversion(); $prefix_required0_checked = ''; $prefix_required1_checked = ''; if ($multiotp->IsDefaultRequestPrefixPin()) { $prefix_required1_checked = ' checked="checked" '; } else { $prefix_required0_checked = ' checked="checked" '; } if ($multiotp->CheckAdminPassword("1234")) { $default_user_info = "(default is admin)"; $default_password_info = "(default is 1234)"; } else { $default_user_info = ""; $default_password_info = ""; } $webpage = <<<EOWEBPAGE <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title> multiOTP web administration console </title> <style> body { font-family: Verdana, Helvetica, Arial; color: black; font-size: 10pt; font-weight: normal; text-decoration: none; } h2 { font-size: 12pt; font-weight: bold; margin-top: 0em; margin-bottom: 0em; } h3 { font-size: 11pt; font-weight: bold; margin-top: 0.5em; margin-bottom: 0.1em; } p { margin-top: 0em; margin-bottom: 0em; } th { text-align: right; } .info { font-style: italic; font-weight: normal; } .section_title { display: block; font-weight: bold; } .section_title a { color: black; text-decoration: none; } /*************************/ /* Custom colors - BEGIN */ body { background-color: black; color: white; font-family: Verdana, Helvetica, Arial; font-size: 10pt; font-weight: normal; text-decoration: none; } .custom_logo_white { color: white; font-weight: bold; font-size: 20px; } .custom_logo_red { color: red; font-weight: bold; font-size: 20px; } a { color: white; font-weight: bold; text-decoration: none; } a:hover { color: red; } .section_title a { color: white; text-decoration: none; } .synced { color: #80ff80; } .locked { color: #ff4040; } .delayed { color: #ff8000; } /* Custom colors - END */ /***********************/ </style> <meta http-equiv="Content-type" content="text/html;charset=UTF-8" /> <script> // Relative url page in order to execute the method remotely var url_page = location.protocol + '//' + location.host + location.pathname; // Shared secret var hash_salt = '$hash_salt'; var selected_color = 'red'; var unselected_color = 'black'; var selected_background_color = '#e0e0e0'; var unselected_background_color = ''; var succeeded_color = '#80ff80'; var failed_color = 'red'; /*************************/ /* Custom colors - BEGIN */ var selected_color = 'red'; var unselected_color = 'white'; var selected_background_color = '#303030'; var unselected_background_color = ''; /* Custom colors - END */ /***********************/ function ChangeAdminPassword() { var newpassword = document.getElementById('newpassword').value; var newpassword2 = document.getElementById('newpassword2').value; document.getElementById('newpassword').value = ''; document.getElementById('newpassword2').value = ''; if ('' == newpassword) { alert('Password is empty!'); } else if (newpassword != newpassword2) { alert('Passwords are not equal!'); } else { var hash_password = md5(hash_salt+newpassword+hash_salt); RemoteCall('SetAdminPasswordHash', hash_password); Logout(); } } function Add() { var newuser = document.getElementById('newuser').value; var newemail = document.getElementById('newemail').value; var newsms = document.getElementById('newsms').value; var prefix_required = (document.getElementById('prefix_required1').checked?'1':'0'); var algorithm = document.getElementById('algorithm').value; var token_serial = document.getElementById('token_serial').value; var pin = document.getElementById('pin').value; if (IsLoggedIn()) { RemoteCall('FastCreateUser', newuser+"\t"+newemail+"\t"+newsms+"\t"+prefix_required+"\t"+algorithm+"\t"+pin+"\t"+token_serial); UpdatePage(); } document.getElementById('newuser').value = ''; document.getElementById('newemail').value = ''; document.getElementById('newsms').value = ''; document.getElementById('newuser').focus(); } function DeleteToken(one_token) { if ('' != one_token) { if (confirm('Are you sure you want to delete the token ' + one_token + '?')) { RemoteCall('DeleteToken', one_token); UpdatePage(); } } } function DeleteUser(one_user) { if ('' != one_user) { if (confirm('Are you sure you want to delete the user ' + one_user + '?')) { RemoteCall('DeleteUser', one_user); UpdatePage(); } } } function ResyncUserNow(resync_user, resync_otp1, resync_otp2) { var resynced = ('true' == eval(RemoteCall('ResyncUser', resync_user+"\t"+resync_otp1+"\t"+resync_otp2))); if (resynced) { Toggle('resync', 'none'); document.getElementById('resync_user').value = ''; document.getElementById('resync_otp1').value = ''; document.getElementById('resync_otp2').value = ''; } else { document.getElementById('resync_otp1').select(); document.getElementById('resync_otp1').focus(); } } function CheckUserNow(check_user_user, check_user_otp) { var result = eval(RemoteCall('CheckToken', check_user_user+"\t"+check_user_otp)); UpdatePage(); if ('true' == result) { document.getElementById('check_user_result').innerHTML = '<span style="color:'+succeeded_color+';">succeeded</span>'; document.getElementById('check_user_user').value = ''; document.getElementById('check_user_otp').value = ''; } else { document.getElementById('check_user_result').innerHTML = '<span style="color:'+failed_color+';">failed ('+result+')</span>'; document.getElementById('check_user_user').select(); document.getElementById('check_user_user').focus(); document.getElementById('check_user_otp').value = ''; } } function BackupConfigNow(backup_config_password) { if (backup_config_password != '') { var http_params = "method=BackupConfig"+"&options="+encodeURIComponent(backup_config_password); var full_url = url_page +'?'+http_params; window.open(full_url,'_blank'); document.getElementById('backup_config_password').value = ''; } } function IsLoggedIn() { var logged_in = ('true' == eval(RemoteCall('UserLoggedIn'))); return logged_in; } function Login() { var random_salt = eval(RemoteCall('GetRandomSalt')); var user = document.getElementById('user').value; var password = document.getElementById('password').value; document.getElementById('password').value = ''; var hash_password = md5(random_salt+md5(hash_salt+password+hash_salt)+random_salt); RemoteCall('Login', user+"\t"+hash_password); if (UpdatePage()) { Toggle('add_user', 'block'); document.getElementById('newuser').focus(); } } function Logout() { RemoteCall("Login", ""); Toggle('add_user', 'block'); UpdatePage(); } function PrintQrCode(one_user) { if ('' != one_user) { var http_params = "method=PrintQrCode"+"&options="+encodeURIComponent(one_user); var full_url = url_page +'?'+http_params; window.open(full_url,'_blank'); } } function PrintScratchlist(one_user) { if ('' != one_user) { var http_params = "method=PrintScratchlist"+"&options="+encodeURIComponent(one_user); var full_url = url_page +'?'+http_params; window.open(full_url,'_blank'); } } function ResyncUser(one_user) { document.getElementById('resync_user').value = one_user; Toggle('resync', 'block'); document.getElementById('resync_otp1').focus(); } function RebootDevice() { var result = GetHttp('RebootDevice',''); } function RemoteCall(my_method, my_options, my_id, async, form_method) /****************************************************************************************** * RemoteCall is a sample function that make an (a)synchronous GET or POST request to launch * a remote command and return the result as an HTML content in the defined id if defined. * * @param string my_method remote method to call * @param string my_options options (separated by \t) for the called method * @param string my_id id of the div/span to update asynchronously with the result * @param boolean async define the asynchronous mode * @param string form_method method used to send the request (GET or POST) * @return none ******************************************************************************************/ { my_method = typeof my_method !== 'undefined' ? my_method : ''; my_options = typeof my_options !== 'undefined' ? my_options : ''; my_id = typeof my_id !== 'undefined' ? my_id : ''; async = typeof async !== 'undefined' ? async : false; form_method = typeof form_method !== 'undefined' ? form_method : 'GET'; async = false; var result = ''; if ('POST' != form_method) { form_method = 'GET'; } var xmlhttp; if (window.XMLHttpRequest) { // code for IE7+, Firefox, Chrome, Opera, Safari xmlhttp=new XMLHttpRequest(); } else { // code for IE6, IE5 xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); } if (true == async) { xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { result = xmlhttp.responseText; if ('' != my_id) { document.getElementById(my_id).innerHTML=eval(result); } } } } var http_params = "method="+my_method+"&options="+encodeURIComponent(my_options); var full_url = url_page; var post_params = null; if ('GET' == form_method) { full_url = url_page +'?'+http_params; } else { post_params = http_params; } xmlhttp.open(form_method,full_url,false); if ('POST' == form_method) { xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); xmlhttp.setRequestHeader("Content-length", post_params.length); xmlhttp.setRequestHeader("Connection", "close"); } xmlhttp.send(post_params); if (false == async) { if (xmlhttp.status === 200) { result = xmlhttp.responseText; if ('' != my_id) { document.getElementById(my_id).innerHTML=eval(result); } } return (result); } } function Toggle(my_section, set_value) { var all_sections = ['add_user', 'change_password', 'import_tokens', 'resync', 'check_user', 'backup_config', 'restore_config', 'list_tokens']; // Flush the check section document.getElementById('check_user_user').value = ''; document.getElementById('check_user_otp').value = ''; document.getElementById('check_user_result').innerHTML = ''; set_value = typeof set_value !== 'undefined' ? set_value : ''; if ('all' == set_value) { all_sections.forEach(function(one_section) { document.getElementById(one_section+'_section').style.display = 'block'; document.getElementById(one_section+'_title').style.backgroundColor = selected_background_color; document.getElementById(one_section+'_text').style.color=selected_color; section_title = document.getElementById(one_section+'_toggle').innerHTML; if ('[+]' == section_title) { document.getElementById(one_section+'_toggle').innerHTML = '[-]'; } }); } else if ((('none' == document.getElementById(my_section+'_section').style.display) || ('block' == set_value)) && ('none' != set_value)) { all_sections.forEach(function(one_section) { if (one_section != my_section) { document.getElementById(one_section+'_section').style.display = 'none'; document.getElementById(one_section+'_title').style.backgroundColor = unselected_background_color; document.getElementById(one_section+'_text').style.color=unselected_color; section_title = document.getElementById(one_section+'_toggle').innerHTML; if ('[-]' == section_title) { document.getElementById(one_section+'_toggle').innerHTML = '[+]'; } } }); document.getElementById(my_section+'_section').style.display = 'block'; document.getElementById(my_section+'_title').style.backgroundColor = selected_background_color; document.getElementById(my_section+'_text').style.color=selected_color; section_title = document.getElementById(my_section+'_toggle').innerHTML; if ('[+]' == section_title) { document.getElementById(my_section+'_toggle').innerHTML = '[-]'; } if ('add_user' == my_section) { document.getElementById('newuser').focus(); } else if ('change_password' == my_section) { document.getElementById('newpassword').focus(); } else if ('import_tokens' == my_section) { document.getElementById('token_file').value = ''; var ifrm = document.getElementById('hidden_frame'); ifrm = (ifrm.contentWindow) ? ifrm.contentWindow : (ifrm.contentDocument.document) ? ifrm.contentDocument.document : ifrm.contentDocument; ifrm.document.open(); ifrm.document.write('Waiting...'); ifrm.document.close(); } else if ('resync' == my_section) { document.getElementById('resync_user').select(); document.getElementById('resync_user').focus(); document.getElementById('resync_otp1').value = ''; document.getElementById('resync_otp2').value = ''; } else if ('check_user' == my_section) { document.getElementById('check_user_user').select(); document.getElementById('check_user_user').focus(); } } else { document.getElementById(my_section+'_section').style.display = 'none'; document.getElementById(my_section+'_title').style.backgroundColor = unselected_background_color; document.getElementById(my_section+'_text').style.color=unselected_color; section_title = document.getElementById(my_section+'_toggle').innerHTML; if ('[-]' == section_title) { document.getElementById(my_section+'_toggle').innerHTML = '[+]'; } } } function UnlockUser(one_user) { if ('' != one_user) { RemoteCall('UnlockUser', one_user); UpdatePage(); } } function UpdatePage() { var logged_in = IsLoggedIn(); document.getElementById('logged').innerHTML = (logged_in?'User authenticated':'User NOT authenticated'); document.getElementById('logout_section').style.display=(logged_in?'block':'none'); document.getElementById('login_section').style.display=(logged_in?'none':'block'); document.getElementById('authenticated_section').style.display=(logged_in?'block':'none'); if (!logged_in) { document.getElementById('login_title').style.backgroundColor = selected_background_color; document.getElementById('login_text').style.color=selected_color; } document.getElementById('token_type').style.display = 'table-row'; document.getElementById('pin').value = ''; UpdateTokensList(); UpdateUsersList(); return logged_in; } function UpdateTokensList() { // Tokens var tokens_counter = 0; var remotecall = eval(RemoteCall('GetTokensList')); var tokenslist = typeof remotecall !== 'undefined' ? remotecall.trim() : ''; /* var remotecall = eval(RemoteCall('GetLockedTokensList')); var lockedlist = typeof remotecall !== 'undefined' ? remotecall.trim() : ''; */ var lockedlist = ''; if ('' != tokenslist) { var tokensarray = tokenslist.split("\t"); if ('false' == tokenslist) { tokenslist = 'not authorized'; tokensarray = []; } else { var lockedlistarray = lockedlist.split("\t"); tokenslist = ''; for (var i = 0; i < tokensarray.length; i++) { tokenslist = tokenslist + '<button type="button" onclick="DeleteToken(\''+tokensarray[i]+'\');">Delete</button>'; tokenslist = tokenslist + ' ' + tokensarray[i]; /* for (var j = 0; j < lockedlistarray.length; j++) { if (tokensarray[i] == lockedlistarray[j]) { tokenslist = tokenslist + ' (<a href="#" onclick="UnlockToken(\''+tokensarray[i]+'\');">unlock</a>)'; break; } } */ tokenslist = tokenslist + '<br />'; tokens_counter++; } } select = document.getElementById("token_serial"); select.options.length = 1; for (var i = 0; i < tokensarray.length; i++) { select.options[1 + i] = new Option(tokensarray[i], tokensarray[i]); /* var opt= document.getElementById('token_serial').options[1 + i]; opt.value = tokensarray[i]; opt.text = tokensarray[i]; */ } } document.getElementById('tokenslist').innerHTML = tokenslist; tokenscounter_txt = ''; tokenstitle_txt = 'List of hardware token'; if (tokens_counter > 0) { tokenscounter_txt = '('+tokens_counter+' token'; if (tokens_counter > 1) { tokenscounter_txt = tokenscounter_txt + 's'; tokenstitle_txt = tokenstitle_txt + 's'; } tokenscounter_txt = tokenscounter_txt + ')'; } document.getElementById('tokenscounter').innerHTML = tokenscounter_txt; document.getElementById('tokenstitle').innerHTML = tokenstitle_txt; } function UpdateUsersList() { // Users var userslist = 'No user yet...'; var counter = 0; var remotecall = eval(RemoteCall('GetEnhancedUsersList')); var enhanceduserslist = typeof remotecall !== 'undefined' ? remotecall.trim() : ''; var remotecall = eval(RemoteCall('GetLockedUsersList')); var lockedlist = typeof remotecall !== 'undefined' ? remotecall.trim() : ''; var remotecall = eval(RemoteCall('GetDelayedUsersList')); var delayedlist = typeof remotecall !== 'undefined' ? remotecall.trim() : ''; if ('' != enhanceduserslist) { var enhancedusersarray = enhanceduserslist.split("\t"); if ('false' == enhanceduserslist) { userslist = 'not authorized'; } else { var lockedlistarray = lockedlist.split("\t"); var delayedlistarray = delayedlist.split("\t"); userslist = ''; for (var i = 0; i < enhancedusersarray.length; i++) { var usersinfo = enhancedusersarray[i].split('|'); // usersinfo[0] = username // usersinfo[1] = s1|s0 (AD/LDAP synchronized or not) userclass = ""; synced = ("s1" == usersinfo[1]); if (synced) { userclass="synced"; } locked = false; for (var j = 0; j < lockedlistarray.length; j++) { if (usersinfo[0] == lockedlistarray[j]) { locked = true; userclass="locked"; break; } } delayed = false; delayed_time = 0; for (var j = 0; j < delayedlistarray.length; j++) { var delayinfo = delayedlistarray[j].split('|'); if (usersinfo[0] == delayinfo[0]) { delayed_time = delayinfo[1]; delayed = true; userclass="delayed"; break; } } userslist = userslist + '<button type="button" onclick="DeleteUser(\''+usersinfo[0]+'\');">Delete</button>'; userslist = userslist + '<button type="button" onclick="PrintQrCode(\''+usersinfo[0]+'\');">Print</button>'; userslist = userslist + '<button type="button" onclick="PrintScratchlist(\''+usersinfo[0]+'\');">Scratchlist</button>'; userslist = userslist + '<button type="button" onclick="ResyncUser(\''+usersinfo[0]+'\');">Resync</button>'; userslist = userslist + ' '; if (userclass != '') { userslist = userslist + '<span class="' + userclass + '">'; } userslist = userslist + usersinfo[0]; if (synced) { userslist = userslist + ' ' + '[AD/LDAP]'; } if (locked) { userslist = userslist + ' (locked, <a href="#" onclick="UnlockUser(\''+usersinfo[0]+'\');">unlock</a>)'; } if (delayed) { var delay_end = new Date(delayed_time * 1000 ); userslist = userslist + ' (delayed until ' + delay_end.toLocaleDateString() + ' ' + delay_end.toLocaleTimeString() + ', <a href="#" onclick="UnlockUser(\''+usersinfo[0]+'\');">unlock</a>)'; } if (userclass != '') { userslist = userslist + '</span>'; } userslist = userslist + '<br />'; counter++; } } } document.getElementById('userslist').innerHTML = userslist; userscounter_txt = ''; userstitle_txt = 'List of users'; if (counter > 0) { userscounter_txt = '('+counter+' user'; if (counter > 1) { userscounter_txt = userscounter_txt + 's'; // userstitle_txt = userstitle_txt + 's'; } userscounter_txt = userscounter_txt + ')'; } document.getElementById('userscounter').innerHTML = userscounter_txt; document.getElementById('userstitle').innerHTML = userstitle_txt; } </script><script type='text/javascript' src='md5.js'></script> </head> <body onload=" if (UpdatePage()) { Toggle('add_user', 'block'); document.getElementById('newuser').focus(); }"> <h2>multi<i>OTP</i> web administration console</h2> the open source strong authentication library <br /> $class_name $class_version $class_date <br /> <!-- div id="custom_info"> <br /> <span class="custom_logo_white">Dev</span><span class="custom_logo_red">(</span><span class="custom_logo_white">Talks</span><span class="custom_logo_red">)</span><span class="custom_logo_white">: Edition</span> <br /> <br /> </div --> Web service is ready $actual_date, $server_software $rpi_info<hr /> <div id="login_section"> <form> <div id="package_info_section"> This package is the result of a *bunch* of work. If you find this package useful, <a target="_blank" href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=B78FJAH6RBNZ2">[Donation]</a> are always welcome to support this project. <br /> Please check <a target="_blank" href="https://www.multiotp.net/">https://www.multiotp.net/</a> and you will find the magic button ;-) <br /> Visit <a target="_blank" href="http://forum.multiotp.net/">http://forum.multiotp.net/</a> for additional support. <hr /> \-_infoweb_-/ </div> <hr /> <div class="section_title" id="login_title"><span id="login_text">Login</span></div> Username: <input type=text" name="user" id="user" length="20" value="" /> $default_user_info <br /> Password: <input type="password" onfocus="this.value='';" name="password" id="password" length="20" value="" /> $default_password_info <br /> <span id="login"><button type="button" onclick="Login();" >Login</button></span> </form> </div> <div id="logout_section"> <div id="log_info"></span><span id="logged"></div> <form> <span id="logout"><button type="button" onclick="Logout();">Logout</button></span> </form> <hr /> </div> <div id="authenticated_section"> <iframe name="hidden_frame" id="hidden_frame" style="display:none;"></iframe> <div class="section_title" id="change_password_title"><a href="#" onclick="Toggle('change_password');"><span id="change_password_toggle">[+]</span> <span id="change_password_text">Change admin password</span></a></div> <div id="change_password_section" style="display:none;"> <form> <table> <tr> <th> New admin password: </th> <td> <input type="password" name="newpassword" id="newpassword" length="20" value="" /> </td> </tr> <tr> <th> Retype new admin password: </th> <td> <input type="password" name="newpassword2" id="newpassword2" length="20" value="" /> </td> </tr> <tr> <th> </th> <td> <button type="button" onclick="ChangeAdminPassword();">Apply</button> </td> </tr> </table> </form> <hr /> </div> <div class="section_title" id="import_tokens_title"><a href="#" onclick="Toggle('import_tokens');"><span id="import_tokens_toggle">[+]</span> <span id="import_tokens_text">Import new hardware tokens</span></a></div> <div id="import_tokens_section" style="display:none;"> <form target="hidden_frame" enctype="multipart/form-data" method="post" action=""> <table> <tr> <th> Import tokens definition file (OATH PSKC, Yubico, etc.): </th> <td> <input type="file" name="token_file" id="token_file" /> </td> <tr> <tr> <th> Password (if any): </th> <td> <input type="password" name="token_password" id="token_password" /> </td> <tr> </tr> <th> </th> <td> <input type="submit" value="Import" onClick="Toggle('import_tokens', 'none'); setTimeout(function(){UpdateTokensList()},2500);" /> </td> </tr> </table> </form> <hr /> </div> <div class="section_title" id="list_tokens_title"><a href="#" onclick="Toggle('list_tokens');"><span id="list_tokens_toggle">[+]</span> <span id="list_tokens_text"><span id="tokenstitle">List of hardware tokens</span></span></a> <span class="info" id="tokenscounter"></span></div> <div id="list_tokens_section" style="display:none;"> <br /> <div id="tokenslist"></div> <hr /> </div> <div class="section_title" id="add_user_title"><a href="#" onclick="Toggle('add_user');"><span id="add_user_toggle">[-]</span> <span id="add_user_text">Add a new user</span></a></div> <div id="add_user_section" style="display:block;"> <form> <table> <tr> <th> Username: </th> <td> <input type=text" name="newuser" id="newuser" length="20" value="" /> </td> </tr> <tr> <th> Email address: </th> <td> <input type=text" name="newemail" id="newemail" length="30" value="" /> </td> </tr> <tr> <th> Mobile phone (SMS): </th> <td> <input type=text" name="newsms" id="newsms" length="30" value="" /> </td> </tr> <tr> <th> With prefix PIN: </th> <td> <input type="radio" name="prefix_required" id="prefix_required1" $prefix_required1_checked value="1">yes</input> <input type="radio" name="prefix_required" id="prefix_required0" $prefix_required0_checked value="0">no</input> </td> </tr> <tr> <th> Specific prefix PIN: </th> <td> <input type=text" name="pin" id="pin" length="30" value="" /> </td> </tr> <tr> <th> Select a token: </th> <td> <select name="token_serial" id="token_serial" onchange="if ('' != this.value) { document.getElementById('token_type').style.display = 'none' } else { document.getElementById('token_type').style.display = 'table-row' };"> <option value="" selected="selected">software</option> </select> </td> </tr> <tr id="token_type" style="display:table-row;"> <th> Token type: </th> <td> <select name="algorithm" id="algorithm"> <option value="TOTP" selected="selected">TOTP</option> <option value="HOTP">HOTP</option> <option value="MOTP">MOTP</option> <option value="without2FA">without2FA</option> </select> </td> </tr> <tr> <th> </th> <td> <button type="button" onclick="Add();">Add this user</button> </td> </tr> </table> </form> <hr /> </div> <div class="section_title" id="resync_title"><a href="#" onclick="Toggle('resync');"><span id="resync_toggle">[+]</span> <span id="resync_text">Resync a user</span></a></div> <div id="resync_section" style="display:none;"> <form> <table> <tr> <th> User to resync: </th> <td> <input type="text" name="resync_user" id="resync_user" length="20" value="" /> </td> </tr> <tr> <th> First OTP: </th> <td> <input type="text" name="resync_otp1" id="resync_otp1" length="20" value="" /> </td> </tr> <tr> <th> Second OTP: </th> <td> <input type="text" name="resync_otp2" id="resync_otp2" length="20" value="" /> </td> </tr> <tr> <th> </th> <td> <button type="button" onclick="ResyncUserNow(document.getElementById('resync_user').value, document.getElementById('resync_otp1').value, document.getElementById('resync_otp2').value);">Resync now</button> </td> </tr> </table> </form> </div> <div class="section_title" id="check_user_title"><a href="#" onclick="Toggle('check_user');"><span id="check_user_toggle">[+]</span> <span id="check_user_text">Check a user</span></a></div> <div id="check_user_section" style="display:none;"> <form> <table> <tr> <th> User to check: </th> <td> <input type="text" name="check_user_user" id="check_user_user" length="50" value="" /> </td> </tr> <tr> <th> OTP (with prefix if needed): </th> <td> <input type="text" name="check_user_otp" id="check_user_otp" length="50" value="" /> </td> </tr> <tr> <th> </th> <td> <button type="button" onclick="CheckUserNow(document.getElementById('check_user_user').value, document.getElementById('check_user_otp').value);">Check now</button> </td> </tr> <tr> <th> Test result: </th> <td> <span id="check_user_result"></span> </td> </tr> </table> </form> </div> <div class="section_title" id="backup_config_title"><a href="#" onclick="Toggle('backup_config');"><span id="backup_config_toggle">[+]</span> <span id="backup_config_text">Backup the configuration</span></a></div> <div id="backup_config_section" style="display:none;"> <form> <table> <tr> <th> Backup password (cannot be empty): </th> <td> <input type="text" name="backup_config_password" id="backup_config_password" length="50" value="" /> </td> </tr> <tr> <th> </th> <td> <button type="button" onclick="BackupConfigNow(document.getElementById('backup_config_password').value);">Backup configuration now</button> </td> </tr> </table> </form> </div> <div class="section_title" id="restore_config_title"><a href="#" onclick="Toggle('restore_config');"><span id="restore_config_toggle">[+]</span> <span id="restore_config_text">Restore the configuration</span></a></div> <div id="restore_config_section" style="display:none;"> <form target="_self" enctype="multipart/form-data" method="post" action=""> <table> <tr> <th> Configuration file (*.cfg): </th> <td> <input type="file" name="config_file" id="config_file" /> </td> <tr> <tr> <th> Restore password (cannot be empty): </th> <td> <input type="password" name="restore_config_password" id="restore_config_password" /> </td> <tr> </tr> <th> </th> <td> <input type="submit" value="Restore configuration now" /> </td> </tr> </table> </form> <iframe name="upload_frame" id="upload_frame" style="display:none;"></iframe> <hr /> </div> <hr /> <div class="section_title" id="list_users_title"><span id="list_users_toggle"></span><span id="list_users_text"><span id="userstitle">List of users</span></span> <span class="info" id="userscounter"></span></div> <div id="list_users_section" style="display:block;"> <br /> <div id="userslist"></div> </div> </div> </body> </html> EOWEBPAGE; $infoweb = ""; $infoweb_filename = "infoweb.html"; if (file_exists($multiotp->GetConfigFolder().$infoweb_filename)) { if ($infoweb_handler = @fopen($multiotp->GetConfigFolder().$infoweb_filename, "rt")) { $infoweb = nullable_trim(fgets($infoweb_handler)); fclose($infoweb_handler); } } if (nullable_trim($infoweb == "")) { $infoweb = <<<EOI <i> Are you interested in additional features like automatic syncronization of AD/LDAP users, provisioning PDF automatic email distribution, API automation, HA in master-slave mode and many others, everything through an easy and fast web interface ? <br /> Check out our commercial editions here: <a target="_blank" href="https://www.multiOTP.com/">https://www.multiOTP.com/</a> </i> EOI; } $webpage = str_replace('\-_infoweb_-/', $infoweb, $webpage); echo $webpage; } else { /********************* * Basic Ajax server * *********************/ $method = preg_replace('/[^(x20-\x7F)]*/','', $method); // This filtering is not working for full UTF-8 support // $options = preg_replace('/[^(\x09\x20-\x7E\xA0-\xFF)]*/','', $options); $options = preg_replace('/[^(\x09\x20-\xFF)]*/','', $options); $options_array = explode("\t",$options); // Set the default password to 1234 if no password is set if ('' == $multiotp->GetConfigAttribute('admin_password_hash')) { $multiotp->SetAdminPassword('1234'); $multiotp->WriteConfigData(); } if (!isset($_SESSION['logged'])) { $_SESSION['logged'] = FALSE; } if (!isset($_SESSION['random_salt'])) { $random_salt = mb_substr(md5(time()."@".rand(100000,999999)),0,12); $_SESSION['random_salt'] = $random_salt; } $multiotp->SetRandomSalt($_SESSION['random_salt']); $ajax_result = "false"; switch (mb_strtoupper($method,'UTF-8')) { case mb_strtoupper("GetRandomSalt",'UTF-8'): $ajax_result = $multiotp->GetRandomSalt(); break; case mb_strtoupper("Login",'UTF-8'): $result = FALSE; $username = mb_substr(isset($options_array[0])?$options_array[0]:'',0,255); $password = mb_substr(isset($options_array[1])?$options_array[1]:'',0,255); if ('admin' == $username) { $result = $multiotp->CheckAdminPasswordHashWithRandomSalt($password); } if ($result) { $_SESSION['logged'] = TRUE; /* And we change the random_salt to avoid a second login with the same previous hash */ $random_salt = mb_substr(md5(time()."@".rand(100000,999999)),0,12); $_SESSION['random_salt'] = $random_salt; $multiotp->SetRandomSalt($random_salt); $ajax_result = "true"; } else { $_SESSION = array(); $_SESSION['logged'] = FALSE; $ajax_result = "false"; } break; default: if ((isset($_SESSION['logged']) && $_SESSION['logged'])) { /******************************************************* * The next methods are allowed only if we are logged in *******************************************************/ switch (mb_strtoupper($method,'UTF-8')) { case mb_strtoupper("DeleteUser",'UTF-8'): $ajax_result = $multiotp->DeleteUser($options_array[0]); break; case mb_strtoupper("DeleteToken",'UTF-8'): $ajax_result = $multiotp->DeleteToken($options_array[0]); break; case mb_strtoupper("FastCreateUser",'UTF-8'): $user = nullable_trim((isset($options_array[0])?$options_array[0]:'')); $email = nullable_trim((isset($options_array[1])?$options_array[1]:'')); $sms = nullable_trim((isset($options_array[2])?$options_array[2]:'')); $prefix_pin_needed = intval(isset($options_array[3])?$options_array[3]:$multiotp->GetDefaultRequestPrefixPin()); $algorithm = (isset($options_array[4])?$options_array[4]:"totp"); $pin = (isset($options_array[5])?$options_array[5]:''); $token_serial = nullable_trim((isset($options_array[6])?$options_array[6]:'')); if ('' != $token_serial) { $ajax_result = $multiotp->CreateUserFromToken($user, $token_serial, $email, $sms, $pin, $prefix_pin_needed); } else { $ajax_result = $multiotp->FastCreateUser($user, $email, $sms, $prefix_pin_needed, $algorithm, 1, '', '*DEFAULT*', 0, $pin); } if (isset($options_array[3])) { $multiotp->SetDefaultRequestPrefixPin(intval($options_array[3])); $multiotp->WriteConfigData(); } break; case mb_strtoupper("GetFullVersionInfo",'UTF-8'): $ajax_result = $multiotp->GetFullVersionInfo(); break; case mb_strtoupper("GetTokensList",'UTF-8'): $ajax_result = $multiotp->GetTokensList(); break; case mb_strtoupper("GetUsersList",'UTF-8'): $ajax_result = $multiotp->GetUsersList(); break; case mb_strtoupper("GetDelayedUsersList",'UTF-8'): $ajax_result = $multiotp->GetDelayedUsersList(); break; case mb_strtoupper("GetLockedUsersList",'UTF-8'): $ajax_result = $multiotp->GetLockedUsersList(); break; case mb_strtoupper("GetEnhancedUsersList",'UTF-8'): $ajax_result = $multiotp->GetEnhancedUsersList(); break; case mb_strtoupper("PrintQrCode",'UTF-8'): echo $multiotp->GenerateHtmlQrCode($options_array[0]); $ajax_result = ''; break; case mb_strtoupper("PrintScratchlist",'UTF-8'): echo $multiotp->GenerateHtmlScratchlist($options_array[0]); $ajax_result = ''; break; case mb_strtoupper("ResyncUser",'UTF-8'): $ajax_result = "false"; if ($multiotp->ReadUserData($options_array[0])) { $result = $multiotp->CheckToken($options_array[1], $options_array[2]); if (14 == $result) { // 14 Token has been resynchronized successfully $ajax_result = "true"; } } break; case mb_strtoupper("CheckToken",'UTF-8'): $ajax_result = '21 '.$multiotp->GetErrorText(21); if ($multiotp->ReadUserData($options_array[0])) { $result = $multiotp->CheckToken($options_array[1]); if (0 == $result) { $ajax_result = "true"; } else { $ajax_result = $result.' '.$multiotp->GetErrorText($result); } } break; case mb_strtoupper("BackupConfig",'UTF-8'): $tmp = '/tmp'; if (!file_exists($tmp)) { $tmp = $multiotp->ConvertToWindowsPathIfNeeded($multiotp->GetScriptFolder()."../_temp"); } $backup_file_name = "multiotp-".date('Y-m-d-His').".cfg"; $backup_config_file = "$tmp/$backup_file_name"; if (file_exists($backup_config_file)) { unlink($backup_config_file); } $result = $multiotp->BackupConfiguration(array("backup_file" => $backup_config_file, "encryption_key" => $options_array[0], "flush_attributes" => array("admin_password_hash"), "return_content" => FALSE)); if ($result) { // $size = filesize($backup_config_file); header("Expires: " . gmdate("D, d M Y H:i:s") . " GMT"); header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); header("Cache-Control: no-store, no-cache, must-revalidate"); header("Cache-Control: post-check=0, pre-check=0", false); header("Pragma: no-cache"); header("Content-Type: application/force-download"); header("Content-Type: application/octet-stream"); header("Content-Type: application/download\n"); header("Content-Disposition: attachment; filename=\"".basename($backup_config_file)."\""); header("Content-Transfer-Encoding: binary"); // header("Content-Length: $size"); $fn=fopen($backup_config_file, "rb"); while(!feof($fn)) { @set_time_limit(0); echo fread($fn, 1024*8); flush(); } fclose($fn); $ajax_result = ''; } else { echo "*** BACKUP ERROR ***"; } break; case mb_strtoupper("SetAdminPasswordHash",'UTF-8'): if ($multiotp->IsDemoMode()) { $result = "false"; } else { $ajax_result = $multiotp->SetAdminPasswordHash($options_array[0]); $multiotp->WriteConfigData(); } break; case mb_strtoupper("UnlockUser",'UTF-8'): $ajax_result = $multiotp->UnlockUser($options_array[0]); break; case mb_strtoupper("UserLoggedIn",'UTF-8'): $ajax_result = "true"; //User is logged if code arrives here! break; default: $ajax_result = "false"; break; } } else { $ajax_result = "false"; } break; } if ('' != $ajax_result) { echo json_encode($ajax_result); } @ob_flush(); flush(); } } ?>