diff --git a/app/OS/neato_Alpine.php b/app/OS/neato_Alpine.php index a023fb8..9074e22 100644 --- a/app/OS/neato_Alpine.php +++ b/app/OS/neato_Alpine.php @@ -2,6 +2,7 @@ final class neato { + use \traits\su; use \traits\linux_core; use \traits\packages; use \traits\init_systems; @@ -14,6 +15,14 @@ final class neato { const get_super_user_bin = '/usr/sbin/'; const get_user_local_bin = '/usr/local/bin/'; + public static $init_systems = [ + '/etc/systemd'=>'systemd', + '/etc/init.d'=>'sys_v_init', + '/etc/init'=>'upstart', + '/etc/runlevels'=>'open_rc', + '/etc/runit'=>'runit', + ]; + protected function __construct() { } } \ No newline at end of file diff --git a/app/OS/neato_Linux_Generic.php b/app/OS/neato_Linux_Generic.php index a19bdcf..b53d610 100644 --- a/app/OS/neato_Linux_Generic.php +++ b/app/OS/neato_Linux_Generic.php @@ -2,6 +2,7 @@ final class neato { + use \traits\su; use \traits\linux_core; use \traits\packages; use \traits\init_systems; @@ -14,6 +15,14 @@ final class neato { const get_super_user_bin = '/usr/sbin/'; const get_user_local_bin = '/usr/local/bin/'; + public static $init_systems = [ + '/etc/systemd'=>'systemd', + '/etc/init.d'=>'sys_v_init', + '/etc/init'=>'upstart', + '/etc/runlevels'=>'open_rc', + '/etc/runit'=>'runit', + ]; + protected function __construct() { } } \ No newline at end of file diff --git a/app/OS/neato_Ubuntu.php b/app/OS/neato_Ubuntu.php index 037c2b4..42da66b 100644 --- a/app/OS/neato_Ubuntu.php +++ b/app/OS/neato_Ubuntu.php @@ -1,7 +1,8 @@ 'systemd', + '/etc/init.d'=>'sys_v_init', + '/etc/init'=>'upstart', + '/etc/runlevels'=>'open_rc', + '/etc/runit'=>'runit', + ]; + protected function __construct() { } } \ No newline at end of file diff --git a/app/init_systems/systemd.php b/app/init_systems/systemd.php index 9a0b996..12de724 100644 --- a/app/init_systems/systemd.php +++ b/app/init_systems/systemd.php @@ -5,8 +5,19 @@ namespace init_systems; // Used by: RHEL, Fedora, Debian, Ubuntu, Arch, openSUSE class systemd { + + private static function _doRoot(): string { + $root = \neato::becomeRoot(); + if ($root === true) { + return ""; + } + if ($root === false) { + throw new \Exception("Unable to su as root"); + } + return $root . " "; + } - private static function get_valid_action_for_service(string $action): string|false { + private static function getValidActionForService(string $action): string|false { return match($action) { 'start'=>'start', 'stop'=>'stop', @@ -28,7 +39,7 @@ class systemd { }; } - private static function get_valid_action_for_system_ctl(string $action): string|false { + private static function getValidActionForSystemCtl(string $action): string|false { return match($action) { 'start'=>'start', 'stop'=>'stop', @@ -42,16 +53,16 @@ class systemd { } public static function service(string $name, string $action = 'restart') { - $my_action = self::get_valid_action_for_service($action); - exec(\neato::get_super_user_bin . 'service ' . safeCmd($name, $my_action), $output, $exit_code); + $my_action = self::getValidActionForService($action); + exec(self::_doRoot() . \neato::get_super_user_bin . 'service ' . safeCmd($name, $my_action), $output, $exit_code); display($output); checkForError($exit_code, "Unable to {$action} Service called: {$name}"); return $exit_code; } public static function systemctl(string $name, string $action = 'enable') { - $my_action = self::get_valid_action_for_system_ctl($action); - exec(\neato::get_bin . 'systemctl ' . safeCmd($my_action, $name), $output, $exit_code); + $my_action = self::getValidActionForSystemCtl($action); + exec(self::_doRoot() . \neato::get_bin . 'systemctl ' . safeCmd($my_action, $name), $output, $exit_code); checkForError($exit_code, "Unable to {$action} Service called: {$name}"); return $exit_code; } diff --git a/app/neato_colors.php b/app/neato_colors.php index 1f56f15..369ab10 100644 --- a/app/neato_colors.php +++ b/app/neato_colors.php @@ -78,7 +78,7 @@ function getTermColors(array|string $input, $options): string $colored_string .= "\033[" . $bg_colors[$bg_color] . "m"; } - $str = ''; + $str = ''; if (is_array($input)) { foreach ($input as $s) { $str .= $s . PHP_EOL; diff --git a/app/neato_common.php b/app/neato_common.php index 2d4905d..60fb6a8 100644 --- a/app/neato_common.php +++ b/app/neato_common.php @@ -24,12 +24,12 @@ require 'neato_enc.php'; Configure::set('logger_time_zone', 'America/Detroit'); -Neato_Registry::set('loader', new \Neato_Auto_Loader); -Neato_Registry::get('loader')->register(); -Neato_Registry::get('loader')->addNamespace('utils', 'utils'); -Neato_Registry::get('loader')->addNamespace('traits', 'traits'); -Neato_Registry::get('loader')->addNamespace('package_managers', 'package_managers'); -Neato_Registry::get('loader')->addNamespace('init_systems', 'init_systems'); +Registry::set('loader', new \Neato_Auto_Loader); +Registry::get('loader')->register(); +Registry::get('loader')->addNamespace('utils', 'utils'); +Registry::get('loader')->addNamespace('traits', 'traits'); +Registry::get('loader')->addNamespace('package_managers', 'package_managers'); +Registry::get('loader')->addNamespace('init_systems', 'init_systems'); /** * Force script to require being root to run diff --git a/app/neato_fns.php b/app/neato_fns.php index 58c8509..75a0d10 100644 --- a/app/neato_fns.php +++ b/app/neato_fns.php @@ -257,7 +257,7 @@ function stdErr(): string } /** - * Force and script to only Run One time...! + * Force the script to only Run One time...! * * @param bool $output Display? Will it say Script was run once before... * @param bool $halt Will exit(1) diff --git a/app/neato_init.php b/app/neato_init.php index da1ebf1..18a626c 100644 --- a/app/neato_init.php +++ b/app/neato_init.php @@ -41,6 +41,15 @@ if (isCLI() === false) { exit(1); } +function formatBytes(int $bytes, int $precision = 2): string { + $units = ['B', 'KB', 'MB', 'GB', 'TB']; + $bytes = max($bytes, 0); + $pow = floor(($bytes ? log($bytes) : 0) / log(1024)); + $pow = min($pow, count($units) - 1); + $bytes /= (1 << (10 * $pow)); // Calculation: 1024^$pow + return round($bytes, $precision) . ' ' . $units[$pow]; +} + /** * Grabs the Kernel and System Architecture using PHP uname. * diff --git a/app/neato_registry.php b/app/neato_registry.php index 83322d2..d3efb21 100644 --- a/app/neato_registry.php +++ b/app/neato_registry.php @@ -20,7 +20,7 @@ * @license https://mit-license.org/ MIT License * @link https://git.mysnippetsofcode.com/tts/neatoDeploy */ -final class Neato_Registry +final class Registry { private static $_registry = []; @@ -167,7 +167,7 @@ final class Di } // Initialize our Dependency Injector -Neato_Registry::set('di', new Di()); +Registry::set('di', new Di()); // Setup php for working with Unicode data, if possible if (extension_loaded('mbstring')) { diff --git a/app/traits/init_systems.php b/app/traits/init_systems.php index 0211bb0..18cefa2 100644 --- a/app/traits/init_systems.php +++ b/app/traits/init_systems.php @@ -4,15 +4,8 @@ namespace traits; trait init_systems { - private static function get_init_system(): string|false { - $a_init_systems = [ - '/etc/systemd'=>'systemd', - '/etc/init.d'=>'sys_v_init', - '/etc/init'=>'upstart', - '/etc/runlevels'=>'open_rc', - '/etc/runit'=>'runit', - ]; - foreach($a_init_systems as $init_dir=>$init_system_name) { + private static function getInitSystem(): string|false { + foreach(\neato::$init_systems as $init_dir=>$init_system_name) { if (file_exists($init_dir) && is_dir($init_dir)) { return $init_system_name; } @@ -21,7 +14,7 @@ trait init_systems { } public static function service(string $name, string $action = 'restart') { - $my_init = self::get_init_system(); + $my_init = self::getInitSystem(); if ($my_init === false) { return false; } @@ -30,7 +23,7 @@ trait init_systems { } public static function systemctl(string $name, string $action = 'enable') { - $my_init = self::get_init_system(); + $my_init = self::getInitSystem(); if ($my_init === false) { return false; } diff --git a/app/traits/linux_core.php b/app/traits/linux_core.php index 2800480..1bf6c2a 100644 --- a/app/traits/linux_core.php +++ b/app/traits/linux_core.php @@ -3,12 +3,37 @@ namespace traits; trait linux_core { - - public static function no_sticky_bit(string $file) { + + public static bool $linuxRoot = false; + + private static function _doRoot(): string { + if (self::$linuxRoot === false) { + return ""; + } + $root = \neato::becomeRoot(); + if ($root === true) { + return ""; + } + if ($root === false) { + throw new \Exception("Unable to su as root"); + } + return $root . " "; + } + + public static function removeStickyBits(string $file) { + if (! file_exists($file)) { + return true; + } + exec(self::_doRoot().self::get_user_bin . 'chmod -s ' . safeCmd($file), $output, $exit_code); + checkForError($exit_code, "Unable to remove sticky bit with chmod: {$file}"); + return $exit_code; + } + + public static function removeSUID_Bit(string $file) { if (! file_exists($file)) { return true; } - exec(self::get_user_bin . 'chmod -s ' . safeCmd($file), $output, $exit_code); + exec(self::_doRoot().self::get_user_bin . 'chmod u-s ' . safeCmd($file), $output, $exit_code); checkForError($exit_code, "Unable to remove sticky bit with chmod: {$file}"); return $exit_code; } @@ -18,7 +43,7 @@ trait linux_core { $exit_code = false; } else { $perm = getPerms($kind); - exec(self::get_user_bin . 'find ' . safeCmd($dir) . ' -type d -exec ' . self::get_bin . 'chmod ' . $perm . ' {} \;', $output, $exit_code); + exec(self::_doRoot().self::get_user_bin . 'find ' . safeCmd($dir) . ' -type d -exec ' . self::get_bin . 'chmod ' . $perm . ' {} \;', $output, $exit_code); } checkForError($exit_code, "Unable to chmod folders in: {$dir}"); return $exit_code; @@ -29,7 +54,7 @@ trait linux_core { $exit_code = false; } else { $perm = getPerms($kind); - exec(self::get_user_bin . 'find ' . safeCmd($dir) . ' -type f -exec ' . self::get_bin . 'chmod ' . $perm . ' {} \;', $output, $exit_code); + exec(self::_doRoot().self::get_user_bin . 'find ' . safeCmd($dir) . ' -type f -exec ' . self::get_bin . 'chmod ' . $perm . ' {} \;', $output, $exit_code); } checkForError($exit_code, "Unable to chmod files in: {$dir}"); return $exit_code; @@ -39,7 +64,7 @@ trait linux_core { if (!is_file($file)) { $exit_code = false; } else { - exec(self::get_user_bin . 'chattr +i ' . safeCmd($file), $output, $exit_code); + exec(self::_doRoot().self::get_user_bin . 'chattr +i ' . safeCmd($file), $output, $exit_code); } checkForError($exit_code, "Unable to write protect: {$file}"); return $exit_code; @@ -49,7 +74,7 @@ trait linux_core { if (!is_file($file)) { $exit_code = false; } else { - exec(self::get_user_bin . 'chattr -i ' . safeCmd($file), $output, $exit_code); + exec(self::_doRoot().self::get_user_bin . 'chattr -i ' . safeCmd($file), $output, $exit_code); } checkForError($exit_code, "Unable to un-write protect: {$file}"); return $exit_code; @@ -57,7 +82,7 @@ trait linux_core { public static function groupadd(string $groupname, int $gid = 0) { $group_id = ($gid > 0) ? "-g {$gid} " : ""; - exec(self::get_super_user_bin . 'groupadd '. $group_id . safeCmd($groupname), $output, $exit_code); + exec(self::_doRoot().self::get_super_user_bin . 'groupadd '. $group_id . safeCmd($groupname), $output, $exit_code); if ($exit_code === 0) { display(getTermColors("Added new group named: $groupname", ['color'=>'green'])); } @@ -66,7 +91,7 @@ trait linux_core { } public static function userdel(string $username) { - exec(self::get_super_user_bin . 'userdel ' . safeCmd($username), $output, $exit_code); + exec(self::_doRoot().self::get_super_user_bin . 'userdel ' . safeCmd($username), $output, $exit_code); if ($exit_code === 0) { display(getTermColors("Deleted user account named: $username", ['color'=>'green'])); } @@ -77,7 +102,7 @@ trait linux_core { public static function useradd(string $username, int $uid = 0, string $shell="/bin/bash", string $comment = "", string $groups="", string $homedir="") { $user_id = ($uid > 0) ? "-u {$uid} " : ""; $dir = (empty($homedir)) ? " -m " : " -d " . safeCmd($homedir); - exec(self::get_super_user_bin . 'useradd '. $user_id . '-s '. safeCmd($shell) . $dir . ' -c '. safeCmd($comment) .'-G'. safeCmd($groups) . ' ' . safeCmd($username), $output, $exit_code); + exec(self::_doRoot().self::get_super_user_bin . 'useradd '. $user_id . '-s '. safeCmd($shell) . $dir . ' -c '. safeCmd($comment) .'-G'. safeCmd($groups) . ' ' . safeCmd($username), $output, $exit_code); if ($exit_code === 0) { display(getTermColors("Added new user account named: $username", ['color'=>'green'])); } @@ -86,7 +111,7 @@ trait linux_core { } public static function lock_status(string $username) { - exec(self::get_user_bin . 'passwd -S ' . safeCmd($username) . " | awk '{print $2}'", $output, $exit_code); + exec(self::_doRoot().self::get_user_bin . 'passwd -S ' . safeCmd($username) . " | awk '{print $2}'", $output, $exit_code); $sw = $output[0] ?? ""; switch ($sw) { case "P": echo "Account is not locked"; break; @@ -99,28 +124,28 @@ trait linux_core { } public static function passwd(string $username) { - exec(self::get_user_bin . 'passwd ' . safeCmd($username), $output, $exit_code); + exec(self::_doRoot().self::get_user_bin . 'passwd ' . safeCmd($username), $output, $exit_code); checkForError($exit_code, "Unable to set user password: {$username}"); return $exit_code; } // Details about age of passwords public static function chage(string $username) { - exec(self::get_user_bin . 'chage -l ' . safeCmd($username), $output, $exit_code); + exec(self::_doRoot().self::get_user_bin . 'chage -l ' . safeCmd($username), $output, $exit_code); checkForError($exit_code, "Unable to view user password changes: {$username}"); return $exit_code; } // yyyy-mm-dd public static function lock(string $username, string $expires_on="") { $exp = (! empty($expires_on)) ? "--expiredate ". safeCmd($expires_on) . " " : ""; - exec(self::get_super_user_bin . 'usermod -L '. $exp . safeCmd($username), $output, $exit_code); + exec(self::_doRoot().self::get_super_user_bin . 'usermod -L '. $exp . safeCmd($username), $output, $exit_code); checkForError($exit_code, "Unable to Lock user account: {$username}"); return $exit_code; } public static function unlock(string $username, string $expires_on="") { $exp = (! empty($expires_on)) ? "--expiredate ". safeCmd($expires_on) . " " : "--expiredate '' "; - exec(self::get_super_user_bin . 'usermod -U ' . $exp . safeCmd($username), $output, $exit_code); + exec(self::_doRoot().self::get_super_user_bin . 'usermod -U ' . $exp . safeCmd($username), $output, $exit_code); checkForError($exit_code, "Unable to Unlock user account: {$username}"); return $exit_code; } diff --git a/app/traits/su.php b/app/traits/su.php new file mode 100644 index 0000000..c50ab8c --- /dev/null +++ b/app/traits/su.php @@ -0,0 +1,102 @@ + \neato::get_user_bin.$prog, + \neato::get_super_user_bin => \neato::get_super_user_bin.$prog, + \neato::get_bin => \neato::get_bin.$prog, + \neato::get_super_bin => \neato::get_super_bin.$prog, + default => false, + }; + } + + /** + * becomeRoot user + * + * @return string|bool sudo or doas, or true is root, false unknown su root + * + * @throws \Exception upon un-trusted BIN path + */ + public static function becomeRoot(): string|bool + { + if (posix_getuid() === 0) { + return true; + } + $use_find_exec = self::getExecutableDetails(); + + exec($use_find_exec . ' doas', $output, $exit_code); + if ($exit_code === 0) { + $trusted = self::getTrustedPath($output[0]); + if ($trusted === false) { + throw new \Exception("Not a trusted BIN path!"); + } + return $trusted; + } + unset($output); + exec($use_find_exec . ' sudo', $output, $exit_code); + if ($exit_code === 0) { + $trusted = self::getTrustedPath($output[0]); + if ($trusted === false) { + throw new \Exception("Not a trusted BIN path!"); + } + return $trusted; + } + return false; + } + + public static function becomeNormal(string $username): string|bool + { + if (posix_getuid() > 0) { + return true; + } + $use_find_exec = self::getExecutableDetails(); + + exec($use_find_exec . ' doas', $output, $exit_code); + if ($exit_code === 0) { + $trusted = self::getTrustedPath($output[0]); + if ($trusted === false) { + throw new \Exception("Not a trusted BIN path!"); + } + return $trusted . " -u " .$username; + } + unset($output); + exec($use_find_exec . ' sudo', $output, $exit_code); + if ($exit_code === 0) { + $trusted = self::getTrustedPath($output[0]); + if ($trusted === false) { + throw new \Exception("Not a trusted BIN path!"); + } + return $trusted . " -u " .$username; + } + return false; + } +} \ No newline at end of file diff --git a/build/view_phar_file_contents.php b/build/view_phar_file_contents.php index ac51614..75268a7 100644 --- a/build/view_phar_file_contents.php +++ b/build/view_phar_file_contents.php @@ -1,17 +1,65 @@ getPathname() . PHP_EOL; + foreach ($iterator as $file) { + $path = $file->getPathname(); + $parent = dirname($path); + $bp = basename($parent); + if ($bp == $pharFile) { + $first = ""; + } else { + $first = $bp . '/'; + } + $lastTwoParts = $first . basename($path); + if (hasNoSizeFlag()) { + echo $lastTwoParts . PHP_EOL; + } else { + $size = formatBytes($file->getSize()) . "\t "; + echo $size . $lastTwoParts . PHP_EOL; + } } -} catch (PharException $e) { +} catch (PharException | Exception $e) { echo "Error reading Phar archive: " . $e->getMessage(); } diff --git a/deploy_files/deploy_mysql_ex1.php b/deploy_files/deploy_mysql_ex1.php index 03d143e..db4ab08 100644 --- a/deploy_files/deploy_mysql_ex1.php +++ b/deploy_files/deploy_mysql_ex1.php @@ -6,8 +6,8 @@ Configure::set('passwords', ['length' => rand(16, 26)]); Configure::set('pre_actions', [ /** @phpstan-ignore-next-line Variable $cwd might not be defined */ - 'make_dir' => [$cwd . '/my_vaults'=>'', '/etc/neato_secrets'=>''], - 'chmod_file_or_dir' => + 'makeDir' => [$cwd . '/my_vaults'=>'', '/etc/neato_secrets'=>''], + 'chmodFileOrDir' => /** @phpstan-ignore-next-line Variable $cwd might not be defined */ [ $cwd . '/my_vaults' => 'keydir', '/etc/neato_secrets' => 'keydir' ], ]); diff --git a/deploy_files/deploy_podman.php b/deploy_files/deploy_podman.php index 510b27b..de1a7fb 100644 --- a/deploy_files/deploy_podman.php +++ b/deploy_files/deploy_podman.php @@ -4,8 +4,8 @@ Configure::set('logfile', false); // Save to log folder Configure::set('syslog', false); Configure::set('pre_actions', [ - 'make_dir' => ['/etc/containers'=>''], - 'chmod_file_or_dir' => + 'makeDir' => ['/etc/containers'=>''], + 'chmodFileOrDir' => ['/etc/containers' => 'dir'], ]); diff --git a/static_tests.sh b/static_tests.sh index 202c4be..0c5a334 100755 --- a/static_tests.sh +++ b/static_tests.sh @@ -58,4 +58,4 @@ else esac fi -./vendor/bin/phpstan analyse $@ $command_params \ No newline at end of file +vendor/bin/phpstan analyse $@ $command_params \ No newline at end of file diff --git a/testing.md b/testing.md index 6ce9f0b..5c33317 100644 --- a/testing.md +++ b/testing.md @@ -9,7 +9,7 @@ $ ./static_tests.sh ## Quick and Dirty testing ``` from your app folder, run an deployment file, EXAMPLE: -$ ./just_testing.sh [deploy_tets1.php] +$ ./just_testing.sh [deploy_test1.php] ``` ## Where are the deployment files?