diff --git a/lam/HISTORY b/lam/HISTORY index 59e6384c..73091522 100644 --- a/lam/HISTORY +++ b/lam/HISTORY @@ -1,5 +1,6 @@ June 2018 - Passwords can be checked against external service (e.g. https://api.pwnedpasswords.com/range) + - IMAP: create mailbox via file upload - LAM Pro: -> Better support for 389ds password expiration diff --git a/lam/docs/manual-sources/chapter-modules.xml b/lam/docs/manual-sources/chapter-modules.xml index 1620adb6..2f676ab8 100644 --- a/lam/docs/manual-sources/chapter-modules.xml +++ b/lam/docs/manual-sources/chapter-modules.xml @@ -2132,6 +2132,10 @@ AuthorizedKeysCommandUser root When you edit an user account then you will now see the tab "Mailbox". Here you can create/delete the mailbox for this user. + Please note that mailbox creation via file upload is not possible + if you configured in LAM server profile to ask for the admin + password. + diff --git a/lam/lib/modules/imapAccess.inc b/lam/lib/modules/imapAccess.inc index 5b16d226..1ff7f3ad 100644 --- a/lam/lib/modules/imapAccess.inc +++ b/lam/lib/modules/imapAccess.inc @@ -1,10 +1,9 @@ array( "Headline" => _("Initial folders"), "Text" => _("Use this to provide a list of folders (e.g. Trash) to add for new accounts.")), + 'createMailbox' => array( + "Headline" => _("Create mailbox"), + "Text" => _('Set to "true" to create the mailbox.')), ); // configuration checks $return['config_checks']['all']['ImapAccess_ImapServerAddress'] = array ( @@ -160,20 +162,28 @@ class imapAccess extends baseModule { $this->messages['managemailbox'][6] = array('WARN', _('Your LAM login password was not accepted by the IMAP server.')); $this->messages['managemailbox'][7] = array('ERROR', _('Cannot update quota.')); $this->messages['managemailbox'][8] = array('ERROR', _('Wrong quota format. Quota must be numeric.')); + $this->messages['managemailbox'][9] = array('ERROR', _('Account %s:') . ' imapAccess_quota', _('Wrong quota format. Quota must be numeric.')); + $this->messages['createMailbox'][0] = array('ERROR', _('Account %s:') . ' imapAccess_createMailbox', _('This value can only be "true" or "false".')); } /** * Extracts user name and email address from inetOrgPerson/posixAccount/windowsUser modules. * + * @param array $attrs LDAP attributes (retrieved from other account modules if empty) * @return htmlStatusMessage message if any */ - private function extractUserAndEmail() { + private function extractUserAndEmail($attrs = null) { $this->email = ''; - if ($this->getAccountContainer()->getAccountModule('inetOrgPerson') != null) { - $attrs = $this->getAccountContainer()->getAccountModule('inetOrgPerson')->getAttributes(); - } - else { - $attrs = $this->getAccountContainer()->getAccountModule('windowsUser')->getAttributes(); + if ($attrs === null) { + if ($this->getAccountContainer()->getAccountModule('inetOrgPerson') != null) { + $attrs = $this->getAccountContainer()->getAccountModule('inetOrgPerson')->getAttributes(); + } + else { + $attrs = $this->getAccountContainer()->getAccountModule('windowsUser')->getAttributes(); + } + if ($this->getAccountContainer()->getAccountModule('posixAccount') != null) { + $attrs = array_merge($attrs, $this->getAccountContainer()->getAccountModule('posixAccount')->getAttributes()); + } } $this->email = !empty($attrs['mail'][0]) ? $attrs['mail'][0] : ''; $this->user = ''; @@ -190,13 +200,7 @@ class imapAccess extends baseModule { } // extract user name from Unix user name (might be in inetOrgPerson/windowUser or posixAccount module) else { - if ($this->getAccountContainer()->getAccountModule('posixAccount') != null) { - $attrsUnix = $this->getAccountContainer()->getAccountModule('posixAccount')->getAttributes(); - $this->user = !empty($attrsUnix['uid'][0]) ? $attrsUnix['uid'][0] : ''; - } - else { - $this->user = !empty($attrs['uid'][0]) ? $attrs['uid'][0] : ''; - } + $this->user = !empty($attrs['uid'][0]) ? $attrs['uid'][0] : ''; } if (empty($this->email)) { @@ -355,11 +359,11 @@ class imapAccess extends baseModule { } $imap_admin_password = $this->getAdminPassword(); - $mbox = 0;//default state is false + $imapConnection = 0;//default state is false if ($imap_admin_password) { - $mbox = @imap_open("{" . $imap_server_address . "}", $imap_admin_user, $imap_admin_password, OP_HALFOPEN, 1); + $imapConnection = @imap_open("{" . $imap_server_address . "}", $imap_admin_user, $imap_admin_password, OP_HALFOPEN, 1); } - if ($mbox) { + if ($imapConnection) { $this->extractUserAndEmail(); $email_domain = substr(strstr($this->email, '@'), 1); @@ -368,71 +372,115 @@ class imapAccess extends baseModule { $errors[] = $this->messages['managemailbox'][4]; } else { - if (!imap_setacl($mbox, $prefix . $this->getSep() . $this->user, $imap_admin_user, "c")) { + if (!imap_setacl($imapConnection, $prefix . $this->getSep() . $this->user, $imap_admin_user, "c")) { $errors[] = $this->messages['managemailbox'][0]; } $delete_mailbox_arg = "{" . $imap_server_address . "}" . $prefix . $this->getSep() . $this->user; - if (!@imap_deletemailbox($mbox, $delete_mailbox_arg)) { + if (!@imap_deletemailbox($imapConnection, $delete_mailbox_arg)) { $errors[] = $this->messages['managemailbox'][1]; } } } if (isset($_POST['createMailbox'])) { - if ($this->isWrongDomain($email_domain)) { - $errors[] = $this->messages['managemailbox'][4]; - } - else { - $create_mailbox_arg = "{" . $imap_server_address . "}" . $prefix . $this->getSep() . $this->user; - if (imap_createmailbox($mbox, imap_utf7_encode($create_mailbox_arg))) { - $list = imap_list($mbox, "{" . $imap_server_address . "}", $prefix . $this->getSep() . $this->user); - if (!is_array($list) || (sizeof($list) != 1)) { - $errors[] = $this->messages['managemailbox'][3]; - } - // create initial folders - foreach ($this->getInitialFolders() as $folder) { - $created = imap_createmailbox($mbox, imap_utf7_encode($create_mailbox_arg . $this->getSep() . $folder)); - if (!$created) { - $error = $this->messages['managemailbox'][2]; - $error[] = htmlspecialchars($folder); - $errors[] = $error; - } - } - } - else { - $errors[] = $this->messages['managemailbox'][2]; - } - } + $createMessages = $this->createMailbox($imapConnection, $this->user, $email_domain); + $errors = array_merge($errors, $createMessages); } if (isset($_POST['updateQuota'])) { - if ($this->isWrongDomain($email_domain)) { - $errors[] = $this->messages['managemailbox'][4]; + $quota = $_POST['ImapUserQuotaLimit']; + $quotaMessages = $this->setQuota($imapConnection, $this->user, $email_domain, $quota); + $errors = array_merge($errors, $quotaMessages); + } + imap_close($imapConnection); + } + // Return error-messages + return $errors; + } + + /** + * Creates the mailbox for a user. + * + * @param handle $imapConnection IMAP connection + * @param string $userName user name + * @param string $email_domain email domain + * @return array error messages + */ + private function createMailbox($imapConnection, $userName, $email_domain) { + $errors = array(); + $imap_server_address = $this->getServerAddress(); + $prefix = $this->getMailboxPrefix(); + if ($this->isWrongDomain($email_domain)) { + $errors[] = $this->messages['managemailbox'][4]; + } + else { + $create_mailbox_arg = "{" . $imap_server_address . "}" . $prefix . $this->getSep() . $userName; + logNewMessage(LOG_DEBUG, 'Creating mailbox: ' . $create_mailbox_arg); + if (imap_createmailbox($imapConnection, imap_utf7_encode($create_mailbox_arg))) { + logNewMessage(LOG_DEBUG, 'Mailbox created'); + $list = imap_list($imapConnection, "{" . $imap_server_address . "}", $prefix . $this->getSep() . $userName); + if (!is_array($list) || (sizeof($list) != 1)) { + $errors[] = $this->messages['managemailbox'][3]; } - else { - if (!isset($_POST['ImapUserQuotaLimit']) || ($_POST['ImapUserQuotaLimit'] == '')) { -/* deactivated because -1 is not accepted, no possibility to remove quota - * if (!imap_set_quota($mbox, $prefix . $this->getSep() . $email_username, -1)) { - $message = $this->messages['managemailbox'][7]; - $message[] = imap_last_error(); - $errors[] = $message; - }*/ - } - elseif (isset($_POST['ImapUserQuotaLimit']) && ($_POST['ImapUserQuotaLimit'] != '') && get_preg($_POST['ImapUserQuotaLimit'], 'digit')){ - if (!imap_set_quota($mbox, $prefix . $this->getSep() . $this->user, $_POST['ImapUserQuotaLimit'])) { - $message = $this->messages['managemailbox'][7]; - $message[] = imap_last_error(); - $errors[] = $message; - } + // create initial folders + foreach ($this->getInitialFolders() as $folder) { + $folderCommand = $create_mailbox_arg . $this->getSep() . $folder; + logNewMessage(LOG_DEBUG, 'Creating folder: ' . $folderCommand); + $created = imap_createmailbox($imapConnection, imap_utf7_encode($folderCommand)); + if (!$created) { + $error = $this->messages['managemailbox'][2]; + $error[] = htmlspecialchars($folder); + $errors[] = $error; } else { - $errors[] = $this->messages['managemailbox'][8]; + logNewMessage(LOG_DEBUG, 'Folder created'); } } } - imap_close($mbox); + else { + $errors[] = $this->messages['managemailbox'][2]; + } + } + return $errors; + } + + /** + * Sets the mailbox quota for a user. + * + * @param handle $imapConnection IMAP connection + * @param string $userName user name + * @param string $email_domain email domain + * @param string $quota mailbox quota + * @return array error messages + */ + private function setQuota($imapConnection, $userName, $email_domain, $quota) { + $prefix = $this->getMailboxPrefix(); + $errors = array(); + if ($this->isWrongDomain($email_domain)) { + $errors[] = $this->messages['managemailbox'][4]; + } + else { + if ($quota == '') { +/* deactivated because -1 is not accepted, no possibility to remove quota + * if (!imap_set_quota($mbox, $prefix . $this->getSep() . $email_username, -1)) { + $message = $this->messages['managemailbox'][7]; + $message[] = imap_last_error(); + $errors[] = $message; + }*/ + } + elseif (get_preg($quota, 'digit')){ + $root = $prefix . $this->getSep() . $userName; + logNewMessage(LOG_DEBUG, 'Setting quota ' . $quota . ' for ' . $root); + if (!imap_set_quota($imapConnection, $root, $quota)) { + $message = $this->messages['managemailbox'][7]; + $message[] = imap_last_error(); + $errors[] = $message; + } + } + else { + $errors[] = $this->messages['managemailbox'][8]; + } } - // Return error-messages return $errors; } @@ -703,6 +751,156 @@ class imapAccess extends baseModule { return $list; } + /** + * {@inheritDoc} + * @see baseModule::get_uploadColumns() + */ + public function get_uploadColumns($selectedModules, &$type) { + $pwd = $this->getAdminPassword(); + if (empty($pwd)) { + return array(); + } + return array( + array( + 'name' => 'imapAccess_createMailbox', + 'description' => _('Create mailbox'), + 'example' => 'false', + 'default' => 'false', + 'values' => 'true, false', + 'help' => 'createMailbox' + ), + array( + 'name' => 'imapAccess_quota', + 'description' => _('Quota limit (kB)'), + 'example' => '1000000', + 'help' => 'ImapUserQuotaLimit' + ), + ); + } + + /** + * {@inheritDoc} + * @see baseModule::build_uploadAccounts() + */ + public function build_uploadAccounts($rawAccounts, $ids, &$partialAccounts, $selectedModules, &$type) { + $errors = array(); + if (!isset($ids['imapAccess_createMailbox'])) { + return $errors; + } + for ($i = 0; $i < sizeof($rawAccounts); $i++) { + if (isset($rawAccounts[$i][$ids['imapAccess_createMailbox']]) + && !in_array($rawAccounts[$i][$ids['imapAccess_createMailbox']], array('true', 'false'))) { + $errMsg = $this->messages['createMailbox'][0]; + array_push($errMsg, array($i)); + $errors[] = $errMsg; + } + if (isset($rawAccounts[$i][$ids['imapAccess_createMailbox']]) + && ($rawAccounts[$i][$ids['imapAccess_createMailbox']] === 'true') + && !empty($ids['imapAccess_quota']) + && isset($rawAccounts[$i][$ids['imapAccess_quota']]) + && !get_preg($rawAccounts[$i][$ids['imapAccess_quota']], 'digit')) { + $errMsg = $this->messages['managemailbox'][9]; + array_push($errMsg, array($i)); + $errors[] = $errMsg; + } + } + return $errors; + } + + /** + * {@inheritDoc} + * @see baseModule::doUploadPostActions() + */ + function doUploadPostActions(&$data, $ids, $failed, &$temp, &$accounts, $selectedModules, $type) { + if (!checkIfWriteAccessIsAllowed($this->get_scope())) { + die(); + } + // on first call generate list of IMAP operations + if (!isset($temp['counter'])) { + $temp['users'] = array(); + $temp['counter'] = 0; + $errors = array(); + if (isset($ids['imapAccess_createMailbox'])) { + foreach ($data as $i => $dataRow) { + if (in_array($i, $failed)) { + continue; // ignore failed accounts + } + if ($dataRow[$ids['imapAccess_createMailbox']] === 'true') { + $limit = ''; + if (isset($ids['imapAccess_quota']) + && isset($dataRow[$ids['imapAccess_quota']]) + && ($dataRow[$ids['imapAccess_quota']] !== '')) { + $limit = $dataRow[$ids['imapAccess_quota']]; + } + $attributes = $accounts[$i]; + foreach ($attributes as $name => $value) { + if (!is_array($value)) { + $attributes[$name] = array($value); + } + } + $extractErrors = $this->extractUserAndEmail($attributes); + if (!empty($extractErrors)) { + $errors = array_merge($errors, $extractErrors); + } + $temp['users'][] = array( + 'uid' => $this->user, + 'limit' => $limit, + 'email' => substr(strstr($this->email, '@'), 1) + ); + } + } + } + return array( + 'status' => 'inProgress', + 'progress' => 0, + 'errors' => $errors + ); + } + // add mailbox + elseif ($temp['counter'] < sizeof($temp['users'])) { + $errors = array(); + $data = $temp['users'][$temp['counter']]; + $uid = $data['uid']; + $limit = $data['limit']; + $email_domain = $data['email']; + ob_start(); + $imap_server_address = $this->getServerAddress(); + $imap_admin_user = $this->getAdminUser(); + $imap_admin_password = $this->getAdminPassword(); + $imapConnection = 0;//default state is false + if ($imap_admin_password) { + $imapConnection = @imap_open("{" . $imap_server_address . "}", $imap_admin_user, $imap_admin_password, OP_HALFOPEN, 1); + $createErrors = $this->createMailbox($imapConnection, $uid, $email_domain); + $errors = array_merge($errors, $createErrors); + if (empty($createErrors)) { + $quotaErrors = $this->setQuota($imapConnection, $uid, $email_domain, $limit); + $errors = array_merge($errors, $quotaErrors); + } + } + if ($imapConnection) { + imap_close($imapConnection); + } + else { + $errors[] = $this->messages['managemailbox'][5]; + } + ob_end_clean(); + $temp['counter']++; + return array ( + 'status' => 'inProgress', + 'progress' => ($temp['counter'] * 100) / sizeof($temp['users']), + 'errors' => $errors + ); + } + // all modifications are done + else { + return array ( + 'status' => 'finished', + 'progress' => 100, + 'errors' => array() + ); + } + } + } ?>