pidgin/pidgin

oscar: Add kerberos authentication method support for AIM
oscar_auth
2016-05-06, Youness Alaoui
0105b155a3d1
Parents 4b57eced35d5
Children ddd9c4c0e596
oscar: Add kerberos authentication method support for AIM

This doesn't actually use kerberos to authenticate to the chat server,
but it uses the kerberos KDC server to authenticate and it receives
the authentication cookie for the IM service at the same time.
We simply don't use the KDC ticket to authenticate for the website.
--- a/libpurple/protocols/oscar/Makefile.am Tue May 03 15:00:13 2016 -0400
+++ b/libpurple/protocols/oscar/Makefile.am Fri May 06 16:22:21 2016 -0400
@@ -11,6 +11,7 @@
aim.h \
bstream.c \
clientlogin.c \
+ kerberos.c \
encoding.c \
encoding.h \
family_admin.c \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/oscar/kerberos.c Fri May 06 16:22:21 2016 -0400
@@ -0,0 +1,468 @@
+/*
+ * 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"
+
+#include "ciphers/hmaccipher.h"
+#include "ciphers/sha256hash.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 clientLogin 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(PurpleHttpConnection *http_conn,
+ PurpleHttpResponse *response, gpointer _od)
+{
+ OscarData *od = _od;
+ PurpleConnection *gc;
+ const gchar *got_data;
+ size_t got_len;
+ 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->hc = NULL;
+
+ if (!purple_http_response_is_successful(response)) {
+ gchar *tmp;
+ gchar *url;
+
+ url = get_kdc_url(od);
+ tmp = g_strdup_printf(_("Error requesting %s: %s"),
+ url,
+ purple_http_response_get_error(response));
+ purple_connection_error(gc,
+ PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
+ g_free(tmp);
+ g_free(url);
+ return;
+ }
+
+ got_data = purple_http_response_get_data(response, &got_len);
+ 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(gc,
+ PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
+ _("Incorrect password"));
+ return;
+ }
+ if (xsnac.family != 0x50C || xsnac.subtype != 0x0003) {
+ purple_connection_error(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);
+ byte_stream_get32(&tbs);
+ tlvlist = aim_tlvlist_read (&tbs);
+ if (aim_tlv_gettlv (tlvlist, 0x0005, 1))
+ bosip = aim_tlv_getstr (tlvlist, 0x0005, 1);
+ if (aim_tlv_gettlv (tlvlist, 0x0005, 1))
+ tlsCertName = aim_tlv_getstr (tlvlist, 0x008D, 1);
+ tlv = aim_tlv_gettlv(tlvlist, 0x0006, 1);
+ if (tlv) {
+ cookie_len = tlv->length;
+ cookie = tlv->value;
+ }
+ }
+ break;
+ }
+ }
+ if (bosip && cookie) {
+ port = AIM_DEFAULT_KDC_PORT;
+ for (i = 0; i < strlen(bosip); i++) {
+ if (bosip[i] == ':') {
+ port = atoi(&(bosip[i+1]));
+ break;
+ }
+ }
+ host = g_strndup(bosip, i);
+ oscar_connect_to_bos(gc, od, host, port, cookie, cookie_len, tlsCertName);
+ g_free (host);
+ } else {
+ purple_connection_error(gc,
+ PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+ _("Unknown error during authentication"));
+ }
+ aim_xsnac_free (&xsnac);
+ if (tlsCertName)
+ g_free (tlsCertName);
+ if (bosip)
+ g_free (bosip);
+}
+
+/**
+ * This function sends a request to
+ * https://api.screenname.aol.com/auth/clientLogin with the user's
+ * username and password and receives the user's session key, which is
+ * used to request a connection to the BOSS server.
+ */
+void send_kerberos_login(OscarData *od, const char *username)
+{
+ PurpleConnection *gc;
+ PurpleHttpRequest *req;
+ gchar *url;
+ const gchar *password;
+ guint8 password_xored[MAXAIMPASSLEN];
+ const gchar *client_key;
+ gchar *imapp_key;
+ gchar *body;
+ gint body_len;
+ guint16 len_be;
+ guint16 reqid;
+ const gchar header[] = {
+ 0x05, 0x0C, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
+ 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05,
+ 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x18, 0x99,
+ 0x00, 0x05, 0x00, 0x04, 0x43, 0x4F, 0x4F, 0x4C,
+ 0x00, 0x0A, 0x00, 0x02, 0x00, 0x01, 0x00, 0x0B,
+ 0x00, 0x04, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+ 0x55, 0x53, 0x00, 0x02, 0x65, 0x6E, 0x00, 0x04,
+ 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0D,
+ 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x05};
+ const gchar pre_username[] = {
+ 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x01, 0x8B,
+ 0x01, 0x00, 0x00, 0x00, 0x00};
+ const gchar post_username[] = {
+ 0x00, 0x07, 0x69, 0x6D, 0x2F, 0x62, 0x6F, 0x73,
+ 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x02};
+ const gchar pre_password[] = {
+ 0x40, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01,
+ 0x00, 0x00};
+ const gchar post_password[] = {0x00, 0x00, 0x00, 0x1D};
+ const gchar footer[] = {
+ 0x00, 0x21, 0x00, 0x32, 0x00, 0x01, 0x10, 0x03,
+ 0x00, 0x2C, 0x00, 0x07, 0x00, 0x14, 0x00, 0x04,
+ 0x00, 0x00, 0x01, 0x8B, 0x00, 0x16, 0x00, 0x02,
+ 0x00, 0x26, 0x00, 0x17, 0x00, 0x02, 0x00, 0x07,
+ 0x00, 0x18, 0x00, 0x02, 0x00, 0x00, 0x00, 0x19,
+ 0x00, 0x02, 0x00, 0x0D, 0x00, 0x1A, 0x00, 0x02,
+ 0x00, 0x04, 0x00, 0xAB, 0x00, 0x00, 0x00, 0x28,
+ 0x00, 0x00};
+
+ gc = od->gc;
+
+ password = purple_connection_get_password(gc);
+ aim_encode_password (password, password_xored);
+
+ client_key = get_client_key(od);
+ imapp_key = g_strdup_printf ("imApp key=%s", client_key);
+
+ /* Construct the body of the HTTP POST request */
+ body_len = sizeof(header);
+ body_len += 2 + strlen (imapp_key);
+ body_len += sizeof(pre_username);
+ body_len += 2 + strlen (username);
+ body_len += sizeof(post_username);
+ body_len += 2 + sizeof(pre_password);
+ body_len += 4 + strlen (password);
+ body_len += sizeof(post_password);
+ body_len += 2 + strlen (client_key);
+ body_len += sizeof(footer);
+
+ body = g_malloc (body_len);
+
+ body_len = 0;
+ reqid = (guint16) g_random_int();
+ memcpy (body, header, sizeof(header));
+ memcpy (body + 0xC, (void *)&reqid, sizeof(guint16));
+ body_len += sizeof(header);
+
+ len_be = GUINT16_TO_BE (strlen (imapp_key));
+ memcpy (body + body_len, (void *)&len_be, sizeof(guint16));
+ body_len += sizeof(guint16);
+ memcpy (body + body_len, imapp_key, strlen (imapp_key));
+ body_len += strlen (imapp_key);
+
+ memcpy (body + body_len, pre_username, sizeof(pre_username));
+ body_len += sizeof(pre_username);
+ len_be = GUINT16_TO_BE (strlen (username));
+ memcpy (body + body_len, (void *)&len_be, sizeof(guint16));
+ body_len += sizeof(guint16);
+ memcpy (body + body_len, username, strlen (username));
+ body_len += strlen (username);
+ memcpy (body + body_len, post_username, sizeof(post_username));
+ body_len += sizeof(post_username);
+
+ len_be = GUINT16_TO_BE (strlen (password) + 0x10);
+ memcpy (body + body_len, (void *)&len_be, sizeof(guint16));
+ body_len += sizeof(guint16);
+ memcpy (body + body_len, pre_password, sizeof(pre_password));
+ body_len += sizeof(pre_password);
+ len_be = GUINT16_TO_BE (strlen (password) + 4);
+ memcpy (body + body_len, (void *)&len_be, sizeof(guint16));
+ body_len += sizeof(guint16);
+ len_be = GUINT16_TO_BE (strlen (password));
+ memcpy (body + body_len, (void *)&len_be, sizeof(guint16));
+ body_len += sizeof(guint16);
+ memcpy (body + body_len, password_xored, strlen (password));
+ body_len += strlen (password);
+ memcpy (body + body_len, post_password, sizeof(post_password));
+ body_len += sizeof(post_password);
+
+ len_be = GUINT16_TO_BE (strlen (client_key));
+ memcpy (body + body_len, (void *)&len_be, sizeof(guint16));
+ body_len += sizeof(guint16);
+ memcpy (body + body_len, client_key, strlen (client_key));
+ body_len += strlen (client_key);
+ memcpy (body + body_len, footer, sizeof(footer));
+ body_len += sizeof(footer);
+
+ g_free(imapp_key);
+
+ url = get_kdc_url(od);
+ req = purple_http_request_new(url);
+ purple_http_request_set_method(req, "POST");
+ purple_http_request_header_set(req, "Content-Type",
+ "application/x-snac");
+ purple_http_request_header_set(req, "Accept",
+ "application/x-snac");
+ purple_http_request_set_contents(req, body, body_len);
+ od->hc = purple_http_request(gc, req, kerberos_login_cb, od);
+ purple_http_request_unref(req);
+
+ g_free (body);
+ g_free (url);
+}
--- a/libpurple/protocols/oscar/oscar.c Tue May 03 15:00:13 2016 -0400
+++ b/libpurple/protocols/oscar/oscar.c Fri May 06 16:22:21 2016 -0400
@@ -350,7 +350,7 @@
{
const gchar *login_type = purple_account_get_string(account, "login_type", OSCAR_DEFAULT_LOGIN);
- if (strcmp(login_type, OSCAR_CLIENT_LOGIN) == 0)
+ if (strcmp(login_type, OSCAR_MD5_LOGIN) != 0)
{
ClientInfo aiminfo = CLIENTINFO_PURPLE_AIM;
ClientInfo icqinfo = CLIENTINFO_PURPLE_ICQ;
@@ -762,7 +762,35 @@
* clientLogin is not enabled.
*/
if (strcmp(login_type, OSCAR_CLIENT_LOGIN) == 0) {
+ /* Note: Actual server/port configuration is ignored here */
send_client_login(od, purple_account_get_username(account));
+ } else if (strcmp(login_type, OSCAR_KERBEROS_LOGIN) == 0) {
+ const char *server;
+
+ if (!od->use_ssl) {
+ purple_connection_error(
+ gc,
+ PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT,
+ _("You required Kerberos authentication but encryption is disabled in your account settings."));
+ return;
+ }
+ server = purple_account_get_string(account, "server", AIM_DEFAULT_KDC_SERVER);
+ /*
+ * If the account's server is what the oscar protocol has offered as
+ * the default login server through the vast eons (all two of
+ * said default options, AFAIK) and the user wants KDC, we'll
+ * do what we know is best for them and change the setting out
+ * from under them to the KDC login server.
+ */
+ if (!strcmp(server, oscar_get_login_server(od->icq, FALSE)) ||
+ !strcmp(server, oscar_get_login_server(od->icq, TRUE)) ||
+ !strcmp(server, AIM_ALT_LOGIN_SERVER) ||
+ !strcmp(server, "")) {
+ purple_debug_info("oscar", "Account uses Kerberos auth, so changing server to default KDC server\n");
+ purple_account_set_string(account, "server", AIM_DEFAULT_KDC_SERVER);
+ purple_account_set_int(account, "port", AIM_DEFAULT_KDC_PORT);
+ }
+ send_kerberos_login(od, purple_account_get_username(account));
} else {
FlapConnection *newconn;
const char *server;
@@ -779,9 +807,13 @@
* do what we know is best for them and change the setting out
* from under them to the SSL login server.
*/
- if (!strcmp(server, oscar_get_login_server(od->icq, FALSE)) || !strcmp(server, AIM_ALT_LOGIN_SERVER)) {
+ if (!strcmp(server, oscar_get_login_server(od->icq, FALSE)) ||
+ !strcmp(server, AIM_ALT_LOGIN_SERVER) ||
+ !strcmp(server, AIM_DEFAULT_KDC_SERVER) ||
+ !strcmp(server, "")) {
purple_debug_info("oscar", "Account uses SSL, so changing server to default SSL server\n");
purple_account_set_string(account, "server", oscar_get_login_server(od->icq, TRUE));
+ purple_account_set_int(account, "port", OSCAR_DEFAULT_LOGIN_PORT),
server = oscar_get_login_server(od->icq, TRUE);
}
@@ -796,9 +828,12 @@
* SSL but their server is set to OSCAR_DEFAULT_SSL_LOGIN_SERVER,
* set it back to the default.
*/
- if (!strcmp(server, oscar_get_login_server(od->icq, TRUE))) {
+ if (!strcmp(server, oscar_get_login_server(od->icq, TRUE)) ||
+ !strcmp(server, AIM_DEFAULT_KDC_SERVER) ||
+ !strcmp(server, "")) {
purple_debug_info("oscar", "Account does not use SSL, so changing server back to non-SSL\n");
purple_account_set_string(account, "server", oscar_get_login_server(od->icq, FALSE));
+ purple_account_set_int(account, "port", OSCAR_DEFAULT_LOGIN_PORT),
server = oscar_get_login_server(od->icq, FALSE);
}
@@ -5574,16 +5609,30 @@
OSCAR_NO_ENCRYPTION,
NULL
};
- static const gchar *login_keys[] = {
+ static const gchar *aim_login_keys[] = {
+ N_("Use clientLogin authentication"),
+ N_("Use Kerberos-based authentication"),
+ N_("Use MD5 based authentication"),
+ NULL
+ };
+ static const gchar *aim_login_values[] = {
+ OSCAR_CLIENT_LOGIN,
+ OSCAR_KERBEROS_LOGIN,
+ OSCAR_MD5_LOGIN,
+ NULL
+ };
+ static const gchar *icq_login_keys[] = {
N_("Use clientLogin authentication"),
N_("Use MD5 based authentication"),
NULL
};
- static const gchar *login_values[] = {
+ static const gchar *icq_login_values[] = {
OSCAR_CLIENT_LOGIN,
OSCAR_MD5_LOGIN,
NULL
};
+ const gchar **login_keys;
+ const gchar **login_values;
GList *encryption_options = NULL;
GList *login_options = NULL;
int i;
@@ -5603,6 +5652,13 @@
option = purple_account_option_list_new(_("Connection security"), "encryption", encryption_options);
protocol->account_options = g_list_append(protocol->account_options, option);
+ if (is_icq) {
+ login_keys = icq_login_keys;
+ login_values = icq_login_values;
+ } else {
+ login_keys = aim_login_keys;
+ login_values = aim_login_values;
+ }
for (i = 0; login_keys[i]; i++) {
PurpleKeyValuePair *kvp = g_new0(PurpleKeyValuePair, 1);
kvp->key = g_strdup(_(login_keys[i]));
--- a/libpurple/protocols/oscar/oscar.h Tue May 03 15:00:13 2016 -0400
+++ b/libpurple/protocols/oscar/oscar.h Fri May 06 16:22:21 2016 -0400
@@ -524,6 +524,12 @@
*/
void send_client_login(OscarData *od, const char *username);
+/**
+ * Only used when connecting with kerberos login.
+ */
+void send_kerberos_login(OscarData *od, const char *username);
+
+
/* flap_connection.c */
FlapConnection *flap_connection_new(OscarData *, int type);
void flap_connection_close(OscarData *od, FlapConnection *conn);
--- a/libpurple/protocols/oscar/oscarcommon.h Tue May 03 15:00:13 2016 -0400
+++ b/libpurple/protocols/oscar/oscarcommon.h Fri May 06 16:22:21 2016 -0400
@@ -38,6 +38,9 @@
#define ICQ_DEFAULT_LOGIN_SERVER "login.icq.com"
#define ICQ_DEFAULT_SSL_LOGIN_SERVER "slogin.icq.com"
+#define AIM_DEFAULT_KDC_SERVER "kdc.uas.aol.com"
+#define AIM_DEFAULT_KDC_PORT 443
+
#define OSCAR_DEFAULT_LOGIN_PORT 5190
#define OSCAR_OPPORTUNISTIC_ENCRYPTION "opportunistic_encryption"
@@ -46,6 +49,7 @@
#define OSCAR_MD5_LOGIN "md5_login"
#define OSCAR_CLIENT_LOGIN "client_login"
+#define OSCAR_KERBEROS_LOGIN "kerberos_login"
#ifndef _WIN32
#define OSCAR_DEFAULT_CUSTOM_ENCODING "ISO-8859-1"