Commit 6d313884 authored by Murray Cumming's avatar Murray Cumming

Escape database connection details properly.

* glom/libglom/db_utils.[h|cc]: Added gda_cnc_string_encode() for use
with GdaConnection's cnc_string and auth_string, for instance to
escape the database directory, name, username, and password.
* glom/libglom/connectionpool_backends/postgres.cc:
* glom/libglom/connectionpool_backends/postgres_self.cc:
* glom/libglom/connectionpool_backends/sqlite.cc: Properly escape the
cnc_string and auth_string key values.

* tests/test_selfhosting_utils.cc: test_create_and_selfhost_from_example(),
test_create_and_selfhost_from_uri(): Add an optional subdirectory parameter
that we can use to force weird parts into the path.
* Makefile_tests.am:
* tests/test_selfhosting_new_from_example_strangepath.cc: Add a
test case that uses a path with some weird characters. This now works
thanks to the above changes.
parent 3004628b
2011-11-10 Murray Cumming <murrayc@murrayc.com>
Escape database connection details properly.
* glom/libglom/db_utils.[h|cc]: Added gda_cnc_string_encode() for use
with GdaConnection's cnc_string and auth_string, for instance to
escape the database directory, name, username, and password.
* glom/libglom/connectionpool_backends/postgres.cc:
* glom/libglom/connectionpool_backends/postgres_self.cc:
* glom/libglom/connectionpool_backends/sqlite.cc: Properly escape the
cnc_string and auth_string key values.
* tests/test_selfhosting_utils.cc: test_create_and_selfhost_from_example(),
test_create_and_selfhost_from_uri(): Add an optional subdirectory parameter
that we can use to force weird parts into the path.
* Makefile_tests.am:
* tests/test_selfhosting_new_from_example_strangepath.cc: Add a
test case that uses a path with some weird characters. This now works
thanks to the above changes.
2011-11-09 Murray Cumming <murrayc@murrayc.com>
Use Glib::shell_quote() when spawning tar.
......
......@@ -27,6 +27,7 @@ check_PROGRAMS = \
tests/python/test_python_module \
tests/test_selfhosting_new_empty \
tests/test_selfhosting_new_from_example \
tests/test_selfhosting_new_from_example_strangepath \
tests/test_selfhosting_new_then_report \
tests/test_selfhosting_new_then_image \
tests/test_selfhosting_new_then_backup_restore \
......@@ -48,6 +49,7 @@ TESTS = tests/test_document_load \
tests/python/test_python_module \
tests/test_selfhosting_new_empty \
tests/test_selfhosting_new_from_example \
tests/test_selfhosting_new_from_example_strangepath \
tests/test_selfhosting_new_then_report \
tests/test_selfhosting_new_then_backup_restore \
tests/test_selfhosting_new_then_image \
......@@ -148,6 +150,11 @@ tests_test_selfhosting_new_from_example_SOURCES = tests/test_selfhosting_new_fro
tests_test_selfhosting_new_from_example_LDADD = $(tests_ldadd)
tests_test_selfhosting_new_from_example_CPPFLAGS = $(tests_cppflags)
tests_test_selfhosting_new_from_example_strangepath_SOURCES = tests/test_selfhosting_new_from_example_strangepath.cc $(sources_test_selfhosting_utils)
tests_test_selfhosting_new_from_example_strangepath_LDADD = $(tests_ldadd)
tests_test_selfhosting_new_from_example_strangepath_CPPFLAGS = $(tests_cppflags)
tests_test_selfhosting_new_then_report_SOURCES = tests/test_selfhosting_new_then_report.cc $(sources_test_selfhosting_utils)
tests_test_selfhosting_new_then_report_LDADD = $(tests_ldadd)
tests_test_selfhosting_new_then_report_CPPFLAGS = $(tests_cppflags)
......
......@@ -46,7 +46,8 @@ static Glib::ustring create_auth_string(const Glib::ustring& username, const Gli
if(username.empty() and password.empty())
return Glib::ustring();
else
return "USERNAME=" + username + ";PASSWORD=" + password; //TODO: How should we quote and escape these?
return "USERNAME=" + Glom::DbUtils::gda_cnc_string_encode(username) +
";PASSWORD=" + Glom::DbUtils::gda_cnc_string_encode(password);
}
} //anonymous namespace
......@@ -69,8 +70,9 @@ Glib::RefPtr<Gnome::Gda::Connection> Postgres::attempt_connect(const Glib::ustri
//This _might_ be different on some systems. I hope not. murrayc
const Glib::ustring default_database = "template1";
//const Glib::ustring& actual_database = (!database.empty()) ? database : default_database;;
const Glib::ustring cnc_string_main = "HOST=" + m_host + ";PORT=" + port;
Glib::ustring cnc_string = cnc_string_main + ";DB_NAME=" + database;
const Glib::ustring cnc_string_main = "HOST=" + DbUtils::gda_cnc_string_encode(m_host)
+ ";PORT=" + DbUtils::gda_cnc_string_encode(port);
const Glib::ustring cnc_string = cnc_string_main + ";DB_NAME=" + DbUtils::gda_cnc_string_encode(database);
Glib::RefPtr<Gnome::Gda::Connection> connection;
Glib::RefPtr<Gnome::Gda::DataModel> data_model;
......@@ -99,7 +101,7 @@ Glib::RefPtr<Gnome::Gda::Connection> Postgres::attempt_connect(const Glib::ustri
std::cout << "debug: " << G_STRFUNC << ": Attempting to connect without specifying the database." << std::endl;
#endif
const Glib::ustring cnc_string = cnc_string_main + ";DB_NAME=" + default_database;
const Glib::ustring cnc_string = cnc_string_main + ";DB_NAME=" + DbUtils::gda_cnc_string_encode(default_database);
Glib::RefPtr<Gnome::Gda::Connection> temp_conn;
Glib::ustring auth_string = create_auth_string(username, password);
try
......
......@@ -435,6 +435,7 @@ Backend::StartupErrors PostgresSelfHosted::startup(const SlotProgress& slot_prog
+ " -c ident_file=" + Glib::shell_quote(dbdir_ident)
+ " -k " + Glib::shell_quote(dbdir)
+ " --external_pid_file=" + Glib::shell_quote(dbdir_pid);
//std::cout << G_STRFUNC << ": debug: " << command_postgres_start << std::endl;
// Make sure to use double quotes for the executable path, because the
// CreateProcess() API used on Windows does not support single quotes.
......
......@@ -53,6 +53,7 @@ Glib::RefPtr<Gnome::Gda::Connection> Sqlite::connect(const Glib::ustring& databa
if(!file_exists)
{
std::cerr << G_STRFUNC << ": The db file does not exist at path: " << db_file->get_uri() << std::endl;
//std::cerr << " as filepath: " << db_file->get_path() << std::endl;
}
else
{
......@@ -65,8 +66,10 @@ Glib::RefPtr<Gnome::Gda::Connection> Sqlite::connect(const Glib::ustring& databa
// Convert URI to path, for GDA connection string
const std::string database_directory = db_dir->get_path();
const Glib::ustring cnc_string = "DB_DIR=" + database_directory + ";DB_NAME=" + database;
const Glib::ustring auth_string = Glib::ustring::compose("USERNAME=%1;PASSWORD=%2", username, password);
const Glib::ustring cnc_string = "DB_DIR=" + DbUtils::gda_cnc_string_encode(database_directory) +
";DB_NAME=" + DbUtils::gda_cnc_string_encode(database);
const Glib::ustring auth_string = Glib::ustring::compose("USERNAME=%1;PASSWORD=%2",
DbUtils::gda_cnc_string_encode(username), DbUtils::gda_cnc_string_encode(password));
connection = Gnome::Gda::Connection::open_from_string("SQLite",
cnc_string, auth_string,
......@@ -100,7 +103,8 @@ bool Sqlite::create_database(const Glib::ustring& database_name, const Glib::ust
Glib::RefPtr<Gio::File> file = Gio::File::create_for_uri(m_database_directory_uri);
const std::string database_directory = file->get_path();
const Glib::ustring cnc_string = Glib::ustring::compose("DB_DIR=%1;DB_NAME=%2", database_directory, database_name);
const Glib::ustring cnc_string = Glib::ustring::compose("DB_DIR=%1;DB_NAME=%2",
DbUtils::gda_cnc_string_encode(database_directory), DbUtils::gda_cnc_string_encode(database_name));
Glib::RefPtr<Gnome::Gda::Connection> cnc =
Gnome::Gda::Connection::open_from_string("SQLite",
......
......@@ -1871,6 +1871,15 @@ Glib::ustring escape_sql_id(const Glib::ustring& id)
return gda_connection->quote_sql_identifier(id);
}
Glib::ustring gda_cnc_string_encode(const Glib::ustring& str)
{
char* pch = gda_rfc1738_encode(str.c_str());
if(!pch)
return Glib::ustring();
else
return Glib::ustring(pch);
}
Glib::ustring build_query_create_group(const Glib::ustring& group, bool superuser)
{
if(group.empty())
......
......@@ -151,6 +151,11 @@ bool drop_table(const Glib::ustring& table_name);
*/
Glib::ustring escape_sql_id(const Glib::ustring& id);
/** Just a wrapper around gda_rfc1738_encode(),
* for use when building libgda connection strings or authentication strings.
*/
Glib::ustring gda_cnc_string_encode(const Glib::ustring& str);
Glib::ustring build_query_create_group(const Glib::ustring& group, bool superuser = false);
Glib::ustring build_query_add_user_to_group(const Glib::ustring& group, const Glib::ustring& user);
......
/* Glom
*
* Copyright (C) 2010 Openismus GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the
71 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "tests/test_selfhosting_utils.h"
#include <libglom/init.h>
#include <libglom/utils.h>
#include <libglom/db_utils.h>
#include <glib.h> //For g_assert()
#include <iostream>
#include <cstdlib> //For EXIT_SUCCESS and EXIT_FAILURE
static bool test(Glom::Document::HostingMode hosting_mode)
{
Glom::Document document;
const bool recreated =
test_create_and_selfhost_from_example("example_music_collection.glom", document,
hosting_mode, "path with space and \" quote and single ' quote and $ dollar sign and / forward slash and \backwards slash ");
if(!recreated)
{
std::cerr << "Recreation failed." << std::endl;
return false;
}
if(!test_example_musiccollection_data(&document))
{
std::cerr << "test_example_musiccollection_data() failed." << std::endl;
return false;
}
if(!test_table_exists("songs", document))
{
return false;
}
if(!test_table_exists("publishers", document))
{
return false;
}
test_selfhosting_cleanup();
return true;
}
int main()
{
Glom::libglom_init();
if(!test(Glom::Document::HOSTING_MODE_POSTGRES_SELF))
{
std::cerr << "Failed with PostgreSQL" << std::endl;
test_selfhosting_cleanup();
return EXIT_FAILURE;
}
if(!test(Glom::Document::HOSTING_MODE_SQLITE))
{
std::cerr << "Failed with SQLite" << std::endl;
test_selfhosting_cleanup();
return EXIT_FAILURE;
}
Glom::libglom_deinit();
return EXIT_SUCCESS;
}
......@@ -138,7 +138,7 @@ void test_selfhosting_cleanup()
temp_filepath_dir.clear();
}
bool test_create_and_selfhost_from_example(const std::string& example_filename, Glom::Document& document, Glom::Document::HostingMode hosting_mode)
bool test_create_and_selfhost_from_example(const std::string& example_filename, Glom::Document& document, Glom::Document::HostingMode hosting_mode, const std::string& subdirectory_path)
{
Glib::ustring uri;
......@@ -156,10 +156,10 @@ bool test_create_and_selfhost_from_example(const std::string& example_filename,
return false;
}
return test_create_and_selfhost_from_uri(uri, document, hosting_mode);
return test_create_and_selfhost_from_uri(uri, document, hosting_mode, subdirectory_path);
}
bool test_create_and_selfhost_from_uri(const Glib::ustring& example_file_uri, Glom::Document& document, Glom::Document::HostingMode hosting_mode)
bool test_create_and_selfhost_from_uri(const Glib::ustring& example_file_uri, Glom::Document& document, Glom::Document::HostingMode hosting_mode, const std::string& subdirectory_path)
{
if( (hosting_mode != Glom::Document::HOSTING_MODE_POSTGRES_SELF) &&
(hosting_mode != Glom::Document::HOSTING_MODE_SQLITE) )
......@@ -189,10 +189,12 @@ bool test_create_and_selfhost_from_uri(const Glib::ustring& example_file_uri, Gl
Glom::ConnectionPool* connection_pool = Glom::ConnectionPool::get_instance();
//Save a copy, specifying the path to file in a directory:
//For instance, /tmp/testfileglom/testfile.glom");
//For instance, /tmp/testglom/testglom.glom");
const std::string temp_filename = "testglom";
temp_filepath_dir =
Glom::Utils::get_temp_directory_path(temp_filename);
if(!subdirectory_path.empty())
temp_filepath_dir = Glib::build_filename(temp_filepath_dir, subdirectory_path);
const std::string temp_filepath = Glib::build_filename(temp_filepath_dir, temp_filename);
//Make sure that the file does not exist yet:
......
......@@ -28,14 +28,16 @@
/** Create a .glom file from an example, with database data, and start a PostgreSQL server if necessary.
*
* @param hosting_mode Either HOSTING_MODE_POSTGRES_SELF or HOSTING_MODE_SQLITE
* @param subdirectory_path: An additional directory path to use under the temporary directory that will be used to save the file.
*/
bool test_create_and_selfhost_from_example(const std::string& example_filename, Glom::Document& document, Glom::Document::HostingMode hosting_mode);
bool test_create_and_selfhost_from_example(const std::string& example_filename, Glom::Document& document, Glom::Document::HostingMode hosting_mode, const std::string& subdirectory_path = std::string());
/** Create a .glom file from an existing .glom example file with database data, and start a PostgreSQL server if necessary.
*
* @param hosting_mode Either HOSTING_MODE_POSTGRES_SELF or HOSTING_MODE_SQLITE
* @param subdirectory_path: An additional directory path to use under the temporary directory that will be used to save the file.
*/
bool test_create_and_selfhost_from_uri(const Glib::ustring& file_uri, Glom::Document& document, Glom::Document::HostingMode hosting_mode);
bool test_create_and_selfhost_from_uri(const Glib::ustring& file_uri, Glom::Document& document, Glom::Document::HostingMode hosting_mode, const std::string& subdirectory_path = std::string());
bool test_model_expected_size(const Glib::RefPtr<Gnome::Gda::DataModel>& data_model, guint columns_count, guint rows_count);
bool test_table_exists(const Glib::ustring& table_name, const Glom::Document& document);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment