aboutsummaryrefslogtreecommitdiffstats
path: root/storage_xml.c
diff options
context:
space:
mode:
authorDennis Kaarsemaker <dennis@kaarsemaker.net>2016-02-23 19:41:34 +0100
committerDennis Kaarsemaker <dennis@kaarsemaker.net>2016-03-25 19:07:53 +0100
commit8e6ecfe23ff985e57675bd00b94860edb62de9ad (patch)
treef45c9b7a256a16a483e0e072d4cb917d38fd6228 /storage_xml.c
parent446a23ea39184c5fe43cd40706bb683b89534e2e (diff)
Authentication: scaffolding for multiple authentication backends
Instead of always putting users passwords in XML files, allow site admins to configure a different authentication method to integrate authentication with other systems. This doesn't add any authentication backends yet, merely the scaffolding. Notably: - Password checking and loading/removing from storage has been decoupled. A new auth_check_pass function is used to check passwords. It does check against the configured storage first, but will handle the authentication backends as well. The XML storage merely signals that a user's password should be checked using an authentication backend. - If unknown-to-bitlbee users identify using an authentication backend, they are automatically registered. - If an authentication backend is used, that fact is stored in the XML file, the password is not. Passwords are also stored unencrypted in this case, as the password used to encrypt them can change underneath us. - configure and Makefile changes for the backend objects
Diffstat (limited to 'storage_xml.c')
-rw-r--r--storage_xml.c136
1 files changed, 74 insertions, 62 deletions
diff --git a/storage_xml.c b/storage_xml.c
index dbdd151d..7e8555ef 100644
--- a/storage_xml.c
+++ b/storage_xml.c
@@ -33,11 +33,9 @@
#include <glib/gstdio.h>
typedef enum {
- XML_PASS_CHECK_ONLY = -1,
- XML_PASS_UNKNOWN = 0,
- XML_PASS_WRONG,
- XML_PASS_OK
-} xml_pass_st;
+ XML_PASS_CHECK = 0,
+ XML_LOAD
+} xml_action;
/* To make it easier later when extending the format: */
#define XML_FORMAT_VERSION "1"
@@ -120,28 +118,35 @@ static xt_status handle_account(struct xt_node *node, gpointer data)
if (!handle || !pass_b64 || !protocol || !prpl) {
return XT_ABORT;
- } else if ((pass_len = base64_decode(pass_b64, (unsigned char **) &pass_cr)) &&
- arc_decode(pass_cr, pass_len, &password, xd->given_pass) >= 0) {
- acc = account_add(xd->irc->b, prpl, handle, password);
- if (server) {
- set_setstr(&acc->set, "server", server);
- }
- if (autoconnect) {
- set_setstr(&acc->set, "auto_connect", autoconnect);
- }
- if (tag) {
- set_setstr(&acc->set, "tag", tag);
- }
- if (local) {
- acc->flags |= ACC_FLAG_LOCAL;
- }
- if (locked && !g_strcasecmp(locked, "true")) {
- acc->flags |= ACC_FLAG_LOCKED;
- }
+ }
+
+ base64_decode(pass_b64, (unsigned char **) &pass_cr);
+ if (xd->irc->auth_backend) {
+ password = g_strdup((char *)pass_cr);
} else {
- g_free(pass_cr);
- g_free(password);
- return XT_ABORT;
+ pass_len = arc_decode(pass_cr, pass_len, &password, xd->given_pass);
+ if (pass_len < 0) {
+ g_free(pass_cr);
+ g_free(password);
+ return XT_ABORT;
+ }
+ }
+
+ acc = account_add(xd->irc->b, prpl, handle, password);
+ if (server) {
+ set_setstr(&acc->set, "server", server);
+ }
+ if (autoconnect) {
+ set_setstr(&acc->set, "auto_connect", autoconnect);
+ }
+ if (tag) {
+ set_setstr(&acc->set, "tag", tag);
+ }
+ if (local) {
+ acc->flags |= ACC_FLAG_LOCAL;
+ }
+ if (locked && !g_strcasecmp(locked, "true")) {
+ acc->flags |= ACC_FLAG_LOCKED;
}
g_free(pass_cr);
@@ -197,7 +202,7 @@ static const struct xt_handler_entry handlers[] = {
{ NULL, NULL, NULL, },
};
-static storage_status_t xml_load_real(irc_t *irc, const char *my_nick, const char *password, xml_pass_st action)
+static storage_status_t xml_load_real(irc_t *irc, const char *my_nick, const char *password, xml_action action)
{
struct xml_parsedata xd[1];
char *fn, buf[2048];
@@ -239,24 +244,27 @@ static storage_status_t xml_load_real(irc_t *irc, const char *my_nick, const cha
goto error;
}
- {
+ if (action == XML_PASS_CHECK) {
char *nick = xt_find_attr(node, "nick");
char *pass = xt_find_attr(node, "password");
+ char *backend = xt_find_attr(node, "auth_backend");
- if (!nick || !pass) {
+ if (!nick || !(pass || backend)) {
goto error;
+ }
+
+ if (backend) {
+ g_free(xd->irc->auth_backend);
+ xd->irc->auth_backend = g_strdup(backend);
+ ret = STORAGE_CHECK_BACKEND;
} else if ((st = md5_verify_password(xd->given_pass, pass)) != 0) {
ret = STORAGE_INVALID_PASSWORD;
- goto error;
+ } else {
+ ret = STORAGE_OK;
}
- }
-
- if (action == XML_PASS_CHECK_ONLY) {
- ret = STORAGE_OK;
goto error;
}
- /* DO NOT call xt_handle() before verifying the password! */
if (xt_handle(xp, NULL, 1) == XT_HANDLED) {
ret = STORAGE_OK;
}
@@ -271,12 +279,12 @@ error:
static storage_status_t xml_load(irc_t *irc, const char *password)
{
- return xml_load_real(irc, irc->user->nick, password, XML_PASS_UNKNOWN);
+ return xml_load_real(irc, irc->user->nick, password, XML_LOAD);
}
-static storage_status_t xml_check_pass(const char *my_nick, const char *password)
+static storage_status_t xml_check_pass(irc_t *irc, const char *my_nick, const char *password)
{
- return xml_load_real(NULL, my_nick, password, XML_PASS_CHECK_ONLY);
+ return xml_load_real(irc, my_nick, password, XML_PASS_CHECK);
}
@@ -291,24 +299,27 @@ struct xt_node *xml_generate(irc_t *irc)
GSList *l;
struct xt_node *root, *cur;
- /* Generate a salted md5sum of the password. Use 5 bytes for the salt
- (to prevent dictionary lookups of passwords) to end up with a 21-
- byte password hash, more convenient for base64 encoding. */
- random_bytes(pass_md5 + 16, 5);
- md5_init(&md5_state);
- md5_append(&md5_state, (md5_byte_t *) irc->password, strlen(irc->password));
- md5_append(&md5_state, pass_md5 + 16, 5); /* Add the salt. */
- md5_finish(&md5_state, pass_md5);
- /* Save the hash in base64-encoded form. */
- pass_buf = base64_encode(pass_md5, 21);
-
root = cur = xt_new_node("user", NULL, NULL);
+ if (irc->auth_backend) {
+ xt_add_attr(cur, "auth_backend", irc->auth_backend);
+ } else {
+ /* Generate a salted md5sum of the password. Use 5 bytes for the salt
+ (to prevent dictionary lookups of passwords) to end up with a 21-
+ byte password hash, more convenient for base64 encoding. */
+ random_bytes(pass_md5 + 16, 5);
+ md5_init(&md5_state);
+ md5_append(&md5_state, (md5_byte_t *) irc->password, strlen(irc->password));
+ md5_append(&md5_state, pass_md5 + 16, 5); /* Add the salt. */
+ md5_finish(&md5_state, pass_md5);
+ /* Save the hash in base64-encoded form. */
+ pass_buf = base64_encode(pass_md5, 21);
+ xt_add_attr(cur, "password", pass_buf);
+ g_free(pass_buf);
+ }
+
xt_add_attr(cur, "nick", irc->user->nick);
- xt_add_attr(cur, "password", pass_buf);
xt_add_attr(cur, "version", XML_FORMAT_VERSION);
- g_free(pass_buf);
-
xml_generate_settings(cur, &irc->b->set);
for (acc = irc->b->accounts; acc; acc = acc->next) {
@@ -318,9 +329,16 @@ struct xt_node *xml_generate(irc_t *irc)
char *pass_b64;
int pass_len;
- pass_len = arc_encode(acc->pass, strlen(acc->pass), (unsigned char **) &pass_cr, irc->password, 12);
- pass_b64 = base64_encode(pass_cr, pass_len);
- g_free(pass_cr);
+ if(irc->auth_backend) {
+ /* If we don't "own" the password, it may change without us
+ * knowing, so we cannot encrypt the data, as we then may not be
+ * able to decrypt it */
+ pass_b64 = base64_encode((unsigned char *)acc->pass, strlen(acc->pass));
+ } else {
+ pass_len = arc_encode(acc->pass, strlen(acc->pass), (unsigned char **) &pass_cr, irc->password, 12);
+ pass_b64 = base64_encode(pass_cr, pass_len);
+ g_free(pass_cr);
+ }
cur = xt_new_node("account", NULL, NULL);
xt_add_attr(cur, "protocol", acc->prpl->name);
@@ -439,15 +457,9 @@ finish:
}
-static storage_status_t xml_remove(const char *nick, const char *password)
+static storage_status_t xml_remove(const char *nick)
{
char s[512], *lc;
- storage_status_t status;
-
- status = xml_check_pass(nick, password);
- if (status != STORAGE_OK) {
- return status;
- }
lc = g_strdup(nick);
nick_lc(NULL, lc);