| Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 1 | <?php
 | 
 | 2 | function relayhost($_action, $_data = null) {
 | 
| Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 3 |   global $pdo;
 | 
 | 4 |   global $lang;
 | 
| Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 5 |   $_data_log = $_data;
 | 
 | 6 |   switch ($_action) {
 | 
 | 7 |     case 'add':
 | 
 | 8 |       if ($_SESSION['mailcow_cc_role'] != "admin") {
 | 
 | 9 |         $_SESSION['return'][] = array(
 | 
 | 10 |           'type' => 'danger',
 | 
 | 11 |           'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 12 |           'msg' => 'access_denied'
 | 
 | 13 |         );
 | 
 | 14 |         return false;
 | 
 | 15 |       }
 | 
 | 16 |       $hostname = trim($_data['hostname']);
 | 
 | 17 |       $username = str_replace(':', '\:', trim($_data['username']));
 | 
 | 18 |       $password = str_replace(':', '\:', trim($_data['password']));
 | 
 | 19 |       if (empty($hostname)) {
 | 
 | 20 |         $_SESSION['return'][] = array(
 | 
 | 21 |           'type' => 'danger',
 | 
 | 22 |           'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 23 |           'msg' => array('invalid_host', htmlspecialchars($host))
 | 
 | 24 |         );
 | 
 | 25 |         return false;
 | 
 | 26 |       }
 | 
 | 27 |       try {
 | 
 | 28 |         $stmt = $pdo->prepare("INSERT INTO `relayhosts` (`hostname`, `username` ,`password`, `active`)
 | 
 | 29 |           VALUES (:hostname, :username, :password, :active)");
 | 
 | 30 |         $stmt->execute(array(
 | 
 | 31 |           ':hostname' => $hostname,
 | 
 | 32 |           ':username' => $username,
 | 
 | 33 |           ':password' => str_replace(':', '\:', $password),
 | 
 | 34 |           ':active' => '1'
 | 
 | 35 |         ));
 | 
 | 36 |       }
 | 
 | 37 |       catch (PDOException $e) {
 | 
 | 38 |         $_SESSION['return'][] = array(
 | 
 | 39 |           'type' => 'danger',
 | 
 | 40 |           'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 41 |           'msg' => array('mysql_error', $e)
 | 
 | 42 |         );
 | 
 | 43 |         return false;
 | 
 | 44 |       }
 | 
 | 45 |       $_SESSION['return'][] = array(
 | 
 | 46 |         'type' => 'success',
 | 
 | 47 |         'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
| Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 48 |         'msg' => array('relayhost_added', htmlspecialchars(implode(', ', (array)$hosts)))
 | 
| Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 49 |       );
 | 
 | 50 |     break;
 | 
 | 51 |     case 'edit':
 | 
 | 52 |       if ($_SESSION['mailcow_cc_role'] != "admin") {
 | 
 | 53 |         $_SESSION['return'][] = array(
 | 
 | 54 |           'type' => 'danger',
 | 
 | 55 |           'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 56 |           'msg' => 'access_denied'
 | 
 | 57 |         );
 | 
 | 58 |         return false;
 | 
 | 59 |       }
 | 
 | 60 |       $ids = (array)$_data['id'];
 | 
 | 61 |       foreach ($ids as $id) {
 | 
 | 62 |         $is_now = relayhost('details', $id);
 | 
 | 63 |         if (!empty($is_now)) {
 | 
 | 64 |           $hostname = (!empty($_data['hostname'])) ? trim($_data['hostname']) : $is_now['hostname'];
 | 
 | 65 |           $username = (isset($_data['username'])) ? trim($_data['username']) : $is_now['username'];
 | 
 | 66 |           $password = (isset($_data['password'])) ? trim($_data['password']) : $is_now['password'];
 | 
 | 67 |           $active   = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
 | 
 | 68 |         }
 | 
 | 69 |         else {
 | 
 | 70 |           $_SESSION['return'][] = array(
 | 
 | 71 |             'type' => 'danger',
 | 
 | 72 |             'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 73 |             'msg' => array('relayhost_invalid', $id)
 | 
 | 74 |           );
 | 
 | 75 |           continue;
 | 
 | 76 |         }
 | 
 | 77 |         try {
 | 
 | 78 |           $stmt = $pdo->prepare("UPDATE `relayhosts` SET
 | 
 | 79 |             `hostname` = :hostname,
 | 
 | 80 |             `username` = :username,
 | 
 | 81 |             `password` = :password,
 | 
 | 82 |             `active` = :active
 | 
 | 83 |               WHERE `id` = :id");
 | 
 | 84 |           $stmt->execute(array(
 | 
 | 85 |             ':id' => $id,
 | 
 | 86 |             ':hostname' => $hostname,
 | 
 | 87 |             ':username' => $username,
 | 
 | 88 |             ':password' => $password,
 | 
 | 89 |             ':active' => $active
 | 
 | 90 |           ));
 | 
 | 91 |         }
 | 
 | 92 |         catch (PDOException $e) {
 | 
 | 93 |           $_SESSION['return'][] = array(
 | 
 | 94 |             'type' => 'danger',
 | 
 | 95 |             'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 96 |             'msg' => array('mysql_error', $e)
 | 
 | 97 |           );
 | 
 | 98 |           continue;
 | 
 | 99 |         }
 | 
 | 100 |         $_SESSION['return'][] = array(
 | 
 | 101 |           'type' => 'success',
 | 
 | 102 |           'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
| Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 103 |           'msg' => array('object_modified', htmlspecialchars(implode(', ', (array)$hostnames)))
 | 
| Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 104 |         );
 | 
 | 105 |       }
 | 
 | 106 |     break;
 | 
 | 107 |     case 'delete':
 | 
 | 108 |       if ($_SESSION['mailcow_cc_role'] != "admin") {
 | 
 | 109 |         $_SESSION['return'][] = array(
 | 
 | 110 |           'type' => 'danger',
 | 
 | 111 |           'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 112 |           'msg' => 'access_denied'
 | 
 | 113 |         );
 | 
 | 114 |         return false;
 | 
 | 115 |       }
 | 
 | 116 |       $ids = (array)$_data['id'];
 | 
 | 117 |       foreach ($ids as $id) {
 | 
 | 118 |         try {
 | 
 | 119 |           $stmt = $pdo->prepare("DELETE FROM `relayhosts` WHERE `id`= :id");
 | 
 | 120 |           $stmt->execute(array(':id' => $id));
 | 
 | 121 |           $stmt = $pdo->prepare("UPDATE `domain` SET `relayhost` = '0' WHERE `relayhost`= :id");
 | 
 | 122 |           $stmt->execute(array(':id' => $id));
 | 
 | 123 |         }
 | 
 | 124 |         catch (PDOException $e) {
 | 
 | 125 |           $_SESSION['return'][] = array(
 | 
 | 126 |             'type' => 'danger',
 | 
 | 127 |             'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 128 |             'msg' => array('mysql_error', $e)
 | 
 | 129 |           );
 | 
 | 130 |           continue;
 | 
 | 131 |         }
 | 
 | 132 |         $_SESSION['return'][] = array(
 | 
 | 133 |           'type' => 'success',
 | 
 | 134 |           'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 135 |           'msg' => array('relayhost_removed', htmlspecialchars($id))
 | 
 | 136 |         );
 | 
 | 137 |       }
 | 
 | 138 |     break;
 | 
 | 139 |     case 'get':
 | 
| Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 140 |       if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
 | 
| Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 141 |         return false;
 | 
 | 142 |       }
 | 
 | 143 |       $relayhosts = array();
 | 
| Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 144 |       $stmt = $pdo->query("SELECT `id`, `hostname`, `username`, `active` FROM `relayhosts`");
 | 
| Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 145 |       $relayhosts = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
 | 146 |       return $relayhosts;
 | 
 | 147 |     break;
 | 
 | 148 |     case 'details':
 | 
 | 149 |       if ($_SESSION['mailcow_cc_role'] != "admin" || !isset($_data)) {
 | 
 | 150 |         return false;
 | 
 | 151 |       }
 | 
 | 152 |       $relayhostdata = array();
 | 
 | 153 |       $stmt = $pdo->prepare("SELECT `id`,
 | 
 | 154 |         `hostname`,
 | 
 | 155 |         `username`,
 | 
 | 156 |         `password`,
 | 
 | 157 |         `active`,
 | 
 | 158 |         CONCAT(LEFT(`password`, 3), '...') AS `password_short`
 | 
 | 159 |           FROM `relayhosts`
 | 
 | 160 |             WHERE `id` = :id");
 | 
 | 161 |       $stmt->execute(array(':id' => $_data));
 | 
 | 162 |       $relayhostdata = $stmt->fetch(PDO::FETCH_ASSOC);
 | 
 | 163 |       if (!empty($relayhostdata)) {
 | 
 | 164 |         $stmt = $pdo->prepare("SELECT GROUP_CONCAT(`domain` SEPARATOR ', ') AS `used_by_domains` FROM `domain` WHERE `relayhost` = :id");
 | 
 | 165 |         $stmt->execute(array(':id' => $_data));
 | 
 | 166 |         $used_by_domains = $stmt->fetch(PDO::FETCH_ASSOC)['used_by_domains'];
 | 
 | 167 |         $used_by_domains = (empty($used_by_domains)) ? '' : $used_by_domains;
 | 
 | 168 |         $relayhostdata['used_by_domains'] = $used_by_domains;
 | 
| Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 169 |         $stmt = $pdo->prepare("SELECT GROUP_CONCAT(`username` SEPARATOR ', ') AS `used_by_mailboxes` FROM `mailbox` WHERE JSON_VALUE(`attributes`, '$.relayhost') = :id");
 | 
 | 170 |         $stmt->execute(array(':id' => $_data));
 | 
 | 171 |         $used_by_mailboxes = $stmt->fetch(PDO::FETCH_ASSOC)['used_by_mailboxes'];
 | 
 | 172 |         $used_by_mailboxes = (empty($used_by_mailboxes)) ? '' : $used_by_mailboxes;
 | 
 | 173 |         $relayhostdata['used_by_mailboxes'] = $used_by_mailboxes;
 | 
| Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 174 |       }
 | 
 | 175 |       return $relayhostdata;
 | 
 | 176 |     break;
 | 
 | 177 |   }
 | 
 | 178 | }
 | 
 | 179 | function transport($_action, $_data = null) {
 | 
| Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 180 |   global $pdo;
 | 
 | 181 |   global $lang;
 | 
| Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 182 |   $_data_log = $_data;
 | 
 | 183 |   switch ($_action) {
 | 
 | 184 |     case 'add':
 | 
 | 185 |       if ($_SESSION['mailcow_cc_role'] != "admin") {
 | 
 | 186 |         $_SESSION['return'][] = array(
 | 
 | 187 |           'type' => 'danger',
 | 
 | 188 |           'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 189 |           'msg' => 'access_denied'
 | 
 | 190 |         );
 | 
 | 191 |         return false;
 | 
 | 192 |       }
 | 
 | 193 |       $destinations  = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['destination']));
 | 
 | 194 |       $active = intval($_data['active']);
 | 
| Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 195 |       $is_mx_based = intval($_data['is_mx_based']);
 | 
| Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 196 |       $nexthop = trim($_data['nexthop']);
 | 
 | 197 |       if (filter_var($nexthop, FILTER_VALIDATE_IP)) {
 | 
 | 198 |         $nexthop = '[' . $nexthop . ']';
 | 
 | 199 |       }
 | 
 | 200 |       preg_match('/\[(.+)\].*/', $nexthop, $next_hop_matches);
 | 
 | 201 |       $next_hop_clean = (isset($next_hop_matches[1])) ? $next_hop_matches[1] : $nexthop;
 | 
 | 202 |       $username = str_replace(':', '\:', trim($_data['username']));
 | 
 | 203 |       $password = str_replace(':', '\:', trim($_data['password']));
 | 
 | 204 |       if (empty($nexthop)) {
 | 
 | 205 |         $_SESSION['return'][] = array(
 | 
 | 206 |           'type' => 'danger',
 | 
 | 207 |           'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 208 |           'msg' => array('invalid_nexthop')
 | 
 | 209 |         );
 | 
 | 210 |         return false;
 | 
 | 211 |       }
 | 
 | 212 |       $transports = transport('get');
 | 
 | 213 |       if (!empty($transports)) {
 | 
 | 214 |         foreach ($transports as $transport) {
 | 
 | 215 |           $transport_data = transport('details', $transport['id']);
 | 
 | 216 |           $existing_nh[] = $transport_data['nexthop'];
 | 
 | 217 |           preg_match('/\[(.+)\].*/', $transport_data['nexthop'], $existing_clean_nh[]);
 | 
 | 218 |           if (($transport_data['nexthop'] == $nexthop || $transport_data['nexthop'] == $next_hop_clean) && $transport_data['username'] != $username) {
 | 
 | 219 |             $_SESSION['return'][] = array(
 | 
 | 220 |               'type' => 'danger',
 | 
 | 221 |               'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 222 |               'msg' => 'invalid_nexthop_authenticated'
 | 
 | 223 |             );
 | 
 | 224 |             return false;
 | 
 | 225 |           }
 | 
 | 226 |           foreach ($destinations as $d_ix => &$dest) {
 | 
 | 227 |             if (empty($dest)) {
 | 
 | 228 |               unset($destinations[$d_ix]);
 | 
 | 229 |               continue;
 | 
 | 230 |             }
 | 
 | 231 |             if ($transport_data['destination'] == $dest) {
 | 
 | 232 |               $_SESSION['return'][] = array(
 | 
 | 233 |                 'type' => 'danger',
 | 
 | 234 |                 'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 235 |                 'msg' => array('transport_dest_exists', $dest)
 | 
 | 236 |               );
 | 
 | 237 |               unset($destinations[$d_ix]);
 | 
 | 238 |               continue;
 | 
 | 239 |             }
 | 
 | 240 |             // ".domain" is a valid destination, "..domain" is not
 | 
| Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 241 |             if ($is_mx_based == 0 && (empty($dest) || (is_valid_domain_name(preg_replace('/^' . preg_quote('.', '/') . '/', '', $dest)) === false && $dest != '*' && filter_var($dest, FILTER_VALIDATE_EMAIL) === false))) {
 | 
 | 242 |               $_SESSION['return'][] = array(
 | 
 | 243 |                 'type' => 'danger',
 | 
 | 244 |                 'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 245 |                 'msg' => array('invalid_destination', $dest)
 | 
 | 246 |               );
 | 
 | 247 |               unset($destinations[$d_ix]);
 | 
 | 248 |               continue;
 | 
 | 249 |             }
 | 
 | 250 |             if ($is_mx_based == 1 && (empty($dest) || @preg_match('/' . $dest . '/', null) === false)) {
 | 
| Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 251 |               $_SESSION['return'][] = array(
 | 
 | 252 |                 'type' => 'danger',
 | 
 | 253 |                 'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 254 |                 'msg' => array('invalid_destination', $dest)
 | 
 | 255 |               );
 | 
 | 256 |               unset($destinations[$d_ix]);
 | 
 | 257 |               continue;
 | 
 | 258 |             }
 | 
 | 259 |           }
 | 
 | 260 |         }
 | 
 | 261 |       }
 | 
 | 262 |       $destinations = array_filter(array_values(array_unique($destinations)));
 | 
 | 263 |       if (empty($destinations)) { return false; }
 | 
 | 264 |       if (isset($next_hop_matches[1])) {
 | 
| Matthias Andreas Benkard | 12a5735 | 2021-12-28 18:02:04 +0100 | [diff] [blame] | 265 |         if ($existing_nh !== null && in_array($next_hop_clean, $existing_nh)) {
 | 
| Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 266 |           $_SESSION['return'][] = array(
 | 
 | 267 |             'type' => 'danger',
 | 
 | 268 |             'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 269 |             'msg' => array('next_hop_interferes', $next_hop_clean, $nexthop)
 | 
 | 270 |           );
 | 
 | 271 |           return false;
 | 
 | 272 |         }
 | 
 | 273 |       }
 | 
 | 274 |       else {
 | 
 | 275 |         foreach ($existing_clean_nh as $existing_clean_nh_each) {
 | 
 | 276 |           if ($existing_clean_nh_each[1] == $nexthop) {
 | 
 | 277 |             $_SESSION['return'][] = array(
 | 
 | 278 |               'type' => 'danger',
 | 
 | 279 |               'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 280 |               'msg' => array('next_hop_interferes_any', $nexthop)
 | 
 | 281 |             );
 | 
 | 282 |             return false;
 | 
 | 283 |           }
 | 
 | 284 |         }
 | 
 | 285 |       }
 | 
 | 286 |       foreach ($destinations as $insert_dest) {
 | 
| Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 287 |         $stmt = $pdo->prepare("INSERT INTO `transports` (`nexthop`, `destination`, `is_mx_based`, `username` , `password`,  `active`)
 | 
 | 288 |           VALUES (:nexthop, :destination, :is_mx_based, :username, :password, :active)");
 | 
| Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 289 |         $stmt->execute(array(
 | 
 | 290 |           ':nexthop' => $nexthop,
 | 
 | 291 |           ':destination' => $insert_dest,
 | 
| Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 292 |           ':is_mx_based' => $is_mx_based,
 | 
| Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 293 |           ':username' => $username,
 | 
 | 294 |           ':password' => str_replace(':', '\:', $password),
 | 
| Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 295 |           ':active' => $active
 | 
 | 296 |         ));
 | 
 | 297 |       }
 | 
 | 298 |       $stmt = $pdo->prepare("UPDATE `transports` SET
 | 
 | 299 |         `username` = :username,
 | 
 | 300 |         `password` = :password
 | 
 | 301 |           WHERE `nexthop` = :nexthop");
 | 
 | 302 |       $stmt->execute(array(
 | 
 | 303 |         ':nexthop' => $nexthop,
 | 
 | 304 |         ':username' => $username,
 | 
 | 305 |         ':password' => $password
 | 
 | 306 |       ));
 | 
 | 307 |       $_SESSION['return'][] = array(
 | 
 | 308 |         'type' => 'success',
 | 
 | 309 |         'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
| Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 310 |         'msg' => array('relayhost_added', htmlspecialchars(implode(', ', (array)$hosts)))
 | 
| Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 311 |       );
 | 
 | 312 |     break;
 | 
 | 313 |     case 'edit':
 | 
 | 314 |       if ($_SESSION['mailcow_cc_role'] != "admin") {
 | 
 | 315 |         $_SESSION['return'][] = array(
 | 
 | 316 |           'type' => 'danger',
 | 
 | 317 |           'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 318 |           'msg' => 'access_denied'
 | 
 | 319 |         );
 | 
 | 320 |         return false;
 | 
 | 321 |       }
 | 
 | 322 |       $ids = (array)$_data['id'];
 | 
 | 323 |       foreach ($ids as $id) {
 | 
 | 324 |         $is_now = transport('details', $id);
 | 
 | 325 |         if (!empty($is_now)) {
 | 
 | 326 |           $destination = (!empty($_data['destination'])) ? trim($_data['destination']) : $is_now['destination'];
 | 
 | 327 |           $nexthop = (!empty($_data['nexthop'])) ? trim($_data['nexthop']) : $is_now['nexthop'];
 | 
 | 328 |           $username = (isset($_data['username'])) ? trim($_data['username']) : $is_now['username'];
 | 
 | 329 |           $password = (isset($_data['password'])) ? trim($_data['password']) : $is_now['password'];
 | 
| Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 330 |           $is_mx_based = (isset($_data['is_mx_based']) && $_data['is_mx_based'] != '') ? intval($_data['is_mx_based']) : $is_now['is_mx_based'];
 | 
| Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 331 |           $active   = (isset($_data['active']) && $_data['active'] != '') ? intval($_data['active']) : $is_now['active'];
 | 
 | 332 |         }
 | 
 | 333 |         else {
 | 
 | 334 |           $_SESSION['return'][] = array(
 | 
 | 335 |             'type' => 'danger',
 | 
 | 336 |             'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 337 |             'msg' => array('relayhost_invalid', $id)
 | 
 | 338 |           );
 | 
 | 339 |           continue;
 | 
 | 340 |         }
 | 
 | 341 |         preg_match('/\[(.+)\].*/', $nexthop, $next_hop_matches);
 | 
 | 342 |         if (filter_var($nexthop, FILTER_VALIDATE_IP)) {
 | 
 | 343 |           $nexthop = '[' . $nexthop . ']';
 | 
 | 344 |         }
 | 
 | 345 |         $next_hop_clean = (isset($next_hop_matches[1])) ? $next_hop_matches[1] : $nexthop;
 | 
 | 346 |         $transports = transport('get');
 | 
 | 347 |         if (!empty($transports)) {
 | 
 | 348 |           foreach ($transports as $transport) {
 | 
 | 349 |             $transport_data = transport('details', $transport['id']);
 | 
 | 350 |             if ($transport['id'] == $id) {
 | 
 | 351 |               continue;
 | 
 | 352 |             }
 | 
 | 353 |             $existing_nh[] = $transport_data['nexthop'];
 | 
 | 354 |             preg_match('/\[(.+)\].*/', $transport_data['nexthop'], $existing_clean_nh[]);
 | 
 | 355 |             if ($transport_data['destination'] == $destination) {
 | 
 | 356 |               $_SESSION['return'][] = array(
 | 
 | 357 |                 'type' => 'danger',
 | 
 | 358 |                 'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 359 |                 'msg' => 'transport_dest_exists'
 | 
 | 360 |               );
 | 
 | 361 |               return false;
 | 
 | 362 |             }
 | 
 | 363 |           }
 | 
 | 364 |         }
 | 
| Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 365 |         if ($is_mx_based == 0 && (empty($destination) || (is_valid_domain_name(preg_replace('/^' . preg_quote('.', '/') . '/', '', $destination)) === false && $destination != '*' && filter_var($destination, FILTER_VALIDATE_EMAIL) === false))) {
 | 
 | 366 |           $_SESSION['return'][] = array(
 | 
 | 367 |             'type' => 'danger',
 | 
 | 368 |             'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 369 |             'msg' => array('invalid_destination', $destination)
 | 
 | 370 |           );
 | 
 | 371 |           return false;
 | 
 | 372 |         }
 | 
 | 373 |         if ($is_mx_based == 1 && (empty($destination) || @preg_match('/' . $destination . '/', null) === false)) {
 | 
 | 374 |           $_SESSION['return'][] = array(
 | 
 | 375 |             'type' => 'danger',
 | 
 | 376 |             'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 377 |             'msg' => array('invalid_destination', $destination)
 | 
 | 378 |           );
 | 
 | 379 |           return false;
 | 
 | 380 |         }
 | 
| Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 381 |         if (isset($next_hop_matches[1])) {
 | 
| Matthias Andreas Benkard | 12a5735 | 2021-12-28 18:02:04 +0100 | [diff] [blame] | 382 |           if ($existing_nh !== null && in_array($next_hop_clean, $existing_nh)) {
 | 
| Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 383 |             $_SESSION['return'][] = array(
 | 
 | 384 |               'type' => 'danger',
 | 
 | 385 |               'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 386 |               'msg' => array('next_hop_interferes', $next_hop_clean, $nexthop)
 | 
 | 387 |             );
 | 
 | 388 |             return false;
 | 
 | 389 |           }
 | 
 | 390 |         }
 | 
 | 391 |         else {
 | 
 | 392 |           foreach ($existing_clean_nh as $existing_clean_nh_each) {
 | 
 | 393 |             if ($existing_clean_nh_each[1] == $nexthop) {
 | 
 | 394 |               $_SESSION['return'][] = array(
 | 
 | 395 |                 'type' => 'danger',
 | 
 | 396 |                 'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 397 |                 'msg' => array('next_hop_interferes_any', $nexthop)
 | 
 | 398 |               );
 | 
 | 399 |               return false;
 | 
 | 400 |             }
 | 
 | 401 |           }
 | 
 | 402 |         }
 | 
 | 403 |         if (empty($username)) {
 | 
 | 404 |           $password = '';
 | 
 | 405 |         }
 | 
 | 406 |         try {
 | 
 | 407 |           $stmt = $pdo->prepare("UPDATE `transports` SET
 | 
 | 408 |             `destination` = :destination,
 | 
| Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 409 |             `is_mx_based` = :is_mx_based,
 | 
| Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 410 |             `nexthop` = :nexthop,
 | 
 | 411 |             `username` = :username,
 | 
 | 412 |             `password` = :password,
 | 
| Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 413 |             `active` = :active
 | 
 | 414 |               WHERE `id` = :id");
 | 
 | 415 |           $stmt->execute(array(
 | 
 | 416 |             ':id' => $id,
 | 
 | 417 |             ':destination' => $destination,
 | 
| Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 418 |             ':is_mx_based' => $is_mx_based,
 | 
| Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 419 |             ':nexthop' => $nexthop,
 | 
 | 420 |             ':username' => $username,
 | 
 | 421 |             ':password' => $password,
 | 
| Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 422 |             ':active' => $active
 | 
 | 423 |           ));
 | 
 | 424 |           $stmt = $pdo->prepare("UPDATE `transports` SET
 | 
 | 425 |             `username` = :username,
 | 
 | 426 |             `password` = :password
 | 
 | 427 |               WHERE `nexthop` = :nexthop");
 | 
 | 428 |           $stmt->execute(array(
 | 
 | 429 |             ':nexthop' => $nexthop,
 | 
 | 430 |             ':username' => $username,
 | 
 | 431 |             ':password' => $password
 | 
 | 432 |           ));
 | 
 | 433 |         }
 | 
 | 434 |         catch (PDOException $e) {
 | 
 | 435 |           $_SESSION['return'][] = array(
 | 
 | 436 |             'type' => 'danger',
 | 
 | 437 |             'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 438 |             'msg' => array('mysql_error', $e)
 | 
 | 439 |           );
 | 
 | 440 |           continue;
 | 
 | 441 |         }
 | 
 | 442 |         $_SESSION['return'][] = array(
 | 
 | 443 |           'type' => 'success',
 | 
 | 444 |           'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
| Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 445 |           'msg' => array('object_modified', htmlspecialchars(implode(', ', (array)$hostnames)))
 | 
| Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 446 |         );
 | 
 | 447 |       }
 | 
 | 448 |     break;
 | 
 | 449 |     case 'delete':
 | 
 | 450 |       if ($_SESSION['mailcow_cc_role'] != "admin") {
 | 
 | 451 |         $_SESSION['return'][] = array(
 | 
 | 452 |           'type' => 'danger',
 | 
 | 453 |           'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 454 |           'msg' => 'access_denied'
 | 
 | 455 |         );
 | 
 | 456 |         return false;
 | 
 | 457 |       }
 | 
 | 458 |       $ids = (array)$_data['id'];
 | 
 | 459 |       foreach ($ids as $id) {
 | 
 | 460 |         try {
 | 
 | 461 |           $stmt = $pdo->prepare("DELETE FROM `transports` WHERE `id`= :id");
 | 
 | 462 |           $stmt->execute(array(':id' => $id));
 | 
 | 463 |         }
 | 
 | 464 |         catch (PDOException $e) {
 | 
 | 465 |           $_SESSION['return'][] = array(
 | 
 | 466 |             'type' => 'danger',
 | 
 | 467 |             'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 468 |             'msg' => array('mysql_error', $e)
 | 
 | 469 |           );
 | 
 | 470 |           continue;
 | 
 | 471 |         }
 | 
 | 472 |         $_SESSION['return'][] = array(
 | 
 | 473 |           'type' => 'success',
 | 
 | 474 |           'log' => array(__FUNCTION__, $_action, $_data_log),
 | 
 | 475 |           'msg' => array('relayhost_removed', htmlspecialchars($id))
 | 
 | 476 |         );
 | 
 | 477 |       }
 | 
 | 478 |     break;
 | 
 | 479 |     case 'get':
 | 
 | 480 |       if ($_SESSION['mailcow_cc_role'] != "admin") {
 | 
 | 481 |         return false;
 | 
 | 482 |       }
 | 
 | 483 |       $transports = array();
 | 
| Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 484 |       $stmt = $pdo->query("SELECT `id`, `is_mx_based`, `destination`, `nexthop`, `username` FROM `transports`");
 | 
| Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 485 |       $transports = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
 | 486 |       return $transports;
 | 
 | 487 |     break;
 | 
 | 488 |     case 'details':
 | 
 | 489 |       if ($_SESSION['mailcow_cc_role'] != "admin" || !isset($_data)) {
 | 
 | 490 |         return false;
 | 
 | 491 |       }
 | 
 | 492 |       $transportdata = array();
 | 
 | 493 |       $stmt = $pdo->prepare("SELECT `id`,
 | 
| Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 494 |         `is_mx_based`,
 | 
| Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 495 |         `destination`,
 | 
 | 496 |         `nexthop`,
 | 
 | 497 |         `username`,
 | 
 | 498 |         `password`,
 | 
 | 499 |         `active`,
 | 
| Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 500 |         CONCAT(LEFT(`password`, 3), '...') AS `password_short`
 | 
 | 501 |           FROM `transports`
 | 
 | 502 |             WHERE `id` = :id");
 | 
 | 503 |       $stmt->execute(array(':id' => $_data));
 | 
 | 504 |       $transportdata = $stmt->fetch(PDO::FETCH_ASSOC);
 | 
 | 505 |       return $transportdata;
 | 
 | 506 |     break;
 | 
 | 507 |   }
 | 
| Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 508 | }
 |