From 1cbdbc73970008ff9c193066d9e55f2d775b90b5 Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Fri, 6 Apr 2012 13:12:43 +0000 Subject: [PATCH] allow to display account locking status --- lam/graphics/partiallyLocked.png | Bin 0 -> 3461 bytes lam/graphics/unlocked.png | Bin 0 -> 760 bytes lam/lib/lists.inc | 59 +++++++-- lam/lib/types/user.inc | 220 ++++++++++++++++++++++++++++++- 4 files changed, 267 insertions(+), 12 deletions(-) create mode 100644 lam/graphics/partiallyLocked.png create mode 100644 lam/graphics/unlocked.png diff --git a/lam/graphics/partiallyLocked.png b/lam/graphics/partiallyLocked.png new file mode 100644 index 0000000000000000000000000000000000000000..0414b21b5f6d5e185bd30223292f61a010f2bc86 GIT binary patch literal 3461 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 literal 0 HcmV?d00001 diff --git a/lam/graphics/unlocked.png b/lam/graphics/unlocked.png new file mode 100644 index 0000000000000000000000000000000000000000..9189185139dcd2956ae519b224ed4a9347629e7d GIT binary patch literal 760 zcmVPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iyb( z3<)rY!u@Fg00MYPL_t(I%gvI{OB7)k$3O4Ptgh>>3Mq@UDHdB^pADdNi-TE6bjJS*I(V*dZsHHjdX-UfeL`q zQh%bT$he!!*)Mc}VDJo%^Buq6q`kcj(>#jbuhH1p5om93>oLuv-G0BOSyp;d*TqI8 zQdM7G9z5&w88dpY^t3OX8S}PoaFwQ}7?!oc;NU3HXzj74rq~V3+Nc~H9PJ$#7`Yvf z&%FV!uD-tZh@op3zLE+b8C-x+c?cmK5{Wsc;tL!+bf8QKr!z;kI$WNoK7U> z86E%nJY#DuxvaC#SWCX%+_}TbI{ZxeNZW#mWF6&U?Cn}jBrqaNOqti)!^t;KJn7$~a`M1AmqQjK!68MfNRX(GuwTE|GW& zw3I`7Y?Jxf5~q;3jO2$%tK4M-~z7PhDbnxP!#12G*4*-0n@YI^!v q9&EYViqb~0000oeZ literal 0 HcmV?d00001 diff --git a/lam/lib/lists.inc b/lam/lib/lists.inc index c7a8dc01..57b8a2aa 100644 --- a/lam/lib/lists.inc +++ b/lam/lib/lists.inc @@ -94,6 +94,9 @@ class lamList { /** ID for list size config option */ const LIST_SIZE_OPTION_NAME = "L_SIZE"; + /** prefix for virtual (non-LDAP) attributes */ + const VIRTUAL_ATTRIBUTE_PREFIX = 'lam_virtual_'; + /** * Constructor * @@ -345,19 +348,33 @@ class lamList { echo "\n"; // print input boxes for filters for ($k = 0; $k < sizeof ($this->descArray); $k++) { - $value = ""; - if (isset($_GET["filter" . strtolower($this->attrArray[$k])])) { - $value = " value=\"" . $_GET["filter" . strtolower($this->attrArray[$k])] . "\""; - } - if (isset($_POST["filter" . strtolower($this->attrArray[$k])])) { - $value = " value=\"" . $_POST["filter" . strtolower($this->attrArray[$k])] . "\""; - } echo ""; - echo "attrArray[$k]) ."\"" . $value . " onkeypress=\"SubmitForm('apply_filter', event);\">"; + if ($this->canBeFiltered($this->attrArray[$k])) { + $value = ""; + if (isset($_GET["filter" . strtolower($this->attrArray[$k])])) { + $value = " value=\"" . $_GET["filter" . strtolower($this->attrArray[$k])] . "\""; + } + if (isset($_POST["filter" . strtolower($this->attrArray[$k])])) { + $value = " value=\"" . $_POST["filter" . strtolower($this->attrArray[$k])] . "\""; + } + echo "attrArray[$k]) ."\"" . $value . " onkeypress=\"SubmitForm('apply_filter', event);\">"; + } echo "\n"; } echo "\n"; } + + /** + * Returns if the given attribute can be filtered. + * If filtering is not possible then no filter box will be displayed. + * By default all attributes can be filtered. + * + * @param String $attr attribute name + * @return boolean filtering possible + */ + protected function canBeFiltered($attr) { + return true; + } /** * Prints the entry list @@ -751,7 +768,7 @@ class lamList { * * @return array attribute list */ - private function listGetAttributeDescriptionList() { + protected function listGetAttributeDescriptionList() { $ret = array(); $attr_string = $_SESSION["config"]->get_listAttributes($this->type); $temp_array = explode(";", $attr_string); @@ -836,6 +853,20 @@ class lamList { $module_filter = get_ldap_filter($this->type); // basic filter is provided by modules $filter = "(&" . $module_filter . $this->filterPart . ")"; $attrs = $this->attrArray; + // remove virtual attributes from list + for ($i = 0; $i < sizeof($attrs); $i++) { + if (strpos($attrs[$i], self::VIRTUAL_ATTRIBUTE_PREFIX) === 0) { + unset($attrs[$i]); + } + } + $attrs = array_values($attrs); + // include additional attributes + $additionalAttrs = $this->getAdditionalLDAPAttributesToRead(); + for ($i = 0; $i < sizeof($additionalAttrs); $i++) { + if (!in_array_ignore_case($additionalAttrs[$i], $attrs)) { + $attrs[] = $additionalAttrs[$i]; + } + } $this->entries = searchLDAP($this->suffix, $filter, $attrs); $lastError = getLastLDAPError(); if ($lastError != null) { @@ -846,6 +877,16 @@ class lamList { $this->possibleSuffixes = $typeObj->getSuffixList(); } + /** + * Returns a list of additional LDAP attributes that should be read. + * This can be used to show additional data even if the user selected other attributes to show in the list. + * + * @return array additional attribute names + */ + protected function getAdditionalLDAPAttributesToRead() { + return array(); + } + /** * Returns a list of lamListTool objects to display next to the edit/delete buttons. * diff --git a/lam/lib/types/user.inc b/lam/lib/types/user.inc index 065fa14b..56965541 100644 --- a/lam/lib/types/user.inc +++ b/lam/lib/types/user.inc @@ -178,13 +178,21 @@ class lamUserList extends lamList { /** Controls if GID number is translated to group name */ private $trans_primary = false; + + /** Controls if the account status is shown */ + private $showAccountStatus = false; /** translates GID to group name */ private $trans_primary_hash = array(); - /** ID for config option */ + /** ID for config option to translate primary group GIDs to group names */ const TRANS_PRIMARY_OPTION_NAME = "LU_TP"; - + /** ID for config option to show account status */ + const ACCOUNT_STATUS_OPTION_NAME = "LU_AS"; + + /** virtual attribute name for account status column */ + const ATTR_ACCOUNT_STATUS = 'lam_virtual_account_status'; + /** * Constructor * @@ -219,6 +227,9 @@ class lamUserList extends lamList { if ($this->trans_primary == "on") { $this->refreshPrimaryGroupTranslation(); } + if ($this->showAccountStatus) { + $this->injectAccountStatusAttribute(); + } } /** @@ -243,7 +254,9 @@ class lamUserList extends lamList { */ protected function listPrintTableCellContent(&$entry, &$attribute) { // check if there is something to display at all - if (!isset($entry[$attribute]) || !is_array($entry[$attribute]) || (sizeof($entry[$attribute]) < 1)) return; + if (($attribute != self::ATTR_ACCOUNT_STATUS) && (!isset($entry[$attribute]) || !is_array($entry[$attribute]) || (sizeof($entry[$attribute]) < 1))) { + return; + } // translate GID to group name if (($attribute == "gidnumber") && ($this->trans_primary == "on")) { if (isset($this->trans_primary_hash[$entry[$attribute][0]])) { @@ -310,6 +323,10 @@ class lamUserList extends lamList { } } } + // account status + elseif ($attribute == self::ATTR_ACCOUNT_STATUS) { + $this->printAccountStatus($entry); + } // print all other attributes else { parent::listPrintTableCellContent($entry, $attribute); @@ -337,6 +354,7 @@ class lamUserList extends lamList { protected function listGetAllConfigOptions() { $options = parent::listGetAllConfigOptions(); $options[] = new lamBooleanListOption(_('Translate GID number to group name'), self::TRANS_PRIMARY_OPTION_NAME); + $options[] = new lamBooleanListOption(_('Show account status'), self::ACCOUNT_STATUS_OPTION_NAME); return $options; } @@ -347,6 +365,202 @@ class lamUserList extends lamList { parent::listConfigurationChanged(); $tpOption = $this->listGetConfigOptionByID(self::TRANS_PRIMARY_OPTION_NAME); $this->trans_primary = $tpOption->isSelected(); + $asOption = $this->listGetConfigOptionByID(self::ACCOUNT_STATUS_OPTION_NAME); + $this->showAccountStatus = $asOption->isSelected(); + } + + /** + * Returns an hash array containing with all attributes to be shown and their descriptions. + *
Format: array(attribute => description) + *
+ *
The user list may display an additional account status column + * + * @return array attribute list + */ + protected function listGetAttributeDescriptionList() { + $list = parent::listGetAttributeDescriptionList(); + if ($this->showAccountStatus) { + $list[self::ATTR_ACCOUNT_STATUS] = _('Account status'); + } + return $list; + } + + /** + * Returns if the given attribute can be filtered. + * If filtering is not possible then no filter box will be displayed. + *
+ *
The user list allows no filtering for account status. + * + * @param String $attr attribute name + * @return boolean filtering possible + */ + protected function canBeFiltered($attr) { + if ($attr == self::ATTR_ACCOUNT_STATUS) { + return false; + } + elseif (strtolower($attr) == 'jpegphoto') { + return false; + } + return true; + } + + /** + * Returns a list of additional LDAP attributes that should be read. + * This can be used to show additional data even if the user selected other attributes to show in the list. + *
+ *
The user list reads pwdAccountLockedTime, sambaAcctFlags and userPassword + * + * @return array additional attribute names + */ + protected function getAdditionalLDAPAttributesToRead() { + $attrs = parent::getAdditionalLDAPAttributesToRead(); + if ($this->showAccountStatus) { + $attrs[] = 'pwdAccountLockedTime'; + $attrs[] = 'sambaAcctFlags'; + $attrs[] = 'userPassword'; + $attrs[] = 'objectClass'; + } + return $attrs; + } + + /** + * Injects values for the virtual account status attribute to make it sortable. + */ + private function injectAccountStatusAttribute() { + for ($i = 0; $i < sizeof($this->entries); $i++) { + $status = 0; + if (!$this->isUnixLocked($this->entries[$i])) { + $status++; + } + if (!$this->isSambaLocked($this->entries[$i])) { + $status++; + } + if (!$this->isPPolicyLocked($this->entries[$i])) { + $status++; + } + $this->entries[$i][self::ATTR_ACCOUNT_STATUS][0] = $status; + } + } + + /** + * Prints the account status. + * + * @param array $attrs LDAP attributes + */ + private function printAccountStatus(&$attrs) { + // check status + $unixAvailable = $this->isUnixAvailable($attrs); + $unixLocked = $this->isUnixLocked($attrs); + $sambaAvailable = $this->isSambaAvailable($attrs); + $sambaLocked = $this->isSambaLocked($attrs); + $ppolicyAvailable = $this->isPPolicyAvailable($attrs); + $ppolicyLocked = $this->isPPolicyLocked($attrs); + $partiallyLocked = $unixLocked || $sambaLocked || $ppolicyLocked; + $fullyLocked = ($unixAvailable || $sambaAvailable || $ppolicyAvailable) + && (!$unixAvailable || $unixLocked) + && (!$sambaAvailable || $sambaLocked) + && (!$ppolicyAvailable || $ppolicyLocked); + $icon = 'unlocked.png'; + if ($fullyLocked) { + $icon = 'lock.png'; + } + elseif ($partiallyLocked) { + $icon = 'partiallyLocked.png'; + } + // print icon and detail tooltips + if ($unixAvailable || $sambaAvailable || $ppolicyAvailable) { + $tipContent = ''; + // Unix + if ($unixAvailable) { + $unixIcon = 'unlocked.png'; + if ($unixLocked) { + $unixIcon = 'lock.png'; + } + $tipContent .= ''; + } + // Samba + if ($sambaAvailable) { + $sambaIcon = 'unlocked.png'; + if ($sambaLocked) { + $sambaIcon = 'lock.png'; + } + $tipContent .= ''; + } + // PPolicy + if ($ppolicyAvailable) { + $ppolicyIcon = 'unlocked.png'; + if ($ppolicyLocked) { + $ppolicyIcon = 'lock.png'; + } + $tipContent .= ''; + } + $tipContent .= '
' . _('Unix') . '  
' . _('Samba') . '  
' . _('Password policy') . '  
'; + $tooltip = "'" . $tipContent . "', TITLE, '" . _('Account status') . "'"; + echo 'status'; + } + else { + echo 'status'; + } + } + + /** + * Returns if the Unix part exists. + * + * @param array $attrs LDAP attributes + * @return boolean Unix part exists + */ + private function isUnixAvailable(&$attrs) { + return (isset($attrs['objectclass']) && in_array_ignore_case('posixAccount', $attrs['objectclass'])); + } + + /** + * Returns if the Unix part is locked. + * + * @param array $attrs LDAP attributes + * @return boolean Unix part locked + */ + private function isUnixLocked(&$attrs) { + return (isset($attrs['userpassword'][0]) && !pwd_is_enabled($attrs['userpassword'][0])); + } + + /** + * Returns if the Samba part exists. + * + * @param array $attrs LDAP attributes + * @return boolean Samba part exists + */ + private function isSambaAvailable(&$attrs) { + return (isset($attrs['objectclass']) && in_array_ignore_case('sambaSamAccount', $attrs['objectclass'])); + } + + /** + * Returns if the Samba part is locked. + * + * @param array $attrs LDAP attributes + * @return boolean Samba part is locked + */ + private function isSambaLocked(&$attrs) { + return (isset($attrs['sambaacctflags'][0]) && strpos($attrs['sambaacctflags'][0], "D")); + } + + /** + * Returns if the PPolicy part exists. + * + * @param array $attrs LDAP attributes + * @return boolean PPolicy part exists + */ + private function isPPolicyAvailable(&$attrs) { + return in_array('ppolicyUser', $_SESSION['config']->get_AccountModules('user')); + } + + /** + * Returns if the PPolicy part is locked. + * + * @param array $attrs LDAP attributes + * @return boolean PPolicy part is locked + */ + private function isPPolicyLocked(&$attrs) { + return (isset($attrs['pwdaccountlockedtime'][0]) && ($attrs['pwdaccountlockedtime'][0] != '')); } }