started to refactor functions to classes and use PSR-4 autoloader and namespacing
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
This commit is contained in:
356
lib/Froxlor/FileDir.php
Normal file
356
lib/Froxlor/FileDir.php
Normal file
@@ -0,0 +1,356 @@
|
||||
<?php
|
||||
namespace Froxlor;
|
||||
|
||||
use Froxlor\Database as Database;
|
||||
|
||||
class FileDir
|
||||
{
|
||||
|
||||
/**
|
||||
* Wrapper around the exec command.
|
||||
*
|
||||
* @param string $exec_string
|
||||
* command to be executed
|
||||
* @param string $return_value
|
||||
* referenced variable where the output is stored
|
||||
* @param array $allowedChars
|
||||
* optional array of allowed characters in path/command
|
||||
*
|
||||
* @return string result of exec()
|
||||
*/
|
||||
public static function safe_exec($exec_string, &$return_value = false, $allowedChars = null)
|
||||
{
|
||||
$disallowed = array(
|
||||
';',
|
||||
'|',
|
||||
'&',
|
||||
'>',
|
||||
'<',
|
||||
'`',
|
||||
'$',
|
||||
'~',
|
||||
'?'
|
||||
);
|
||||
|
||||
$acheck = false;
|
||||
if ($allowedChars != null && is_array($allowedChars) && count($allowedChars) > 0) {
|
||||
$acheck = true;
|
||||
}
|
||||
|
||||
foreach ($disallowed as $dc) {
|
||||
if ($acheck && in_array($dc, $allowedChars))
|
||||
continue;
|
||||
// check for bad signs in execute command
|
||||
if (stristr($exec_string, $dc)) {
|
||||
die("SECURITY CHECK FAILED!\nThe execute string '" . $exec_string . "' is a possible security risk!\nPlease check your whole server for security problems by hand!\n");
|
||||
}
|
||||
}
|
||||
|
||||
// execute the command and return output
|
||||
$return = '';
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
if ($return_value == false) {
|
||||
exec($exec_string, $return);
|
||||
} else {
|
||||
exec($exec_string, $return, $return_value);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a directory below a users homedir and sets all directories,
|
||||
* which had to be created below with correct Owner/Group
|
||||
* (Copied from cron_tasks.php:rev1189 as we'll need this more often in future)
|
||||
*
|
||||
* @param string $homeDir
|
||||
* The homedir of the user
|
||||
* @param string $dirToCreate
|
||||
* The dir which should be created
|
||||
* @param int $uid
|
||||
* The uid of the user
|
||||
* @param int $gid
|
||||
* The gid of the user
|
||||
* @param bool $placeindex
|
||||
* Place standard-index.html into the new folder
|
||||
* @param bool $allow_notwithinhomedir
|
||||
* Allow creating a directory out of the customers docroot
|
||||
*
|
||||
* @return bool true if everything went okay, false if something went wrong
|
||||
*/
|
||||
public static function mkDirWithCorrectOwnership($homeDir, $dirToCreate, $uid, $gid, $placeindex = false, $allow_notwithinhomedir = false)
|
||||
{
|
||||
if ($homeDir != '' && $dirToCreate != '') {
|
||||
$homeDir = self::makeCorrectDir($homeDir);
|
||||
$dirToCreate = self::makeCorrectDir($dirToCreate);
|
||||
|
||||
if (substr($dirToCreate, 0, strlen($homeDir)) == $homeDir) {
|
||||
$subdir = substr($dirToCreate, strlen($homeDir) - 1);
|
||||
$within_homedir = true;
|
||||
} else {
|
||||
$subdir = $dirToCreate;
|
||||
$within_homedir = false;
|
||||
}
|
||||
|
||||
$subdir = self::makeCorrectDir($subdir);
|
||||
$subdirs = array();
|
||||
|
||||
if ($within_homedir || ! $allow_notwithinhomedir) {
|
||||
$subdirlen = strlen($subdir);
|
||||
$offset = 0;
|
||||
|
||||
while ($offset < $subdirlen) {
|
||||
$offset = strpos($subdir, '/', $offset);
|
||||
$subdirelem = substr($subdir, 0, $offset);
|
||||
$offset ++;
|
||||
array_push($subdirs, self::makeCorrectDir($homeDir . $subdirelem));
|
||||
}
|
||||
} else {
|
||||
array_push($subdirs, $dirToCreate);
|
||||
}
|
||||
|
||||
$subdirs = array_unique($subdirs);
|
||||
sort($subdirs);
|
||||
foreach ($subdirs as $sdir) {
|
||||
if (! is_dir($sdir)) {
|
||||
$sdir = self::makeCorrectDir($sdir);
|
||||
self::safe_exec('mkdir -p ' . escapeshellarg($sdir));
|
||||
// place index
|
||||
if ($placeindex) {
|
||||
// @fixme
|
||||
$loginname = getLoginNameByUid($uid);
|
||||
if ($loginname !== false) {
|
||||
// @fixme
|
||||
storeDefaultIndex($loginname, $sdir, null);
|
||||
}
|
||||
}
|
||||
self::safe_exec('chown -R ' . (int) $uid . ':' . (int) $gid . ' ' . escapeshellarg($sdir));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* store the default index-file in a given destination folder
|
||||
*
|
||||
* @param string $loginname customers loginname
|
||||
* @param string $destination path where to create the file
|
||||
* @param object $logger FroxlorLogger object
|
||||
* @param boolean $force force creation whatever the settings say (needed for task #2, create new user)
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public static function storeDefaultIndex($loginname = null, $destination = null, $logger = null, $force = false) {
|
||||
|
||||
if ($force
|
||||
|| (int)Settings::Get('system.store_index_file_subs') == 1
|
||||
) {
|
||||
$result_stmt = Database::prepare("
|
||||
SELECT `t`.`value`, `c`.`email` AS `customer_email`, `a`.`email` AS `admin_email`, `c`.`loginname` AS `customer_login`, `a`.`loginname` AS `admin_login`
|
||||
FROM `" . TABLE_PANEL_CUSTOMERS . "` AS `c` INNER JOIN `" . TABLE_PANEL_ADMINS . "` AS `a`
|
||||
ON `c`.`adminid` = `a`.`adminid`
|
||||
INNER JOIN `" . TABLE_PANEL_TEMPLATES . "` AS `t`
|
||||
ON `a`.`adminid` = `t`.`adminid`
|
||||
WHERE `varname` = 'index_html' AND `c`.`loginname` = :loginname");
|
||||
Database::pexecute($result_stmt, array('loginname' => $loginname));
|
||||
|
||||
if (Database::num_rows() > 0) {
|
||||
|
||||
$template = $result_stmt->fetch(\PDO::FETCH_ASSOC);
|
||||
|
||||
$replace_arr = array(
|
||||
'SERVERNAME' => Settings::Get('system.hostname'),
|
||||
'CUSTOMER' => $template['customer_login'],
|
||||
'ADMIN' => $template['admin_login'],
|
||||
'CUSTOMER_EMAIL' => $template['customer_email'],
|
||||
'ADMIN_EMAIL' => $template['admin_email']
|
||||
);
|
||||
|
||||
// @fixme replace_variables
|
||||
$htmlcontent = PhpHelper::replace_variables($template['value'], $replace_arr);
|
||||
$indexhtmlpath = self::makeCorrectFile($destination . '/index.' . Settings::Get('system.index_file_extension'));
|
||||
$index_html_handler = fopen($indexhtmlpath, 'w');
|
||||
fwrite($index_html_handler, $htmlcontent);
|
||||
fclose($index_html_handler);
|
||||
if ($logger !== null) {
|
||||
$logger->logAction(CRON_ACTION, LOG_NOTICE, 'Creating \'index.' . Settings::Get('system.index_file_extension') . '\' for Customer \'' . $template['customer_login'] . '\' based on template in directory ' . escapeshellarg($indexhtmlpath));
|
||||
}
|
||||
|
||||
} else {
|
||||
$destination = self::makeCorrectDir($destination);
|
||||
if ($logger !== null) {
|
||||
$logger->logAction(CRON_ACTION, LOG_NOTICE, 'Running: cp -a ' . FROXLOR_INSTALL_DIR . '/templates/misc/standardcustomer/* ' . escapeshellarg($destination));
|
||||
}
|
||||
self::safe_exec('cp -a ' . FROXLOR_INSTALL_DIR . '/templates/misc/standardcustomer/* ' . escapeshellarg($destination));
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function which returns a correct filename, means to add a slash at the beginning if there wasn't one
|
||||
*
|
||||
* @param string $filename
|
||||
* the filename
|
||||
*
|
||||
* @return string the corrected filename
|
||||
*/
|
||||
public static function makeCorrectFile($filename)
|
||||
{
|
||||
if (! isset($filename) || trim($filename) == '') {
|
||||
$error = 'Given filename for function ' . __FUNCTION__ . ' is empty.' . "\n";
|
||||
$error .= 'This is very dangerous and should not happen.' . "\n";
|
||||
$error .= 'Please inform the Froxlor team about this issue so they can fix it.';
|
||||
echo $error;
|
||||
// so we can see WHERE this happened
|
||||
debug_print_backtrace();
|
||||
die();
|
||||
}
|
||||
|
||||
if (substr($filename, 0, 1) != '/') {
|
||||
$filename = '/' . $filename;
|
||||
}
|
||||
|
||||
$filename = self::makeSecurePath($filename);
|
||||
return $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function which returns a correct dirname, means to add slashes at the beginning and at the end if there weren't some
|
||||
*
|
||||
* @param string $path
|
||||
* the path to correct
|
||||
*
|
||||
* @throws \Exception
|
||||
* @return string the corrected path
|
||||
*/
|
||||
public static function makeCorrectDir($dir)
|
||||
{
|
||||
if (is_string($dir) && strlen($dir) > 0) {
|
||||
$dir = trim($dir);
|
||||
if (substr($dir, - 1, 1) != '/') {
|
||||
$dir .= '/';
|
||||
}
|
||||
if (substr($dir, 0, 1) != '/') {
|
||||
$dir = '/' . $dir;
|
||||
}
|
||||
return self::makeSecurePath($dir);
|
||||
}
|
||||
throw new \Exception("Cannot validate directory in " . __FUNCTION__ . " which is very dangerous.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Function which returns a secure path, means to remove all multiple dots and slashes
|
||||
*
|
||||
* @param string $path
|
||||
* the path to secure
|
||||
*
|
||||
* @return string the corrected path
|
||||
*/
|
||||
public static function makeSecurePath($path)
|
||||
{
|
||||
|
||||
// check for bad characters, some are allowed with escaping
|
||||
// but we generally don't want them in our directory-names,
|
||||
// thx to aaronmueller for this snipped
|
||||
$badchars = array(
|
||||
':',
|
||||
';',
|
||||
'|',
|
||||
'&',
|
||||
'>',
|
||||
'<',
|
||||
'`',
|
||||
'$',
|
||||
'~',
|
||||
'?',
|
||||
"\0"
|
||||
);
|
||||
foreach ($badchars as $bc) {
|
||||
$path = str_replace($bc, "", $path);
|
||||
}
|
||||
|
||||
$search = array(
|
||||
'#/+#',
|
||||
'#\.+#'
|
||||
);
|
||||
$replace = array(
|
||||
'/',
|
||||
'.'
|
||||
);
|
||||
$path = preg_replace($search, $replace, $path);
|
||||
// don't just replace a space with an escaped space
|
||||
// it might be escaped already
|
||||
$path = str_replace("\ ", " ", $path);
|
||||
$path = str_replace(" ", "\ ", $path);
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if the system is FreeBSD (if exact)
|
||||
* or BSD-based (NetBSD, OpenBSD, etc.
|
||||
* if exact = false [default])
|
||||
*
|
||||
* @param boolean $exact
|
||||
* whether to check explicitly for FreeBSD or *BSD
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function isFreeBSD($exact = false)
|
||||
{
|
||||
if (($exact && PHP_OS == 'FreeBSD') || (! $exact && stristr(PHP_OS, 'BSD'))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the immutable flag for a file
|
||||
*
|
||||
* @param string $filename
|
||||
* the file to set the flag for
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function setImmutable($filename = null)
|
||||
{
|
||||
safe_exec(self::getImmutableFunction(false) . escapeshellarg($filename));
|
||||
}
|
||||
|
||||
/**
|
||||
* removes the immutable flag for a file
|
||||
*
|
||||
* @param string $filename
|
||||
* the file to set the flag for
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function removeImmutable($filename = null)
|
||||
{
|
||||
safe_exec(self::getImmutableFunction(true) . escapeshellarg($filename));
|
||||
}
|
||||
|
||||
/**
|
||||
* internal function to check whether
|
||||
* to use chattr (Linux) or chflags (FreeBSD)
|
||||
*
|
||||
* @param boolean $remove
|
||||
* whether to use +i|schg (false) or -i|noschg (true)
|
||||
*
|
||||
* @return string functionname + parameter (not the file)
|
||||
*/
|
||||
private static function getImmutableFunction($remove = false)
|
||||
{
|
||||
if (self::isFreeBSD()) {
|
||||
// FreeBSD style
|
||||
return 'chflags ' . (($remove === true) ? 'noschg ' : 'schg ');
|
||||
} else {
|
||||
// Linux style
|
||||
return 'chattr ' . (($remove === true) ? '-i ' : '+i ');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user