* Setup/LDAP/ADS: script to change uidNumber and gidNumber in LDAP to match relative id (last part of SID) in preparation of Samba4 migration and using ActiveDirectory

This commit is contained in:
Ralf Becker 2013-06-18 18:14:08 +00:00
parent 0cd63aefc2
commit 014a273908
3 changed files with 258 additions and 22 deletions

95
setup/doc/chown.php Executable file
View File

@ -0,0 +1,95 @@
#!/usr/bin/php
<?php
/**
* EGroupware setup - test or create the ldap connection and hierarchy
*
* @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @package setup
* @copyright (c) 2013 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
*/
chdir(dirname(__FILE__)); // to enable our relative pathes to work
if (isset($_SERVER['HTTP_HOST'])) // security precaution: forbit calling as web-page
{
die('<h1>setup/doc/chown.php must NOT be called as web-page --> exiting !!!</h1>');
}
$recursive = false;
$cmd = array_shift($_SERVER['argv']);
if ($_SERVER['argv'] && in_array($_SERVER['argv'][0], array('-R', '--recursive')))
{
$recursive = true;
array_shift($_SERVER['argv']);
}
if (count($_SERVER['argv']) != 2)
{
usage();
}
function usage()
{
die("\nUsage: $cmd [-R|--recursive] from-id,to-id[,from-id2,to-id2,...] path\n\nonly nummeric ids are allowed, group-ids have to be negative!\n\n");
}
$ids = explode(',', $_SERVER['argv'][0]);
$change = array();
while($ids)
{
$from = (int)array_shift($ids);
$to = (int)array_shift($ids);
if (!$from || !$to || ($from < 0) != ($to < 0))
{
echo "from-id and to-id must be nummeric and have same sign (negative for groups)!\n\n";
usage();
}
$change[$from] = $to;
}
$path = $_SERVER['argv'][1];
if (!file_exists($path))
{
echo "File or directory '$path' not found!\n\n";
usage();
}
if (posix_getuid())
{
die("\nNeed to run as root, to be able to change owner and group!\n\n");
}
chown_grp($path, null, $recursive);
function chown_grp($path, array $stat=null, $recursive=false)
{
global $change;
if (is_null($stat) && !($stat = stat($path))) return false;
if (isset($change[$stat['uid']]) && !chown($path, $uid=$change[$stat['uid']]))
{
echo "Faild to set new owner #$uid for $path\n";
}
if (isset($change[-$stat['gid']]) && !chgrp($path, $gid=-$change[-$stat['gid']]))
{
echo "Faild to set new group #$gid for $path\n";
}
if ($recursive && is_dir($path))
{
foreach(new DirectoryIterator($path) as $child)
{
if (!$child->isDot())
chown_grp($child->getPathname(), array(
'uid' => $child->getOwner(),
'gid' => $child->getGroup(),
), $recursive);
}
}
}

View File

@ -1,11 +1,11 @@
<?php
/**
* eGgroupWare setup - test or create the ldap connection and hierarchy
* EGroupware setup - test or create the ldap connection and hierarchy
*
* @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @package setup
* @copyright (c) 2007-10 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2007-13 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
*/
@ -15,8 +15,17 @@
*
* All commands can be run via setup-cli eg:
*
* setup/setup-cli.php --setup_cmd_ldap stylite.de,config-user,config-pw sub_command=set_mailbox \
* ldap_base=dc=local ldap_admin=cn=admin,dc=local ldap_admin_pw=secret ldap_host=localhost test=1
* setup/setup-cli.php [--dry-run] --setup_cmd_ldap <domain>,<config-user>,<config-pw> sub_command=set_mailbox \
* ldap_base=dc=local ldap_root_dn=cn=admin,dc=local ldap_root_pw=secret ldap_host=localhost
*
* Changing uid/gidNumber to match SID in preparation to Samba4 migration:
*
* setup/setup-cli.php [--dry-run] --setup_cmd_ldap <domain>,<config-user>,<config-pw> sub_command=sid2uidnumber \
* ldap_base=dc=local ldap_root_dn=cn=admin,dc=local ldap_root_pw=secret ldap_host=localhost
*
* - First run it with --dry-run to get ids to change / admin-cli command to change ids in EGroupware.
* - Then run admin/admin-cli.php --change-account-id and after this command again without --dry-run.
* - After that you need to run the given setup/doc/chown.php command to change filesystem uid/gid in samba share.
*/
class setup_cmd_ldap extends setup_cmd
{
@ -91,8 +100,10 @@ class setup_cmd_ldap extends setup_cmd
{
throw new egw_exception_wrong_userinput(lang("'%1' is no valid domain name!",$this->domain));
}
if ($this->remote_id && $check_only) return true; // further checks can only done locally
if ($this->remote_id && $check_only && !in_array($this->sub_command, array('set_mailbox', 'sid2uidnumber')))
{
return true; // further checks can only done locally
}
$this->_merge_defaults();
//_debug_array($this->as_array());
@ -115,7 +126,10 @@ class setup_cmd_ldap extends setup_cmd
$msg = $this->migrate($this->sub_command == 'migrate_to_ldap');
break;
case 'set_mailbox':
$msg = $this->set_mailbox();
$msg = $this->set_mailbox($check_only);
break;
case 'sid2uidnumber':
$msg = $this->sid2uidnumber($check_only);
break;
case 'create_ldap':
default:
@ -125,6 +139,97 @@ class setup_cmd_ldap extends setup_cmd
return $msg;
}
const sambaSID = 'sambasid';
/**
* Change uidNumber and gidNumber to match rid (last part of sambaSID)
*
* First run it with --dry-run to get ids to change / admin-cli command to change ids in EGroupware.
* Then run admin/admin-cli.php --change-account-id and after this command again without --dry-run.
* After that you need to run the given chown.php command to change filesystem uid/gid in samba share.
*
* @param boolean $check_only=false true: only connect and output necessary commands
*/
private function sid2uidnumber($check_only=false)
{
$msg = array();
$this->connect();
// check if base does exist
if (!@ldap_read($this->test_ldap->ds,$this->ldap_base,'objectClass=*'))
{
throw new egw_exception_wrong_userinput(lang('Base dn "%1" NOT found!',$this->ldap_base));
}
if (!($sr = ldap_search($this->test_ldap->ds,$this->ldap_base,
'(&(|(objectClass=posixAccount)(objectClass=posixGroup))('.$search=self::sambaSID.'=*)(!(gecos=*)))',
array('uidNumber','gidNumber','uid','cn', 'objectClass',self::sambaSID))) ||
!($entries = ldap_get_entries($this->test_ldap->ds, $sr)))
{
throw new egw_exception(lang('Error searching "dn=%1" for "%2"!',$this->ldap_base, $search));
}
$change = $accounts = array();
$cmd_change_account_id = 'admin/admin-cli.php --change-account-id <admin>@<domain>,<adminpw>';
$change_account_id = '';
foreach($entries as $key => $entry)
{
if ($key === 'count') continue;
$entry = self::ldap2array($entry);
$accounts[$entry['dn']] = $entry;
//print_r($entry);
$parts = explode('-', $entry[self::sambaSID]);
$rid = array_pop($parts);
if (in_array('posixAccount', $entry['objectclass']))
{
$id = $entry['uidnumber'];
}
else
{
$id = -$entry['gidnumber'];
$rid *= -1;
}
if ($id != $rid)
{
$change[$id] = $rid;
$change_account_id .= ','.$id.','.$rid;
}
}
//print_r($change); die('Stop');
// change account-ids inside EGroupware
if ($check_only) $msg[] = "You need to run now:\n$cmd_change_account_id $change_account_id";
//$cmd = new admin_cmd_change_account_id($change);
//$msg[] = $cmd->run($time=null, $set_modifier=false, $skip_checks=false, $check_only);
// now change them in LDAP
$changed = 0;
foreach($accounts as $dn => $account)
{
$modify = array();
if (!empty($account['uidnumber']) && isset($change[$account['uidnumber']]))
{
$modify['uidnumber'] = $change[$account['uidnumber']];
}
if (isset($change[-$account['gidnumber']]))
{
$modify['gidnumber'] = -$change[-$account['gidnumber']];
}
if (!$check_only && $modify && !ldap_modify($this->test_ldap->ds, $dn, $modify))
{
throw new egw_exception("Failed to modify ldap: !ldap_modify({$this->test_ldap->ds}, '$dn', ".array2string($modify).") ".ldap_error($this->test_ldap->ds).
"\n- ".implode("\n- ", $msg)); // EGroupware change already run successful
}
if ($modify) ++$changed;
}
$msg[] = "You need to run now on your samba share(s):\nsetup/doc/chown.php -R $change_account_id <share>";
return ($check_only ? 'Need to update' : 'Updated')." $changed entries with new uid/gidNumber in LDAP".
"\n- ".implode("\n- ", $msg);
}
/**
* Migrate to other account storage
*
@ -383,6 +488,35 @@ class setup_cmd_ldap extends setup_cmd
return $hash;
}
/**
* Convert a single ldap value into a associative array
*
* @param array $ldap array with numerical and associative indexes and count's
* @return array with only associative index and no count's
*/
public static function ldap2array($ldap)
{
if (!is_array($ldap)) return false;
$arr = array();
foreach($ldap as $var => $val)
{
if (is_int($var) || $var === 'count') continue;
if (is_array($val) && $val['count'] == 1)
{
$arr[$var] = $val[0];
}
else
{
if (is_array($val)) unset($val['count']);
$arr[$var] = $val;
}
}
return $arr;
}
/**
* Read all accounts from sql or ldap
*
@ -602,7 +736,7 @@ class setup_cmd_ldap extends setup_cmd
* @return string with success message N entries modified
* @throws egw_exception if dn not found, not listable or delete fails
*/
private function set_mailbox()
private function set_mailbox($check_only=false)
{
$this->connect($this->ldap_admin,$this->ldap_admin_pw);
@ -639,16 +773,16 @@ class setup_cmd_ldap extends setup_cmd
if ($mbox === $entry[$mbox_attr][0]) continue; // nothing to change
if (!$this->test && !ldap_modify($this->test_ldap->ds,$entry['dn'],array(
if (!$check_only && !ldap_modify($this->test_ldap->ds,$entry['dn'],array(
$mbox_attr => $mbox,
)))
{
throw new egw_exception(lang("Error modifying dn=%1: %2='%3'!",$dn,$mbox_attr,$mbox));
}
++$modified;
if ($this->test) echo "$modified: $entry[dn]: $mbox_attr={$entry[$mbox_attr][0]} --> $mbox\n";
if ($check_only) echo "$modified: $entry[dn]: $mbox_attr={$entry[$mbox_attr][0]} --> $mbox\n";
}
return $this->test ? lang('%1 entries would have been modified.',$modified) :
return $check_only ? lang('%1 entries would have been modified.',$modified) :
lang('%1 entries modified.',$modified);
}

View File

@ -6,7 +6,7 @@
* @link http://www.egroupware.org
* @package setup
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2006-9 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2006-13 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
*/
@ -17,10 +17,17 @@ if (isset($_SERVER['HTTP_HOST'])) // security precaution: forbit calling setup-c
{
die('<h1>setup-cli.php must NOT be called as web-page --> exiting !!!</h1>');
}
elseif ($_SERVER['argc'] > 1)
$dry_run = false;
array_shift($_SERVER['argv']);
if ($_SERVER['argv'])
{
if ($_SERVER['argv'][0] == '--dry-run')
{
$dry_run = true;
array_shift($_SERVER['argv']);
}
$arguments = $_SERVER['argv'];
array_shift($arguments);
$action = array_shift($arguments);
if (isset($arguments[0])) list($_POST['FormDomain']) = explode(',',$arguments[0]); // header include needs that to detects the right domain
}
@ -52,7 +59,7 @@ $GLOBALS['egw_setup']->system_charset = $charset;
if ((float) PHP_VERSION < $GLOBALS['egw_setup']->required_php_version)
{
throw new egw_exception_wrong_userinput(lang('You are using PHP version %1. eGroupWare now requires %2 or later, recommended is PHP %3.',PHP_VERSION,$GLOBALS['egw_setup']->required_php_version,$GLOBALS['egw_setup']->recommended_php_version),98);
throw new egw_exception_wrong_userinput(lang('You are using PHP version %1. EGroupware now requires %2 or later, recommended is PHP %3.',PHP_VERSION,$GLOBALS['egw_setup']->required_php_version,$GLOBALS['egw_setup']->recommended_php_version),98);
}
switch($action)
@ -136,7 +143,7 @@ switch($action)
}
}
$cmd = new $class($args);
$msg = $cmd->run();
$msg = $cmd->run($time=null, $set_modifier=true, $skip_checks=false, $check_only=$dry_run);
if (is_array($msg)) $msg = print_r($msg,true);
echo "$msg\n";
break;
@ -146,7 +153,7 @@ switch($action)
exit(0);
/**
* Configure eGroupWare
* Configure EGroupware
*
* @param array $args domain(default),[config user(admin)],password,[,name=value,...] --files-dir --backup-dir --mailserver
*/
@ -351,7 +358,7 @@ function _check_auth_config($arg,$stop,$set_lang=true)
}
/**
* Install eGroupWare
* Install EGroupware
*
* @param array $args array(0 => "domain,[config user(admin)],password,[backup-file],[charset],[lang]", "name=value", ...)
*/
@ -461,7 +468,7 @@ function do_usage($what='')
if (!$what)
{
echo '--check '.lang('checks eGroupWare\'s installed, it\'s versions and necessary upgrads (return values see --exit-codes)')."\n";
echo '--check '.lang('checks EGroupware\'s installed, it\'s versions and necessary upgrads (return values see --exit-codes)')."\n";
echo '--install '.lang('domain(default),[config user(admin)],password,[backup to install],[charset(default depends on language)]')."\n";
}
if (!$what || $what == 'config')
@ -491,7 +498,7 @@ function do_usage($what='')
}
if (!$what || $what == 'header')
{
echo lang('Create or edit the eGroupWare configuration file: header.inc.php:')."\n";
echo lang('Create or edit the EGroupware configuration file: header.inc.php:')."\n";
echo '--create-header '.lang('header-password[,header-user(admin)]')."\n";
echo '--edit-header '.lang('[header-password],[header-user],[new-password],[new-user]')."\n";
if (!$what) echo ' --help header '.lang('gives further options')."\n";
@ -499,14 +506,14 @@ function do_usage($what='')
if ($what == 'header')
{
echo "\n".lang('Additional options and there defaults (in brackets)')."\n";
echo '--server-root '.lang('path of eGroupWare install directory (default auto-detected)')."\n";
echo '--server-root '.lang('path of EGroupware install directory (default auto-detected)')."\n";
echo '--session-type '.lang('{db | php(default) | php-restore}')."\n";
echo '--limit-access '.lang('comma separated ip-addresses or host-names, default access to setup from everywhere')."\n";
echo '--mcrypt '.lang('use mcrypt to crypt session-data: {off(default) | on},[mcrypt-init-vector(default randomly generated)],[mcrypt-version]')."\n";
echo '--db-persistent '.lang('use persistent db connections: {on(default) | off}')."\n";
echo '--domain-selectbox '.lang('{off(default) | on}')."\n";
echo "\n".lang('Adding, editing or deleting an eGroupWare domain / database instance:')."\n";
echo "\n".lang('Adding, editing or deleting an EGroupware domain / database instance:')."\n";
echo '--domain '.lang('add or edit a domain: [domain-name(default)],[db-name(egroupware)],[db-user(egroupware)],db-password,[db-type(mysql)],[db-host(localhost)],[db-port(db specific)],[config-user(as header)],[config-passwd(as header)]')."\n";
echo '--delete-domain '.lang('domain-name')."\n";
}