$values) { // UnBreak special cases $section = str_replace("_", " ", $section); $content .= "[".$section."]\n"; //append the values foreach($values as $key=>$value) { if ($value == '') { $content .= $key."= \n"; } else { $content .= $key."=".$value."\n"; } } } // write it into file if (!$handle = fopen($filepath, 'w')) { return false; } $success = fwrite($handle, $content); fclose($handle); // /etc/ircddbgateway is a FLAT key=value file on disk — the // synthetic [ircddbgateway] header was injected at line ~75 // only to satisfy parse_ini_file()'s section model. The /tmp // staging file keeps the header (so the form re-render via // parse_ini_file at the bottom of this script still finds // sections); the on-disk version must not. Strip via PHP's // preg_replace and install the cleaned content directly — // drops the prior `sudo sed -i` from this code path (L-7). $etcContent = preg_replace('/^\[ircddbgateway\]\r?\n/m', '', $content); // A3-3: per-request random staging file rather than a // predictable hardcoded /tmp/.tmp path. tempnam() also // creates the file mode 600 — and since this is a freshly // created file (not yet referenced anywhere), there's no // race for an attacker to swap in a symlink before our write. $etcStaging = tempnam('/tmp', 'pistar-edit-etc-'); file_put_contents($etcStaging, $etcContent); // Atomic install: content + mode + owner set in one syscall // sequence (B5 / L-5 pattern). Replaces the prior cp + // chmod + chown trio so an interrupted RW window can't leave // /etc/ircddbgateway in a transient state. exec('sudo mount -o remount,rw /'); exec('sudo install -m 644 -o root -g root ' . escapeshellarg($etcStaging) . ' /etc/ircddbgateway'); exec('sudo mount -o remount,ro /'); @unlink($etcStaging); // Reload the affected daemon exec('sudo systemctl restart ircddbgateway.service'); // Reload the daemon return $success; } // parse the ini file using default parse_ini_file() PHP function $parsed_ini = parse_ini_file($filepath, true); echo '
'."\n"; echo csrf_field_html()."\n"; foreach($parsed_ini as $section=>$values) { // keep the section as hidden text so we can update once the form submitted // INI section / key / value all come from the underlying // /etc/ file. Same hardening as edit_mmdvmhost.php // (#23): htmlspecialchars(ENT_QUOTES) on display so a value // with a literal `"` or `<` (e.g. an Options string) can't // break out of the `value="…"` attribute. The save handler // writes the POST bytes verbatim, so legitimate quoted // values round-trip byte-identically. $sectionHtml = htmlspecialchars((string)$section, ENT_QUOTES, 'UTF-8'); echo "\n"; echo "\n"; echo "\n"; // print all other values as input fields, so can edit. // note the name='' attribute it has both section and key foreach($values as $key=>$value) { $keyHtml = htmlspecialchars((string)$key, ENT_QUOTES, 'UTF-8'); $valueHtml = htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8'); echo "\n"; } echo "
$sectionHtml
$keyHtml
\n"; echo ''."\n"; echo "
\n"; } echo ""; ?>