diff --git a/GNUmakefile b/GNUmakefile index 53fec87..de55a68 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -209,6 +209,10 @@ plugin_logging_TARGET := mod_logging.so plugin_auth_SOURCES := src/plugins/mod_auth_simple.c plugin_auth_TARGET := mod_auth_simple.so +plugin_auth_sqlite_SOURCES := src/plugins/mod_auth_sqlite.c +plugin_auth_sqlite_TARGET := mod_auth_sqlite.so +plugin_auth_sqlite_LIBS := -lsqlite3 + # Source to objects libuhub_OBJECTS := $(libuhub_SOURCES:.c=.o) @@ -221,7 +225,7 @@ adcrush_OBJECTS := $(adcrush_SOURCES:.c=.o) admin_OBJECTS := $(admin_SOURCES:.c=.o) all_OBJECTS := $(libuhub_OBJECTS) $(uhub_OBJECTS) $(libutils_OBJECTS) $(adcrush_OBJECTS) $(autotest_OBJECTS) $(admin_OBJECTS) $(libadc_common_OBJECTS) $(libadc_client_OBJECTS) -all_plugins := $(plugin_example_TARGET) $(plugin_logging_TARGET) $(plugin_auth_TARGET) +all_plugins := $(plugin_example_TARGET) $(plugin_logging_TARGET) $(plugin_auth_TARGET) $(plugin_auth_sqlite_TARGET) uhub_BINARY=uhub$(BIN_EXT) adcrush_BINARY=adcrush$(BIN_EXT) @@ -244,6 +248,9 @@ plugins: $(uhub_BINARY) $(all_plugins) $(plugin_auth_TARGET): $(plugin_auth_SOURCES) $(libutils_OBJECTS) $(MSG_CC) $(CC) -shared -fPIC -o $@ $^ $(CFLAGS) +$(plugin_auth_sqlite_TARGET): $(plugin_auth_sqlite_SOURCES) $(libutils_OBJECTS) + $(MSG_CC) $(CC) -shared -fPIC -o $@ $^ $(CFLAGS) $(plugin_auth_sqlite_LIBS) + $(plugin_example_TARGET): $(plugin_example_SOURCES) $(MSG_CC) $(CC) -shared -fPIC -o $@ $^ $(CFLAGS) diff --git a/src/plugins/mod_auth_sqlite.c b/src/plugins/mod_auth_sqlite.c new file mode 100644 index 0000000..5ce8c7a --- /dev/null +++ b/src/plugins/mod_auth_sqlite.c @@ -0,0 +1,172 @@ +/* + * uhub - A tiny ADC p2p connection hub + * Copyright (C) 2010, Jan Vidar Krey + */ + +#include "plugin_api/handle.h" +#include +#include "util/memory.h" +#include "util/list.h" +#include "util/ipcalc.h" +#include "util/misc.h" +#include "util/log.h" +#include "util/config_token.h" + + +static void set_error_message(struct plugin_handle* plugin, const char* msg) +{ + plugin->error_msg = msg; +} + +struct sql_data +{ + int exclusive; + sqlite3* db; +}; + +static struct sql_data* parse_config(const char* line, struct plugin_handle* plugin) +{ + struct sql_data* data = (struct sql_data*) hub_malloc_zero(sizeof(struct sql_data)); + struct cfg_tokens* tokens = cfg_tokenize(line); + char* token = cfg_token_get_first(tokens); + + if (!data) + return 0; + + while (token) + { + + char* split = strchr(token, '='); + size_t len = strlen(token); + size_t key = split ? (split - token) : len; + if (key == 4 && strncmp(token, "file", 4) == 0 && data->db == 0) + { + if (sqlite3_open(split + 1, &data->db)) + { + cfg_tokens_free(tokens); + hub_free(data); + return 0; + } + } + else if (key == 9 && strncmp(token, "exclusive", 9) == 0) + { + if (!string_to_boolean(split + 1, &data->exclusive)) + data->exclusive = 1; + } + else + { + set_error_message(plugin, "Unable to parse startup parameters"); + cfg_tokens_free(tokens); + hub_free(data); + return 0; + } + token = cfg_token_get_next(tokens); + } + + cfg_tokens_free(tokens); + return data; +} + +static const char* sql_escape_string(const char* str) +{ + static char out[1024]; + size_t i = 0; + size_t n = 0; + for (; n < strlen(str); n++) + { + if (str[n] == '\'' || str[n] == '\\') + out[i++] = '\\'; + out[i++] = str[n]; + } + return out; +} + +static int get_user_callback(void* ptr, int argc, char **argv, char **colName){ + struct auth_info* data = (struct auth_info*) ptr; + int i; + for(i=0; inickname, argv[i], MAX_NICK_LEN); + else if (strcmp(colName[i], "password") == 0) + strncpy(data->password, argv[i], MAX_PASS_LEN); + else if (strcmp(colName[i], "credentials") == 0) + { + auth_string_to_cred(colName[i], &data->credentials); + } + } + return 0; +} + +static plugin_st get_user(struct plugin_handle* plugin, const char* nickname, struct auth_info* data) +{ + struct sql_data* sql = (struct sql_data*) plugin->ptr; + char query[1024]; + char* errMsg; + int rc; + + snprintf(query, sizeof(query), "SELECT * FROM users WHERE nickname='%s';", sql_escape_string(nickname)); + memset(data, 0, sizeof(struct auth_info)); + + rc = sqlite3_exec(sql->db, query , get_user_callback, data, &errMsg); + if( rc != SQLITE_OK ){ + fprintf(stderr, "SQL error: %s\n", errMsg); + sqlite3_free(errMsg); + } + + return st_allow; +} + +static plugin_st register_user(struct plugin_handle* plugin, struct auth_info* user) +{ + struct sql_data* sql = (struct sql_data*) plugin->ptr; + if (sql->exclusive) + return st_deny; + return st_default; +} + +static plugin_st update_user(struct plugin_handle* plugin, struct auth_info* user) +{ + struct sql_data* sql = (struct sql_data*) plugin->ptr; + if (sql->exclusive) + return st_deny; + return st_default; +} + +static plugin_st delete_user(struct plugin_handle* plugin, struct auth_info* user) +{ + struct sql_data* sql = (struct sql_data*) plugin->ptr; + if (sql->exclusive) + return st_deny; + return st_default; +} + +int plugin_register(struct plugin_handle* plugin, const char* config) +{ + plugin->name = "SQLite authentication plugin"; + plugin->version = "0.1"; + plugin->description = "Authenticate users based on a SQLite database."; + plugin->plugin_api_version = PLUGIN_API_VERSION; + plugin->plugin_funcs_size = sizeof(struct plugin_funcs); + memset(&plugin->funcs, 0, sizeof(struct plugin_funcs)); + + // Authentication actions. + plugin->funcs.auth_get_user = get_user; + plugin->funcs.auth_register_user = register_user; + plugin->funcs.auth_update_user = update_user; + plugin->funcs.auth_delete_user = delete_user; + + plugin->ptr = parse_config(config, plugin); + if (plugin->ptr) + return 0; + return -1; +} + +int plugin_unregister(struct plugin_handle* plugin) +{ + set_error_message(plugin, 0); + struct sql_data* sql = (struct sql_data*) plugin->ptr; + sqlite3_close(sql->db); + hub_free(sql); + return 0; +} + diff --git a/src/util/credentials.c b/src/util/credentials.c index 18354ef..b8d6faf 100644 --- a/src/util/credentials.c +++ b/src/util/credentials.c @@ -75,3 +75,38 @@ const char* auth_cred_to_string(enum auth_credentials cred) return ""; }; +int auth_string_to_cred(const char* str, enum auth_credentials* out) +{ + if (!str || !*str || !out) + return 0; + + switch (strlen(str)) + { + case 2: + if (!strcasecmp(str, "op")) { *out = auth_cred_operator; return 1; } + return 0; + + case 3: + if (!strcasecmp(str, "bot")) { *out = auth_cred_bot; return 1; } + if (!strcasecmp(str, "reg")) { *out = auth_cred_user; return 1; } + return 0; + + case 4: + if (!strcasecmp(str, "user")) { *out = auth_cred_user; return 1; } + if (!strcasecmp(str, "link")) { *out = auth_cred_link; return 1; } + return 0; + + case 5: + if (!strcasecmp(str, "admin")) { *out = auth_cred_admin; return 1; } + if (!strcasecmp(str, "super")) { *out = auth_cred_super; return 1; } + if (!strcasecmp(str, "guest")) { *out = auth_cred_guest; return 1; } + return 0; + + case 8: + if (!strcasecmp(str, "operator")) { *out = auth_cred_operator; return 1; } + return 0; + + default: + return 0; + } +} diff --git a/src/util/credentials.h b/src/util/credentials.h index cb6e2b4..8323988 100644 --- a/src/util/credentials.h +++ b/src/util/credentials.h @@ -51,4 +51,7 @@ int auth_cred_is_registered(enum auth_credentials cred); */ const char* auth_cred_to_string(enum auth_credentials cred); + +int auth_string_to_cred(const char* str, enum auth_credentials* out); + #endif /* HAVE_UHUB_CREDENTIALS_H */ diff --git a/tools/convert_to_sqlite.pl b/tools/convert_to_sqlite.pl new file mode 100755 index 0000000..52a2ffc --- /dev/null +++ b/tools/convert_to_sqlite.pl @@ -0,0 +1,38 @@ +#!/usr/bin/perl + +my $input = $ARGV[0]; + +open (FILE, "$input") || die "# Unable to open input file $input: $!"; +my @lines = ; +close (FILE); + +print "CREATE TABLE users(nickname CHAR(64) UNIQUE, password CHAR(64), credentials CHAR(5));\n"; + +foreach my $line (@lines) { + + chomp($line); + + $line =~ s/#.*//g; + + next if ($line =~ /^\s*$/); + + if ($line =~ /^\s*user_(op|admin|super|reg)\s*(.+):(.+)\s*/) + { + my $cred = $1; + my $nick = $2; + my $pass = $3; + + $nick =~ s/'/\\'/g; + $pass =~ s/'/\\'/g; + + print "INSERT INTO users VALUES('" . $nick . "', '" . $pass . "', '" . $cred . "');\n"; + } + else + { + # print "# Warning: Unrecognized line: \"" . $line . "\"\n"; + } +} + + + +