#457 added logon hours

This commit is contained in:
Roland Gruber 2025-08-25 20:19:02 +02:00
parent b460f80232
commit e894abf0ed
2 changed files with 110 additions and 1 deletions

View file

@ -1,5 +1,6 @@
September 2025 9.3 September 2025 9.3
- Tree view: added comparison feature (440) - Tree view: added comparison feature (440)
- Windows: added logon hours (457)
- Lamdaemon: run /usr/sbin/userdel.local before (and no longer after) home directory is deleted (443) - Lamdaemon: run /usr/sbin/userdel.local before (and no longer after) home directory is deleted (443)
- LAM Pro: - LAM Pro:
-> SMS support for password sending and password self-reset (441) -> SMS support for password sending and password self-reset (441)

View file

@ -64,6 +64,11 @@ class windowsUser extends baseModule implements passwordService, AccountStatusPr
'pwdLastSet', 'lastLogonTimestamp', 'accountexpires', 'lockouttime', 'personaltitle', 'roomnumber', 'pwdLastSet', 'lastLogonTimestamp', 'accountexpires', 'lockouttime', 'personaltitle', 'roomnumber',
'jpegPhoto', 'thumbnailphoto']; 'jpegPhoto', 'thumbnailphoto'];
/** HEX to binary conversion table */
private const HEX2BIT_STRING = ['0' => '0000', '1' => '0001', '2' => '0010', '3' => '0011', '4' => '0100',
'5' => '0101', '6' => '0110', '7' => '0111', '8' => '1000', '9' => '1001', 'a' => '1010',
'b' => '1011', 'c' => '1100', 'd' => '1101', 'e' => '1110', 'f' => '1111'];
/** initial account flags */ /** initial account flags */
private const DEFAULT_ACCOUNT_CONTROL = 0x00000200; private const DEFAULT_ACCOUNT_CONTROL = 0x00000200;
/** password never expires */ /** password never expires */
@ -154,7 +159,7 @@ class windowsUser extends baseModule implements passwordService, AccountStatusPr
'lastLogonTimestamp', 'accountexpires', 'jpegPhoto', 'title', 'carLicense', 'employeeNumber', 'employeeType', 'lastLogonTimestamp', 'accountexpires', 'jpegPhoto', 'title', 'carLicense', 'employeeNumber', 'employeeType',
'businessCategory', 'department', 'departmentNumber', 'ou', 'o', 'manager', 'facsimileTelephoneNumber', 'company', 'businessCategory', 'department', 'departmentNumber', 'ou', 'o', 'manager', 'facsimileTelephoneNumber', 'company',
'pager', 'otherPager', 'mobile', 'otherMobile', 'proxyAddresses', 'lockouttime', 'userWorkstations', 'roomnumber', 'pager', 'otherPager', 'mobile', 'otherMobile', 'proxyAddresses', 'lockouttime', 'userWorkstations', 'roomnumber',
'personaltitle', 'thumbnailphoto' 'personaltitle', 'thumbnailphoto', 'logonhours'
]; ];
$return['hiddenAttributes'] = ['msds-userpasswordexpirytimecomputed']; $return['hiddenAttributes'] = ['msds-userpasswordexpirytimecomputed'];
// help Entries // help Entries
@ -328,6 +333,10 @@ class windowsUser extends baseModule implements passwordService, AccountStatusPr
"Headline" => _('Last login'), 'attr' => 'lastLogonTimestamp', "Headline" => _('Last login'), 'attr' => 'lastLogonTimestamp',
"Text" => _('Time of user\'s last login.') "Text" => _('Time of user\'s last login.')
], ],
"logonhours" => [
"Headline" => _("Logon hours"), 'attr' => 'logonHours',
"Text" => _("This option defines the allowed logon hours for this account.")
],
'accountexpires' => [ 'accountexpires' => [
"Headline" => _('Account expiration date'), 'attr' => 'accountExpires', "Headline" => _('Account expiration date'), 'attr' => 'accountExpires',
"Text" => _('This is the date when the account will expire.') "Text" => _('This is the date when the account will expire.')
@ -1611,6 +1620,14 @@ class windowsUser extends baseModule implements passwordService, AccountStatusPr
$userWorkstationsGroup->addElement(new htmlHelpLink('userWorkstations')); $userWorkstationsGroup->addElement(new htmlHelpLink('userWorkstations'));
$containerLeft->addField($userWorkstationsGroup); $containerLeft->addField($userWorkstationsGroup);
} }
if (!$this->isBooleanConfigOptionSet('windowsUser_hidelogonHours')) {
$containerLeft->addLabel(new htmlOutputText(_('Logon hours')));
$logonHoursGroup = new htmlGroup();
$logonHoursGroup->addElement(new htmlAccountPageButton(static::class, 'logonHours', 'open', _('Edit')));
$logonHoursGroup->addElement(new htmlSpacer('0.5rem', null));
$logonHoursGroup->addElement(new htmlHelpLink('logonhours'));
$containerLeft->addField($logonHoursGroup);
}
// user profile area // user profile area
$showProfilePath = !$this->isBooleanConfigOptionSet('windowsUser_hideprofilePath'); $showProfilePath = !$this->isBooleanConfigOptionSet('windowsUser_hideprofilePath');
$showScriptPath = !$this->isBooleanConfigOptionSet('windowsUser_hidescriptPath'); $showScriptPath = !$this->isBooleanConfigOptionSet('windowsUser_hidescriptPath');
@ -2845,6 +2862,96 @@ class windowsUser extends baseModule implements passwordService, AccountStatusPr
return []; return [];
} }
/**
* This function will create the HTML page to edit logon hours.
*
* @return htmlElement meta HTML code
*/
function display_html_logonHours() {
$return = new htmlResponsiveRow();
$timeZone = getTimeZoneOffsetHours();
$titles = [_('Time'), _('Monday'), _('Tuesday'), _('Wednesday'), _('Thursday'),
_('Friday'), _('Saturday'), _('Sunday')];
$data = [];
if (!isset($this->attributes['logonhours'][0]) || ($this->attributes['logonhours'][0] === '')) {
$this->attributes['logonhours'][0] = pack( 'H*', 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF');
}
// convert the existing logonHours string to a bit array
$logonHoursHex = unpack('H*', $this->attributes['logonhours'][0])[1];
$logonHoursDual = '';
for ($i = 0; $i < strlen($logonHoursHex); $i++) {
$logonHoursDual .= self::HEX2BIT_STRING[$logonHoursHex[$i]];
}
// reverse bits low to high (1 is 0:00 Sunday, 2 is 1:00 Sunday, etc.)
$logonHours = "";
for ($i = 0; $i < 21; $i++) {
$logonHours .= strrev(substr($logonHoursDual, $i * 8, 8));
}
$hour = [];
for ($i = 0; $i < 24 * 7; $i++) {
$hour[$i] = substr($logonHours, $i, 1);
}
// display input
$boxes = [];
// dynamically place boxes depending on time zone
for ($i = 0; $i < 24 * 7; $i++) {
$hr = $i - $timeZone;
if ($hr < 0) {
$hr += 24 * 7;
}
elseif ($hr >= 24 * 7) {
$hr -= 24 * 7;
}
$checkbox = new htmlInputCheckbox('lh_' . $hr, $hour[$hr]);
$boxes[$i % 24][floor($i / 24)] = $checkbox;
}
for ($h = 0; $h < 24; $h++) {
$hour = str_pad($h, 2, '0', STR_PAD_LEFT);
$row = [];
$row[] = new htmlOutputText("$hour:00 - " . str_pad($h + 1, 2, '0', STR_PAD_LEFT) . ":00");
for ($d = 1; $d < 7; $d++) {
$row[] = $boxes[$h][$d];
}
$row[] = $boxes[$h][0]; // Sunday goes last
$data[] = $row;
}
$return->add(new htmlResponsiveTable($titles, $data));
$return->addVerticalSpacer('2rem');
$return->addLabel(new htmlAccountPageButton(static::class, 'attributes', 'submit', _('Ok')));
$return->addField(new htmlAccountPageButton(static::class, 'attributes', 'abort', _('Cancel')));
return $return;
}
/**
* Processes user input of the logon hours page.
* It checks if all input values are correct and updates the associated LDAP attributes.
*
* @return array list of info/error messages
*/
function process_logonHours() {
if (isset($_POST['form_subpage_sambaSamAccount_attributes_abort'])) {
return [];
}
// set new logon hours
$logonHours = '';
for ($i = 0; $i < 24 * 7; $i++) {
$logonHours .= isset($_POST['lh_' . $i]) ? '1' : '0';
}
// reconstruct HEX string
$bitstring2hex = array_flip(self::HEX2BIT_STRING);
$logonHoursNew = '';
for ($i = 0; $i < 21; $i++) {
$part = strrev(substr($logonHours, $i * 8, 8));
$byte['hi'] = substr($part, 0, 4);
$byte['low'] = substr($part, 4, 4);
$hex = $bitstring2hex[$byte['hi']] . $bitstring2hex[$byte['low']];
$logonHoursNew .= $hex;
}
$this->attributes['logonhours'][0] = pack('H*', $logonHoursNew);
return [];
}
/** /**
* Returns a list of existing hosts. * Returns a list of existing hosts.
* *
@ -4354,6 +4461,7 @@ class windowsUser extends baseModule implements passwordService, AccountStatusPr
$hiddenOptions[_('Last password change')] = ['windowsUser_hidepwdLastSet', false]; $hiddenOptions[_('Last password change')] = ['windowsUser_hidepwdLastSet', false];
$hiddenOptions[_('Password expiration')] = ['windowsUser_hidepwdChangeRequired', false]; $hiddenOptions[_('Password expiration')] = ['windowsUser_hidepwdChangeRequired', false];
$hiddenOptions[_('Last login')] = ['windowsUser_hidelastLogonTimestamp', false]; $hiddenOptions[_('Last login')] = ['windowsUser_hidelastLogonTimestamp', false];
$hiddenOptions[_('Logon hours')] = ['windowsUser_hidelogonHours', false];
$hiddenOptions[_('Workstations')] = ['windowsUser_hideWorkstations', false]; $hiddenOptions[_('Workstations')] = ['windowsUser_hideWorkstations', false];
$hiddenOptions[_('Photo')] = ['windowsUser_hidejpegPhoto', true]; $hiddenOptions[_('Photo')] = ['windowsUser_hidejpegPhoto', true];
$hiddenOptions[_('Thumbnail')] = ['windowsUser_hidethumbnailphoto', true]; $hiddenOptions[_('Thumbnail')] = ['windowsUser_hidethumbnailphoto', true];