<?php
/**
 *  Secioss_ConfigManager.php
 *
 *  @author     {$author}
 *  @package    Secioss
 *  @version    $Id: skel.app_manager.php 387 2006-11-06 14:31:24Z cocoitiban $
 */

if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
    define('HTPASSWD', '/usr/bin/htpasswd -b');
}

/**
 *  Secioss_ConfigManager
 *
 *  @author     {$author}
 *  @access     public
 *  @package    Secioss
 */
class Lism_ConfigManager extends Ethna_AppManager
{
    function getIniFile($file, $params)
    {
        $values = array();

        if (!file_exists($file)) {
            return false;
        }

        $lp = $this->_lock($file, LOCK_SH);

        $contents = file_get_contents($file);

        $this->_unlock($lp);

        if (!$contents) {
            return Ethna::raiseError("Reading $file failed");
        }

        foreach ($params as $key) {
            switch($key) {
              case 'pwmaxage':
              case 'pwexpwarn':
              case 'pwminage':
                $values[] = preg_match("/$key += +\"?([^\"\n]+)\"?/", $contents, $matches) ? $matches[1] / 24 / 3600 : 0;
                break;
              case 'pwloduration':
                $values[] = preg_match("/$key += +\"?([^\"\n]+)\"?/", $contents, $matches) ? $matches[1] / 60 : 0;
                break;
              case 'pwallowtype':
                $regexp = preg_match("/pwdeny += +\"?([^\"\n]+)\"?/", $contents, $matches) ? $matches[1] : '';
                if ($regexp == '[^a-zA-Z0-9]') {
                    $values[] = 'alphnum';
                } else if (preg_match('/\[\^a-zA-Z0-9[^\]]+\]/', $regexp)) {
                    $values[] = 'alphnumetc';
                } else {
                    $values[] = 'all';
                }
                break;
              case 'pwallowchars':
                $regexp = preg_match("/pwdeny += +\"?([^\"\n]+)\"?/", $contents, $matches) ? $matches[1] : '';
                if ($regexp == '[^a-zA-Z0-9]') {
                    $values[] = '';
                } else if (preg_match('/\[\^a-zA-Z0-9([^\]]+)\]/', $regexp, $matches)) {
                    $values[] = $matches[1];
                } else {
                    $values[] = '';
                }
                break;
              case 'pwinhistory':
                $values[] = preg_match("/$key += +\"?([^\"\n]+)\"?/", $contents, $matches) ? $matches[1] : 0;
                break;
              case 'servername':
                $values[] = preg_match('/login += +\"?(https?:\/\/[^\/]+)/', $contents, $matches) ? $matches[1] : '';
                break;
              default:
                $values[] = preg_match("/$key += +\"?([^\"\n]+)\"?/", $contents,
 $matches) ? $matches[1] : '';
                break;
            }
        }

        return $values;
    }

    function setIniFile($file, $params)
    {
        if (!file_exists($file)) {
            return false;
        }
        $output = BASEDIR.'/tmp/'.basename($file);

        $ldapconf = $this->config->get('ldap');

        $lp = $this->_lock($file, LOCK_EX);

        $conf = parse_ini_file($file, true);
        if ($conf == false) {
            $this->_unlock($lp);
            return Ethna::raiseError("Reading $file failed");
        }

        $fp = fopen($output, 'w');
        if ($fp === false) {
            return Ethna::raiseError("Can't open $output to write");
        }

        foreach ($conf as $key1 => $item) {
            if (is_array($item)) {
                fwrite($fp, "[$key1]\n");
                foreach ($item as $key2 => $value) {
                    if ($key1 == 'url') {
                        switch($key2) {
                          case 'login':
                            if (isset($params['url'])) {
                                if (isset($params['type'])) {
                                    $value = preg_replace("/^https?:\/\/[^\/]+\/".$params['type']."/", $params['url'], $value);
                                } else if (isset($params['oldurl'])) {
                                    $value = preg_replace("/^".addcslashes($params['oldurl'], '/.')."/", $params['url'], $value);
                                }
                            }
                            break;
                          case 'back':
                            if (isset($params['path']) && isset($params['url'])) {
                                preg_match('/^(https?:\/\/[^\/]+)/', $params['url'], $matches);

                                if (preg_match('/^http/', $value)) {
                                   $substitution = "^https?:\/\/[^\/]+";
                                } else {
                                   $substitution = "^";
                                }
                                if ($params['system'] == 'proxy') {
                                    $replace = $params['path'];
                                } else {
                                    $replace = $matches[1].$params['path'];
                                }

                                if (isset($params['type'])) {
                                    $value = preg_replace("/$substitution\/".$params['type']."/", $replace, $value);
                                } else if (isset($params['oldpath'])) {
                                    $value = preg_replace("/$substitution".addcslashes($params['oldpath'], '/.')."/", $replace, $value);
                                }
                            }
                            break;
                          case 'fatal':
                            if (isset($params['servername'])) {
                                $value = preg_replace('/^https?:\/\/[^\/]+/', $params['servername'], $value);
                            }
                            break;
                          case 'password':
                            if (isset($params['servername'])) {
                                $value = preg_replace(array('/^https?:\/\/[^\/]+/', '/^http:/'), array($params['servername'], 'https:'), $value);
                            }
                            break;
                        }
                    } else if ($key1 == 'autologin') {
                        switch($key2) {
                          case 'domain':
                            if (isset($params['domain'])) {
                                $value = $params['domain'];
                            }
                            break;
                          default:
                            if(isset($params[$key2])) {
                                $value = $params[$key2];
                            }
                            break;
                        }
                    } else if ($key1 == 'password') {
                        switch($key2) {
                          case 'pwminlen':
                          case 'pwmaxlen':
                          case 'pwinhistory':
                          case 'pwmaxage':
                          case 'pwexpwarn':
                          case 'pwminage':
                          case 'pwmaxfailure':
                          case 'pwfailureinterval':
                          case 'pwloduration':
                            if (isset($params[$key2])) {
                                $value = $params[$key2];
                            }
                            break;
                          case 'pwdeny':
                            if (!isset($params['pwallowtype'])) {
                                continue;
                            }
                            switch($params['pwallowtype']) {
                              case 'all':
                                $value = '';
                                break;
                              case 'alphnum':
                                $value = '[^a-zA-Z0-9]';
                                break;
                              case 'alphnumetc':
                                $value = '[^a-zA-Z0-9'.$params['pwallowchars'].']';
                               break;
                            }
                            break;
                          case 'uri':
                          case 'binddn':
                          case 'bindpw':
                          case 'basedn':
                          case 'pwhash':
                            if (isset($ldapconf['type']) && $ldapconf['type'] == 'LISM') {
                                if ($key2 == 'pwhash') {
                                    $value = 'PLAINTEXT';
                                }
                                break;
                            }

                            if(isset($params[$key2])) {
                                $value = $params[$key2];
                            }
                            break;
                          default:
                            if(isset($params[$key2])) {
                                $value = $params[$key2];
                            }
                            break;
                        }
                    }
                    fwrite($fp, "$key2 = \"$value\"\n");
                }
                fwrite($fp, "\n");
            } else {
                $value = $item;
                switch($key1) {
                  default:
                    if (isset($params[$key1])) {
                        $value = $params[$key1];
                    }
                }
                fwrite($fp, "$key1 = \"$value\"\n");
            }
        }
        fclose($fp);

        if (!move($output, $file)) {
            $this->_unlock($lp);
            return Ethna::raiseError("Renaming $file failed");
        }

        $this->_replicate($file);

        $this->_unlock($lp);

        return true;
    }

    function getLismConf($file, $params)
    {
        $values = array();

        $lp = $this->_lock($file, LOCK_SH);

        $contents = file_get_contents($file);

        $this->_unlock($lp);

        if (!$contents) {
            return Ethna::raiseError("Reading $file failed");
        }
        foreach ($params as $key) {
            switch($key) {
              default:
                $values[] = preg_match("/$key\s+[\"']?([^\"'\n]+)/", $contents, $matches) ? $matches[1] : null;
                break;
            }
        }

        return $values;
    }

    function getXmlFile($file, $params, $dname = 'LDAP') {
        $dname = preg_replace("/\./", "_", $dname);
        $values = array(); 

        if (!is_array($params)) {
            return $values;
        }

        $lp = $this->_lock($file, LOCK_SH);
        if(!($xml = simplexml_load_file($file))) {
            $this->_unlock($lp);
            return Ethna::raiseError("Can't open $file");
        }

        $this->_unlock($lp);

        if (array_search('master', $params) !== false) {
            $values[] = (string)$xml->sync->master->data;
        }
        if (array_search('sync_cluster', $params) !== false || array_search('sync_master', $params) !== false) {
            $sync_cluster = array();
            $master_cluster = array();
            foreach ($xml->sync->data as $sdata) {
                $sync_flag = false;
                $master_flag = false;

                foreach ($sdata->object as $sobject) {
                    if (isset($sobject->syncdn)) {
                        $sync_flag = true;
                    }
                    if (isset($sobject->masterdn)) {
                        $master_flag = true;
                    }
                }

                if ($sync_flag) {
                    $sync_cluster[] = $sdata->attributes()->name;
                }
                if ($master_flag) {
                    $sync_master[] = $sdata->attributes()->name;
                }
            }
            if (array_search('sync_cluster', $params) !== false) {
                $values[] = $sync_cluster;
            }
            if (array_search('sync_master', $params) !== false) {
                $values[] = $sync_master;
            }
        }

        foreach($xml->data as $data) {
            if($data->attributes()->name == $dname){
                if (isset($data->storage)) {
                    $storage = $data->storage;
                } else {
                    continue;
                }

                foreach($params as $key) {
                    if ($key == 'storage') {
                        $values[] = $storage->attributes()->name;
                        continue;
                    } else if ($key == 'description') {
                        foreach ($data->container->attr as $attr) {
                            if ($attr->attributes()->name == 'description') {
                                $values[] = $data->container->attr;
                                break;
                            }
                        }
                        continue;
                    }

                    switch($storage->attributes()->name) {
                      case 'LDAP':
                      case 'AD':
                        switch($key) {
                          case 'master':
                            break;
                          case 'hash':
                            $values[] = (string)$storage->attributes()->hash;
                            break;
                          case 'uri':
                            $uri = (string)$storage->uri;
                            $values[] = preg_replace('/\/[^\/]*$/', '', $uri);
                            break;
                          case 'basedn':
                            $uri = (string)$storage->uri;
                            $values[] = preg_replace('/ldaps?:\/\/[^\/]*\//', '', $uri);
                            break;
                          case 'userdn':
                            $handler = null;
                            foreach ($data->handler as $elt) {
                                if ($elt->attributes()->name == 'Rewrite') {
                                    $handler = $elt;
                                    break;
                                }
                            }
                            if ($handler) {
                                $value = null;
                                foreach ($handler->rewrite as $rewrite) {
                                    if ($rewrite->attributes()->context != 'request') {
                                        continue;
                                    }

                                    $substitution = $rewrite->attributes()->substitution;
                                    if (preg_match("/([^,]+),ou=%1,/", $substitution, $matches)) {
                                        $value = $matches[1];
                                    }
                                    break;
                                }
                                $values[] = $value;
                            } else {
                                $values[] = 'ou=People';
                            }
                            break;
                          default:
                            $values[] = (string)$storage->$key;
                        }
                        break;
                      case 'SQL':
                        switch($key) {
                          case 'dbhost':
                            $dsn = (string)$storage->dsn;
                            if (preg_match('/^DBI:mysql:/', $dsn)) {
                                $values[] = preg_match('/^DBI:mysql:[^:]+:([^:]+)/', $dsn, $matches) ? $matches[1] : '';
                            } else if (preg_match('/^DBI:Pg:/', $dsn)) {
                                $values[] = preg_match('/^DBI:Pg:[^;]+;host=([^;]+)/', $dsn, $matches) ? $matches[1] : '';
                            }
                            break;
                          case 'dbport':
                            $dsn = (string)$storage->dsn;
                            if (preg_match('/^DBI:mysql:/', $dsn)) {
                                $values[] = preg_match('/^DBI:mysql:[^:]+:[^:]+:([0-9]+)/', $dsn, $matches) ? $matches[1] : '';
                            } else if (preg_match('/^DBI:Pg:/', $dsn)) {
                                $values[] = preg_match('/^DBI:Pg:[^;]+;host=[^;]+;port=([0-9]+)/', $dsn, $matches) ? $matches[1] : '';
                            }
                            break;
                          default:
                            $values[] = $storage->$key;
                        }
                        break;
                      case 'SOAP':
                        switch($key) {
                          case 'status':
                            $status = (string)$data->status;
                            $values[] = $status && $status == 'disable' ? null : 'on';
                            break;
                          case 'tenantid':
                            $values[] = preg_match('/^o=([^,]+)/i', $storage->basedn, $matches) ? $matches[1] : null;
                            break;
                          case 'url':
                            $values[] = $storage->proxy;
                            break;
                          case 'admin':
                            $values[] = preg_match('/^cn=([^,]+)/i', $storage->binddn, $matches) ? $matches[1] : null;
                            break;
                          case 'attributes':
                            $attrs = array();
                            foreach ($sync->data as $sdata) {
                                if ($sdata->attributes()->name == $dname) {
                                    $sobject = $sdata->object;
                                    break;
                                }
                            }
                            if ($sobject) {
                                foreach ($sobject->syncattr as $attr) {
                                    $attrs[] = $attr->name;
                                }
                            }
                            $values[] = $attrs;
                            break;
                        }
                        break;
                      case 'GoogleApps':
                        switch($key) {
                          default:
                            $values[] = $storage->$key;
                            break;
                        }
                        break;
                      default:
                        $values[] = null;
                    }
                }
            }
        }

        return $values;
    }

    function setXmlFile($file, $params, $dname = 'LDAP') {
        $output = BASEDIR.'/tmp/'.basename($file);
        $orgdname = $dname;
        $dname = preg_replace("/\./", "_", $dname);

        $lp = $this->_lock($file, LOCK_EX);

        $dom = new DOMDocument;
        $dom->preserveWhiteSpace = false;
        if(!$dom->load($file)) {
            $this->_unlock($lp);
            return Ethna::raiseError("Can't open $file");
        }
        $dom->formatOutput = true;
        $delement = $dom->documentElement;

        $sync = $dom->getElementsByTagName("sync")->item(0);
        if (isset($params['master'])) {
            $master = $sync->getElementsByTagName("master")->item(0);
            if (!$master) {
                $master = $dom->createElement("master");
                $master->appendChild($dom->createElement("containerdn", "ou=Master"));
                $master->appendChild($dom->createElement("data", "MASTER"));
                $sync->appendChild($master);
            }
            $master->getElementsByTagName("data")->item(0)->nodeValue = $params['master'];
        }

        $storage = null;
        foreach ($dom->getElementsByTagName("data") as $data) {
            if($data->getAttribute("name") === $dname){
                $storage = $data->getElementsByTagName("storage")->item(0);
                if ($storage) {
                    break;
                }
            }
        }

        if ($storage == null) {
            if (isset($params['storage'])) {
                $sname = $params['storage'];
            } else {
                $sname = 'LDAP';
            }

            if (file_exists(BASEDIR.'/conf/lism/lism-'.$sname.'.conf')) {
                $strgtmpl = new DomDocument;
                $strgtmpl->load(BASEDIR.'/conf/lism/lism-'.$sname.'.conf');
                $data = $dom->importNode($strgtmpl->documentElement, true);
                $data->setAttribute("name", $dname);
                $data->getElementsByTagName("container")->item(0)->getElementsByTagName("rdn")->item(0)->nodeValue = "ou=$dname";
                $storage = $data->getElementsByTagName("storage")->item(0);

                if (!isset($params['master'])) {
                    $synctmpl = new DomDocument;
                    $synctmpl->load(BASEDIR.'/conf/lism/sync-'.$sname.'.conf');
                    $sdata = $dom->importNode($synctmpl->documentElement, true);
                    $sdata->setAttribute("name", $dname);
                }
            } else {
                $this->unlock(lp);
                return Ethna::raiseError("$sname template file doesn't exist");
            }

            $delement->appendChild($data);
            if (!isset($params['master'])) {
                $sync->appendChild($sdata);
            }

            switch ($sname) {
              case 'SOAP':
                $data->getElementByTagName("container")->item[0]->getElementByTagName("rdn")->item[0]->nodeValue = "ou=$orgdname";
                break;
              default:
            }
        } else {
            $sname = $storage->getAttribute("name");
        }

        if ($params === null) {
            foreach ($sync->getElementsByTagName("data") as $sdata) {
                if ($sdata->getAttribute("name") == $dname) {
                    break;
                }
            }
            if ($sdata->parentNode->nodeName == "master") {
                $sync->removeChild($sdata->parentNode);
            } else {
                $sdata->parentNode->removeChild($sdata);
            }

            $data->parentNode->removeChild($data);

            $dom->save(BASEDIR.'/tmp/'.basename($file));
            $dom->saveXML();

            if (!move($output, $file)) {
                $this->_unlock($lp);
                return Ethna::raiseError("Renaming $file failed");
            }

            $this->_replicate($file);

            $this->_unlock($lp);

            return true;
        }

        foreach ($params as $key => $value) {
            switch($sname) {
              case 'LDAP':
              case 'AD':
                $rewrite = null;
                $setval = null;
                foreach ($data->getElementsByTagName("handler") as $elt) {
                    if ($elt->getAttribute("name") == 'Rewrite') {
                        $rewrite = $elt;
                    } else if ($elt->getAttribute("name") == 'Setval') {
                        $setval = $elt;
                    }
                }

                switch($key) {
                  case 'uri':
                    if (!isset($params['basedn'])) {
                        break;
                    }
                    $uri = $params['uri'].'/'.$params['basedn'];
                    $storage->getElementsByTagName($key)->item(0)->nodeValue = $uri;
                    break;
                  case 'basedn':
                    if ($sname != 'AD') {
                        break;
                    }

                    $elts = split(', *', $params['basedn']);
                    $domain = '';
                    for ($i = count($elts); $i > 0; $i--) {
                        if (preg_match('/^dc=(.+)/i', $elts[$i-1], $matches)) {
                            $domain = '.'.$matches[1].$domain;
                        } else {
                            break;
                        }
                    }
                    $domain = substr($domain, 1);
                    $entry = $setval->getElementsByTagName('entry')->item(0);
                    foreach ($entry->getElementsByTagName('default') as $elt) {
                        if ($elt->getAttribute("name") == 'userPrincipalName') {
                            $elt->getElementsByTagName("value")->item(0)->nodeValue = preg_replace("/'@[^@']*'$/", "'@$domain'", $elt->getElementsByTagName("value")->item(0)->nodeValue);
                        }
                    }
                    break;
                  case 'hash':
                    $storage->setAttribute('hash', $value);
                    break;
                  case 'userdn':
                    if ($rewrite) {
                        $rewrite->parentNode->removeChild($rewrite);
                    }
                    if (!preg_match("/^ou=People$/i", $value)) {
                        $rewrite = $data->appendChild($dom->createElement("handler"));
                        $rewrite->setAttribute("name", "Rewrite");
                        if ($value) {
                            $rewrite->appendChild($this->_createRewrite($dom, "request", "ou=People,ou=(Master|LDAP|AD),", "$value,ou=%1,"));
                            $rewrite->appendChild($this->_createRewrite($dom, "searchResult", "$value,ou=(Master|LDAP|AD),", "ou=People,ou=%1,"));
                        } else {
                            $rewrite->appendChild($this->_createRewrite($dom, "searchResult", "(uid=[^,]+).*,ou=(Master|LDAP|AD),", "%1,ou=People,ou=%2,"));
                        }
                    }
                    break;
                  default:
                    $storage->getElementsByTagName($key)->item(0)->nodeValue = $params[$key];
                }
                break;
              case 'SQL':
                switch($key) {
                  case 'dbhost':
                    $dsn = $storage->getElementsByTagName('dsn')->item(0)->nodeValue;
                    if (preg_match('/^DBI:mysql:/', $dsn)) {
                        preg_replace('/^DBI:mysql:([^:]+):[^:]+/', 'DBI:mysql:$1:'.$params['dbhost'], $dsn);
                    } else if (preg_match('/^DBI:Pg:/', $dsn)) {
                        preg_replace('/^DBI:Pg:([^;]+);host=[^;]+/', 'DBI:Pg:$1:host='.$params['dbhost'], $dsn);
                    }
                    $storage->getElementsByTagName('dsn')->item(0)->nodeValue = $dsn;
                    break;
                  case 'dbport':
                    if (!$params['dbport']) {
                        break;
                    }

                    $dsn = $storage->getElementsByTagName('dsn')->item(0)->nodeValue;
                    if (preg_match('/^DBI:mysql:/', $dsn)) {
                        if (preg_match('/^DBI:mysql:[^:]+:[^:]+:[0-9]+/', $dsn)) {
                            preg_replace('/^DBI:mysql:([^:]+):([^:]+):[0-9]+/', 'DBI:mysql:$1:$2:'.$params['dbport'], $dsn);
                        } else {
                            preg_replace('/^DBI:mysql:([^:]+):([^:]+)/', 'DBI:mysql:$1:$2:'.$params['dbport'], $dsn);
                        }
                    } else if (preg_match('/^DBI:Pg:/', $dsn)) {
                        if (preg_match('/^DBI:Pg:[^:]+;host=[^;]+;port=[0-9]+/', $dsn)) {
                            preg_replace('/^DBI:Pg:([^;]+);(host=[^;]+);port=[0-9]+/', 'DBI:Pg:$1;$2;port='.$params['dbport'], $dsn);
                        } else {
                            preg_replace('/^DBI:Pg:([^;]+);(host=[^;]+)/', 'DBI:Pg:$1;$2;port='.$params['dbport'], $dsn);
                        }
                    }
                    $storage->getElementsByTagName('dsn')->item(0)->nodeValue = $dsn;
                    break;
                  default:
                    $storage->getElementsByTagName($key)->item(0)->nodeValue = $params[$key];
                }
                break;
              case 'SOAP':
                switch($key) {
                  case 'status':
                    $data->getElementsByTagName('status')->item(0)->nodeValue = $params['status'] == 'on' ? 'enable' : 'disable';
                    break;
                  case 'tenantid':
                    $storage->getElementsByTagName('basedn')->item(0)->nodeValue = $params['tenantid'] ? 'o='.$params['tenantid'].',o=lism' : 'o=lism';
                    break;
                  case 'url':
                    if (preg_match('/\/lism\.cgi$/', $params['url'])) {
                        $package = 'SoapLism';
                    } else {
                        $package = 'SoapLdap';
                    }
                    $storage->getElementsByTagName('proxy')->item(0)->nodeValue = $params['url'];
                    $storage->getElementsByTagName('uri')->item(0)->nodeValue = preg_replace('/^(https?:\/\/[^\/]+).*$/', '$1', $params['url'])."/$package";
                    break;
                  case 'admin':
                    $storage->getElementsByTagName('binddn')->item(0)->nodeValue = 'cn='.$params['admin'].','.$storage->getElementsByTagName('basedn')->item(0)->nodeValue;
                    break;
                  case 'password':
                    $storage->getElementsByTagName('bindpw')->item(0)->nodeValue = $params['password'];
                    break;
                  case 'attributes':
                    foreach ($sync->getElementsByTagName("data") as $sdata) {
                        if ($sdata->getAttribute("name") == $dname) {
                            $sobj = $sdata->getElementsByTagName("object")->item(0);
                            break;
                        }
                        }
                    $newsobj = $this->_createSyncObject($dom, $params['attributes']);
                    $sobj->parentNode->replaceChild($newsobj, $sobj);
                    break;
                }
                break;
              case 'GoogleApps':
                switch($key) {
                  default:
                    $storage->getElementsByTagName($key)->item(0)->nodeValue = $params[$key];
                    break;
                }
                break;
            }
        }

        $dom->save($output);
        $dom->saveXML();

        if (!move($output, $file)) {
            $this->_unlock($lp);
            return Ethna::raiseError("Renaming $file failed");
        }

        $this->_replicate($file);

        $this->_unlock($lp);

        return true;
    }

    function readCluster($params) {
        $MASTERATTR = 'lismClusterMaster';
        $ACTIVEATTR = 'lismClusterActive';

        $conf = $this->config->get('ldap');
        $secioss = $this->config->get('secioss');

        $ldap = ldap_connect($conf['uri']);
        if(!$ldap){
            return Ethna::raiseError("Could not connect to LDAP server.", E_DB_CONNECT);
        }

        if (isset($secioss['suffix'])) {
            $suffix = $secioss['suffix'];
        } else {
            $suffix = $secioss['basedn'];
        }
        if (!($lr = ldap_read($ldap, 'cn=cluster,'.$suffix, '(objectClass=*)'))) {
            return Ethna::raiseError("Could not get cluster information.", E_DB_CONNECT);
        }

        $entry = ldap_first_entry($ldap, $lr);
        $attrs = ldap_get_attributes($ldap, $entry);
        $master = isset($attrs[$MASTERATTR]) ? $attrs[$MASTERATTR][0] : '';

        $values = array();
        foreach ($params as $key) {
            switch($key) {
              case 'master':
                $values[] = $master;
                break;
              case 'cluster':
                $vals = array();
                if (isset($attrs[$ACTIVEATTR])) {
                    for ($i = 0; $i < $attrs[$ACTIVEATTR]['count']; $i++) {
                        if ($master != $attrs[$ACTIVEATTR][$i]) {
                            $vals[] = $attrs[$ACTIVEATTR][$i];
                        }
                    }
                }
                $values[] = $vals;
                break;
              default:
                $values[] = '';
            }
        }

        return $values;
    }

    function _createSyncObject($dom, $attrs) {
        $obj = $dom->createElement("object");
        $obj->setAttribute("name", "User");
        $obj->appendChild($dom->createElement("syncdn", "*"));
        $obj->appendChild($dom->createElement("syncfilter", "(objectClass=inetOrgPerson)"));
        foreach ($attrs as $attr) {
            $syncattr = $dom->createElement("syncattr");
            $syncattr->appendChild($dom->createElement("name", $attr));
            $obj->appendChild($syncattr);
        }

        return $obj;
    }

    function _createRewrite($dom, $context, $match, $substitution) {
        $rewrite = $dom->createElement("rewrite");
        $rewrite->setAttribute("context", $context);
        $rewrite->setAttribute("match", $match);
        $rewrite->setAttribute("substitution", $substitution);

        return $rewrite;
    }

    function setPasswdFile($file, $id, $password) {
        if (!$password) {
            return Ethna::raiseError("Password is empty");
        }

        if (!(file_exists($file))) {
            return Ethna::raiseError("$file doesn't exist");
        }

        $lp = $this->_lock($file, LOCK_EX);

        if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
            system(HTPASSWD." $file $id $password", $rc);
            if ($rc !== 0) {
                return Ethna::raiseError("htpasswd failed");
            }
        } else {
            $fp = fopen($file, 'w');
            if ($fp === false) {
                return Ethna::raiseError("Can't open $file to write");
            }

            $token = array_merge(range('0', '9'), range('a', 'z'), range('A', 'Z'));
            $salt = $token[rand(0, count($token) - 1)].$token[rand(0, count($token) - 1)];
            $password = crypt($password, $salt);
            fwrite($fp, "$id:$password");
            fclose($fp);
        }

        $this->_replicate($file);

        $this->_unlock($lp);

        return true;
    }

    function _lock($file, $op) {
        $lockfile = BASEDIR.'/tmp/'.basename($file).'.lock';

        $fp = fopen($lockfile, 'w');
        flock($fp, $op);

        return $fp;

    }

    function _unlock($fp) {
        flock($fp, LOCK_UN);
        fclose($fp);

        return 0;
    }

    function _replicate($file) {
        if (file_exists(HOSTS)) {
            foreach (file(HOSTS, FILE_IGNORE_NEW_LINES) as $host) {
                system(SCRIPT." $host $file");
            }
        }
    }
}
?>
