cpw.sulabh.yahoo_16: d0e53002: Yahoo version 16 login. ---yet to do: pr...

sulabh at soc.pidgin.im sulabh at soc.pidgin.im
Wed May 6 14:50:32 EDT 2009


-----------------------------------------------------------------
Revision: d0e53002eb30c6dbf9735ca50784d42141dfc96a
Ancestor: 0cb6e54b872e187a678895961106518e55aab987
Author: sulabh at soc.pidgin.im
Date: 2009-05-06T08:48:57
Branch: im.pidgin.cpw.sulabh.yahoo_16
URL: http://d.pidgin.im/viewmtn/revision/info/d0e53002eb30c6dbf9735ca50784d42141dfc96a

Deleted entries:
        libpurple/protocols/yahoo/yahoo_auth.c
        libpurple/protocols/yahoo/yahoo_auth.h
        libpurple/protocols/yahoo/yahoo_crypt.c
        libpurple/protocols/yahoo/yahoo_crypt.h
Modified files:
        libpurple/protocols/yahoo/Makefile.am
        libpurple/protocols/yahoo/Makefile.mingw
        libpurple/protocols/yahoo/yahoo.c
        libpurple/protocols/yahoo/yahoo.h
        libpurple/protocols/yahoo/yahoo_doodle.c
        libpurple/protocols/yahoo/yahoo_packet.h

ChangeLog: 

Yahoo version 16 login. ---yet to do: prevent password from being displayed in debug logs---

-------------- next part --------------
============================================================
--- libpurple/protocols/yahoo/Makefile.am	eaf9c3dc7fa9d6426f3911a238c9bc6c39ad806a
+++ libpurple/protocols/yahoo/Makefile.am	aabcd64b33d9f8ef54737c57e6c2a4b440b8b43b
@@ -11,10 +11,6 @@ YAHOOSOURCES = \
 	yahoochat.c \
 	yahoo_aliases.c \
 	yahoo_aliases.h \
-	yahoo_auth.c \
-	yahoo_auth.h \
-	yahoo_crypt.h \
-	yahoo_crypt.c \
 	yahoo_doodle.h \
 	yahoo_doodle.c \
 	yahoo_filexfer.h \
============================================================
--- libpurple/protocols/yahoo/Makefile.mingw	7484dd539cfd2f0ce6bd8202f9c2aece4af99fab
+++ libpurple/protocols/yahoo/Makefile.mingw	ea2b65dfce8eb07ef7176b059f599ab6c4c69192
@@ -41,8 +41,6 @@ C_SRC =			util.c \
 			yahoo.c \
 			yahoochat.c \
 			yahoo_aliases.c \
-			yahoo_auth.c \
-			yahoo_crypt.c \
 			yahoo_doodle.c \
 			yahoo_filexfer.c \
 			yahoo_friend.c \
============================================================
--- libpurple/protocols/yahoo/yahoo.c	e55a2de00eb1107425a90f982389ed96af3ae3fb
+++ libpurple/protocols/yahoo/yahoo.c	0a2ae02c9798c43ff1891a28cfbde2976e761ce6
@@ -44,8 +44,6 @@
 #include "yahoo.h"
 #include "yahoochat.h"
 #include "yahoo_aliases.h"
-#include "yahoo_auth.h"
-#include "yahoo_crypt.h"
 #include "yahoo_doodle.h"
 #include "yahoo_filexfer.h"
 #include "yahoo_friend.h"
@@ -1527,11 +1525,19 @@ static void yahoo_process_mail(PurpleCon
 						   NULL, NULL);
 	}
 }
+
+/* We use this structure once while we authenticate */
+struct yahoo_auth_data
+{
+	PurpleConnection *gc;
+	char *seed;
+};
+
 /* This is the y64 alphabet... it's like base64, but has a . and a _ */
 static const char base64digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._";
 
-/* This is taken from Sylpheed by Hiroyuki Yamamoto.  We have our own tobase64 function
- * in util.c, but it has a bug I don't feel like finding right now ;) */
+/* This is taken from Sylpheed by Hiroyuki Yamamoto. We have our own tobase64 function
+ * in util.c, but it is different from the one yahoo uses */
 static void to_y64(char *out, const unsigned char *in, gsize inlen)
      /* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */
 {
@@ -1558,605 +1564,247 @@ static void to_y64(char *out, const unsi
 	*out = '\0';
 }
 
-static void yahoo_process_auth_old(PurpleConnection *gc, const char *seed)
+static void yahoo_auth16_stage3(PurpleConnection *gc, char *crypt)
 {
-	struct yahoo_packet *pack;
+	struct yahoo_data *yd = gc->proto_data;
 	PurpleAccount *account = purple_connection_get_account(gc);
 	const char *name = purple_normalize(account, purple_account_get_username(account));
-	const char *pass = purple_connection_get_password(gc);
-	struct yahoo_data *yd = gc->proto_data;
+	PurpleCipher *md5_cipher;
+	PurpleCipherContext *md5_ctx;
+	guchar md5_digest[16];
+	gchar base64_string[25];
+	struct yahoo_packet *pkt;
 
-	/* So, Yahoo has stopped supporting its older clients in India, and undoubtedly
-	 * will soon do so in the rest of the world.
-	 *
-	 * The new clients use this authentication method.  I warn you in advance, it's
-	 * bizarre, convoluted, inordinately complicated.  It's also no more secure than
-	 * crypt() was.  The only purpose this scheme could serve is to prevent third
-	 * party clients from connecting to their servers.
-	 *
-	 * Sorry, Yahoo.
-	 */
+	purple_debug_info("yahoo","Authentication: In yahoo_auth16_stage3\n");
 
-	PurpleCipher *cipher;
-	PurpleCipherContext *context;
-	guchar digest[16];
+	md5_cipher = purple_ciphers_find_cipher("md5");
+	md5_ctx = purple_cipher_context_new(md5_cipher, NULL);
+	purple_cipher_context_append(md5_ctx,(guchar *)crypt, strlen(crypt));
+	purple_cipher_context_digest(md5_ctx, sizeof(md5_digest),md5_digest, NULL);
 
-	char *crypt_result;
-	char password_hash[25];
-	char crypt_hash[25];
-	char *hash_string_p = g_malloc(50 + strlen(name));
-	char *hash_string_c = g_malloc(50 + strlen(name));
+	to_y64(base64_string, md5_digest, 16);
 
-	char checksum;
-
-	int sv;
-
-	char result6[25];
-	char result96[25];
-
-	sv = seed[15];
-	sv = sv % 8;
-
-	cipher = purple_ciphers_find_cipher("md5");
-	context = purple_cipher_context_new(cipher, NULL);
-
-	purple_cipher_context_append(context, (const guchar *)pass, strlen(pass));
-	purple_cipher_context_digest(context, sizeof(digest), digest, NULL);
-
-	to_y64(password_hash, digest, 16);
-
-	crypt_result = yahoo_crypt(pass, "$1$_2S43d5f$");
-
-	purple_cipher_context_reset(context, NULL);
-	purple_cipher_context_append(context, (const guchar *)crypt_result, strlen(crypt_result));
-	purple_cipher_context_digest(context, sizeof(digest), digest, NULL);
-	to_y64(crypt_hash, digest, 16);
-
-	switch (sv) {
-	case 1:
-	case 6:
-		checksum = seed[seed[9] % 16];
-		g_snprintf(hash_string_p, strlen(name) + 50,
-			   "%c%s%s%s", checksum, name, seed, password_hash);
-		g_snprintf(hash_string_c, strlen(name) + 50,
-			   "%c%s%s%s", checksum, name, seed, crypt_hash);
-		break;
-	case 2:
-	case 7:
-		checksum = seed[seed[15] % 16];
-		g_snprintf(hash_string_p, strlen(name) + 50,
-			   "%c%s%s%s", checksum, seed, password_hash, name);
-		g_snprintf(hash_string_c, strlen(name) + 50,
-			   "%c%s%s%s", checksum, seed, crypt_hash, name);
-		break;
-	case 3:
-		checksum = seed[seed[1] % 16];
-		g_snprintf(hash_string_p, strlen(name) + 50,
-			   "%c%s%s%s", checksum, name, password_hash, seed);
-		g_snprintf(hash_string_c, strlen(name) + 50,
-			   "%c%s%s%s", checksum, name, crypt_hash, seed);
-		break;
-	case 4:
-		checksum = seed[seed[3] % 16];
-		g_snprintf(hash_string_p, strlen(name) + 50,
-			   "%c%s%s%s", checksum, password_hash, seed, name);
-		g_snprintf(hash_string_c, strlen(name) + 50,
-			   "%c%s%s%s", checksum, crypt_hash, seed, name);
-		break;
-	case 0:
-	case 5:
-		checksum = seed[seed[7] % 16];
-			g_snprintf(hash_string_p, strlen(name) + 50,
-                                   "%c%s%s%s", checksum, password_hash, name, seed);
-                        g_snprintf(hash_string_c, strlen(name) + 50,
-				   "%c%s%s%s", checksum, crypt_hash, name, seed);
-			break;
-	}
-
-	purple_cipher_context_reset(context, NULL);
-	purple_cipher_context_append(context, (const guchar *)hash_string_p, strlen(hash_string_p));
-	purple_cipher_context_digest(context, sizeof(digest), digest, NULL);
-	to_y64(result6, digest, 16);
-
-	purple_cipher_context_reset(context, NULL);
-	purple_cipher_context_append(context, (const guchar *)hash_string_c, strlen(hash_string_c));
-	purple_cipher_context_digest(context, sizeof(digest), digest, NULL);
-	purple_cipher_context_destroy(context);
-	to_y64(result96, digest, 16);
-
-	pack = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP,	YAHOO_STATUS_AVAILABLE, 0);
-
+	pkt = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, YAHOO_STATUS_WEBLOGIN, yd->session_id);
 	if(yd->jp) {
-		yahoo_packet_hash(pack, "sssss",
-						  0, name,
-						  6, result6,
-						  96, result96,
-						  1, name,
-						  135, YAHOOJP_CLIENT_VERSION);
-	} else {
-		yahoo_packet_hash(pack, "ssssss",
-						  0, name,
-						  6, result6,
-						  96, result96,
-						  1, name,
-						  244, YAHOO_CLIENT_VERSION_ID,
-						  135, YAHOO_CLIENT_VERSION);
+		yahoo_packet_hash(pkt, "ssssssss",
+					1, name,
+					0, name,
+					277, yd->cookie_y,
+					278, yd->cookie_t,
+					307, base64_string,
+					2, name,
+					2, "1",
+					135, YAHOOJP_CLIENT_VERSION);
+	} else	{
+		yahoo_packet_hash(pkt, "sssssssss",
+					1, name,
+					0, name,
+					277, yd->cookie_y,
+					278, yd->cookie_t,
+					307, base64_string,
+					244, YAHOO_CLIENT_VERSION_ID,
+					2, name,
+					2, "1",
+					135, YAHOO_CLIENT_VERSION);
 	}
+	if (yd->picture_checksum)
+		yahoo_packet_hash_int(pkt, 192, yd->picture_checksum);
+	yahoo_packet_send_and_free(pkt, yd);
 
-	yahoo_packet_send_and_free(pack, yd);
-
-	g_free(hash_string_p);
-	g_free(hash_string_c);
+	purple_cipher_context_destroy(md5_ctx);
+	g_free(crypt);	
 }
 
-/* I'm dishing out some uber-mad props to Cerulean Studios for cracking this
- * and sending the fix!  Thanks guys. */
-
-static void yahoo_process_auth_new(PurpleConnection *gc, const char *seed)
+static void yahoo_auth16_stage2(PurpleUtilFetchUrlData *url_data2, gpointer user_data, const gchar *ret_data, size_t len, const gchar *error_message)
 {
-	struct yahoo_packet *pack = NULL;
-	PurpleAccount *account = purple_connection_get_account(gc);
-	const char *name = purple_normalize(account, purple_account_get_username(account));
-	const char *pass = purple_connection_get_password(gc);
-	char *enc_pass;
-	struct yahoo_data *yd = gc->proto_data;
+	struct yahoo_auth_data *auth_data = user_data;
+	PurpleConnection *gc = auth_data->gc;
+	struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data;
+	gchar **split_data = NULL;
+	int totalelements;
+	int response_no;
+	char *crumb = NULL;
+	char *error_reason = NULL;
+	char *crypt = NULL;
+	gboolean try_login_on_error = FALSE;
 
-	PurpleCipher		*md5_cipher;
-	PurpleCipherContext	*md5_ctx;
-	guchar				md5_digest[16];
+	purple_debug_info("yahoo","Authentication: In yahoo_auth16_stage2\n");
 
-	PurpleCipher		*sha1_cipher;
-	PurpleCipherContext	*sha1_ctx1;
-	PurpleCipherContext	*sha1_ctx2;
+	g_return_if_fail(PURPLE_CONNECTION_IS_VALID(gc));
 
-	char				*alphabet1			= "FBZDWAGHrJTLMNOPpRSKUVEXYChImkwQ";
-	char				*alphabet2			= "F0E1D2C3B4A59687abcdefghijklmnop";
-
-	char				*challenge_lookup	= "qzec2tb3um1olpar8whx4dfgijknsvy5";
-	char				*operand_lookup		= "+|&%/*^-";
-	char				*delimit_lookup		= ",;";
-
-	char				*password_hash		= (char *)g_malloc(25);
-	char				*crypt_hash			= (char *)g_malloc(25);
-	char				*crypt_result		= NULL;
-
-	unsigned char		pass_hash_xor1[64];
-	unsigned char		pass_hash_xor2[64];
-	unsigned char		crypt_hash_xor1[64];
-	unsigned char		crypt_hash_xor2[64];
-	char				resp_6[100];
-	char				resp_96[100];
-
-	unsigned char		digest1[20];
-	unsigned char		digest2[20];
-	unsigned char		comparison_src[20];
-	unsigned char		magic_key_char[4];
-	const char			*magic_ptr;
-
-	unsigned int		magic[64];
-	unsigned int		magic_work = 0;
-	unsigned int		magic_4 = 0;
-
-	int					x;
-	int					y;
-	int					cnt = 0;
-	int					magic_cnt = 0;
-	int					magic_len;
-
-	memset(password_hash, 0, 25);
-	memset(crypt_hash, 0, 25);
-	memset(&pass_hash_xor1, 0, 64);
-	memset(&pass_hash_xor2, 0, 64);
-	memset(&crypt_hash_xor1, 0, 64);
-	memset(&crypt_hash_xor2, 0, 64);
-	memset(&digest1, 0, 20);
-	memset(&digest2, 0, 20);
-	memset(&magic, 0, 64);
-	memset(&resp_6, 0, 100);
-	memset(&resp_96, 0, 100);
-	memset(&magic_key_char, 0, 4);
-	memset(&comparison_src, 0, 20);
-
-	md5_cipher = purple_ciphers_find_cipher("md5");
-	md5_ctx = purple_cipher_context_new(md5_cipher, NULL);
-
-	sha1_cipher = purple_ciphers_find_cipher("sha1");
-	sha1_ctx1 = purple_cipher_context_new(sha1_cipher, NULL);
-	sha1_ctx2 = purple_cipher_context_new(sha1_cipher, NULL);
-
-	/*
-	 * Magic: Phase 1.  Generate what seems to be a 30 byte value (could change if base64
-	 * ends up differently?  I don't remember and I'm tired, so use a 64 byte buffer.
-	 */
-
-	magic_ptr = seed;
-
-	while (*magic_ptr != '\0') {
-		char   *loc;
-
-		/* Ignore parentheses. */
-
-		if (*magic_ptr == '(' || *magic_ptr == ')') {
-			magic_ptr++;
-			continue;
+	if (error_message != NULL)	{
+		purple_debug_error("yahoo", "Login Failed, unable to retrieve stage 2 url: %s\n", error_message);
+		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_message);
+		g_free(auth_data->seed);
+		g_free(auth_data);	
+		return;
+	}
+	else if (len > 0 && ret_data && *ret_data) {
+		split_data = g_strsplit(ret_data, "\r\n", -1);
+		totalelements = g_strv_length(split_data);
+		if(totalelements >= 5)	{
+			response_no = strtol(*(split_data+1), NULL, 10);
+			crumb = g_strdup(*(split_data+2)+6);
+			yd->cookie_y = g_strdup(*(split_data+3)+2);
+			yd->cookie_t = g_strdup(*(split_data+4)+2);
 		}
+		else
+			response_no = -1;
 
-		/* Characters and digits verify against the challenge lookup. */
+		g_strfreev(split_data);
 
-		if (isalpha(*magic_ptr) || isdigit(*magic_ptr)) {
-			loc = strchr(challenge_lookup, *magic_ptr);
-			if (!loc) {
-			  /* SME XXX Error - disconnect here */
+		if(response_no != 0)	{
+			/* Some error in the login process */
+			PurpleConnectionError error;
+			switch(response_no)	{
+				case -1:
+					/* Some error in the received stream */
+					error_reason = g_strdup(_("Error in the received data"));
+					error = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
+					break;
+				case 100:
+					/* Unknown error */
+					error_reason = g_strdup(_("Unknown error"));
+					error = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
+					break;
+				default:
+					/* if we have everything we need, why not try to login irrespective of response */
+					if((crumb != NULL) && (yd->cookie_y != NULL) && (yd->cookie_t != NULL))	{
+						try_login_on_error = TRUE;
+						break;
+					}
+					error_reason = g_strdup(_("Unknown error"));
+					error = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
+					break;
 			}
-
-			/* Get offset into lookup table and shl 3. */
-
-			magic_work = loc - challenge_lookup;
-			magic_work <<= 3;
-
-			magic_ptr++;
-			continue;
-		} else {
-			unsigned int	local_store;
-
-			loc = strchr(operand_lookup, *magic_ptr);
-			if (!loc) {
-				/* SME XXX Disconnect */
+			if(error_reason)	{
+				purple_debug_error("yahoo","Authentication error: %s", error_reason);
+				purple_connection_error_reason(gc, error, error_reason);
+				g_free(error_reason);
 			}
-
-			local_store = loc - operand_lookup;
-
-			/* Oops; how did this happen? */
-
-			if (magic_cnt >= 64)
-				break;
-
-			magic[magic_cnt++] = magic_work | local_store;
-			magic_ptr++;
-			continue;
 		}
-			}
-
-	magic_len = magic_cnt;
-	magic_cnt = 0;
-
-	/* Magic: Phase 2.  Take generated magic value and sprinkle fairy
-	 * dust on the values.
-	 */
-
-	for (magic_cnt = magic_len - 2; magic_cnt >= 0; magic_cnt--) {
-		unsigned char	byte1;
-		unsigned char	byte2;
-
-		/* Bad.  Abort. */
-
-		if ((magic_cnt + 1 > magic_len) || (magic_cnt > magic_len))
-			break;
-
-		byte1 = magic[magic_cnt];
-		byte2 = magic[magic_cnt+1];
-
-		byte1 *= 0xcd;
-		byte1 ^= byte2;
-
-		magic[magic_cnt+1] = byte1;
-	}
-
-	/*
-	 * Magic: Phase 3.  This computes 20 bytes.  The first 4 bytes are used as our magic
-	 * key (and may be changed later); the next 16 bytes are an MD5 sum of the magic key
-	 * plus 3 bytes.  The 3 bytes are found by looping, and they represent the offsets
-	 * into particular functions we'll later call to potentially alter the magic key.
-	 *
-	 * %-)
-	 */
-
-	magic_cnt = 1;
-	x = 0;
-
-	do {
-		unsigned int bl = 0;
-		unsigned int cl = magic[magic_cnt++];
-
-		if (magic_cnt >= magic_len)
-			break;
-
-		if (cl > 0x7F) {
-			if (cl < 0xe0)
-				bl = cl = (cl & 0x1f) << 6;
-			else {
-				bl = magic[magic_cnt++];
-				cl = (cl & 0x0f) << 6;
-				bl = ((bl & 0x3f) + cl) << 6;
-			}
-
-			cl = magic[magic_cnt++];
-			bl = (cl & 0x3f) + bl;
-		} else
-			bl = cl;
-
-		comparison_src[x++] = (bl & 0xff00) >> 8;
-		comparison_src[x++] = bl & 0xff;
-	} while (x < 20);
-
-	/* First four bytes are magic key. */
-	memcpy(&magic_key_char[0], comparison_src, 4);
-	magic_4 = magic_key_char[0] | (magic_key_char[1] << 8) |
-			(magic_key_char[2] << 16) | (magic_key_char[3] << 24);
-
-	/*
-	 * Magic: Phase 4.  Determine what function to use later by getting outside/inside
-	 * loop values until we match our previous buffer.
-	 */
-	for (x = 0; x < 65535; x++) {
-		int leave = 0;
-
-		for (y = 0; y < 5; y++) {
-			unsigned char test[3];
-
-			/* Calculate buffer. */
-			test[0] = x;
-			test[1] = x >> 8;
-			test[2] = y;
-
-			purple_cipher_context_reset(md5_ctx, NULL);
-			purple_cipher_context_append(md5_ctx, magic_key_char, 4);
-			purple_cipher_context_append(md5_ctx, test, 3);
-			purple_cipher_context_digest(md5_ctx, sizeof(md5_digest),
-									   md5_digest, NULL);
-
-			if (!memcmp(md5_digest, comparison_src+4, 16)) {
-				leave = 1;
-				break;
-			}
+		if((response_no == 0) || try_login_on_error)	{
+			crypt = g_strconcat(crumb, auth_data->seed, NULL);
+			yahoo_auth16_stage3(gc, crypt);
+			g_free(crumb);
 		}
-
-		if (leave == 1)
-			break;
 	}
+	g_free(auth_data->seed);
+	g_free(auth_data);
+}
 
-	/* If y != 0, we need some help. */
-	if (y != 0) {
-		unsigned int	updated_key;
+static void yahoo_auth16_stage1_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *ret_data, size_t len, const gchar *error_message)
+{
+	struct yahoo_auth_data *auth_data = user_data;
+	PurpleConnection *gc = auth_data->gc;
+	gchar **split_data = NULL;
+	int response_no;
+	int totalelements;
+	char *error_reason = NULL;
+	PurpleUtilFetchUrlData *url_data2 = NULL;
+	char *token = NULL;
 
-		/* Update magic stuff.
-		 * Call it twice because Yahoo's encryption is super bad ass.
-		 */
-		updated_key = yahoo_auth_finalCountdown(magic_4, 0x60, y, x);
-		updated_key = yahoo_auth_finalCountdown(updated_key, 0x60, y, x);
+	purple_debug_info("yahoo","Authentication: In yahoo_auth16_stage1_cb\n");
 
-		magic_key_char[0] = updated_key & 0xff;
-		magic_key_char[1] = (updated_key >> 8) & 0xff;
-		magic_key_char[2] = (updated_key >> 16) & 0xff;
-		magic_key_char[3] = (updated_key >> 24) & 0xff;
-	}
+	g_return_if_fail(PURPLE_CONNECTION_IS_VALID(gc));
 
-	enc_pass = yahoo_string_encode(gc, pass, NULL);
-
-	/* Get password and crypt hashes as per usual. */
-	purple_cipher_context_reset(md5_ctx, NULL);
-	purple_cipher_context_append(md5_ctx, (const guchar *)enc_pass, strlen(enc_pass));
-	purple_cipher_context_digest(md5_ctx, sizeof(md5_digest),
-							   md5_digest, NULL);
-	to_y64(password_hash, md5_digest, 16);
-
-	crypt_result = yahoo_crypt(enc_pass, "$1$_2S43d5f$");
-
-	g_free(enc_pass);
-	enc_pass = NULL;
-
-	purple_cipher_context_reset(md5_ctx, NULL);
-	purple_cipher_context_append(md5_ctx, (const guchar *)crypt_result, strlen(crypt_result));
-	purple_cipher_context_digest(md5_ctx, sizeof(md5_digest),
-							   md5_digest, NULL);
-	to_y64(crypt_hash, md5_digest, 16);
-
-	/* Our first authentication response is based off of the password hash. */
-	for (x = 0; x < (int)strlen(password_hash); x++)
-		pass_hash_xor1[cnt++] = password_hash[x] ^ 0x36;
-
-	if (cnt < 64)
-		memset(&(pass_hash_xor1[cnt]), 0x36, 64-cnt);
-
-	cnt = 0;
-
-	for (x = 0; x < (int)strlen(password_hash); x++)
-		pass_hash_xor2[cnt++] = password_hash[x] ^ 0x5c;
-
-	if (cnt < 64)
-		memset(&(pass_hash_xor2[cnt]), 0x5c, 64-cnt);
-
-	/*
-	 * The first context gets the password hash XORed with 0x36 plus a magic value
-	 * which we previously extrapolated from our challenge.
-	 */
-
-	purple_cipher_context_append(sha1_ctx1, pass_hash_xor1, 64);
-	if (y >= 3)
-		purple_cipher_context_set_option(sha1_ctx1, "sizeLo", GINT_TO_POINTER(0x1ff));
-	purple_cipher_context_append(sha1_ctx1, magic_key_char, 4);
-	purple_cipher_context_digest(sha1_ctx1, sizeof(digest1), digest1, NULL);
-
-	/*
-	 * The second context gets the password hash XORed with 0x5c plus the SHA-1 digest
-	 * of the first context.
-	 */
-
-	purple_cipher_context_append(sha1_ctx2, pass_hash_xor2, 64);
-	purple_cipher_context_append(sha1_ctx2, digest1, 20);
-	purple_cipher_context_digest(sha1_ctx2, sizeof(digest2), digest2, NULL);
-
-	/*
-	 * Now that we have digest2, use it to fetch characters from an alphabet to construct
-	 * our first authentication response.
-	 */
-
-	for (x = 0; x < 20; x += 2) {
-		unsigned int	val = 0;
-		unsigned int	lookup = 0;
-
-		char			byte[6];
-
-		memset(&byte, 0, 6);
-
-		/* First two bytes of digest stuffed together. */
-
-		val = digest2[x];
-		val <<= 8;
-		val += digest2[x+1];
-
-		lookup = (val >> 0x0b);
-		lookup &= 0x1f;
-		if (lookup >= strlen(alphabet1))
-			break;
-		sprintf(byte, "%c", alphabet1[lookup]);
-		strcat(resp_6, byte);
-		strcat(resp_6, "=");
-
-		lookup = (val >> 0x06);
-		lookup &= 0x1f;
-		if (lookup >= strlen(alphabet2))
-			break;
-		sprintf(byte, "%c", alphabet2[lookup]);
-		strcat(resp_6, byte);
-
-		lookup = (val >> 0x01);
-		lookup &= 0x1f;
-		if (lookup >= strlen(alphabet2))
-			break;
-		sprintf(byte, "%c", alphabet2[lookup]);
-		strcat(resp_6, byte);
-
-		lookup = (val & 0x01);
-		if (lookup >= strlen(delimit_lookup))
-			break;
-		sprintf(byte, "%c", delimit_lookup[lookup]);
-		strcat(resp_6, byte);
+	if (error_message != NULL)	{
+		purple_debug_error("yahoo", "Login Failed, unable to retrieve login url: %s\n", error_message);
+		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_message);
+		g_free(auth_data->seed);
+		g_free(auth_data);
+		return;
 	}
+	else if (len > 0 && ret_data && *ret_data) {
+		split_data = g_strsplit(ret_data, "\r\n", -1);
+		totalelements = g_strv_length(split_data);
+		
+		if(totalelements >= 5)	{
+			response_no = strtol(*(split_data+1), NULL, 10);
+			token = g_strdup(*(split_data+2)+6);
+		}
+		else
+			response_no = -1;
 
-	/* Our second authentication response is based off of the crypto hash. */
+		g_strfreev(split_data);
 
-	cnt = 0;
-	memset(&digest1, 0, 20);
-	memset(&digest2, 0, 20);
-
-	for (x = 0; x < (int)strlen(crypt_hash); x++)
-		crypt_hash_xor1[cnt++] = crypt_hash[x] ^ 0x36;
-
-	if (cnt < 64)
-		memset(&(crypt_hash_xor1[cnt]), 0x36, 64-cnt);
-
-	cnt = 0;
-
-	for (x = 0; x < (int)strlen(crypt_hash); x++)
-		crypt_hash_xor2[cnt++] = crypt_hash[x] ^ 0x5c;
-
-	if (cnt < 64)
-		memset(&(crypt_hash_xor2[cnt]), 0x5c, 64-cnt);
-
-	purple_cipher_context_reset(sha1_ctx1, NULL);
-	purple_cipher_context_reset(sha1_ctx2, NULL);
-
-	/*
-	 * The first context gets the password hash XORed with 0x36 plus a magic value
-	 * which we previously extrapolated from our challenge.
-	 */
-
-	purple_cipher_context_append(sha1_ctx1, crypt_hash_xor1, 64);
-	if (y >= 3) {
-		purple_cipher_context_set_option(sha1_ctx1, "sizeLo",
-									   GINT_TO_POINTER(0x1ff));
+		if(response_no != 0)	{
+			/* Some error in the login process */
+			PurpleConnectionError error;
+			switch(response_no)	{
+				case -1:
+					/* Some error in the received stream */
+					error_reason = g_strdup(_("Error in the received data"));
+					error = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
+					break;
+				case 1212:
+					/* Password incorrect */
+					error_reason = g_strdup(_("Incorrect Password"));
+					error = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
+					break;
+				case 1213:
+					/* security lock from too many failed login attempts */
+					error_reason = g_strdup(_("Login locked: Too many failed login attempts"));
+					error = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
+					break;
+				case 1235:
+					/* the username does not exist */
+					error_reason = g_strdup(_("Username does not exist"));
+					error = PURPLE_CONNECTION_ERROR_INVALID_USERNAME;
+					break;
+				case 1236:
+					/* indicates a lock of some description */
+					error_reason = g_strdup(_("Login locked: See the debug log"));
+					error = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
+					break;
+				case 100:
+					/* username or password missing */
+					error_reason = g_strdup(_("Username or password missing"));
+					error = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
+					break;
+				default:
+					/* Unknown error! */
+					error_reason = g_strdup(_("Unkown error"));
+					error = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
+					break;
+			}
+			purple_debug_error("yahoo","Authentication error: %s", error_reason);
+			purple_connection_error_reason(gc, error, error_reason);
+			g_free(error_reason);
+			g_free(auth_data->seed);
+			g_free(auth_data);
+		}
+		else	{
+			/* OK to login, correct information provided */
+			char *url = g_strdup_printf("https://login.yahoo.com/config/pwtoken_login?src=ymsgr&ts=&token=%s",token);
+			url_data2 = purple_util_fetch_url_request(url, TRUE, "Mozilla/4.0 (compatible; MSIE 5.5)", TRUE, NULL, FALSE, yahoo_auth16_stage2, auth_data);
+			g_free(url);
+			g_free(token);
+		}
 	}
-	purple_cipher_context_append(sha1_ctx1, magic_key_char, 4);
-	purple_cipher_context_digest(sha1_ctx1, sizeof(digest1), digest1, NULL);
+}
 
-	/*
-	 * The second context gets the password hash XORed with 0x5c plus the SHA-1 digest
-	 * of the first context.
-	 */
+static void yahoo_auth16_stage1(PurpleConnection *gc, const char *seed)
+{
+	PurpleUtilFetchUrlData *url_data;
+	struct yahoo_auth_data *auth_data = NULL;
+	char *url = NULL;
 
-	purple_cipher_context_append(sha1_ctx2, crypt_hash_xor2, 64);
-	purple_cipher_context_append(sha1_ctx2, digest1, 20);
-	purple_cipher_context_digest(sha1_ctx2, sizeof(digest2), digest2, NULL);
+	purple_debug_info("yahoo","Authentication: In yahoo_auth16_stage1\n");
 
-	/*
-	 * Now that we have digest2, use it to fetch characters from an alphabet to construct
-	 * our first authentication response.
-	 */
-
-	for (x = 0; x < 20; x += 2) {
-		unsigned int	val = 0;
-		unsigned int	lookup = 0;
-
-		char			byte[6];
-
-		memset(&byte, 0, 6);
-
-		/* First two bytes of digest stuffed together. */
-
-		val = digest2[x];
-		val <<= 8;
-		val += digest2[x+1];
-
-		lookup = (val >> 0x0b);
-		lookup &= 0x1f;
-		if (lookup >= strlen(alphabet1))
-			break;
-		sprintf(byte, "%c", alphabet1[lookup]);
-		strcat(resp_96, byte);
-		strcat(resp_96, "=");
-
-		lookup = (val >> 0x06);
-		lookup &= 0x1f;
-		if (lookup >= strlen(alphabet2))
-			break;
-		sprintf(byte, "%c", alphabet2[lookup]);
-		strcat(resp_96, byte);
-
-		lookup = (val >> 0x01);
-		lookup &= 0x1f;
-		if (lookup >= strlen(alphabet2))
-			break;
-		sprintf(byte, "%c", alphabet2[lookup]);
-		strcat(resp_96, byte);
-
-		lookup = (val & 0x01);
-		if (lookup >= strlen(delimit_lookup))
-			break;
-		sprintf(byte, "%c", delimit_lookup[lookup]);
-		strcat(resp_96, byte);
+	if(!purple_ssl_is_supported()) {
+		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT, _("Server requires TLS/SSL for login.  No TLS/SSL support found."));
+		return;
 	}
-	purple_debug_info("yahoo", "yahoo status: %d\n", yd->current_status);
-	pack = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP,	yd->current_status, 0);
 
-	if(yd->jp) {
-		yahoo_packet_hash(pack, "sssss",
-						  0, name,
-						  6, resp_6,
-						  96, resp_96,
-						  1, name,
-						  135, YAHOOJP_CLIENT_VERSION);
-	} else {
-		yahoo_packet_hash(pack, "ssssss",
-						  0, name,
-						  6, resp_6,
-						  96, resp_96,
-						  1, name,
-						  244, YAHOO_CLIENT_VERSION_ID,
-						  135, YAHOO_CLIENT_VERSION);
-	}
+	auth_data = g_new0(struct yahoo_auth_data, 1);
+	auth_data->gc = gc;
+	auth_data->seed = g_strdup(seed);
 
-	if (yd->picture_checksum)
-		yahoo_packet_hash_int(pack, 192, yd->picture_checksum);
+	url = g_strdup_printf("https://login.yahoo.com/config/pwtoken_get?src=ymsgr&ts=&login=%s&passwd=%s&chal=%s",purple_account_get_username(purple_connection_get_account(gc)), purple_connection_get_password(gc), seed);
 
-	yahoo_packet_send_and_free(pack, yd);
-
-	purple_cipher_context_destroy(md5_ctx);
-	purple_cipher_context_destroy(sha1_ctx1);
-	purple_cipher_context_destroy(sha1_ctx2);
-
-	g_free(password_hash);
-	g_free(crypt_hash);
+	url_data = purple_util_fetch_url_request(url, TRUE, "Mozilla/4.0 (compatible; MSIE 5.5)", TRUE, NULL, FALSE, yahoo_auth16_stage1_cb, auth_data);
+	g_free(url);
 }
 
 static void yahoo_process_auth(PurpleConnection *gc, struct yahoo_packet *pkt)
@@ -2181,11 +1829,10 @@ static void yahoo_process_auth(PurpleCon
 	if (seed) {
 		switch (m) {
 		case 0:
-			yahoo_process_auth_old(gc, seed);
-			break;
+			/* used to be for really old auth routine, dont support now */
 		case 1:
-		case 2: /* This case seems to work, could probably use testing */
-			yahoo_process_auth_new(gc, seed);
+		case 2: /* Yahoo ver 16 authentication */
+			yahoo_auth16_stage1(gc, seed);
 			break;
 		default:
 			{
@@ -2198,7 +1845,7 @@ static void yahoo_process_auth(PurpleCon
 				purple_notify_error(gc, "", _("Failed Yahoo! Authentication"),
 							buf);
 				g_free(buf);
-				yahoo_process_auth_new(gc, seed); /* Can't hurt to try it anyway. */
+				yahoo_auth16_stage1(gc, seed); /* Can't hurt to try it anyway. */
 				break;
 			}
 		}
============================================================
--- libpurple/protocols/yahoo/yahoo.h	30e914fd5a298ef8af0c992d4efe57271669e73f
+++ libpurple/protocols/yahoo/yahoo.h	b419a255b56b09e4bff8143dbe268a1338a9db75
@@ -79,8 +79,8 @@
 #define YAHOO_STATUS_TYPE_INVISIBLE "invisible"
 #define YAHOO_STATUS_TYPE_MOBILE "mobile"
 
-#define YAHOO_CLIENT_VERSION_ID "2097087"
-#define YAHOO_CLIENT_VERSION "8.1.0.421"
+#define YAHOO_CLIENT_VERSION_ID "4194239"
+#define YAHOO_CLIENT_VERSION "9.0.0.2152"
 
 #define YAHOOJP_CLIENT_VERSION_ID "524223"
 #define YAHOOJP_CLIENT_VERSION "7,0,1,1"
============================================================
--- libpurple/protocols/yahoo/yahoo_doodle.c	4a86f7fd0511ca34bc48ecc2129cc568103f79cd
+++ libpurple/protocols/yahoo/yahoo_doodle.c	bc916afb3fa84e1825080db91c564eda2fc975ad
@@ -46,7 +46,6 @@
 #include "yahoo_friend.h"
 #include "yahoochat.h"
 #include "ycht.h"
-#include "yahoo_auth.h"
 #include "yahoo_filexfer.h"
 #include "yahoo_picture.h"
 
============================================================
--- libpurple/protocols/yahoo/yahoo_packet.h	8e9c2ff523731785e8d9ad1f5d9c04fd9a920ee6
+++ libpurple/protocols/yahoo/yahoo_packet.h	dd4eaf1713d9ac88b89cee6c2ebaa8a429d05d1d
@@ -125,8 +125,8 @@ struct yahoo_packet {
 };
 
 #define YAHOO_WEBMESSENGER_PROTO_VER 0x0065
-#define YAHOO_PROTO_VER 0x000f
-#define YAHOO_PROTO_VER_JAPAN 0x000f
+#define YAHOO_PROTO_VER 0x0010
+#define YAHOO_PROTO_VER_JAPAN 0x0010
 
 #define YAHOO_PACKET_HDRLEN (4 + 2 + 2 + 2 + 2 + 4 + 4)
 


More information about the Commits mailing list