[Web] Implemented SSO for domain admins
Signed-off-by: Kristian Feldsam <feldsam@gmail.com> Revert "[Web] Implemented SSO for domain admins" This reverts commit 6860dc8ebe2c8f53d77df5bca7787f7cb3bb4ee0. Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
This commit is contained in:
		| @@ -699,6 +699,38 @@ paths: | ||||
|                   type: string | ||||
|               type: object | ||||
|       summary: Create Domain Admin user | ||||
|   /api/v1/add/sso/domain-admin: | ||||
|     post: | ||||
|       responses: | ||||
|         "401": | ||||
|           $ref: "#/components/responses/Unauthorized" | ||||
|         "200": | ||||
|           content: | ||||
|             application/json: | ||||
|               examples: | ||||
|                 response: | ||||
|                   value: | ||||
|                     token: "591F6D-5C3DD2-7455CD-DAF1C1-AA4FCC" | ||||
|           description: OK | ||||
|           headers: { } | ||||
|       tags: | ||||
|         - Single Sign-On | ||||
|       description: >- | ||||
|         Using this endpoint you can issue a token for Domain Admin user. This token can be used for | ||||
|         autologin Domain Admin user by using query_string var sso_token={token}. Token expiration time is 30s | ||||
|       operationId: Issue Domain Admin SSO token | ||||
|       requestBody: | ||||
|         content: | ||||
|           application/json: | ||||
|             schema: | ||||
|               example: | ||||
|                 username: testadmin | ||||
|               properties: | ||||
|                 username: | ||||
|                   description: the username for the admin user | ||||
|                   type: object | ||||
|               type: object | ||||
|       summary: Issue Domain Admin SSO token | ||||
|   /api/v1/edit/da-acl: | ||||
|     post: | ||||
|       responses: | ||||
| @@ -1999,7 +2031,7 @@ paths: | ||||
|                 - domain.tld | ||||
|                 - domain2.tld | ||||
|               properties: | ||||
|                 items:  | ||||
|                 items: | ||||
|                   type: array | ||||
|                   items: | ||||
|                     type: string | ||||
| @@ -2993,7 +3025,7 @@ paths: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 type: array | ||||
|                 items:  | ||||
|                 items: | ||||
|                   type: object | ||||
|                   properties: | ||||
|                     log: | ||||
| @@ -5586,6 +5618,8 @@ tags: | ||||
|     description: Manage DKIM keys | ||||
|   - name: Domain admin | ||||
|     description: Create or udpdate domain admin users | ||||
|   - name: Single Sign-On | ||||
|     description: Issue tokens for users | ||||
|   - name: Address Rewriting | ||||
|     description: Create BCC maps or recipient maps | ||||
|   - name: Outgoing TLS Policy Map Overrides | ||||
|   | ||||
| @@ -1,407 +1,468 @@ | ||||
| <?php | ||||
| function domain_admin($_action, $_data = null) { | ||||
|   global $pdo; | ||||
|   global $lang; | ||||
|   $_data_log = $_data; | ||||
|   !isset($_data_log['password']) ?: $_data_log['password'] = '*'; | ||||
|   !isset($_data_log['password2']) ?: $_data_log['password2'] = '*'; | ||||
|   !isset($_data_log['user_old_pass']) ?: $_data_log['user_old_pass'] = '*'; | ||||
|   !isset($_data_log['user_new_pass']) ?: $_data_log['user_new_pass'] = '*'; | ||||
|   !isset($_data_log['user_new_pass2']) ?: $_data_log['user_new_pass2'] = '*'; | ||||
|   switch ($_action) { | ||||
|     case 'add': | ||||
|       $username		= strtolower(trim($_data['username'])); | ||||
|       $password		= $_data['password']; | ||||
|       $password2  = $_data['password2']; | ||||
|       $domains    = (array)$_data['domains']; | ||||
|       $active     = intval($_data['active']); | ||||
|       if ($_SESSION['mailcow_cc_role'] != "admin") { | ||||
|         $_SESSION['return'][] = array( | ||||
|           'type' => 'danger', | ||||
|           'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|           'msg' => 'access_denied' | ||||
|         ); | ||||
|         return false; | ||||
|       } | ||||
|       if (empty($domains)) { | ||||
|         $_SESSION['return'][] = array( | ||||
|           'type' => 'danger', | ||||
|           'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|           'msg' => 'domain_invalid' | ||||
|         ); | ||||
|         return false; | ||||
|       } | ||||
|       if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $username)) || empty ($username) || $username == 'API') { | ||||
|         $_SESSION['return'][] = array( | ||||
|           'type' => 'danger', | ||||
|           'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|           'msg' => array('username_invalid', $username) | ||||
|         ); | ||||
|         return false; | ||||
|       } | ||||
|  | ||||
|       $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` | ||||
|         WHERE `username` = :username"); | ||||
|       $stmt->execute(array(':username' => $username)); | ||||
|       $num_results[] = count($stmt->fetchAll(PDO::FETCH_ASSOC)); | ||||
|  | ||||
|       $stmt = $pdo->prepare("SELECT `username` FROM `admin` | ||||
|         WHERE `username` = :username"); | ||||
|       $stmt->execute(array(':username' => $username)); | ||||
|       $num_results[] = count($stmt->fetchAll(PDO::FETCH_ASSOC)); | ||||
|  | ||||
|       $stmt = $pdo->prepare("SELECT `username` FROM `domain_admins` | ||||
|         WHERE `username` = :username"); | ||||
|       $stmt->execute(array(':username' => $username)); | ||||
|       $num_results[] = count($stmt->fetchAll(PDO::FETCH_ASSOC)); | ||||
|  | ||||
|       foreach ($num_results as $num_results_each) { | ||||
|         if ($num_results_each != 0) { | ||||
|           $_SESSION['return'][] = array( | ||||
|             'type' => 'danger', | ||||
|             'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|             'msg' => array('object_exists', htmlspecialchars($username)) | ||||
|           ); | ||||
|           return false; | ||||
|         } | ||||
|       } | ||||
|       if (password_check($password, $password2) !== true) { | ||||
|         continue; | ||||
|       } | ||||
|       $password_hashed = hash_password($password); | ||||
|       $valid_domains = 0; | ||||
|       foreach ($domains as $domain) { | ||||
|         if (!is_valid_domain_name($domain) || mailbox('get', 'domain_details', $domain) === false) { | ||||
|           $_SESSION['return'][] = array( | ||||
|             'type' => 'danger', | ||||
|             'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|             'msg' => array('domain_invalid', htmlspecialchars($domain)) | ||||
|           ); | ||||
|           continue; | ||||
|         } | ||||
|         $valid_domains++; | ||||
|         $stmt = $pdo->prepare("INSERT INTO `domain_admins` (`username`, `domain`, `created`, `active`) | ||||
|             VALUES (:username, :domain, :created, :active)"); | ||||
|         $stmt->execute(array( | ||||
|           ':username' => $username, | ||||
|           ':domain' => $domain, | ||||
|           ':created' => date('Y-m-d H:i:s'), | ||||
|           ':active' => $active | ||||
|         )); | ||||
|       } | ||||
|       if ($valid_domains != 0) { | ||||
|         $stmt = $pdo->prepare("INSERT INTO `admin` (`username`, `password`, `superadmin`, `active`) | ||||
|           VALUES (:username, :password_hashed, '0', :active)"); | ||||
|         $stmt->execute(array( | ||||
|           ':username' => $username, | ||||
|           ':password_hashed' => $password_hashed, | ||||
|           ':active' => $active | ||||
|         )); | ||||
|       } | ||||
|       $stmt = $pdo->prepare("INSERT INTO `da_acl` (`username`) VALUES (:username)"); | ||||
|       $stmt->execute(array( | ||||
|         ':username' => $username | ||||
|       )); | ||||
|       $_SESSION['return'][] = array( | ||||
|         'type' => 'success', | ||||
|         'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|         'msg' => array('domain_admin_added', htmlspecialchars($username)) | ||||
|       ); | ||||
|     break; | ||||
|     case 'edit': | ||||
|       if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") { | ||||
|         $_SESSION['return'][] = array( | ||||
|           'type' => 'danger', | ||||
|           'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|           'msg' => 'access_denied' | ||||
|         ); | ||||
|         return false; | ||||
|       } | ||||
|       // Administrator | ||||
|       if ($_SESSION['mailcow_cc_role'] == "admin") { | ||||
|         if (!is_array($_data['username'])) { | ||||
|           $usernames = array(); | ||||
|           $usernames[] = $_data['username']; | ||||
|         } | ||||
|         else { | ||||
|           $usernames = $_data['username']; | ||||
|         } | ||||
|         foreach ($usernames as $username) { | ||||
|           $is_now = domain_admin('details', $username); | ||||
|           $domains = (isset($_data['domains'])) ? (array)$_data['domains'] : null; | ||||
|           if (!empty($is_now)) { | ||||
|             $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active']; | ||||
|             $domains = (!empty($domains)) ? $domains : $is_now['selected_domains']; | ||||
|             $username_new = (!empty($_data['username_new'])) ? $_data['username_new'] : $is_now['username']; | ||||
|           } | ||||
|           else { | ||||
|             $_SESSION['return'][] = array( | ||||
|               'type' => 'danger', | ||||
|               'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|               'msg' => 'access_denied' | ||||
|             ); | ||||
|             continue; | ||||
|           } | ||||
|           $password     = $_data['password']; | ||||
|           $password2    = $_data['password2']; | ||||
|           if (!empty($domains)) { | ||||
|             foreach ($domains as $domain) { | ||||
|               if (!is_valid_domain_name($domain) || mailbox('get', 'domain_details', $domain) === false) { | ||||
|                 $_SESSION['return'][] = array( | ||||
|                   'type' => 'danger', | ||||
|                   'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|                   'msg' => array('domain_invalid', htmlspecialchars($domain)) | ||||
|                 ); | ||||
|                 continue 2; | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|           if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $username_new))) { | ||||
|             $_SESSION['return'][] = array( | ||||
|               'type' => 'danger', | ||||
|               'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|               'msg' => array('username_invalid', $username_new) | ||||
|             ); | ||||
|             continue; | ||||
|           } | ||||
|           if ($username_new != $username) { | ||||
|             if (!empty(domain_admin('details', $username_new)['username'])) { | ||||
|               $_SESSION['return'][] = array( | ||||
|                 'type' => 'danger', | ||||
|                 'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|                 'msg' => array('username_invalid', $username_new) | ||||
|               ); | ||||
|               continue; | ||||
|             } | ||||
|           } | ||||
|           $stmt = $pdo->prepare("DELETE FROM `domain_admins` WHERE `username` = :username"); | ||||
|           $stmt->execute(array( | ||||
|             ':username' => $username, | ||||
|           )); | ||||
|           $stmt = $pdo->prepare("UPDATE `da_acl` SET `username` = :username_new WHERE `username` = :username"); | ||||
|           $stmt->execute(array( | ||||
|             ':username_new' => $username_new, | ||||
|             ':username' => $username | ||||
|           )); | ||||
|           if (!empty($domains)) { | ||||
|             foreach ($domains as $domain) { | ||||
|               $stmt = $pdo->prepare("INSERT INTO `domain_admins` (`username`, `domain`, `created`, `active`) | ||||
|                 VALUES (:username_new, :domain, :created, :active)"); | ||||
|               $stmt->execute(array( | ||||
|                 ':username_new' => $username_new, | ||||
|                 ':domain' => $domain, | ||||
|                 ':created' => date('Y-m-d H:i:s'), | ||||
|                 ':active' => $active | ||||
|               )); | ||||
|             } | ||||
|           } | ||||
|           if (!empty($password)) { | ||||
|             if (password_check($password, $password2) !== true) { | ||||
|               return false; | ||||
|             } | ||||
|             $password_hashed = hash_password($password); | ||||
|             $stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username_new, `active` = :active, `password` = :password_hashed WHERE `username` = :username"); | ||||
|             $stmt->execute(array( | ||||
|               ':password_hashed' => $password_hashed, | ||||
|               ':username_new' => $username_new, | ||||
|               ':username' => $username, | ||||
|               ':active' => $active | ||||
|             )); | ||||
|             if (isset($_data['disable_tfa'])) { | ||||
|               $stmt = $pdo->prepare("UPDATE `tfa` SET `active` = '0' WHERE `username` = :username"); | ||||
|               $stmt->execute(array(':username' => $username)); | ||||
|             } | ||||
|             else { | ||||
|               $stmt = $pdo->prepare("UPDATE `tfa` SET `username` = :username_new WHERE `username` = :username"); | ||||
|               $stmt->execute(array(':username_new' => $username_new, ':username' => $username)); | ||||
|             } | ||||
|           } | ||||
|           else { | ||||
|             $stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username_new, `active` = :active WHERE `username` = :username"); | ||||
|             $stmt->execute(array( | ||||
|               ':username_new' => $username_new, | ||||
|               ':username' => $username, | ||||
|               ':active' => $active | ||||
|             )); | ||||
|             if (isset($_data['disable_tfa'])) { | ||||
|               $stmt = $pdo->prepare("UPDATE `tfa` SET `active` = '0' WHERE `username` = :username"); | ||||
|               $stmt->execute(array(':username' => $username)); | ||||
|             } | ||||
|             else { | ||||
|               $stmt = $pdo->prepare("UPDATE `tfa` SET `username` = :username_new WHERE `username` = :username"); | ||||
|               $stmt->execute(array(':username_new' => $username_new, ':username' => $username)); | ||||
|             } | ||||
|           } | ||||
|           $_SESSION['return'][] = array( | ||||
|             'type' => 'success', | ||||
|             'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|             'msg' => array('domain_admin_modified', htmlspecialchars($username)) | ||||
|           ); | ||||
|         } | ||||
|         return true; | ||||
|       } | ||||
|       // Domain administrator | ||||
|       // Can only edit itself | ||||
|       elseif ($_SESSION['mailcow_cc_role'] == "domainadmin") { | ||||
|         $username = $_SESSION['mailcow_cc_username']; | ||||
|         $password_old		= $_data['user_old_pass']; | ||||
|         $password_new	= $_data['user_new_pass']; | ||||
|         $password_new2	= $_data['user_new_pass2']; | ||||
|  | ||||
|         $stmt = $pdo->prepare("SELECT `password` FROM `admin` | ||||
|             WHERE `username` = :user"); | ||||
|         $stmt->execute(array(':user' => $username)); | ||||
|         $row = $stmt->fetch(PDO::FETCH_ASSOC); | ||||
|         if (!verify_hash($row['password'], $password_old)) { | ||||
|           $_SESSION['return'][] = array( | ||||
|             'type' => 'danger', | ||||
|             'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|             'msg' => 'access_denied' | ||||
|           ); | ||||
|           return false; | ||||
|         } | ||||
|         if (password_check($password_new, $password_new2) !== true) { | ||||
|           return false; | ||||
|         } | ||||
|         $password_hashed = hash_password($password_new); | ||||
|         $stmt = $pdo->prepare("UPDATE `admin` SET `password` = :password_hashed WHERE `username` = :username"); | ||||
|         $stmt->execute(array( | ||||
|           ':password_hashed' => $password_hashed, | ||||
|           ':username' => $username | ||||
|         )); | ||||
|         $_SESSION['return'][] = array( | ||||
|           'type' => 'success', | ||||
|           'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|           'msg' => array('domain_admin_modified', htmlspecialchars($username)) | ||||
|         ); | ||||
|       } | ||||
|     break; | ||||
|     case 'delete': | ||||
|       if ($_SESSION['mailcow_cc_role'] != "admin") { | ||||
|         $_SESSION['return'][] = array( | ||||
|           'type' => 'danger', | ||||
|           'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|           'msg' => 'access_denied' | ||||
|         ); | ||||
|         return false; | ||||
|       } | ||||
|       $usernames = (array)$_data['username']; | ||||
|       foreach ($usernames as $username) { | ||||
|         if (empty(domain_admin('details', $username))) { | ||||
|           $_SESSION['return'][] = array( | ||||
|             'type' => 'danger', | ||||
|             'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|             'msg' => array('username_invalid', $username) | ||||
|           ); | ||||
|           continue; | ||||
|         } | ||||
|         $stmt = $pdo->prepare("DELETE FROM `domain_admins` WHERE `username` = :username"); | ||||
|         $stmt->execute(array( | ||||
|           ':username' => $username, | ||||
|         )); | ||||
|         $stmt = $pdo->prepare("DELETE FROM `admin` WHERE `username` = :username"); | ||||
|         $stmt->execute(array( | ||||
|           ':username' => $username, | ||||
|         )); | ||||
|         $stmt = $pdo->prepare("DELETE FROM `da_acl` WHERE `username` = :username"); | ||||
|         $stmt->execute(array( | ||||
|           ':username' => $username, | ||||
|         )); | ||||
|         $stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username"); | ||||
|         $stmt->execute(array( | ||||
|           ':username' => $username, | ||||
|         )); | ||||
|         $stmt = $pdo->prepare("DELETE FROM `fido2` WHERE `username` = :username"); | ||||
|         $stmt->execute(array( | ||||
|           ':username' => $username, | ||||
|         )); | ||||
|         $_SESSION['return'][] = array( | ||||
|           'type' => 'success', | ||||
|           'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|           'msg' => array('domain_admin_removed', htmlspecialchars($username)) | ||||
|         ); | ||||
|       } | ||||
|     break; | ||||
|     case 'get': | ||||
|       $domainadmins = array(); | ||||
|       if ($_SESSION['mailcow_cc_role'] != "admin") { | ||||
|         $_SESSION['return'][] = array( | ||||
|           'type' => 'danger', | ||||
|           'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|           'msg' => 'access_denied' | ||||
|         ); | ||||
|         return false; | ||||
|       } | ||||
|       $stmt = $pdo->query("SELECT DISTINCT | ||||
|         `username` | ||||
|           FROM `domain_admins` | ||||
|             WHERE `username` IN ( | ||||
|               SELECT `username` FROM `admin` | ||||
|                 WHERE `superadmin`!='1' | ||||
|             )"); | ||||
|       $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); | ||||
|       while ($row = array_shift($rows)) { | ||||
|         $domainadmins[] = $row['username']; | ||||
|       } | ||||
|       return $domainadmins; | ||||
|     break; | ||||
|     case 'details': | ||||
|       $domainadmindata = array(); | ||||
|       if ($_SESSION['mailcow_cc_role'] == "domainadmin" && $_data != $_SESSION['mailcow_cc_username']) { | ||||
|         return false; | ||||
|       } | ||||
|       elseif ($_SESSION['mailcow_cc_role'] != "admin" || !isset($_data)) { | ||||
|         return false; | ||||
|       } | ||||
|       if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $_data))) { | ||||
|         return false; | ||||
|       } | ||||
|       $stmt = $pdo->prepare("SELECT | ||||
|         `tfa`.`active` AS `tfa_active`, | ||||
|         `domain_admins`.`username`, | ||||
|         `domain_admins`.`created`, | ||||
|         `domain_admins`.`active` AS `active` | ||||
|           FROM `domain_admins` | ||||
|           LEFT OUTER JOIN `tfa` ON `tfa`.`username`=`domain_admins`.`username` | ||||
|             WHERE `domain_admins`.`username`= :domain_admin"); | ||||
|       $stmt->execute(array( | ||||
|         ':domain_admin' => $_data | ||||
|       )); | ||||
|       $row = $stmt->fetch(PDO::FETCH_ASSOC); | ||||
|       if (empty($row)) { | ||||
|         return false; | ||||
|       } | ||||
|       $domainadmindata['username'] = $row['username']; | ||||
|       $domainadmindata['tfa_active'] = (is_null($row['tfa_active'])) ? 0 : $row['tfa_active']; | ||||
|       $domainadmindata['tfa_active_int'] = (is_null($row['tfa_active'])) ? 0 : $row['tfa_active']; | ||||
|       $domainadmindata['active'] = $row['active']; | ||||
|       $domainadmindata['active_int'] = $row['active']; | ||||
|       $domainadmindata['created'] = $row['created']; | ||||
|       // GET SELECTED | ||||
|       $stmt = $pdo->prepare("SELECT `domain` FROM `domain` | ||||
|         WHERE `domain` IN ( | ||||
|           SELECT `domain` FROM `domain_admins` | ||||
|             WHERE `username`= :domain_admin)"); | ||||
|       $stmt->execute(array(':domain_admin' => $_data)); | ||||
|       $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); | ||||
|       while($row = array_shift($rows)) { | ||||
|         $domainadmindata['selected_domains'][] = $row['domain']; | ||||
|       } | ||||
|       // GET UNSELECTED | ||||
|       $stmt = $pdo->prepare("SELECT `domain` FROM `domain` | ||||
|         WHERE `domain` NOT IN ( | ||||
|           SELECT `domain` FROM `domain_admins` | ||||
|             WHERE `username`= :domain_admin)"); | ||||
|       $stmt->execute(array(':domain_admin' => $_data)); | ||||
|       $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); | ||||
|       while($row = array_shift($rows)) { | ||||
|         $domainadmindata['unselected_domains'][] = $row['domain']; | ||||
|       } | ||||
|       if (!isset($domainadmindata['unselected_domains'])) { | ||||
|         $domainadmindata['unselected_domains'] = ""; | ||||
|       } | ||||
|  | ||||
|       return $domainadmindata; | ||||
|     break; | ||||
|   } | ||||
| } | ||||
| <?php | ||||
| function domain_admin($_action, $_data = null) { | ||||
|   global $pdo; | ||||
|   global $lang; | ||||
|   $_data_log = $_data; | ||||
|   !isset($_data_log['password']) ?: $_data_log['password'] = '*'; | ||||
|   !isset($_data_log['password2']) ?: $_data_log['password2'] = '*'; | ||||
|   !isset($_data_log['user_old_pass']) ?: $_data_log['user_old_pass'] = '*'; | ||||
|   !isset($_data_log['user_new_pass']) ?: $_data_log['user_new_pass'] = '*'; | ||||
|   !isset($_data_log['user_new_pass2']) ?: $_data_log['user_new_pass2'] = '*'; | ||||
|   switch ($_action) { | ||||
|     case 'add': | ||||
|       $username		= strtolower(trim($_data['username'])); | ||||
|       $password		= $_data['password']; | ||||
|       $password2  = $_data['password2']; | ||||
|       $domains    = (array)$_data['domains']; | ||||
|       $active     = intval($_data['active']); | ||||
|       if ($_SESSION['mailcow_cc_role'] != "admin") { | ||||
|         $_SESSION['return'][] = array( | ||||
|           'type' => 'danger', | ||||
|           'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|           'msg' => 'access_denied' | ||||
|         ); | ||||
|         return false; | ||||
|       } | ||||
|       if (empty($domains)) { | ||||
|         $_SESSION['return'][] = array( | ||||
|           'type' => 'danger', | ||||
|           'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|           'msg' => 'domain_invalid' | ||||
|         ); | ||||
|         return false; | ||||
|       } | ||||
|       if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $username)) || empty ($username) || $username == 'API') { | ||||
|         $_SESSION['return'][] = array( | ||||
|           'type' => 'danger', | ||||
|           'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|           'msg' => array('username_invalid', $username) | ||||
|         ); | ||||
|         return false; | ||||
|       } | ||||
|  | ||||
|       $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` | ||||
|         WHERE `username` = :username"); | ||||
|       $stmt->execute(array(':username' => $username)); | ||||
|       $num_results[] = count($stmt->fetchAll(PDO::FETCH_ASSOC)); | ||||
|  | ||||
|       $stmt = $pdo->prepare("SELECT `username` FROM `admin` | ||||
|         WHERE `username` = :username"); | ||||
|       $stmt->execute(array(':username' => $username)); | ||||
|       $num_results[] = count($stmt->fetchAll(PDO::FETCH_ASSOC)); | ||||
|  | ||||
|       $stmt = $pdo->prepare("SELECT `username` FROM `domain_admins` | ||||
|         WHERE `username` = :username"); | ||||
|       $stmt->execute(array(':username' => $username)); | ||||
|       $num_results[] = count($stmt->fetchAll(PDO::FETCH_ASSOC)); | ||||
|  | ||||
|       foreach ($num_results as $num_results_each) { | ||||
|         if ($num_results_each != 0) { | ||||
|           $_SESSION['return'][] = array( | ||||
|             'type' => 'danger', | ||||
|             'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|             'msg' => array('object_exists', htmlspecialchars($username)) | ||||
|           ); | ||||
|           return false; | ||||
|         } | ||||
|       } | ||||
|       if (password_check($password, $password2) !== true) { | ||||
|         continue; | ||||
|       } | ||||
|       $password_hashed = hash_password($password); | ||||
|       $valid_domains = 0; | ||||
|       foreach ($domains as $domain) { | ||||
|         if (!is_valid_domain_name($domain) || mailbox('get', 'domain_details', $domain) === false) { | ||||
|           $_SESSION['return'][] = array( | ||||
|             'type' => 'danger', | ||||
|             'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|             'msg' => array('domain_invalid', htmlspecialchars($domain)) | ||||
|           ); | ||||
|           continue; | ||||
|         } | ||||
|         $valid_domains++; | ||||
|         $stmt = $pdo->prepare("INSERT INTO `domain_admins` (`username`, `domain`, `created`, `active`) | ||||
|             VALUES (:username, :domain, :created, :active)"); | ||||
|         $stmt->execute(array( | ||||
|           ':username' => $username, | ||||
|           ':domain' => $domain, | ||||
|           ':created' => date('Y-m-d H:i:s'), | ||||
|           ':active' => $active | ||||
|         )); | ||||
|       } | ||||
|       if ($valid_domains != 0) { | ||||
|         $stmt = $pdo->prepare("INSERT INTO `admin` (`username`, `password`, `superadmin`, `active`) | ||||
|           VALUES (:username, :password_hashed, '0', :active)"); | ||||
|         $stmt->execute(array( | ||||
|           ':username' => $username, | ||||
|           ':password_hashed' => $password_hashed, | ||||
|           ':active' => $active | ||||
|         )); | ||||
|       } | ||||
|       $stmt = $pdo->prepare("INSERT INTO `da_acl` (`username`) VALUES (:username)"); | ||||
|       $stmt->execute(array( | ||||
|         ':username' => $username | ||||
|       )); | ||||
|       $_SESSION['return'][] = array( | ||||
|         'type' => 'success', | ||||
|         'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|         'msg' => array('domain_admin_added', htmlspecialchars($username)) | ||||
|       ); | ||||
|     break; | ||||
|     case 'edit': | ||||
|       if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") { | ||||
|         $_SESSION['return'][] = array( | ||||
|           'type' => 'danger', | ||||
|           'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|           'msg' => 'access_denied' | ||||
|         ); | ||||
|         return false; | ||||
|       } | ||||
|       // Administrator | ||||
|       if ($_SESSION['mailcow_cc_role'] == "admin") { | ||||
|         if (!is_array($_data['username'])) { | ||||
|           $usernames = array(); | ||||
|           $usernames[] = $_data['username']; | ||||
|         } | ||||
|         else { | ||||
|           $usernames = $_data['username']; | ||||
|         } | ||||
|         foreach ($usernames as $username) { | ||||
|           $is_now = domain_admin('details', $username); | ||||
|           $domains = (isset($_data['domains'])) ? (array)$_data['domains'] : null; | ||||
|           if (!empty($is_now)) { | ||||
|             $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active']; | ||||
|             $domains = (!empty($domains)) ? $domains : $is_now['selected_domains']; | ||||
|             $username_new = (!empty($_data['username_new'])) ? $_data['username_new'] : $is_now['username']; | ||||
|           } | ||||
|           else { | ||||
|             $_SESSION['return'][] = array( | ||||
|               'type' => 'danger', | ||||
|               'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|               'msg' => 'access_denied' | ||||
|             ); | ||||
|             continue; | ||||
|           } | ||||
|           $password     = $_data['password']; | ||||
|           $password2    = $_data['password2']; | ||||
|           if (!empty($domains)) { | ||||
|             foreach ($domains as $domain) { | ||||
|               if (!is_valid_domain_name($domain) || mailbox('get', 'domain_details', $domain) === false) { | ||||
|                 $_SESSION['return'][] = array( | ||||
|                   'type' => 'danger', | ||||
|                   'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|                   'msg' => array('domain_invalid', htmlspecialchars($domain)) | ||||
|                 ); | ||||
|                 continue 2; | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|           if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $username_new))) { | ||||
|             $_SESSION['return'][] = array( | ||||
|               'type' => 'danger', | ||||
|               'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|               'msg' => array('username_invalid', $username_new) | ||||
|             ); | ||||
|             continue; | ||||
|           } | ||||
|           if ($username_new != $username) { | ||||
|             if (!empty(domain_admin('details', $username_new)['username'])) { | ||||
|               $_SESSION['return'][] = array( | ||||
|                 'type' => 'danger', | ||||
|                 'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|                 'msg' => array('username_invalid', $username_new) | ||||
|               ); | ||||
|               continue; | ||||
|             } | ||||
|           } | ||||
|           $stmt = $pdo->prepare("DELETE FROM `domain_admins` WHERE `username` = :username"); | ||||
|           $stmt->execute(array( | ||||
|             ':username' => $username, | ||||
|           )); | ||||
|           $stmt = $pdo->prepare("UPDATE `da_acl` SET `username` = :username_new WHERE `username` = :username"); | ||||
|           $stmt->execute(array( | ||||
|             ':username_new' => $username_new, | ||||
|             ':username' => $username | ||||
|           )); | ||||
|           if (!empty($domains)) { | ||||
|             foreach ($domains as $domain) { | ||||
|               $stmt = $pdo->prepare("INSERT INTO `domain_admins` (`username`, `domain`, `created`, `active`) | ||||
|                 VALUES (:username_new, :domain, :created, :active)"); | ||||
|               $stmt->execute(array( | ||||
|                 ':username_new' => $username_new, | ||||
|                 ':domain' => $domain, | ||||
|                 ':created' => date('Y-m-d H:i:s'), | ||||
|                 ':active' => $active | ||||
|               )); | ||||
|             } | ||||
|           } | ||||
|           if (!empty($password)) { | ||||
|             if (password_check($password, $password2) !== true) { | ||||
|               return false; | ||||
|             } | ||||
|             $password_hashed = hash_password($password); | ||||
|             $stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username_new, `active` = :active, `password` = :password_hashed WHERE `username` = :username"); | ||||
|             $stmt->execute(array( | ||||
|               ':password_hashed' => $password_hashed, | ||||
|               ':username_new' => $username_new, | ||||
|               ':username' => $username, | ||||
|               ':active' => $active | ||||
|             )); | ||||
|             if (isset($_data['disable_tfa'])) { | ||||
|               $stmt = $pdo->prepare("UPDATE `tfa` SET `active` = '0' WHERE `username` = :username"); | ||||
|               $stmt->execute(array(':username' => $username)); | ||||
|             } | ||||
|             else { | ||||
|               $stmt = $pdo->prepare("UPDATE `tfa` SET `username` = :username_new WHERE `username` = :username"); | ||||
|               $stmt->execute(array(':username_new' => $username_new, ':username' => $username)); | ||||
|             } | ||||
|           } | ||||
|           else { | ||||
|             $stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username_new, `active` = :active WHERE `username` = :username"); | ||||
|             $stmt->execute(array( | ||||
|               ':username_new' => $username_new, | ||||
|               ':username' => $username, | ||||
|               ':active' => $active | ||||
|             )); | ||||
|             if (isset($_data['disable_tfa'])) { | ||||
|               $stmt = $pdo->prepare("UPDATE `tfa` SET `active` = '0' WHERE `username` = :username"); | ||||
|               $stmt->execute(array(':username' => $username)); | ||||
|             } | ||||
|             else { | ||||
|               $stmt = $pdo->prepare("UPDATE `tfa` SET `username` = :username_new WHERE `username` = :username"); | ||||
|               $stmt->execute(array(':username_new' => $username_new, ':username' => $username)); | ||||
|             } | ||||
|           } | ||||
|           $_SESSION['return'][] = array( | ||||
|             'type' => 'success', | ||||
|             'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|             'msg' => array('domain_admin_modified', htmlspecialchars($username)) | ||||
|           ); | ||||
|         } | ||||
|         return true; | ||||
|       } | ||||
|       // Domain administrator | ||||
|       // Can only edit itself | ||||
|       elseif ($_SESSION['mailcow_cc_role'] == "domainadmin") { | ||||
|         $username = $_SESSION['mailcow_cc_username']; | ||||
|         $password_old		= $_data['user_old_pass']; | ||||
|         $password_new	= $_data['user_new_pass']; | ||||
|         $password_new2	= $_data['user_new_pass2']; | ||||
|  | ||||
|         $stmt = $pdo->prepare("SELECT `password` FROM `admin` | ||||
|             WHERE `username` = :user"); | ||||
|         $stmt->execute(array(':user' => $username)); | ||||
|         $row = $stmt->fetch(PDO::FETCH_ASSOC); | ||||
|         if (!verify_hash($row['password'], $password_old)) { | ||||
|           $_SESSION['return'][] = array( | ||||
|             'type' => 'danger', | ||||
|             'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|             'msg' => 'access_denied' | ||||
|           ); | ||||
|           return false; | ||||
|         } | ||||
|         if (password_check($password_new, $password_new2) !== true) { | ||||
|           return false; | ||||
|         } | ||||
|         $password_hashed = hash_password($password_new); | ||||
|         $stmt = $pdo->prepare("UPDATE `admin` SET `password` = :password_hashed WHERE `username` = :username"); | ||||
|         $stmt->execute(array( | ||||
|           ':password_hashed' => $password_hashed, | ||||
|           ':username' => $username | ||||
|         )); | ||||
|         $_SESSION['return'][] = array( | ||||
|           'type' => 'success', | ||||
|           'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|           'msg' => array('domain_admin_modified', htmlspecialchars($username)) | ||||
|         ); | ||||
|       } | ||||
|     break; | ||||
|     case 'delete': | ||||
|       if ($_SESSION['mailcow_cc_role'] != "admin") { | ||||
|         $_SESSION['return'][] = array( | ||||
|           'type' => 'danger', | ||||
|           'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|           'msg' => 'access_denied' | ||||
|         ); | ||||
|         return false; | ||||
|       } | ||||
|       $usernames = (array)$_data['username']; | ||||
|       foreach ($usernames as $username) { | ||||
|         if (empty(domain_admin('details', $username))) { | ||||
|           $_SESSION['return'][] = array( | ||||
|             'type' => 'danger', | ||||
|             'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|             'msg' => array('username_invalid', $username) | ||||
|           ); | ||||
|           continue; | ||||
|         } | ||||
|         $stmt = $pdo->prepare("DELETE FROM `domain_admins` WHERE `username` = :username"); | ||||
|         $stmt->execute(array( | ||||
|           ':username' => $username, | ||||
|         )); | ||||
|         $stmt = $pdo->prepare("DELETE FROM `admin` WHERE `username` = :username"); | ||||
|         $stmt->execute(array( | ||||
|           ':username' => $username, | ||||
|         )); | ||||
|         $stmt = $pdo->prepare("DELETE FROM `da_acl` WHERE `username` = :username"); | ||||
|         $stmt->execute(array( | ||||
|           ':username' => $username, | ||||
|         )); | ||||
|         $stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username"); | ||||
|         $stmt->execute(array( | ||||
|           ':username' => $username, | ||||
|         )); | ||||
|         $stmt = $pdo->prepare("DELETE FROM `fido2` WHERE `username` = :username"); | ||||
|         $stmt->execute(array( | ||||
|           ':username' => $username, | ||||
|         )); | ||||
|         $_SESSION['return'][] = array( | ||||
|           'type' => 'success', | ||||
|           'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|           'msg' => array('domain_admin_removed', htmlspecialchars($username)) | ||||
|         ); | ||||
|       } | ||||
|     break; | ||||
|     case 'get': | ||||
|       $domainadmins = array(); | ||||
|       if ($_SESSION['mailcow_cc_role'] != "admin") { | ||||
|         $_SESSION['return'][] = array( | ||||
|           'type' => 'danger', | ||||
|           'log' => array(__FUNCTION__, $_action, $_data_log), | ||||
|           'msg' => 'access_denied' | ||||
|         ); | ||||
|         return false; | ||||
|       } | ||||
|       $stmt = $pdo->query("SELECT DISTINCT | ||||
|         `username` | ||||
|           FROM `domain_admins` | ||||
|             WHERE `username` IN ( | ||||
|               SELECT `username` FROM `admin` | ||||
|                 WHERE `superadmin`!='1' | ||||
|             )"); | ||||
|       $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); | ||||
|       while ($row = array_shift($rows)) { | ||||
|         $domainadmins[] = $row['username']; | ||||
|       } | ||||
|       return $domainadmins; | ||||
|     break; | ||||
|     case 'details': | ||||
|       $domainadmindata = array(); | ||||
|       if ($_SESSION['mailcow_cc_role'] == "domainadmin" && $_data != $_SESSION['mailcow_cc_username']) { | ||||
|         return false; | ||||
|       } | ||||
|       elseif ($_SESSION['mailcow_cc_role'] != "admin" || !isset($_data)) { | ||||
|         return false; | ||||
|       } | ||||
|       if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $_data))) { | ||||
|         return false; | ||||
|       } | ||||
|       $stmt = $pdo->prepare("SELECT | ||||
|         `tfa`.`active` AS `tfa_active`, | ||||
|         `domain_admins`.`username`, | ||||
|         `domain_admins`.`created`, | ||||
|         `domain_admins`.`active` AS `active` | ||||
|           FROM `domain_admins` | ||||
|           LEFT OUTER JOIN `tfa` ON `tfa`.`username`=`domain_admins`.`username` | ||||
|             WHERE `domain_admins`.`username`= :domain_admin"); | ||||
|       $stmt->execute(array( | ||||
|         ':domain_admin' => $_data | ||||
|       )); | ||||
|       $row = $stmt->fetch(PDO::FETCH_ASSOC); | ||||
|       if (empty($row)) { | ||||
|         return false; | ||||
|       } | ||||
|       $domainadmindata['username'] = $row['username']; | ||||
|       $domainadmindata['tfa_active'] = (is_null($row['tfa_active'])) ? 0 : $row['tfa_active']; | ||||
|       $domainadmindata['tfa_active_int'] = (is_null($row['tfa_active'])) ? 0 : $row['tfa_active']; | ||||
|       $domainadmindata['active'] = $row['active']; | ||||
|       $domainadmindata['active_int'] = $row['active']; | ||||
|       $domainadmindata['created'] = $row['created']; | ||||
|       // GET SELECTED | ||||
|       $stmt = $pdo->prepare("SELECT `domain` FROM `domain` | ||||
|         WHERE `domain` IN ( | ||||
|           SELECT `domain` FROM `domain_admins` | ||||
|             WHERE `username`= :domain_admin)"); | ||||
|       $stmt->execute(array(':domain_admin' => $_data)); | ||||
|       $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); | ||||
|       while($row = array_shift($rows)) { | ||||
|         $domainadmindata['selected_domains'][] = $row['domain']; | ||||
|       } | ||||
|       // GET UNSELECTED | ||||
|       $stmt = $pdo->prepare("SELECT `domain` FROM `domain` | ||||
|         WHERE `domain` NOT IN ( | ||||
|           SELECT `domain` FROM `domain_admins` | ||||
|             WHERE `username`= :domain_admin)"); | ||||
|       $stmt->execute(array(':domain_admin' => $_data)); | ||||
|       $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); | ||||
|       while($row = array_shift($rows)) { | ||||
|         $domainadmindata['unselected_domains'][] = $row['domain']; | ||||
|       } | ||||
|       if (!isset($domainadmindata['unselected_domains'])) { | ||||
|         $domainadmindata['unselected_domains'] = ""; | ||||
|       } | ||||
|  | ||||
|       return $domainadmindata; | ||||
|     break; | ||||
|   } | ||||
| } | ||||
| function domain_admin_sso($_action, $_data) { | ||||
|   global $pdo; | ||||
|  | ||||
|   switch ($_action) { | ||||
|     case 'check': | ||||
|       $token = $_data; | ||||
|  | ||||
|       $stmt = $pdo->prepare("SELECT `t1`.`username` FROM `da_sso` AS `t1` JOIN `admin` AS `t2` ON `t1`.`username` = `t2`.`username` WHERE `t1`.`token` = :token AND `t1`.`created` > DATE_SUB(NOW(), INTERVAL '30' SECOND) AND `t2`.`active` = 1 AND `t2`.`superadmin` = 0;"); | ||||
|       $stmt->execute(array( | ||||
|         ':token' => preg_replace('/[^a-zA-Z0-9-]/', '', $token) | ||||
|       )); | ||||
|       $return = $stmt->fetch(PDO::FETCH_ASSOC); | ||||
|       return empty($return['username']) ? false : $return['username']; | ||||
|     case 'issue': | ||||
|       if ($_SESSION['mailcow_cc_role'] != "admin") { | ||||
|         $_SESSION['return'][] = array( | ||||
|           'type' => 'danger', | ||||
|           'log' => array(__FUNCTION__, $_action, $_data), | ||||
|           'msg' => 'access_denied' | ||||
|         ); | ||||
|         return false; | ||||
|       } | ||||
|  | ||||
|       $username = $_data['username']; | ||||
|  | ||||
|       $stmt = $pdo->prepare("SELECT `username` FROM `domain_admins` | ||||
|         WHERE `username` = :username"); | ||||
|       $stmt->execute(array(':username' => $username)); | ||||
|       $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC)); | ||||
|  | ||||
|       if ($num_results < 1) { | ||||
|         $_SESSION['return'][] = array( | ||||
|           'type' => 'danger', | ||||
|           'log' => array(__FUNCTION__, $_action, $_data), | ||||
|           'msg' => array('object_doesnt_exist', htmlspecialchars($username)) | ||||
|         ); | ||||
|         return false; | ||||
|       } | ||||
|  | ||||
|       $token = implode('-', array( | ||||
|         strtoupper(bin2hex(random_bytes(3))), | ||||
|         strtoupper(bin2hex(random_bytes(3))), | ||||
|         strtoupper(bin2hex(random_bytes(3))), | ||||
|         strtoupper(bin2hex(random_bytes(3))), | ||||
|         strtoupper(bin2hex(random_bytes(3))) | ||||
|       )); | ||||
|  | ||||
|       $stmt = $pdo->prepare("INSERT INTO `da_sso` (`username`, `token`) | ||||
|             VALUES (:username, :token)"); | ||||
|       $stmt->execute(array( | ||||
|         ':username' => $username, | ||||
|         ':token' => $token | ||||
|       )); | ||||
|  | ||||
|       // perform cleanup | ||||
|       $pdo->query("DELETE FROM `da_sso` WHERE created < DATE_SUB(NOW(), INTERVAL '30' SECOND);"); | ||||
|  | ||||
|       return ['token' => $token]; | ||||
|     break; | ||||
|   } | ||||
| } | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,140 +1,140 @@ | ||||
| <?php | ||||
| // Start session | ||||
| if (session_status() !== PHP_SESSION_ACTIVE) { | ||||
|   ini_set("session.cookie_httponly", 1); | ||||
|   ini_set('session.gc_maxlifetime', $SESSION_LIFETIME); | ||||
| } | ||||
|  | ||||
| if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&  | ||||
|   strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == "https") { | ||||
|   if (session_status() !== PHP_SESSION_ACTIVE) { | ||||
|     ini_set("session.cookie_secure", 1); | ||||
|   } | ||||
|   $IS_HTTPS = true; | ||||
| } | ||||
| elseif (isset($_SERVER['HTTPS'])) { | ||||
|   if (session_status() !== PHP_SESSION_ACTIVE) { | ||||
|     ini_set("session.cookie_secure", 1); | ||||
|   } | ||||
|   $IS_HTTPS = true; | ||||
| } | ||||
| else { | ||||
|   $IS_HTTPS = false; | ||||
| } | ||||
|  | ||||
| if (session_status() !== PHP_SESSION_ACTIVE) { | ||||
|   session_start(); | ||||
| } | ||||
|  | ||||
| if (!isset($_SESSION['CSRF']['TOKEN'])) { | ||||
|   $_SESSION['CSRF']['TOKEN'] = bin2hex(random_bytes(32)); | ||||
| } | ||||
|  | ||||
| // Set session UA | ||||
| if (!isset($_SESSION['SESS_REMOTE_UA'])) { | ||||
|   $_SESSION['SESS_REMOTE_UA'] = $_SERVER['HTTP_USER_AGENT']; | ||||
| } | ||||
|  | ||||
| // Keep session active | ||||
| if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > $SESSION_LIFETIME)) { | ||||
|   session_unset(); | ||||
|   session_destroy(); | ||||
| } | ||||
| $_SESSION['LAST_ACTIVITY'] = time(); | ||||
|  | ||||
| // API | ||||
| if (!empty($_SERVER['HTTP_X_API_KEY'])) { | ||||
|   $stmt = $pdo->prepare("SELECT * FROM `api` WHERE `api_key` = :api_key AND `active` = '1';"); | ||||
|   $stmt->execute(array( | ||||
|     ':api_key' => preg_replace('/[^a-zA-Z0-9-]/', '', $_SERVER['HTTP_X_API_KEY']) | ||||
|   )); | ||||
|   $api_return = $stmt->fetch(PDO::FETCH_ASSOC); | ||||
|   if (!empty($api_return['api_key'])) { | ||||
|     $skip_ip_check = ($api_return['skip_ip_check'] == 1); | ||||
|     $remote = get_remote_ip(false); | ||||
|     $allow_from = array_map('trim', preg_split( "/( |,|;|\n)/", $api_return['allow_from'])); | ||||
|     if ($skip_ip_check === true || ip_acl($remote, $allow_from)) { | ||||
|       $_SESSION['mailcow_cc_username'] = 'API'; | ||||
|       $_SESSION['mailcow_cc_role'] = 'admin'; | ||||
|       $_SESSION['mailcow_cc_api'] = true; | ||||
|       if ($api_return['access'] == 'rw') { | ||||
|         $_SESSION['mailcow_cc_api_access'] = 'rw'; | ||||
|       } | ||||
|       else { | ||||
|         $_SESSION['mailcow_cc_api_access'] = 'ro'; | ||||
|       } | ||||
|     } | ||||
|     else { | ||||
|       $redis->publish("F2B_CHANNEL", "mailcow UI: Invalid password for API_USER by " . $_SERVER['REMOTE_ADDR']); | ||||
|       error_log("mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']); | ||||
|       http_response_code(401); | ||||
|       echo json_encode(array( | ||||
|         'type' => 'error', | ||||
|         'msg' => 'api access denied for ip ' . $_SERVER['REMOTE_ADDR'] | ||||
|       )); | ||||
|       unset($_POST); | ||||
|       exit(); | ||||
|     } | ||||
|   } | ||||
|   else { | ||||
|     $redis->publish("F2B_CHANNEL", "mailcow UI: Invalid password for API_USER by " . $_SERVER['REMOTE_ADDR']); | ||||
|     error_log("mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']); | ||||
|     http_response_code(401); | ||||
|     echo json_encode(array( | ||||
|       'type' => 'error', | ||||
|       'msg' => 'authentication failed' | ||||
|     )); | ||||
|     unset($_POST); | ||||
|     exit(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| // Handle logouts | ||||
| if (isset($_POST["logout"])) { | ||||
|   if (isset($_SESSION["dual-login"])) { | ||||
|     $_SESSION["mailcow_cc_username"] = $_SESSION["dual-login"]["username"]; | ||||
|     $_SESSION["mailcow_cc_role"] = $_SESSION["dual-login"]["role"]; | ||||
|     unset($_SESSION["dual-login"]); | ||||
|     header("Location: /mailbox"); | ||||
|     exit(); | ||||
|   } | ||||
|   else { | ||||
|     session_regenerate_id(true); | ||||
|     session_unset(); | ||||
|     session_destroy(); | ||||
|     session_write_close(); | ||||
|     header("Location: /"); | ||||
|   } | ||||
| } | ||||
|  | ||||
| // Check session | ||||
| function session_check() { | ||||
|   if (isset($_SESSION['mailcow_cc_api']) && $_SESSION['mailcow_cc_api'] === true) { | ||||
|     return true; | ||||
|   } | ||||
|   if (!isset($_SESSION['SESS_REMOTE_UA']) || ($_SESSION['SESS_REMOTE_UA'] != $_SERVER['HTTP_USER_AGENT'])) { | ||||
|     $_SESSION['return'][] = array( | ||||
|       'type' => 'warning', | ||||
|       'msg' => 'session_ua' | ||||
|     ); | ||||
|     return false; | ||||
|   } | ||||
|   if (!empty($_POST)) { | ||||
|     if ($_SESSION['CSRF']['TOKEN'] != $_POST['csrf_token']) { | ||||
|       $_SESSION['return'][] = array( | ||||
|         'type' => 'warning', | ||||
|         'msg' => 'session_token' | ||||
|       ); | ||||
|       return false; | ||||
|     } | ||||
|     unset($_POST['csrf_token']); | ||||
|     $_SESSION['CSRF']['TOKEN'] = bin2hex(random_bytes(32)); | ||||
|     $_SESSION['CSRF']['TIME'] = time(); | ||||
|   } | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| if (isset($_SESSION['mailcow_cc_role']) && session_check() === false) { | ||||
|   $_POST = array(); | ||||
|   $_FILES = array(); | ||||
| } | ||||
| <?php | ||||
| // Start session | ||||
| if (session_status() !== PHP_SESSION_ACTIVE) { | ||||
|   ini_set("session.cookie_httponly", 1); | ||||
|   ini_set('session.gc_maxlifetime', $SESSION_LIFETIME); | ||||
| } | ||||
|  | ||||
| if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && | ||||
|   strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == "https") { | ||||
|   if (session_status() !== PHP_SESSION_ACTIVE) { | ||||
|     ini_set("session.cookie_secure", 1); | ||||
|   } | ||||
|   $IS_HTTPS = true; | ||||
| } | ||||
| elseif (isset($_SERVER['HTTPS'])) { | ||||
|   if (session_status() !== PHP_SESSION_ACTIVE) { | ||||
|     ini_set("session.cookie_secure", 1); | ||||
|   } | ||||
|   $IS_HTTPS = true; | ||||
| } | ||||
| else { | ||||
|   $IS_HTTPS = false; | ||||
| } | ||||
|  | ||||
| if (session_status() !== PHP_SESSION_ACTIVE) { | ||||
|   session_start(); | ||||
| } | ||||
|  | ||||
| if (!isset($_SESSION['CSRF']['TOKEN'])) { | ||||
|   $_SESSION['CSRF']['TOKEN'] = bin2hex(random_bytes(32)); | ||||
| } | ||||
|  | ||||
| // Set session UA | ||||
| if (!isset($_SESSION['SESS_REMOTE_UA'])) { | ||||
|   $_SESSION['SESS_REMOTE_UA'] = $_SERVER['HTTP_USER_AGENT']; | ||||
| } | ||||
|  | ||||
| // Keep session active | ||||
| if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > $SESSION_LIFETIME)) { | ||||
|   session_unset(); | ||||
|   session_destroy(); | ||||
| } | ||||
| $_SESSION['LAST_ACTIVITY'] = time(); | ||||
|  | ||||
| // API | ||||
| if (!empty($_SERVER['HTTP_X_API_KEY'])) { | ||||
|   $stmt = $pdo->prepare("SELECT * FROM `api` WHERE `api_key` = :api_key AND `active` = '1';"); | ||||
|   $stmt->execute(array( | ||||
|     ':api_key' => preg_replace('/[^a-zA-Z0-9-]/', '', $_SERVER['HTTP_X_API_KEY']) | ||||
|   )); | ||||
|   $api_return = $stmt->fetch(PDO::FETCH_ASSOC); | ||||
|   if (!empty($api_return['api_key'])) { | ||||
|     $skip_ip_check = ($api_return['skip_ip_check'] == 1); | ||||
|     $remote = get_remote_ip(false); | ||||
|     $allow_from = array_map('trim', preg_split( "/( |,|;|\n)/", $api_return['allow_from'])); | ||||
|     if ($skip_ip_check === true || ip_acl($remote, $allow_from)) { | ||||
|       $_SESSION['mailcow_cc_username'] = 'API'; | ||||
|       $_SESSION['mailcow_cc_role'] = 'admin'; | ||||
|       $_SESSION['mailcow_cc_api'] = true; | ||||
|       if ($api_return['access'] == 'rw') { | ||||
|         $_SESSION['mailcow_cc_api_access'] = 'rw'; | ||||
|       } | ||||
|       else { | ||||
|         $_SESSION['mailcow_cc_api_access'] = 'ro'; | ||||
|       } | ||||
|     } | ||||
|     else { | ||||
|       $redis->publish("F2B_CHANNEL", "mailcow UI: Invalid password for API_USER by " . $_SERVER['REMOTE_ADDR']); | ||||
|       error_log("mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']); | ||||
|       http_response_code(401); | ||||
|       echo json_encode(array( | ||||
|         'type' => 'error', | ||||
|         'msg' => 'api access denied for ip ' . $_SERVER['REMOTE_ADDR'] | ||||
|       )); | ||||
|       unset($_POST); | ||||
|       exit(); | ||||
|     } | ||||
|   } | ||||
|   else { | ||||
|     $redis->publish("F2B_CHANNEL", "mailcow UI: Invalid password for API_USER by " . $_SERVER['REMOTE_ADDR']); | ||||
|     error_log("mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']); | ||||
|     http_response_code(401); | ||||
|     echo json_encode(array( | ||||
|       'type' => 'error', | ||||
|       'msg' => 'authentication failed' | ||||
|     )); | ||||
|     unset($_POST); | ||||
|     exit(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| // Handle logouts | ||||
| if (isset($_POST["logout"])) { | ||||
|   if (isset($_SESSION["dual-login"])) { | ||||
|     $_SESSION["mailcow_cc_username"] = $_SESSION["dual-login"]["username"]; | ||||
|     $_SESSION["mailcow_cc_role"] = $_SESSION["dual-login"]["role"]; | ||||
|     unset($_SESSION["dual-login"]); | ||||
|     header("Location: /mailbox"); | ||||
|     exit(); | ||||
|   } | ||||
|   else { | ||||
|     session_regenerate_id(true); | ||||
|     session_unset(); | ||||
|     session_destroy(); | ||||
|     session_write_close(); | ||||
|     header("Location: /"); | ||||
|   } | ||||
| } | ||||
|  | ||||
| // Check session | ||||
| function session_check() { | ||||
|   if (isset($_SESSION['mailcow_cc_api']) && $_SESSION['mailcow_cc_api'] === true) { | ||||
|     return true; | ||||
|   } | ||||
|   if (!isset($_SESSION['SESS_REMOTE_UA']) || ($_SESSION['SESS_REMOTE_UA'] != $_SERVER['HTTP_USER_AGENT'])) { | ||||
|     $_SESSION['return'][] = array( | ||||
|       'type' => 'warning', | ||||
|       'msg' => 'session_ua' | ||||
|     ); | ||||
|     return false; | ||||
|   } | ||||
|   if (!empty($_POST)) { | ||||
|     if ($_SESSION['CSRF']['TOKEN'] != $_POST['csrf_token']) { | ||||
|       $_SESSION['return'][] = array( | ||||
|         'type' => 'warning', | ||||
|         'msg' => 'session_token' | ||||
|       ); | ||||
|       return false; | ||||
|     } | ||||
|     unset($_POST['csrf_token']); | ||||
|     $_SESSION['CSRF']['TOKEN'] = bin2hex(random_bytes(32)); | ||||
|     $_SESSION['CSRF']['TIME'] = time(); | ||||
|   } | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| if (isset($_SESSION['mailcow_cc_role']) && session_check() === false) { | ||||
|   $_POST = array(); | ||||
|   $_FILES = array(); | ||||
| } | ||||
|   | ||||
| @@ -1,4 +1,15 @@ | ||||
| <?php | ||||
| // SSO Domain Admin | ||||
| if (!empty($_GET['sso_token'])) { | ||||
|   $username = domain_admin_sso('check', $_GET['sso_token']); | ||||
|  | ||||
|   if ($username !== false) { | ||||
|     $_SESSION['mailcow_cc_username'] = $username; | ||||
|     $_SESSION['mailcow_cc_role'] = 'domainadmin'; | ||||
|     header('Location: /mailbox'); | ||||
|   } | ||||
| } | ||||
|  | ||||
| if (isset($_POST["verify_tfa_login"])) { | ||||
|   if (verify_tfa_login($_SESSION['pending_mailcow_cc_username'], $_POST)) { | ||||
|     $_SESSION['mailcow_cc_username'] = $_SESSION['pending_mailcow_cc_username']; | ||||
| @@ -6,7 +17,7 @@ if (isset($_POST["verify_tfa_login"])) { | ||||
|     unset($_SESSION['pending_mailcow_cc_username']); | ||||
|     unset($_SESSION['pending_mailcow_cc_role']); | ||||
|     unset($_SESSION['pending_tfa_methods']); | ||||
| 	 | ||||
|  | ||||
|     header("Location: /user"); | ||||
|   } else { | ||||
|     unset($_SESSION['pending_mailcow_cc_username']); | ||||
| @@ -34,7 +45,7 @@ if (isset($_POST["quick_delete"])) { | ||||
| if (isset($_POST["login_user"]) && isset($_POST["pass_user"])) { | ||||
| 	$login_user = strtolower(trim($_POST["login_user"])); | ||||
| 	$as = check_login($login_user, $_POST["pass_user"]); | ||||
|    | ||||
|  | ||||
| 	if ($as == "admin") { | ||||
| 		$_SESSION['mailcow_cc_username'] = $login_user; | ||||
| 		$_SESSION['mailcow_cc_role'] = "admin"; | ||||
|   | ||||
| @@ -288,6 +288,18 @@ if (isset($_GET['query'])) { | ||||
|         case "domain-admin": | ||||
|           process_add_return(domain_admin('add', $attr)); | ||||
|         break; | ||||
|         case "sso": | ||||
|           switch ($object) { | ||||
|             case "domain-admin": | ||||
|               $data = domain_admin_sso('issue', $attr); | ||||
|               if($data) { | ||||
|                 echo json_encode($data); | ||||
|                 exit(0); | ||||
|               } | ||||
|               process_add_return($data); | ||||
|             break; | ||||
|           } | ||||
|         break; | ||||
|         case "admin": | ||||
|           process_add_return(admin('add', $attr)); | ||||
|         break; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user