diff --git a/admin.php b/admin.php
new file mode 100644
index 0000000..4e76234
--- /dev/null
+++ b/admin.php
@@ -0,0 +1,143 @@
+
+// Copyright (c) 2022 High5!
+// License Info: LICENSE.TXT
+//
+// File: admin.php
+//
+// Template File: admin_admin.tpl
+//
+//
+// Template Variables:
+//
+// action
+// message
+// username
+// domains
+//
+// POST / GET Variables:
+//
+// username
+// password1
+// password2
+// domains
+//
+require_once './functions.inc.php';
+include './languages/' . check_language() . '.lang';
+
+$SESSID_USERNAME = check_session();
+$PERMISSIONS = check_permissions();
+
+if ($PERMISSIONS != ADMIN_RIGHTS) {
+ header("Location: list-domain.php");
+ die();;
+}
+
+$list_domains = list_domains();
+$list_admins = list_admins();
+
+if ($_SERVER['REQUEST_METHOD'] == "GET") {
+ $action = filter_input(INPUT_GET, 'action', FILTER_DEFAULT) ?? 'add';
+ if ($action == 'edit') {
+ $username = filter_input(INPUT_GET, 'username', FILTER_VALIDATE_EMAIL);
+ $domains['domains'] = array_column(list_domains($username), 'domain');
+ }
+}
+
+if ($_SERVER['REQUEST_METHOD'] == "POST") {
+ $action = filter_input(INPUT_GET, 'action', FILTER_DEFAULT) ?? 'add';
+ $username = filter_input(INPUT_POST, 'username', FILTER_VALIDATE_EMAIL);
+ $password1 = filter_input(INPUT_POST, 'password1', FILTER_DEFAULT);
+ $password2 = filter_input(INPUT_POST, 'password2', FILTER_DEFAULT);
+ $domains = filter_input_array(INPUT_POST, array('domains' => array('filter' => FILTER_VALIDATE_DOMAIN, 'flags' => FILTER_REQUIRE_ARRAY)));
+
+
+ if ($action == 'add') {
+ if (empty($username) || in_array($username, array_column($list_admins, 'username'))) {
+ $message = $LANG['AdminAdd_admin_username_error'];
+ }
+
+ if (empty($password1) || $password1 != $password2) {
+ $message = $LANG['AdminAdd_admin_password_error'];
+ }
+
+ if (empty($domains['domains'])) {
+ $message = $LANG['AdminAdd_admin_domain_error'];
+ }
+
+ if (empty($message)) {
+ $hashed = bcrypt($password1);
+ try {
+ $dbh = pdo_connect();
+ $sth = $dbh->prepare("INSERT INTO admin (username,password,created,modified) VALUES (?,?,NOW(),NOW())");
+ $sth->bindParam(1, $username, PDO::PARAM_STR);
+ $sth->bindParam(2, $hashed, PDO::PARAM_STR);
+ $sth->execute();
+ foreach ($domains['domains'] as $row) {
+ $sth = $dbh->prepare("INSERT INTO domain_admins (username,domain,created) VALUES (?,?,NOW())");
+ $sth->bindParam(1, $username, PDO::PARAM_STR);
+ $sth->bindParam(2, $row, PDO::PARAM_STR);
+ $sth->execute();
+ }
+ $message = $LANG['AdminAdd_admin_result_succes'] . "
($username)";
+ } catch(PDOException $e) {
+ $message = $LANG['AdminAdd_admin_result_error'] . "
($username)
";
+ }
+ }
+ }
+
+ if (in_array($username, array_column($list_admins, 'username')) && $action == 'edit') {
+ if ($password1 != $password2) {
+ $message = $LANG['AdminAdd_admin_password_error'];
+ }
+ if (empty($message) && !empty($password1)) {
+ $hashed = bcrypt($password1);
+ try {
+ $dbh = pdo_connect();
+ $sth = $dbh->prepare("UPDATE admin SET password=?,modified=NOW() WHERE username=?");
+ $sth->bindParam(1, $hashed, PDO::PARAM_STR);
+ $sth->bindParam(2, $username, PDO::PARAM_STR);
+ $sth->execute();
+ } catch(PDOException $e) {
+ $message = $LANG['AdminEdit_admin_result_error'] . "
($username)
";
+ }
+ }
+
+ if (empty($domains['domains'])) {
+ $message = $LANG['AdminAdd_admin_domain_error'];
+ }
+ if (empty($message)) {
+ try {
+ $dbh = pdo_connect();
+ $sth = $dbh->prepare("SELECT COUNT(*) FROM domain_admins WHERE username=?");
+ $sth->execute(array($username));
+ $count_domain_admins = $sth->fetchColumn();
+
+ $sth = $dbh->prepare("DELETE FROM domain_admins WHERE username=?");
+ $sth->execute(array($username));
+ if ($sth->rowCount() != $count_domain_admins) {
+ throw new RuntimeException('Unable to delete entries from the domain_admins table.');
+ }
+
+ foreach ($domains['domains'] as $row) {
+ $sth = $dbh->prepare("INSERT INTO domain_admins (username,domain,created) VALUES (?,?,NOW())");
+ $sth->bindParam(1, $username, PDO::PARAM_STR);
+ $sth->bindParam(2, $row, PDO::PARAM_STR);
+ $sth->execute();
+ }
+ header("Location: list-admin.php");
+ } catch (RuntimeException $e) {
+ $message = $LANG['AdminEdit_admin_result_error'];
+ } catch (PDOException $e) {
+ $message = $LANG['AdminEdit_admin_result_error'];
+ }
+ }
+ }
+}
+include './templates/header.tpl';
+include './templates/menu.tpl';
+include './templates/admin.tpl';
+include './templates/footer.tpl';
+?>
diff --git a/backup.php b/backup.php
new file mode 100644
index 0000000..d9546e3
--- /dev/null
+++ b/backup.php
@@ -0,0 +1,78 @@
+
+// Copyright (c) 2022 High5!
+// License Info: LICENSE.TXT
+//
+// File: backup.php
+//
+// Template File: -none-
+//
+// Template Variables:
+//
+// -none-
+//
+// POST / GET Variables:
+//
+// -none-
+//
+require_once './functions.inc.php';
+include './languages/' . check_language() . '.lang';
+date_default_timezone_set('Europe/Amsterdam');
+
+$SESSID_USERNAME = check_session();
+$PERMISSIONS = check_permissions();
+
+if ($PERMISSIONS != ADMIN_RIGHTS) {
+ header("Location: list-domain.php");
+ die();;
+}
+
+if ($_SERVER['REQUEST_METHOD'] == "GET") {
+ umask(077);
+ $filename = "opensmtpadmin-" . date("Ymd") . "-" . getmypid() . ".sql";
+ $backup = "/tmp/" . $filename;
+ $header = "#\n# OpenSMTPD Admin " . VERSION . "\n# Date: " . date("D M j G:i:s T Y") . "\n#\n";
+ $tables = array('admin','alias','domain','domain_admins','log','mailbox','vacation');
+
+ if (!$fh = fopen($backup, 'w')) {
+ $message = "