blob: 3032e5a6ce02a5d462d8fbf496bd796474fc73df [file] [log] [blame]
<?php
/*
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
require_once(".ht-inc/secrets.php");
require_once(".ht-inc/authentication.php");
require_once(".ht-inc/spyc-0.5.1/Spyc.php");
if(file_exists(".ht-inc/vcldocs.php"))
require_once(".ht-inc/vcldocs.php");
/**
* \file
*/
/// used for processInputVar, means the input variable should be numeric
define("ARG_NUMERIC", 1);
/// used for processInputVar, means the input variable should be a string
define("ARG_STRING", 1 << 1);
/// used for processInputVar, means the input variable should be an array of numbers
define("ARG_MULTINUMERIC", 1 << 2);
/// used for processInputVar, means the input variable should be an array of strings
define("ARG_MULTISTRING", 1 << 3);
/// global array used to hold request information between calling isAvailable
/// and addRequest
$requestInfo = array();
/// global array to cache arrays of node parents for getNodeParents
$nodeparents = array();
/// global array to cache various data
$cache = array();
/// global variable to store what needs to be printed in printHTMLHeader
$HTMLheader = "";
/// global variable to store if header has been printed
$printedHTMLheader = 0;
spl_autoload_register('vclAutoLoader');
////////////////////////////////////////////////////////////////////////////////
///
/// \fn initGlobals()
///
/// \brief this is where globals get initialized
///
////////////////////////////////////////////////////////////////////////////////
function initGlobals() {
global $mode, $user, $remoteIP, $authed, $oldmode;
global $days, $phpVer, $keys, $pemkey, $submitErr, $submitErrMsg;
global $passwdArray, $skin, $contdata, $lastmode, $inContinuation;
global $ERRORS, $actions;
global $affilValFunc, $addUserFunc, $updateUserFunc, $addUserFuncArgs;
global $uniqid, $cryptkey, $ivsize;
define("SECINDAY", 86400);
define("SECINWEEK", 604800);
define("SECINMONTH", 2678400);
define("SECINYEAR", 31536000);
define("SYMALGO", "AES");
define("SYMOPT", "CBC");
define("SYMLEN", 256);
define("ASYMALGO", "RSA");
define("ASYMOPT", "OAEP");
define("ASYMLEN", 4096);
if(! defined('QUERYLOGGING'))
define('QUERYLOGGING', 1);
# TODO validate security of this
if(array_key_exists("PATH_INFO", $_SERVER)) {
$pathdata = explode("/", $_SERVER["PATH_INFO"]);
$tmp = explode('.', $pathdata[1]);
$_GET["mode"] = $tmp[0];
}
if(function_exists('openssl_encrypt')) {
define('USE_PHPSECLIB', 0);
$cryptkey = base64_decode($cryptkey);
}
else {
define('USE_PHPSECLIB', 1);
require_once(".ht-inc/phpseclib/Crypt/Base.php");
require_once(".ht-inc/phpseclib/Crypt/Rijndael.php");
require_once(".ht-inc/phpseclib/Crypt/AES.php");
require_once(".ht-inc/phpseclib/Crypt/Random.php");
}
$ivsize = 16;
$mode = processInputVar("mode", ARG_STRING, 'main');
$inContinuation = 0;
$contdata = array();
$contuserid = '';
$continuation = processInputVar('continuation', ARG_STRING);
if(! empty($continuation)) {
$tmp = getContinuationsData($continuation);
if(empty($tmp))
abort(11);
elseif(array_key_exists('error', $tmp)) {
$mode = "continuationsError";
$contdata = $tmp;
}
else {
$inContinuation = 1;
$contuserid = $tmp['userid'];
$lastmode = $tmp['frommode'];
$mode = $tmp['nextmode'];
$contdata = $tmp['data'];
}
}
$submitErr = 0;
$submitErrMsg = array();
$remoteIP = $_SERVER["REMOTE_ADDR"];
$days = array(i('Sunday'), i('Monday'), i('Tuesday'), i('Wednesday'), i('Thursday'), i('Friday'), i('Saturday'));
$phpVerArr = explode('.', phpversion());
$phpVer = $phpVerArr[0];
$host = $_SERVER['HTTP_HOST'];
if(strpos($host, ':')) {
$host = substr($host, 0, strpos($host, ':'));
}
$uniqid = uniqid($host . "-" . getmypid() . "-");
$passwdArray = array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '0');
if(isset($_COOKIE['VCLAUTH']) ||
$mode == 'submitLogin' ||
$mode == 'selectauth' ||
$mode == 'xmlrpccall' ||
$mode == 'main') {
// open keys
$fp = fopen(".ht-inc/keys.pem", "r");
$key = fread($fp, 8192);
fclose($fp);
$keys["private"] = openssl_pkey_get_private($key, $pemkey);
if(! $keys['private'])
abort(6);
$fp = fopen(".ht-inc/pubkey.pem", "r");
$key = fread($fp, 8192);
fclose($fp);
$keys["public"] = openssl_pkey_get_public($key);
if(! $keys['public'])
abort(7);
}
# USING A SINGLE USER WITHOUT LOGGING IN:
# to automatically log in to vcl with the same user
# every time, comment out from this comment block to
# the 'end auth check' comment, then, right after
# that, set $authed = 1 and $userid to the id from
# the user table corresponding to the user you want
# logged in
# start auth check
$authed = 0;
if(array_key_exists("VCLAUTH", $_COOKIE)) {
$userid = readAuthCookie();
if(! is_null($userid))
$authed = 1;
}
else {
global $authFuncs;
foreach($authFuncs as $type) {
if($type['test']()) {
$userid = $type['auth']();
if(! is_null($userid)) {
$authed = 1;
break;
}
}
}
}
# end auth check
if($authed && $mode == 'selectauth')
$mode = 'main';
# check that mode is valid
if(! array_key_exists($mode, $actions['pages']))
$mode = 'main';
if(! $authed) {
# set $skin based on cookie (so it gets set before user logs in
# later, we set it by affiliation (helps with 'view as user')
if(array_key_exists('VCLSKIN', $_COOKIE)) {
switch($_COOKIE['VCLSKIN']) {
case 'EXAMPLE2':
$skin = 'example2';
break;
default:
$skin = getAffiliationTheme(0);
break;
}
}
# set skin based on IP address, useful to ensure anyone coming
# from a certain organization automatically gets a different skin
/*elseif(preg_match('/^152\.9\./', $_SERVER['REMOTE_ADDR']) ||
(array_key_exists('VCLSKIN', $_COOKIE) && $_COOKIE['VCLSKIN'] == 'EXAMPLE1')) {
$skin = 'example1';
}*/
else
$skin = getAffiliationTheme(0);
if($mode != 'selectauth' && $mode != 'submitLogin')
require_once("themes/$skin/page.php");
require_once(".ht-inc/requests.php");
if($mode != "logout" &&
$mode != "shiblogout" &&
$mode != "xmlrpccall" &&
$mode != "xmlrpcaffiliations" &&
$mode != "selectauth" &&
$mode != "submitLogin" &&
$mode != "changeLocale") {
$oldmode = $mode;
$mode = "auth";
}
if($mode == 'xmlrpccall' || $mode == 'xmlrpcaffiliations') {
require_once(".ht-inc/xmlrpcWrappers.php");
require_once(".ht-inc/requests.php");
#require_once(".ht-inc/serverprofiles.php");
require_once(".ht-inc/groups.php");
setupSession();
}
return;
}
setupSession();
if(array_key_exists('user', $_SESSION)) {
$user = $_SESSION['user'];
if(! empty($contuserid) &&
$user['id'] != $contuserid)
abort(51);
}
else {
# get info about user
if(! $user = getUserInfo($userid)) {
// if first call to getUserInfo fails, try calling with $noupdate set
if(! $user = getUserInfo($userid, 1)) {
$ERRORS[1] = i("Failed to get user info from database. userid was ") . "$userid";
abort(1);
}
}
if(! empty($contuserid) &&
$user['id'] != $contuserid)
abort(51);
$_SESSION['user'] = $user;
}
# setskin
$skin = getAffiliationTheme($user['affiliationid']);
require_once("themes/$skin/page.php");
$_SESSION['mode'] = $mode;
// check for and possibly clear dirty permission cache
$dontClearModes = array('AJchangeUserPrivs', 'AJchangeUserGroupPrivs', 'AJchangeResourcePrivs');
if(! in_array($mode, $dontClearModes) &&
array_key_exists('dirtyprivs', $_SESSION) &&
$_SESSION['dirtyprivs']) {
clearPrivCache();
$_SESSION['dirtyprivs'] = 0;
}
# set up $affilValFunc, $addUserFunc, $updateUserFunc for any shibonly affiliations
$query = "SELECT id FROM affiliation WHERE shibonly = 1";
$qh = doQuery($query);
while($row = mysqli_fetch_assoc($qh)) {
$id = $row['id'];
if(! array_key_exists($id, $affilValFunc)) {
if(ALLOWADDSHIBUSERS)
$affilValFunc[$id] = function() {return 1;};
else
$affilValFunc[$id] = function() {return 0;};
}
if(! array_key_exists($id, $addUserFunc)) {
if(ALLOWADDSHIBUSERS) {
$addUserFunc[$id] = 'addShibUserStub';
$addUserFuncArgs[$id] = $id;
}
else
$addUserFunc[$id] = function() {return 0;};
}
if(! array_key_exists($id, $updateUserFunc))
$updateUserFunc[$id] = function() {return NULL;};
}
# include appropriate files
switch($actions['pages'][$mode]) {
case 'blockAllocations':
require_once(".ht-inc/blockallocations.php");
break;
case 'help':
require_once(".ht-inc/help.php");
break;
case 'userPreferences':
require_once(".ht-inc/userpreferences.php");
break;
case 'statistics':
require_once(".ht-inc/statistics.php");
break;
case 'manageGroups':
require_once(".ht-inc/groups.php");
break;
case 'privileges':
case 'userLookup':
require_once(".ht-inc/privileges.php");
break;
case 'sitemaintenance':
require_once(".ht-inc/sitemaintenance.php");
break;
case 'vm':
require_once(".ht-inc/vm.php");
break;
case 'dashboard':
require_once(".ht-inc/dashboard.php");
break;
case 'siteconfig':
require_once(".ht-inc/siteconfig.php");
break;
case 'resource':
case 'config':
case 'image':
case 'computer':
case 'managementnode':
case 'schedule':
case 'addomain':
require_once(".ht-inc/resource.php");
break;
case 'storebackend':
require_once(".ht-inc/storebackend.php");
break;
/*case 'serverProfiles':
require_once(".ht-inc/serverprofiles.php");
require_once(".ht-inc/requests.php");
break;*/
case 'oneClicks':
require_once(".ht-inc/oneclick.php");
break;
default:
require_once(".ht-inc/requests.php");
}
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn vclAutoLoader($class)
///
/// \param $class - name of a class
///
/// \brief handles loading class implementation file for a specified class
///
////////////////////////////////////////////////////////////////////////////////
function vclAutoLoader($class) {
global $actions;
$class = strtolower($class);
require_once(".ht-inc/resource.php");
if(array_key_exists($class, $actions['classmapping'])) {
require_once(".ht-inc/{$actions['classmapping'][$class]}.php");
return;
}
require_once(".ht-inc/$class.php");
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn checkAccess()
///
/// \brief gets the user's access level to the locker from the ptsowner_admin
/// table
///
////////////////////////////////////////////////////////////////////////////////
function checkAccess() {
global $mode, $user, $actionFunction, $authMechs;
global $itecsauthkey, $ENABLE_ITECSAUTH, $actions;
global $inContinuation, $apiValidateFunc;
if($mode == 'xmlrpccall') {
// double check for SSL
if(! isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") {
printXMLRPCerror(4); # must have SSL enabled
dbDisconnect();
exit;
}
if(! isset($_SERVER['HTTP_X_USER'])) {
printXMLRPCerror(3); # access denied
dbDisconnect();
exit;
}
$xmluser = processInputData($_SERVER['HTTP_X_USER'], ARG_STRING, 1);
if(! $user = getUserInfo($xmluser)) {
// if first call to getUserInfo fails, try calling with $noupdate set
if(! $user = getUserInfo($xmluser, 1)) {
$testid = $xmluser;
$affilid = DEFAULT_AFFILID;
getAffilidAndLogin($testid, $affilid);
addLoginLog($testid, 'unknown', $affilid, 0);
printXMLRPCerror(3); # access denied
dbDisconnect();
exit;
}
}
if(! array_key_exists('HTTP_X_PASS', $_SERVER) || strlen($_SERVER['HTTP_X_PASS']) == 0) {
addLoginLog($xmluser, 'unknown', $user['affilid'], 0);
printXMLRPCerror(3); # access denied
dbDisconnect();
exit;
}
$xmlpass = $_SERVER['HTTP_X_PASS'];
$apiver = processInputData($_SERVER['HTTP_X_APIVERSION'], ARG_NUMERIC, 1);
if($apiver == 1) {
addLoginLog($xmluser, 'unknown', $user['affilid'], 0);
printXMLRPCerror(8); # unsupported API version
dbDisconnect();
exit;
}
elseif($apiver == 2) {
$authtype = "";
foreach($authMechs as $key => $authmech) {
if($authmech['affiliationid'] == $user['affiliationid']) {
$authtype = $key;
break;
}
}
if(empty($authtype)) {
print "No authentication mechanism found for passed in X-User";
addLoginLog($xmluser, 'unknown', $user['affilid'], 0);
dbDisconnect();
exit;
}
if($authMechs[$authtype]['type'] == 'ldap') {
$auth = $authMechs[$authtype];
$ds = ldap_connect("ldaps://{$auth['server']}/");
if(! $ds) {
addLoginLog($xmluser, $authtype, $user['affilid'], 0);
printXMLRPCerror(5); # failed to connect to auth server
dbDisconnect();
exit;
}
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ds, LDAP_OPT_REFERRALS, 0);
if($auth['lookupuserbeforeauth']) {
# in this case, we have to look up what part of the tree the user is in
# before we can actually look up the user
if(array_key_exists('masterlogin', $auth) && strlen($auth['masterlogin']))
$res = ldap_bind($ds, $auth['masterlogin'], $auth['masterpwd']);
else
$res = ldap_bind($ds);
if(! $res) {
addLoginLog($user['unityid'], $authtype, $user['affiliationid'], 0);
printXMLRPCerror(5); # failed to connect to auth server
dbDisconnect();
exit;
}
$search = ldap_search($ds,
$auth['binddn'],
"{$auth['lookupuserfield']}={$user['unityid']}",
array('dn'), 0, 3, 15);
if($search) {
$tmpdata = ldap_get_entries($ds, $search);
if(! $tmpdata['count'] || ! array_key_exists('dn', $tmpdata[0])) {
addLoginLog($user['unityid'], $authtype, $user['affiliationid'], 0);
printXMLRPCerror(3); # access denied
dbDisconnect();
exit;
}
$ldapuser = $tmpdata[0]['dn'];
}
else {
addLoginLog($user['unityid'], $authtype, $user['affiliationid'], 0);
printXMLRPCerror(3); # access denied
dbDisconnect();
exit;
}
}
else
$ldapuser = sprintf($auth['userid'], $user['unityid']);
$res = ldap_bind($ds, $ldapuser, $xmlpass);
if(! $res) {
addLoginLog($user['unityid'], $authtype, $user['affiliationid'], 0);
printXMLRPCerror(3); # access denied
dbDisconnect();
exit;
}
addLoginLog($user['unityid'], $authtype, $user['affiliationid'], 1);
}
elseif($ENABLE_ITECSAUTH &&
$authMechs[$authtype]['affiliationid'] == getAffiliationID('ITECS')) {
$rc = ITECSAUTH_validateUser($itecsauthkey, $user['unityid'], $xmlpass);
if(empty($rc) || $rc['passfail'] == 'fail') {
printXMLRPCerror(3); # access denied
dbDisconnect();
exit;
}
}
elseif($authMechs[$authtype]['type'] == 'local') {
if(! validateLocalAccount($user['unityid'], $xmlpass)) {
printXMLRPCerror(3); # access denied
dbDisconnect();
exit;
}
}
elseif($authMechs[$authtype]['type'] == 'redirect') {
$affilid = $authMechs[$authtype]['affiliationid'];
if(!(isset($apiValidateFunc) && is_array($apiValidateFunc) &&
array_key_exists($affilid, $apiValidateFunc) &&
$apiValidateFunc[$affilid]($xmluser, $xmlpass))) {
printXMLRPCerror(3); # access denied
dbDisconnect();
exit;
}
}
else {
printXMLRPCerror(6); # unable to auth passed in X-User
dbDisconnect();
exit;
}
}
else {
printXMLRPCerror(7); # unknown API version
dbDisconnect();
exit;
}
}
elseif($mode == 'xmlrpcaffiliations') {
// double check for SSL, not really required for this mode, but it keeps things consistant
if(! isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") {
printXMLRPCerror(4); # must have SSL enabled
dbDisconnect();
exit;
}
$apiver = processInputData($_SERVER['HTTP_X_APIVERSION'], ARG_NUMERIC, 1);
if($apiver == 1) {
printXMLRPCerror(8); # unsupported API version
dbDisconnect();
exit;
}
elseif($apiver != 2) {
printXMLRPCerror(7); # unknown API version
dbDisconnect();
exit;
}
}
elseif(! empty($mode)) {
if(! in_array($mode, $actions['entry']) &&
! $inContinuation) {
$mode = "main";
$actionFunction = "main";
return;
}
else {
if(! $inContinuation) {
# check that user has access to this area
switch($mode) {
case 'viewGroups':
if(! in_array("groupAdmin", $user["privileges"])) {
$mode = "";
$actionFunction = "main";
return;
}
break;
/*case 'serverProfiles':
if(! in_array("serverProfileAdmin", $user["privileges"]) &&
! in_array("serverCheckOut", $user["privileges"])) {
$mode = "";
$actionFunction = "main";
return;
}
break;*/
case 'pickTimeTable':
$computermetadata = getUserComputerMetaData();
if(! count($computermetadata["platforms"]) ||
! count($computermetadata["schedules"])) {
$mode = "";
$actionFunction = "main";
return;
}
break;
case 'viewNodes':
if(! in_array("userGrant", $user["privileges"]) &&
! in_array("resourceGrant", $user["privileges"]) &&
! in_array("nodeAdmin", $user["privileges"])) {
$mode = "";
$actionFunction = "main";
return;
}
break;
case 'userLookup':
if(! checkUserHasPerm('User Lookup (global)') &&
! checkUserHasPerm('User Lookup (affiliation only)')) {
$mode = "";
$actionFunction = "main";
return;
}
break;
case 'editVMInfo':
if(! in_array("computerAdmin", $user["privileges"])) {
$mode = "";
$actionFunction = "main";
return;
}
break;
case 'siteMaintenance':
if(! checkUserHasPerm('Schedule Site Maintenance')) {
$mode = "";
$actionFunction = "main";
return;
}
break;
case 'dashboard':
if(! checkUserHasPerm('View Dashboard (global)') &&
! checkUserHasPerm('View Dashboard (affiliation only)')) {
$mode = "";
$actionFunction = "main";
return;
}
break;
}
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn checkCryptkey()
///
/// \brief checks for an entry in cryptkey; if missing, generates keys
///
////////////////////////////////////////////////////////////////////////////////
function checkCryptkey() {
global $pemkey;
$reg = "|" . SCRIPT . "$|";
$filebase = preg_replace($reg, '', $_SERVER['SCRIPT_FILENAME']);
$filebase .= "/.ht-inc/cryptkey";
$idfile = "$filebase/cryptkeyid";
if(is_file($idfile)) {
$fh = fopen($idfile, 'r');
$id = fread($fh, 50);
fclose($fh);
$_id = vcl_mysql_escape_string($id);
$query = "SELECT id "
. "FROM cryptkey "
. "WHERE id = '$_id'";
$qh = doQuery($query);
if($row = mysqli_fetch_assoc($qh))
return;
}
// if no id file and cannot write to cryptkey directory, return
if(! is_writable($filebase))
return;
# no id file or no matching entry in cryptkey, create new key
$keyfile = "$filebase/private.pem";
$_algorithm = constant("OPENSSL_KEYTYPE_" . ASYMALGO);
$args = array('private_key_bits' => ASYMLEN,
'private_key_type' => $_algorithm);
# open and lock id file before generating key
$fh = fopen($idfile, 'w');
if(! flock($fh, LOCK_EX | LOCK_NB)) {
# assume collision with another web server generating a key
# return because when the key is needed, it should exist from
# the other server
fclose($fh);
return;
}
# generate key pair
$prikeyobj = openssl_pkey_new($args);
# create and secure private key file
touch($keyfile);
chmod($keyfile, 0600);
# save private key to file
$rc = openssl_pkey_export_to_file($prikeyobj, $keyfile, $pemkey);
if(! $rc) {
# release lock, close and delete file, return
flock($fh, LOCK_UN);
fclose($fh);
unlink($keyfile);
return;
}
# save public key to database
$tmp = openssl_pkey_get_details($prikeyobj);
$pubkey = $tmp['key'];
$query = "INSERT INTO cryptkey "
. "(hostid, "
. "hosttype, "
. "pubkey, "
. "algorithm, "
. "algorithmoption, "
. "keylength) "
. "SELECT COALESCE(MAX(hostid), 0) + 1, "
. "'web', "
. "'$pubkey', "
. "'" . ASYMALGO . "', "
. "'" . ASYMOPT . "', "
. ASYMLEN . " "
. "FROM cryptkey "
. "WHERE hosttype = 'web'";
doQuery($query);
$cryptkeyid = dbLastInsertID();
# save cryptkey id to file
fwrite($fh, $cryptkeyid);
# unlock file
flock($fh, LOCK_UN);
fclose($fh);
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn maintenanceCheck()
///
/// \brief checks for site being in maintenance; if so, read user message from
/// current maintenance file; print site header, maintenance message, and site
/// foother; then exit; also removes any old maintenance files
///
////////////////////////////////////////////////////////////////////////////////
function maintenanceCheck() {
global $authed, $mode, $user;
$now = time();
$reg = "|" . SCRIPT . "$|";
$search = preg_replace($reg, '', $_SERVER['SCRIPT_FILENAME']);
$search .= "/.ht-inc/maintenance/";
$files = glob("{$search}[0-9]*");
if(! is_array($files))
return;
if(empty($files)) {
dbConnect();
$query = "SELECT id "
. "FROM sitemaintenance "
. "WHERE start <= NOW() AND "
. "end > NOW()";
$qh = doQuery($query);
$ids = array();
while($row = mysqli_fetch_assoc($qh))
$ids[] = $row['id'];
if(empty($ids)) {
dbDisconnect();
return;
}
$allids = implode(',', $ids);
$query = "UPDATE sitemaintenance "
. "SET end = NOW() "
. "WHERE id IN ($allids)";
doQuery($query, 101, 'vcl', 1);
dbDisconnect();
return;
}
$inmaintenance = 0;
$skin = '';
foreach($files as $file) {
if(! preg_match("|^$search([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})$|", $file, $matches))
continue;
#YYYYMMDDHHMM
$tmp = "{$matches[1]}-{$matches[2]}-{$matches[3]} {$matches[4]}:{$matches[5]}:00";
$start = datetimeToUnix($tmp);
if($start < $now) {
# check to see if end time has been reached
$fh = fopen($file, 'r');
$msg = '';
while($line = fgets($fh)) {
$line = strip_tags($line);
if(preg_match("/^END=([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})$/", $line, $matches)) {
$tmp = "{$matches[1]}-{$matches[2]}-{$matches[3]} {$matches[4]}:{$matches[5]}:00";
$end = datetimeToUnix($tmp);
if($end < $now) {
fclose($fh);
unlink($file);
$_SESSION['usersessiondata'] = array();
return;
}
else
$inmaintenance = 1;
}
elseif(preg_match("/^THEME=([-A-Za-z0-9@#_:;,\.])+$/", $line, $matches)) {
$skin = $matches[1];
}
else
$msg .= $line;
}
fclose($fh);
if($inmaintenance)
break;
}
}
if($inmaintenance) {
$authed = 0;
$mode = 'inmaintenance';
$user = array();
if(array_key_exists('VCLSKIN', $_COOKIE))
$skin = strtolower($_COOKIE['VCLSKIN']);
if($skin != '') {
$allskins = array();
foreach(glob('themes/*') as $item) {
if(! is_dir($item))
continue;
$tmp = explode('/', $item);
$item = array_pop($tmp);
$allskins[$item] = 1;
}
if(! array_key_exists($skin, $allskins))
$skin = DEFAULTTHEME;
}
else
$skin = DEFAULTTHEME;
setVCLLocale();
require_once("themes/$skin/page.php");
printHTMLHeader();
print "<h2>" . i("Site Currently Under Maintenance") . "</h2>\n";
if(! empty($msg)) {
$msg = htmlentities($msg);
$msg = preg_replace("/\n/", "<br>\n", $msg);
print "$msg<br>\n";
}
else
print i("This site is currently in maintenance.") . "<br>\n";
$niceend = prettyDatetime($end, 1, 0, 1);
printf(i("The maintenance is scheduled to end <strong>%s</strong>.") . "<br><br><br>\n", $niceend);
printHTMLFooter();
exit;
}
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn maintenanceNotice()
///
/// \brief checks informhoursahead for upcoming maintenance items and prints
/// message about upcoming maintenance if currently within warning window
///
////////////////////////////////////////////////////////////////////////////////
function maintenanceNotice() {
$items = getMaintItems();
foreach($items as $item) {
$start = datetimeToUnix($item['start']);
$file = date('YmdHi', $start);
$secahead = $item['informhoursahead'] * 3600;
if($start - $secahead < time()) {
$reg = "|" . SCRIPT . "$|";
$search = preg_replace($reg, '', $_SERVER['SCRIPT_FILENAME']);
$search .= "/.ht-inc/maintenance/$file";
$files = glob("$search");
if(empty($files)) {
$_SESSION['usersessiondata'] = array();
return;
}
$nicestart = prettyDatetime($start, 1, 0, 1);
$niceend = prettyDatetime($item['end'], 1, 0, 1);
print "<div id=\"maintenancenotice\">\n";
print "<strong>" . i("NOTICE:") . "</strong> ";
print i("This site will be down for maintenance during the following times:") . "<br><br>\n";
print i("Start:") . " $nicestart<br>\n";
print i("End:") . " $niceend.<br><br>\n";
if($item['allowreservations']) {
print i("You will be able to access your reserved machines during this maintenance. However, you will not be able to access information on how to connect to them.") . "<br>\n";
}
else {
print i("You will not be able to access any of your reservations during this maintenance.") . "<br>\n";
}
print "</div>\n";
return;
}
}
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn clearPrivCache()
///
/// \brief sets userresources, nodeprivileges, cascadenodeprivileges, and
/// userhaspriv keys of $_SESSION array to empty arrays
///
////////////////////////////////////////////////////////////////////////////////
function clearPrivCache() {
$_SESSION['userresources'] = array();
$_SESSION['nodeprivileges'] = array();
$_SESSION['cascadenodeprivileges'] = array();
$_SESSION['userhaspriv'] = array();
$_SESSION['compstateflow'] = array();
$_SESSION['usersessiondata'] = array();
$_SESSION['variables'] = array();
unset($_SESSION['user']);
unset($_SESSION['locales']);
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn AJclearPermCache()
///
/// \brief ajax wrapper for clearPrivCache
///
////////////////////////////////////////////////////////////////////////////////
function AJclearPermCache() {
clearPrivCache();
print "alert('Permission cache cleared');";
dbDisconnect();
exit;
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn setupSession()
///
/// \brief starts php session and initializes useful variables
///
////////////////////////////////////////////////////////////////////////////////
function setupSession() {
global $mode;
if($mode == 'xmlrpccall')
$_SESSION = array();
else
session_start();
if(! array_key_exists('cachetimestamp', $_SESSION))
$_SESSION['cachetimestamp'] = time();
else {
if(($_SESSION['cachetimestamp'] + (PRIV_CACHE_TIMEOUT * 60)) < time()) {
clearPrivCache();
$_SESSION['cachetimestamp'] = time();
return;
}
}
if(! array_key_exists('userresources', $_SESSION))
$_SESSION['userresources'] = array();
if(! array_key_exists('nodeprivileges', $_SESSION))
$_SESSION['nodeprivileges'] = array();
if(! array_key_exists('cascadenodeprivileges', $_SESSION))
$_SESSION['cascadenodeprivileges'] = array();
if(! array_key_exists('userhaspriv', $_SESSION))
$_SESSION['userhaspriv'] = array();
if(! array_key_exists('compstateflow', $_SESSION))
$_SESSION['compstateflow'] = array();
if(! array_key_exists('usersessiondata', $_SESSION))
$_SESSION['usersessiondata'] = array();
if(! array_key_exists('variables', $_SESSION))
$_SESSION['variables'] = array();
if(! array_key_exists('persistdata', $_SESSION))
$_SESSION['persistdata'] = array();
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn stopSession()
///
/// \brief ends the user's session and prints info to notify the user
///
////////////////////////////////////////////////////////////////////////////////
function stopSession() {
$_SESSION = array();
if(isset($_COOKIE[session_name()]))
setcookie(session_name(), "", time()-42000, '/');
session_destroy();
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn main()
///
/// \brief prints a welcome screen
///
////////////////////////////////////////////////////////////////////////////////
function main() {
global $user, $authed;
print "<H2>" . i("Welcome to the Virtual Computing Lab") . "</H2>\n";
if($authed) {
if(! empty($user['lastname']) && ! empty($user['preferredname']))
print i("Hello") . " {$user["preferredname"]} {$user['lastname']}<br><br>\n";
elseif(! empty($user['lastname']) && ! empty($user['firstname']))
print i("Hello") . " {$user["firstname"]} {$user['lastname']}<br><br>\n";
$tmp = array_values($user['groups']);
if(count($tmp) == 1 && $tmp[0] == 'nodemo') {
print "Your account is a demo account that has expired. ";
print "You cannot make any more reservations. Please contact <a href=\"";
print "mailto:" . HELPEMAIL . "\">" . HELPEMAIL . "</a> if you need ";
print "further access to VCL.<br>\n";
return;
}
$requests = getUserRequests("all", $user["id"]);
if($num = count($requests)) {
if($num == 1)
print i("You currently have 1 reservation.") . "<br>\n";
else
printf(i("You currently have %d reservations.") . "<br>\n", $num);
}
else {
print i("You do not have any current reservations.") . "<br>\n";
}
print i("Please make a selection from the menu to continue.") . "<br>\n";
}
else {
print i("Please log in to start using the VCL system.") . "<br>\n";
}
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn abort($errcode, $query)
///
/// \param $errcode - error code
/// \param $query - a myql query
///
/// \brief prints out error message(s), closes db connection, prints footer
/// and exits
///
////////////////////////////////////////////////////////////////////////////////
function abort($errcode, $query="") {
global $mysqli_link_vcl, $mysqli_link_acct, $ERRORS, $user, $mode;
global $ENABLE_ITECSAUTH, $requestInfo, $aborting;
if(! isset($aborting))
$aborting = 1;
elseif($aborting == 1)
return;
if($mode == 'xmlrpccall')
xmlRPCabort($errcode, $query);
if(ONLINEDEBUG && checkUserHasPerm('View Debug Information')) {
if($errcode >= 100 && $errcode < 400) {
print "<span class=\"rederrormsg\">" . mysqli_error($mysqli_link_vcl) . "</span><br>\n";
error_log(mysqli_error($mysqli_link_vcl));
if($ENABLE_ITECSAUTH) {
print "<span class=\"rederrormsg\">" . mysqli_error($mysqli_link_acct) . "</span><br>\n";
error_log(mysqli_error($mysqli_link_acct));
}
print "$query<br>\n";
error_log($query);
}
print "ERROR($errcode): " . $ERRORS["$errcode"] . "<BR>\n";
error_log("===========================================================================");
error_log("ERROR($errcode): " . $ERRORS["$errcode"]);
$backtrace = getBacktraceString(FALSE);
print "<pre>\n";
print $backtrace;
print "</pre>\n";
error_log($backtrace);
}
else {
$message = "";
if($errcode >= 100 && $errcode < 400) {
$message .= mysqli_error($mysqli_link_vcl) . "\n";
if($ENABLE_ITECSAUTH)
$message .= mysqli_error($mysqli_link_acct) . "\n";
$message .= $query . "\n";
}
$message .= "ERROR($errcode): " . $ERRORS["$errcode"] . "\n";
if(is_array($user) && array_key_exists('unityid', $user))
$message .= "Logged in user was " . $user["unityid"] . "\n";
$message .= "Mode was $mode\n\n";
if($errcode == 20) {
$urlArray = explode('?', $_SERVER["HTTP_REFERER"]);
$message .= "HTTP_REFERER URL - " . $urlArray[0] . "\n";
$message .= "correct URL - " . BASEURL . SCRIPT . "\n";
}
if($errcode == 40) {
$message .= "One of the following computers didn't get a mgmt node:\n";
foreach($requestInfo["images"] as $key => $imageid) {
$message .= "imageid: $imageid\n";
$message .= "compid: {$requestInfo['computers'][$key]}\n";
}
}
$message .= getBacktraceString(FALSE);
if($errcode == 8)
$message = preg_replace("/Argument#: 3 => .*\n/", "Argument#: 3 => *********\n", $message);
$mailParams = "-f" . ENVELOPESENDER;
error_log($message);
mail(ERROREMAIL, "Error with VCL pages ($errcode)", $message, '', $mailParams);
$subj = rawurlencode(i("Problem With VCL"));
$href = "<a href=\"mailto:" . HELPEMAIL . "?Subject=$subj\">" . HELPEMAIL . "</a>";
printf(i("An error has occurred. If this problem persists, please email %s for further assistance. Please include the steps you took that led up to this problem in your email message."), $href);
}
// call clearPrivCache in case that helps clear up what caused the error
clearPrivCache();
// release semaphore lock
cleanSemaphore();
dbDisconnect();
printHTMLFooter();
exit;
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn errorrpt()
///
/// \brief takes input from ajax call and emails error to ERROREMAIL
///
////////////////////////////////////////////////////////////////////////////////
function errorrpt() {
$mailParams = "-f" . ENVELOPESENDER;
mail(ERROREMAIL, "Error with VCL pages (ajax sent html wrappers)", $_POST['data'], '', $mailParams);
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn validateUserid($loginid)
///
/// \param $loginid - a submitted loginid
///
/// \return 0 if the loginid is not found in one of the authentications
/// systems, 1 if it is
///
/// \brief checks to see if $loginid is found in one of the authentication
/// systems
///
////////////////////////////////////////////////////////////////////////////////
function validateUserid($loginid) {
global $affilValFuncArgs, $affilValFunc;
if(empty($loginid))
return 0;
$rc = getAffilidAndLogin($loginid, $affilid);
if($rc == -1)
return 0;
if(empty($affilid))
return 0;
$escloginid = vcl_mysql_escape_string($loginid);
$query = "SELECT id "
. "FROM user "
. "WHERE unityid = '$escloginid' AND "
. "affiliationid = $affilid";
$qh = doQuery($query, 101);
if(mysqli_num_rows($qh))
return 1;
if($rc == 0 &&
ALLOWADDSHIBUSERS == 1 &&
strpos($loginid, '@')) {
$query = "SELECT shibonly "
. "FROM affiliation "
. "WHERE id = " . DEFAULT_AFFILID;
$qh = doQuery($query);
$row = mysqli_fetch_assoc($qh);
if($row['shibonly'] == 1)
return 0;
}
$valfunc = $affilValFunc[$affilid];
if(array_key_exists($affilid, $affilValFuncArgs))
return $valfunc($affilValFuncArgs[$affilid], $loginid);
else
return $valfunc($loginid);
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn AJvalidateUserid()
///
/// \brief checks to see if submitted userid is valid
///
////////////////////////////////////////////////////////////////////////////////
function AJvalidateUserid() {
$user = processInputVar('user', ARG_STRING);
if(validateUserid($user))
sendJSON(array('status' => 'valid'));
else
sendJSON(array('status' => 'invalid'));
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn getAffilidAndLogin(&$login, &$affilid)
///
/// \param $login - login for user, may include \@affiliation
/// \param $affilid - variable in which to stick the affiliation id
///
/// \return 1 if $affilid set by a registered function, 0 if set to default,
/// -1 if @affiliation was part of $login but did not contain a known
/// affiliation
///
/// \brief tries registered affiliation lookup functions to determine the
/// affiliation id of the user; if it finds it, sticks the affiliationid in
/// $affilid and sets $login to not include \@affiliation if it did
///
////////////////////////////////////////////////////////////////////////////////
function getAffilidAndLogin(&$login, &$affilid) {
global $findAffilFuncs;
foreach($findAffilFuncs as $func) {
$rc = $func($login, $affilid);
if($rc)
return $rc;
}
$affilid = DEFAULT_AFFILID;
return 0;
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn mysql_connect_plus($host, $user, $pwd, $db)
///
/// \param $host - mysql host
/// \param $user - userid to use for connection
/// \param $pwd - password to use for connection
/// \param $db - database to use after connecting
///
/// \return mysql resource identifier, 0 if failure to connect
///
/// \brief opens a socket connection to $host, if it is not established in 5
/// seconds, returns an error, otherwise, opens a connection to the database
/// and returns the identifier
///
////////////////////////////////////////////////////////////////////////////////
function mysql_connect_plus($host, $user, $pwd, $db) {
$timeout = 5; /* timeout in seconds */
if($fp = @fsockopen($host, 3306, $errno, $errstr, $timeout)) {
fclose($fp);
return $link = mysqli_connect($host, $user, $pwd, $db);
} else {
#print "ERROR: socket timeout<BR>\n";
return 0;
}
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn dbConnect()
///
/// \brief opens connections to database, the resource identifiers are\n
/// \b $mysqli_link_vcl - for vcl database\n
/// \b $mysqli_link_acct - for accounts database\n
///
////////////////////////////////////////////////////////////////////////////////
function dbConnect() {
global $vclhost, $vcldb, $vclusername, $vclpassword, $mysqli_link_vcl;
global $accthost, $acctusername, $acctpassword, $mysqli_link_acct;
global $ENABLE_ITECSAUTH;
if($ENABLE_ITECSAUTH) {
// open a connection to mysql server for accounts
if(! ($mysqli_link_acct = mysql_connect_plus($accthost, $acctusername, $acctpassword, 'accounts')))
$ENABLE_ITECSAUTH = 0;
}
// open a connection to mysql server for vcl
if(! $mysqli_link_vcl = mysql_connect_plus($vclhost, $vclusername, $vclpassword, $vcldb)) {
die("Error connecting to $vclhost.<br>\n");
}
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn dbDisconnect()
///
/// \brief closes connections to the database
///
////////////////////////////////////////////////////////////////////////////////
function dbDisconnect() {
global $mysqli_link_vcl, $mysqli_link_acct, $ENABLE_ITECSAUTH;
mysqli_close($mysqli_link_vcl);
if($ENABLE_ITECSAUTH)
mysqli_close($mysqli_link_acct);
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn doQuery($query, $errcode, $db, $nolog)
///
/// \param $query - SQL statement
/// \param $errcode - error code
/// \param $db - (optional, defaul=vcl), database to query against
/// \param $nolog - (optional, defaul=0), don't log to queryLog table
///
/// \return $qh - query handle
///
/// \brief performs the query and returns $qh or aborts on error
///
////////////////////////////////////////////////////////////////////////////////
function doQuery($query, $errcode=101, $db="vcl", $nolog=0) {
global $mysqli_link_vcl, $mysqli_link_acct, $user, $mode, $ENABLE_ITECSAUTH;
if($db == "vcl") {
if(QUERYLOGGING != 0 && (! $nolog) &&
preg_match('/^(UPDATE|INSERT|DELETE)/', $query) &&
strpos($query, 'UPDATE continuations SET expiretime = ') === FALSE) {
if(isset($user['id']))
$id = $user['id'];
else
$id = 0;
$q = "INSERT INTO querylog "
. "(userid, "
. "timestamp, "
. "mode, "
. "query) "
. "VALUES "
. "(?, " # $id
. "NOW(), "
. "?, " # $mode
. "?)"; # $logquery
$s = mysqli_prepare($mysqli_link_vcl, $q);
mysqli_stmt_bind_param($s, 'iss', $id, $mode, $query);
mysqli_stmt_execute($s);
}
for($i = 0; ! ($qh = mysqli_query($mysqli_link_vcl, $query)) && $i < 3; $i++) {
if(mysqli_errno($mysqli_link_vcl) == '1213') # DEADLOCK, sleep and retry
usleep(50);
else
abort($errcode, $query);
}
}
elseif($db == "accounts") {
if($ENABLE_ITECSAUTH)
$qh = mysqli_query($mysqli_link_acct, $query) or abort($errcode, $query);
else
$qh = NULL;
}
return $qh;
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn doPSQuery($query, $paramtypes, $params, $errcode, $db, $nolog)
///
/// \param $query - SQL statement
/// \param $paramtypes - string containing the types of parameters to fill in
/// for the ?s in the query, ex: 'ssi' for string string integer
/// \param $params - array of parameters to fill in for the ?s in the query
/// \param $errcode - error code
/// \param $db - (optional, defaul=vcl), database to query against
/// \param $nolog - (optional, defaul=0), don't log to queryLog table
///
/// \return $qh - query handle or NULL if problem encountered
///
/// \brief performs the query and returns $qh or aborts on error
///
////////////////////////////////////////////////////////////////////////////////
function doPSQuery($query, $paramtypes, $params, $errcode=101, $db="vcl",
$nolog=0) {
global $mysqli_link_vcl, $mysqli_link_acct, $user, $mode, $ENABLE_ITECSAUTH;
global $totalQueries, $queryTimes, $totalQueryTime;
$totalQueries++;
if(strlen($paramtypes) != count($params))
return NULL;
if($db == "vcl") {
if(QUERYLOGGING != 0 && (! $nolog) &&
preg_match('/^(UPDATE|INSERT|DELETE)/', $query) &&
strpos($query, 'UPDATE continuations SET expiretime = ') === FALSE) {
if(isset($user['id']))
$id = $user['id'];
else
$id = 0;
$q = "INSERT INTO querylog "
. "(userid, "
. "timestamp, "
. "mode, "
. "query) "
. "VALUES "
. "(?, " # $id
. "NOW(), "
. "?, " # $mode
. "?)"; # $logquery
$s = mysqli_prepare($mysqli_link_vcl, $q);
mysqli_stmt_bind_param($s, 'iss', $id, $mode, $query);
mysqli_stmt_execute($s);
}
$stmt = mysqli_prepare($mysqli_link_vcl, $query);
if(strlen($paramtypes))
mysqli_stmt_bind_param($stmt, $paramtypes, ...$params);
for($i = 0; ! mysqli_stmt_execute($stmt) && $i < 3; $i++) {
if(mysqli_errno($mysqli_link_vcl) == '1213') # DEADLOCK, sleep and retry
usleep(50);
else
abort($errcode, $query);
}
$qh = mysqli_stmt_get_result($stmt);
}
elseif($db == "accounts") {
if($ENABLE_ITECSAUTH) {
$stmt = mysqli_prepare($mysqli_link_acct, $query);
mysqli_stmt_bind_param($stmt, $paramtypes, ...$params);
mysqli_stmt_execute($stmt);
$qh = mysqli_stmt_get_result($stmt) or abort($errcode, $query);
}
else
$qh = NULL;
}
return $qh;
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn dbLastInsertID()
///
/// \return last insert id for $mysqli_link_vcl
///
/// \brief calls mysqli_insert_id for $mysqli_link_vcl
///
////////////////////////////////////////////////////////////////////////////////
function dbLastInsertID() {
global $mysqli_link_vcl;
return mysqli_insert_id($mysqli_link_vcl);
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn vcl_mysql_escape_string($string) {
///
/// \param $string - string to be escaped
///
/// \return escaped string
///
/// \brief wrapper for mysqli_real_escape_string so that $mysqli_link_vcl global
/// variable doesn't have to be included in every function needing to call it
///
////////////////////////////////////////////////////////////////////////////////
function vcl_mysql_escape_string($string) {
global $mysqli_link_vcl;
if(is_null($string))
$string = '';
return mysqli_real_escape_string($mysqli_link_vcl, $string);
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn getOSList()
///
/// \return $oslist - array of OSs
///
/// \brief builds an array of OSs
///
////////////////////////////////////////////////////////////////////////////////
function getOSList() {
$query = "SELECT id, name, prettyname, type, installtype FROM OS ORDER BY prettyname";
$qh = doQuery($query, "115");
$oslist = array();
while($row = mysqli_fetch_assoc($qh))
$oslist[$row['id']] = $row;
return $oslist;
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn getImages($includedeleted=0, $imageid=0)
///
/// \param $includedeleted = (optional) 1 to show deleted images, 0 not to
/// \param $imageid = (optional) only get data for this image, defaults
/// to getting data for all images
///
/// \return $imagelist - array of images with the following elements:\n
/// \b name - name of image\n
/// \b prettyname - pretty name of image\n
/// \b ownerid - userid of owner\n
/// \b owner - unity id of owner\n
/// \b platformid - platformid for the platform the image if for\n
/// \b platform - platform the image is for\n
/// \b osid - osid for the os on the image\n
/// \b os - os the image contains\n
/// \b installtype - method used to install image\n
/// \b ostypeid - id of the OS type in the image\n
/// \b ostype - name of the OS type in the image\n
/// \b minram - minimum amount of RAM needed for image\n
/// \b minprocnumber - minimum number of processors needed for image\n
/// \b minprocspeed - minimum speed of processor(s) needed for image\n
/// \b minnetwork - minimum speed of network needed for image\n
/// \b maxconcurrent - maximum concurrent usage of this iamge\n
/// \b reloadtime - time in minutes for image to be loaded\n
/// \b deleted - 'yes' or 'no'; whether or not this image has been deleted\n
/// \b test - 0 or 1; whether or not there is a test version of this image\n
/// \b resourceid - image's resource id from the resource table\n
/// \b lastupdate - datetime image was last updated\n
/// \b forcheckout - 0 or 1; whether or not the image is allowed to be directly
/// checked out\n
/// \b maxinitialtime - maximum time (in minutes) to be shown when requesting
/// a reservation that the image can reserved for\n
/// \b imagemetaid - NULL or corresponding id from imagemeta table and the
/// following additional information:\n
/// \b checkuser - whether or not vcld should check for a logged in user\n
/// \b sysprep - whether or not to use sysprep on creation of the image\n
/// \b connectmethods - array of enabled connect methods\n
/// \b subimages - an array of subimages to be loaded along with selected
/// image\n
/// \b imagerevision - an array of revision info about the image, it has these
/// keys: id, revision, userid, user, datecreated, prettydate, production,
/// imagename
///
/// \brief generates an array of images
///
////////////////////////////////////////////////////////////////////////////////
function getImages($includedeleted=0, $imageid=0) {
# key in $imagelist is for $includedeleted
static $imagelist = array(0 => array(), 1 => array());
if(! empty($imagelist[$includedeleted])) {
if($imageid == 0)
return $imagelist[$includedeleted];
else
return array($imageid => $imagelist[$includedeleted][$imageid]);
}
# get all image meta data
$allmetadata = array();
$query = "SELECT checkuser, "
. "rootaccess, "
. "subimages, "
. "sysprep, "
. "sethostname, "
. "id "
. "FROM imagemeta";
$qh = doQuery($query);
while($row = mysqli_fetch_assoc($qh))
$allmetadata[$row['id']] = $row;
# get all image revision data
$allrevisiondata = array();
$query = "SELECT i.id, "
. "i.imageid, "
. "i.revision, "
. "i.userid, "
. "CONCAT(u.unityid, '@', a.name) AS user, "
. "i.datecreated, "
. "DATE_FORMAT(i.datecreated, '%c/%d/%y %l:%i %p') AS prettydate, "
. "i.deleted, "
. "i.datedeleted, "
. "i.production, "
. "i.imagename "
. "FROM imagerevision i, "
. "affiliation a, "
. "user u "
. "WHERE i.userid = u.id AND ";
if(! $includedeleted)
$query .= "i.deleted = 0 AND ";
$query .= "u.affiliationid = a.id "
. "ORDER BY i.imageid, i.revision";
$qh = doQuery($query, 101);
while($row = mysqli_fetch_assoc($qh)) {
$id = $row['imageid'];
unset($row['imageid']);
$allrevisiondata[$id][$row['id']] = $row;
}
$query = "SELECT i.id AS id,"
. "i.name AS name, "
. "i.prettyname AS prettyname, "
. "i.ownerid AS ownerid, "
. "CONCAT(u.unityid, '@', a.name) AS owner, "
. "i.platformid AS platformid, "
. "p.name AS platform, "
. "i.OSid AS osid, "
. "o.name AS os, "
. "o.installtype, "
. "ot.id AS ostypeid, "
. "ot.name AS ostype, "
. "i.minram AS minram, "
. "i.minprocnumber AS minprocnumber, "
. "i.minprocspeed AS minprocspeed, "
. "i.minnetwork AS minnetwork, "
. "i.maxconcurrent AS maxconcurrent, "
. "i.reloadtime AS reloadtime, "
. "i.deleted AS deleted, "
. "i.test AS test, "
. "r.id AS resourceid, "
. "i.lastupdate, "
. "i.forcheckout, "
. "i.maxinitialtime, "
. "i.imagemetaid, "
. "ad.id AS addomainid, "
. "ad.name AS addomain, "
. "iadd.baseOU "
. "FROM platform p, "
. "OS o, "
. "OStype ot, "
. "resource r, "
. "resourcetype t, "
. "user u, "
. "affiliation a, "
. "image i "
. "LEFT JOIN imageaddomain iadd ON (i.id = iadd.imageid) "
. "LEFT JOIN addomain ad ON (iadd.addomainid = ad.id) "
. "WHERE i.platformid = p.id AND "
. "r.resourcetypeid = t.id AND "
. "t.name = 'image' AND "
. "r.subid = i.id AND "
. "i.OSid = o.id AND "
. "o.type = ot.name AND "
. "i.ownerid = u.id AND "
. "u.affiliationid = a.id ";
if(! $includedeleted)
$query .= "AND i.deleted = 0 ";
$query .= "ORDER BY i.prettyname";
$qh = doQuery($query, 120);
while($row = mysqli_fetch_assoc($qh)) {
if(is_null($row['maxconcurrent']))
$row['maxconcurrent'] = 0;
$imagelist[$includedeleted][$row["id"]] = $row;
$imagelist[$includedeleted][$row["id"]]['checkuser'] = 1;
$imagelist[$includedeleted][$row["id"]]['rootaccess'] = 1;
if($row['ostype'] == 'windows' || $row['ostype'] == 'osx')
$imagelist[$includedeleted][$row['id']]['sethostname'] = 0;
else
$imagelist[$includedeleted][$row['id']]['sethostname'] = 1;
$imagelist[$includedeleted][$row['id']]['adauthenabled'] = 0;
if($row['addomainid'] != NULL)
$imagelist[$includedeleted][$row['id']]['adauthenabled'] = 1;
if($row["imagemetaid"] != NULL) {
if(isset($allmetadata[$row['imagemetaid']])) {
$metaid = $row['imagemetaid'];
$imagelist[$includedeleted][$row['id']]['checkuser'] = $allmetadata[$metaid]['checkuser'];
$imagelist[$includedeleted][$row['id']]['rootaccess'] = $allmetadata[$metaid]['rootaccess'];
$imagelist[$includedeleted][$row['id']]['sysprep'] = $allmetadata[$metaid]['sysprep'];
if($allmetadata[$metaid]['sethostname'] != NULL)
$imagelist[$includedeleted][$row['id']]['sethostname'] = $allmetadata[$metaid]['sethostname'];
$imagelist[$includedeleted][$row["id"]]["subimages"] = array();
if($allmetadata[$metaid]["subimages"]) {
$query2 = "SELECT imageid "
. "FROM subimages "
. "WHERE imagemetaid = $metaid";
$qh2 = doQuery($query2, 101);
while($row2 = mysqli_fetch_assoc($qh2))
$imagelist[$includedeleted][$row["id"]]["subimages"][] = $row2["imageid"];
}
}
else
$imagelist[$includedeleted][$row["id"]]["imagemetaid"] = NULL;
}
if(isset($allrevisiondata[$row['id']]))
$imagelist[$includedeleted][$row['id']]['imagerevision'] = $allrevisiondata[$row['id']];
$imagelist[$includedeleted][$row['id']]['connectmethods'] = getImageConnectMethods($row['id']);
}
if($imageid != 0)
return array($imageid => $imagelist[$includedeleted][$imageid]);
return $imagelist[$includedeleted];
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn getServerProfiles($id)
///
/// \param $id - (optional) if specified, only return data for specified profile
///
/// \return an array where each key is a profile id whose value is an array with
/// these values:\n
/// \b name - profile name\n
/// \b description - profile description\n
/// \b imageid - id of image associated with profile\n
/// \b image - pretty name of image associated with profile\n
/// \b ownerid - user id of owner of profile\n
/// \b owner - unityid of owner of profile\n
/// \b fixedIP - IP address to be used with deployed profile\n
/// \b fixedMAC - MAC address to be used with deployed profile\n
/// \b admingroupid - id of admin user group associated with profile\n
/// \b admingroup - name of admin user group associated with profile\n
/// \b logingroupid - id of login user group associated with profile\n
/// \b logingroup - name of login user group associated with profile\n
/// \b monitored - whether or not deployed profile should be monitored\n
/// \b resourceid - resource id of profile
///
/// \brief gets information about server profiles
///
////////////////////////////////////////////////////////////////////////////////
/*function getServerProfiles($id=0) {
$key = getKey(array('getServerProfiles', $id));
if(isset($_SESSION['usersessiondata'][$key]))
return $_SESSION['usersessiondata'][$key];
$fixeddata = array();
$query = "SELECT name, value FROM variable WHERE name LIKE 'fixedIPsp%'";
$qh = doQuery($query);
while($row = mysqli_fetch_assoc($qh)) {
$spid = str_replace('fixedIPsp', '', $row['name']);
$fixeddata[$spid] = Spyc::YAMLLoad($row['value']);
}
$query = "SELECT s.id, "
. "s.name, "
. "s.description, "
. "s.imageid, "
. "i.prettyname AS image, "
. "s.ownerid, "
. "CONCAT(u.unityid, '@', a.name) AS owner, "
. "s.fixedIP, "
. "s.fixedMAC, "
. "s.admingroupid, "
. "CONCAT(ga.name, '@', aa.name) AS admingroup, "
. "s.logingroupid, "
. "CONCAT(gl.name, '@', al.name) AS logingroup, "
. "s.monitored, "
. "r.id AS resourceid "
. "FROM serverprofile s "
. "LEFT JOIN image i ON (i.id = s.imageid) "
. "LEFT JOIN user u ON (u.id = s.ownerid) "
. "LEFT JOIN affiliation a ON (a.id = u.affiliationid) "
. "LEFT JOIN usergroup ga ON (ga.id = s.admingroupid) "
. "LEFT JOIN affiliation aa ON (aa.id = ga.affiliationid) "
. "LEFT JOIN usergroup gl ON (gl.id = s.logingroupid) "
. "LEFT JOIN affiliation al ON (al.id = gl.affiliationid) "
. "LEFT JOIN resource r ON (r.subid = s.id) "
. "WHERE r.resourcetypeid = 17 ";
if($id != 0)
$query .= "AND s.id = $id";
else
$query .= "ORDER BY name";
$qh = doQuery($query, 101);
$profiles = array();
while($row = mysqli_fetch_assoc($qh)) {
$profiles[$row['id']] = $row;
if(isset($fixeddata[$row['id']])) {
$profiles[$row['id']]['netmask'] = $fixeddata[$row['id']]['netmask'];
$profiles[$row['id']]['router'] = $fixeddata[$row['id']]['router'];
$profiles[$row['id']]['dns'] = implode(',', $fixeddata[$row['id']]['dns']);
}
else {
$profiles[$row['id']]['netmask'] = '';
$profiles[$row['id']]['router'] = '';
$profiles[$row['id']]['dns'] = '';
}
}
$_SESSION['usersessiondata'][$key] = $profiles;
return $profiles;
}*/
////////////////////////////////////////////////////////////////////////////////
///
/// \fn getServerProfileImages($userid)
///
/// \param $userid - id from user table
///
/// \return array where the key is the id of the image and the value is the
/// prettyname of the image
///
/// \brief builds an array of images that user has access to via server profiles
///
////////////////////////////////////////////////////////////////////////////////
/*function getServerProfileImages($userid) {
$key = getKey(array('getServerProfileImages', $userid));
if(isset($_SESSION['usersessiondata'][$key]))
return $_SESSION['usersessiondata'][$key];
$resources = getUserResources(array('serverCheckOut', 'serverProfileAdmin'),
array('available', 'administer'));
$ids = array_keys($resources['serverprofile']);
$inids = implode(',', $ids);
if(empty($inids)) {
$_SESSION['usersessiondata'][$key] = array();
return array();
}
$query = "SELECT i.id, "
. "i.prettyname AS image "
. "FROM serverprofile s, "
. "image i "
. "WHERE s.imageid = i.id AND "
. "s.id IN ($inids)";
$qh = doQuery($query, 101);
$profiles = array();
while($row = mysqli_fetch_assoc($qh))
$profiles[$row['id']] = $row['image'];
$_SESSION['usersessiondata'][$key] = $profiles;
return $profiles;
}*/
////////////////////////////////////////////////////////////////////////////////
///
/// \fn getImageRevisions($imageid, $incdeleted)
///
/// \param $imageid - id of an image
/// \param $incdeleted - (optional, defaults to 0) 1 to include deleted images
///
/// \return an array where each key is the id of the image revision and each
/// element has these values:\n
/// \b id - id of revision\n
/// \b revision - revision number\n
/// \b creatorid - user id of person that created the revision\n
/// \b creator - user@affiliation\n
/// \b datecreated - datetime of when revision was created\n
/// \b deleted - 1 if deleted, 0 if not\n
/// \b production - 1 if production revision, 0 if not\n
/// \b comments - comments about the revision\n
/// \b imagename - name for files related to revision
///
/// \brief gets image revision data related to $imageid
///
////////////////////////////////////////////////////////////////////////////////
function getImageRevisions($imageid, $incdeleted=0) {
$query = "SELECT i.id, "
. "i.revision, "
. "i.userid AS creatorid, "
. "CONCAT(u.unityid, '@', a.name) AS creator, "
. "i.datecreated, "
. "i.deleted, "
. "i.production, "
. "i.comments, "
. "i.imagename "
. "FROM imagerevision i, "
. "user u, "
. "affiliation a "
. "WHERE i.userid = u.id "
. "AND u.affiliationid = a.id "
. "AND i.imageid = $imageid";
if(! $incdeleted)
$query .= " AND i.deleted = 0";
$query .= " ORDER BY revision";
$qh = doQuery($query, 101);
$return = array();
while($row = mysqli_fetch_assoc($qh))
$return[$row['id']] = $row;
return $return;
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn getImageNotes($imageid)
///
/// \param $imageid - id of an image
/// \param $revisionid - image revision id
///
/// \return an array with these keys:\n
/// \b description - description of image\n
/// \b usage - notes on using the image
///
/// \brief gets data from the imageinfo table for $imageid and $revisionid
///
////////////////////////////////////////////////////////////////////////////////
function getImageNotes($imageid) {
if(empty($imageid))
$imageid = 0;
$query = "SELECT COALESCE(description, '') as description, "
. "COALESCE(`usage`, '') as `usage` "
. "FROM image "
. "WHERE id = $imageid";
$qh = doQuery($query, 101);
if($row = mysqli_fetch_assoc($qh))
return $row;
else
return array('description' => '', 'usage' => '');
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn getImageConnectMethods($imageid, $revisionid, $nostatic=0)
///
/// \param $imageid - id of an image
/// \param $revisionid - (optional, default=0) revision id of image
/// \param $nostatic - (optional, default=0) pass 1 to keep from using the
/// static variable defined in the function
///
/// \return an array of connect methods enabled for specified image where the
/// key is the id of the connect method and the value is the description
///
/// \brief builds an array of connect methods enabled for the image
///
////////////////////////////////////////////////////////////////////////////////
function getImageConnectMethods($imageid, $revisionid=0, $nostatic=0) {
$key = getKey(array('getImageConnectMethods', (int)$imageid, (int)$revisionid));
if(isset($_SESSION['usersessiondata'][$key]))
return $_SESSION['usersessiondata'][$key];
if($revisionid == 0)
$revisionid = getProductionRevisionid($imageid, $nostatic);
if($revisionid == '') {
$_SESSION['usersessiondata'][$key] = array();
return array();
}
static $allmethods = array();
if($nostatic)
$allmethods = array();
if(empty($allmethods)) {
$query = "DROP TEMPORARY TABLE IF EXISTS imageconnectmethods";
doQuery($query);
$query = "CREATE TEMPORARY TABLE imageconnectmethods ( "
. "imageid smallint(5) unsigned NOT NULL, "
. "imagerevisionid mediumint(8) unsigned NOT NULL, "
. "connectmethodid tinyint unsigned NOT NULL, "
. "description varchar(255) NOT NULL, "
. "disabled tinyint(1) unsigned NOT NULL, "
. "UNIQUE KEY (imagerevisionid, connectmethodid, disabled) "
. ") ENGINE=MEMORY";
doQuery($query, 101);
$qbase = "INSERT IGNORE INTO imageconnectmethods "
. "SELECT DISTINCT i.id, "
. "ir.id, "
. "c.id, "
. "c.description, "
. "cm.disabled "
. "FROM image i "
. "LEFT JOIN OS o ON (o.id = i.OSid) "
. "LEFT JOIN OStype ot ON (ot.name = o.type) "
. "LEFT JOIN imagerevision ir ON (ir.imageid = i.id) "
. "LEFT JOIN connectmethodmap cm ON (%s) "
. "LEFT JOIN connectmethod c ON (cm.connectmethodid = c.id) "
. "WHERE cm.autoprovisioned IS NULL "
. "HAVING c.id IS NOT NULL "
. "ORDER BY i.id, "
. "cm.disabled, "
. "c.description";
$query = sprintf($qbase, "cm.OStypeid = ot.id");
doQuery($query);
$query = sprintf($qbase, "cm.OSid = o.id");
doQuery($query);
$query = sprintf($qbase, "cm.imagerevisionid = ir.id");
doQuery($query);
$query = "SELECT imageid, "
. "imagerevisionid, "
. "connectmethodid, "
. "description, "
. "disabled "
. "FROM imageconnectmethods "
. "ORDER BY imagerevisionid, "
. "connectmethodid, "
. "disabled";
$qh = doQuery($query);
while($row = mysqli_fetch_assoc($qh)) {
if($row['disabled'] &&
isset($allmethods[$row['imageid']][$row['imagerevisionid']][$row['connectmethodid']]))
unset($allmethods[$row['imageid']][$row['imagerevisionid']][$row['connectmethodid']]);
else
$allmethods[$row['imageid']][$row['imagerevisionid']][$row['connectmethodid']] = $row['description'];
}
}
if(! isset($allmethods[$imageid][$revisionid])) {
$_SESSION['usersessiondata'][$key] = array();
return array();
}
$methods = $allmethods[$imageid][$revisionid];
$_SESSION['usersessiondata'][$key] = $methods;
return $methods;
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn getImageConnectMethodTexts($imageid, $revisionid)
///
/// \param $imageid - id of an image
/// \param $revisionid - (optional, default=0) revision id of image
///
/// \return an array of connect method texts enabled for specified image where
/// the key is the id of the connect method and the value is the connecttext
///
/// \brief builds an array of connect methods enabled for the image
///
////////////////////////////////////////////////////////////////////////////////
function getImageConnectMethodTexts($imageid, $revisionid=0) {
global $locale;
$descfield = 'description';
$textfield = 'connecttext';
if(! preg_match('/^en/', $locale)) {
$query = "DESC connectmethod";
$qh = doQuery($query, 101);
while($row = mysqli_fetch_assoc($qh)) {
if($row['Field'] == "description_$locale")
$descfield = "description_$locale";
if($row['Field'] == "connecttext_$locale")
$textfield = "connecttext_$locale";
}
}
$cmports = array();
$query = "SELECT id, "
. "connectmethodid, "
. "port, "
. "protocol "
. "FROM connectmethodport";
$qh = doQuery($query);
while($row = mysqli_fetch_assoc($qh)) {
$row['key'] = "#Port-{$row['protocol']}-{$row['port']}#";
$cmports[$row['connectmethodid']][] = $row;
}
if($revisionid == 0)
$revisionid = getProductionRevisionid($imageid);
$query = "SELECT c.id, "
. "c.`$descfield` AS description, "
. "c.`$textfield` AS connecttext, "
. "cm.disabled "
. "FROM connectmethod c, "
. "connectmethodmap cm, "
. "image i "
. "LEFT JOIN OS o ON (o.id = i.OSid) "
. "LEFT JOIN OStype ot ON (ot.name = o.type) "
. "WHERE i.id = $imageid AND "
. "cm.connectmethodid = c.id AND "
. "cm.autoprovisioned IS NULL AND "
. "(cm.OStypeid = ot.id OR "
. "cm.OSid = o.id OR "
. "cm.imagerevisionid = $revisionid) "
. "ORDER BY cm.disabled, "
. "c.`$descfield`";
$methods = array();
$qh = doQuery($query, 101);
while($row = mysqli_fetch_assoc($qh)) {
if($row['disabled']) {
if(isset($methods[$row['id']]))
unset($methods[$row['id']]);
}
else
$methods[$row['id']] = array('description' => $row['description'],
'connecttext' => $row['connecttext'],
'ports' => $cmports[$row['id']]);
}
return $methods;
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn getImageTypes()
///
/// \return array of image types where each key is the id and each value is the
/// name
///
/// \brief builds an array of image types from the imagetype table
///
////////////////////////////////////////////////////////////////////////////////
function getImageTypes() {
$query = "SELECT id, name FROM imagetype ORDER BY name";
$qh = doQuery($query);
$data = array();
while($row = mysqli_fetch_assoc($qh))
$data[$row['id']] = $row['name'];
return $data;
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn checkClearImageMeta($imagemetaid, $imageid, $ignorefield)
///
/// \param $imagemetaid - id from imagemeta table
/// \param $imageid - id from image table
/// \param $ignorefield - (optional, default='') field to ignore being different
/// from default
///
/// \return 0 if imagemeta entry was not deleted, 1 if it was
///
/// \brief checks to see if all values of the imagemeta table are defaults, and
/// if so, deletes the entry and sets imagemetaid to NULL in image table
///
////////////////////////////////////////////////////////////////////////////////
function checkClearImageMeta($imagemetaid, $imageid, $ignorefield='') {
# get defaults for imagemeta table
$query = "DESC imagemeta";
$qh = doQuery($query, 101);
$defaults = array();
while($row = mysqli_fetch_assoc($qh))
$defaults[$row['Field']] = $row['Default'];
# get imagemeta data
$query = "SELECT * FROM imagemeta WHERE id = $imagemetaid";
$qh = doQuery($query, 101);
$row = mysqli_fetch_assoc($qh);
$alldefaults = 1;
if(mysqli_num_rows($qh) == 0)
# it is possible that the imagemeta record could have been deleted before
# this was submitted
return 1;
foreach($row as $field => $val) {
if($field == 'id' || $field == $ignorefield)
continue;
if($defaults[$field] != $val) {
$alldefaults = 0;
break;
}
}
// if all default values, delete imagemeta entry
if($alldefaults) {
$query = "DELETE FROM imagemeta WHERE id = $imagemetaid";
doQuery($query, 101);
$query = "UPDATE image SET imagemetaid = NULL WHERE id = $imageid";
doQuery($query, 101);
return 1;
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn getProductionRevisionid($imageid, $nostatic=0)
///
/// \param $imageid
/// \param $nostatic - (optional, default=0) pass 1 to keep from using the
/// static variable defined in the function
///
/// \return the production revision id for $imageid
///
/// \brief gets the production revision id for $imageid from the imagerevision
/// table
///
////////////////////////////////////////////////////////////////////////////////
function getProductionRevisionid($imageid, $nostatic=0) {
static $alldata = array();
if($nostatic)
$alldata = array();
if(! empty($alldata))
if(isset($alldata[$imageid]))
return $alldata[$imageid];
else
return '';
$query = "SELECT id, "
. "imageid "
. "FROM imagerevision "
. "WHERE production = 1";
$qh = doQuery($query, 101);
while($row = mysqli_fetch_assoc($qh))
$alldata[$row['imageid']] = $row['id'];
return $alldata[$imageid];
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn removeNoCheckout($images)
///
/// \param $images - an array of images
///
/// \return an array of images with the images that have forcheckout == 0
/// removed
///
/// \brief removes any images in $images that have forcheckout == 0
///
////////////////////////////////////////////////////////////////////////////////
function removeNoCheckout($images) {
$allimages = getImages();
foreach(array_keys($images) as $id) {
if(isset($allimages[$id]) && ! $allimages[$id]["forcheckout"])
unset($images[$id]);
}
return $images;
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn getUserResources($userprivs, $resourceprivs, $onlygroups,
/// $includedeleted, $userid, $groupid)
///
/// \param $userprivs - array of privileges to look for (such as
/// imageAdmin, imageCheckOut, etc) - this is an OR list; don't include 'block'
/// or 'cascade'
/// \param $resourceprivs - array of privileges to look for (such as
/// available, administer, manageGroup) - this is an OR list; don't include
/// 'block' or 'cascade'
/// \param $onlygroups - (optional) if 1, return the resource groups instead
/// of the resources
/// \param $includedeleted - (optional) included deleted resources if 1,
/// don't if 0
/// \param $userid - (optional) id from the user table, if not given, use the
/// id of the currently logged in user
/// \param $groupid - (optional) id from the usergroup table, if not given, look
/// up by $userid; $userid must be 0 to look up by $groupid
///
/// \return an array of 2 arrays where the first indexes are resource types
/// and each one's arrays are a list of resources available to the user where
/// the index of each item is the id and the value is the name of the
/// resource\n
/// if $onlygroups == 1:\n
/// {[computer] => {[groupid] => "groupname",\n
/// [groupid] => "groupname"},\n
/// [image] => {[groupid] => "groupname",\n
/// [groupid] => "groupname"},\n
/// ...}\n
/// if $onlygroups == 0:\n
/// {[computer] => {[compid] => "hostname",\n
/// [compid] => "hosename"},\n
/// [image] => {[imageid] => "prettyname",\n
/// [imageid] => "prettyname"},\n
/// ...}
///
/// \brief builds a list of resources a user has access to and returns it
///
////////////////////////////////////////////////////////////////////////////////
function getUserResources($userprivs, $resourceprivs=array("available"),
$onlygroups=0, $includedeleted=0, $userid=0,
$groupid=0) {
global $user;
if(isset($userprivs['managementnodeAdmin']))
$userprivs[] = 'mgmtNodeAdmin';
$key = getKey(array($userprivs, $resourceprivs, $onlygroups, $includedeleted, $userid, $groupid));
if(isset($_SESSION['userresources'][$key]))
return $_SESSION['userresources'][$key];
#FIXME this whole function could be much more efficient
$bygroup = 0;
if($userid == 0 && $groupid != 0)
$bygroup = 1;
if(! $userid)
$userid = $user["id"];
$nodeprivs = array();
$startnodes = array();
# build a list of nodes where user is granted $userprivs
$inlist = "'" . implode("','", $userprivs) . "'";
$query = "SELECT u.privnodeid "
. "FROM userpriv u, "
. "userprivtype t "
. "WHERE u.userprivtypeid = t.id AND "
. "t.name IN ($inlist) AND ";
if(! $bygroup) {
$query .= "(u.userid = $userid OR "
. "u.usergroupid IN (SELECT usergroupid "
. "FROM usergroupmembers "
. "WHERE userid = $userid))";
}
else
$query .= "u.usergroupid = $groupid";
$qh = doQuery($query, 101);
while($row = mysqli_fetch_assoc($qh)) {
array_push($startnodes, $row["privnodeid"]);
}
# build data array from userprivtype and userpriv tables to reduce queries
# in addNodeUserResourcePrivs
$privdataset = array('user' => array(), 'usergroup' => array());
$query = "SELECT t.name, "
. "u.privnodeid "
. "FROM userprivtype t, "
. "userpriv u "
. "WHERE u.userprivtypeid = t.id AND "
. "u.userid IS NOT NULL AND "
. "u.userid = $userid AND "
. "t.name IN ('block','cascade',$inlist)";
$qh = doQuery($query);
while($row = mysqli_fetch_assoc($qh))
$privdataset['user'][$row['privnodeid']][] = $row['name'];
$query = "SELECT t.name, "
. "u.usergroupid, "
. "u.privnodeid "
. "FROM userprivtype t, "
. "userpriv u "
. "WHERE u.userprivtypeid = t.id AND "
. "u.usergroupid IS NOT NULL AND ";
if($bygroup)
$query .= "u.usergroupid = $groupid AND ";
else
$query .= "u.usergroupid IN (SELECT usergroupid "
. "FROM usergroupmembers "
. "WHERE userid = $userid) AND ";
$query .= "t.name IN ('block','cascade',$inlist) "
. "ORDER BY u.privnodeid, "
. "u.usergroupid";
$qh = doQuery($query, 101);
while($row = mysqli_fetch_assoc($qh))
$privdataset['usergroup'][$row['privnodeid']][] = array('name' => $row['name'], 'groupid' => $row['usergroupid']);
# travel up tree looking at privileges granted at parent nodes
foreach($startnodes as $nodeid) {
getUserResourcesUp($nodeprivs, $nodeid, $userid, $userprivs, $privdataset);
}
# travel down tree looking at privileges granted at child nodes if cascade privs at this node
foreach($startnodes as $nodeid) {
getUserResourcesDown($nodeprivs, $nodeid, $userid, $userprivs, $privdataset);
}
$nodeprivs = simplifyNodePrivs($nodeprivs, $userprivs); // call this before calling addUserResources
addUserResources($nodeprivs, $userid);
# build a list of resource groups user has access to
$resourcegroups = array();
$types = getTypes("resources");
foreach($types["resources"] as $type) {
$resourcegroups[$type] = array();
}
foreach(array_keys($nodeprivs) as $nodeid) {
// if user doesn't have privs at this node, no need to look
// at any resource groups here
$haspriv = 0;
foreach($userprivs as $priv) {
if($nodeprivs[$nodeid][$priv])
$haspriv = 1;
}
if(! $haspriv)
continue;
# check to see if resource groups has any of $resourceprivs at this node
foreach(array_keys($nodeprivs[$nodeid]["resources"]) as $resourceid) {
foreach($resourceprivs as $priv) {
if(isset($nodeprivs[$nodeid]["resources"][$resourceid][$priv])) {
list($type, $name, $id) = explode('/', $resourceid);
$resourcegroups[$type][$id] = $name;
}
}
}
# check to see if resource groups has any of $resourceprivs cascaded to this node
foreach(array_keys($nodeprivs[$nodeid]["cascaderesources"]) as $resourceid) {
foreach($resourceprivs as $priv) {
if(isset($nodeprivs[$nodeid]["cascaderesources"][$resourceid][$priv]) &&
! (isset($nodeprivs[$nodeid]["resources"][$resourceid]["block"]))) {
list($type, $name, $id) = explode('/', $resourceid);
$resourcegroups[$type][$id] = $name;
}
}
}
}
if(! $bygroup)
addOwnedResourceGroups($resourcegroups, $userid);
if($onlygroups) {
foreach(array_keys($resourcegroups) as $type)
uasort($resourcegroups[$type], "sortKeepIndex");
$_SESSION['userresources'][$key] = $resourcegroups;
return $resourcegroups;
}
$resources = array();
foreach(array_keys($resourcegroups) as $type) {
$resources[$type] =
getResourcesFromGroups($resourcegroups[$type], $type, $includedeleted);
}
if(! $bygroup)
addOwnedResources($resources, $includedeleted, $userid);
$noimageid = getImageId('noimage');
if(isset($resources['image'][$noimageid]))
unset($resources['image'][$noimageid]);
$_SESSION['userresources'][$key] = $resources;
return $resources;
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn getUserResourcesUp(&$nodeprivs, $nodeid, $userid,
/// $resourceprivs, $privdataset)
///
/// \param $nodeprivs - node privilege array used in getUserResources
/// \param $nodeid - an id from the nodepriv table
/// \param $userid - an id from the user table
/// \param $resourceprivs - array of privileges to look for (such as
/// imageAdmin, imageCheckOut, etc); don't include 'block' or 'cascade'
/// \param $privdataset - array of data from userpriv table built in
/// getUserResources function
///
/// \return modifies $nodeprivs, but doesn't return anything
///
/// \brief adds resource privileges to $nodeprivs for the parents of $nodeid
///
////////////////////////////////////////////////////////////////////////////////
function getUserResourcesUp(&$nodeprivs, $nodeid, $userid,
$resourceprivs, $privdataset) {
# build list of parent nodes
# starting at top, get images available at that node and user privs there and
# walk down to $nodeid
$nodelist = getParentNodes($nodeid);
array_unshift($nodelist, $nodeid);
$lastid = 0;
while(count($nodelist)) {
$id = array_pop($nodelist);
if(isset($nodeprivs[$id]))
continue;
addNodeUserResourcePrivs($nodeprivs, $id, $lastid, $userid, $resourceprivs, $privdataset);
$lastid = $id;
}
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn getUserResourcesDown(&$nodeprivs, $nodeid, $userid,
/// $resourceprivs, $privdataset)
///
/// \param $nodeprivs - node privilege array used in getUserResources
/// \param $nodeid - an id from the nodepriv table
/// \param $userid - an id from the user table
/// \param $resourceprivs - array of privileges to look for (such as
/// imageAdmin, imageCheckOut, etc); don't include 'block' or 'cascade'
/// \param $privdataset - array of data from userpriv table built in
/// getUserResources function
///
/// \return modifies $nodeprivs, but doesn't return anything
///
/// \brief recursively adds resource privileges to $nodeprivs for any children
/// of $nodeid
///
////////////////////////////////////////////////////////////////////////////////
function getUserResourcesDown(&$nodeprivs, $nodeid, $userid,
$resourceprivs, $privdataset) {
# FIXME can we check for cascading and if not there, don't descend?
$children = getChildNodes($nodeid);
foreach($children as $id => $tmp) {
addNodeUserResourcePrivs($nodeprivs, $id, $nodeid, $userid, $resourceprivs, $privdataset);
getUserResourcesDown($nodeprivs, $id, $userid, $resourceprivs, $privdataset);
}
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn addNodeUserResourcePrivs(&$nodeprivs, $id, $lastid, $userid,
/// $resourceprivs, $privdataset)
///
/// \param $nodeprivs - node privilege array used in getUserResources
/// \param $id - an id from the nodepriv table
/// \param $lastid - $id's parent, 0 if at the root
/// \param $userid - an id from the user table
/// \param $resourceprivs - array of privileges to look for (such as
/// imageAdmin, imageCheckOut, etc); don't include 'block' or 'cascade'
/// \param $privdataset - array of data from userpriv table built in
/// getUserResources function
///
/// \return modifies $nodeprivs, but doesn't return anything
///
/// \brief for $id, gets privileges and cascaded privileges the user and any
/// groups the user is and adds them to $nodeprivs
///
////////////////////////////////////////////////////////////////////////////////
function addNodeUserResourcePrivs(&$nodeprivs, $id, $lastid, $userid,
$resourceprivs, $privdataset) {
$nodeprivs[$id]["user"] = array("cascade" => 0);
foreach($resourceprivs as $priv) {
$nodeprivs[$id]["user"][$priv] = 0;
}
# add permissions for user
$block = 0;
if(isset($privdataset['user'][$id])) {
foreach($privdataset['user'][$id] as $name) {
if($name != 'block')
$nodeprivs[$id]['user'][$name] = 1;
else
$block = 1;
}
}
// if don't have anything in $resourceprivs, set cascade = 0
if($nodeprivs[$id]["user"]["cascade"]) {
$noprivs = 1;
foreach($resourceprivs as $priv) {
if($nodeprivs[$id]["user"][$priv])
$noprivs = 0;
}
if($noprivs)
$nodeprivs[$id]["user"]["cascade"] = 0;
}
// if not blocking at this node, and previous node had cascade
if($lastid && ! $block && $nodeprivs[$lastid]["user"]["cascade"]) {
# set cascade = 1
$nodeprivs[$id]["user"]["cascade"] = 1;
# set each priv in $resourceprivs = 1
foreach($resourceprivs as $priv) {
if($nodeprivs[$lastid]["user"][$priv])
$nodeprivs[$id]["user"][$priv] = 1;
}
}
# add permissions for user's groups
$basearray = array("cascade" => 0,
"block" => 0);
foreach($resourceprivs as $priv)
$basearray[$priv] = 0;
if(isset($privdataset['usergroup'][$id])) {
foreach($privdataset['usergroup'][$id] as $data) {
if(! isset($nodeprivs[$id][$data["groupid"]]))
$nodeprivs[$id][$data["groupid"]] = $basearray;
$nodeprivs[$id][$data["groupid"]][$data["name"]] = 1;
}
}
# add groups from $lastid if it is not 0
if($lastid) {
foreach($nodeprivs[$lastid] as $groupid => $tmp) {
if(isset($nodeprivs[$id][$groupid]))
continue;
$nodeprivs[$id][$groupid] = $basearray;
}
}
foreach($nodeprivs[$id] as $groupid => $tmp) {
if(! is_numeric($groupid))
continue;
// if don't have anything in $resourceprivs, set cascade = 0
if($nodeprivs[$id][$groupid]["cascade"]) {
$noprivs = 1;
foreach($resourceprivs as $priv) {
if($nodeprivs[$id][$groupid][$priv])
$noprivs = 0;
}
if($noprivs)
$nodeprivs[$id][$groupid]["cascade"] = 0;
}
// if group not blocking at this node, and group had cascade at previous
# node
if($lastid && ! $nodeprivs[$id][$groupid]["block"] &&
isset($nodeprivs[$lastid][$groupid]) &&
$nodeprivs[$lastid][$groupid]["cascade"]) {
# set cascade = 1
$nodeprivs[$id][$groupid]["cascade"] = 1;
# set each priv in $resourceprivs = 1
foreach($resourceprivs as $priv) {
if($nodeprivs[$lastid][$groupid][$priv])
$nodeprivs[$id][$groupid][$priv] = 1;
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn simplifyNodePrivs($nodeprivs, $resourceprivs)
///
/// \param $nodeprivs - node privilege array used in getUserResources
/// \param $resourceprivs - array of privileges to look for (such as
/// imageAdmin, imageCheckOut, etc); don't include 'block' or 'cascade'
///
/// \return a simplified version of $nodeprivs
///
/// \brief checks the user and group privileges for each node in $nodeprivs and
/// creates a new privilege array that just shows if the user has that
/// permission (either directly or from a group)
///
////////////////////////////////////////////////////////////////////////////////
function simplifyNodePrivs($nodeprivs, $resourceprivs) {
$return = array();
$basearray = array();
foreach($resourceprivs as $priv) {
$basearray[$priv] = 0;
}
foreach(array_keys($nodeprivs) as $nodeid) {
$return[$nodeid] = $basearray;
foreach(array_keys($nodeprivs[$nodeid]) as $key) {
foreach($resourceprivs as $priv) {
if($nodeprivs[$nodeid][$key][$priv])
$return[$nodeid][$priv] = 1;
}
}
}
return $return;
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn addUserResources(&$nodeprivs, $userid)
///
/// \param $nodeprivs - node privilege array used in getUserResources
/// \param $userid - an id from the user table
///
/// \return modifies $nodeprivs, but doesn't return anything
///
/// \brief for each node in $nodeprivs, adds any resources that are available
/// to $nodeprivs
///
////////////////////////////////////////////////////////////////////////////////
function addUserResources(&$nodeprivs, $userid) {
require_once(".ht-inc/privileges.php");
foreach(array_keys($nodeprivs) as $nodeid) {
$privs = getNodePrivileges($nodeid, "resources");
$nodeprivs[$nodeid]["resources"] = $privs["resources"];
$privs = getNodeCascadePrivileges($nodeid, "resources");
$nodeprivs[$nodeid]["cascaderesources"] = $privs["resources"];
}
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn addOwnedResources(&$resources, $includedeleted, $userid)
///
/// \param $resources - array of resources from getUserResources
/// \param $includedeleted - 1 to include deleted resources, 0 not to
/// \param $userid - id from user table
///
/// \return modifies $resources, but doesn't return anything
///
/// \brief adds resources that the user owns
///
////////////////////////////////////////////////////////////////////////////////
function addOwnedResources(&$resources, $includedeleted, $userid) {
foreach(array_keys($resources) as $type) {
# TODO make this get name field from classes
switch($type) {
case "image":
$field = 'prettyname';
break;
case "computer":
case "managementnode":
$field = 'hostname';
break;
default:
$field = 'name';
break;
}
$query = "SELECT id, "
. "$field "
. "FROM $type "
. "WHERE ownerid = $userid";
if(! $includedeleted &&
($type == "image" || $type == "computer" || $type == 'config'))
$query .= " AND deleted = 0";
if(! $includedeleted && $type == 'managementnode')
$query .= " AND stateid != (SELECT id FROM state WHERE name = 'deleted') ";
$qh = doQuery($query, 101);
while($row = mysqli_fetch_assoc($qh)) {
if(! isset($resources[$type][$row["id"]]))
$resources[$type][$row["id"]] = $row[$field];
}
}
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn addOwnedResourceGroups(&$resourcegroups, $userid)
///
/// \param $resourcegroups - array of resources from getUserResources
/// \param $userid - id from user table
///
/// \return modifies $resources, but doesn't return anything
///
/// \brief adds resources that the user owns
///
////////////////////////////////////////////////////////////////////////////////
function addOwnedResourceGroups(&$resourcegroups, $userid) {
if(! $user = getUserInfo($userid, 1, 1))
return;
$userid = $user["id"];
$groupids = implode(',', array_keys($user["groups"]));
if(empty($groupids))
$groupids = "''";
$query = "SELECT g.id AS id, "
. "g.name AS name, "
. "t.name AS type "
. "FROM resourcegroup g, "
. "resourcetype t "
. "WHERE g.resourcetypeid = t.id AND "
. "g.ownerusergroupid IN ($groupids)";
$qh = doQuery($query, 101);
while($row = mysqli_fetch_assoc($qh)) {
if(! isset($resourcegroups[$row["type"]][$row["id"]]))
$resourcegroups[$row["type"]][$row["id"]] = $row["name"];
}
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn getResourcesFromGroups($groups, $type, $includedeleted)
///
/// \param $groups - an array of group names
/// \param $type - the type of the groups (from resourcetype table)
/// \param $includedeleted - 1 to include deleted resources, 0 not to
///
/// \return an array of resources where the index is the id of the resource and
/// the value is the name of the resource
///
/// \brief builds an array of resources from $groups
///
////////////////////////////////////////////////////////////////////////////////
function getResourcesFromGroups($groups, $type, $includedeleted) {
$return = array();
switch($type) {
case "image":
$field = 'prettyname';
break;
case "computer":
case "managementnode":
$field = 'hostname';
break;
default:
$field = 'name';
break;
}
$groups = implode("','", $groups);
$inlist = "'$groups'";
$query = "SELECT DISTINCT(r.subid) AS id, "
. "t.$field AS name "
. "FROM $type t, "
. "resource r, "
. "resourcegroupmembers m, "
. "resourcegroup g, "
. "resourcetype rt "
. "WHERE r.subid = t.id AND "
. "r.id = m.resourceid AND "
. "m.resourcegroupid = g.id AND "
. "g.name IN ($inlist) AND "
. "g.resourcetypeid = rt.id AND "
. "rt.name = '$type' ";
if(! $includedeleted &&
($type == "image" || $type == "computer" || $type == 'config')) {
$query .= "AND deleted = 0 ";
}
if(! $includedeleted && $type == 'managementnode')
$query .= "AND t.stateid != (SELECT id FROM state WHERE name = 'deleted') ";
/*if($type == "image")
$query .= "AND test = 0 ";*/
$query .= "ORDER BY t.$field";
$qh = doQuery($query, 101);
while($row = mysqli_fetch_assoc($qh)) {
$return[$row["id"]] = $row["name"];
}
return $return;
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn updateUserOrGroupPrivs($name, $node, $adds, $removes, $mode)
///
/// \param $name - loginid, user id, or user group id
/// \param $node - id of the node
/// \param $adds - array of privs (the name, not the id) to add
/// \param $removes - array of privs (the name, not the id) to remove
/// \param $mode - "user" or "group"
///
/// \brief adds/removes $adds/$removes privs for $unityid to/from $node
///
////////////////////////////////////////////////////////////////////////////////
function updateUserOrGroupPrivs($name, $node, $adds, $removes, $mode) {
if(! (count($adds) || count($removes))) {
return;
}
if($mode == "user") {
$field = "userid";
if(is_numeric($name))
$id = $name;
else {
$id = getUserlistID($name);
if(! $id)
$id = addUser($name);
}
}
else {
$field = "usergroupid";
$id = $name;
}
foreach($adds as $type) {
$typeid = getUserPrivTypeID($type);
$query = "INSERT IGNORE INTO userpriv ("
. "$field, "
. "privnodeid, "
. "userprivtypeid) "
. "VALUES ("
. "$id, "
. "$node, "
. "$typeid)";
doQuery($query, 375);
}
foreach($removes as $type) {
$typeid = getUserPrivTypeID($type);
$query = "DELETE FROM userpriv "
. "WHERE $field = $id AND "
. "privnodeid = $node AND "
. "userprivtypeid = $typeid";
doQuery($query, 376);
}
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn updateResourcePrivs($group, $node, $adds, $removes)
///
/// \param $group - id from resourcegroup table, or group name of the form
/// type/name
/// \param $node - id of the node
/// \param $adds - array of privs (the name, not the id) to add
/// \param $removes - array of privs (the name, not the id) to remove
///
/// \brief adds/removes $adds/$removes privs for $name to/from $node
///
////////////////////////////////////////////////////////////////////////////////
function updateResourcePrivs($group, $node, $adds, $removes) {
if(! (count($adds) || count($removes))) {
return;
}
if(is_numeric($group))
$groupid = $group;
else
$groupid = getResourceGroupID($group);
foreach($adds as $type) {
$type = vcl_mysql_escape_string($type);
$query = "INSERT IGNORE INTO resourcepriv ("
. "resourcegroupid, "
. "privnodeid, "
. "type) "
. "VALUES ("
. "$groupid, "
. "$node, "
. "'$type')";
doQuery($query, 377);
}
foreach($removes as $type) {
$type = vcl_mysql_escape_string($type);
$query = "DELETE FROM resourcepriv "
. "WHERE resourcegroupid = $groupid AND "
. "privnodeid = $node AND "
. "type = '$type'";
doQuery($query, 378);
}
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn getKey($data)
///
/// \param $data - an array
///
/// \return an md5 string that is unique for $data
///
/// \brief generates an md5sum for $data
///
////////////////////////////////////////////////////////////////////////////////
function getKey($data) {
return md5(serialize($data));
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn encryptData($data, $cryptkey, $algo, $option, $keylength)
///
/// \param $data - a string
/// \param $cryptkey - key for encryption
/// \param $algo - algorithm to use for decryption
/// \param $option - an algorithm option (such as CBC)
/// \param $keylength - length of key being used
///
/// \return an encrypted form of $data that has been base64 encoded or NULL if
/// encryption failed
///
/// \brief encrypts $data with $algo and $option and base64 encodes it; IV is
/// generated and prepended to encrypted data before base64 encoding
///
////////////////////////////////////////////////////////////////////////////////
function encryptData($data, $cryptkey, $algo, $option, $keylength) {
global $ivsize;
if(! $data)
return false;
if(USE_PHPSECLIB) {
# only AES is currently supported
if($algo == 'AES') {
$mode = constant("CRYPT_AES_MODE_$option");
$aes = new Crypt_AES($mode);
}
else
return false;
$aes->setKeyLength($keylength);
$aes->setKey($cryptkey);
$iv = crypt_random_string($ivsize);
$aes->setIV($iv);
$cryptdata = $aes->encrypt($data);
}
else {
$iv = openssl_random_pseudo_bytes($ivsize);
$mode = "{$algo}-{$keylength}-{$option}";
$cryptdata = openssl_encrypt($data, $mode, $cryptkey, 1, $iv);
if($cryptdata === FALSE)
return NULL;
}
$cryptdata = $iv . $cryptdata;
return trim(base64_encode($cryptdata));
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn decryptData($data, $cryptkey, $algo, $option, $keylength)
///
/// \param $data - a string
/// \param $cryptkey - key for decryption
/// \param $algo - algorithm to use for decryption
/// \param $option - an algorithm option (such as CBC)
/// \param $keylength - length of key being used
///
/// \return decrypted form of $data or false on error
///
/// \brief base64 decodes $data and decrypts it; $data is split into IV and
/// encrypted data after base64 decoding
///
////////////////////////////////////////////////////////////////////////////////
function decryptData($data, $cryptkey, $algo, $option, $keylength) {
global $ivsize;
if(! $data)
return false;
$cryptdata = base64_decode($data);
$iv = substr($cryptdata, 0, $ivsize);
if(strlen($iv) < $ivsize)
return false;
$cryptdata = substr($cryptdata, $ivsize);
if(strlen($cryptdata) == 0)
return false;
if(USE_PHPSECLIB) {
if($algo == 'AES') {
$mode = constant("CRYPT_AES_MODE_$option");
$aes = new Crypt_AES($mode);
}
else
return false;
$aes->setKeyLength($keylength);
$aes->setKey($cryptkey);
$aes->setIV($iv);
$decryptdata = $aes->decrypt($cryptdata);
}
else {
$mode = "{$algo}-{$keylength}-{$option}";
$decryptdata = openssl_decrypt($cryptdata, $mode, $cryptkey, 1, $iv);
if($decryptdata === FALSE)
return false;
}
return trim($decryptdata);
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn encryptDBdata($data, $secretid)
///
/// \param $data - a string
/// \param $secretid - secretid from cryptsecret table
///
/// \return base64-encoded, encrypted form of $data or NULL on error
///
/// \brief encrypts $data with secret key from cryptsecret table
///
////////////////////////////////////////////////////////////////////////////////
function encryptDBdata($data, $secretid) {
# fetch cryptsecret from db
$cryptkeyid = getCryptKeyID();
if($cryptkeyid == NULL)
return NULL;
$query = "SELECT cryptsecret, "
. "algorithm, "
. "algorithmoption, "
. "keylength "
. "FROM cryptsecret "
. "WHERE cryptkeyid = $cryptkeyid AND "
. "secretid = $secretid";
$qh = doQuery($query);
if(! ($row = mysqli_fetch_assoc($qh)))
return NULL;
$secret = decryptSecretKey($row['cryptsecret']);
if($secret === NULL)
return NULL;
$edata = encryptData($data, $secret, $row['algorithm'], $row['algorithmoption'], $row['keylength']);
return $edata;
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn encryptSecretKey($secret, $cryptkey)
///
/// \param $secret - secret key to encrypt
/// \param $cryptkey - id from cryptkey table for public key to use or public
/// key itself
///
/// \return encrypted data; returns NULL on error
///
/// \brief encrypts $secret with key for $cryptkeyid
///
////////////////////////////////////////////////////////////////////////////////
function encryptSecretKey($secret, $cryptkey) {
if(is_numeric($cryptkey)) {
$query = "SELECT pubkey, "
. "algorithmoption "
. "FROM cryptkey "
. "WHERE id = $cryptkey";
$qh = doQuery($query);
if(! ($row = mysqli_fetch_assoc($qh)))
return NULL;
$cryptkey = $row['pubkey'];
if($row['algorithmoption'] == 'OAEP' || 1) # OAEP only currently supported option
$padding = constant('OPENSSL_PKCS1_OAEP_PADDING');
}
else
$padding = constant('OPENSSL_PKCS1_OAEP_PADDING');
$savehdlr = set_error_handler(function() {});
if(@openssl_public_encrypt($secret, $encdata, $cryptkey, $padding)) {
set_error_handler($savehdlr);
$b64data = base64_encode($encdata);
return $b64data;
}
set_error_handler($savehdlr);
return NULL;
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn decryptSecretKey($encsecret)
///
/// \param $encsecret - encrypted secret
///
/// \return string that is decrypted form of $encsecret or NULL on error
///
/// \brief decrypts $encsecret using web server's secret key
///
////////////////////////////////////////////////////////////////////////////////
function decryptSecretKey($encsecret) {
global $pemkey;
$cryptsecret = base64_decode($encsecret);
# read private key from file
$reg = "|" . SCRIPT . "$|";
$file = preg_replace($reg, '', $_SERVER['SCRIPT_FILENAME']);
$file .= "/.ht-inc/cryptkey/private.pem";
$prikey = openssl_pkey_get_private("file://$file", $pemkey);
# decrypt secret using private key
$savehdlr = set_error_handler(function() {});
if(ASYMOPT == 'OAEP')
$padding = constant('OPENSSL_PKCS1_OAEP_PADDING');
# OAEP currently only supported padding option
if(! openssl_private_decrypt($cryptsecret, $secret, $prikey, $padding)) {
set_error_handler($savehdlr);
return NULL;
}
return $secret;
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn getSecretKeyID($table, $field, $recordid)
///
/// \param $table - name of a database table having a secret
/// \param $field - name of field in table referencing secretid
/// \param $recordid - id for record in table
///
/// \return id corresponding to a cryptsecret.secretid value; if value not found
/// and function failed to generate a new secret ID, NULL is returned
///
/// \brief gets the id for a cryptsecret.secretid entry from a table containing
/// an encrypted value; if no entry is found, a new secret is generated and
/// saved in cryptsecret
///
////////////////////////////////////////////////////////////////////////////////
function getSecretKeyID($table, $field, $recordid) {
$query = "SELECT $field FROM $table WHERE id = $recordid";
$qh = doQuery($query);
if(($row = mysqli_fetch_row($qh)) && $row[0] != 0)
return $row[0];
# generate secret key
if(USE_PHPSECLIB)
$key = crypt_random_string(32);
else {
$key = openssl_random_pseudo_bytes(32);
if($key === FALSE)
return NULL;
}
# encrypt with my public key
$cryptkeyid = getCryptKeyID();
if($cryptkeyid === NULL)
return NULL;
$encdata = encryptSecretKey($key, $cryptkeyid);
if($encdata === NULL)
return NULL;
# write to cryptsecret
$query = "INSERT INTO cryptsecret "
. "(cryptkeyid, "
. "secretid, "
. "cryptsecret, "
. "algorithm, "
. "algorithmoption, "
. "keylength) "
. "SELECT $cryptkeyid, "
. "COALESCE(MAX(secretid), 0) + 1, "
. "'$encdata', "
. "'" . SYMALGO . "', "
. "'" . SYMOPT . "', "
. SYMLEN . " "
. "FROM cryptsecret";
doQuery($query);
$id = dbLastInsertID();
if($id < 1)
return NULL;
$query = "SELECT secretid FROM cryptsecret WHERE id = $id";
$qh = doQuery($query);
if(! ($row = mysqli_fetch_assoc($qh)))
return NULL;
# encrypt with all other public keys and write to cryptsecret
encryptWebSecretKeys($key, $row['secretid'], $cryptkeyid);
return $row['secretid'];
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn deleteSecretKeys($secretid)
///
/// \param $secretid - secretid value corresponding to cryptsecret.secretid
///
/// \brief deletes all entries in cryptsecret for $secretid
///
////////////////////////////////////////////////////////////////////////////////
function deleteSecretKeys($secretid) {
$query = "DELETE FROM cryptsecret WHERE secretid = $secretid";
doQuery($query);
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn getCryptKeyID()
///
/// \return id from cryptkey table corresponding to this web server's file
/// space; returns NULL on error
///
/// \brief reads id from cryptkeyid file in web server's file space; if not
/// found, calls checkCryptkey to generate a key and then returns it
///
////////////////////////////////////////////////////////////////////////////////
function getCryptKeyID() {
$reg = "|" . SCRIPT . "$|";
$filebase = preg_replace($reg, '', $_SERVER['SCRIPT_FILENAME']);
$filebase = preg_replace('|/shibauth|', '', $filebase);
$filebase .= "/.ht-inc/cryptkey";
$idfile = "$filebase/cryptkeyid";
static $create = 1; # set flag so that recursion only goes one level deep
if(! is_file($idfile)) {
if($create) {
$create = 0; # set to 0, subsequent calls to function should never need to create a key
checkCryptkey();
return getCryptKeyID();