read())
if ((substr($entry, strlen($entry) - 4, 4) == '.inc') && is_file($modulesINC_dirname . '/'.$entry)) {
include_once($modulesINC_dirname . '/'.$entry);
}
/**
* Returns the alias name of a module
*
* @param string $name the module name
* @param string $scope the account type ("user", "group", "host")
* @return string alias name
*/
function getModuleAlias($name, $scope) {
$module = new $name($scope);
return $module->get_alias();
}
/**
* Returns true if the module is a base module
*
* @param string $name the module name
* @param string $scope the account type ("user", "group", "host")
* @return boolean true if base module
*/
function is_base_module($name, $scope) {
$module = new $name($scope);
return $module->is_base_module();
}
/**
* Returns the LDAP filter used by the account lists
*
* @param string $scope the account type ("user", "group", "host")
* @return string LDAP filter
*/
function get_ldap_filter($scope) {
$mods = $_SESSION['config']->get_AccountModules($scope);
$filters = array();
$orFilter = '';
for ($i = 0; $i < sizeof($mods); $i++) {
if (is_base_module($mods[$i], $scope)) {
$module = new $mods[$i]($scope);
$modinfo = $module->get_ldap_filter();
if (isset($modinfo['or'])) $filters['or'][] = $modinfo['or'];
if (isset($modinfo['and'])) $filters['and'][] = $modinfo['and'];
}
}
// build OR filter
if (sizeof($filters['or']) == 1) {
$orFilter = $filters['or'][0];
}
elseif (sizeof($filters['or']) > 1) {
$orFilter = "(|" . implode("", $filters['or']) . ")";
}
// add built OR filter to AND filters
if ($orFilter != '') $filters['and'][] = $orFilter;
// collapse AND filters
if (sizeof($filters['and']) < 2) return $filters['and'][0];
else return "(&" . implode("", $filters['and']) . ")";
}
/**
* Returns a list of LDAP attributes which can be used to form the RDN.
*
* The list is already sorted by the priority given by the nodules.
*
* @param string $scope account type (user, group, host)
* @return array list of LDAP attributes
*/
function getRDNAttributes($scope) {
$mods = $_SESSION['config']->get_AccountModules($scope);
$return = array();
$attrs_low = array();
$attrs_normal = array();
$attrs_high = array();
for ($i = 0; $i < sizeof($mods); $i++) {
// get list of attributes
$module = new $mods[$i]($scope);
$attrs = $module->get_RDNAttributes();
$keys = array_keys($attrs);
// sort attributes
for ($k = 0; $k < sizeof($keys); $k++) {
switch ($attrs[$keys[$k]]) {
case "low":
$attrs_low[] = $keys[$k];
break;
case "normal":
$attrs_normal[] = $keys[$k];
break;
case "high":
$attrs_high[] = $keys[$k];
break;
default:
$attrs_low[] = $keys[$k];
break;
}
}
}
// merge arrays
$return = $attrs_high;
for ($i = 0; $i < sizeof($attrs_normal); $i++) $return[] = $attrs_normal[$i];
for ($i = 0; $i < sizeof($attrs_low); $i++) $return[] = $attrs_low[$i];
$return = array_values(array_unique($return));
return $return;
}
/**
* Returns a hash array (module name => dependencies) of all module dependencies
*
* "dependencies" contains an array with two sub arrays: depends, conflicts
* The elements of "depends" are either module names or an array of module names (OR-case).
* The elements of conflicts are module names.
*
* @param string $scope the account type (user, group, host)
* @return array dependencies
*/
function getModulesDependencies($scope) {
$mods = getAvailableModules($scope);
for ($i = 0; $i < sizeof($mods); $i++) {
$module = new $mods[$i]($scope);
$return[$mods[$i]] = $module->get_dependencies();
}
return $return;
}
/**
* Checks if there are missing dependencies between modules.
*
* @param array $selected selected module names
* @param array $deps module dependencies
* @return mixed false if no misssing dependency was found,
* otherwise an array of array(selected module, depending module) if missing dependencies were found
*/
function check_module_depends($selected, $deps) {
$ret = array();
for ($m = 0; $m < sizeof($selected); $m++) { // check selected modules
for ($i = 0; $i < sizeof($deps[$selected[$m]]['depends']); $i++) { // check dependencies of module
// check if we have OR-combined modules
if (is_array($deps[$selected[$m]]['depends'][$i])) {
// one of the elements is needed
$found = false;
$depends = $deps[$selected[$m]]['depends'][$i];
for ($d = 0; $d < sizeof($depends); $d++) {
if (in_array($depends[$d], $selected)) {
$found = true;
break;
}
}
if (! $found) {
// missing dependency, add to return value
$ret[] = array($selected[$m], implode(" || ", $depends));
}
}
else {
// single dependency
if (! in_array($deps[$selected[$m]]['depends'][$i], $selected)) {
// missing dependency, add to return value
$ret[] = array($selected[$m], $deps[$selected[$m]]['depends'][$i]);
}
}
}
}
if (sizeof($ret) > 0) return $ret;
else return false;
}
/**
* Checks if there are conflicts between modules
*
* @param array $selected selected module names
* @param array $deps module dependencies
* @return false if no conflict was found,
* otherwise an array of array(selected module, conflicting module) if conflicts were found
*/
function check_module_conflicts($selected, $deps) {
$ret = array();
for ($m = 0; $m < sizeof($selected); $m++) {
for ($i = 0; $i < sizeof($deps[$selected[$m]]['conflicts']); $i++) {
if (in_array($deps[$selected[$m]]['conflicts'][$i], $selected)) {
$ret[] = array($selected[$m], $deps[$selected[$m]]['conflicts'][$i]);
}
}
}
if (sizeof($ret) > 0) return $ret;
else return false;
}
/**
* Returns an array with all available user module names
*
* @param string $scope account type (user, group, host)
* @return array list of possible modules
*/
function getAvailableModules($scope) {
$dirname = substr(__FILE__, 0, strlen(__FILE__) - 12) . "/modules";
$dir = dir($dirname);
$return = array();
// get module names.
while ($entry = $dir->read())
if ((substr($entry, strlen($entry) - 4, 4) == '.inc') && is_file($dirname . '/'.$entry)) {
$entry = substr($entry, 0, strpos($entry, '.'));
$temp = new $entry($scope);
if ($temp->can_manage()) $return[] = $entry;
}
return $return;
}
/**
* Returns the elements for the profile page.
*
* @param string $scope account type (user, group, host)
* @return array profile elements
*/
function getProfileOptions($scope) {
// create new account container if needed
if (! isset($_SESSION["profile_account_$scope"])) {
$_SESSION["profile_account_$scope"] = new accountContainer($scope, "profile_account_$scope");
$_SESSION["profile_account_$scope"]->new_account();
}
// get options
return $_SESSION["profile_account_$scope"]->getProfileOptions();
}
/**
* Checks if the profile options are valid
*
* @param string $scope account type (user, group, host)
* @param array $options hash array containing all options (name => array(...))
* @return array list of error messages
*/
function checkProfileOptions($scope, $options) {
// create new account container if needed
if (! isset($_SESSION["profile_account_$scope"])) {
$_SESSION["profile_account_$scope"] = new accountContainer($scope, "profile_account_$scope");
$_SESSION["profile_account_$scope"]->new_account();
}
// get options
return $_SESSION["profile_account_$scope"]->checkProfileOptions($options);
}
/**
* Returns a hash array (module name => elements) of all module options for the configuration page.
*
* @param array $scopes hash array (module name => array(account types))
* @return array configuration options
*/
function getConfigOptions($scopes) {
$return = array();
$modules = array_keys($scopes);
for ($i = 0; $i < sizeof($modules); $i++) {
$m = new $modules[$i]('none');
$return[$modules[$i]] = $m->get_configOptions($scopes[$modules[$i]]);
}
return $return;
}
/**
* Returns a hash array (module name => descriptions) containing descriptions shown on configuration pages.
*
* The returned array has the format array('legend' => array('posixAccount' => '...', ...), descriptions => array('option1' => '...', ...)).
* The "legend" value is used as text for the fieldset, the descriptions are used when the configuration is printed.
*
* @return array configuration descriptions
*/
function getConfigDescriptions() {
$return = array('legend' => array(), 'descriptions' => array());
$modules = array_merge(getAvailableModules('user'), getAvailableModules('group'), getAvailableModules('host'));
$modules = array_values(array_unique($modules));
for ($i = 0; $i < sizeof($modules); $i++) {
$m = new $modules[$i]('none');
$desc = $m->get_configDescriptions();
$return['legend'][$modules[$i]] = $desc['legend'];
$return['descriptions'] = array_merge($return['descriptions'], $desc['descriptions']);
}
return $return;
}
/**
* Checks if the configuration options are valid
*
* @param array $scopes hash array (module name => array(account types))
* @param array $options hash array containing all options (name => array(...))
* @return array list of error messages
*/
function checkConfigOptions($scopes, $options) {
$return = array();
$modules = array_keys($scopes);
for ($i = 0; $i < sizeof($modules); $i++) {
$m = new $modules[$i]('none');
$errors = $m->check_configOptions($scopes[$modules[$i]], $options);
$return = array_merge($return, $errors);
}
return $return;
}
/**
* Returns a help entry from an account module.
*
* @param string $helpID help identifier
* @param string $module module name
* @return array help entry
*/
function getHelp($module,$helpID,$scope='') {
$moduleObject = new $module((($scope != '') ? $scope : 'none'));
return $moduleObject->get_help($helpID,$scope);
}
/**
* Returns a list of available PDF entries.
*
* @param string $scope account type (user, group, host)
* @return array PDF entries
*/
function getAvailablePDFFields($scope) {
// create new account container if needed
if (! isset($_SESSION["profile_account_$scope"])) {
$_SESSION["profile_account_$scope"] = new accountContainer($scope, "profile_account_$scope");
$_SESSION["profile_account_$scope"]->new_account();
}
// get options
return $_SESSION["profile_account_$scope"]->getAvailablePDFFields();
}
/**
* Return a list of current available scopes
*
* @return array Available scopes
*/
function getAvailableScopes() {
return array('user','group','host', 'domain');
}
/**
* Returns an array containing all input columns for the file upload.
*
* Syntax:
* array(
* string: name, // fixed non-translated name which is used as column name (should be of format: _)
* string: description, // short descriptive name
* string: help, // help ID
* string: example, // example value
* boolean: required // true, if user must set a value for this column
* )
*
* @param string $scope account type
* @return array column list
*/
function getUploadColumns($scope) {
// create new account container if needed
if (! isset($_SESSION["profile_account_$scope"])) {
$_SESSION["profile_account_$scope"] = new accountContainer($scope, "profile_account_$scope");
$_SESSION["profile_account_$scope"]->new_account();
}
// get options
return $_SESSION["profile_account_$scope"]->get_uploadColumns();
}
/**
* This function builds the LDAP accounts for the file upload.
*
* If there are problems status messages will be printed automatically.
*
* @param string $scope account type
* @param array $data array containing one account in each element
* @param array $ids array( => )
* @return mixed array including accounts or false if there were errors
*/
function buildUploadAccounts($scope, $data, $ids) {
// build module order
$unOrdered = $_SESSION['config']->get_AccountModules($scope);
$ordered = array();
$predepends = array();
// get dependencies
for ($i = 0; $i < sizeof($unOrdered); $i++) {
$mod = new $unOrdered[$i]($scope);
$predepends[$unOrdered[$i]] = $mod->get_uploadPreDepends();
}
// first all modules without predepends can be ordered
for ($i = 0; $i < sizeof($unOrdered); $i++) {
if (sizeof($predepends[$unOrdered[$i]]) == 0) {
$ordered[] = $unOrdered[$i];
unset($unOrdered[$i]);
$unOrdered = array_values($unOrdered);
$i--;
}
}
$unOrdered = array_values($unOrdered); // fix indexes
// now add all modules with fulfilled dependencies until all are in order
while (sizeof($unOrdered) > 0) {
$newRound = false;
for ($i = 0; $i < sizeof($unOrdered); $i++) {
$deps = $predepends[$unOrdered[$i]];
$depends = false;
for ($d = 0; $d < sizeof($deps); $d++) {
if (in_array($deps[$d], $unOrdered)) {
$depends = true;
break;
}
}
if (!$depends) { // add to order if dependencies are fulfilled
$ordered[] = $unOrdered[$i];
unset($unOrdered[$i]);
$unOrdered = array_values($unOrdered);
$newRound = true;
break;
}
}
if ($newRound) continue;
// this point should never be reached, LAM was unable to find a correct module order
StatusMessage("ERROR", _("Internal Error: Unable to find correct module order."), "");
return false;
}
// give raw data to modules
$errors = array();
$partialAccounts = array();
for ($i = 0; $i < sizeof($data); $i++) $partialAccounts[$i]['objectClass'] = array();
for ($i = 0; $i < sizeof($ordered); $i++) {
$module = new $ordered[$i]($scope);
$errors = $module->build_uploadAccounts($data, $ids, $partialAccounts);
if (sizeof($errors) > 0) {
array_unshift($errors, array("INFO", _("Displayed account numbers start at \"0\". Add 2 to get the row in your spreadsheet."), ""));
$errors[] = array("ERROR", _("Upload was stopped after errors in %s module!"), "", array($module->get_alias()));
break;
}
}
if (sizeof($errors) > 0) {
for ($i = 0; (($i < sizeof($errors)) || ($i > 49)); $i++) call_user_func_array("StatusMessage", $errors[$i]);
return false;
}
else return $partialAccounts;
}
/**
* This class includes all modules and attributes of an account.
*
* @package modules
*/
class accountContainer {
// Constructor
function accountContainer($type, $base) {
/* Set the type of account. Valid
* types are: user, group, host
*/
// Check input variable
if (!is_string($type)) trigger_error(_('Argument of accountContainer must be string.'), E_USER_ERROR);
if (!is_string($base)) trigger_error(_('Argument of accountContainer must be string.'), E_USER_ERROR);
// *** fixme use global variable to determine allowed types
if (!in_array($type, getAvailableScopes())) trigger_error(_('Account type not recognized.'), E_USER_ERROR);
$this->type = $type;
$this->base = $base;
// Set startpage
$this->current_page=0;
$this->subpage='attributes';
return 0;
}
/* Array of all used attributes
* Syntax is attribute => array ( objectClass => MUST or MAY, ...)
*/
var $attributes;
/* This variale stores the type
* of account. Current unix, group, host are supported
*/
var $type;
var $module; // This is an array with all module objects
// DN of the account
var $dn;
var $dn_orig;
// this are stores the module order
var $order;
// name of accountContainer so we can read other classes in accuontArray
var $base;
// This variable stores the number of the current displayed page
var $current_page;
// This variable os set to the pagename of a subpage if it should be displayed
var $subpage;
/* Get the type of account. Valid
* types are: user, group, host
*/
function get_type() {
return $this->type;
}
function continue_main($post) {
if ($this->subpage=='') $this->subpage='attributes';
if ($post['form_main_reset']) {
$this->load_account($this->dn_orig);
}
else {
if ($this->current_page==0) {
if ($this->subpage=='attributes') {
$result = 0;
// change dn
if ($post['suffix']!='') $this->dn = $post['suffix'];
// load profile
if ($post['selectLoadProfile'] && $post['loadProfile']) {
// *** fixme load*Profile must return array in the same way ldap_get_attributes does.
$newattributes = loadAccountProfile($post['selectLoadProfile'], $scope);
// pass newattributes to each module
$modules = array_keys($this->module);
foreach ($modules as $module) $this->module[$module]->load_attributes($newattributes);
$result = 0;
}
// save account
if ($post['create']) {
$errors = $this->save_account();
if (is_array($errors)) $result = array($errors);
// return name of subpage
$result = 'finish';
}
// save profile
if ($post['saveProfile']) {
if ($post['selectSaveProfile']=='') $errors['saveProfile'][] = array('ERROR', _('Save profile'), _('No profilename given.'));
else {
//saveAccountProfile($scope); // TODO missing parameters, remove?
if ($function) $errors['saveProfile'][] = array('INFO', _('Save profile'), _('New profile created.'));
else $errors['saveProfile'][] = array('ERROR', _('Save profile'), _('Wrong profilename given.'));
}
if (is_array($errors)) $result = $errors;
else $result = 0;
}
}
if ($this->subpage=='finish') {
if ($post['createagain']) {
// Reset objects
$modules = array_keys($this->module);
foreach ($modules as $module) unset($this->module[$module]);
// Reset accountContainer
$this->dn = '';
$this->dn_orig = '';
$this->attributes = array();
$this->order = array();
$this->current_page = 0;
$this->subpage = '';
// Add all required objects etc.
$this->new_account();
$result = 0;
}
if ($post['backmain']) {
// Return to *-list
// *** fixme unset accountContainer in session
metaRefresh("../lists/list".$this->type."s.php");
exit;
}
if ($post['outputpdf']) {
// Create / display PDf-file
$function = 'create'.ucfirst($this->type).'PDF(array($_SESSION[$this->base]));';
//eval($function);
call_user_func('create'.ucfirst($this->type).'PDF', array($_SESSION[$this->base]));
exit;
}
}
}
else $result = call_user_func(array(&$this->module[$this->order[$this->current_page]], 'proccess_'.$this->subpage), &$post);
}
if (is_string($result)) $this->subpage = $result;
if (is_int($result)) {
if ($post['form_main_main']) {
$this->current_page = 0;
$this->subpage='attributes';
}
else for ($i=1; $iorder); $i++ )
if ($post['form_main_'.$this->order[$i]] && ($this->module[$this->order[$i]]->module_ready())) {
$this->current_page = $i;
$this->subpage='attributes';
}
}
// Write HTML-Code
echo $_SESSION['header'];
echo "";
if ($this->dn_orig!='') echo _("Modify Account");
else echo _("Create new Account");
echo "\n";
echo "\n";
echo "\n";
echo "\n";
echo "\n";
echo "