. */ /* login is stored as : @@url;login Password is salted (3 random characters) and encrypted All is encrypted with AES256 and key : PKDBF2(hmac_sha256, master key, url, 1000) */ $MAX_ENTRY_LEN = 512; $USERS_PATH = "./users/"; $TARGET_DB_VERSION = 2; function sanitize($val) { return (isset($_POST[$val])) ? addslashes($_POST[$val]) : ""; } // From http://php.net/manual/en/function.copy.php function recurse_copy($src,$dst) { $dir = opendir($src); if ($dir == FALSE) return FALSE; if (!@mkdir($dst)) return FALSE; while(false !== ( $file = readdir($dir)) ) { if (( $file != '.' ) && ( $file != '..' )) { if ( is_dir($src . '/' . $file) ) { return recurse_copy($src . '/' . $file,$dst . '/' . $file); } else { copy($src . '/' . $file,$dst . '/' . $file); } } } closedir($dir); return TRUE; } function create_user($user) { global $USERS_PATH; if (strpos($user, "..") || strpos($user, "/") || $user[0] == "." || $user[0] == "_") { echo "
Invalid user
"; } else { $user = $USERS_PATH . $user; if (file_exists($user)) { echo "
User already exists
"; } else { if (!recurse_copy("./ref", $user)) { echo "
Cannot create user $user
"; } else { return true; } } } return false; } function _migrate_0($user, $db) { try { $db->query("ALTER TABLE gpass ADD access_token VARCHAR(32)"); $db->query("ALTER TABLE gpass ADD shadow_login VARCHAR(32)"); $db->query("ALTER TABLE gpass ADD salt VARCHAR(32)"); $db->query("CREATE TABLE db_version(version INTEGER)"); $db->query("INSERT INTO db_version (version) VALUES (1)"); } catch(Exception $e) { $db->close(); echo "
Unable to load database for user $user ! : $e
"; return -1; } return 0; } function _migrate_1($user, $db) { try { $db->query("CREATE TABLE conf(db_version INTEGER, last_access_time INTEGER)"); $db->query("INSERT INTO conf VALUES(2, 0)"); } catch(Exception $e) { $db->close(); echo "
Unable to load database for user $user ! : $e
"; return -1; } return 0; } function migrate_database($user, $db) { global $TARGET_DB_VERSION; $migration_functions = ['_migrate_0', '_migrate_1']; $version = $db->querySingle("SELECT db_version FROM conf"); if ($version == false || $version == -1) { $version = $db->querySingle("SELECT version FROM db_version"); if ($version == false || $version == -1) $version = 0; } for($i=$version; $i<$TARGET_DB_VERSION; $i++) { if ($migration_functions[$i]($user, $db)) return -1; } return 0; } function load_database($user) { global $USERS_PATH; try { $db = new SQLite3($USERS_PATH . "$user/gpass.bdd", SQLITE3_OPEN_READWRITE); } catch(Exception $e) { echo "
Unable to load database for user $user !
"; return null; } if (migrate_database($user, $db)) return null; // New access need to reset crypto unset($_SESSION['td']); return $db; } function add_entry($user, $login, $password, $shadow_login, $salt, $access_token) { $db = load_database($user); if ($db == null) { echo "Unknown user"; return false; } $count = $db->querySingle("SELECT COUNT(*) FROM gpass WHERE login='" . $login . "'"); if ($count != 0) { echo "Entry already exists"; return false; } $result = $db->query("INSERT INTO gpass ('login', 'password', 'shadow_login', 'salt', 'access_token') VALUES ('" . $login . "', '" . $password . "', '" . $shadow_login . "', '" . $salt . "', '" . $access_token . "')"); /* error_log("INSERT INTO gpass ('login', 'password', 'shadow_login', 'salt', 'access_token') VALUES */ /* ('" . $login . "', '" . $password . "', '" . $shadow_login . "', '" . $salt . "', '" . $access_token . "')"); */ $db->close(); if ($result == FALSE) { echo "Error " . $db->lastErrorMsg(); return false; } else { echo "OK"; return true; } } function delete_entry($user, $login, $access_token) { $db = load_database($user); if ($db == null) { echo "Unknown user"; return false; } if ($USE_SHADOW_LOGINS) { $db_ac = $db->querySingle("SELECT access_token FROM gpass WHERE login='" . $login . "'"); if (strlen($db_ac) != 0 && strcmp($db_ac, $access_token)) { $db->close(); echo "Bad access token"; return false; } } $result = $db->query("DELETE FROM gpass WHERE login='" . $login . "'"); $db->close(); if ($result == FALSE) { echo "Error " . $db->lastErrorMsg(); return false; } else { echo "OK"; return true; } } function update_entry($user, $mkey, $old_login, $url, $login, $password, $shadow_login, $salt, $old_access_token, $new_access_token) { if (delete_entry($user, $old_login, $old_access_token)) return add_entry($user, $mkey, $url, $login, $password, $shadow_login, $salt, $new_access_token); return false; } function list_entries($user) { $db = load_database($user); if ($db == null) return; $result = $db->query("SELECT * FROM gpass"); $first = false; header('Content-Type: application/json'); echo "{ \"entries\" : [\n"; while (($row = $result->fetchArray())) { if ($first) echo ","; else $first = true; if (!strlen($row['shadow_login'])) echo "{\"login\" : \"" . $row['login'] . "\", \"password\" : \"" . $row['password'] . "\" }\n"; else echo "{\"shadow_login\" : \"" . $row['shadow_login'] . "\", \"salt\" : \"" . $row['salt'] . "\" }\n"; } echo "]}"; $db->close(); } function get_secure_entries($user, $access_tokens) { $db = load_database($user); if ($db == null) return; $query = "SELECT access_token, login, password FROM gpass WHERE access_token IN ("; $first = false; foreach (preg_split("/,/", $access_tokens) as $ac) { /* error_log($ac); */ if ($first) $query .= ", "; else $first = true; $query .= "'$ac'"; } $query .= ")"; //error_log($query); $result = $db->query($query); header('Content-Type: application/json'); $first = false; echo "{ \"entries\" : [\n"; while (($row = $result->fetchArray())) { if ($first) echo ","; else $first = true; echo "{\"access_token\" : \"" . $row['access_token'] . "\", \"login\" : \"" . $row['login'] . "\", \"password\" : \"" . $row['password'] . "\" }\n"; } echo "]}"; $db->close(); } ?>