Last active
December 27, 2015 10:59
-
-
Save tpokorra/7315298 to your computer and use it in GitHub Desktop.
upgrade ldif data from Kolab 2.3 to Kolab 3.x
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
# Timotheus Pokorra, for TBits.net, April 2013 | |
# | |
# import ldif file that has been dumped from Kolab2 | |
# restoring domains, domain admins, and users | |
require_once "/usr/share/kolab-webadmin/lib/functions.php"; | |
function debug($msg){ | |
if(is_writeable("/tmp/mylog.log")){ | |
$fh = fopen("/tmp/mylog.log",'a+'); | |
fputs($fh,"[UPGRADE] $msg\n"); | |
fclose($fh); | |
} | |
} | |
function firstChar($s, $cmp) | |
{ | |
return (strlen($s) > 0 && $s[0] == $cmp); | |
} | |
function endsWith($haystack, $needle) | |
{ | |
$length = strlen($needle); | |
if ($length == 0) { | |
return true; | |
} | |
return (substr($haystack, -$length) === $needle); | |
} | |
# parse ldif file for upgrade from kolab2 to kolab3 | |
function parseLDIF($filename) | |
{ | |
$dn_objects = array(); | |
$lines = file($filename); | |
$counter = 0; | |
$current_dn = ''; | |
while ($counter < count($lines)) { | |
$currentLine = trim($lines[$counter]); | |
$counter++; | |
while ($counter < count($lines) && firstChar($lines[$counter], ' ')) { | |
$currentLine .= trim($lines[$counter]); | |
$counter++; | |
} | |
if (firstChar($currentLine, '#') || strlen($currentLine) == 0) { | |
// skip comment and empty lines | |
continue; | |
} | |
if (strpos($currentLine, ": ") === false) { | |
if (strpos($currentLine, ":") === false) { | |
echo "cannot parse line $counter: $currentLine\n"; | |
} else { | |
# ignore empty values | |
} | |
} else { | |
$pos = strpos($currentLine, ':: '); | |
if ($pos !== false) { | |
$pair = array(substr($currentLine, 0, $pos), base64_decode(substr($currentLine, $pos + 3))); | |
} | |
else | |
{ | |
$pos = strpos($currentLine, ': '); | |
$pair = array(substr($currentLine, 0, $pos), substr($currentLine, $pos + 2)); | |
} | |
if ($pair[0] == "dn") { | |
$current_dn = $pair[1]; | |
$dn_objects[$current_dn] = array(); | |
} else { | |
if (isset($dn_objects[$current_dn][$pair[0]])) { | |
if (!is_array($dn_objects[$current_dn][$pair[0]])) { | |
$dn_objects[$current_dn][$pair[0]] = array($dn_objects[$current_dn][$pair[0]]); | |
} | |
$dn_objects[$current_dn][$pair[0]][] = $pair[1]; | |
} else if ($pair[0] == "domains" || $pair[0] == "member") { | |
# always use an array, to make it easier to access | |
$dn_objects[$current_dn][$pair[0]] = array($pair[1]); | |
} else { | |
$dn_objects[$current_dn][$pair[0]] = $pair[1]; | |
} | |
} | |
} | |
} | |
return $dn_objects; | |
} | |
function importDomain($domain_name) | |
{ | |
global $auth; | |
if ($auth->domain_info($domain_name) === false) { | |
$attribs = array(); | |
$attribs['objectclass'] = array("top", "domainrelatedobject", "inetdomain"); | |
if ($auth->domain_add($domain_name, $attribs) === false) { | |
die("failed to add domain " .$domain_name); | |
} | |
return true; | |
} | |
return false; | |
} | |
function importUser($domain_name, $person) | |
{ | |
global $auth; | |
$person["ou"] = "ou=People,dc=".implode(",dc=", explode(".", $domain_name)); | |
# $person["uid"] is already set | |
# TODO add kolabhomeserver, etc to schema | |
unset($person['kolabHomeServer']); | |
unset($person['lastLogin']); | |
# add objectClass mailRecipient, so that attribute mailQuota can be set | |
$person['objectClass'][] = 'mailRecipient'; | |
# mailQuota is in KiloByte, cyrus-userquota was in MegaByte | |
$person['mailQuota'] = $person['cyrus-userquota'] * 1024; | |
unset($person['cyrus-userquota']); | |
# some users have these attributes, which are not known: | |
# /var/log/kolab-webadmin/errors: ldap_add(): Add: Object class violation in /usr/share/kolab-webadmin/lib/ext/Net/LDAP3.php on line 212 | |
# /var/log/dirsrv/slapd-centos6-kolab3/errors: Entry "uid=pop-....,ou=People,..." -- attribute "c" not allowed | |
unset($person['search']); | |
unset($person['result']); | |
unset($person['c']); | |
if (empty($person["displayName"])) { | |
$person["displayName"] = $person["sn"].", ".$person["givenName"]; | |
} | |
# Roundcube UI will use this language | |
if (!isset($person['preferredLanguage'])) { | |
$person['preferredLanguage'] = "de_DE"; | |
} | |
if (strpos($person["givenName"], ' ') !== false) | |
{ | |
#TODO mail should not be made up of givenName. Kolab3 skips the space for new users. but Kolab2 just had the first part of the givenname | |
#die (print_r($person, true)); | |
# $person['mail'] = substr($person["givenName"], 0, strpos($person["givenName"], ' ')); | |
} | |
#echo "adding person ".print_r($person, true); | |
# check if user already exists | |
if ($auth->user_info("uid=".$person["uid"].",".$person["ou"]) === false) { | |
$auth->user_add($person); | |
} | |
} | |
function importUsers($dn_objects, $domain_name) | |
{ | |
foreach ($dn_objects as $name => $value) { | |
if (endsWith($name, ",cn=customers,cn=internal,dc=kolab,dc=tbits,dc=net")) { | |
# if this customer contains the domain_name | |
if (in_array($domain_name, $value["domains"])) { | |
# go through all members, and check their email address | |
foreach ($value["member"] as $member_dn) { | |
$person = $dn_objects[$member_dn]; | |
if (endsWith($person['mail'], "@".$domain_name)) { | |
importUser($domain_name, $person); | |
} | |
} | |
} | |
} | |
} | |
} | |
# add the domain admin as a user to kolab.tbits.net, so that all domain admins are in one user list | |
function importDomainAdmin($dn_objects, $default_domain_dn, $person) | |
{ | |
global $primary_domain; | |
global $auth; | |
$person["ou"] = "ou=People,".$default_domain_dn; | |
if (empty($person["displayName"])) { | |
$person["displayName"] = $person["cn"]; | |
} | |
if (empty($person["givenName"])) { | |
$person["givenName"] = trim(str_replace($person["sn"], "", $person["cn"])); | |
} | |
$person['objectClass'][] = 'mailRecipient'; | |
# use the customerQuota of the customer object | |
$personuid = explode('-', $person["uid"]); | |
$customerid = $personuid[1]; | |
$customer = $dn_objects["cn=$customerid,cn=customers,cn=internal,dc=kolab,dc=tbits,dc=net"]; | |
$person['mailQuota'] = $customer['customerQuota']*1024; | |
$person['mail'] = $person["uid"]."@".$primary_domain; | |
#TODO add role kolab_admin | |
# check if domain admin already exists | |
if ($auth->user_info("uid=".$person["uid"].",".$person["ou"]) === false) { | |
$auth->user_add($person); | |
} | |
} | |
function importDomainAdmins($dn_objects, $domain_name) | |
{ | |
global $primary_domain; | |
global $auth; | |
$default_domain_dn = "dc=".implode(",dc=", explode(".", $primary_domain)); | |
# go through all domain maintainers | |
foreach ($dn_objects["cn=domain-maintainer,cn=internal,dc=kolab,dc=tbits,dc=net"]["member"] as $domainmaintainer) { | |
$domainmaintainer_object = $dn_objects[$domainmaintainer]; | |
$domainadmin = "uid=".$domainmaintainer_object['uid'].",ou=People,".$default_domain_dn; | |
# check the current domain and see if the domain maintainer owns this domain | |
$domain = $dn_objects["cn=$domain_name,cn=domains,cn=internal,dc=kolab,dc=tbits,dc=net"]; | |
# if this domain admin owns the domain | |
if ($domain != null && $domain["member"] != null && in_array($domainmaintainer, $domain["member"])) { | |
# create this user in the default domain | |
importDomainAdmin($dn_objects, $default_domain_dn, $domainmaintainer_object); | |
# add permissions for this domain | |
$domainToSave = $auth->domain_info($domain["cn"]); | |
$domaindata = $domainToSave[key($domainToSave)]; | |
if (!in_array($domainadmin, $domaindata["domainadmin"])) { | |
$domaindata["domainadmin"][] = $domainadmin; | |
$auth->domain_edit($domain["cn"], $domaindata); | |
} | |
} | |
} | |
} | |
function importDomains($dn_objects) | |
{ | |
$count = 0; | |
$domainsImported = 0; | |
$domains = null; | |
if (file_exists("domains.txt")) | |
{ | |
$domains = file("domains.txt", FILE_IGNORE_NEW_LINES); | |
} | |
# go through all domains | |
foreach ($dn_objects as $name => $value) { | |
if (strpos($name, ",cn=domains,cn=internal,dc=kolab") !== false) { | |
$domain_name = $value["cn"]; | |
if ($domains != null && !in_array($domain_name, $domains)) { | |
continue; | |
} | |
echo $domain_name."\n"; | |
if (importDomain($domain_name)) { | |
$domainsImported++; | |
} | |
# add users | |
importUsers($dn_objects, $domain_name); | |
# add domain admins | |
importDomainAdmins($dn_objects, $domain_name); | |
# TODO [domainQuota] => 5000 | |
# [domainDefaultQuota] => 500 | |
# [maxAccounts] => 50 | |
#if ($count > 4) die("stop at 4 domains"); | |
$count++; | |
if ($domainsImported == 10) { | |
# restart ldap server to avoid too many open files | |
# this does not work, since we lose the connection to the ldap server | |
return false; | |
system("service dirsrv restart"); | |
$domainsImported = 0; | |
} | |
} | |
} | |
return true; | |
} | |
function upgrade($filename) | |
{ | |
$dn_objects = parseLDIF($filename); | |
return importDomains($dn_objects); | |
} | |
$filename = isset($argv[1])?$argv[1]:""; | |
$ldappassword = isset($argv[2])?$argv[2]:""; | |
# Do we have all infos to continue? | |
if($filename == "" || $ldappassword == "") { | |
die("Usage: ".$argv[0]." <kolab2_ldif_filename> <ldappwd> \n". | |
"e.g. ".$argv[0]." ldap20130430.txt secret \n"); | |
} | |
# cancel if kolabd is still running, so that no mailboxes etc are created during the upgrade | |
$status = system("service kolabd status"); | |
if ($status != "kolabd is stopped") { | |
echo "please run \"service kolabd stop\" before importing the ldap data!\n"; | |
exit(1); | |
} | |
$conf = Conf::get_instance(); | |
$primary_domain = $conf->get('kolab', 'primary_domain'); | |
$_SESSION['user'] = new User(); | |
$valid = $_SESSION['user']->authenticate("cn=Directory Manager", $ldappassword, $primary_domain); | |
if ($valid === false) { | |
die ("cannot authenticate user cn=Directory Manager"); | |
} | |
$auth = Auth::get_instance(); | |
if (!upgrade($filename)) { | |
echo "\n\nPlease run this script again, we did not finish processing all domains!\n\n"; | |
exit(2); | |
} | |
# for changes to kolab.conf to take effect | |
system("service httpd reload"); | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment