userList = array(); $this->userIsAdmin = array(); $this->userUserGroups = array(); $this->userPasswordGroups = array(); $this->key = null; $this->alg = MCRYPT_RIJNDAEL_256; $this->mode = MCRYPT_MODE_ECB; if ($username !== null) { if ($password !== null) { if ($driver_options !== null) { parent::__construct($dsn, $username, $password, $driver_options); } else { parent::__construct($dsn, $username, $password); } } else { parent::__construct($dsn, $username); } } else { parent::__construct($dsn); } } function setKey($key) { $this->key = $key; } function userExists($username) { if (in_array($username, $this->userList)) { return true; } $sth = $this->prepare('SELECT id FROM users WHERE username = ?'); $sth->execute(array($username)); if ($sth->fetch()) { $this->userList[] = $username; return true; } return false; } function isAdmin($username) { if (!array_key_exists($username, $this->userIsAdmin)) { $userIsAdmin[$username] = false; $sth = $this->prepare('SELECT administrator FROM users WHERE username = ?'); $sth->execute(array($username)); if ($row = $sth->fetch()) { $this->userIsAdmin[$username] = ($row['administrator'] == 1); } } return $this->userIsAdmin[$username]; } function userUsergroups($username) { if (!array_key_exists($username, $this->userUserGroups)) { $this->userUserGroups[$username] = array(); $sth = $this->prepare('SELECT groups FROM users WHERE username = ?'); $sth->execute(array($username)); if ($row = $sth->fetch()) { $this->userUserGroups[$username] = explode(':', $row['groups']); } } return $this->userUserGroups[$username]; } function userPasswordgroups($username) { if (!array_key_exists($username, $this->userPasswordGroups)) { $this->userPasswordGroups[$username] = array(); if ($this->isAdmin($username)) { $query = 'SELECT groupname || \'+\' AS permissions FROM passwordgroups'; } else { $query = 'SELECT permissions FROM usergroups WHERE groupname IN (\'' . join("', '", $this->userUsergroups($username)) . '\')'; } $sth = $this->prepare($query); $sth->execute(); while ($row = $sth->fetch()) { $pwgs = explode(':', $row['permissions']); foreach ($pwgs as $pwg) { $writable = false; if (substr($pwg, -1) == '+') { $pwg = substr($pwg, 0, -1); $writable = true; } if (!array_key_exists($pwg, $this->userPasswordGroups[$username])) { $this->userPasswordGroups[$username][$pwg] = ($writable) ? 'rw' : 'r'; } else if ($writable) { $this->userPasswordGroups[$username][$pwg] = 'rw'; } } } } return $this->userPasswordGroups[$username]; } function changePassword($username, $oldpw, $newpw1, $newpw2) { if ($newpw1 != $newpw2) { throw new PWSdbhException('New passwords don\'t match', PWSDBH_NOMATCH); } if ($newpw1 == '') { throw new PWSdbhException('No new password is provided!', PWSDBH_NONEWPW); } if ($this->weakPassword($newpw1)) { throw new PWSdhbException('New password is too weak', PWSDBH_WEAKPW); } $sth = $this->prepare('SELECT username, password FROM users WHERE username = ?'); if ($sth->execute(array($username))) { if ($row = $sth->fetch()) { if (crypt($oldpw, $row['password']) != $row['password']) { throw new PWSdbhException('Old password doesn\'t match!', PWSDBH_BADOLD); } else { $update_sth = $this->prepare('UPDATE users SET password = ? WHERE username = ?'); if ($update_sth->execute(array(crypt($newpw1), $username))) { return true; } } } else { throw new PWSdbhException('No such user!', PWSDBH_BADUSER); } } } function weakPassword($password) { if (!preg_match('/[0-9]/', $password)) { return true; } if (!preg_match('/[a-z]/', $password)) { return true; } if (!preg_match('/[A-Z]/', $password)) { return true; } return false; } function passwordgroupAccessible($groupname, $username, $forwrite = false) { if ($this->isAdmin($username)) { return true; } $accessibleGroups = $this->userPasswordgroups($username); return (array_key_exists($groupname, $accessibleGroups) && (!$forwrite || $accessibleGroups[$groupname] == 'rw')); } function getPasswordgroupData($groupname) { $sth = $this->prepare('SELECT id, groupname, description FROM passwordgroups WHERE groupname = ?'); $sth->execute(array($_POST['name'])); if ($row = $sth->fetch()) { return $row; } return null; } function passwordAccessible($passwordId, $username, $forwrite = false) { if ($this->isAdmin($username)) { return true; } $sth = $this->prepare('SELECT id, groups FROM passwords WHERE id = ?'); $sth->execute(array($passwordId)); if ($row = $sth->fetch()) { $groups = explode(':', $row['groups']); foreach ($groups as $group) { if ($this->passwordgroupAccessible($group, $username, $forwrite)) { return true; } } } return false; } function getPasswordData($passwordId) { $sth = $this->prepare('SELECT id, short, long, username, password, additional, groups FROM passwords WHERE id = ?'); $sth->execute(array($passwordId)); if ($row = $sth->fetch()) { if (substr($row['password'], 0, 7) == '{CLEAR}') { $row['password'] = substr($row['password'], 7); $this->updatePassword($passwordId, $row['password']); } else { $row['password'] = $this->decryptPassword($row['password']); } $this->updatePasswordAccess($passwordId); return $row; } return array(); } function updatePassword($passwordId, $newPassword, $username = null) { $query = ''; $params = array(); if ($username === null) { $query = 'UPDATE passwords SET password = ? WHERE id = ?'; $params = array($this->encryptPassword($newPassword), $passwordId); } else { $query = 'UPDATE passwords SET password = ?, modifiedby = ?, modifiedat = datetime(\'now\') WHERE id = ?'; $params = array($this->encryptPassword($newPassword), $username, $passwordId); } $sth = $this->prepare($query); $sth->execute($params); } function updatePasswordAccess($passwordId) { $sth = $this->prepare('UPDATE passwords SET lastaccess = datetime(\'now\') WHERE id = ?'); $sth->execute(array($passwordId)); } function encryptPassword($password) { return base64_encode($this->_encryptPassword($password)); } function decryptPassword($password) { return $this->_decryptPassword(base64_decode($password)); } private function _encryptPassword($password) { $cipher = mcrypt_module_open($this->alg, '', 'ecb', ''); $iv_size = mcrypt_get_iv_size($this->alg, $this->mode); $iv = mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM); mcrypt_generic_init($cipher, $this->key, $iv); $enc = mcrypt_generic($cipher, $password); mcrypt_generic_deinit($cipher); return $enc; } private function _decryptPassword($password) { $cipher = mcrypt_module_open($this->alg, '', 'ecb', ''); $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB); $iv = mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM); mcrypt_generic_init($cipher, $this->key, $iv); $dec = mdecrypt_generic($cipher, $password); mcrypt_generic_deinit($cipher); for ($i = 0; $i < strlen($dec); $i++) { if (ord(substr($dec, $i, 1)) == 0) break; } if ($i < strlen($dec)) { $dec = substr($dec, 0, $i); } return $dec; } function authUser($username, $password) { $sth = $this->prepare('SELECT username, password FROM users WHERE username = ?'); $sth->execute(array($username)); if ($row = $sth->fetch()) { if (crypt($password, $row['password']) == $row['password']) { $this->updateUserRecord($username); return true; } } throw new PWSdbhException('Bad username or password!', PWSDBH_BADACCOUNT); return false; } function updateUserRecord($username) { $sth = $this->prepare('UPDATE users SET lastlogin = datetime(\'now\') WHERE username = ?'); $sth->execute(array($username)); } function getAllPasswords($pwgroup) { $sth = $this->prepare('SELECT id, short FROM passwords WHERE groups LIKE ? OR groups LIKE ? OR groups LIKE ? OR groups = ?'); $sth->execute(array('%:' . $pwgroup . ':%', '%:' . $pwgroup, $pwgroup . ':%', $pwgroup)); return $sth->fetchAll(); } function findPasswords($query) { $sth = $this->prepare('SELECT id, short, groups FROM passwords WHERE short LIKE :querytext OR long LIKE :querytext ESCAPE \'~\' ORDER BY short'); $sth->execute(array(':querytext' => '%' . str_replace(array('%', '_'), array('~%', '~_'), $query) . '%')); return $sth->fetchAll(); } function getClearPasswords() { $sth = $this->prepare('SELECT id, password FROM passwords WHERE password LIKE ?'); $sth->execute(array('{CLEAR}%')); return $sth->fetchAll(); } function getInactiveUsers($inactiveInterval) { $sth = $this->prepare('SELECT id, username, lastlogin, administrator FROM users WHERE datetime(lastlogin, ?) < datetime(\'now\')'); $sth->execute(array($inactiveInterval)); return $sth->fetchAll(); } function getInactivePasswords($inactiveInterval) { $sth = $this->prepare('SELECT id, short, long, username, groups, lastaccess FROM passwords WHERE datetime(lastaccess, ?) < datetime(\'now\')'); $sth->execute(array($inactiveInterval)); return $sth->fetchAll(); } } } if (!isset($pwsdbhs)) { $pwsdbhs = array(); } if (!function_exists('pwsdbh')) { function pwsdbh($dsn, $username = null, $password = null, $driver_options = null) { global $pwsdbhs; $key = $dsn . '|' . $username . '|' . $password . '|' . $driver_options; if (array_key_exists($key, $pwsdbhs)) { if ($pwsdbhs[$key] === null) { $pwsdbhs[$key] = new PWSdb($dsn, $username, $password, $driver_options); } } else { $pwsdbhs[$key] = new PWSdb($dsn, $username, $password, $driver_options); } return $pwsdbhs[$key]; } }