ldap-sync.php 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. <?php
  2. require_once(__DIR__ . '/../web/inc/vars.inc.php');
  3. if (file_exists(__DIR__ . '/../web/inc/vars.local.inc.php')) {
  4. include_once(__DIR__ . '/../web/inc/vars.local.inc.php');
  5. }
  6. require_once __DIR__ . '/../web/inc/lib/vendor/autoload.php';
  7. // Init database
  8. //$dsn = $database_type . ':host=' . $database_host . ';dbname=' . $database_name;
  9. $dsn = $database_type . ":unix_socket=" . $database_sock . ";dbname=" . $database_name;
  10. $opt = [
  11. PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
  12. PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
  13. PDO::ATTR_EMULATE_PREPARES => false,
  14. ];
  15. try {
  16. $pdo = new PDO($dsn, $database_user, $database_pass, $opt);
  17. }
  18. catch (PDOException $e) {
  19. logMsg("err", $e->getMessage());
  20. session_destroy();
  21. exit;
  22. }
  23. // Init Redis
  24. $redis = new Redis();
  25. try {
  26. if (!empty(getenv('REDIS_SLAVEOF_IP'))) {
  27. $redis->connect(getenv('REDIS_SLAVEOF_IP'), getenv('REDIS_SLAVEOF_PORT'));
  28. }
  29. else {
  30. $redis->connect('redis-mailcow', 6379);
  31. }
  32. }
  33. catch (Exception $e) {
  34. echo "Exiting: " . $e->getMessage();
  35. session_destroy();
  36. exit;
  37. }
  38. function logMsg($priority, $message, $task = "LDAP Sync") {
  39. global $redis;
  40. $finalMsg = array(
  41. "time" => time(),
  42. "priority" => $priority,
  43. "task" => $task,
  44. "message" => $message
  45. );
  46. $redis->lPush('CRON_LOG', json_encode($finalMsg));
  47. }
  48. // Load core functions first
  49. require_once __DIR__ . '/../web/inc/functions.inc.php';
  50. require_once __DIR__ . '/../web/inc/functions.auth.inc.php';
  51. require_once __DIR__ . '/../web/inc/sessions.inc.php';
  52. require_once __DIR__ . '/../web/inc/functions.mailbox.inc.php';
  53. require_once __DIR__ . '/../web/inc/functions.ratelimit.inc.php';
  54. require_once __DIR__ . '/../web/inc/functions.acl.inc.php';
  55. $_SESSION['mailcow_cc_username'] = "admin";
  56. $_SESSION['mailcow_cc_role'] = "admin";
  57. $_SESSION['acl']['tls_policy'] = "1";
  58. $_SESSION['acl']['quarantine_notification'] = "1";
  59. $_SESSION['acl']['quarantine_category'] = "1";
  60. $_SESSION['acl']['ratelimit'] = "1";
  61. $_SESSION['acl']['sogo_access'] = "1";
  62. $_SESSION['acl']['protocol_access'] = "1";
  63. $_SESSION['acl']['mailbox_relayhost'] = "1";
  64. $_SESSION['acl']['unlimited_quota'] = "1";
  65. // Init Provider
  66. $iam_provider = identity_provider('init');
  67. $iam_settings = identity_provider('get');
  68. if ($iam_settings['authsource'] != "ldap" || (intval($iam_settings['periodic_sync']) != 1 && intval($iam_settings['import_users']) != 1)) {
  69. session_destroy();
  70. exit;
  71. }
  72. // Set pagination variables
  73. $start = 0;
  74. $max = 25;
  75. // lock sync if already running
  76. $lock_file = '/tmp/iam-sync.lock';
  77. if (file_exists($lock_file)) {
  78. $lock_file_parts = explode("\n", file_get_contents($lock_file));
  79. $pid = $lock_file_parts[0];
  80. if (count($lock_file_parts) > 1){
  81. $last_execution = $lock_file_parts[1];
  82. $elapsed_time = (time() - $last_execution) / 60;
  83. if ($elapsed_time < intval($iam_settings['sync_interval'])) {
  84. logMsg("warning", "Sync not ready (".number_format((float)$elapsed_time, 2, '.', '')."min / ".$iam_settings['sync_interval']."min)");
  85. session_destroy();
  86. exit;
  87. }
  88. }
  89. if (posix_kill($pid, 0)) {
  90. logMsg("warning", "Sync is already running");
  91. session_destroy();
  92. exit;
  93. } else {
  94. unlink($lock_file);
  95. }
  96. }
  97. $lock_file_handle = fopen($lock_file, 'w');
  98. fwrite($lock_file_handle, getmypid());
  99. fclose($lock_file_handle);
  100. // Get ldap users
  101. $ldap_query = $iam_provider->query();
  102. if (!empty($iam_settings['filter'])) {
  103. $ldap_query = $ldap_query->rawFilter($iam_settings['filter']);
  104. }
  105. $response = $ldap_query->where($iam_settings['username_field'], "*")
  106. ->where($iam_settings['attribute_field'], "*")
  107. ->select([$iam_settings['username_field'], $iam_settings['attribute_field'], 'displayname'])
  108. ->paginate($max);
  109. // Process the users
  110. foreach ($response as $user) {
  111. $mailcow_template = $user[$iam_settings['attribute_field']][0];
  112. // try get mailbox user
  113. $stmt = $pdo->prepare("SELECT `mailbox`.* FROM `mailbox`
  114. INNER JOIN domain on mailbox.domain = domain.domain
  115. WHERE `kind` NOT REGEXP 'location|thing|group'
  116. AND `domain`.`active`='1'
  117. AND `username` = :user");
  118. $stmt->execute(array(':user' => $user[$iam_settings['username_field']][0]));
  119. $row = $stmt->fetch(PDO::FETCH_ASSOC);
  120. // check if matching attribute mapping exists
  121. $mbox_template = null;
  122. foreach ($iam_settings['mappers'] as $index => $mapper){
  123. if ($mapper == $mailcow_template) {
  124. $mbox_template = $iam_settings['templates'][$index];
  125. break;
  126. }
  127. }
  128. if (!$mbox_template){
  129. logMsg("warning", "No matching attribute mapping found for user " . $user[$iam_settings['username_field']][0]);
  130. continue;
  131. }
  132. if (!$row && intval($iam_settings['import_users']) == 1){
  133. // mailbox user does not exist, create...
  134. logMsg("info", "Creating user " . $user[$iam_settings['username_field']][0]);
  135. mailbox('add', 'mailbox_from_template', array(
  136. 'domain' => explode('@', $user[$iam_settings['username_field']][0])[1],
  137. 'local_part' => explode('@', $user[$iam_settings['username_field']][0])[0],
  138. 'name' => $user['displayname'][0],
  139. 'authsource' => 'ldap',
  140. 'template' => $mbox_template
  141. ));
  142. } else if ($row && intval($iam_settings['periodic_sync']) == 1) {
  143. // mailbox user does exist, sync attribtues...
  144. logMsg("info", "Syncing attributes for user " . $user[$iam_settings['username_field']][0]);
  145. mailbox('edit', 'mailbox_from_template', array(
  146. 'username' => $user[$iam_settings['username_field']][0],
  147. 'name' => $user['displayname'][0],
  148. 'template' => $mbox_template
  149. ));
  150. } else {
  151. // skip mailbox user
  152. logMsg("info", "Skipping user " . $user[$iam_settings['username_field']][0]);
  153. }
  154. sleep(0.025);
  155. }
  156. logMsg("info", "DONE!");
  157. // add last execution time to lock file
  158. $lock_file_handle = fopen($lock_file, 'w');
  159. fwrite($lock_file_handle, getmypid() . "\n" . time());
  160. fclose($lock_file_handle);
  161. session_destroy();