Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 103 additions & 2 deletions lam/lib/account.inc
Original file line number Diff line number Diff line change
Expand Up @@ -1112,7 +1112,7 @@ function deleteDN($dn, $recursive): array {
}
}
// delete parent DN
$success = @ldap_delete($_SESSION['ldap']->server(), $dn);
$success = ldapDeleteEntry($_SESSION['ldap']->server(), $dn);
if (!$success) {
logNewMessage(LOG_ERR, 'Unable to delete DN: ' . $dn . ' (' . ldap_error($_SESSION['ldap']->server()) . ').');
$errors[] = ['ERROR', sprintf(_('Was unable to delete DN: %s.'), $dn), getDefaultLDAPErrorString($_SESSION['ldap']->server())];
Expand Down Expand Up @@ -1158,7 +1158,7 @@ function copyDnRecursive(string $oldDn, string $targetDn): void {
unset($attributes[$systemAttributeToSkip]);
}
}
$success = ldap_add($_SESSION['ldap']->server(), $newDn, $attributes);
$success = ldapAddNewEntry($_SESSION['ldap']->server(), $newDn, $attributes);
if (!$success) {
logNewMessage(LOG_ERR, sprintf(_('Was unable to create DN: %s.'), unescapeLdapSpecialCharacters($oldDn)) . ' ' .
getExtendedLDAPErrorMessage($_SESSION['ldap']->server()));
Expand Down Expand Up @@ -1187,6 +1187,107 @@ function moveDn(string $oldDn, string $targetDn): void {
}
}

/**
* Adds a new LDAP entry.
*
* @param Connection $connection LDAP connection
* @param string $dn DN
* @param array<string, string[]> $entry attributes
* @return bool the operation was successful
*/
function ldapAddNewEntry(Connection $connection, string $dn, array $entry): bool {
logNewMessage(LOG_DEBUG, 'Adding new entry: ' . $dn . ' with attributes: ' . json_encode($entry, JSON_PRETTY_PRINT));
logAuditMessage('Adding new entry: ' . $dn . ' with attributes: ' . json_encode($entry, JSON_PRETTY_PRINT));
$result = @ldap_add($connection, $dn, $entry);
logNewMessage(LOG_DEBUG, 'Operation ' . ($result ? 'was successful' : 'failed') . '.');
logAuditMessage('Operation ' . ($result ? 'was successful' : 'failed') . '. Server returned ' . ldap_errno($connection) . ' - ' . ldap_error($connection));
return $result;
}

/**
* Deletes an LDAP entry.
*
* @param Connection $connection connection
* @param string $dn DN
* @return bool success
*/
function ldapDeleteEntry(Connection $connection, string $dn): bool {
logNewMessage(LOG_DEBUG, 'Deleting entry: ' . $dn);
logAuditMessage('Deleting entry: ' . $dn);
$result = @ldap_delete($connection, $dn);
logNewMessage(LOG_DEBUG, 'Operation ' . ($result ? 'was successful' : 'failed') . '.');
logAuditMessage('Operation ' . ($result ? 'was successful' : 'failed') . '. Server returned ' . ldap_errno($connection) . ' - ' . ldap_error($connection));
return $result;
}

/**
* Modifies an LDAP entry.
*
* @param Connection $connection LDAP connection
* @param string $dn DN
* @param array<string, string[]|string> $attributes attributes to add
* @return bool the operation was successful
*/
function ldapAddAttributes(Connection $connection, string $dn, array $attributes): bool {
logNewMessage(LOG_DEBUG, 'Adding new attributes to ' . $dn . ': ' . json_encode($attributes, JSON_PRETTY_PRINT));
logAuditMessage('Adding new attributes to ' . $dn . ': ' . json_encode($attributes, JSON_PRETTY_PRINT));
$result = @ldap_mod_add($connection, $dn, $attributes);
logNewMessage(LOG_DEBUG, 'Operation ' . ($result ? 'was successful' : 'failed') . '.');
logAuditMessage('Operation ' . ($result ? 'was successful' : 'failed') . '. Server returned ' . ldap_errno($connection) . ' - ' . ldap_error($connection));
return $result;
}

/**
* Modifies an LDAP entry.
*
* @param Connection $connection LDAP connection
* @param string $dn DN
* @param array<string, string[]|string> $attributes attributes to remove
* @return bool the operation was successful
*/
function ldapDeleteAttributes(Connection $connection, string $dn, array $attributes): bool {
logNewMessage(LOG_DEBUG, 'Removing attributes from ' . $dn . ': ' . json_encode($attributes, JSON_PRETTY_PRINT));
logAuditMessage('Removing attributes from ' . $dn . ': ' . json_encode($attributes, JSON_PRETTY_PRINT));
$result = @ldap_mod_del($connection, $dn, $attributes);
logNewMessage(LOG_DEBUG, 'Operation ' . ($result ? 'was successful' : 'failed') . '.');
logAuditMessage('Operation ' . ($result ? 'was successful' : 'failed') . '. Server returned ' . ldap_errno($connection) . ' - ' . ldap_error($connection));
return $result;
}

/**
* Modifies an LDAP entry.
*
* @param Connection $connection LDAP connection
* @param string $dn DN
* @param array<string, string[]|string> $attributes attributes to change
* @return bool the operation was successful
*/
function ldapModifyAttributes(Connection $connection, string $dn, array $attributes): bool {
logNewMessage(LOG_DEBUG, 'Replacing attributes in ' . $dn . ': ' . json_encode($attributes, JSON_PRETTY_PRINT));
logAuditMessage('Replacing attributes in ' . $dn . ': ' . json_encode($attributes, JSON_PRETTY_PRINT));
$result = @ldap_mod_replace($connection, $dn, $attributes);
logNewMessage(LOG_DEBUG, 'Operation ' . ($result ? 'was successful' : 'failed') . '.');
logAuditMessage('Operation ' . ($result ? 'was successful' : 'failed') . '. Server returned ' . ldap_errno($connection) . ' - ' . ldap_error($connection));
return $result;
}

/**
* Modifies an LDAP entry.
*
* @param Connection $connection LDAP connection
* @param string $dn DN
* @param array<string, string[]|string|int>[] $attributes attribute operations to perform in batch mode
* @return bool the operation was successful
*/
function ldapModifyAttributesBatch(Connection $connection, string $dn, array $attributes): bool {
logNewMessage(LOG_DEBUG, 'Replacing attributes in ' . $dn . ': ' . json_encode($attributes, JSON_PRETTY_PRINT));
logAuditMessage('Replacing attributes in ' . $dn . ': ' . json_encode($attributes, JSON_PRETTY_PRINT));
$result = @ldap_modify_batch($connection, $dn, $attributes, getCommonLdapControls());
logNewMessage(LOG_DEBUG, 'Operation ' . ($result ? 'was successful' : 'failed') . '.');
logAuditMessage('Operation ' . ($result ? 'was successful' : 'failed') . '. Server returned ' . ldap_errno($connection) . ' - ' . ldap_error($connection));
return $result;
}

/**
* Returns the parameters for a StatusMessage of the last LDAP search.
*
Expand Down
40 changes: 35 additions & 5 deletions lam/lib/config.inc
Original file line number Diff line number Diff line change
Expand Up @@ -2893,6 +2893,12 @@ class LAMCfgMain {
/** log destination ("SYSLOG":syslog, "/...":file, "NONE":none, "REMOTE":server:port) */
public string $logDestination = "SYSLOG";

/** type of audit log */
public string $auditLogType = 'NONE';

/** target of audit log */
public string $auditLogTarget = '';

/** list of hosts which may access LAM */
public string $allowedHosts = "";

Expand Down Expand Up @@ -3034,6 +3040,7 @@ class LAMCfgMain {
/** @var string[] $settings list of data fields to save in config file */
private array $settings = ["password", "default", "sessionTimeout", "hideLoginErrorDetails",
"logLevel", "logDestination", "allowedHosts", "passwordMinLength",
'auditLogType', 'auditLogTarget',
"passwordMinUpper", "passwordMinLower", "passwordMinNumeric",
"passwordMinClasses", "passwordMinSymbol", 'checkedRulesCount',
'passwordMustNotContainUser', 'passwordMustNotContain3Chars',
Expand Down Expand Up @@ -3703,11 +3710,34 @@ class LAMCfgMain {
* @return bool is valid
*/
public static function isValidLogFilename(string $path): bool {
return !empty($path)
&& preg_match("/^[a-z0-9\\/._-]+$/i", $path)
&& (str_ends_with($path, '.log') || str_ends_with($path, '.txt'))
&& !str_contains($path, '..')
&& !str_starts_with($path, './');
$realPath = file_exists($path) ? realpath($path) : $path;
$blockedPrefixes = ['/usr', '/etc', '/dev', '/boot', '/lib', '/proc', '/root', '/run', '/sys', '/snap'];
if (!empty($_SERVER['DOCUMENT_ROOT'])) {
$blockedPrefixes[] = $_SERVER['DOCUMENT_ROOT'];
}
foreach ($blockedPrefixes as $blockedPrefix) {
if (str_starts_with($realPath, $blockedPrefix)) {
return false;
}
}
return !empty($realPath)
&& preg_match("/^[a-z0-9\\/._-]+$/i", $realPath)
&& (str_ends_with($realPath, '.log') || str_ends_with($realPath, '.txt'))
&& !str_contains($realPath, '..')
&& !str_starts_with($realPath, './');
}

}

enum LOG_FILE_TARGET: string {

/** audit log entries are sent to file */
case FILE = 'FILE';
/** audit log entries are sent to remote server */
case REMOTE = 'REMOTE';
/** audit log entries are sent to syslog */
case SYSLOG = 'SYSLOG';
/** audit log is disabled */
case NONE = 'NONE';

}
12 changes: 6 additions & 6 deletions lam/lib/import.inc
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ class AddEntryTask implements ImporterTask {
*/
public function run(): string {
$ldap = $_SESSION['ldap']->server();
$success = @ldap_add($ldap, $this->dn, $this->attributes);
$success = ldapAddNewEntry($ldap, $this->dn, $this->attributes);
if ($success) {
return Importer::formatMessage('INFO', _('Entry created'), htmlspecialchars($this->dn));
}
Expand Down Expand Up @@ -533,7 +533,7 @@ class DeleteEntryTask implements ImporterTask {
*/
public function run(): string {
$ldap = $_SESSION['ldap']->server();
$success = @ldap_delete($ldap, $this->dn);
$success = ldapDeleteEntry($ldap, $this->dn);
if ($success) {
return Importer::formatMessage('INFO', sprintf(_('Successfully deleted DN %s'), $this->dn), '');
}
Expand Down Expand Up @@ -620,7 +620,7 @@ class AddAttributesTask implements ImporterTask {
*/
public function run(): string {
$ldap = $_SESSION['ldap']->server();
$success = @ldap_mod_add($ldap, $this->dn, $this->attributes);
$success = ldapAddAttributes($ldap, $this->dn, $this->attributes);
if ($success) {
return '';
}
Expand Down Expand Up @@ -679,10 +679,10 @@ class DeleteAttributesTask implements ImporterTask {
public function run(): string {
$ldap = $_SESSION['ldap']->server();
if (!empty($this->attributes)) {
$success = @ldap_mod_del($ldap, $this->dn, $this->attributes);
$success = ldapDeleteAttributes($ldap, $this->dn, $this->attributes);
}
else {
$success = @ldap_modify($ldap, $this->dn, [$this->attributeName => []]);
$success = ldapModifyAttributes($ldap, $this->dn, [$this->attributeName => []]);
}
if ($success) {
return '';
Expand Down Expand Up @@ -747,7 +747,7 @@ class ReplaceAttributesTask implements ImporterTask {
*/
public function run(): string {
$ldap = $_SESSION['ldap']->server();
$success = @ldap_modify($ldap, $this->dn, $this->attributes);
$success = ldapModifyAttributes($ldap, $this->dn, $this->attributes);
if ($success) {
return '';
}
Expand Down
8 changes: 4 additions & 4 deletions lam/lib/modules.inc
Original file line number Diff line number Diff line change
Expand Up @@ -1988,7 +1988,7 @@ class accountContainer {
if (isset($attributes[$this->finalDN]['modify']) && is_array($attributes[$this->finalDN]['modify'])) {
$attr = array_merge_recursive($attr, $attributes[$this->finalDN]['modify']);
}
$success = @ldap_add($_SESSION['ldap']->server(), $this->finalDN, $attr);
$success = ldapAddNewEntry($_SESSION['ldap']->server(), $this->finalDN, $attr);
if (!$success) {
logNewMessage(LOG_ERR, 'Unable to create DN: ' . $this->finalDN . ' (' . ldap_error($_SESSION['ldap']->server()) . '). '
. getExtendedLDAPErrorMessage($_SESSION['ldap']->server()));
Expand All @@ -2007,7 +2007,7 @@ class accountContainer {
logNewMessage(LOG_DEBUG, 'Attribute changes for ' . $DNs[$i] . ":\n" . print_r($attributes[$DNs[$i]], true));
// modify attributes
if (!empty($attributes[$DNs[$i]]['modify'])) {
$success = @ldap_mod_replace($_SESSION['ldap']->server(), $DNs[$i], $attributes[$DNs[$i]]['modify']);
$success = ldapModifyAttributes($_SESSION['ldap']->server(), $DNs[$i], $attributes[$DNs[$i]]['modify']);
if (!$success) {
logNewMessage(LOG_ERR, 'Unable to modify attributes of DN: ' . $DNs[$i] . ' (' . ldap_error($_SESSION['ldap']->server()) . '). '
. getExtendedLDAPErrorMessage($_SESSION['ldap']->server()));
Expand All @@ -2026,7 +2026,7 @@ class accountContainer {
}
// add attributes
if (!empty($attributes[$DNs[$i]]['add']) && !$stopprocessing) {
$success = @ldap_mod_add($_SESSION['ldap']->server(), $DNs[$i], $attributes[$DNs[$i]]['add']);
$success = ldapAddAttributes($_SESSION['ldap']->server(), $DNs[$i], $attributes[$DNs[$i]]['add']);
if (!$success) {
logNewMessage(LOG_ERR, 'Unable to add attributes to DN: ' . $DNs[$i] . ' (' . ldap_error($_SESSION['ldap']->server()) . '). '
. getExtendedLDAPErrorMessage($_SESSION['ldap']->server()));
Expand All @@ -2039,7 +2039,7 @@ class accountContainer {
}
// remove attributes
if (!empty($attributes[$DNs[$i]]['remove']) && !$stopprocessing) {
$success = @ldap_mod_del($_SESSION['ldap']->server(), $DNs[$i], $attributes[$DNs[$i]]['remove']);
$success = ldapDeleteAttributes($_SESSION['ldap']->server(), $DNs[$i], $attributes[$DNs[$i]]['remove']);
if (!$success) {
logNewMessage(LOG_ERR, 'Unable to delete attributes from DN: ' . $DNs[$i] . ' (' . ldap_error($_SESSION['ldap']->server()) . '). '
. getExtendedLDAPErrorMessage($_SESSION['ldap']->server()));
Expand Down
10 changes: 5 additions & 5 deletions lam/lib/modules/asteriskExtension.inc
Original file line number Diff line number Diff line change
Expand Up @@ -879,29 +879,29 @@ class asteriskExtension extends baseModule {
}
if (!empty($ldapChanges)) {
if (!isset($ldapChanges['cn'])) {
ldap_mod_replace($_SESSION['ldap']->server(), "cn=" . $row["cn"][0] . "," . $this->getAccountContainer()->dnSuffix, $ldapChanges);
ldapModifyAttributes($_SESSION['ldap']->server(), "cn=" . $row["cn"][0] . "," . $this->getAccountContainer()->dnSuffix, $ldapChanges);
}
else {
$origDN = "cn=" . $rowOrig["cn"][0] . "," . extractDNSuffix($this->getAccountContainer()->dn_orig);
$newRDN = "cn=" . $row["cn"][0];
ldap_rename($_SESSION['ldap']->server(), $origDN, $newRDN, extractDNSuffix($this->getAccountContainer()->dn_orig), true);
unset($ldapChanges['cn']);
if (!empty($ldapChanges)) {
ldap_mod_replace($_SESSION['ldap']->server(), $newRDN . "," . extractDNSuffix($this->getAccountContainer()->dn_orig), $ldapChanges);
ldapModifyAttributes($_SESSION['ldap']->server(), $newRDN . "," . extractDNSuffix($this->getAccountContainer()->dn_orig), $ldapChanges);
}
}
}
// if new suffix just move old rows to the new suffix and go on
$this->moveExtentionToNewSuffix($row);
}
else {
ldap_delete($_SESSION['ldap']->server(), "cn=" . $rowOrig["cn"][0] . "," . extractDNSuffix($this->getAccountContainer()->dn_orig));
ldapDeleteEntry($_SESSION['ldap']->server(), "cn=" . $rowOrig["cn"][0] . "," . extractDNSuffix($this->getAccountContainer()->dn_orig));
}
}
// add new config rows
for ($rowCounter = count($this->extensionRowsOrig); $rowCounter < count($this->extensionRows); $rowCounter++) {
$row = $this->extensionRows[$rowCounter];
ldap_add($_SESSION['ldap']->server(), "cn=" . $row["cn"][0] . "," . $this->getAccountContainer()->dnSuffix, $row);
ldapAddNewEntry($_SESSION['ldap']->server(), "cn=" . $row["cn"][0] . "," . $this->getAccountContainer()->dnSuffix, $row);
}

//a trick for Edit again to work
Expand All @@ -925,7 +925,7 @@ class asteriskExtension extends baseModule {
for ($rowCounter = 0; $rowCounter < count($entries); $rowCounter++) {
$rowOrig = $entries[$rowCounter];
if ($rowOrig["astpriority"][0] > 1) {
ldap_delete($_SESSION['ldap']->server(), $rowOrig['dn']);
ldapDeleteEntry($_SESSION['ldap']->server(), $rowOrig['dn']);
}
}
return [];
Expand Down
16 changes: 8 additions & 8 deletions lam/lib/modules/fixed_ip.inc
Original file line number Diff line number Diff line change
Expand Up @@ -672,32 +672,32 @@ class fixed_ip extends baseModule {
}

foreach ($delete as $cn) {
ldap_delete($_SESSION['ldap']->server(), 'cn=' . $cn . $ldapSuffix);
ldapDeleteEntry($_SESSION['ldap']->server(), 'cn=' . $cn . $ldapSuffix);
}

foreach ($add as $arr) {
$attr = [];
$attr['cn'] = $arr['cn'];
$attr['objectClass'][0] = 'top';
$attr['objectClass'][1] = 'dhcpHost';
$attr['dhcpHWAddress'] = 'ethernet ' . $arr['mac'];
$attr['cn'][] = $arr['cn'];
$attr['objectClass'][] = 'top';
$attr['objectClass'][] = 'dhcpHost';
$attr['dhcpHWAddress'][] = 'ethernet ' . $arr['mac'];
if ($arr['ip'] != '') {
$attr['dhcpStatements'][] = 'fixed-address ' . $arr['ip'];
}
if ($arr['active'] === false) {
$attr['dhcpStatements'][] = 'deny booting';
}
$attr['dhcpOption'] = 'host-name "' . $arr['cn'] . '"';
$attr['dhcpOption'][] = 'host-name "' . $arr['cn'] . '"';
if (!empty($arr['description'])) {
$attr['dhcpComments'][] = $arr['description'];
}
if ($attr['cn'] != "") {
ldap_add($_SESSION['ldap']->server(), 'cn=' . $arr['cn'] . $ldapSuffix, $attr);
ldapAddNewEntry($_SESSION['ldap']->server(), 'cn=' . $arr['cn'] . $ldapSuffix, $attr);
}
}
// entries to modify
foreach ($mod as $dn => $attrs) {
ldap_modify($_SESSION['ldap']->server(), $dn, $attrs);
ldapModifyAttributes($_SESSION['ldap']->server(), $dn, $attrs);
}
}
return [];
Expand Down
8 changes: 4 additions & 4 deletions lam/lib/modules/inetOrgPerson.inc
Original file line number Diff line number Diff line change
Expand Up @@ -912,9 +912,9 @@ class inetOrgPerson extends baseModule implements passwordService, AccountStatus
if (empty($result)) {
$attrs = [
'objectClass' => ['organizationalUnit'],
'ou' => 'addressbook'
'ou' => ['addressbook']
];
$success = @ldap_add($_SESSION['ldap']->server(), $dn, $attrs);
$success = ldapAddNewEntry($_SESSION['ldap']->server(), $dn, $attrs);
if (!$success) {
logNewMessage(LOG_ERR, 'Unable to add addressbook for user ' . $accountContainer->finalDN . ' (' . ldap_error($_SESSION['ldap']->server()) . ').');
$messages[] = ['ERROR', sprintf(_("Was unable to create DN: %s."), htmlspecialchars($dn)), getDefaultLDAPErrorString($_SESSION['ldap']->server())];
Expand Down Expand Up @@ -2584,10 +2584,10 @@ class inetOrgPerson extends baseModule implements passwordService, AccountStatus
if ($this->isBooleanConfigOptionSet('inetOrgPerson_addAddressbook')) {
$attrs = [
'objectClass' => ['organizationalUnit'],
'ou' => 'addressbook'
'ou' => ['addressbook']
];
$dn = 'ou=addressbook,' . $accounts[$temp['counter']]['dn'];
$success = @ldap_add($_SESSION['ldap']->server(), $dn, $attrs);
$success = ldapAddNewEntry($_SESSION['ldap']->server(), $dn, $attrs);
if (!$success) {
logNewMessage(LOG_ERR, 'Unable to add addressbook for user ' . $accounts[$temp['counter']]['dn'] . ' (' . ldap_error($_SESSION['ldap']->server()) . ').');
$errors[] = ['ERROR', sprintf(_("Was unable to create DN: %s."), htmlspecialchars($dn)), getDefaultLDAPErrorString($_SESSION['ldap']->server())];
Expand Down
Loading
Loading