Mercurial > pidgin
annotate src/protocols/jabber/auth.c @ 10684:72a5babfa8b4
[gaim-migrate @ 12231]
the cipher api that grim has been working on for ages is finally done!! big
congrats and thanks to him!!
lots of modified files in this commit. it builds here.
moved the md5 files to src/protocols/oscar so that it continues to depend
on nothing in gaim. everything else uses the new centralized cipher api.
I'm not sure if src/md5.* needs to be removed or not, so I left it there.
someone let me know or do it directly.
someone check if these need to be added to potfiles.in
and let there be much rejoicing!
committer: Tailor Script <tailor@pidgin.im>
author | Luke Schierer <lschiere@pidgin.im> |
---|---|
date | Fri, 11 Mar 2005 13:05:31 +0000 |
parents | dc33b3b475c2 |
children | b256ce6b85b8 |
rev | line source |
---|---|
7014 | 1 /* |
2 * gaim - Jabber Protocol Plugin | |
3 * | |
4 * Copyright (C) 2003, Nathan Walp <faceprint@faceprint.com> | |
5 * | |
6 * This program is free software; you can redistribute it and/or modify | |
7 * it under the terms of the GNU General Public License as published by | |
8 * the Free Software Foundation; either version 2 of the License, or | |
9 * (at your option) any later version. | |
10 * | |
11 * This program is distributed in the hope that it will be useful, | |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 * GNU General Public License for more details. | |
15 * | |
16 * You should have received a copy of the GNU General Public License | |
17 * along with this program; if not, write to the Free Software | |
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 * | |
20 */ | |
21 #include "internal.h" | |
22 | |
23 #include "jutil.h" | |
24 #include "auth.h" | |
25 #include "xmlnode.h" | |
26 #include "jabber.h" | |
27 #include "iq.h" | |
28 | |
29 #include "debug.h" | |
30 #include "util.h" | |
10684
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10496
diff
changeset
|
31 #include "cipher.h" |
7014 | 32 #include "sslconn.h" |
8397 | 33 #include "request.h" |
34 | |
35 static void auth_old_result_cb(JabberStream *js, xmlnode *packet, | |
36 gpointer data); | |
7014 | 37 |
8296 | 38 gboolean |
39 jabber_process_starttls(JabberStream *js, xmlnode *packet) | |
7014 | 40 { |
41 xmlnode *starttls; | |
42 | |
7157 | 43 if((starttls = xmlnode_get_child(packet, "starttls"))) { |
7630 | 44 if(gaim_account_get_bool(js->gc->account, "use_tls", TRUE) && |
45 gaim_ssl_is_supported()) { | |
7157 | 46 jabber_send_raw(js, |
7642 | 47 "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>", -1); |
8296 | 48 return TRUE; |
7157 | 49 } else if(xmlnode_get_child(starttls, "required")) { |
10441 | 50 if(gaim_ssl_is_supported()) { |
10496 | 51 gaim_connection_error(js->gc, _("Server requires TLS/SSL for login. Select \"Use TLS if available\" in account properties")); |
10441 | 52 } else { |
53 gaim_connection_error(js->gc, _("Server requires TLS/SSL for login. No TLS/SSL support found.")); | |
54 } | |
8296 | 55 return TRUE; |
7157 | 56 } |
7014 | 57 } |
58 | |
8296 | 59 return FALSE; |
60 } | |
61 | |
8397 | 62 static void finish_plaintext_authentication(JabberStream *js) |
63 { | |
64 if(js->auth_type == JABBER_AUTH_PLAIN) { | |
65 xmlnode *auth; | |
66 GString *response; | |
10441 | 67 unsigned char *enc_out; |
8397 | 68 |
69 auth = xmlnode_new("auth"); | |
70 xmlnode_set_attrib(auth, "xmlns", "urn:ietf:params:xml:ns:xmpp-sasl"); | |
71 | |
72 response = g_string_new(""); | |
73 response = g_string_append_len(response, "\0", 1); | |
74 response = g_string_append(response, js->user->node); | |
75 response = g_string_append_len(response, "\0", 1); | |
76 response = g_string_append(response, | |
77 gaim_account_get_password(js->gc->account)); | |
78 | |
79 enc_out = gaim_base64_encode(response->str, response->len); | |
80 | |
81 xmlnode_set_attrib(auth, "mechanism", "PLAIN"); | |
82 xmlnode_insert_data(auth, enc_out, -1); | |
83 g_free(enc_out); | |
84 g_string_free(response, TRUE); | |
85 | |
86 jabber_send(js, auth); | |
87 xmlnode_free(auth); | |
88 } else if(js->auth_type == JABBER_AUTH_IQ_AUTH) { | |
89 JabberIq *iq; | |
90 xmlnode *query, *x; | |
91 | |
92 iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:auth"); | |
93 query = xmlnode_get_child(iq->node, "query"); | |
94 x = xmlnode_new_child(query, "username"); | |
95 xmlnode_insert_data(x, js->user->node, -1); | |
96 x = xmlnode_new_child(query, "resource"); | |
97 xmlnode_insert_data(x, js->user->resource, -1); | |
98 x = xmlnode_new_child(query, "password"); | |
99 xmlnode_insert_data(x, gaim_account_get_password(js->gc->account), -1); | |
100 jabber_iq_set_callback(iq, auth_old_result_cb, NULL); | |
101 jabber_iq_send(iq); | |
102 } | |
103 } | |
104 | |
105 static void allow_plaintext_auth(GaimAccount *account) | |
106 { | |
107 gaim_account_set_bool(account, "auth_plain_in_clear", TRUE); | |
108 | |
109 finish_plaintext_authentication(account->gc->proto_data); | |
110 } | |
111 | |
112 static void disallow_plaintext_auth(GaimAccount *account) | |
113 { | |
114 gaim_connection_error(account->gc, _("Server requires plaintext authentication over an unencrypted stream")); | |
115 } | |
116 | |
8296 | 117 void |
118 jabber_auth_start(JabberStream *js, xmlnode *packet) | |
119 { | |
120 xmlnode *mechs, *mechnode; | |
121 | |
122 gboolean digest_md5 = FALSE, plain=FALSE; | |
123 | |
124 | |
8016 | 125 if(js->registration) { |
126 jabber_register_start(js); | |
127 return; | |
128 } | |
129 | |
7014 | 130 mechs = xmlnode_get_child(packet, "mechanisms"); |
131 | |
132 if(!mechs) { | |
7981 | 133 gaim_connection_error(js->gc, _("Invalid response from server.")); |
7014 | 134 return; |
135 } | |
136 | |
8135 | 137 for(mechnode = xmlnode_get_child(mechs, "mechanism"); mechnode; |
138 mechnode = xmlnode_get_next_twin(mechnode)) | |
7014 | 139 { |
8135 | 140 char *mech_name = xmlnode_get_data(mechnode); |
141 if(mech_name && !strcmp(mech_name, "DIGEST-MD5")) | |
142 digest_md5 = TRUE; | |
143 else if(mech_name && !strcmp(mech_name, "PLAIN")) | |
144 plain = TRUE; | |
145 g_free(mech_name); | |
7014 | 146 } |
147 | |
7703 | 148 |
7645 | 149 if(digest_md5) { |
8397 | 150 xmlnode *auth; |
151 | |
152 js->auth_type = JABBER_AUTH_DIGEST_MD5; | |
153 auth = xmlnode_new("auth"); | |
154 xmlnode_set_attrib(auth, "xmlns", "urn:ietf:params:xml:ns:xmpp-sasl"); | |
7291 | 155 xmlnode_set_attrib(auth, "mechanism", "DIGEST-MD5"); |
8397 | 156 |
157 jabber_send(js, auth); | |
158 xmlnode_free(auth); | |
8086 | 159 } else if(plain) { |
8397 | 160 js->auth_type = JABBER_AUTH_PLAIN; |
7703 | 161 |
8086 | 162 if(js->gsc == NULL && !gaim_account_get_bool(js->gc->account, "auth_plain_in_clear", FALSE)) { |
8397 | 163 gaim_request_yes_no(js->gc, _("Plaintext Authentication"), |
164 _("Plaintext Authentication"), | |
165 _("This server requires plaintext authentication over an unencrypted connection. Allow this and continue authentication?"), | |
166 2, js->gc->account, allow_plaintext_auth, | |
167 disallow_plaintext_auth); | |
8086 | 168 return; |
169 } | |
8397 | 170 finish_plaintext_authentication(js); |
7014 | 171 } else { |
172 gaim_connection_error(js->gc, | |
173 _("Server does not use any supported authentication method")); | |
174 } | |
175 } | |
176 | |
7395 | 177 static void auth_old_result_cb(JabberStream *js, xmlnode *packet, gpointer data) |
7014 | 178 { |
179 const char *type = xmlnode_get_attrib(packet, "type"); | |
180 | |
7730 | 181 if(type && !strcmp(type, "result")) { |
182 jabber_stream_set_state(js, JABBER_STREAM_CONNECTED); | |
183 } else { | |
8401 | 184 char *msg = jabber_parse_error(js, packet); |
185 xmlnode *error; | |
186 const char *err_code; | |
7014 | 187 |
8401 | 188 if((error = xmlnode_get_child(packet, "error")) && |
189 (err_code = xmlnode_get_attrib(error, "code")) && | |
190 !strcmp(err_code, "401")) { | |
191 js->gc->wants_to_die = TRUE; | |
7730 | 192 } |
7014 | 193 |
8401 | 194 gaim_connection_error(js->gc, msg); |
195 g_free(msg); | |
7014 | 196 } |
197 } | |
198 | |
7395 | 199 static void auth_old_cb(JabberStream *js, xmlnode *packet, gpointer data) |
7014 | 200 { |
201 JabberIq *iq; | |
202 xmlnode *query, *x; | |
7514 | 203 const char *type = xmlnode_get_attrib(packet, "type"); |
7014 | 204 const char *pw = gaim_account_get_password(js->gc->account); |
205 | |
7514 | 206 if(!type) { |
7981 | 207 gaim_connection_error(js->gc, _("Invalid response from server.")); |
7014 | 208 return; |
7515 | 209 } else if(!strcmp(type, "error")) { |
8401 | 210 char *msg = jabber_parse_error(js, packet); |
211 gaim_connection_error(js->gc, msg); | |
212 g_free(msg); | |
7515 | 213 } else if(!strcmp(type, "result")) { |
7514 | 214 query = xmlnode_get_child(packet, "query"); |
215 if(js->stream_id && xmlnode_get_child(query, "digest")) { | |
216 unsigned char hashval[20]; | |
217 char *s, h[41], *p; | |
218 int i; | |
7014 | 219 |
8397 | 220 iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:auth"); |
221 query = xmlnode_get_child(iq->node, "query"); | |
222 x = xmlnode_new_child(query, "username"); | |
223 xmlnode_insert_data(x, js->user->node, -1); | |
224 x = xmlnode_new_child(query, "resource"); | |
225 xmlnode_insert_data(x, js->user->resource, -1); | |
226 | |
7514 | 227 x = xmlnode_new_child(query, "digest"); |
228 s = g_strdup_printf("%s%s", js->stream_id, pw); | |
10684
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10496
diff
changeset
|
229 |
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10496
diff
changeset
|
230 gaim_cipher_digest_region("sha1", (guint8 *)s, strlen(s), |
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10496
diff
changeset
|
231 hashval, NULL); |
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10496
diff
changeset
|
232 |
7514 | 233 p = h; |
234 for(i=0; i<20; i++, p+=2) | |
235 snprintf(p, 3, "%02x", hashval[i]); | |
236 xmlnode_insert_data(x, h, -1); | |
237 g_free(s); | |
8397 | 238 jabber_iq_set_callback(iq, auth_old_result_cb, NULL); |
239 jabber_iq_send(iq); | |
240 | |
241 } else if(xmlnode_get_child(query, "password")) { | |
242 if(js->gsc == NULL && !gaim_account_get_bool(js->gc->account, | |
243 "auth_plain_in_clear", FALSE)) { | |
244 gaim_request_yes_no(js->gc, _("Plaintext Authentication"), | |
245 _("Plaintext Authentication"), | |
246 _("This server requires plaintext authentication over an unencrypted connection. Allow this and continue authentication?"), | |
247 2, js->gc->account, allow_plaintext_auth, | |
248 disallow_plaintext_auth); | |
249 return; | |
250 } | |
251 finish_plaintext_authentication(js); | |
7514 | 252 } else { |
8397 | 253 gaim_connection_error(js->gc, |
254 _("Server does not use any supported authentication method")); | |
255 return; | |
7514 | 256 } |
7014 | 257 } |
258 } | |
259 | |
260 void jabber_auth_start_old(JabberStream *js) | |
261 { | |
262 JabberIq *iq; | |
263 xmlnode *query, *username; | |
264 | |
265 iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:auth"); | |
266 | |
267 query = xmlnode_get_child(iq->node, "query"); | |
268 username = xmlnode_new_child(query, "username"); | |
269 xmlnode_insert_data(username, js->user->node, -1); | |
270 | |
7395 | 271 jabber_iq_set_callback(iq, auth_old_cb, NULL); |
7014 | 272 |
273 jabber_iq_send(iq); | |
274 } | |
275 | |
276 static GHashTable* parse_challenge(const char *challenge) | |
277 { | |
278 GHashTable *ret = g_hash_table_new_full(g_str_hash, g_str_equal, | |
279 g_free, g_free); | |
280 char **pairs; | |
281 int i; | |
282 | |
283 pairs = g_strsplit(challenge, ",", -1); | |
284 | |
285 for(i=0; pairs[i]; i++) { | |
286 char **keyval = g_strsplit(pairs[i], "=", 2); | |
287 if(keyval[0] && keyval[1]) { | |
288 if(keyval[1][0] == '"' && keyval[1][strlen(keyval[1])-1] == '"') | |
289 g_hash_table_replace(ret, g_strdup(keyval[0]), g_strndup(keyval[1]+1, strlen(keyval[1])-2)); | |
290 else | |
291 g_hash_table_replace(ret, g_strdup(keyval[0]), g_strdup(keyval[1])); | |
292 } | |
293 g_strfreev(keyval); | |
294 } | |
295 | |
296 g_strfreev(pairs); | |
297 | |
298 return ret; | |
299 } | |
300 | |
301 static unsigned char* | |
302 generate_response_value(JabberID *jid, const char *passwd, const char *nonce, | |
7267 | 303 const char *cnonce, const char *a2, const char *realm) |
7014 | 304 { |
10684
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10496
diff
changeset
|
305 GaimCipher *cipher; |
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10496
diff
changeset
|
306 GaimCipherContext *context; |
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10496
diff
changeset
|
307 guint8 result[16]; |
10136 | 308 size_t a1len; |
7014 | 309 |
10441 | 310 unsigned char *x, *a1, *ha1, *ha2, *kd, *z, *convnode, *convpasswd; |
7014 | 311 |
10136 | 312 if((convnode = g_convert(jid->node, strlen(jid->node), "iso-8859-1", "utf-8", |
313 NULL, NULL, NULL)) == NULL) { | |
314 convnode = g_strdup(jid->node); | |
315 } | |
316 if((convpasswd = g_convert(passwd, strlen(passwd), "iso-8859-1", "utf-8", | |
317 NULL, NULL, NULL)) == NULL) { | |
318 convpasswd = g_strdup(passwd); | |
319 } | |
320 | |
10684
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10496
diff
changeset
|
321 cipher = gaim_ciphers_find_cipher("md5"); |
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10496
diff
changeset
|
322 context = gaim_cipher_context_new(cipher, NULL); |
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10496
diff
changeset
|
323 |
10136 | 324 x = g_strdup_printf("%s:%s:%s", convnode, realm, convpasswd); |
10684
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10496
diff
changeset
|
325 gaim_cipher_context_append(context, x, strlen(x)); |
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10496
diff
changeset
|
326 gaim_cipher_context_digest(context, NULL, result); |
7014 | 327 |
10136 | 328 a1 = g_strdup_printf("xxxxxxxxxxxxxxxx:%s:%s", nonce, cnonce); |
329 a1len = strlen(a1); | |
330 g_memmove(a1, result, 16); | |
7014 | 331 |
10684
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10496
diff
changeset
|
332 gaim_cipher_context_reset(context, NULL); |
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10496
diff
changeset
|
333 gaim_cipher_context_append(context, a1, a1len); |
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10496
diff
changeset
|
334 gaim_cipher_context_digest(context, NULL, result); |
7014 | 335 |
7106
db6bd3e794d8
[gaim-migrate @ 7671]
Christian Hammond <chipx86@chipx86.com>
parents:
7014
diff
changeset
|
336 ha1 = gaim_base16_encode(result, 16); |
7014 | 337 |
10684
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10496
diff
changeset
|
338 gaim_cipher_context_reset(context, NULL); |
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10496
diff
changeset
|
339 gaim_cipher_context_append(context, a2, strlen(a2)); |
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10496
diff
changeset
|
340 gaim_cipher_context_digest(context, NULL, result); |
7014 | 341 |
7106
db6bd3e794d8
[gaim-migrate @ 7671]
Christian Hammond <chipx86@chipx86.com>
parents:
7014
diff
changeset
|
342 ha2 = gaim_base16_encode(result, 16); |
7014 | 343 |
344 kd = g_strdup_printf("%s:%s:00000001:%s:auth:%s", ha1, nonce, cnonce, ha2); | |
345 | |
10684
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10496
diff
changeset
|
346 gaim_cipher_context_reset(context, NULL); |
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10496
diff
changeset
|
347 gaim_cipher_context_append(context, kd, strlen(kd)); |
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10496
diff
changeset
|
348 gaim_cipher_context_digest(context, NULL, result); |
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10496
diff
changeset
|
349 gaim_cipher_context_destroy(context); |
7014 | 350 |
7106
db6bd3e794d8
[gaim-migrate @ 7671]
Christian Hammond <chipx86@chipx86.com>
parents:
7014
diff
changeset
|
351 z = gaim_base16_encode(result, 16); |
7014 | 352 |
10136 | 353 g_free(convnode); |
354 g_free(convpasswd); | |
7014 | 355 g_free(x); |
356 g_free(a1); | |
357 g_free(ha1); | |
358 g_free(ha2); | |
359 g_free(kd); | |
360 | |
361 return z; | |
362 } | |
363 | |
364 void | |
365 jabber_auth_handle_challenge(JabberStream *js, xmlnode *packet) | |
366 { | |
367 | |
7703 | 368 if(js->auth_type == JABBER_AUTH_DIGEST_MD5) { |
7291 | 369 char *enc_in = xmlnode_get_data(packet); |
370 char *dec_in; | |
371 char *enc_out; | |
372 GHashTable *parts; | |
7014 | 373 |
7395 | 374 if(!enc_in) { |
7981 | 375 gaim_connection_error(js->gc, _("Invalid response from server.")); |
7395 | 376 return; |
377 } | |
378 | |
7291 | 379 gaim_base64_decode(enc_in, &dec_in, NULL); |
7395 | 380 gaim_debug(GAIM_DEBUG_MISC, "jabber", "decoded challenge (%d): %s\n", |
381 strlen(dec_in), dec_in); | |
7291 | 382 |
383 parts = parse_challenge(dec_in); | |
7014 | 384 |
385 | |
7291 | 386 if (g_hash_table_lookup(parts, "rspauth")) { |
387 char *rspauth = g_hash_table_lookup(parts, "rspauth"); | |
7014 | 388 |
389 | |
7291 | 390 if(rspauth && js->expected_rspauth && |
391 !strcmp(rspauth, js->expected_rspauth)) { | |
392 jabber_send_raw(js, | |
7642 | 393 "<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl' />", |
394 -1); | |
7291 | 395 } else { |
396 gaim_connection_error(js->gc, _("Invalid challenge from server")); | |
397 } | |
398 g_free(js->expected_rspauth); | |
399 } else { | |
400 /* assemble a response, and send it */ | |
401 /* see RFC 2831 */ | |
402 GString *response = g_string_new(""); | |
403 char *a2; | |
404 char *auth_resp; | |
405 char *buf; | |
406 char *cnonce; | |
407 char *realm; | |
408 char *nonce; | |
7014 | 409 |
7291 | 410 /* we're actually supposed to prompt the user for a realm if |
411 * the server doesn't send one, but that really complicates things, | |
412 * so i'm not gonna worry about it until is poses a problem to | |
413 * someone, or I get really bored */ | |
414 realm = g_hash_table_lookup(parts, "realm"); | |
415 if(!realm) | |
416 realm = js->user->domain; | |
7014 | 417 |
7291 | 418 cnonce = g_strdup_printf("%x%u%x", g_random_int(), (int)time(NULL), |
419 g_random_int()); | |
420 nonce = g_hash_table_lookup(parts, "nonce"); | |
7014 | 421 |
422 | |
7291 | 423 a2 = g_strdup_printf("AUTHENTICATE:xmpp/%s", realm); |
424 auth_resp = generate_response_value(js->user, | |
425 gaim_account_get_password(js->gc->account), nonce, cnonce, a2, realm); | |
426 g_free(a2); | |
427 | |
428 a2 = g_strdup_printf(":xmpp/%s", realm); | |
429 js->expected_rspauth = generate_response_value(js->user, | |
430 gaim_account_get_password(js->gc->account), nonce, cnonce, a2, realm); | |
431 g_free(a2); | |
432 | |
433 | |
434 g_string_append_printf(response, "username=\"%s\"", js->user->node); | |
435 g_string_append_printf(response, ",realm=\"%s\"", realm); | |
436 g_string_append_printf(response, ",nonce=\"%s\"", nonce); | |
437 g_string_append_printf(response, ",cnonce=\"%s\"", cnonce); | |
438 g_string_append_printf(response, ",nc=00000001"); | |
439 g_string_append_printf(response, ",qop=auth"); | |
440 g_string_append_printf(response, ",digest-uri=\"xmpp/%s\"", realm); | |
441 g_string_append_printf(response, ",response=%s", auth_resp); | |
442 g_string_append_printf(response, ",charset=utf-8"); | |
443 | |
444 g_free(auth_resp); | |
445 g_free(cnonce); | |
446 | |
447 enc_out = gaim_base64_encode(response->str, response->len); | |
448 | |
449 gaim_debug(GAIM_DEBUG_MISC, "jabber", "decoded response (%d): %s\n", response->len, response->str); | |
450 | |
451 buf = g_strdup_printf("<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>%s</response>", enc_out); | |
452 | |
7642 | 453 jabber_send_raw(js, buf, -1); |
7291 | 454 |
455 g_free(buf); | |
456 | |
457 g_free(enc_out); | |
458 | |
459 g_string_free(response, TRUE); | |
7014 | 460 } |
7291 | 461 |
462 g_free(enc_in); | |
463 g_free(dec_in); | |
464 g_hash_table_destroy(parts); | |
7014 | 465 } |
466 } | |
467 | |
468 void jabber_auth_handle_success(JabberStream *js, xmlnode *packet) | |
469 { | |
470 const char *ns = xmlnode_get_attrib(packet, "xmlns"); | |
471 | |
472 if(!ns || strcmp(ns, "urn:ietf:params:xml:ns:xmpp-sasl")) { | |
7981 | 473 gaim_connection_error(js->gc, _("Invalid response from server.")); |
7014 | 474 return; |
475 } | |
476 | |
477 jabber_stream_set_state(js, JABBER_STREAM_REINITIALIZING); | |
478 } | |
479 | |
480 void jabber_auth_handle_failure(JabberStream *js, xmlnode *packet) | |
481 { | |
8401 | 482 char *msg = jabber_parse_error(js, packet); |
7014 | 483 |
8401 | 484 if(!msg) { |
7981 | 485 gaim_connection_error(js->gc, _("Invalid response from server.")); |
8401 | 486 } else { |
487 gaim_connection_error(js->gc, msg); | |
488 g_free(msg); | |
7014 | 489 } |
490 } |