getValue ( 'SELECT sync FROM account.user WHERE name = #', [$userName] ); if ($isSync) return; self::sync ($db, $userName, $password); } static function sync ($db, $userName, $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 = #', [$userName] ); if ($hasAccount) { self::ldapSync ($db, $userName, $password); self::sambaSync ($db, $userName, $password); } $db->query ( 'UPDATE account.user SET sync = TRUE WHERE name = #', [$userName] ); } /** * Synchronizes the user credentials in the LDAP server. */ static function ldapSync ($db, $userName, $password) { // 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)); try { 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)); // Prepares the data $domain = $db->getValue ('SELECT domain FROM account.mailConfig'); $user = $db->getObject ( 'SELECT id, nickname, lang FROM account.user WHERE name = #', [$userName] ); $cn = empty ($user->nickname) ? $userName : $user->nickname; $nameArgs = explode (' ', $user->nickname); $givenName = $nameArgs[0]; if (count ($nameArgs) > 1) $sn = $nameArgs[1]; if (empty ($sn)) $sn = 'Empty'; $attrs = [ 'cn' => $cn, 'displayName' => $user->nickname, 'givenName' => $givenName, 'sn' => $sn, 'mail' => "$userName@{$domain}", 'userPassword' => sshaEncode ($password), 'preferredLanguage' => $user->lang ]; // Search the user entry $filter = "uid=$userName"; if (!empty($conf->filter)) $filter = "(&($filter)($conf->filter))"; $res = ldap_search ($ds, $conf->baseDn, $filter); if (!$res) throw new Exception ("Can't get the LDAP entry: ". ldapError ($ds)); $dn = "uid=$userName,{$conf->baseDn}"; $entry = ldap_first_entry ($ds, $res); $classes = ldap_get_values ($ds, $entry, 'objectClass'); if (!in_array ('inetOrgPerson', $classes)) { ldap_delete ($ds, $dn); $entry = NULL; } if ($entry) { $modifs = []; $curAttrs = ldap_get_attributes ($ds, $entry); foreach ($attrs as $attribute => $value) if (!empty ($value)) { $modifs[] = [ 'attrib' => $attribute, 'modtype' => LDAP_MODIFY_BATCH_REPLACE, 'values' => [$value] ]; } elseif (isset ($curAttrs[$attribute])) { $modifs[] = [ 'attrib' => $attribute, 'modtype' => LDAP_MODIFY_BATCH_REMOVE_ALL ]; } $updated = ldap_modify_batch ($ds, $dn, $modifs); } else { $addAttrs = []; foreach ($attrs as $attribute => $value) if (!empty ($value)) $addAttrs[$attribute] = $value; $addAttrs = array_merge ($addAttrs, [ 'objectClass' => ['inetOrgPerson'], 'uid' => $userName ]); $updated = ldap_add ($ds, $dn, $addAttrs); } if (!$updated) throw new Exception ("Can't update the LDAP entry: ". ldapError ($ds)); } catch (Exception $e) { ldap_unbind ($ds); throw $e; } } /** * Synchronizes the user credentials in the Samba server. */ static function sambaSync ($db, $userName, $password) { $conf = $db->getObject ( 'SELECT host, sshUser, sshPass, uidBase FROM account.sambaConfig' ); $domain = $db->getValue ('SELECT domain FROM account.mailConfig'); $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 = #', [$userName]); $samba->exec ("$scriptDir/create-user.sh %s %s %s" ,$userName ,$conf->uidBase + $userId ,"$userName@{$domain}" ); // Syncronizes the Samba password if (empty ($password)) return; $samba->exec ("$scriptDir/set-password.sh %s %s" ,$userName ,$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); return ssh2_exec ($this->connection, $command); } /** * Escapes the double quotes from an string. */ static function escape ($str) { return '"'. str_replace ('"', '\\"', $str) .'"'; } }