pidgin/pidgin

bf8ed95aaa1c
Merged in kakaroto/main/oscar_auth (pull request #69)

Adding Oscar kerberos authentication (AIM 6.x and 7.x)
--- a/ChangeLog Thu Jun 16 17:09:33 2016 -0500
+++ b/ChangeLog Fri Jun 17 18:11:18 2016 -0500
@@ -83,6 +83,9 @@
* Support file transfers up to ~9 EiB.
* Invalid user moods can no longer be sent to the server.
+ AIM:
+ * Add support for the newer kerberos-based authentication of AIM 8.x
+
Plugins:
* A new plugin API has been introduced. Plugins are no longer required
to be of a predefined type (such as protocol, standard, loader etc),
--- a/libpurple/protocols/oscar/Makefile.am Thu Jun 16 17:09:33 2016 -0500
+++ b/libpurple/protocols/oscar/Makefile.am Fri Jun 17 18:11:18 2016 -0500
@@ -11,6 +11,7 @@
aim.h \
bstream.c \
clientlogin.c \
+ kerberos.c \
encoding.c \
encoding.h \
family_admin.c \
--- a/libpurple/protocols/oscar/aim.c Thu Jun 16 17:09:33 2016 -0500
+++ b/libpurple/protocols/oscar/aim.c Fri Jun 17 18:11:18 2016 -0500
@@ -36,14 +36,7 @@
protocol->id = "prpl-aim";
protocol->name = "AIM";
- oscar_init_account_options(protocol);
-
- option = purple_account_option_bool_new(_("Allow multiple simultaneous logins"), "allow_multiple_logins",
- OSCAR_DEFAULT_ALLOW_MULTIPLE_LOGINS);
- protocol->account_options = g_list_append(protocol->account_options, option);
-
- option = purple_account_option_string_new(_("Server"), "server", oscar_get_login_server(FALSE, TRUE));
- protocol->account_options = g_list_append(protocol->account_options, option);
+ oscar_init_account_options(protocol, FALSE);
}
static void
--- a/libpurple/protocols/oscar/icq.c Thu Jun 16 17:09:33 2016 -0500
+++ b/libpurple/protocols/oscar/icq.c Fri Jun 17 18:11:18 2016 -0500
@@ -52,13 +52,8 @@
protocol->id = "prpl-icq";
protocol->name = "ICQ";
- oscar_init_account_options(protocol);
+ oscar_init_account_options(protocol, TRUE);
- option = purple_account_option_string_new(_("Server"), "server", oscar_get_login_server(TRUE, TRUE));
- protocol->account_options = g_list_append(protocol->account_options, option);
-
- option = purple_account_option_string_new(_("Encoding"), "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
- protocol->account_options = g_list_append(protocol->account_options, option);
}
static void
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/oscar/kerberos.c Fri Jun 17 18:11:18 2016 -0500
@@ -0,0 +1,436 @@
+/*
+ * 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(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 (purple_strequal(xsnac.tokens[i].service, "im/boss")) {
+ 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);
+ g_free(tlsCertName);
+ g_free(bosip);
+}
+
+/**
+ * This function sends a binary blob request to the Kerberos KDC server
+ * https://kdc.uas.aol.com with the user's username and password and
+ * receives the IM cookie, which is used to request a connection to the
+ * BOSS server.
+ * The binary data below is what AIM 8.0.8.1 sends in order to authenticate
+ * to the KDC server. It is an 'X-SNAC' packet, which is relatively similar
+ * to SNAC packets but somehow different.
+ * The header starts with the 0x50C family follow by 0x0002 subtype, then
+ * some fixed length data and TLVs. The string "COOL" appears in there for
+ * some reason followed by the 'US' and 'en' strings.
+ * Then the 'imApp key=<client key>' comes after that, and then the username
+ * and the string "im/boss" which seems to represent the service we are
+ * requesting the authentication for. Changing that will lead to a
+ * 'unknown service' error. The client key is then added again (without the
+ * 'imApp key' string prepended to it) then a XOR-ed version of the password.
+ * The meaning of the header/footer/in-between bytes is not known but never
+ * seems to change so there is no need to reverse engineer their meaning at
+ * this point.
+ */
+void send_kerberos_login(OscarData *od, const char *username)
+{
+ PurpleConnection *gc;
+ PurpleHttpRequest *req;
+ gchar *url;
+ const gchar *password;
+ gchar password_xored[MAXAIMPASSLEN];
+ const gchar *client_key;
+ gchar *imapp_key;
+ GString *body;
+ 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 = g_string_new(NULL);
+ g_string_append_len(body, header, sizeof(header));
+ reqid = (guint16) g_random_int();
+ g_string_overwrite_len(body, 0xC, (void *)&reqid, sizeof(guint16));
+
+ len_be = GUINT16_TO_BE(strlen(imapp_key));
+ g_string_append_len(body, (void *)&len_be, sizeof(guint16));
+ g_string_append(body, imapp_key);
+
+ len_be = GUINT16_TO_BE(strlen(username));
+ g_string_append_len(body, pre_username, sizeof(pre_username));
+ g_string_append_len(body, (void *)&len_be, sizeof(guint16));
+ g_string_append(body, username);
+ g_string_append_len(body, post_username, sizeof(post_username));
+
+ len_be = GUINT16_TO_BE(strlen(password) + 0x10);
+ g_string_append_len(body, (void *)&len_be, sizeof(guint16));
+ g_string_append_len(body, pre_password, sizeof(pre_password));
+ len_be = GUINT16_TO_BE(strlen(password) + 4);
+ g_string_append_len(body, (void *)&len_be, sizeof(guint16));
+ len_be = GUINT16_TO_BE(strlen(password));
+ g_string_append_len(body, (void *)&len_be, sizeof(guint16));
+ g_string_append_len(body, password_xored, strlen(password));
+ g_string_append_len(body, post_password, sizeof(post_password));
+
+ len_be = GUINT16_TO_BE(strlen(client_key));
+ g_string_append_len(body, (void *)&len_be, sizeof(guint16));
+ g_string_append(body, client_key);
+ g_string_append_len(body, footer, 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->str, body->len);
+ od->hc = purple_http_request(gc, req, kerberos_login_cb, od);
+ purple_http_request_unref(req);
+
+ g_string_free(body, TRUE);
+ g_free(url);
+}
--- a/libpurple/protocols/oscar/oscar.c Thu Jun 16 17:09:33 2016 -0500
+++ b/libpurple/protocols/oscar/oscar.c Fri Jun 17 18:11:18 2016 -0500
@@ -348,7 +348,9 @@
flap_connection_send_version(od, conn);
else
{
- if (purple_account_get_bool(account, "use_clientlogin", OSCAR_DEFAULT_USE_CLIENTLOGIN))
+ const gchar *login_type = purple_account_get_string(account, "login_type", OSCAR_DEFAULT_LOGIN);
+
+ if (!purple_strequal(login_type, OSCAR_MD5_LOGIN))
{
ClientInfo aiminfo = CLIENTINFO_PURPLE_AIM;
ClientInfo icqinfo = CLIENTINFO_PURPLE_ICQ;
@@ -641,6 +643,7 @@
PurpleConnection *gc;
OscarData *od;
const gchar *encryption_type;
+ const gchar *login_type;
GList *handlers;
GList *sorted_handlers;
GList *cur;
@@ -740,8 +743,9 @@
od->default_port = purple_account_get_int(account, "port", OSCAR_DEFAULT_LOGIN_PORT);
+ login_type = purple_account_get_string(account, "login_type", OSCAR_DEFAULT_LOGIN);
encryption_type = purple_account_get_string(account, "encryption", OSCAR_DEFAULT_ENCRYPTION);
- od->use_ssl = strcmp(encryption_type, OSCAR_NO_ENCRYPTION) != 0;
+ od->use_ssl = purple_strequal(encryption_type, OSCAR_NO_ENCRYPTION) == FALSE;
/* Connect to core Purple signals */
purple_prefs_connect_callback(purple_connection_get_protocol(gc), "/purple/away/idle_reporting", idle_reporting_pref_cb, gc);
@@ -757,8 +761,36 @@
* This authentication method is used for both ICQ and AIM when
* clientLogin is not enabled.
*/
- if (purple_account_get_bool(account, "use_clientlogin", OSCAR_DEFAULT_USE_CLIENTLOGIN)) {
+ if (purple_strequal(login_type, OSCAR_CLIENT_LOGIN)) {
+ /* Note: Actual server/port configuration is ignored here */
send_client_login(od, purple_account_get_username(account));
+ } else if (purple_strequal(login_type, OSCAR_KERBEROS_LOGIN)) {
+ 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 (purple_strequal(server, oscar_get_login_server(od->icq, FALSE)) ||
+ purple_strequal(server, oscar_get_login_server(od->icq, TRUE)) ||
+ purple_strequal(server, AIM_ALT_LOGIN_SERVER) ||
+ purple_strequal(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;
@@ -775,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 (purple_strequal(server, oscar_get_login_server(od->icq, FALSE)) ||
+ purple_strequal(server, AIM_ALT_LOGIN_SERVER) ||
+ purple_strequal(server, AIM_DEFAULT_KDC_SERVER) ||
+ purple_strequal(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);
}
@@ -792,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 (purple_strequal(server, oscar_get_login_server(od->icq, TRUE)) ||
+ purple_strequal(server, AIM_DEFAULT_KDC_SERVER) ||
+ purple_strequal(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);
}
@@ -1079,9 +1118,9 @@
if (!redir->use_ssl) {
const gchar *encryption_type = purple_account_get_string(account, "encryption", OSCAR_DEFAULT_ENCRYPTION);
- if (strcmp(encryption_type, OSCAR_OPPORTUNISTIC_ENCRYPTION) == 0) {
+ if (purple_strequal(encryption_type, OSCAR_OPPORTUNISTIC_ENCRYPTION)) {
purple_debug_warning("oscar", "We won't use SSL for FLAP type 0x%04hx.\n", redir->group);
- } else if (strcmp(encryption_type, OSCAR_REQUIRE_ENCRYPTION) == 0) {
+ } else if (purple_strequal(encryption_type, OSCAR_REQUIRE_ENCRYPTION)) {
purple_debug_error("oscar", "FLAP server %s:%d of type 0x%04hx doesn't support encryption.\n", host, port, redir->group);
purple_connection_error(
gc,
@@ -1252,7 +1291,7 @@
? oscar_encoding_to_utf8(info->status_encoding, info->status, info->status_len)
: NULL;
- if (strcmp(status_id, OSCAR_STATUS_ID_AVAILABLE) == 0) {
+ if (purple_strequal(status_id, OSCAR_STATUS_ID_AVAILABLE)) {
/* TODO: If itmsurl is NULL, does that mean the URL has been
cleared? Or does it mean the URL should remain unchanged? */
if (info->itmsurl != NULL) {
@@ -5555,7 +5594,7 @@
return FALSE;
}
-void oscar_init_account_options(PurpleProtocol *protocol)
+void oscar_init_account_options(PurpleProtocol *protocol, gboolean is_icq)
{
PurpleAccountOption *option;
static const gchar *encryption_keys[] = {
@@ -5570,9 +5609,37 @@
OSCAR_NO_ENCRYPTION,
NULL
};
+ 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 *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;
+ option = purple_account_option_string_new(_("Server"), "server", oscar_get_login_server(is_icq, TRUE));
+ protocol->account_options = g_list_append(protocol->account_options, option);
+
option = purple_account_option_int_new(_("Port"), "port", OSCAR_DEFAULT_LOGIN_PORT);
protocol->account_options = g_list_append(protocol->account_options, option);
@@ -5585,14 +5652,35 @@
option = purple_account_option_list_new(_("Connection security"), "encryption", encryption_options);
protocol->account_options = g_list_append(protocol->account_options, option);
- option = purple_account_option_bool_new(_("Use clientLogin"), "use_clientlogin",
- OSCAR_DEFAULT_USE_CLIENTLOGIN);
+ 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]));
+ kvp->value = g_strdup(login_values[i]);
+ login_options = g_list_append(login_options, kvp);
+ }
+ option = purple_account_option_list_new(_("Authentication method"), "login_type", login_options);
protocol->account_options = g_list_append(protocol->account_options, option);
option = purple_account_option_bool_new(
_("Always use AIM/ICQ proxy server for\nfile transfers and direct IM (slower,\nbut does not reveal your IP address)"), "always_use_rv_proxy",
OSCAR_DEFAULT_ALWAYS_USE_RV_PROXY);
protocol->account_options = g_list_append(protocol->account_options, option);
+
+ if (is_icq) {
+ option = purple_account_option_string_new(_("Encoding"), "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
+ protocol->account_options = g_list_append(protocol->account_options, option);
+ } else {
+ option = purple_account_option_bool_new(_("Allow multiple simultaneous logins"), "allow_multiple_logins",
+ OSCAR_DEFAULT_ALLOW_MULTIPLE_LOGINS);
+ protocol->account_options = g_list_append(protocol->account_options, option);
+ }
}
static void
--- a/libpurple/protocols/oscar/oscar.h Thu Jun 16 17:09:33 2016 -0500
+++ b/libpurple/protocols/oscar/oscar.h Fri Jun 17 18:11:18 2016 -0500
@@ -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);
@@ -1367,7 +1373,7 @@
void oscar_free_name_data(struct name_data *data);
-void oscar_init_account_options(PurpleProtocol *protocol);
+void oscar_init_account_options(PurpleProtocol *protocol, gboolean is_icq);
#ifdef __cplusplus
}
--- a/libpurple/protocols/oscar/oscarcommon.h Thu Jun 16 17:09:33 2016 -0500
+++ b/libpurple/protocols/oscar/oscarcommon.h Fri Jun 17 18:11:18 2016 -0500
@@ -38,12 +38,19 @@
#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"
#define OSCAR_REQUIRE_ENCRYPTION "require_encryption"
#define OSCAR_NO_ENCRYPTION "no_encryption"
+#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"
#else
@@ -54,7 +61,7 @@
#define OSCAR_DEFAULT_WEB_AWARE FALSE
#define OSCAR_DEFAULT_ALWAYS_USE_RV_PROXY FALSE
#define OSCAR_DEFAULT_ALLOW_MULTIPLE_LOGINS TRUE
-#define OSCAR_DEFAULT_USE_CLIENTLOGIN TRUE
+#define OSCAR_DEFAULT_LOGIN OSCAR_CLIENT_LOGIN
#define OSCAR_DEFAULT_ENCRYPTION OSCAR_OPPORTUNISTIC_ENCRYPTION
#ifdef _WIN32