Converted these images to PNG, saving a handful of bytes per image
[adiumx.git] / Utilities / dep-build-scripts / libpurple_jabber_fallback_on_old_auth.diff
blob2634ab2e5cdbc72c7ba64319bd9a0bf04b1258f7
3 # patch "libpurple/protocols/jabber/auth.c"
4 # from [12caf62ded6c3314a811a59f8730fc801420cd8c]
5 # to [c7157e2b2625e9be09dd8b2c201b1d3dcc72fd19]
6 #
7 # patch "libpurple/protocols/jabber/jabber.c"
8 # from [eea6e7d81fa04f0cc37dae64741e2b910f56b45c]
9 # to [2330bff326c57b0af35a8e92d91ad78287655cec]
11 ============================================================
12 --- libpurple/protocols/jabber/auth.c 12caf62ded6c3314a811a59f8730fc801420cd8c
13 +++ libpurple/protocols/jabber/auth.c c7157e2b2625e9be09dd8b2c201b1d3dcc72fd19
14 @@ -330,14 +330,22 @@ static void jabber_auth_start_cyrus(Jabb
15 disallow_plaintext_auth);
16 g_free(msg);
17 return;
18 - /* Everything else has failed, so fail the
19 - * connection. Should probably have a better
20 - * error here.
21 - */
23 } else {
24 - purple_connection_error_reason (js->gc,
25 - PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE,
26 - _("Server does not use any supported authentication method"));
27 + /* We have no mechs which can work.
28 + * Try falling back on the old jabber:iq:auth method. We get here if the server supports
29 + * one or more sasl mechs, we are compiled with cyrus-sasl support, but we support or can connect with none of
30 + * the offerred mechs. jabberd 2.0 w/ SASL and Apple's iChat Server 10.5 both handle and expect
31 + * jabber:iq:auth in this situation. iChat Server in particular offers SASL GSSAPI by default, which is often
32 + * not configured on the client side, and expects a fallback to jabber:iq:auth when it (predictably) fails.
33 + *
34 + * Note: xep-0078 points out that using jabber:iq:auth after a sasl failure is wrong. However,
35 + * I believe this refers to actual authentication failure, not a simple lack of concordant mechanisms.
36 + * Doing otherwise means that simply compiling with SASL support renders the client unable to connect to servers
37 + * which would connect without issue otherwise. -evands
38 + */
39 + js->auth_type = JABBER_AUTH_IQ_AUTH;
40 + jabber_auth_start_old(js);
41 return;
43 /* not reached */
44 @@ -563,6 +570,75 @@ static void auth_old_result_cb(JabberStr
48 +/*!
49 + * @brief Given the server challenge (message) and the key (password), calculate the HMAC-MD5 digest
50 + *
51 + * This is the crammd5 response. Inspired by cyrus-sasl's _sasl_hmac_md5()
52 + */
53 +static void
54 +auth_hmac_md5(const char *challenge, size_t challenge_len, const char *key, size_t key_len, guchar *digest)
56 + PurpleCipher *cipher;
57 + PurpleCipherContext *context;
58 + int i;
59 + /* inner padding - key XORd with ipad */
60 + unsigned char k_ipad[65];
61 + /* outer padding - key XORd with opad */
62 + unsigned char k_opad[65];
64 + cipher = purple_ciphers_find_cipher("md5");
66 + /* if key is longer than 64 bytes reset it to key=MD5(key) */
67 + if (strlen(key) > 64) {
68 + guchar keydigest[16];
70 + context = purple_cipher_context_new(cipher, NULL);
71 + purple_cipher_context_append(context, (const guchar *)key, strlen(key));
72 + purple_cipher_context_digest(context, 16, keydigest, NULL);
73 + purple_cipher_context_destroy(context);
75 + key = (char *)keydigest;
76 + key_len = 16;
77 + }
79 + /*
80 + * the HMAC_MD5 transform looks like:
81 + *
82 + * MD5(K XOR opad, MD5(K XOR ipad, text))
83 + *
84 + * where K is an n byte key
85 + * ipad is the byte 0x36 repeated 64 times
86 + * opad is the byte 0x5c repeated 64 times
87 + * and text is the data being protected
88 + */
90 + /* start out by storing key in pads */
91 + memset(k_ipad, '\0', sizeof k_ipad);
92 + memset(k_opad, '\0', sizeof k_opad);
93 + memcpy(k_ipad, (void *)key, key_len);
94 + memcpy(k_opad, (void *)key, key_len);
96 + /* XOR key with ipad and opad values */
97 + for (i=0; i<64; i++) {
98 + k_ipad[i] ^= 0x36;
99 + k_opad[i] ^= 0x5c;
102 + /* perform inner MD5 */
103 + context = purple_cipher_context_new(cipher, NULL);
104 + purple_cipher_context_append(context, k_ipad, 64); /* start with inner pad */
105 + purple_cipher_context_append(context, (const guchar *)challenge, challenge_len); /* then text of datagram */
106 + purple_cipher_context_digest(context, 16, digest, NULL); /* finish up 1st pass */
107 + purple_cipher_context_destroy(context);
109 + /* perform outer MD5 */
110 + context = purple_cipher_context_new(cipher, NULL);
111 + purple_cipher_context_append(context, k_opad, 64); /* start with outer pad */
112 + purple_cipher_context_append(context, digest, 16); /* then results of 1st hash */
113 + purple_cipher_context_digest(context, 16, digest, NULL); /* finish up 2nd pass */
114 + purple_cipher_context_destroy(context);
117 static void auth_old_cb(JabberStream *js, xmlnode *packet, gpointer data)
119 JabberIq *iq;
120 @@ -608,6 +685,35 @@ static void auth_old_cb(JabberStream *js
121 jabber_iq_set_callback(iq, auth_old_result_cb, NULL);
122 jabber_iq_send(iq);
124 + } else if(js->stream_id && xmlnode_get_child(query, "crammd5")) {
125 + const char *challenge;
126 + guchar digest[16];
127 + char h[17], *p;
128 + int i;
130 + challenge = xmlnode_get_attrib(xmlnode_get_child(query, "crammd5"), "challenge");
131 + auth_hmac_md5(challenge, strlen(challenge), pw, strlen(pw), digest);
133 + /* Create the response query */
134 + iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:auth");
135 + query = xmlnode_get_child(iq->node, "query");
137 + x = xmlnode_new_child(query, "username");
138 + xmlnode_insert_data(x, js->user->node, -1);
139 + x = xmlnode_new_child(query, "resource");
140 + xmlnode_insert_data(x, js->user->resource, -1);
142 + x = xmlnode_new_child(query, "crammd5");
144 + /* Translate the digest to a hexadecimal notation */
145 + p = h;
146 + for(i=0; i<16; i++, p+=2)
147 + snprintf(p, 3, "%02x", digest[i]);
148 + xmlnode_insert_data(x, h, -1);
150 + jabber_iq_set_callback(iq, auth_old_result_cb, NULL);
151 + jabber_iq_send(iq);
153 } else if(xmlnode_get_child(query, "password")) {
154 if(js->gsc == NULL && !purple_account_get_bool(js->gc->account,
155 "auth_plain_in_clear", FALSE)) {