From 26cd5736d2f3ea9ce200f96e010988d53d9e6922 Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Sat, 9 Jan 2016 19:20:57 +0000 Subject: [PATCH] added NIS netgroup module for hosts --- lam/HISTORY | 1 + lam/lib/modules/nisNetGroupHost.inc | 289 ++++++++++++++++++++++++++++ lam/lib/modules/nisNetGroupUser.inc | 105 ++++++---- 3 files changed, 362 insertions(+), 33 deletions(-) create mode 100644 lam/lib/modules/nisNetGroupHost.inc diff --git a/lam/HISTORY b/lam/HISTORY index b6a66347..1b59080c 100644 --- a/lam/HISTORY +++ b/lam/HISTORY @@ -3,6 +3,7 @@ March 2016 5.3 - Windows: support management of fax number - Login can show display name instead of server URL - Personal/Unix: support K5KEY hash type for smbk5pwd + - New NIS netgroup module for hosts - fixed bugs: -> autoload errors in tree view - LAM Pro: diff --git a/lam/lib/modules/nisNetGroupHost.inc b/lam/lib/modules/nisNetGroupHost.inc new file mode 100644 index 00000000..c334cb80 --- /dev/null +++ b/lam/lib/modules/nisNetGroupHost.inc @@ -0,0 +1,289 @@ +get_scope(), array('host')); + } + + /** + * Returns meta data that is interpreted by parent class + * + * @return array array with meta data + * + * @see baseModule::get_metaData() + */ + public function get_metaData() { + $return = parent::get_metaData(); + // module dependencies + $return['dependencies'] = array('depends' => array(array('account', 'posixAccount')), 'conflicts' => array()); + // upload columns + $return['upload_columns'] = array(array( + 'name' => 'nisNetGroup_memberships', + 'description' => _('Memberships'), + 'help' => 'memberships_upload', + 'example' => 'group1#user#domain,group2#user#domain' + )); + return $return; + } + + /** + * This function fills the $messages variable with output messages from this module. + */ + function load_Messages() { + parent::load_Messages(); + $this->messages['user'][0] = array('ERROR', _('User name'), _('User name contains invalid characters. Valid characters are: a-z, A-Z, 0-9 and .-_ !')); + } + + /** + * Checks if the netgroup matches this entry. + * + * @param String $user netgroup user name + * @param String $host netgroup host name + * @param String $domain netgroup domain name + * @param String $uid user name of this entry + */ + protected function isMatchingNetGroup($user, $host, $domain, $uid) { + return $host == $uid; + } + + /** + * Displays the group selection. + * + * @return htmlElement meta HTML code + */ + public function display_html_attributes() { + $return = new htmlTable(); + $return->addElement(new htmlOutputText(_('Group'))); + $return->addElement(new htmlOutputText(_('User name'))); + $return->addElement(new htmlOutputText(_('Domain name')), true); + for ($i = 0; $i < sizeof($this->groups); $i++) { + $group = $this->groups[$i]; + $return->addElement(new htmlOutputText($group['name'])); + $return->addElement(new htmlInputField('user_' . $i, $group['user'])); + $return->addElement(new htmlInputField('domain_' . $i, $group['domain'])); + $delButton = new htmlButton('del_' . $i, 'del.png', true); + $delButton->setTitle(_('Delete')); + $return->addElement($delButton, true); + } + $return->addVerticalSpace('40px'); + + // new entry + $groupList = array(); + $groupData = $this->findGroups(); + if (sizeof($groupData) > 0) { + $filterGroup = new htmlGroup(); + $filterGroup->addElement(new htmlOutputText(_('Filter') . ' ')); + $filter = new htmlInputField('group_filter'); + $filter->setFieldSize('5em'); + $filter->setOnKeyUp('filterSelect(\'group_filter\', \'group_add\', event);'); + $filterGroup->addElement($filter); + $return->addElement($filterGroup, true); + + foreach ($groupData as $group) { + $groupList[$group['cn'][0]] = $group['cn'][0] . '#+#' . $group['dn']; + } + $groupSelect = new htmlSelect('group_add', $groupList); + $groupSelect->setHasDescriptiveElements(true); + $return->addElement($groupSelect); + $return->addElement(new htmlInputField('user_add')); + $return->addElement(new htmlInputField('domain_add')); + $addButton = new htmlButton('addGroup', 'add.png', true); + $addButton->setTitle(_('Add')); + $return->addElement($addButton, true); + } + return $return; + } + + /** + * Processes user input of the group selection page. + * It checks if all input values are correct and updates the associated LDAP attributes. + * + * @return array list of info/error messages + */ + public function process_attributes() { + $errors = array(); + // add new entry + if (isset($_POST['addGroup'])) { + $parts = explode('#+#', $_POST['group_add']); + $this->groups[] = array( + 'name' => $parts[0], + 'dn' => $parts[1], + 'user' => $_POST['user_add'], + 'host' => $this->uidOrig, + 'domain' => $_POST['domain_add'] + ); + if (!empty($_POST['user_add']) && !get_preg($_POST['user_add'], 'username')) { + $message = $this->messages['user'][0]; + $message[2] = $message[2] . '

' . $_POST['user_add']; + $errors[] = $message; + } + if (!empty($_POST['domain_add']) && !get_preg($_POST['domain_add'], 'DNSname')) { + $message = $this->messages['domain'][0]; + $message[2] = $message[2] . '

' . $_POST['domain_add']; + $errors[] = $message; + } + } + // check existing + $counter = 0; + while (isset($_POST['user_' . $counter])) { + if (isset($_POST['del_' . $counter])) { + unset($this->groups[$counter]); + } + else { + $this->groups[$counter]['user'] = $_POST['user_' . $counter]; + if (!empty($_POST['user_' . $counter]) && !get_preg($_POST['user_' . $counter], 'username')) { + $message = $this->messages['user'][0]; + $message[2] = $message[2] . '

' . $_POST['user_' . $counter]; + $errors[] = $message; + } + $this->groups[$counter]['domain'] = $_POST['domain_' . $counter]; + if (!empty($_POST['domain_' . $counter]) && !get_preg($_POST['domain_' . $counter], 'DNSname')) { + $message = $this->messages['domain'][0]; + $message[2] = $message[2] . '

' . $_POST['domain_' . $counter]; + $errors[] = $message; + } + } + $counter++; + } + $this->groups = array_values($this->groups); + usort($this->groups, array($this, 'sortTriple')); + return $errors; + } + + /** + * Creates a netgroup triple from a group object. + * + * @param String $group group object + * @param String $uid own uid + */ + protected function createNetGroupValue($group, $uid) { + return '(' . $uid . ',' . $group['user'] . ',' . $group['domain'] . ')'; + } + + /** + * Returns a list of elements for the account profiles. + * + * @return profile elements + */ + function get_profileOptions() { + $groups = $this->findGroups(); + $groupOptions = array('' => ''); + foreach ($groups as $group) { + $groupOptions[$group['cn'][0]] = $group['cn'][0] . '#+#' . $group['dn']; + } + $return = new htmlTable(); + $return->addElement(new htmlOutputText(_('Group'))); + $return->addElement(new htmlOutputText(_('User name'))); + $return->addElement(new htmlOutputText(_('Domain name')), true); + for ($i = 0; $i < 5; $i++) { + $select = new htmlSelect('nisNetGroupUser_group' . $i, $groupOptions, array('')); + $select->setHasDescriptiveElements(true); + $return->addElement($select); + $return->addElement(new htmlInputField('nisNetGroupUser_user' . $i)); + $return->addElement(new htmlInputField('nisNetGroupUser_domain' . $i), true); + } + return $return; + } + + /** + * Loads the values of an account profile into internal variables. + * + * @param array $profile hash array with profile values (identifier => value) + */ + function load_profile($profile) { + for ($i = 0; $i < 5; $i++) { + if (!empty($profile['nisNetGroupUser_group' . $i][0])) { + $parts = explode('#+#', $profile['nisNetGroupUser_group' . $i][0]); + $this->groups[] = array( + 'name' => $parts[0], + 'dn' => $parts[1], + 'user' => $profile['nisNetGroupUser_user' . $i][0], + 'host' => $this->uidOrig, + 'domain' => $profile['nisNetGroupUser_domain' . $i][0], + ); + } + } + usort($this->groups, array($this, 'sortTriple')); + } + + /** + * Returns a list of possible PDF entries for this account. + * + * @param array $pdfKeys list of PDF keys that are included in document + * @return list of PDF entries (array( => )) + */ + function get_pdfEntries($pdfKeys) { + $return = array(); + $pdfTable = new PDFTable(); + $pdfRow = new PDFTableRow(); + $pdfRow->cells[] = new PDFTableCell(_('Group'), '25%', null, true); + $pdfRow->cells[] = new PDFTableCell(_('User name'), '25%', null, true); + $pdfRow->cells[] = new PDFTableCell(_('Domain name'), '25%', null, true); + $pdfTable->rows[] = $pdfRow; + foreach ($this->groups as $group) { + $pdfRow = new PDFTableRow(); + $pdfRow->cells[] = new PDFTableCell($group['name'], '25%'); + $pdfRow->cells[] = new PDFTableCell($group['user'], '25%'); + $pdfRow->cells[] = new PDFTableCell($group['domain'], '25%'); + $pdfTable->rows[] = $pdfRow; + } + $this->addPDFTable($return, 'memberships', $pdfTable); + return $return; + } + + /** + * Creates a netgroup triple from the input value of file upload. + * + * @param array $value upload value (e.g. array(group1, host, domain)) + * @param String $uid own uid + * @return String netgroup triple + */ + protected function buildNetGroupTripleFromUploadValue($value, $uid) { + $user = empty($value[1]) ? '' : $value[1]; + $domain = empty($value[2]) ? '' : $value[2]; + return '(' . $uid . ',' . $user . ',' . $domain . ')'; + } + +} \ No newline at end of file diff --git a/lam/lib/modules/nisNetGroupUser.inc b/lam/lib/modules/nisNetGroupUser.inc index 70b7de34..36cd26ed 100644 --- a/lam/lib/modules/nisNetGroupUser.inc +++ b/lam/lib/modules/nisNetGroupUser.inc @@ -3,7 +3,7 @@ $Id$ This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) - Copyright (C) 2015 Roland Gruber + Copyright (C) 2015 - 2016 Roland Gruber This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -36,13 +36,13 @@ $Id$ class nisNetGroupUser extends baseModule { /** list of NIS netgroups the user is memberOf (array(array(name => '', dn => '', host => '', domain => ''))) */ - private $groups = array(); + protected $groups = array(); /** list of NIS netgroups the user was memberOf (array(array(name => '', dn => '', host => '', domain => ''))) */ - private $groupsOrig = array(); + protected $groupsOrig = array(); /** group cache (array(array(cn => '', dn => '', nisnetgrouptriple => array()))) */ - private $groupCache = null; + protected $groupCache = null; /** original uid */ - private $uidOrig = null; + protected $uidOrig = null; /** * Returns true if this module can manage accounts of the current type, otherwise false. @@ -79,7 +79,7 @@ class nisNetGroupUser extends baseModule { ); // upload columns $return['upload_columns'][] = array( - 'name' => 'nisNetGroupUser_memberships', + 'name' => 'nisNetGroup_memberships', 'description' => _('Memberships'), 'help' => 'memberships_upload', 'example' => 'group1#host#domain,group2#host#domain' @@ -117,8 +117,7 @@ class nisNetGroupUser extends baseModule { if (empty($attr['uid'][0])) { return; } - $uid = $attr['uid'][0]; - $this->uidOrig = $uid; + $this->uidOrig = $attr['uid'][0]; $types = array('netgroup'); $typeSettings = $_SESSION['config']->get_typeSettings(); $groupList = array(); @@ -142,11 +141,12 @@ class nisNetGroupUser extends baseModule { $host = $matches[1]; $user = $matches[2]; $domain = $matches[3]; - if ($user == $uid) { + if ($this->isMatchingNetGroup($user, $host, $domain, $this->uidOrig)) { $this->groupsOrig[] = array( 'name' => $group['cn'][0], 'dn' => $group['dn'], 'host' => $host, + 'user' => $user, 'domain' => $domain ); } @@ -156,6 +156,18 @@ class nisNetGroupUser extends baseModule { $this->groups = $this->groupsOrig; } + /** + * Checks if the netgroup matches this entry. + * + * @param String $user netgroup user name + * @param String $host netgroup host name + * @param String $domain netgroup domain name + * @param String $uid user name of this entry + */ + protected function isMatchingNetGroup($user, $host, $domain, $uid) { + return $user == $uid; + } + /** * Displays the group selection. * @@ -219,18 +231,19 @@ class nisNetGroupUser extends baseModule { 'name' => $parts[0], 'dn' => $parts[1], 'host' => $_POST['host_add'], + 'user' => $this->uidOrig, 'domain' => $_POST['domain_add'] ); - if (!empty($_POST['host_add']) && !get_preg($_POST['host_add'], 'DNSname')) { - $message = $this->messages['host'][0]; - $message[2] = $message[2] . '

' . $_POST['host_add']; - $errors[] = $message; - } - if (!empty($_POST['domain_add']) && !get_preg($_POST['domain_add'], 'DNSname')) { - $message = $this->messages['domain'][0]; - $message[2] = $message[2] . '

' . $_POST['domain_add']; - $errors[] = $message; - } + if (!empty($_POST['host_add']) && !get_preg($_POST['host_add'], 'DNSname')) { + $message = $this->messages['host'][0]; + $message[2] = $message[2] . '

' . $_POST['host_add']; + $errors[] = $message; + } + if (!empty($_POST['domain_add']) && !get_preg($_POST['domain_add'], 'DNSname')) { + $message = $this->messages['domain'][0]; + $message[2] = $message[2] . '

' . $_POST['domain_add']; + $errors[] = $message; + } } // check existing $counter = 0; @@ -264,7 +277,7 @@ class nisNetGroupUser extends baseModule { * * @return String user ID */ - private function getUid() { + protected function getUid() { $moduleAttributes = array(); if ($this->getAccountContainer()->getAccountModule('posixAccount') != null) { $moduleAttributes = $this->getAccountContainer()->getAccountModule('posixAccount')->getAttributes(); @@ -308,6 +321,7 @@ class nisNetGroupUser extends baseModule { foreach ($toAdd as $k => $group) { if (($group_orig['dn'] == $group['dn']) && ($group_orig['domain'] == $group['domain']) + && ($group_orig['user'] == $group['user']) && ($group_orig['host'] == $group['host'])) { if (!empty($this->uidOrig) && ($this->uidOrig != $uid)) { // uid changed, simply update uid in all net groups @@ -324,11 +338,11 @@ class nisNetGroupUser extends baseModule { // group by DN $changes = array(); foreach ($toAdd as $add) { - $changes[$add['dn']]['add'][] = '(' . $add['host'] . ',' . $uid . ',' . $add['domain'] . ')'; + $changes[$add['dn']]['add'][] = $this->createNetGroupValue($add, $uid); } foreach ($toRem as $del) { $delUid = empty($this->uidOrig) ? $uid : $this->uidOrig; - $changes[$del['dn']]['del'][] = '(' . $del['host'] . ',' . $delUid . ',' . $del['domain'] . ')'; + $changes[$del['dn']]['del'][] = $this->createNetGroupValue($del, $delUid); } // update groups foreach ($changes as $dn => $changeSet) { @@ -357,6 +371,16 @@ class nisNetGroupUser extends baseModule { return $messages; } + /** + * Creates a netgroup triple from a group object. + * + * @param String $group group object + * @param String $uid own uid + */ + protected function createNetGroupValue($group, $uid) { + return '(' . $group['host'] . ',' . $uid . ',' . $group['domain'] . ')'; + } + /** * Additional LDAP operations on delete. * @@ -373,7 +397,7 @@ class nisNetGroupUser extends baseModule { // remove from NIS netgroups $changes = array(); foreach ($this->groups as $group) { - $changes[$group['dn']][] = '(' . $group['host'] . ',' . $uid . ',' . $group['domain'] . ')'; + $changes[$group['dn']][] = $this->createNetGroupValue($group, $uid); } foreach ($changes as $dn => $changeSet) { $current = ldapGetDN($dn, array('nisnetgrouptriple')); @@ -434,6 +458,7 @@ class nisNetGroupUser extends baseModule { 'name' => $parts[0], 'dn' => $parts[1], 'host' => $profile['nisNetGroupUser_host' . $i][0], + 'user' => $this->uidOrig, 'domain' => $profile['nisNetGroupUser_domain' . $i][0], ); } @@ -486,8 +511,8 @@ class nisNetGroupUser extends baseModule { // check input for ($i = 0; $i < sizeof($rawAccounts); $i++) { // group names - if (!empty($rawAccounts[$i][$ids['nisNetGroupUser_memberships']])) { - $triples = preg_split('/,[ ]*/', $rawAccounts[$i][$ids['nisNetGroupUser_memberships']]); + if (!empty($rawAccounts[$i][$ids['nisNetGroup_memberships']])) { + $triples = preg_split('/,[ ]*/', $rawAccounts[$i][$ids['nisNetGroup_memberships']]); foreach ($triples as $triple) { $parts = explode('#', $triple); if (!in_array($parts[0], $groupNames)) { @@ -534,14 +559,12 @@ class nisNetGroupUser extends baseModule { continue; } $uid = $accounts[$i]['uid']; - if (!empty($data[$i][$ids['nisNetGroupUser_memberships']])) { - $triples = preg_split('/,[ ]*/', $data[$i][$ids['nisNetGroupUser_memberships']]); + if (!empty($data[$i][$ids['nisNetGroup_memberships']])) { + $triples = preg_split('/,[ ]*/', $data[$i][$ids['nisNetGroup_memberships']]); foreach ($triples as $triple) { $parts = explode('#', $triple); $group = $parts[0]; - $host = empty($parts[1]) ? '' : $parts[1]; - $domain = empty($parts[2]) ? '' : $parts[2]; - $temp['groups'][$groupMap[$group]][] = '(' . $host . ',' . $uid . ',' . $domain . ')'; + $temp['groups'][$groupMap[$group]][] = $this->buildNetGroupTripleFromUploadValue($parts, $uid); } } } @@ -594,12 +617,25 @@ class nisNetGroupUser extends baseModule { } } + /** + * Creates a netgroup triple from the input value of file upload. + * + * @param array $value upload value (e.g. array(group1, host, domain)) + * @param String $uid own uid + * @return String netgroup triple + */ + protected function buildNetGroupTripleFromUploadValue($value, $uid) { + $host = empty($value[1]) ? '' : $value[1]; + $domain = empty($value[2]) ? '' : $value[2]; + return '(' . $host . ',' . $uid . ',' . $domain . ')'; + } + /** * Finds all existing LDAP NIS net groups. * * @return array groups array(array(cn => array(), dn => '', nisnetgrouptriple => array())) */ - private function findGroups() { + protected function findGroups() { if ($this->groupCache != null) { return $this->groupCache; } @@ -629,18 +665,21 @@ class nisNetGroupUser extends baseModule { } /** - * Sorts NIS netgroup triples by group, host and domain. + * Sorts NIS netgroup triples by group, host, user and domain. * * @param array $first first array * @param array $second second array */ - private function sortTriple($first, $second) { + protected function sortTriple($first, $second) { if ($first['name'] != $second['name']) { return strnatcasecmp($first['name'], $second['name']); } elseif ($first['host'] != $second['host']) { return strnatcasecmp($first['host'], $second['host']); } + elseif ($first['user'] != $second['user']) { + return strnatcasecmp($first['user'], $second['user']); + } return strnatcasecmp($first['domain'], $second['domain']); }