'', dn => '', host => '', domain => ''))) */ private $groups = array(); /** list of NIS netgroups the user was memberOf (array(array(name => '', dn => '', host => '', domain => ''))) */ private $groupsOrig = array(); /** group cache (array(array(cn => '', dn => '', nisnetgrouptriple => array()))) */ private $groupCache = null; /** * Returns true if this module can manage accounts of the current type, otherwise false. * * @return boolean true if module fits */ public function can_manage() { return in_array($this->get_scope(), array('user')); } /** * Returns meta data that is interpreted by parent class * * @return array array with meta data * * @see baseModule::get_metaData() */ public function get_metaData() { $return = array(); // icon $return['icon'] = 'groupBig.png'; // module dependencies $return['dependencies'] = array('depends' => array(array('posixAccount', 'inetOrgPerson')), 'conflicts' => array()); // alias name $return["alias"] = _("NIS net groups"); // available PDF fields $return['PDF_fields']['memberships'] = _('NIS net groups'); // help Entries $return['help'] = array( 'addgroup' => array( 'Headline' => _('Groups of names'), 'Text' => _("Hold the CTRL-key to (de)select multiple groups."). ' '. _("Can be left empty.") ), 'addgroup_upload' => array( "Headline" => _("Groups of names"), "Text" => _("Here you can enter a list of additional group memberships. The group names are separated by commas.") ), ); // upload columns $return['upload_columns'][] = array( 'name' => 'nisNetGroupUser_memberships', 'description' => _('Memberships'), 'help' => 'memberships_upload', 'example' => 'group1##host##domain,group2##host##domain' ); return $return; } /** * This function fills the $messages variable with output messages from this module. */ function load_Messages() { $this->messages['host'][0] = array('ERROR', _('Host name'), _('Host name contains invalid characters. Valid characters are: a-z, A-Z, 0-9 and .-_ !')); $this->messages['domain'][0] = array('ERROR', _('Domain name'), _('Domain name is invalid!')); } /** * Initializes the module after it became part of an accountContainer * * @param string $base the name of the accountContainer object ($_SESSION[$base]) */ function init($base) { // call parent init parent::init($base); $this->groups = array(); $this->groupsOrig = array(); } /** * This function loads all needed LDAP attributes. * * @param array $attr list of attributes */ function load_attributes($attr) { parent::load_attributes($attr); if (empty($attr['uid'][0])) { return; } $uid = $attr['uid'][0]; $types = array('netgroup'); $typeSettings = $_SESSION['config']->get_typeSettings(); $groupList = array(); $filter = '(&(objectClass=nisNetgroup)(nisnetgrouptriple=*))'; if (!empty($typeSettings['filter_' . $types[0]])) { $typeFilter = $typeSettings['filter_' . $types[0]]; if (strpos($typeFilter, '(') !== 0) { $typeFilter = '(' . $typeFilter . ')'; } $filter = '(&' . $filter . $typeFilter . ')'; } $groupList = searchLDAPByFilter($filter, array('dn', 'cn', 'nisnetgrouptriple'), $types); $this->groupsOrig = array(); $tripleRegex = '/^\\(([^,]*),([^,]*),([^,]*)\\)$/'; foreach ($groupList as $group) { foreach ($group['nisnetgrouptriple'] as $triple) { $matches = array(); if (preg_match($tripleRegex, $triple, $matches) == 0) { continue; } $host = $matches[1]; $user = $matches[2]; $domain = $matches[3]; if ($user == $uid) { $this->groupsOrig[] = array( 'name' => $group['cn'][0], 'dn' => $group['dn'], 'host' => $host, 'domain' => $domain ); } } } usort($this->groupsOrig, array($this, 'sortTriple')); $this->groups = $this->groupsOrig; } /** * 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(_('Host 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('host_' . $i, $group['host'])); $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('20px'); // new entry $groupList = array(); $groupData = $this->findGroups(); if (sizeof($groupData) > 0) { 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('host_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], 'host' => $_POST['host_add'], '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; } } // check existing $counter = 0; while (isset($_POST['host_' . $counter])) { if (isset($_POST['del_' . $counter])) { unset($this->groups[$counter]); } else { $this->groups[$counter]['host'] = $_POST['host_' . $counter]; if (!empty($_POST['host_' . $counter]) && !get_preg($_POST['host_' . $counter], 'DNSname')) { $message = $this->messages['host'][0]; $message[2] = $message[2] . '

' . $_POST['host_' . $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; } /** * Runs the postmodify actions. * * @see baseModule::postModifyActions() * * @param boolean $newAccount * @param array $attributes LDAP attributes of this entry * @return array array which contains status messages. Each entry is an array containing the status message parameters. */ public function postModifyActions($newAccount, $attributes) { $moduleAttributes = array(); if ($this->getAccountContainer()->getAccountModule('posixAccount') != null) { $moduleAttributes = $this->getAccountContainer()->getAccountModule('posixAccount')->getAttributes(); } else { $moduleAttributes = $this->getAccountContainer()->getAccountModule('inetOrgPerson')->getAttributes(); } if (empty($moduleAttributes['uid'][0])) { return array(); } $ldapUser = $_SESSION['ldap']->decrypt_login(); $ldapUser = $ldapUser[0]; $uid = $moduleAttributes['uid'][0]; $messages = array(); // calculate differences $toRem = $this->groupsOrig; $toAdd = $this->groups; $counter = sizeof($toRem); for ($i = 0; $i < $counter; $i++) { $group_orig = $toRem[$i]; foreach ($toAdd as $k => $group) { if (($group_orig['dn'] == $group['dn']) && ($group_orig['domain'] == $group['domain']) && ($group_orig['host'] == $group['host'])) { unset($toRem[$i]); unset($toAdd[$k]); break; } } } // group by DN $changes = array(); foreach ($toAdd as $add) { $changes[$add['dn']]['add'][] = '(' . $add['host'] . ',' . $uid . ',' . $add['domain'] . ')'; } foreach ($toRem as $del) { $changes[$del['dn']]['del'][] = '(' . $del['host'] . ',' . $uid . ',' . $del['domain'] . ')'; } // add groups foreach ($changes as $dn => $changeSet) { $current = ldapGetDN($dn, array('nisnetgrouptriple')); if (empty($current)) { $messages[] = array('ERROR', sprintf(_('Was unable to modify attributes of DN: %s.'), $dn)); continue; } $triples = empty($current['nisnetgrouptriple']) ? array() : $current['nisnetgrouptriple']; if (!empty($changeSet['del'])) { $triples = array_delete($changeSet['del'], $triples); } if (!empty($changeSet['add'])) { $triples = array_merge($changeSet['add'], $triples); } $triples = array_values(array_unique($triples)); $attributes = array( 'nisnetgrouptriple' => $triples ); $success = @ldap_mod_replace($_SESSION['ldap']->server(), $dn, $attributes); if (!$success) { logNewMessage(LOG_ERR, '[' . $ldapUser .'] Unable to modify attributes of DN: ' . $dn . ' (' . ldap_error($_SESSION['ldap']->server()) . ').'); $messages[] = array('ERROR', sprintf(_('Was unable to modify attributes of DN: %s.'), $dn), getDefaultLDAPErrorString($_SESSION['ldap']->server())); } } return $messages; } /** * Additional LDAP operations on delete. * * @return List of LDAP operations, same as for save_attributes() */ function delete_attributes() { $return = array(); // remove from group of names return $return; } /** * Returns a list of elements for the account profiles. * * @return profile elements */ function get_profileOptions() { $return = new htmlTable(); // group of names $gons = $this->findGroupOfNames(); $gonList = array(); foreach ($gons as $dn => $attr) { $gonList[$attr['cn'][0]] = $dn; } $gonSelect = new htmlTableExtendedSelect('groupOfNamesUser_gon', $gonList, array(), _('Groups of names'), 'addgroup', 10); $gonSelect->setHasDescriptiveElements(true); $gonSelect->setMultiSelect(true); $gonSelect->setTransformSingleSelect(false); $return->addElement($gonSelect, 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) { // profile mappings in meta data parent::load_profile($profile); // special profile options // group of names if (isset($profile['groupOfNamesUser_gon'][0])) { $this->gonList = $profile['groupOfNamesUser_gon']; } } /** * 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) { $allGons = $this->findGroupOfNames(); $gons = array(); for ($i = 0; $i < sizeof($this->gonList); $i++) { if (isset($allGons[$this->gonList[$i]])) { $gons[] = $allGons[$this->gonList[$i]]['cn'][0]; } } natcasesort($gons); $return = array(); $this->addPDFKeyValue($return, 'gon', _('Groups of names'), $gons); return $return; } /** * In this function the LDAP account is built up. * * @param array $rawAccounts list of hash arrays (name => value) from user input * @param array $ids list of IDs for column position (e.g. "posixAccount_uid" => 5) * @param array $partialAccounts list of hash arrays (name => value) which are later added to LDAP * @param array $selectedModules list of selected account modules * @return array list of error messages if any */ function build_uploadAccounts($rawAccounts, $ids, &$partialAccounts, $selectedModules) { $errors = array(); // get list of existing group of names $gons = $this->findGroupOfNames(); $gonList = array(); foreach ($gons as $dn => $attr) { $gonList[] = $attr['cn'][0]; } // check input for ($i = 0; $i < sizeof($rawAccounts); $i++) { // group of names if ($rawAccounts[$i][$ids['groupOfNamesUser_gon']] != "") { $groups = explode(",", $rawAccounts[$i][$ids['groupOfNamesUser_gon']]); for ($g = 0; $g < sizeof($groups); $g++) { if (!in_array($groups[$g], $gonList)) { $errors[] = array('ERROR', _('Unable to find group in LDAP.'), $groups[$g]); } } } } return $errors; } /** * This function executes one post upload action. * * @param array $data array containing one account in each element * @param array $ids array( => ) * @param array $failed list of accounts which were not created successfully * @param array $temp variable to store temporary data between two post actions * @param array $accounts list of LDAP entries * @return array current status *
array ( *
'status' => 'finished' | 'inProgress' *
'progress' => 0..100 *
'errors' => array () *
) */ function doUploadPostActions(&$data, $ids, $failed, &$temp, &$accounts) { if (!checkIfWriteAccessIsAllowed($this->get_scope())) { die(); } // on first call generate list of LDAP operations if (!isset($temp['counter'])) { $temp['dn_gon'] = array(); $temp['counter'] = 0; // get list of existing group of names $gonList = $this->findGroupOfNames(); $gonMap = array(); foreach ($gonList as $dn => $attr) { $gonMap[$attr['cn'][0]] = $dn; } for ($i = 0; $i < sizeof($data); $i++) { if (in_array($i, $failed)) continue; // ignore failed accounts if (isset($ids['groupOfNamesUser_gon']) && ($data[$i][$ids['groupOfNamesUser_gon']] != "")) { $gons = explode(",", $data[$i][$ids['groupOfNamesUser_gon']]); $memberAttr = 'member'; for ($g = 0; $g < sizeof($gons); $g++) { if (in_array('groupOfUniqueNames', $gonList[$gonMap[$gons[$g]]]['objectclass'])) { $memberAttr = 'uniqueMember'; } $temp['dn_gon'][$gonMap[$gons[$g]]][$memberAttr][] = $accounts[$i]['dn']; } } } $temp['dn_gon_keys'] = array_keys($temp['dn_gon']); return array( 'status' => 'inProgress', 'progress' => 0, 'errors' => array() ); } // add users to group of names elseif ($temp['counter'] < sizeof($temp['dn_gon'])) { $gonDn = $temp['dn_gon_keys'][$temp['counter']]; $gonAttr = $temp['dn_gon'][$gonDn]; $success = @ldap_mod_add($_SESSION['ldap']->server(), $gonDn, $gonAttr); $errors = array(); if (!$success) { $errors[] = array( "ERROR", _("LAM was unable to modify group memberships for group: %s"), getDefaultLDAPErrorString($_SESSION['ldap']->server()), array($temp['groups'][$temp['counter']]) ); } $temp['counter']++; return array ( 'status' => 'inProgress', 'progress' => ($temp['counter'] * 100) / sizeof($temp['dn_gon']), 'errors' => $errors ); } // all modifications are done else { return array ( 'status' => 'finished', 'progress' => 100, 'errors' => array() ); } } /** * Finds all existing LDAP NIS net groups. * * @return array groups array(array(cn => array(), dn => '', nisnetgrouptriple => array())) */ private function findGroups() { if ($this->groupCache != null) { return $this->groupCache; } $return = array(); $types = array('netgroup'); $typeSettings = $_SESSION['config']->get_typeSettings(); if (sizeof($types) > 0) { foreach ($types as $type) { $filter = '(objectClass=nisNetgroup)'; if (!empty($typeSettings['filter_' . $type])) { $typeFilter = $typeSettings['filter_' . $type]; if (strpos($typeFilter, '(') !== 0) { $typeFilter = '(' . $typeFilter . ')'; } $filter = '(&' . $filter . $typeFilter . ')'; } $results = searchLDAPByFilter($filter, array('cn', 'dn', 'nisnetgrouptriple'), array($type)); for ($i = 0; $i < sizeof($results); $i++) { if (isset($results[$i]['cn'][0]) && isset($results[$i]['dn'])) { $return[] = $results[$i]; } } } } $this->groupCache = $return; return $return; } /** * Sorts NIS netgroup triples by group, host and domain. * * @param array $first first array * @param array $second second array */ private 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']); } return strnatcasecmp($first['domain'], $second['domain']); } } ?>