/pidgin/main: bc833d6d81a2: Merged in kakaroto/main/release-2.x....
Gary Kramlich <[email protected]>
| Newsgroups | gmane.comp.gnome.gaim.cvs |
|---|---|
| Message-ID | <[email protected]> |
Changeset: bc833d6d81a2889dfcaafb7496a8ed14a56f9da1 Author: Gary Kramlich <[email protected]> Date: 2016-06-16 15:23 -0500 Branch: release-2.x.y URL: https://hg.pidgin.im/pidgin/main/rev/bc833d6d81a2 Description: Merged in kakaroto/main/release-2.x.y (pull request #70) Release 2.x.y diffstat: ChangeLog | 3 + libpurple/protocols/oscar/Makefile.am | 1 + libpurple/protocols/oscar/kerberos.c | 441 ++++++++++++++++++++++++++++++++ libpurple/protocols/oscar/oscar.c | 94 ++++++- libpurple/protocols/oscar/oscar.h | 5 + libpurple/protocols/oscar/oscarcommon.h | 9 +- libpurple/util.c | 18 +- libpurple/util.h | 26 + 8 files changed, 585 insertions(+), 12 deletions(-) diffs (truncated from 783 to 300 lines): diff --git a/ChangeLog b/ChangeLog --- a/ChangeLog +++ b/ChangeLog @@ -13,6 +13,9 @@ version 2.10.13 (MM/DD/YY): don't support rich text * Fix a potential crash while exiting pidgin + AIM: + * Add support for the newer kerberos-based authentication of AIM 8.x + Windows-Specific Changes: * Use getaddrinfo for DNS to enable IPv6 (#1075) 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,441 @@ +/* + * 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 https + * POSTs to AOL KDC server to validate the user based on the password they + * provided to us. Upon successful authentication we receive two tokens + * in the response. One is assumed to be the kerberos ticket for authentication + * on the various AOL websites, while the other contains BOSS information, such + * as the hostname and port number to use, the TLS certificate name as well as + * the cookie to use to authenticate to the BOS server. + * And then everything else is the same as with BUCP. + * + */ + +#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 : ""); + 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, gchar *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; + + g_free(xsnac->principal1); + 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); + g_free(xsnac->tokens[i].principal1); + g_free(xsnac->tokens[i].service); + g_free(xsnac->tokens[i].principal1_again); + g_free(xsnac->tokens[i].principal2); + 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 (purple_strequal(xsnac.tokens[i].service, "im/boss")) { + aim_tlv_t *tlv; + GSList *tlvlist; + ByteStream tbs; + _______________________________________________ Commits mailing list [email protected] https://pidgin.im/cgi-bin/mailman/listinfo/commits