getValue ( 'SELECT sync FROM account.user WHERE name = #', [$user] ); if ($isSync) return; self::sync ($db, $user, $password); } static function sync ($db, $user, $password = NULL, $force = TRUE) { $hasAccount = $db->getValue ( 'SELECT COUNT(*) > 0 FROM account.user u JOIN account.account a ON u.id = a.id WHERE u.name = #', [$user] ); if ($hasAccount) { self::ldapSync ($db, $user, $password); self::sambaSync ($db, $user, $password); } $db->query ( 'UPDATE account.user SET sync = TRUE WHERE name = #', [$user] ); } /** * Synchronizes the user credentials in the LDAP server. */ static function ldapSync ($db, $user, $password) { if (empty ($password)) return; // Gets LDAP configuration parameters $conf = $db->getObject ( 'SELECT host, rdn, password, baseDn, filter FROM account.ldapConfig'); // Connects an authenticates against server $ds = ldap_connect ($conf->host); if (!$ds) throw new Exception ("Can't connect to LDAP server: ". ldapError ($ds)); ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3); $bind = ldap_bind ($ds, $conf->rdn, base64_decode ($conf->password)); if (!$bind) throw new Exception ("Authentication failed on LDAP server: ". ldapError ($ds)); // Search the user entry $res = ldap_search ($ds, $conf->baseDn, "(&(uid=$user)($conf->filter))"); if (!$res) throw new Exception ("Can't get the LDAP entry: ". ldapError ($ds)); $dn = "uid=$user,{$conf->baseDn}"; $entry = ldap_first_entry ($ds, $res); if ($entry) { $info = ['userPassword' => sshaEncode ($password)]; ldap_modify ($ds, $dn, $info); } else { $info = [ 'objectClass' => ['account', 'simpleSecurityObject', 'top'], 'uid' => $user, 'userPassword' => sshaEncode ($password) ]; ldap_add ($ds, $dn, $info); } ldap_unbind ($ds); } /** * Synchronizes the user credentials in the Samba server. */ static function sambaSync ($db, $user, $password) { $conf = $db->getObject ( 'SELECT host, sshUser, sshPass, domain, uidBase FROM account.sambaConfig' ); $samba = new SshConnection ($conf->host ,$conf->sshUser ,base64_decode ($conf->sshPass) ); $scriptDir = '/mnt/cluster/scripts'; // Creates the Samba user and initializes it's home directory $userId = $db->getValue ( 'SELECT id FROM account.user WHERE name = #', [$user]); $samba->exec ("$scriptDir/create-user.sh %s %s %s" ,$user ,$conf->uidBase + $userId ,"$user@{$conf->domain}" ); // Syncronizes the Samba password if (empty ($password)) return; $samba->exec ("$scriptDir/set-password.sh %s %s" ,$user ,$password ); } } function ldapError ($ds) { return ldap_errno ($ds) .': '. ldap_error ($ds); } function sshaEncode ($value) { mt_srand ((double) microtime () * 1000000); $salt = pack ('CCCC', mt_rand (), mt_rand (), mt_rand (), mt_rand ()); $hash = '{SSHA}' . base64_encode (pack ('H*', sha1 ($value . $salt)) . $salt); return $hash; } function sshaVerify ($hash, $value) { $ohash = base64_decode (substr ($hash, 6)); $osalt = substr ($ohash, 20); $ohash = substr ($ohash, 0, 20); $nhash = pack ('H*', sha1 ($value . $osalt)); return $ohash == $nhash; } class SshConnection { var $connection; /** * Abrebiated method to make SSH connections. */ function __construct ($host, $user, $password) { $this->connection = $connection = ssh2_connect ($host); if (!$connection) throw new Exception ("Can't connect to SSH server $host"); $authOk = ssh2_auth_password ($connection, $user, $password); if (!$authOk) throw new Exception ("SSH authentication failed on server $host"); return $connection; } /** * Executes a command on the host. */ function exec () { $nargs = func_num_args (); $args = func_get_args (); for ($i = 1; $i < $nargs; $i++) $args[$i] = self::escape ($args[$i]); $command = call_user_func_array ('sprintf', $args); error_log ($command); return ssh2_exec ($this->connection, $command); } /** * Escapes the double quotes from an string. */ static function escape ($str) { return '"'. str_replace ('"', '\\"', $str) .'"'; } }