functions.inc.php 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184
  1. <?php
  2. function hash_password($password) {
  3. $salt_str = bin2hex(openssl_random_pseudo_bytes(8));
  4. return "{SSHA256}".base64_encode(hash('sha256', $password . $salt_str, true) . $salt_str);
  5. }
  6. function hasDomainAccess($username, $role, $domain) {
  7. global $pdo;
  8. if (!filter_var($username, FILTER_VALIDATE_EMAIL) && !ctype_alnum(str_replace(array('_', '.', '-'), '', $username))) {
  9. return false;
  10. }
  11. if (empty($domain) || !is_valid_domain_name($domain)) {
  12. return false;
  13. }
  14. if ($role != 'admin' && $role != 'domainadmin' && $role != 'user') {
  15. return false;
  16. }
  17. try {
  18. $stmt = $pdo->prepare("SELECT `domain` FROM `domain_admins`
  19. WHERE (
  20. `active`='1'
  21. AND `username` = :username
  22. AND (`domain` = :domain1 OR `domain` = (SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain2))
  23. )
  24. OR 'admin' = :role");
  25. $stmt->execute(array(':username' => $username, ':domain1' => $domain, ':domain2' => $domain, ':role' => $role));
  26. $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
  27. }
  28. catch(PDOException $e) {
  29. $_SESSION['return'] = array(
  30. 'type' => 'danger',
  31. 'msg' => 'MySQL: '.$e
  32. );
  33. return false;
  34. }
  35. if (!empty($num_results)) {
  36. return true;
  37. }
  38. return false;
  39. }
  40. function hasMailboxObjectAccess($username, $role, $object) {
  41. global $pdo;
  42. if (!filter_var(html_entity_decode(rawurldecode($username)), FILTER_VALIDATE_EMAIL) && !ctype_alnum(str_replace(array('_', '.', '-'), '', $username))) {
  43. return false;
  44. }
  45. if ($role != 'admin' && $role != 'domainadmin' && $role != 'user') {
  46. return false;
  47. }
  48. if ($username == $object) {
  49. return true;
  50. }
  51. try {
  52. $stmt = $pdo->prepare("SELECT `domain` FROM `mailbox` WHERE `username` = :object");
  53. $stmt->execute(array(':object' => $object));
  54. $row = $stmt->fetch(PDO::FETCH_ASSOC);
  55. if (isset($row['domain']) && hasDomainAccess($username, $role, $row['domain'])) {
  56. return true;
  57. }
  58. }
  59. catch(PDOException $e) {
  60. error_log($e);
  61. return false;
  62. }
  63. return false;
  64. }
  65. function pem_to_der($pem_key) {
  66. // Need to remove BEGIN/END PUBLIC KEY
  67. $lines = explode("\n", trim($pem_key));
  68. unset($lines[count($lines)-1]);
  69. unset($lines[0]);
  70. return base64_decode(implode('', $lines));
  71. }
  72. function generate_tlsa_digest($hostname, $port, $starttls = null) {
  73. if (!is_valid_domain_name($hostname)) {
  74. return "Not a valid hostname";
  75. }
  76. if (empty($starttls)) {
  77. $context = stream_context_create(array("ssl" => array("capture_peer_cert" => true, 'verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => true)));
  78. $stream = stream_socket_client('ssl://' . $hostname . ':' . $port, $error_nr, $error_msg, 5, STREAM_CLIENT_CONNECT, $context);
  79. if (!$stream) {
  80. $error_msg = isset($error_msg) ? $error_msg : '-';
  81. return $error_nr . ': ' . $error_msg;
  82. }
  83. }
  84. else {
  85. $stream = stream_socket_client('tcp://' . $hostname . ':' . $port, $error_nr, $error_msg, 5);
  86. if (!$stream) {
  87. return $error_nr . ': ' . $error_msg;
  88. }
  89. $banner = fread($stream, 512 );
  90. if (preg_match("/^220/i", $banner)) { // SMTP
  91. fwrite($stream,"HELO tlsa.generator.local\r\n");
  92. fread($stream, 512);
  93. fwrite($stream,"STARTTLS\r\n");
  94. fread($stream, 512);
  95. }
  96. elseif (preg_match("/imap.+starttls/i", $banner)) { // IMAP
  97. fwrite($stream,"A1 STARTTLS\r\n");
  98. fread($stream, 512);
  99. }
  100. elseif (preg_match("/^\+OK/", $banner)) { // POP3
  101. fwrite($stream,"STLS\r\n");
  102. fread($stream, 512);
  103. }
  104. elseif (preg_match("/^OK/m", $banner)) { // Sieve
  105. fwrite($stream,"STARTTLS\r\n");
  106. fread($stream, 512);
  107. }
  108. else {
  109. return 'Unknown banner: "' . htmlspecialchars(trim($banner)) . '"';
  110. }
  111. // Upgrade connection
  112. stream_set_blocking($stream, true);
  113. stream_context_set_option($stream, 'ssl', 'capture_peer_cert', true);
  114. stream_context_set_option($stream, 'ssl', 'verify_peer', false);
  115. stream_context_set_option($stream, 'ssl', 'verify_peer_name', false);
  116. stream_context_set_option($stream, 'ssl', 'allow_self_signed', true);
  117. stream_socket_enable_crypto($stream, true, STREAM_CRYPTO_METHOD_ANY_CLIENT);
  118. stream_set_blocking($stream, false);
  119. }
  120. $params = stream_context_get_params($stream);
  121. if (!empty($params['options']['ssl']['peer_certificate'])) {
  122. $key_resource = openssl_pkey_get_public($params['options']['ssl']['peer_certificate']);
  123. // We cannot get ['rsa']['n'], the binary data would contain BEGIN/END PUBLIC KEY
  124. $key_data = openssl_pkey_get_details($key_resource)['key'];
  125. return '3 1 1 ' . openssl_digest(pem_to_der($key_data), 'sha256');
  126. }
  127. else {
  128. return 'Error: Cannot read peer certificate';
  129. }
  130. }
  131. function verify_ssha256($hash, $password) {
  132. // Remove tag if any
  133. $hash = preg_replace('/^{SSHA256}/i', '', $hash);
  134. // Decode hash
  135. $dhash = base64_decode($hash);
  136. // Get first 32 bytes of binary which equals a SHA256 hash
  137. $ohash = substr($dhash, 0, 32);
  138. // Remove SHA256 hash from decoded hash to get original salt string
  139. $osalt = str_replace($ohash, '', $dhash);
  140. // Check single salted SHA256 hash against extracted hash
  141. if (hash('sha256', $password . $osalt, true) == $ohash) {
  142. return true;
  143. }
  144. else {
  145. return false;
  146. }
  147. }
  148. function check_login($user, $pass) {
  149. global $pdo;
  150. global $redis;
  151. if (!filter_var($user, FILTER_VALIDATE_EMAIL) && !ctype_alnum(str_replace(array('_', '.', '-'), '', $user))) {
  152. return false;
  153. }
  154. $user = strtolower(trim($user));
  155. $stmt = $pdo->prepare("SELECT `password` FROM `admin`
  156. WHERE `superadmin` = '1'
  157. AND `username` = :user");
  158. $stmt->execute(array(':user' => $user));
  159. $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
  160. foreach ($rows as $row) {
  161. if (verify_ssha256($row['password'], $pass)) {
  162. if (get_tfa($user)['name'] != "none") {
  163. $_SESSION['pending_mailcow_cc_username'] = $user;
  164. $_SESSION['pending_mailcow_cc_role'] = "admin";
  165. $_SESSION['pending_tfa_method'] = get_tfa($user)['name'];
  166. unset($_SESSION['ldelay']);
  167. return "pending";
  168. }
  169. else {
  170. unset($_SESSION['ldelay']);
  171. return "admin";
  172. }
  173. }
  174. }
  175. $stmt = $pdo->prepare("SELECT `password` FROM `admin`
  176. WHERE `superadmin` = '0'
  177. AND `active`='1'
  178. AND `username` = :user");
  179. $stmt->execute(array(':user' => $user));
  180. $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
  181. foreach ($rows as $row) {
  182. if (verify_ssha256($row['password'], $pass) !== false) {
  183. if (get_tfa($user)['name'] != "none") {
  184. $_SESSION['pending_mailcow_cc_username'] = $user;
  185. $_SESSION['pending_mailcow_cc_role'] = "domainadmin";
  186. $_SESSION['pending_tfa_method'] = get_tfa($user)['name'];
  187. unset($_SESSION['ldelay']);
  188. return "pending";
  189. }
  190. else {
  191. unset($_SESSION['ldelay']);
  192. $stmt = $pdo->prepare("UPDATE `tfa` SET `active`='1' WHERE `username` = :user");
  193. $stmt->execute(array(':user' => $user));
  194. return "domainadmin";
  195. }
  196. }
  197. }
  198. $stmt = $pdo->prepare("SELECT `password` FROM `mailbox`
  199. WHERE `kind` NOT REGEXP 'location|thing|group'
  200. AND `active`='1'
  201. AND `username` = :user");
  202. $stmt->execute(array(':user' => $user));
  203. $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
  204. foreach ($rows as $row) {
  205. if (verify_ssha256($row['password'], $pass) !== false) {
  206. unset($_SESSION['ldelay']);
  207. return "user";
  208. }
  209. }
  210. if (!isset($_SESSION['ldelay'])) {
  211. $_SESSION['ldelay'] = "0";
  212. $redis->publish("F2B_CHANNEL", "mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
  213. error_log("mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
  214. }
  215. elseif (!isset($_SESSION['mailcow_cc_username'])) {
  216. $_SESSION['ldelay'] = $_SESSION['ldelay']+0.5;
  217. $redis->publish("F2B_CHANNEL", "mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
  218. error_log("mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
  219. }
  220. sleep($_SESSION['ldelay']);
  221. }
  222. function set_acl() {
  223. global $pdo;
  224. if (!isset($_SESSION['mailcow_cc_username'])) {
  225. return false;
  226. }
  227. if ($_SESSION['mailcow_cc_role'] == 'admin' || $_SESSION['mailcow_cc_role'] == 'domainadmin') {
  228. $stmt = $pdo->query("SHOW COLUMNS FROM `user_acl` WHERE `Field` != 'username';");
  229. $acl_all = $stmt->fetchAll(PDO::FETCH_ASSOC);
  230. while ($row = array_shift($acl_all)) {
  231. $acl['acl'][$row['Field']] = 1;
  232. }
  233. }
  234. else {
  235. $username = strtolower(trim($_SESSION['mailcow_cc_username']));
  236. $stmt = $pdo->prepare("SELECT * FROM `user_acl` WHERE `username` = :username");
  237. $stmt->execute(array(':username' => $username));
  238. $acl['acl'] = $stmt->fetch(PDO::FETCH_ASSOC);
  239. unset($acl['acl']['username']);
  240. }
  241. if (!empty($acl)) {
  242. $_SESSION = array_merge($_SESSION, $acl);
  243. }
  244. else {
  245. return false;
  246. }
  247. }
  248. function get_acl($username) {
  249. global $pdo;
  250. if ($_SESSION['mailcow_cc_role'] != "admin") {
  251. return false;
  252. }
  253. $username = strtolower(trim($username));
  254. $stmt = $pdo->prepare("SELECT * FROM `user_acl` WHERE `username` = :username");
  255. $stmt->execute(array(':username' => $username));
  256. $acl = $stmt->fetch(PDO::FETCH_ASSOC);
  257. unset($acl['username']);
  258. if (!empty($acl)) {
  259. return $acl;
  260. }
  261. else {
  262. return false;
  263. }
  264. }
  265. function formatBytes($size, $precision = 2) {
  266. if(!is_numeric($size)) {
  267. return "0";
  268. }
  269. $base = log($size, 1024);
  270. $suffixes = array(' Byte', ' KiB', ' MiB', ' GiB', ' TiB');
  271. if ($size == "0") {
  272. return "0";
  273. }
  274. return round(pow(1024, $base - floor($base)), $precision) . $suffixes[floor($base)];
  275. }
  276. function edit_admin_account($postarray) {
  277. global $lang;
  278. global $pdo;
  279. if ($_SESSION['mailcow_cc_role'] != "admin") {
  280. $_SESSION['return'] = array(
  281. 'type' => 'danger',
  282. 'msg' => sprintf($lang['danger']['access_denied'])
  283. );
  284. return false;
  285. }
  286. $username_now = $_SESSION['mailcow_cc_username'];
  287. $username = $postarray['admin_user'];
  288. $password = $postarray['admin_pass'];
  289. $password2 = $postarray['admin_pass2'];
  290. if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $username)) || empty ($username)) {
  291. $_SESSION['return'] = array(
  292. 'type' => 'danger',
  293. 'msg' => sprintf($lang['danger']['username_invalid'])
  294. );
  295. return false;
  296. }
  297. if (!empty($password) && !empty($password2)) {
  298. if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) {
  299. $_SESSION['return'] = array(
  300. 'type' => 'danger',
  301. 'msg' => sprintf($lang['danger']['password_complexity'])
  302. );
  303. return false;
  304. }
  305. if ($password != $password2) {
  306. $_SESSION['return'] = array(
  307. 'type' => 'danger',
  308. 'msg' => sprintf($lang['danger']['password_mismatch'])
  309. );
  310. return false;
  311. }
  312. $password_hashed = hash_password($password);
  313. try {
  314. $stmt = $pdo->prepare("UPDATE `admin` SET
  315. `password` = :password_hashed,
  316. `username` = :username1
  317. WHERE `username` = :username2");
  318. $stmt->execute(array(
  319. ':password_hashed' => $password_hashed,
  320. ':username1' => $username,
  321. ':username2' => $username_now
  322. ));
  323. }
  324. catch (PDOException $e) {
  325. $_SESSION['return'] = array(
  326. 'type' => 'danger',
  327. 'msg' => 'MySQL: '.$e
  328. );
  329. return false;
  330. }
  331. }
  332. else {
  333. try {
  334. $stmt = $pdo->prepare("UPDATE `admin` SET
  335. `username` = :username1
  336. WHERE `username` = :username2");
  337. $stmt->execute(array(
  338. ':username1' => $username,
  339. ':username2' => $username_now
  340. ));
  341. }
  342. catch (PDOException $e) {
  343. $_SESSION['return'] = array(
  344. 'type' => 'danger',
  345. 'msg' => 'MySQL: '.$e
  346. );
  347. return false;
  348. }
  349. }
  350. try {
  351. $stmt = $pdo->prepare("UPDATE `domain_admins` SET `domain` = 'ALL', `username` = :username1 WHERE `username` = :username2");
  352. $stmt->execute(array(':username1' => $username, ':username2' => $username_now));
  353. $stmt = $pdo->prepare("UPDATE `tfa` SET `username` = :username1 WHERE `username` = :username2");
  354. $stmt->execute(array(':username1' => $username, ':username2' => $username_now));
  355. }
  356. catch (PDOException $e) {
  357. $_SESSION['return'] = array(
  358. 'type' => 'danger',
  359. 'msg' => 'MySQL: '.$e
  360. );
  361. return false;
  362. }
  363. $_SESSION['mailcow_cc_username'] = $username;
  364. $_SESSION['return'] = array(
  365. 'type' => 'success',
  366. 'msg' => sprintf($lang['success']['admin_modified'])
  367. );
  368. }
  369. function edit_user_account($postarray) {
  370. global $lang;
  371. global $pdo;
  372. $username = $_SESSION['mailcow_cc_username'];
  373. $role = $_SESSION['mailcow_cc_role'];
  374. $password_old = $postarray['user_old_pass'];
  375. if (filter_var($username, FILTER_VALIDATE_EMAIL === false) || $role != 'user') {
  376. $_SESSION['return'] = array(
  377. 'type' => 'danger',
  378. 'msg' => sprintf($lang['danger']['access_denied'])
  379. );
  380. return false;
  381. }
  382. if (isset($postarray['user_new_pass']) && isset($postarray['user_new_pass2'])) {
  383. $password_new = $postarray['user_new_pass'];
  384. $password_new2 = $postarray['user_new_pass2'];
  385. }
  386. $stmt = $pdo->prepare("SELECT `password` FROM `mailbox`
  387. WHERE `kind` NOT REGEXP 'location|thing|group'
  388. AND `username` = :user");
  389. $stmt->execute(array(':user' => $username));
  390. $row = $stmt->fetch(PDO::FETCH_ASSOC);
  391. if (!verify_ssha256($row['password'], $password_old)) {
  392. $_SESSION['return'] = array(
  393. 'type' => 'danger',
  394. 'msg' => sprintf($lang['danger']['access_denied'])
  395. );
  396. return false;
  397. }
  398. if (isset($password_new) && isset($password_new2)) {
  399. if (!empty($password_new2) && !empty($password_new)) {
  400. if ($password_new2 != $password_new) {
  401. $_SESSION['return'] = array(
  402. 'type' => 'danger',
  403. 'msg' => sprintf($lang['danger']['password_mismatch'])
  404. );
  405. return false;
  406. }
  407. if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password_new)) {
  408. $_SESSION['return'] = array(
  409. 'type' => 'danger',
  410. 'msg' => sprintf($lang['danger']['password_complexity'])
  411. );
  412. return false;
  413. }
  414. $password_hashed = hash_password($password_new);
  415. try {
  416. $stmt = $pdo->prepare("UPDATE `mailbox` SET `password` = :password_hashed, `attributes` = JSON_SET(`attributes`, '$.force_pw_update', '0') WHERE `username` = :username");
  417. $stmt->execute(array(
  418. ':password_hashed' => $password_hashed,
  419. ':username' => $username
  420. ));
  421. }
  422. catch (PDOException $e) {
  423. $_SESSION['return'] = array(
  424. 'type' => 'danger',
  425. 'msg' => 'MySQL: '.$e
  426. );
  427. return false;
  428. }
  429. }
  430. }
  431. $_SESSION['return'] = array(
  432. 'type' => 'success',
  433. 'msg' => sprintf($lang['success']['mailbox_modified'], htmlspecialchars($username))
  434. );
  435. }
  436. function user_get_alias_details($username) {
  437. global $lang;
  438. global $pdo;
  439. if ($_SESSION['mailcow_cc_role'] == "user") {
  440. $username = $_SESSION['mailcow_cc_username'];
  441. }
  442. if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
  443. return false;
  444. }
  445. try {
  446. $data['address'] = $username;
  447. $stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(`address` SEPARATOR ', '), '&#10008;') AS `shared_aliases` FROM `alias`
  448. WHERE `goto` REGEXP :username_goto
  449. AND `address` NOT LIKE '@%'
  450. AND `goto` != :username_goto2
  451. AND `address` != :username_address");
  452. $stmt->execute(array(
  453. ':username_goto' => '(^|,)'.$username.'($|,)',
  454. ':username_goto2' => $username,
  455. ':username_address' => $username
  456. ));
  457. $run = $stmt->fetchAll(PDO::FETCH_ASSOC);
  458. while ($row = array_shift($run)) {
  459. $data['shared_aliases'] = $row['shared_aliases'];
  460. }
  461. $stmt = $pdo->prepare("SELECT GROUP_CONCAT(`address` SEPARATOR ', ') AS `direct_aliases` FROM `alias`
  462. WHERE `goto` = :username_goto
  463. AND `address` NOT LIKE '@%'
  464. AND `address` != :username_address");
  465. $stmt->execute(
  466. array(
  467. ':username_goto' => $username,
  468. ':username_address' => $username
  469. ));
  470. $run = $stmt->fetchAll(PDO::FETCH_ASSOC);
  471. while ($row = array_shift($run)) {
  472. $data['direct_aliases'][] = $row['direct_aliases'];
  473. }
  474. $stmt = $pdo->prepare("SELECT GROUP_CONCAT(local_part, '@', alias_domain SEPARATOR ', ') AS `ad_alias` FROM `mailbox`
  475. LEFT OUTER JOIN `alias_domain` on `target_domain` = `domain`
  476. WHERE `username` = :username ;");
  477. $stmt->execute(array(':username' => $username));
  478. $run = $stmt->fetchAll(PDO::FETCH_ASSOC);
  479. while ($row = array_shift($run)) {
  480. $data['direct_aliases'][] = $row['ad_alias'];
  481. }
  482. $data['direct_aliases'] = implode(', ', array_filter($data['direct_aliases']));
  483. $data['direct_aliases'] = empty($data['direct_aliases']) ? '&#10008;' : $data['direct_aliases'];
  484. $stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(`send_as` SEPARATOR ', '), '&#10008;') AS `send_as` FROM `sender_acl` WHERE `logged_in_as` = :username AND `send_as` NOT LIKE '@%';");
  485. $stmt->execute(array(':username' => $username));
  486. $run = $stmt->fetchAll(PDO::FETCH_ASSOC);
  487. while ($row = array_shift($run)) {
  488. $data['aliases_also_send_as'] = $row['send_as'];
  489. }
  490. $stmt = $pdo->prepare("SELECT IFNULL(CONCAT(GROUP_CONCAT(DISTINCT `send_as` SEPARATOR ', '), ', ', GROUP_CONCAT(DISTINCT CONCAT('@',`alias_domain`) SEPARATOR ', ')), '&#10008;') AS `send_as` FROM `sender_acl` LEFT JOIN `alias_domain` ON `alias_domain`.`target_domain` = TRIM(LEADING '@' FROM `send_as`) WHERE `logged_in_as` = :username AND `send_as` LIKE '@%';");
  491. $stmt->execute(array(':username' => $username));
  492. $run = $stmt->fetchAll(PDO::FETCH_ASSOC);
  493. while ($row = array_shift($run)) {
  494. $data['aliases_send_as_all'] = $row['send_as'];
  495. }
  496. $stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(`address` SEPARATOR ', '), '&#10008;') as `address` FROM `alias` WHERE `goto` REGEXP :username AND `address` LIKE '@%';");
  497. $stmt->execute(array(':username' => '(^|,)'.$username.'($|,)'));
  498. $run = $stmt->fetchAll(PDO::FETCH_ASSOC);
  499. while ($row = array_shift($run)) {
  500. $data['is_catch_all'] = $row['address'];
  501. }
  502. return $data;
  503. }
  504. catch(PDOException $e) {
  505. $_SESSION['return'] = array(
  506. 'type' => 'danger',
  507. 'msg' => 'MySQL: '.$e
  508. );
  509. return false;
  510. }
  511. }
  512. function is_valid_domain_name($domain_name) {
  513. if (empty($domain_name)) {
  514. return false;
  515. }
  516. $domain_name = idn_to_ascii($domain_name);
  517. return (preg_match("/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i", $domain_name)
  518. && preg_match("/^.{1,253}$/", $domain_name)
  519. && preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $domain_name));
  520. }
  521. function set_tfa($postarray) {
  522. global $lang;
  523. global $pdo;
  524. global $yubi;
  525. global $u2f;
  526. global $tfa;
  527. if ($_SESSION['mailcow_cc_role'] != "domainadmin" &&
  528. $_SESSION['mailcow_cc_role'] != "admin") {
  529. $_SESSION['return'] = array(
  530. 'type' => 'danger',
  531. 'msg' => sprintf($lang['danger']['access_denied'])
  532. );
  533. return false;
  534. }
  535. $username = $_SESSION['mailcow_cc_username'];
  536. $stmt = $pdo->prepare("SELECT `password` FROM `admin`
  537. WHERE `username` = :user");
  538. $stmt->execute(array(':user' => $username));
  539. $row = $stmt->fetch(PDO::FETCH_ASSOC);
  540. if (!verify_ssha256($row['password'], $postarray["confirm_password"])) {
  541. $_SESSION['return'] = array(
  542. 'type' => 'danger',
  543. 'msg' => sprintf($lang['danger']['access_denied'])
  544. );
  545. return false;
  546. }
  547. switch ($postarray["tfa_method"]) {
  548. case "yubi_otp":
  549. $key_id = (!isset($postarray["key_id"])) ? 'unidentified' : $postarray["key_id"];
  550. $yubico_id = $postarray['yubico_id'];
  551. $yubico_key = $postarray['yubico_key'];
  552. $yubi = new Auth_Yubico($yubico_id, $yubico_key);
  553. if (!$yubi) {
  554. $_SESSION['return'] = array(
  555. 'type' => 'danger',
  556. 'msg' => sprintf($lang['danger']['access_denied'])
  557. );
  558. return false;
  559. }
  560. if (!ctype_alnum($postarray["otp_token"]) || strlen($postarray["otp_token"]) != 44) {
  561. $_SESSION['return'] = array(
  562. 'type' => 'danger',
  563. 'msg' => sprintf($lang['danger']['tfa_token_invalid'])
  564. );
  565. return false;
  566. }
  567. $yauth = $yubi->verify($postarray["otp_token"]);
  568. if (PEAR::isError($yauth)) {
  569. $_SESSION['return'] = array(
  570. 'type' => 'danger',
  571. 'msg' => 'Yubico API: ' . $yauth->getMessage()
  572. );
  573. return false;
  574. }
  575. try {
  576. // We could also do a modhex translation here
  577. $yubico_modhex_id = substr($postarray["otp_token"], 0, 12);
  578. $stmt = $pdo->prepare("DELETE FROM `tfa`
  579. WHERE `username` = :username
  580. AND (`authmech` != 'yubi_otp')
  581. OR (`authmech` = 'yubi_otp' AND `secret` LIKE :modhex)");
  582. $stmt->execute(array(':username' => $username, ':modhex' => '%' . $yubico_modhex_id));
  583. $stmt = $pdo->prepare("INSERT INTO `tfa` (`key_id`, `username`, `authmech`, `active`, `secret`) VALUES
  584. (:key_id, :username, 'yubi_otp', '1', :secret)");
  585. $stmt->execute(array(':key_id' => $key_id, ':username' => $username, ':secret' => $yubico_id . ':' . $yubico_key . ':' . $yubico_modhex_id));
  586. }
  587. catch (PDOException $e) {
  588. $_SESSION['return'] = array(
  589. 'type' => 'danger',
  590. 'msg' => 'MySQL: '.$e
  591. );
  592. return false;
  593. }
  594. $_SESSION['return'] = array(
  595. 'type' => 'success',
  596. 'msg' => sprintf($lang['success']['object_modified'], htmlspecialchars($username))
  597. );
  598. break;
  599. case "u2f":
  600. $key_id = (!isset($postarray["key_id"])) ? 'unidentified' : $postarray["key_id"];
  601. try {
  602. $reg = $u2f->doRegister(json_decode($_SESSION['regReq']), json_decode($postarray['token']));
  603. $stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username AND `authmech` != 'u2f'");
  604. $stmt->execute(array(':username' => $username));
  605. $stmt = $pdo->prepare("INSERT INTO `tfa` (`username`, `key_id`, `authmech`, `keyHandle`, `publicKey`, `certificate`, `counter`, `active`) VALUES (?, ?, 'u2f', ?, ?, ?, ?, '1')");
  606. $stmt->execute(array($username, $key_id, $reg->keyHandle, $reg->publicKey, $reg->certificate, $reg->counter));
  607. $_SESSION['return'] = array(
  608. 'type' => 'success',
  609. 'msg' => sprintf($lang['success']['object_modified'], $username)
  610. );
  611. $_SESSION['regReq'] = null;
  612. }
  613. catch (Exception $e) {
  614. $_SESSION['return'] = array(
  615. 'type' => 'danger',
  616. 'msg' => "U2F: " . $e->getMessage()
  617. );
  618. $_SESSION['regReq'] = null;
  619. return false;
  620. }
  621. break;
  622. case "totp":
  623. $key_id = (!isset($postarray["key_id"])) ? 'unidentified' : $postarray["key_id"];
  624. if ($tfa->verifyCode($_POST['totp_secret'], $_POST['totp_confirm_token']) === true) {
  625. try {
  626. $stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username");
  627. $stmt->execute(array(':username' => $username));
  628. $stmt = $pdo->prepare("INSERT INTO `tfa` (`username`, `key_id`, `authmech`, `secret`, `active`) VALUES (?, ?, 'totp', ?, '1')");
  629. $stmt->execute(array($username, $key_id, $_POST['totp_secret']));
  630. }
  631. catch (PDOException $e) {
  632. $_SESSION['return'] = array(
  633. 'type' => 'danger',
  634. 'msg' => 'MySQL: '.$e
  635. );
  636. return false;
  637. }
  638. $_SESSION['return'] = array(
  639. 'type' => 'success',
  640. 'msg' => sprintf($lang['success']['object_modified'], $username)
  641. );
  642. }
  643. else {
  644. $_SESSION['return'] = array(
  645. 'type' => 'danger',
  646. 'msg' => 'TOTP verification failed'
  647. );
  648. }
  649. break;
  650. case "none":
  651. try {
  652. $stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username");
  653. $stmt->execute(array(':username' => $username));
  654. }
  655. catch (PDOException $e) {
  656. $_SESSION['return'] = array(
  657. 'type' => 'danger',
  658. 'msg' => 'MySQL: '.$e
  659. );
  660. return false;
  661. }
  662. $_SESSION['return'] = array(
  663. 'type' => 'success',
  664. 'msg' => sprintf($lang['success']['object_modified'], htmlspecialchars($username))
  665. );
  666. break;
  667. }
  668. }
  669. function unset_tfa_key($postarray) {
  670. // Can only unset own keys
  671. // Needs at least one key left
  672. global $pdo;
  673. global $lang;
  674. $id = intval($postarray['unset_tfa_key']);
  675. if ($_SESSION['mailcow_cc_role'] != "domainadmin" &&
  676. $_SESSION['mailcow_cc_role'] != "admin") {
  677. $_SESSION['return'] = array(
  678. 'type' => 'danger',
  679. 'msg' => sprintf($lang['danger']['access_denied'])
  680. );
  681. return false;
  682. }
  683. $username = $_SESSION['mailcow_cc_username'];
  684. try {
  685. if (!is_numeric($id)) {
  686. $_SESSION['return'] = array(
  687. 'type' => 'danger',
  688. 'msg' => sprintf($lang['danger']['access_denied'])
  689. );
  690. return false;
  691. }
  692. $stmt = $pdo->prepare("SELECT COUNT(*) AS `keys` FROM `tfa`
  693. WHERE `username` = :username AND `active` = '1'");
  694. $stmt->execute(array(':username' => $username));
  695. $row = $stmt->fetch(PDO::FETCH_ASSOC);
  696. if ($row['keys'] == "1") {
  697. $_SESSION['return'] = array(
  698. 'type' => 'danger',
  699. 'msg' => sprintf($lang['danger']['last_key'])
  700. );
  701. return false;
  702. }
  703. $stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username AND `id` = :id");
  704. $stmt->execute(array(':username' => $username, ':id' => $id));
  705. $_SESSION['return'] = array(
  706. 'type' => 'success',
  707. 'msg' => sprintf($lang['success']['object_modified'], $username)
  708. );
  709. }
  710. catch (PDOException $e) {
  711. $_SESSION['return'] = array(
  712. 'type' => 'danger',
  713. 'msg' => 'MySQL: '.$e
  714. );
  715. return false;
  716. }
  717. }
  718. function get_tfa($username = null) {
  719. global $pdo;
  720. if (isset($_SESSION['mailcow_cc_username'])) {
  721. $username = $_SESSION['mailcow_cc_username'];
  722. }
  723. elseif (empty($username)) {
  724. return false;
  725. }
  726. $stmt = $pdo->prepare("SELECT * FROM `tfa`
  727. WHERE `username` = :username AND `active` = '1'");
  728. $stmt->execute(array(':username' => $username));
  729. $row = $stmt->fetch(PDO::FETCH_ASSOC);
  730. switch ($row["authmech"]) {
  731. case "yubi_otp":
  732. $data['name'] = "yubi_otp";
  733. $data['pretty'] = "Yubico OTP";
  734. $stmt = $pdo->prepare("SELECT `id`, `key_id`, RIGHT(`secret`, 12) AS 'modhex' FROM `tfa` WHERE `authmech` = 'yubi_otp' AND `username` = :username");
  735. $stmt->execute(array(
  736. ':username' => $username,
  737. ));
  738. $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
  739. while($row = array_shift($rows)) {
  740. $data['additional'][] = $row;
  741. }
  742. return $data;
  743. break;
  744. case "u2f":
  745. $data['name'] = "u2f";
  746. $data['pretty'] = "Fido U2F";
  747. $stmt = $pdo->prepare("SELECT `id`, `key_id` FROM `tfa` WHERE `authmech` = 'u2f' AND `username` = :username");
  748. $stmt->execute(array(
  749. ':username' => $username,
  750. ));
  751. $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
  752. while($row = array_shift($rows)) {
  753. $data['additional'][] = $row;
  754. }
  755. return $data;
  756. break;
  757. case "hotp":
  758. $data['name'] = "hotp";
  759. $data['pretty'] = "HMAC-based OTP";
  760. return $data;
  761. break;
  762. case "totp":
  763. $data['name'] = "totp";
  764. $data['pretty'] = "Time-based OTP";
  765. $stmt = $pdo->prepare("SELECT `id`, `key_id`, `secret` FROM `tfa` WHERE `authmech` = 'totp' AND `username` = :username");
  766. $stmt->execute(array(
  767. ':username' => $username,
  768. ));
  769. $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
  770. while($row = array_shift($rows)) {
  771. $data['additional'][] = $row;
  772. }
  773. return $data;
  774. break;
  775. default:
  776. $data['name'] = 'none';
  777. $data['pretty'] = "-";
  778. return $data;
  779. break;
  780. }
  781. }
  782. function verify_tfa_login($username, $token) {
  783. global $pdo;
  784. global $lang;
  785. global $yubi;
  786. global $u2f;
  787. global $tfa;
  788. $stmt = $pdo->prepare("SELECT `authmech` FROM `tfa`
  789. WHERE `username` = :username AND `active` = '1'");
  790. $stmt->execute(array(':username' => $username));
  791. $row = $stmt->fetch(PDO::FETCH_ASSOC);
  792. switch ($row["authmech"]) {
  793. case "yubi_otp":
  794. if (!ctype_alnum($token) || strlen($token) != 44) {
  795. return false;
  796. }
  797. $yubico_modhex_id = substr($token, 0, 12);
  798. $stmt = $pdo->prepare("SELECT `id`, `secret` FROM `tfa`
  799. WHERE `username` = :username
  800. AND `authmech` = 'yubi_otp'
  801. AND `active`='1'
  802. AND `secret` LIKE :modhex");
  803. $stmt->execute(array(':username' => $username, ':modhex' => '%' . $yubico_modhex_id));
  804. $row = $stmt->fetch(PDO::FETCH_ASSOC);
  805. $yubico_auth = explode(':', $row['secret']);
  806. $yubi = new Auth_Yubico($yubico_auth[0], $yubico_auth[1]);
  807. $yauth = $yubi->verify($token);
  808. if (PEAR::isError($yauth)) {
  809. $_SESSION['return'] = array(
  810. 'type' => 'danger',
  811. 'msg' => 'Yubico Authentication error: ' . $yauth->getMessage()
  812. );
  813. return false;
  814. }
  815. else {
  816. $_SESSION['tfa_id'] = $row['id'];
  817. return true;
  818. }
  819. return false;
  820. break;
  821. case "u2f":
  822. try {
  823. $reg = $u2f->doAuthenticate(json_decode($_SESSION['authReq']), get_u2f_registrations($username), json_decode($token));
  824. $stmt = $pdo->prepare("UPDATE `tfa` SET `counter` = ? WHERE `id` = ?");
  825. $stmt->execute(array($reg->counter, $reg->id));
  826. $_SESSION['tfa_id'] = $reg->id;
  827. $_SESSION['authReq'] = null;
  828. return true;
  829. }
  830. catch (Exception $e) {
  831. $_SESSION['return'] = array(
  832. 'type' => 'danger',
  833. 'msg' => "U2F: " . $e->getMessage()
  834. );
  835. $_SESSION['regReq'] = null;
  836. return false;
  837. }
  838. return false;
  839. break;
  840. case "hotp":
  841. return false;
  842. break;
  843. case "totp":
  844. try {
  845. $stmt = $pdo->prepare("SELECT `id`, `secret` FROM `tfa`
  846. WHERE `username` = :username
  847. AND `authmech` = 'totp'
  848. AND `active`='1'");
  849. $stmt->execute(array(':username' => $username));
  850. $row = $stmt->fetch(PDO::FETCH_ASSOC);
  851. if ($tfa->verifyCode($row['secret'], $_POST['token']) === true) {
  852. $_SESSION['tfa_id'] = $row['id'];
  853. return true;
  854. }
  855. return false;
  856. }
  857. catch (PDOException $e) {
  858. $_SESSION['return'] = array(
  859. 'type' => 'danger',
  860. 'msg' => 'MySQL: '.$e
  861. );
  862. return false;
  863. }
  864. break;
  865. default:
  866. return false;
  867. break;
  868. }
  869. return false;
  870. }
  871. function admin_api($action, $data = null) {
  872. global $pdo;
  873. global $lang;
  874. if ($_SESSION['mailcow_cc_role'] != "admin") {
  875. $_SESSION['return'] = array(
  876. 'type' => 'danger',
  877. 'msg' => sprintf($lang['danger']['access_denied'])
  878. );
  879. return false;
  880. }
  881. switch ($action) {
  882. case "edit":
  883. $regen_key = $data['admin_api_regen_key'];
  884. $active = (isset($data['active'])) ? 1 : 0;
  885. $allow_from = array_map('trim', preg_split( "/( |,|;|\n)/", $data['allow_from']));
  886. foreach ($allow_from as $key => $val) {
  887. if (!filter_var($val, FILTER_VALIDATE_IP)) {
  888. unset($allow_from[$key]);
  889. continue;
  890. }
  891. }
  892. $allow_from = implode(',', array_unique(array_filter($allow_from)));
  893. if (empty($allow_from)) {
  894. $_SESSION['return'] = array(
  895. 'type' => 'danger',
  896. 'msg' => 'List of allowed IPs cannot be empty'
  897. );
  898. return false;
  899. }
  900. $api_key = implode('-', array(
  901. strtoupper(bin2hex(random_bytes(3))),
  902. strtoupper(bin2hex(random_bytes(3))),
  903. strtoupper(bin2hex(random_bytes(3))),
  904. strtoupper(bin2hex(random_bytes(3))),
  905. strtoupper(bin2hex(random_bytes(3)))
  906. ));
  907. $stmt = $pdo->prepare("INSERT INTO `api` (`username`, `api_key`, `active`, `allow_from`)
  908. SELECT `username`, :api_key, :active, :allow_from FROM `admin` WHERE `superadmin`='1' AND `active`='1'
  909. ON DUPLICATE KEY UPDATE `active` = :active_u, `allow_from` = :allow_from_u ;");
  910. $stmt->execute(array(
  911. ':api_key' => $api_key,
  912. ':active' => $active,
  913. ':active_u' => $active,
  914. ':allow_from' => $allow_from,
  915. ':allow_from_u' => $allow_from
  916. ));
  917. break;
  918. case "regen_key":
  919. $api_key = implode('-', array(
  920. strtoupper(bin2hex(random_bytes(3))),
  921. strtoupper(bin2hex(random_bytes(3))),
  922. strtoupper(bin2hex(random_bytes(3))),
  923. strtoupper(bin2hex(random_bytes(3))),
  924. strtoupper(bin2hex(random_bytes(3)))
  925. ));
  926. $stmt = $pdo->prepare("UPDATE `api` SET `api_key` = :api_key WHERE `username` IN
  927. (SELECT `username` FROM `admin` WHERE `superadmin`='1' AND `active`='1')");
  928. $stmt->execute(array(
  929. ':api_key' => $api_key
  930. ));
  931. break;
  932. }
  933. $_SESSION['return'] = array(
  934. 'type' => 'success',
  935. 'msg' => sprintf($lang['success']['admin_modified'])
  936. );
  937. }
  938. function rspamd_ui($action, $data = null) {
  939. global $lang;
  940. if ($_SESSION['mailcow_cc_role'] != "admin") {
  941. $_SESSION['return'] = array(
  942. 'type' => 'danger',
  943. 'msg' => sprintf($lang['danger']['access_denied'])
  944. );
  945. return false;
  946. }
  947. switch ($action) {
  948. case "edit":
  949. $rspamd_ui_pass = $data['rspamd_ui_pass'];
  950. $rspamd_ui_pass2 = $data['rspamd_ui_pass2'];
  951. if (empty($rspamd_ui_pass) || empty($rspamd_ui_pass2)) {
  952. $_SESSION['return'] = array(
  953. 'type' => 'danger',
  954. 'msg' => 'Password cannot be empty'
  955. );
  956. return false;
  957. }
  958. if ($rspamd_ui_pass != $rspamd_ui_pass2) {
  959. $_SESSION['return'] = array(
  960. 'type' => 'danger',
  961. 'msg' => 'Passwords do not match'
  962. );
  963. return false;
  964. }
  965. if (strlen($rspamd_ui_pass) < 6) {
  966. $_SESSION['return'] = array(
  967. 'type' => 'danger',
  968. 'msg' => 'Please use at least 6 characters for your password'
  969. );
  970. return false;
  971. }
  972. $docker_return = docker('rspamd-mailcow', 'post', 'exec', array('cmd' => 'worker_password', 'raw' => $rspamd_ui_pass), array('Content-Type: application/json'));
  973. if ($docker_return_array = json_decode($docker_return, true)) {
  974. if ($docker_return_array['type'] == 'success') {
  975. $_SESSION['return'] = array(
  976. 'type' => 'success',
  977. 'msg' => 'Rspamd UI password set successfully'
  978. );
  979. return true;
  980. }
  981. else {
  982. $_SESSION['return'] = array(
  983. 'type' => $docker_return_array['type'],
  984. 'msg' => $docker_return_array['msg']
  985. );
  986. return false;
  987. }
  988. }
  989. else {
  990. $_SESSION['return'] = array(
  991. 'type' => 'danger',
  992. 'msg' => 'Unknown error'
  993. );
  994. return false;
  995. }
  996. break;
  997. }
  998. }
  999. function get_admin_details() {
  1000. // No parameter to be given, only one admin should exist
  1001. global $pdo;
  1002. global $lang;
  1003. $data = array();
  1004. if ($_SESSION['mailcow_cc_role'] != 'admin') {
  1005. return false;
  1006. }
  1007. try {
  1008. $stmt = $pdo->query("SELECT `admin`.`username`, `api`.`active` AS `api_active`, `api`.`api_key`, `api`.`allow_from` FROM `admin`
  1009. INNER JOIN `api` ON `admin`.`username` = `api`.`username`
  1010. WHERE `admin`.`superadmin`='1'
  1011. AND `admin`.`active`='1'");
  1012. $data = $stmt->fetch(PDO::FETCH_ASSOC);
  1013. }
  1014. catch(PDOException $e) {
  1015. $_SESSION['return'] = array(
  1016. 'type' => 'danger',
  1017. 'msg' => 'MySQL: '.$e
  1018. );
  1019. }
  1020. return $data;
  1021. }
  1022. function get_u2f_registrations($username) {
  1023. global $pdo;
  1024. $sel = $pdo->prepare("SELECT * FROM `tfa` WHERE `authmech` = 'u2f' AND `username` = ? AND `active` = '1'");
  1025. $sel->execute(array($username));
  1026. return $sel->fetchAll(PDO::FETCH_OBJ);
  1027. }
  1028. function get_logs($container, $lines = false) {
  1029. if ($lines === false) {
  1030. $lines = $GLOBALS['LOG_LINES'] - 1;
  1031. }
  1032. global $lang;
  1033. global $redis;
  1034. if ($_SESSION['mailcow_cc_role'] != "admin") {
  1035. return false;
  1036. }
  1037. if ($container == "dovecot-mailcow") {
  1038. if (!is_numeric($lines)) {
  1039. list ($from, $to) = explode('-', $lines);
  1040. $data = $redis->lRange('DOVECOT_MAILLOG', intval($from), intval($to));
  1041. }
  1042. else {
  1043. $data = $redis->lRange('DOVECOT_MAILLOG', 0, intval($lines));
  1044. }
  1045. if ($data) {
  1046. foreach ($data as $json_line) {
  1047. $data_array[] = json_decode($json_line, true);
  1048. }
  1049. return $data_array;
  1050. }
  1051. }
  1052. if ($container == "postfix-mailcow") {
  1053. if (!is_numeric($lines)) {
  1054. list ($from, $to) = explode('-', $lines);
  1055. $data = $redis->lRange('POSTFIX_MAILLOG', intval($from), intval($to));
  1056. }
  1057. else {
  1058. $data = $redis->lRange('POSTFIX_MAILLOG', 0, intval($lines));
  1059. }
  1060. if ($data) {
  1061. foreach ($data as $json_line) {
  1062. $data_array[] = json_decode($json_line, true);
  1063. }
  1064. return $data_array;
  1065. }
  1066. }
  1067. if ($container == "sogo-mailcow") {
  1068. if (!is_numeric($lines)) {
  1069. list ($from, $to) = explode('-', $lines);
  1070. $data = $redis->lRange('SOGO_LOG', intval($from), intval($to));
  1071. }
  1072. else {
  1073. $data = $redis->lRange('SOGO_LOG', 0, intval($lines));
  1074. }
  1075. if ($data) {
  1076. foreach ($data as $json_line) {
  1077. $data_array[] = json_decode($json_line, true);
  1078. }
  1079. return $data_array;
  1080. }
  1081. }
  1082. if ($container == "watchdog-mailcow") {
  1083. if (!is_numeric($lines)) {
  1084. list ($from, $to) = explode('-', $lines);
  1085. $data = $redis->lRange('WATCHDOG_LOG', intval($from), intval($to));
  1086. }
  1087. else {
  1088. $data = $redis->lRange('WATCHDOG_LOG', 0, intval($lines));
  1089. }
  1090. if ($data) {
  1091. foreach ($data as $json_line) {
  1092. $data_array[] = json_decode($json_line, true);
  1093. }
  1094. return $data_array;
  1095. }
  1096. }
  1097. if ($container == "acme-mailcow") {
  1098. if (!is_numeric($lines)) {
  1099. list ($from, $to) = explode('-', $lines);
  1100. $data = $redis->lRange('ACME_LOG', intval($from), intval($to));
  1101. }
  1102. else {
  1103. $data = $redis->lRange('ACME_LOG', 0, intval($lines));
  1104. }
  1105. if ($data) {
  1106. foreach ($data as $json_line) {
  1107. $data_array[] = json_decode($json_line, true);
  1108. }
  1109. return $data_array;
  1110. }
  1111. }
  1112. if ($container == "api-mailcow") {
  1113. if (!is_numeric($lines)) {
  1114. list ($from, $to) = explode('-', $lines);
  1115. $data = $redis->lRange('API_LOG', intval($from), intval($to));
  1116. }
  1117. else {
  1118. $data = $redis->lRange('API_LOG', 0, intval($lines));
  1119. }
  1120. if ($data) {
  1121. foreach ($data as $json_line) {
  1122. $data_array[] = json_decode($json_line, true);
  1123. }
  1124. return $data_array;
  1125. }
  1126. }
  1127. if ($container == "netfilter-mailcow") {
  1128. if (!is_numeric($lines)) {
  1129. list ($from, $to) = explode('-', $lines);
  1130. $data = $redis->lRange('NETFILTER_LOG', intval($from), intval($to));
  1131. }
  1132. else {
  1133. $data = $redis->lRange('NETFILTER_LOG', 0, intval($lines));
  1134. }
  1135. if ($data) {
  1136. foreach ($data as $json_line) {
  1137. $data_array[] = json_decode($json_line, true);
  1138. }
  1139. return $data_array;
  1140. }
  1141. }
  1142. if ($container == "autodiscover-mailcow") {
  1143. if (!is_numeric($lines)) {
  1144. list ($from, $to) = explode('-', $lines);
  1145. $data = $redis->lRange('AUTODISCOVER_LOG', intval($from), intval($to));
  1146. }
  1147. else {
  1148. $data = $redis->lRange('AUTODISCOVER_LOG', 0, intval($lines));
  1149. }
  1150. if ($data) {
  1151. foreach ($data as $json_line) {
  1152. $data_array[] = json_decode($json_line, true);
  1153. }
  1154. return $data_array;
  1155. }
  1156. }
  1157. if ($container == "rspamd-history") {
  1158. $curl = curl_init();
  1159. curl_setopt($curl, CURLOPT_UNIX_SOCKET_PATH, '/rspamd-sock/rspamd.sock');
  1160. if (!is_numeric($lines)) {
  1161. list ($from, $to) = explode('-', $lines);
  1162. curl_setopt($curl, CURLOPT_URL,"http://rspamd/history?from=" . intval($from) . "&to=" . intval($to));
  1163. }
  1164. else {
  1165. curl_setopt($curl, CURLOPT_URL,"http://rspamd/history?to=" . intval($lines));
  1166. }
  1167. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  1168. $history = curl_exec($curl);
  1169. if (!curl_errno($curl)) {
  1170. $data_array = json_decode($history, true);
  1171. curl_close($curl);
  1172. return $data_array['rows'];
  1173. }
  1174. curl_close($curl);
  1175. return false;
  1176. }
  1177. return false;
  1178. }
  1179. ?>