/pidgin/main: eda46d7224d7: oscar: Adding kerberos-based authent...
Youness Alaoui
kakaroto at kakaroto.homelinux.net
Thu Jun 16 16:23:51 EDT 2016
Changeset: eda46d7224d7041eb6e2c3c52ddd0aa131c9ee1b
Author: Youness Alaoui <kakaroto at kakaroto.homelinux.net>
Date: 2016-06-14 17:49 -0400
Branch: release-2.x.y
URL: https://hg.pidgin.im/pidgin/main/rev/eda46d7224d7
Description:
oscar: Adding kerberos-based authentication
This is a port to 2.x.y of the oscar_auth branch from PR 69 :
https://bitbucket.org/pidgin/main/pull-requests/69
diffstat:
libpurple/protocols/oscar/Makefile.am | 1 +
libpurple/protocols/oscar/kerberos.c | 454 ++++++++++++++++++++++++++++++++
libpurple/protocols/oscar/oscar.c | 94 +++++-
libpurple/protocols/oscar/oscar.h | 5 +
libpurple/protocols/oscar/oscarcommon.h | 9 +-
5 files changed, 553 insertions(+), 10 deletions(-)
diffs (truncated from 691 to 300 lines):
diff --git a/libpurple/protocols/oscar/Makefile.am b/libpurple/protocols/oscar/Makefile.am
--- a/libpurple/protocols/oscar/Makefile.am
+++ b/libpurple/protocols/oscar/Makefile.am
@@ -9,6 +9,7 @@ OSCARSOURCES = \
authorization.c \
bstream.c \
clientlogin.c \
+ kerberos.c \
encoding.c \
encoding.h \
family_admin.c \
diff --git a/libpurple/protocols/oscar/kerberos.c b/libpurple/protocols/oscar/kerberos.c
new file mode 100644
--- /dev/null
+++ b/libpurple/protocols/oscar/kerberos.c
@@ -0,0 +1,454 @@
+/*
+ * Purple's oscar protocol plugin
+ * This file is the legal property of its developers.
+ * Please see the AUTHORS file distributed alongside this file.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+*/
+
+/**
+ * This file implements AIM's kerberos procedure for authenticating
+ * users. This replaces the older MD5-based and XOR-based
+ * authentication methods that use SNAC family 0x0017.
+ *
+ * This doesn't use SNACs or FLAPs at all. It makes http and https
+ * POSTs to AOL to validate the user based on the password they
+ * provided to us. Upon successful authentication we request a
+ * connection to the BOS server by calling startOSCARsession. The
+ * AOL server gives us the hostname and port number to use, as well
+ * as the cookie to use to authenticate to the BOS server. And then
+ * everything else is the same as with BUCP.
+ *
+ * For details, see:
+ * http://dev.aol.com/aim/oscar/#AUTH
+ * http://dev.aol.com/authentication_for_clients
+ */
+
+#include "oscar.h"
+#include "oscarcommon.h"
+#include "core.h"
+
+#define MAXAIMPASSLEN 16
+
+/*
+ * Incomplete X-SNAC format taken from reverse engineering doen by digsby:
+ * https://github.com/ifwe/digsby/blob/master/digsby/src/oscar/login2.py
+ */
+typedef struct {
+ aim_tlv_t *main_tlv;
+ gchar *principal1;
+ gchar *service;
+ gchar *principal1_again;
+ gchar *principal2;
+ gchar unknown;
+ guint8 *footer;
+ struct {
+ guint32 unknown1;
+ guint32 unknown2;
+ guint32 epoch_now;
+ guint32 epoch_valid;
+ guint32 epoch_renew;
+ guint32 epoch_expire;
+ guint32 unknown3;
+ guint32 unknown4;
+ guint32 unknown5;
+ } dates;
+ GSList *tlvlist;
+} aim_xsnac_token_t;
+
+typedef struct {
+ guint16 family;
+ guint16 subtype;
+ guint8 flags[8];
+ guint16 request_id;
+ guint32 epoch;
+ guint32 unknown;
+ gchar *principal1;
+ gchar *principal2;
+ guint16 num_tokens;
+ aim_xsnac_token_t *tokens;
+ GSList *tlvlist;
+} aim_xsnac_t;
+
+static gchar *get_kdc_url(OscarData *od)
+{
+ PurpleAccount *account = purple_connection_get_account(od->gc);
+ const gchar *server;
+ gchar *url;
+ gchar *port_str = NULL;
+ gint port;
+
+ server = purple_account_get_string(account, "server", AIM_DEFAULT_KDC_SERVER);
+ port = purple_account_get_int(account, "port", AIM_DEFAULT_KDC_PORT);
+ if (port != 443)
+ port_str = g_strdup_printf (":%d", port);
+ url = g_strdup_printf ("https://%s%s/", server, port_str ? port_str : "");
+ if (port_str)
+ g_free (port_str);
+
+ return url;
+}
+
+/*
+ * Using kerberos auth requires a developer ID. This key is for libpurple.
+ * It is the default key for all libpurple-based clients. AOL encourages
+ * UIs (especially ones with lots of users) to override this with their
+ * own key. This key is owned by the AIM account "markdoliner"
+ *
+ * Keys can be managed at http://developer.aim.com/manageKeys.jsp
+ */
+#define DEFAULT_CLIENT_KEY "ma15d7JTxbmVG-RP"
+
+static const char *get_client_key(OscarData *od)
+{
+ return oscar_get_ui_info_string(
+ od->icq ? "prpl-icq-clientkey" : "prpl-aim-clientkey",
+ DEFAULT_CLIENT_KEY);
+}
+
+static void
+aim_encode_password(const char *password, guint8 *encoded)
+{
+ guint8 encoding_table[] = {
+ 0x76, 0x91, 0xc5, 0xe7,
+ 0xd0, 0xd9, 0x95, 0xdd,
+ 0x9e, 0x2F, 0xea, 0xd8,
+ 0x6B, 0x21, 0xc2, 0xbc,
+
+ };
+ guint i;
+
+ /*
+ * We truncate AIM passwords to 16 characters since that's what
+ * the official client does as well.
+ */
+ for (i = 0; i < strlen(password) && i < MAXAIMPASSLEN; i++)
+ encoded[i] = (password[i] ^ encoding_table[i]);
+}
+
+static void
+aim_xsnac_free(aim_xsnac_t *xsnac)
+{
+ gint i;
+
+ if (xsnac->principal1)
+ g_free (xsnac->principal1);
+ if (xsnac->principal2)
+ g_free (xsnac->principal2);
+ aim_tlvlist_free (xsnac->tlvlist);
+
+ for (i = 0; i < xsnac->num_tokens; i++) {
+ g_free(xsnac->tokens[i].main_tlv->value);
+ g_free(xsnac->tokens[i].main_tlv);
+ if (xsnac->tokens[i].principal1)
+ g_free (xsnac->tokens[i].principal1);
+ if (xsnac->tokens[i].principal1_again)
+ if (xsnac->tokens[i].service)
+ g_free (xsnac->tokens[i].service);
+ g_free (xsnac->tokens[i].principal1_again);
+ if (xsnac->tokens[i].principal2)
+ g_free (xsnac->tokens[i].principal2);
+ if (xsnac->tokens[i].footer)
+ g_free (xsnac->tokens[i].footer);
+ aim_tlvlist_free (xsnac->tokens[i].tlvlist);
+ }
+ g_free (xsnac->tokens);
+}
+
+static void
+kerberos_login_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data,
+ const gchar *got_data, gsize got_len, const gchar *error_message)
+{
+ OscarData *od = user_data;
+ PurpleConnection *gc;
+ ByteStream bs;
+ aim_xsnac_t xsnac = {0};
+ guint16 len;
+ gchar *bosip = NULL;
+ gchar *tlsCertName = NULL;
+ guint8 *cookie = NULL;
+ guint32 cookie_len = 0;
+ char *host; int port;
+ gsize i;
+
+ gc = od->gc;
+
+ od->url_data = NULL;
+
+ if (error_message != NULL || got_len == 0) {
+ gchar *tmp;
+ gchar *url;
+
+ url = get_kdc_url(od);
+ tmp = g_strdup_printf(_("Error requesting %s: %s"),
+ url, error_message ?
+ error_message : _("The server returned an empty response"));
+ purple_connection_error_reason(gc,
+ PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
+ g_free(tmp);
+ g_free(url);
+ return;
+ }
+
+ purple_debug_info("oscar", "Received kerberos login HTTP response %lu : ", got_len);
+
+ byte_stream_init (&bs, (guint8 *)got_data, got_len);
+
+ xsnac.family = byte_stream_get16 (&bs);
+ xsnac.subtype = byte_stream_get16(&bs);
+ byte_stream_getrawbuf(&bs, (guint8 *) xsnac.flags, 8);
+
+ if (xsnac.family == 0x50C && xsnac.subtype == 0x0005) {
+ purple_connection_error_reason(gc,
+ PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
+ _("Incorrect password"));
+ return;
+ }
+ if (xsnac.family != 0x50C || xsnac.subtype != 0x0003) {
+ purple_connection_error_reason(gc,
+ PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+ _("Error parsing response from authentication server"));
+ return;
+ }
+ xsnac.request_id = byte_stream_get16(&bs);
+ xsnac.epoch = byte_stream_get32(&bs);
+ xsnac.unknown = byte_stream_get32(&bs);
+ len = byte_stream_get16(&bs);
+ xsnac.principal1 = byte_stream_getstr(&bs, len);
+ len = byte_stream_get16(&bs);
+ xsnac.principal2 = byte_stream_getstr(&bs, len);
+ xsnac.num_tokens = byte_stream_get16(&bs);
+
+ purple_debug_info("oscar", "KDC: %d tokens between '%s' and '%s'\n",
+ xsnac.num_tokens, xsnac.principal1, xsnac.principal2);
+ xsnac.tokens = g_new0 (aim_xsnac_token_t, xsnac.num_tokens);
+ for (i = 0; i < xsnac.num_tokens; i++) {
+ GSList *tlv;
+
+ tlv = aim_tlvlist_readnum(&bs, 1);
+ if (tlv)
+ xsnac.tokens[i].main_tlv = tlv->data;
+ g_slist_free (tlv);
+
+ len = byte_stream_get16(&bs);
+ xsnac.tokens[i].principal1 = byte_stream_getstr(&bs, len);
+ len = byte_stream_get16(&bs);
+ xsnac.tokens[i].service = byte_stream_getstr(&bs, len);
+ len = byte_stream_get16(&bs);
+ xsnac.tokens[i].principal1_again = byte_stream_getstr(&bs, len);
+ len = byte_stream_get16(&bs);
+ xsnac.tokens[i].principal2 = byte_stream_getstr(&bs, len);
+ xsnac.tokens[i].unknown = byte_stream_get8(&bs);
+ len = byte_stream_get16(&bs);
+ xsnac.tokens[i].footer = byte_stream_getraw(&bs, len);
+
+ xsnac.tokens[i].dates.unknown1 = byte_stream_get32(&bs);
+ xsnac.tokens[i].dates.unknown2 = byte_stream_get32(&bs);
+ xsnac.tokens[i].dates.epoch_now = byte_stream_get32(&bs);
+ xsnac.tokens[i].dates.epoch_valid = byte_stream_get32(&bs);
+ xsnac.tokens[i].dates.epoch_renew = byte_stream_get32(&bs);
+ xsnac.tokens[i].dates.epoch_expire = byte_stream_get32(&bs);
+ xsnac.tokens[i].dates.unknown3 = byte_stream_get32(&bs);
+ xsnac.tokens[i].dates.unknown4 = byte_stream_get32(&bs);
+ xsnac.tokens[i].dates.unknown5 = byte_stream_get32(&bs);
+
+ len = byte_stream_get16(&bs);
+ xsnac.tokens[i].tlvlist = aim_tlvlist_readnum(&bs, len);
+
+ purple_debug_info("oscar", "Token %lu has %d TLVs for service '%s'\n",
+ i, len, xsnac.tokens[i].service);
+ }
+ len = byte_stream_get16(&bs);
+ xsnac.tlvlist = aim_tlvlist_readnum(&bs, len);
+
+ for (i = 0; i < xsnac.num_tokens; i++) {
+ if (strcmp (xsnac.tokens[i].service, "im/boss") == 0) {
+ aim_tlv_t *tlv;
+ GSList *tlvlist;
+ ByteStream tbs;
+
+ tlv = aim_tlv_gettlv(xsnac.tokens[i].tlvlist, 0x0003, 1);
+ if (tlv != NULL) {
+ byte_stream_init(&tbs, tlv->value, tlv->length);
More information about the Commits
mailing list