Subversion Repositories oidplus

Rev

Rev 115 | Rev 148 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. <?php
  2.  
  3. /*
  4.  * OIDplus 2.0
  5.  * Copyright 2019 Daniel Marschall, ViaThinkSoft
  6.  *
  7.  * Licensed under the Apache License, Version 2.0 (the "License");
  8.  * you may not use this file except in compliance with the License.
  9.  * You may obtain a copy of the License at
  10.  *
  11.  *     http://www.apache.org/licenses/LICENSE-2.0
  12.  *
  13.  * Unless required by applicable law or agreed to in writing, software
  14.  * distributed under the License is distributed on an "AS IS" BASIS,
  15.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16.  * See the License for the specific language governing permissions and
  17.  * limitations under the License.
  18.  */
  19.  
  20. if (!defined('IN_OIDPLUS')) die();
  21.  
  22. class OIDplus {
  23.         private static /*OIDplusPagePlugin[][]*/ $pagePlugins = array();
  24.         private static /*OIDplusObject*/ $objectTypes = array();
  25.         private static /*OIDplusObject*/ $disabledObjectTypes = array();
  26.  
  27.         private function __construct() {
  28.         }
  29.  
  30.         public static function db() {
  31.                 static $database = null;
  32.                 if (is_null($database)) {
  33.                         $database = new OIDplusDataBaseMySQL();
  34.                 }
  35.                 return $database;
  36.         }
  37.  
  38.         public static function config() {
  39.                 static $config = null;
  40.                 if (is_null($config)) {
  41.                         $config = new OIDplusConfig();
  42.                 }
  43.                 return $config;
  44.         }
  45.  
  46.         public static function gui() {
  47.                 static $gui = null;
  48.                 if (is_null($gui)) {
  49.                         $gui = new OIDplusGui();
  50.                 }
  51.                 return $gui;
  52.         }
  53.  
  54.         public static function authUtils() {
  55.                 static $authUtils = null;
  56.                 if (is_null($authUtils)) {
  57.                         $authUtils = new OIDplusAuthUtils();
  58.                 }
  59.                 return $authUtils;
  60.         }
  61.  
  62.         public static function logger() {
  63.                 static $logger = null;
  64.                 if (is_null($logger)) {
  65.                         $logger = new OIDplusLogger();
  66.                 }
  67.                 return $logger;
  68.         }
  69.  
  70.         public static function sesHandler() {
  71.                 static $sesHandler = null;
  72.                 if (is_null($sesHandler)) {
  73.                         $sesHandler = new OIDplusSessionHandler(OIDPLUS_SESSION_SECRET);
  74.                 }
  75.                 return $sesHandler;
  76.         }
  77.  
  78.         public static function system_url($relative=false) {
  79.                 if (!isset($_SERVER["REQUEST_URI"])) return false;
  80.  
  81.                 $test_dir = dirname($_SERVER['SCRIPT_FILENAME']);
  82.                 $c = 0;
  83.                 while (!file_exists($test_dir.'/oidplus.js')) {
  84.                         $test_dir = dirname($test_dir);
  85.                         $c++;
  86.                         if ($c == 1000) return false;
  87.                 }
  88.  
  89.                 $res = dirname($_SERVER['REQUEST_URI'].'xxx');
  90.  
  91.                 for ($i=1; $i<=$c; $i++) {
  92.                         $res = dirname($res);
  93.                 }
  94.  
  95.                 $res .= '/';
  96.  
  97.                 if (!$relative) {
  98.                         $res = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://$_SERVER[HTTP_HOST]" . $res; // TODO: also add port?
  99.                 }
  100.  
  101.                 return $res;
  102.         }
  103.  
  104.         public static function registerPagePlugin(OIDplusPagePlugin $plugin) {
  105.                 $type = $plugin->type();
  106.                 if ($type === false) return false;
  107.  
  108.                 $prio = $plugin->priority();
  109.                 if ($prio === false) return false;
  110.  
  111.                 if (!isset(self::$pagePlugins[$type])) self::$pagePlugins[$type] = array();
  112.                 self::$pagePlugins[$type][$prio] = $plugin;
  113.  
  114.                 return true;
  115.         }
  116.  
  117.         public static function getPagePlugins($type) {
  118.                 if ($type == '*') {
  119.                         $res = array();
  120.                         foreach (self::$pagePlugins as $data) {
  121.                                 $res = array_merge($res, $data);
  122.                         }
  123.                 } else {
  124.                         $res = isset(self::$pagePlugins[$type]) ? self::$pagePlugins[$type] : array();
  125.                 }
  126.                 ksort($res);
  127.                 return $res;
  128.         }
  129.  
  130.         public static function registerObjectType($ot) {
  131.                 $ns = $ot::ns();
  132.  
  133.                 if (empty($ns)) die("Attention: Empty NS at $ot\n");
  134.  
  135.                 $ns_found = false;
  136.                 foreach (OIDplus::getRegisteredObjectTypes() as $test_ot) {
  137.                         if ($test_ot::ns() == $ns) {
  138.                                 $ns_found = true;
  139.                                 break;
  140.                         }
  141.                 }
  142.                 if ($ns_found) {
  143.                         throw new Exception("Attention: Two objectType plugins use the same namespace \"$ns\"!");
  144.                 }
  145.  
  146.                 $init = OIDplus::config()->getValue("objecttypes_initialized");
  147.                 $init_ary = empty($init) ? array() : explode(';', $init);
  148.                 $init_ary = array_map('trim', $init_ary);
  149.  
  150.                 $enabled = OIDplus::config()->getValue("objecttypes_enabled");
  151.                 $enabled_ary = empty($enabled) ? array() : explode(';', $enabled);
  152.                 $enabled_ary = array_map('trim', $enabled_ary);
  153.  
  154.                 $do_enable = false;
  155.                 if (in_array($ns, $enabled_ary)) {
  156.                         $do_enable = true;
  157.                 } else {
  158.                         if (!OIDplus::config()->getValue('registration_done')) {
  159.                                 $do_enable = $ns == 'oid';
  160.                         } else {
  161.                                 $do_enable = !in_array($ns, $init_ary);
  162.                         }
  163.                 }
  164.  
  165.                 if ($do_enable) {
  166.                         self::$objectTypes[] = $ot;
  167.                         usort(self::$objectTypes, function($a, $b) {
  168.                                 $enabled = OIDplus::config()->getValue("objecttypes_enabled");
  169.                                 $enabled_ary = explode(';', $enabled);
  170.  
  171.                                 $idx_a = array_search($a::ns(), $enabled_ary);
  172.                                 $idx_b = array_search($b::ns(), $enabled_ary);
  173.  
  174.                                 if ($idx_a == $idx_b) {
  175.                                     return 0;
  176.                                 }
  177.                                 return ($idx_a > $idx_b) ? +1 : -1;
  178.                         });
  179.                 } else {
  180.                         self::$disabledObjectTypes[] = $ot;
  181.                 }
  182.  
  183.                 if (!in_array($ns, $init_ary)) {
  184.                         // Was never initialized before, so we add it to the list of enabled object types once
  185.  
  186.                         if ($do_enable) {
  187.                                 $enabled_ary[] = $ns;
  188.                                 OIDplus::config()->setValue("objecttypes_enabled", implode(';', $enabled_ary));
  189.                         }
  190.  
  191.                         $init_ary[] = $ns;
  192.                         OIDplus::config()->setValue("objecttypes_initialized", implode(';', $init_ary));
  193.                 }
  194.         }
  195.  
  196.         public static function getRegisteredObjectTypes() {
  197.                 return self::$objectTypes;
  198.         }
  199.  
  200.         public static function getDisabledObjectTypes() {
  201.                 return self::$disabledObjectTypes;
  202.         }
  203.  
  204.         private static $system_id_cache = null;
  205.         public static function system_id($oid=false) {
  206.                 if (!is_null(self::$system_id_cache)) {
  207.                         $out = self::$system_id_cache;
  208.                 } else {
  209.                         $out = false;
  210.  
  211.                         if (self::pkiStatus(true)) {
  212.                                 $pubKey = OIDplus::config()->getValue('oidplus_public_key');
  213.                                 if (preg_match('@BEGIN PUBLIC KEY\-+(.+)\-+END PUBLIC KEY@ismU', $pubKey, $m)) {
  214.                                         $out = smallhash(base64_decode($m[1]));
  215.                                 }
  216.                         }
  217.                         self::$system_id_cache = $out;
  218.                 }
  219.                 return ($oid ? '1.3.6.1.4.1.37476.30.9.' : '').$out;
  220.         }
  221.  
  222.         public static function pkiStatus($try_generate=true) {
  223.                 if (!function_exists('openssl_pkey_new')) return false;
  224.  
  225.                 $privKey = OIDplus::config()->getValue('oidplus_private_key');
  226.                 $pubKey = OIDplus::config()->getValue('oidplus_public_key');
  227.  
  228.                 if ($try_generate && !verify_private_public_key($privKey, $pubKey)) {
  229.                         $config = array(
  230.                             "digest_alg" => "sha512",
  231.                             "private_key_bits" => 2048,
  232.                             "private_key_type" => OPENSSL_KEYTYPE_RSA,
  233.                         );
  234.  
  235.                         // Create the private and public key
  236.                         $res = openssl_pkey_new($config);
  237.  
  238.                         // Extract the private key from $res to $privKey
  239.                         openssl_pkey_export($res, $privKey);
  240.  
  241.                         OIDplus::config()->setValue('oidplus_private_key', $privKey);
  242.  
  243.                         // Extract the public key from $res to $pubKey
  244.                         $pubKey = openssl_pkey_get_details($res);
  245.                         $pubKey = $pubKey["key"];
  246.  
  247.                         OIDplus::config()->setValue('oidplus_public_key', $pubKey);
  248.                 }
  249.  
  250.                 return verify_private_public_key($privKey, $pubKey);
  251.         }
  252.  
  253.         public static function init($html=true) {
  254.                 define('OIDPLUS_HTML_OUTPUT', $html);
  255.  
  256.                 // Include config file
  257.  
  258.                 if (file_exists(__DIR__ . '/../config.inc.php')) {
  259.                         include_once __DIR__ . '/../config.inc.php';
  260.                 } else {
  261.                         if ($html) {
  262.                                 if (!is_dir('setup')) {
  263.                                         echo 'Error: Setup directory missing.';
  264.                                 } else {
  265.                                         header('Location:setup/');
  266.                                 }
  267.                         } else {
  268.                                 echo 'Error: Setup directory missing!';
  269.                         }
  270.                         die();
  271.                 }
  272.  
  273.                 // Auto-fill non-existing config values
  274.  
  275.                 if (!defined('OIDPLUS_CONFIG_VERSION'))   define('OIDPLUS_CONFIG_VERSION',   0.0);
  276.                 if (!defined('OIDPLUS_ADMIN_PASSWORD'))   define('OIDPLUS_ADMIN_PASSWORD',   '');
  277.                 if (!defined('OIDPLUS_MYSQL_HOST'))       define('OIDPLUS_MYSQL_HOST',       'localhost');
  278.                 if (!defined('OIDPLUS_MYSQL_USERNAME'))   define('OIDPLUS_MYSQL_USERNAME',   'root');
  279.                 if (!defined('OIDPLUS_MYSQL_PASSWORD'))   define('OIDPLUS_MYSQL_PASSWORD',   '');
  280.                 if (!defined('OIDPLUS_MYSQL_DATABASE'))   define('OIDPLUS_MYSQL_DATABASE',   'oidplus');
  281.                 if (!defined('OIDPLUS_TABLENAME_PREFIX')) define('OIDPLUS_TABLENAME_PREFIX', '');
  282.                 if (!defined('OIDPLUS_SESSION_SECRET'))   define('OIDPLUS_SESSION_SECRET',   '');
  283.                 if (!defined('RECAPTCHA_ENABLED'))        define('RECAPTCHA_ENABLED',        false);
  284.                 if (!defined('RECAPTCHA_PUBLIC'))         define('RECAPTCHA_PUBLIC',         '');
  285.                 if (!defined('RECAPTCHA_PRIVATE'))        define('RECAPTCHA_PRIVATE',        '');
  286.                 if (!defined('OIDPLUS_ENFORCE_SSL'))      define('OIDPLUS_ENFORCE_SSL',      2 /* Auto */);
  287.  
  288.                 // Check version of the config file
  289.  
  290.                 if (OIDPLUS_CONFIG_VERSION != 2.0) {
  291.                         if ($html) {
  292.                                 echo '<h1>Error</h1><p>The information located in <b>includes/config.inc.php</b> is outdated.</p><p>Please run <a href="setup/">setup</a> again.</p>';
  293.                         } else {
  294.                                 echo 'The information located in includes/config.inc.php is outdated. Please run setup again.';
  295.                         }
  296.                         die();
  297.                 }
  298.  
  299.                 // Do redirect stuff etc.
  300.  
  301.                 define('OIDPLUS_SSL_AVAILABLE', self::isSslAvailable());
  302.  
  303.                 // System config settings
  304.  
  305.                 OIDplus::config()->prepareConfigKey('objecttypes_initialized', 'List of object type plugins that were initialized once', '', 1, 1);
  306.                 OIDplus::config()->prepareConfigKey('objecttypes_enabled', 'Enabled object types and their order, separated with a semicolon (please reload the page so that the change is applied)', '', 0, 1);
  307.  
  308.                 OIDplus::config()->prepareConfigKey('oidplus_private_key', 'Private key for this system', '', 1, 0);
  309.                 OIDplus::config()->prepareConfigKey('oidplus_public_key', 'Public key for this system. If you "clone" your system, you must delete this key (e.g. using phpMyAdmin), so that a new one is created.', '', 1, 1);
  310.  
  311.                 // Initialize public / private keys
  312.  
  313.                 OIDplus::pkiStatus(true);
  314.  
  315.                 // Register plugins
  316.  
  317.                 $ary = glob(__DIR__ . '/../../plugins/system/'.'*'.'/plugin.inc.php');
  318.                 foreach ($ary as $a) include $a;
  319.                 $ary = glob(__DIR__ . '/../../plugins/publicPages/'.'*'.'/plugin.inc.php');
  320.                 foreach ($ary as $a) include $a;
  321.                 $ary = glob(__DIR__ . '/../../plugins/raPages/'.'*'.'/plugin.inc.php');
  322.                 foreach ($ary as $a) include $a;
  323.                 $ary = glob(__DIR__ . '/../../plugins/adminPages/'.'*'.'/plugin.inc.php');
  324.                 foreach ($ary as $a) include $a;
  325.                 $ary = glob(__DIR__ . '/../../plugins/objectTypes/'.'*'.'/*.class.php');
  326.                 foreach ($ary as $a) include $a;
  327.  
  328.                 // Initialize plugins
  329.  
  330.                 foreach (OIDplus::getPagePlugins('*') as $plugin) {
  331.                         $plugin->init($html);
  332.                 }
  333.         }
  334.  
  335.         public static function getVersion() {
  336.                 $status = @shell_exec('svnversion '.realpath(__FILE__));
  337.                 if (preg_match('/\d+/', $status, $match)) {
  338.                         return 'svn-'.$match[0];
  339.                 } else {
  340.                         return false;
  341.                 }
  342.         }
  343.  
  344.         private static function isSslAvailable() {
  345.                 $timeout = 2;
  346.                 $already_ssl = isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == "on");
  347.                 $ssl_port = 443;
  348.                 $cookie_path = OIDplus::system_url(true);
  349.                 if (empty($cookie_path)) $cookie_path = '/';
  350.  
  351.                 if (php_sapi_name() == 'cli') return false;
  352.  
  353.                 if (OIDPLUS_ENFORCE_SSL == 0) {
  354.                         // No SSL available
  355.                         return $already_ssl;
  356.                 }
  357.  
  358.                 if (OIDPLUS_ENFORCE_SSL == 1) {
  359.                         // Force SSL
  360.                         if ($already_ssl) {
  361.                                 return true;
  362.                         } else {
  363.                                 $location = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
  364.                                 header('Location:'.$location);
  365.                                 die('Redirect to HTTPS');
  366.                                 return true;
  367.                         }
  368.                 }
  369.  
  370.                 if (OIDPLUS_ENFORCE_SSL == 2) {
  371.                         // Automatic SSL detection
  372.  
  373.                         if ($already_ssl) {
  374.                                 // we are already on HTTPS
  375.                                 setcookie('SSL_CHECK', '1', 0, $cookie_path, '', false, true);
  376.                                 return true;
  377.                         } else {
  378.                                 if (isset($_COOKIE['SSL_CHECK'])) {
  379.                                         // We already had the HTTPS detection done before.
  380.                                         if ($_COOKIE['SSL_CHECK']) {
  381.                                                 // HTTPS was detected before, but we are HTTP. Redirect now
  382.                                                 $location = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
  383.                                                 header('Location:'.$location);
  384.                                                 die('Redirect to HTTPS');
  385.                                                 return true;
  386.                                         } else {
  387.                                                 // No HTTPS available. Do nothing.
  388.                                                 return false;
  389.                                         }
  390.                                 } else {
  391.                                         // This is our first check (or the browser didn't accept the SSL_CHECK cookie)
  392.                                         if (@fsockopen($_SERVER['HTTP_HOST'], $ssl_port, $errno, $errstr, $timeout)) {
  393.                                                 // HTTPS detected. Redirect now, and remember that we had detected HTTPS
  394.                                                 setcookie('SSL_CHECK', '1', 0, $cookie_path, '', false, true);
  395.                                                 $location = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
  396.                                                 header('Location:'.$location);
  397.                                                 die('Redirect to HTTPS');
  398.                                                 return true;
  399.                                         } else {
  400.                                                 // No HTTPS detected. Do nothing, and next time, don't try to detect HTTPS again.
  401.                                                 setcookie('SSL_CHECK', '0', 0, $cookie_path, '', false, true);
  402.                                                 return false;
  403.                                         }
  404.                                 }
  405.                         }
  406.                 }
  407.         }
  408. }
  409.