comparison libpurple/plugins/ssl/ssl-gnutls.c @ 29659:df9de37e0274

gnutls/nss: Don't call the handshake functions synchronously. Fixes #11525 If the handshake callbacks are called sychronously and they fail (e.g. passing GnuTLS a bad priority string or doing voodoo with NSS, see #11524 for details), the error_cb is called and the gsc destroyed, but this happens /before/ the assignment to, e.g., js->gsc happens (see jabber.c:tls_init). Thus, js->gsc is assigned a (now invalid) pointer and jabber_close tries to free it (again).
author Paul Aurich <paul@darkrain42.org>
date Thu, 01 Apr 2010 05:26:44 +0000
parents 1b8ed243d6d1
children 43af903bd816
comparison
equal deleted inserted replaced
29658:89de871ecffc 29659:df9de37e0274
34 34
35 typedef struct 35 typedef struct
36 { 36 {
37 gnutls_session session; 37 gnutls_session session;
38 guint handshake_handler; 38 guint handshake_handler;
39 guint handshake_timer;
39 } PurpleSslGnutlsData; 40 } PurpleSslGnutlsData;
40 41
41 #define PURPLE_SSL_GNUTLS_DATA(gsc) ((PurpleSslGnutlsData *)gsc->private_data) 42 #define PURPLE_SSL_GNUTLS_DATA(gsc) ((PurpleSslGnutlsData *)gsc->private_data)
42 43
43 static gnutls_certificate_client_credentials xcred = NULL; 44 static gnutls_certificate_client_credentials xcred = NULL;
365 } 366 }
366 } 367 }
367 368
368 } 369 }
369 370
371 static gboolean
372 start_handshake_cb(gpointer data)
373 {
374 PurpleSslConnection *gsc = data;
375 PurpleSslGnutlsData *gnutls_data = PURPLE_SSL_GNUTLS_DATA(gsc);
376
377 purple_debug_info("gnutls", "Starting handshake with %s\n", gsc->host);
378
379 gnutls_data->handshake_timer = 0;
380
381 ssl_gnutls_handshake_cb(gsc, gsc->fd, PURPLE_INPUT_READ);
382 return FALSE;
383 }
370 384
371 static void 385 static void
372 ssl_gnutls_connect(PurpleSslConnection *gsc) 386 ssl_gnutls_connect(PurpleSslConnection *gsc)
373 { 387 {
374 PurpleSslGnutlsData *gnutls_data; 388 PurpleSslGnutlsData *gnutls_data;
408 gnutls_transport_set_ptr(gnutls_data->session, GINT_TO_POINTER(gsc->fd)); 422 gnutls_transport_set_ptr(gnutls_data->session, GINT_TO_POINTER(gsc->fd));
409 423
410 gnutls_data->handshake_handler = purple_input_add(gsc->fd, 424 gnutls_data->handshake_handler = purple_input_add(gsc->fd,
411 PURPLE_INPUT_READ, ssl_gnutls_handshake_cb, gsc); 425 PURPLE_INPUT_READ, ssl_gnutls_handshake_cb, gsc);
412 426
413 purple_debug_info("gnutls", "Starting handshake with %s\n", gsc->host);
414
415 /* Orborde asks: Why are we configuring a callback, then 427 /* Orborde asks: Why are we configuring a callback, then
416 immediately calling it? 428 (almost) immediately calling it?
417 429
418 Answer: gnutls_handshake (up in handshake_cb) needs to be called 430 Answer: gnutls_handshake (up in handshake_cb) needs to be called
419 once in order to get the ball rolling on the SSL connection. 431 once in order to get the ball rolling on the SSL connection.
420 Once it has done so, only then will the server reply, triggering 432 Once it has done so, only then will the server reply, triggering
421 the callback. 433 the callback.
422 434
423 Since the logic driving gnutls_handshake is the same with the first 435 Since the logic driving gnutls_handshake is the same with the first
424 and subsequent calls, we'll just fire the callback immediately to 436 and subsequent calls, we'll just fire the callback immediately to
425 accomplish this. 437 accomplish this.
426 */ 438 */
427 ssl_gnutls_handshake_cb(gsc, gsc->fd, PURPLE_INPUT_READ); 439 gnutls_data->handshake_timer = purple_timeout_add(0, start_handshake_cb,
440 gsc);
428 } 441 }
429 442
430 static void 443 static void
431 ssl_gnutls_close(PurpleSslConnection *gsc) 444 ssl_gnutls_close(PurpleSslConnection *gsc)
432 { 445 {
435 if(!gnutls_data) 448 if(!gnutls_data)
436 return; 449 return;
437 450
438 if(gnutls_data->handshake_handler) 451 if(gnutls_data->handshake_handler)
439 purple_input_remove(gnutls_data->handshake_handler); 452 purple_input_remove(gnutls_data->handshake_handler);
453 if (gnutls_data->handshake_timer)
454 purple_timeout_remove(gnutls_data->handshake_timer);
440 455
441 gnutls_bye(gnutls_data->session, GNUTLS_SHUT_RDWR); 456 gnutls_bye(gnutls_data->session, GNUTLS_SHUT_RDWR);
442 457
443 gnutls_deinit(gnutls_data->session); 458 gnutls_deinit(gnutls_data->session);
444 459