git subrepo commit (merge) mailcow/src/mailcow-dockerized

subrepo: subdir:   "mailcow/src/mailcow-dockerized"
  merged:   "02ae5285"
upstream: origin:   "https://github.com/mailcow/mailcow-dockerized.git"
  branch:   "master"
  commit:   "649a5c01"
git-subrepo: version:  "0.4.3"
  origin:   "???"
  commit:   "???"
Change-Id: I870ad468fba026cc5abf3c5699ed1e12ff28b32b
diff --git a/mailcow/src/mailcow-dockerized/data/web/json_api.php b/mailcow/src/mailcow-dockerized/data/web/json_api.php
index 46d6e35..cdefb83 100644
--- a/mailcow/src/mailcow-dockerized/data/web/json_api.php
+++ b/mailcow/src/mailcow-dockerized/data/web/json_api.php
@@ -141,7 +141,7 @@
         // fido2-registration via POST

         case "fido2-registration":

           header('Content-Type: application/json');

-          if (isset($_SESSION["mailcow_cc_role"]) && ($_SESSION["mailcow_cc_role"] == "admin" || $_SESSION["mailcow_cc_role"] == "domainadmin")) {

+          if (isset($_SESSION["mailcow_cc_role"])) {

             $post = trim(file_get_contents('php://input'));

             if ($post) {

               $post = json_decode($post);

@@ -302,11 +302,23 @@
           if ($obj_props['superadmin'] === 1) {

             $_SESSION["mailcow_cc_role"] = "admin";

           }

-          else {

+          elseif ($obj_props['superadmin'] === 0) {

             $_SESSION["mailcow_cc_role"] = "domainadmin";

           }

+          else {

+            $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :username");

+            $stmt->execute(array(':username' => $process_fido2['username']));

+            $row = $stmt->fetch(PDO::FETCH_ASSOC);

+            if ($row['username'] == $process_fido2['username']) {

+              $_SESSION["mailcow_cc_role"] = "user";

+            }

+          }

+          if (empty($_SESSION["mailcow_cc_role"])) {

+            session_unset();

+            session_destroy();

+            exit;

+          }

           $_SESSION["mailcow_cc_username"] = $process_fido2['username'];

-          $_SESSION['mailcow_cc_last_login'] = last_login($process_fido2['username']);

           $_SESSION["fido2_cid"] = $process_fido2['cid'];

           unset($_SESSION["challenge"]);

           $_SESSION['return'][] =  array(

@@ -319,8 +331,14 @@
       }

     break;

     case "get":

-      function process_get_return($data) {

-        echo (!isset($data) || empty($data)) ? '{}' : json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);

+      function process_get_return($data, $object = true) {

+        if ($object === true) {

+          $ret_str = '{}';

+        }

+        else {

+          $ret_str = '[]';

+        }

+        echo (!isset($data) || empty($data)) ? $ret_str : json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);

       }

       // only allow GET requests to GET API endpoints

       if ($_SERVER['REQUEST_METHOD'] != 'GET') {

@@ -334,17 +352,15 @@
       switch ($category) {

         case "u2f-registration":

           header('Content-Type: application/javascript');

-          if (isset($_SESSION["mailcow_cc_role"]) &&

-            ($_SESSION["mailcow_cc_role"] == "admin" || $_SESSION["mailcow_cc_role"] == "domainadmin") &&

-            $_SESSION["mailcow_cc_username"] == $object) {

-              list($req, $sigs) = $u2f->getRegisterData(get_u2f_registrations($object));

-              $_SESSION['regReq'] = json_encode($req);

-              $_SESSION['regSigs'] = json_encode($sigs);

-              echo 'var req = ' . json_encode($req) . ';';

-              echo 'var registeredKeys = ' . json_encode($sigs) . ';';

-              echo 'var appId = req.appId;';

-              echo 'var registerRequests = [{version: req.version, challenge: req.challenge}];';

-              return;

+          if (isset($_SESSION["mailcow_cc_role"]) && $_SESSION["mailcow_cc_username"] == $object) {

+            list($req, $sigs) = $u2f->getRegisterData(get_u2f_registrations($object));

+            $_SESSION['regReq'] = json_encode($req);

+            $_SESSION['regSigs'] = json_encode($sigs);

+            echo 'var req = ' . json_encode($req) . ';';

+            echo 'var registeredKeys = ' . json_encode($sigs) . ';';

+            echo 'var appId = req.appId;';

+            echo 'var registerRequests = [{version: req.version, challenge: req.challenge}];';

+            return;

           }

           else {

             return;

@@ -353,9 +369,7 @@
         // fido2-registration via GET

         case "fido2-registration":

           header('Content-Type: application/json');

-          if (isset($_SESSION["mailcow_cc_role"]) &&

-            ($_SESSION["mailcow_cc_role"] == "admin" || $_SESSION["mailcow_cc_role"] == "domainadmin") &&

-            $_SESSION["mailcow_cc_username"] == $object) {

+          if (isset($_SESSION["mailcow_cc_role"])) {

               // Exclude existing CredentialIds, if any

               $excludeCredentialIds = fido2(array("action" => "get_user_cids"));

               $createArgs = $WebAuthn->getCreateArgs($_SESSION["mailcow_cc_username"], $_SESSION["mailcow_cc_username"], $_SESSION["mailcow_cc_username"], 30, true, $GLOBALS['FIDO2_UV_FLAG_REGISTER'], $excludeCredentialIds);

@@ -446,6 +460,20 @@
             }

           break;

 

+          case "passwordpolicy":

+            switch ($object) {

+              case "html":

+                $password_complexity_rules = password_complexity('html');

+                if ($password_complexity_rules !== false) {

+                  process_get_return($password_complexity_rules);

+                }

+                else {

+                  echo '{}';

+                }

+              break;

+            }

+          break;

+

           case "app-passwd":

             switch ($object) {

               case "all":

@@ -620,6 +648,27 @@
             }

           break;

 

+          case "last-login":

+            if ($object) {

+              // extra == days

+              if (isset($extra) && intval($extra) >= 1) {

+                $data = last_login('get', $object, intval($extra));

+              }

+              else {

+                $data = last_login('get', $object);

+              }

+              process_get_return($data);

+            }

+          break;

+

+          // Todo: move to delete

+          case "reset-last-login":

+            if ($object) {

+              $data = last_login('reset', $object);

+              process_get_return($data);

+            }

+          break;

+

           case "transport":

             switch ($object) {

               case "all":

@@ -780,6 +829,17 @@
                 }

                 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';

               break;

+              case "sasl":

+                // 0 is first record, so empty is fine

+                if (isset($extra)) {

+                  $extra = preg_replace('/[^\d\-]/i', '', $extra);

+                  $logs = get_logs('sasl', $extra);

+                }

+                else {

+                  $logs = get_logs('sasl');

+                }

+                echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';

+              break;

               case "watchdog":

                 // 0 is first record, so empty is fine

                 if (isset($extra)) {

@@ -841,18 +901,19 @@
           case "mailbox":

             switch ($object) {

               case "all":

+              case "reduced":

                 if (empty($extra)) {

                   $domains = mailbox('get', 'domains');

                 }

                 else {

-                  $domains = array($extra);

+                  $domains = explode(',', $extra);

                 }

                 if (!empty($domains)) {

                   foreach ($domains as $domain) {

                     $mailboxes = mailbox('get', 'mailboxes', $domain);

                     if (!empty($mailboxes)) {

                       foreach ($mailboxes as $mailbox) {

-                        if ($details = mailbox('get', 'mailbox_details', $mailbox)) {

+                        if ($details = mailbox('get', 'mailbox_details', $mailbox, $object)) {

                           $data[] = $details;

                         }

                         else {

@@ -1154,10 +1215,10 @@
             // "all" will not print details

             switch ($object) {

               case "all":

-                process_get_return(quarantine('get'));

+                process_get_return(quarantine('get'), false);

               break;

               default:

-                process_get_return(quarantine('details', $object));

+                process_get_return(quarantine('details', $object), false);

               break;

             }

           break;

@@ -1189,7 +1250,7 @@
                   $domains = array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains'));

                 }

                 else {

-                  $domains = array($extra);

+                  $domains = explode(',', $extra);

                 }

                 if (!empty($domains)) {

                   foreach ($domains as $domain) {

@@ -1437,7 +1498,6 @@
           process_delete_return(dkim('delete', array('domains' => $items)));

         break;

         case "domain":

-          file_put_contents('/tmp/dssaa', $items);

           process_delete_return(mailbox('delete', 'domain', array('domain' => $items)));

         break;

         case "alias-domain":

@@ -1560,6 +1620,9 @@
         case "app_links":

           process_edit_return(customize('edit', 'app_links', $attr));

         break;

+        case "passwordpolicy":

+          process_edit_return(password_complexity('edit', $attr));

+        break;

         case "relayhost":

           process_edit_return(relayhost('edit', array_merge(array('id' => $items), $attr)));

         break;

@@ -1590,6 +1653,9 @@
         case "quota_notification":

           process_edit_return(quota_notification('edit', $attr));

         break;

+        case "quota_notification_bcc":

+          process_edit_return(quota_notification_bcc('edit', $attr));

+        break;

         case "mailq":

           process_edit_return(mailq('edit', array_merge(array('qid' => $items), $attr)));

         break;