📄 yahoo.c
字号:
add_req = g_new0(struct yahoo_add_request, 1); add_req->gc = gc; while (l) { struct yahoo_pair *pair = l->data; switch (pair->key) { case 1: add_req->id = g_strdup(pair->value); break; case 3: add_req->who = g_strdup(pair->value); break; case 15: /* time, for when they add us and we're offline */ break; case 14: msg = pair->value; break; } l = l->next; } if (add_req->id) { if (msg) add_req->msg = yahoo_string_decode(gc, msg, FALSE); /* DONE! this is almost exactly the same as what MSN does, * this should probably be moved to the core. */ purple_account_request_authorization(purple_connection_get_account(gc), add_req->who, add_req->id, NULL, add_req->msg, purple_find_buddy(purple_connection_get_account(gc),add_req->who) != NULL, G_CALLBACK(yahoo_buddy_add_authorize_cb), G_CALLBACK(yahoo_buddy_add_deny_reason_cb), add_req); } else { g_free(add_req->id); g_free(add_req->who); /*g_free(add_req->msg);*/ g_free(add_req); }}static void yahoo_buddy_denied_our_add(PurpleConnection *gc, struct yahoo_packet *pkt){ char *who = NULL; char *msg = NULL; GSList *l = pkt->hash; GString *buf = NULL; struct yahoo_data *yd = gc->proto_data; while (l) { struct yahoo_pair *pair = l->data; switch (pair->key) { case 3: who = pair->value; break; case 14: msg = pair->value; break; } l = l->next; } if (who) { char *msg2; buf = g_string_sized_new(0); if (!msg) { g_string_printf(buf, _("%s has (retroactively) denied your request to add them to your list."), who); } else { msg2 = yahoo_string_decode(gc, msg, FALSE); g_string_printf(buf, _("%s has (retroactively) denied your request to add them to your list for the following reason: %s."), who, msg2); g_free(msg2); } purple_notify_info(gc, NULL, _("Add buddy rejected"), buf->str); g_string_free(buf, TRUE); g_hash_table_remove(yd->friends, who); purple_prpl_got_user_status(purple_connection_get_account(gc), who, "offline", NULL); /* FIXME: make this set not on list status instead */ /* TODO: Shouldn't we remove the buddy from our local list? */ }}static void yahoo_process_contact(PurpleConnection *gc, struct yahoo_packet *pkt){ switch (pkt->status) { case 1: yahoo_process_status(gc, pkt); return; case 3: yahoo_buddy_added_us(gc, pkt); break; case 7: yahoo_buddy_denied_our_add(gc, pkt); break; default: break; }}#define OUT_CHARSET "utf-8"static char *yahoo_decode(const char *text){ char *converted = NULL; char *n, *new; const char *end, *p; int i, k; n = new = g_malloc(strlen (text) + 1); end = text + strlen(text); for (p = text; p < end; p++, n++) { if (*p == '\\') { if (p[1] >= '0' && p[1] <= '7') { p += 1; for (i = 0, k = 0; k < 3; k += 1) { char c = p[k]; if (c < '0' || c > '7') break; i *= 8; i += c - '0'; } *n = i; p += k - 1; } else { /* bug 959248 */ /* If we see a \ not followed by an octal number, * it means that it is actually a \\ with one \ * already eaten by some unknown function. * This is arguably broken. * * I think wing is wrong here, there is no function * called that I see that could have done it. I guess * it is just really sending single \'s. That's yahoo * for you. */ *n = *p; } } else *n = *p; } *n = '\0'; if (strstr(text, "\033$B")) converted = g_convert(new, n - new, OUT_CHARSET, "iso-2022-jp", NULL, NULL, NULL); if (!converted) converted = g_convert(new, n - new, OUT_CHARSET, "iso-8859-1", NULL, NULL, NULL); g_free(new); return converted;}static void yahoo_process_mail(PurpleConnection *gc, struct yahoo_packet *pkt){ PurpleAccount *account = purple_connection_get_account(gc); struct yahoo_data *yd = gc->proto_data; char *who = NULL; char *email = NULL; char *subj = NULL; char *yahoo_mail_url = (yd->jp? YAHOOJP_MAIL_URL: YAHOO_MAIL_URL); int count = 0; GSList *l = pkt->hash; if (!purple_account_get_check_mail(account)) return; while (l) { struct yahoo_pair *pair = l->data; if (pair->key == 9) count = strtol(pair->value, NULL, 10); else if (pair->key == 43) who = pair->value; else if (pair->key == 42) email = pair->value; else if (pair->key == 18) subj = pair->value; l = l->next; } if (who && subj && email && *email) { char *dec_who = yahoo_decode(who); char *dec_subj = yahoo_decode(subj); char *from = g_strdup_printf("%s (%s)", dec_who, email); purple_notify_email(gc, dec_subj, from, purple_account_get_username(account), yahoo_mail_url, NULL, NULL); g_free(dec_who); g_free(dec_subj); g_free(from); } else if (count > 0) { const char *to = purple_account_get_username(account); const char *url = yahoo_mail_url; purple_notify_emails(gc, count, FALSE, NULL, NULL, &to, &url, NULL, NULL); }}/* 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 ;) */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) */{ for (; inlen >= 3; inlen -= 3) { *out++ = base64digits[in[0] >> 2]; *out++ = base64digits[((in[0] << 4) & 0x30) | (in[1] >> 4)]; *out++ = base64digits[((in[1] << 2) & 0x3c) | (in[2] >> 6)]; *out++ = base64digits[in[2] & 0x3f]; in += 3; } if (inlen > 0) { unsigned char fragment; *out++ = base64digits[in[0] >> 2]; fragment = (in[0] << 4) & 0x30; if (inlen > 1) fragment |= in[1] >> 4; *out++ = base64digits[fragment]; *out++ = (inlen < 2) ? '-' : base64digits[(in[1] << 2) & 0x3c]; *out++ = '-'; } *out = '\0';}static void yahoo_process_auth_old(PurpleConnection *gc, const char *seed){ struct yahoo_packet *pack; 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; /* 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. */ PurpleCipher *cipher; PurpleCipherContext *context; guchar digest[16]; 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)); 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); yahoo_packet_hash(pack, "ssss", 0, name, 6, result6, 96, result96, 1, name); yahoo_packet_send_and_free(pack, yd); g_free(hash_string_p); g_free(hash_string_c);}/* 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){ 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; PurpleCipher *md5_cipher; PurpleCipherContext *md5_ctx; guchar md5_digest[16]; PurpleCipher *sha1_cipher; PurpleCipherContext *sha1_ctx1; PurpleCipherContext *sha1_ctx2; 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 != (int)NULL) { char *loc; /* Ignore parentheses. */ if (*magic_ptr == '(' || *magic_ptr == ')') { magic_ptr++; continue; } /* Characters and digits verify against the challenge lookup. */ if (isalpha(*magic_ptr) || isdigit(*magic_ptr)) { loc = strchr(challenge_lookup, *magic_ptr); if (!loc) { /* SME XXX Error - disconnect here */ } /* 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 */ } 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -