<?php 
/** 
 * @file  multiotp.cli.proxy.php 
 * @brief Command line calling the proxy of the multiOTP PHP class. 
 * 
 * multiOTP PHP CLI proxy - Strong two-factor authentication PHP class 
 * http://www.multiotp.net 
 * 
 * Visit http://forum.multiotp.net/ for additional support. 
 * 
 * Donation are always welcome! Please check http://www.multiotp.net 
 * and you will find the magic button ;-) 
 * 
 * 
 * PHP 5.3.0 or higher is supported. 
 * 
 * @author    Andre Liechti, SysCo systemes de communication sa, <[email protected]> 
 * @version   5.6.1.5 
 * @date      2019-10-23 
 * @since     2010-06-08 
 * @copyright (c) 2010-2019 SysCo systemes de communication sa 
 * @copyright GNU Lesser General Public License 
 * 
 *//* 
 * 
 * LICENCE 
 * 
 *   Copyright (c) 2014-2019 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/>. 
 * 
 * 
 * Command line usage 
 * 
 *   Same usage as multiotp.cli.header.php. It's just a proxy to call 
 *    the web version of multiotp.cli.header.php, which could be cached, 
 *    giving a massive speed improvement on "weak" machines like Raspberry Pi. 
 * 
 *   If the web version is not responding, it will fallback nicely and 
 *     will do a require_once of the local proxy file. 
 * 
 *********************************************************************/ 
 
@set_time_limit(0); // It can take a lot of time... 
 
global $argc; 
global $argv; 
 
// Define the stream context 
if (function_exists("stream_context_set_default")) { 
  $default_ssl_context = array( 
    'ssl' => array( 
      'verify_peer'         => false, 
      'verify_peer_name'    => false, 
      'disable_compression' => true, 
      'ciphers'             => 'ALL!EXPORT!EXPORT40!EXPORT56!aNULL!LOW!RC4' 
    ) 
  ); 
  $default_context = stream_context_set_default($default_ssl_context); 
} 
 
$proxy_full_url = isset($proxy_full_url) ? $proxy_full_url : "http://127.0.0.1:18081/"; 
$timeout = isset($timeout)?intval($timeout):15; 
$local_proxy_file = isset($local_proxy_file) ? $local_proxy_file : "multiotp.proxy.php"; 
 
// Clean quotes of the parameters if any 
if (!function_exists('clean_quotes')) { 
  function clean_quotes($value) 
  { 
    $cleaned = false; 
    $var = $value; 
    if ((('"' == substr($var,0,1)) || ("'" == substr($var,0,1))) && (('"' == substr($var,-1)) || ("'" == substr($var,-1)))) { 
      $var = substr($var, 1, strlen($var)-2); 
      $cleaned = true; 
    } 
    if ($cleaned) { 
      $var = clean_quotes($var); 
    } 
    return $var; 
  } 
} 
 
$value_unencoded = ''; 
// $_SERVER["argv"][0] is useless, it's the name of the script 
 
$argv = isset($_SERVER["argv"]) ? $_SERVER["argv"] : (isset($argv) ? $argv : ""); 
$argc = intval(isset($_SERVER["argc"]) ? $_SERVER["argc"] : (isset($argc) ? $argc : 0)); 
 
for ($arg_loop=1; $arg_loop < $argc; $arg_loop++) { 
  $current_arg = clean_quotes($argv[$arg_loop]); 
  if ('' != $value_unencoded) { 
    $value_unencoded.= chr(0); 
  } 
  $value_unencoded.= $current_arg; 
} 
 
$key = 'argv'; 
$value = base64_encode($value_unencoded); 
 
$multiotp_error_level_received = FALSE; 
$multiotp_error_level = 99; // Unknown error 
 
$post_url = $proxy_full_url; 
 
$result = ''; 
$content_to_post = $key.'='.$value; 
 
$pos = mb_strpos($post_url, '://'); 
if (FALSE === $pos) { 
  $protocol = ''; 
} else { 
  switch (mb_strtolower(substr($post_url,0,$pos))) { 
    case 'https': 
    case 'ssl': 
        $protocol = 'ssl://'; 
        break; 
    case 'tls': 
        $protocol = 'tls://'; 
        break; 
    default: 
        $protocol = ''; 
        break; 
  } 
  $post_url = substr($post_url,$pos+3); 
} 
 
$pos = mb_strpos($post_url, '/'); 
if (FALSE === $pos) { 
  $host = $post_url; 
  $url = '/'; 
} else { 
  $host = substr($post_url,0,$pos); 
  $url = substr($post_url,$pos); // And not +1 as we want the / at the beginning 
} 
 
$pos = mb_strpos($host, ':'); 
if (FALSE === $pos) { 
  $port = 80; 
} else { 
  $port = substr($host,$pos+1); 
  $host = substr($host,0,$pos); 
} 
 
$errno = 0; 
$errdesc = 0; 
$fp = @fsockopen($protocol.$host, $port, $errno, $errdesc, $timeout); 
if (FALSE !== $fp) { 
  $info['timed_out'] = FALSE; 
  fputs($fp, "POST ".$url." HTTP/1.0\r\n"); 
  fputs($fp, "Content-Type: application/x-www-form-urlencoded\r\n"); 
  fputs($fp, "Content-Length: ".strlen($content_to_post)."\r\n"); 
  fputs($fp, "User-Agent: multiOTP proxy\r\n"); 
  fputs($fp, "Host: ".$host."\r\n"); 
  fputs($fp, "\r\n"); 
  fputs($fp, $content_to_post); 
  fputs($fp, "\r\n"); 
 
  stream_set_blocking($fp, TRUE); 
  stream_set_timeout($fp, 86400); // It can take a lot of time, if we are doing AD/LDAP sync for example 
  $info = stream_get_meta_data($fp);  
 
  $reply = ''; 
  $last_length = 0; 
  while ((!feof($fp)) && ((!$info['timed_out']) || ($last_length != strlen($reply)))) { 
    $last_length = strlen($reply); 
    $reply.= fgets($fp, 1024); 
    $info = stream_get_meta_data($fp); 
    @ob_flush(); // Avoid notice if any (if the buffer is empty and therefore cannot be flushed) 
    flush();  
  } 
  fclose($fp); 
 
  if ($info['timed_out']) { 
    // error_log("Warning: timeout after $timeout seconds for $protocol$host:$port$url with a result code of $errno ($errdesc)"); 
  } else { 
    // error_log("CLI ok"); 
    $pos = mb_strpos(mb_strtolower($reply), "\r\n\r\n"); 
    $header = substr($reply, 0, $pos); 
     
    $header_array = explode("\r\n", $header); 
    foreach($header_array as $one_header) { 
      $one_header_array = explode(":", $one_header, 2); 
      if (isset($one_header_array[1])) { 
        if ('X-multiOTP-Error-Level' == trim($one_header_array[0])) { 
          $multiotp_error_level_received = TRUE; 
          $multiotp_error_level = intval(trim($one_header_array[1])); 
          break; 
        } 
      } 
    } 
     
    $answer = substr($reply, $pos + 4); 
     
    $result = $answer; 
    if ($errno > 0) { 
      // Error ? 
    } 
  } 
} 
 
if (!$multiotp_error_level_received) { 
  require_once(dirname(__FILE__)."/".$local_proxy_file); 
} else { 
  echo $result; 
  exit($multiotp_error_level); 
} 
?>
 
 |