forked from verdnatura/hedera-web
256 lines
6.0 KiB
PHP
256 lines
6.0 KiB
PHP
<?php
|
|
|
|
class Account {
|
|
static function trySync($db, $userName, $password = NULL) {
|
|
$isSync = $db->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);
|
|
}
|
|
|
|
$bcryptPassword = password_hash($password, PASSWORD_BCRYPT);
|
|
|
|
$userId = $db->getValue(
|
|
'SELECT id FROM account.user WHERE `name` = #',
|
|
[$userName]
|
|
);
|
|
$db->query(
|
|
'CALL account.user_syncPassword(#, #)',
|
|
[$userId, $password]
|
|
);
|
|
$db->query(
|
|
'UPDATE account.user SET
|
|
sync = TRUE,
|
|
bcryptPassword = #
|
|
WHERE id = #',
|
|
[$bcryptPassword, $userId]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 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`, `role`
|
|
FROM account.user
|
|
WHERE `name` = #',
|
|
[$userName]
|
|
);
|
|
|
|
$accountCfg = $db->getObject(
|
|
'SELECT homedir, shell, idBase
|
|
FROM account.accountConfig'
|
|
);
|
|
|
|
$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,
|
|
'homeDirectory' => "$accountCfg->homedir/$userName",
|
|
'loginShell' => $accountCfg->shell,
|
|
'uidNumber' => $accountCfg->idBase + $user->id,
|
|
'gidNumber' => $accountCfg->idBase + $user->role
|
|
];
|
|
|
|
// 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);
|
|
if ($entry) ldap_delete($ds, $dn);
|
|
|
|
$addAttrs = [];
|
|
|
|
foreach ($attrs as $attribute => $value)
|
|
if (!empty($value))
|
|
$addAttrs[$attribute] = $value;
|
|
|
|
$addAttrs = array_merge($addAttrs, [
|
|
'objectClass' => ['inetOrgPerson', 'posixAccount'],
|
|
'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
|
|
FROM account.sambaConfig'
|
|
);
|
|
|
|
$accountCfg = $db->getObject(
|
|
'SELECT idBase
|
|
FROM account.accountConfig'
|
|
);
|
|
|
|
$domain = $db->getValue('SELECT domain FROM account.mailConfig');
|
|
|
|
$samba = new SshConnection($conf->host
|
|
,$conf->sshUser
|
|
,base64_decode($conf->sshPass)
|
|
);
|
|
|
|
$scriptDir = '/mnt/storage/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
|
|
,$accountCfg->idBase + $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) .'"';
|
|
}
|
|
}
|