Skip to content

Commit abd2cc3

Browse files
rjd22jaapmarcus
andauthored
WIP: Hardening of installer security and improving usability (hestiacp#4690)
* Disallow usage of running command without user in installers * Fix format --------- Co-authored-by: Jaap Marcus <9754650+jaapmarcus@users.noreply.github.com>
1 parent a0240c2 commit abd2cc3

File tree

9 files changed

+48
-75
lines changed

9 files changed

+48
-75
lines changed

web/src/app/System/HestiaApp.php

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -15,41 +15,6 @@ public function __construct() {
1515
@mkdir(self::TMPDIR_DOWNLOADS);
1616
}
1717

18-
public function run(string $cmd, $args, &$cmd_result = null): bool {
19-
$cli_script = realpath(HESTIA_DIR_BIN . $cmd);
20-
if (!str_starts_with((string) $cli_script, HESTIA_DIR_BIN)) {
21-
$errstr = "$cmd is trying to traverse outside of " . HESTIA_DIR_BIN;
22-
trigger_error($errstr);
23-
throw new \Exception($errstr);
24-
}
25-
$cli_script = "/usr/bin/sudo " . quoteshellarg($cli_script);
26-
27-
$cli_arguments = "";
28-
if (!empty($args) && is_array($args)) {
29-
foreach ($args as $arg) {
30-
$cli_arguments .= quoteshellarg((string) $arg) . " ";
31-
}
32-
} else {
33-
$cli_arguments = quoteshellarg($args);
34-
}
35-
36-
exec($cli_script . " " . $cli_arguments . " 2>&1", $output, $exit_code);
37-
38-
$result["code"] = $exit_code;
39-
$result["args"] = $cli_arguments;
40-
$result["raw"] = $output;
41-
$result["text"] = implode(PHP_EOL, $output);
42-
$result["json"] = json_decode($result["text"], true);
43-
$cmd_result = (object) $result;
44-
if ($exit_code > 0) {
45-
//log error message in nginx-error.log
46-
trigger_error($result["text"]);
47-
//throw exception if command fails
48-
throw new \Exception($result["text"]);
49-
}
50-
return $exit_code === 0;
51-
}
52-
5318
public function runUser(string $cmd, $args, &$cmd_result = null): bool {
5419
if (!empty($args) && is_array($args)) {
5520
array_unshift($args, $this->user());
@@ -364,4 +329,39 @@ public function cleanupTmpDir(): void {
364329
public function __destruct() {
365330
$this->cleanupTmpDir();
366331
}
332+
333+
private function run(string $cmd, $args, &$cmd_result = null): bool {
334+
$cli_script = realpath(HESTIA_DIR_BIN . $cmd);
335+
if (!str_starts_with((string) $cli_script, HESTIA_DIR_BIN)) {
336+
$errstr = "$cmd is trying to traverse outside of " . HESTIA_DIR_BIN;
337+
trigger_error($errstr);
338+
throw new \Exception($errstr);
339+
}
340+
$cli_script = "/usr/bin/sudo " . quoteshellarg($cli_script);
341+
342+
$cli_arguments = "";
343+
if (!empty($args) && is_array($args)) {
344+
foreach ($args as $arg) {
345+
$cli_arguments .= quoteshellarg((string) $arg) . " ";
346+
}
347+
} else {
348+
$cli_arguments = quoteshellarg($args);
349+
}
350+
351+
exec($cli_script . " " . $cli_arguments . " 2>&1", $output, $exit_code);
352+
353+
$result["code"] = $exit_code;
354+
$result["args"] = $cli_arguments;
355+
$result["raw"] = $output;
356+
$result["text"] = implode(PHP_EOL, $output);
357+
$result["json"] = json_decode($result["text"], true);
358+
$cmd_result = (object) $result;
359+
if ($exit_code > 0) {
360+
//log error message in nginx-error.log
361+
trigger_error($cli_script . " " . $cli_arguments . " | " . $result["text"]);
362+
//throw exception if command fails
363+
throw new \Exception($result["text"]);
364+
}
365+
return $exit_code === 0;
366+
}
367367
}

web/src/app/WebApp/Installers/DokuWiki/DokuWikiSetup.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,8 @@ public function install(array $options = null, &$status = null) {
6767
parent::setup($options);
6868

6969
//check if ssl is enabled
70-
$this->appcontext->run(
71-
"v-list-web-domain",
72-
[$this->appcontext->user(), $this->domain, "json"],
73-
$status,
74-
);
70+
$this->appcontext->runUser("v-list-web-domain", [$this->domain, "json"], $status);
71+
7572
$sslEnabled = $status->json[$this->domain]["SSL"] == "no" ? 0 : 1;
7673

7774
$webDomain = ($sslEnabled ? "https://" : "http://") . $this->domain . "/";

web/src/app/WebApp/Installers/Dolibarr/DolibarrSetup.php

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,7 @@ public function install(array $options = null): bool {
5858
$status,
5959
);
6060

61-
$this->appcontext->run(
62-
"v-list-web-domain",
63-
[$this->appcontext->user(), $this->domain, "json"],
64-
$status,
65-
);
61+
$this->appcontext->runUser("v-list-web-domain", [$this->domain, "json"], $status);
6662

6763
$sslEnabled = $status->json[$this->domain]["SSL"] == "no" ? false : true;
6864
$webDomain = ($sslEnabled ? "https://" : "http://") . $this->domain;

web/src/app/WebApp/Installers/Flarum/FlarumSetup.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,8 @@ public function install(array $options = null): bool {
149149
);
150150

151151
// POST install
152-
$this->appcontext->run(
153-
"v-list-web-domain",
154-
[$this->appcontext->user(), $this->domain, "json"],
155-
$status,
156-
);
152+
$this->appcontext->runUser("v-list-web-domain", [$this->domain, "json"], $status);
153+
157154
$sslEnabled = $status->json[$this->domain]["SSL"] == "no" ? 0 : 1;
158155
$webDomain = ($sslEnabled ? "https://" : "http://") . $this->domain;
159156
$webPort = $sslEnabled ? "443" : "80";

web/src/app/WebApp/Installers/MediaWiki/MediaWikiSetup.php

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,7 @@ public function install(array $options = null) {
4545
parent::setup($options);
4646

4747
//check if ssl is enabled
48-
$this->appcontext->run(
49-
"v-list-web-domain",
50-
[$this->appcontext->user(), $this->domain, "json"],
51-
$status,
52-
);
48+
$this->appcontext->runUser("v-list-web-domain", [$this->domain, "json"], $status);
5349

5450
if ($status->code !== 0) {
5551
throw new \Exception("Cannot list domain");

web/src/app/WebApp/Installers/OpenCart/OpenCartSetup.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,8 @@ public function install(array $options = null): bool {
6363
$this->getDocRoot(".htaccess"),
6464
]);
6565
#Check if SSL is enabled
66-
$this->appcontext->run(
67-
"v-list-web-domain",
68-
[$this->appcontext->user(), $this->domain, "json"],
69-
$status,
70-
);
66+
$this->appcontext->runUser("v-list-web-domain", [$this->domain, "json"], $status);
67+
7168
if ($status->code !== 0) {
7269
throw new \Exception("Cannot list domain");
7370
}

web/src/app/WebApp/Installers/PrestaShop/PrestaShopSetup.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,8 @@ public function install(array $options = null): bool {
4949
$this->getDocRoot(),
5050
);
5151
//check if ssl is enabled
52-
$this->appcontext->run(
53-
"v-list-web-domain",
54-
[$this->appcontext->user(), $this->domain, "json"],
55-
$status,
56-
);
52+
$this->appcontext->runUser("v-list-web-domain", [$this->domain, "json"], $status);
53+
5754
if ($status->code !== 0) {
5855
throw new \Exception("Cannot list domain");
5956
}

web/src/app/WebApp/Installers/ThirtyBees/ThirtyBeesSetup.php

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,7 @@ public function install(array $options = null): bool {
5353

5454
// Verificación del estado SSL del dominio
5555
$status = null;
56-
$this->appcontext->run(
57-
"v-list-web-domain",
58-
[$this->appcontext->user(), $this->domain, "json"],
59-
$status,
60-
);
56+
$this->appcontext->runUser("v-list-web-domain", [$this->domain, "json"], $status);
6157

6258
if ($status->code !== 0) {
6359
throw new \Exception("No se puede listar el dominio");

web/src/app/WebApp/Installers/WordPress/WordPressSetup.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -210,11 +210,8 @@ public function install(array $options = null) {
210210
);
211211
}
212212

213-
$this->appcontext->run(
214-
"v-list-web-domain",
215-
[$this->appcontext->user(), $this->domain, "json"],
216-
$status,
217-
);
213+
$this->appcontext->runUser("v-list-web-domain", [$this->domain, "json"], $status);
214+
218215
$sslEnabled = $status->json[$this->domain]["SSL"] == "no" ? 0 : 1;
219216
$webDomain = ($sslEnabled ? "https://" : "http://") . $this->domain . "/";
220217
$webPort = $sslEnabled ? "443" : "80";

0 commit comments

Comments
 (0)