static void _purple_socket_connected_tls(gpointer _ps, PurpleSslConnection *tls_connection, PurpleInputCondition cond) { PurpleSocket *ps = _ps; if (!purple_socket_check_state(ps, PURPLE_SOCKET_STATE_CONNECTING)) { purple_ssl_close(tls_connection); ps->tls_connection = NULL; ps->cb(ps, _("Invalid socket state"), ps->cb_data); return; } if (ps->tls_connection->fd <= 0) { ps->state = PURPLE_SOCKET_STATE_ERROR; purple_ssl_close(tls_connection); ps->tls_connection = NULL; ps->cb(ps, _("Invalid file descriptor"), ps->cb_data); return; } ps->state = PURPLE_SOCKET_STATE_CONNECTED; ps->fd = ps->tls_connection->fd; ps->cb(ps, NULL, ps->cb_data); }
/* * ssl_openssl_connect * * given a socket, put an openssl connection around it. */ static void ssl_openssl_connect(PurpleSslConnection *gsc) { PurpleSslOpensslData *openssl_data; /* * allocate some memory to store variables for the openssl connection. * the memory comes zero'd from g_new0 so we don't need to null the * pointers held in this struct. */ openssl_data = g_new0(PurpleSslOpensslData, 1); gsc->private_data = openssl_data; /* * allocate a new SSL_CTX object */ openssl_data->ssl_ctx = SSL_CTX_new(SSLv23_client_method()); if (openssl_data->ssl_ctx == NULL) { purple_debug_error("openssl", "SSL_CTX_new failed\n"); if (gsc->error_cb != NULL) gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); purple_ssl_close(gsc); return; } /* * allocate a new SSL object */ openssl_data->ssl = SSL_new(openssl_data->ssl_ctx); if (openssl_data->ssl == NULL) { purple_debug_error("openssl", "SSL_new failed\n"); if (gsc->error_cb != NULL) gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); purple_ssl_close(gsc); return; } /* * now we associate the file descriptor we have with the SSL connection */ if (SSL_set_fd(openssl_data->ssl, gsc->fd) == 0) { purple_debug_error("openssl", "SSL_set_fd failed\n"); if (gsc->error_cb != NULL) gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); purple_ssl_close(gsc); return; } openssl_data->handshake_handler = purple_input_add(gsc->fd, PURPLE_INPUT_READ, ssl_openssl_handshake_cb, gsc); ssl_openssl_handshake_cb(gsc, gsc->fd, PURPLE_INPUT_READ); }
/** * Close (but not free) a connection. * * This cancels any currently pending connection attempt, * closes any open fd and frees the auth cookie. * * @param conn The connection to close. */ void flap_connection_close(OscarData *od, FlapConnection *conn) { if (conn->connect_data != NULL) { purple_proxy_connect_cancel(conn->connect_data); conn->connect_data = NULL; } if (conn->gsc != NULL && conn->gsc->connect_data != NULL) { purple_ssl_close(conn->gsc); conn->gsc = NULL; } if (conn->new_conn_data != NULL) { if (conn->type == SNAC_FAMILY_CHAT) { oscar_chat_destroy(conn->new_conn_data); conn->new_conn_data = NULL; } } if ((conn->fd >= 0 || conn->gsc != NULL) && conn->type == SNAC_FAMILY_LOCATE) flap_connection_send_close(od, conn); if (conn->watcher_incoming != 0) { purple_input_remove(conn->watcher_incoming); conn->watcher_incoming = 0; } if (conn->watcher_outgoing != 0) { purple_input_remove(conn->watcher_outgoing); conn->watcher_outgoing = 0; } if (conn->fd >= 0) { close(conn->fd); conn->fd = -1; } if (conn->gsc != NULL) { purple_ssl_close(conn->gsc); conn->gsc = NULL; } g_free(conn->buffer_incoming.data.data); conn->buffer_incoming.data.data = NULL; purple_circ_buffer_destroy(conn->buffer_outgoing); conn->buffer_outgoing = NULL; }
static void irc_input_cb_ssl(gpointer data, PurpleSslConnection *gsc, PurpleInputCondition cond) { PurpleConnection *gc = data; struct irc_conn *irc = gc->proto_data; int len; if(!g_list_find(purple_connections_get_all(), gc)) { purple_ssl_close(gsc); return; } if (irc->inbuflen < irc->inbufused + IRC_INITIAL_BUFSIZE) { irc->inbuflen += IRC_INITIAL_BUFSIZE; irc->inbuf = g_realloc(irc->inbuf, irc->inbuflen); } len = purple_ssl_read(gsc, irc->inbuf + irc->inbufused, IRC_INITIAL_BUFSIZE - 1); if (len < 0 && errno == EAGAIN) { /* Try again later */ return; } else if (len < 0) { purple_connection_error(gc, _("Read error")); return; } else if (len == 0) { purple_connection_error(gc, _("Server has disconnected")); return; } read_input(irc, len); }
void om_connection_destroy(OmegleConnection *omconn) { omconn->oma->conns = g_slist_remove(omconn->oma->conns, omconn); if (omconn->request != NULL) g_string_free(omconn->request, TRUE); g_free(omconn->rx_buf); if (omconn->connect_data != NULL) purple_proxy_connect_cancel(omconn->connect_data); if (omconn->ssl_conn != NULL) purple_ssl_close(omconn->ssl_conn); if (omconn->fd >= 0) { close(omconn->fd); } if (omconn->input_watcher > 0) purple_input_remove(omconn->input_watcher); g_free(omconn->url); g_free(omconn->hostname); g_free(omconn); }
static void msn_soap_connection_sanitize(MsnSoapConnection *conn, gboolean disconnect) { if (conn->event_handle) { purple_input_remove(conn->event_handle); conn->event_handle = 0; } if (conn->run_timer) { purple_timeout_remove(conn->run_timer); conn->run_timer = 0; } if (conn->message) { msn_soap_message_destroy(conn->message); conn->message = NULL; } if (conn->buf) { g_string_free(conn->buf, TRUE); conn->buf = NULL; } if (conn->ssl && (disconnect || conn->close_when_done)) { purple_ssl_close(conn->ssl); conn->ssl = NULL; } if (conn->current_request) { msn_soap_request_destroy(conn->current_request, FALSE); conn->current_request = NULL; } }
void steam_connection_destroy(SteamConnection *steamcon) { steamcon->sa->conns = g_slist_remove(steamcon->sa->conns, steamcon); if (steamcon->request != NULL) g_string_free(steamcon->request, TRUE); g_free(steamcon->rx_buf); if (steamcon->connect_data != NULL) purple_proxy_connect_cancel(steamcon->connect_data); if (steamcon->ssl_conn != NULL) purple_ssl_close(steamcon->ssl_conn); if (steamcon->fd >= 0) { close(steamcon->fd); } if (steamcon->input_watcher > 0) purple_input_remove(steamcon->input_watcher); g_free(steamcon->url); g_free(steamcon->hostname); g_free(steamcon); }
void sevencup_connection_close(SevenCupConnection *scon) { scon->sa->conns = g_slist_remove(scon->sa->conns, scon); if (scon->connect_data != NULL) { purple_proxy_connect_cancel(scon->connect_data); scon->connect_data = NULL; } if (scon->ssl_conn != NULL) { purple_ssl_close(scon->ssl_conn); scon->ssl_conn = NULL; } if (scon->fd >= 0) { close(scon->fd); scon->fd = -1; } if (scon->input_watcher > 0) { purple_input_remove(scon->input_watcher); scon->input_watcher = 0; } purple_timeout_remove(scon->timeout_watcher); g_free(scon->rx_buf); scon->rx_buf = NULL; scon->rx_len = 0; }
void fb_connection_destroy(FacebookConnection *fbconn) { fbconn->fba->conns = g_slist_remove(fbconn->fba->conns, fbconn); if (fbconn->request != NULL) g_string_free(fbconn->request, TRUE); g_free(fbconn->rx_buf); if (fbconn->connect_data != NULL) purple_proxy_connect_cancel(fbconn->connect_data); if (fbconn->ssl_conn != NULL) purple_ssl_close(fbconn->ssl_conn); if (fbconn->fd >= 0) { close(fbconn->fd); } if (fbconn->input_watcher > 0) purple_input_remove(fbconn->input_watcher); g_free(fbconn->hostname); g_free(fbconn); }
static void msn_soap_read_cb(gpointer data, gint fd, PurpleInputCondition cond) { MsnSoapConnection *conn = data; int count = 0, cnt, perrno; /* This buffer needs to be larger than any packets received from login.live.com or Adium will fail to receive the packet (something weird with the login.live.com server). With NSS it works fine, so I believe it's some bug with OS X */ char buf[16 * 1024]; gsize cursor; if (conn->message == NULL) { conn->message = msn_soap_message_new(NULL, NULL); } if (conn->buf == NULL) { conn->buf = g_string_new_len(buf, 0); } cursor = conn->buf->len; while ((cnt = purple_ssl_read(conn->ssl, buf, sizeof(buf))) > 0) { purple_debug_info("soap", "read %d bytes\n", cnt); count += cnt; g_string_append_len(conn->buf, buf, cnt); } perrno = errno; if (cnt < 0 && perrno != EAGAIN) purple_debug_info("soap", "read: %s\n", g_strerror(perrno)); if (conn->current_request && conn->current_request->secure && !purple_debug_is_unsafe()) purple_debug_misc("soap", "Received secure request.\n"); else if (count != 0) purple_debug_misc("soap", "current %s\n", conn->buf->str + cursor); /* && count is necessary for Adium, on OS X the last read always return an error, so we want to proceed anyway. See #5212 for discussion on this and the above buffer size issues */ if(cnt < 0 && errno == EAGAIN && count == 0) return; /* msn_soap_process could alter errno */ msn_soap_process(conn); if ((cnt < 0 && perrno != EAGAIN) || cnt == 0) { /* It's possible msn_soap_process closed the ssl connection */ if (conn->ssl) { purple_ssl_close(conn->ssl); conn->ssl = NULL; msn_soap_connection_handle_next(conn); } } }
static void http_connection_disconnected(PurpleHTTPConnection *conn) { gboolean had_requests = FALSE; /* * Well, then. Fine! I never liked you anyway, server! I was cheating on you * with AIM! */ conn->state = HTTP_CONN_OFFLINE; if (conn->psc) { purple_ssl_close(conn->psc); conn->psc = NULL; } else if (conn->fd >= 0) { close(conn->fd); conn->fd = -1; } if (conn->readh) { purple_input_remove(conn->readh); conn->readh = 0; } if (conn->writeh) { purple_input_remove(conn->writeh); conn->writeh = 0; } had_requests = (conn->requests > 0); if (had_requests && conn->read_buf->len == 0) { purple_debug_error("jabber", "bosh: Adjusting BOSHconn requests (%d) to %d\n", conn->bosh->requests, conn->bosh->requests - conn->requests); conn->bosh->requests -= conn->requests; conn->requests = 0; } if (conn->bosh->pipelining) { /* Hmmmm, fall back to multiple connections */ jabber_bosh_disable_pipelining(conn->bosh); } if (!had_requests) /* If the server disconnected us without any requests, let's * just wait until we have something to send before we reconnect */ return; if (++conn->bosh->failed_connections == MAX_FAILED_CONNECTIONS) { purple_connection_error_reason(conn->bosh->js->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Unable to establish a connection with the server")); } else { /* No! Please! Take me back. It was me, not you! I was weak! */ http_connection_connect(conn); } }
static void http_connection_disconnected(PurpleHTTPConnection *conn) { /* * Well, then. Fine! I never liked you anyway, server! I was cheating on you * with AIM! */ conn->state = HTTP_CONN_OFFLINE; if (conn->psc) { purple_ssl_close(conn->psc); conn->psc = NULL; } else if (conn->fd >= 0) { close(conn->fd); conn->fd = -1; } if (conn->readh) { purple_input_remove(conn->readh); conn->readh = 0; } if (conn->writeh) { purple_input_remove(conn->writeh); conn->writeh = 0; } if (conn->requests > 0 && conn->read_buf->len == 0) { purple_debug_error("jabber", "bosh: Adjusting BOSHconn requests (%d) to %d\n", conn->bosh->requests, conn->bosh->requests - conn->requests); conn->bosh->requests -= conn->requests; conn->requests = 0; } if (conn->bosh->pipelining) { /* Hmmmm, fall back to multiple connections */ conn->bosh->pipelining = FALSE; if (conn->bosh->connections[1] == NULL) { conn->bosh->connections[1] = jabber_bosh_http_connection_init(conn->bosh); http_connection_connect(conn->bosh->connections[1]); } } if (++conn->bosh->failed_connections == MAX_FAILED_CONNECTIONS) { purple_connection_error_reason(conn->bosh->js->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Unable to establish a connection with the server")); } else { /* No! Please! Take me back. It was me, not you! I was weak! */ http_connection_connect(conn); } }
static void irc_close(PurpleConnection *gc) { struct irc_conn *irc = gc->proto_data; if (irc == NULL) return; if (irc->gsc || (irc->fd >= 0)) irc_cmd_quit(irc, "quit", NULL, NULL); if (gc->inpa) purple_input_remove(gc->inpa); g_free(irc->inbuf); if (irc->gsc) { purple_ssl_close(irc->gsc); } else if (irc->fd >= 0) { close(irc->fd); } if (irc->timer) purple_timeout_remove(irc->timer); g_hash_table_destroy(irc->cmds); g_hash_table_destroy(irc->msgs); g_hash_table_destroy(irc->buddies); if (irc->motd) g_string_free(irc->motd, TRUE); g_free(irc->server); if (irc->writeh) purple_input_remove(irc->writeh); purple_circ_buffer_destroy(irc->outbuf); g_free(irc->mode_chars); g_free(irc->reqnick); #ifdef HAVE_CYRUS_SASL if (irc->sasl_conn) { sasl_dispose(&irc->sasl_conn); irc->sasl_conn = NULL; } g_free(irc->sasl_cb); if(irc->sasl_mechs) g_string_free(irc->sasl_mechs, TRUE); #endif g_free(irc); }
static void ssl_nss_verified_cb(PurpleCertificateVerificationStatus st, gpointer userdata) { PurpleSslConnection *gsc = (PurpleSslConnection *) userdata; if (st == PURPLE_CERTIFICATE_VALID) { /* Certificate valid? Good! Do the connection! */ gsc->connect_cb(gsc->connect_cb_data, gsc, PURPLE_INPUT_READ); } else { /* Otherwise, signal an error */ if(gsc->error_cb != NULL) gsc->error_cb(gsc, PURPLE_SSL_CERTIFICATE_INVALID, gsc->connect_cb_data); purple_ssl_close(gsc); } }
static void irc_input_cb_ssl(gpointer data, PurpleSslConnection *gsc, PurpleInputCondition cond) { PurpleConnection *gc = data; struct irc_conn *irc = gc->proto_data; int len; if(!g_list_find(purple_connections_get_all(), gc)) { purple_ssl_close(gsc); return; } do { // resize buffer upwards so we have at least IRC_BUFSIZE_INCREMENT // bytes free in inbuf if (irc->inbuflen < irc->inbufused + IRC_BUFSIZE_INCREMENT) { if (irc->inbuflen + IRC_BUFSIZE_INCREMENT <= IRC_MAX_BUFSIZE) { irc->inbuflen += IRC_BUFSIZE_INCREMENT; irc->inbuf = g_realloc(irc->inbuf, irc->inbuflen); } else { // discard unparseable data from the buffer irc->inbufused = 0; } } len = purple_ssl_read(gsc, irc->inbuf + irc->inbufused, irc->inbuflen - irc->inbufused - 1); if (len > 0) { read_input(irc, len); } } while (len > 0); if (len < 0 && errno != EAGAIN) { gchar *tmp = g_strdup_printf(_("Lost connection with server: %s"), g_strerror(errno)); purple_connection_error_reason (gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp); g_free(tmp); } else if (len == 0) { purple_connection_error_reason (gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Server closed the connection")); } /* else: len < 0 && errno == EAGAIN; this is fine, try again later */ }
/** * @param source When this function is called as a callback source is * set to the fd that triggered the callback. But this function * is also called directly from flap_connection_send_byte_stream(), * in which case source will be -1. So don't use source--use * conn->gsc or conn->fd instead. */ static void send_cb(gpointer data, gint source, PurpleInputCondition cond) { FlapConnection *conn; int writelen, ret; const gchar *output = NULL; conn = data; writelen = purple_circular_buffer_get_max_read(conn->buffer_outgoing); output = purple_circular_buffer_get_output(conn->buffer_outgoing); if (writelen == 0) { purple_input_remove(conn->watcher_outgoing); conn->watcher_outgoing = 0; return; } if (conn->gsc) ret = purple_ssl_write(conn->gsc, output, writelen); else ret = send(conn->fd, output, writelen, 0); if (ret <= 0) { if (ret < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) /* No worries */ return; /* Error! */ purple_input_remove(conn->watcher_outgoing); conn->watcher_outgoing = 0; if (conn->gsc) { purple_ssl_close(conn->gsc); conn->gsc = NULL; } else { close(conn->fd); conn->fd = -1; } flap_connection_schedule_destroy(conn, OSCAR_DISCONNECT_LOST_CONNECTION, g_strerror(errno)); return; } purple_circular_buffer_mark_read(conn->buffer_outgoing, ret); }
static void pb_close(PurpleConnection *pc) { PushBulletAccount *pba = pc->proto_data; PurpleAccount *account; account = purple_connection_get_account(pc); purple_account_set_string(account, "main_sms_device", pba->main_sms_device); g_free(pba->main_sms_device); pba->main_sms_device = NULL; purple_timeout_remove(pba->phone_threads_poll); purple_timeout_remove(pba->everything_poll); purple_ssl_close(pba->websocket); g_hash_table_destroy(pba->sent_messages_hash); pba->sent_messages_hash = NULL; g_free(pba->access_token); pba->access_token = NULL; g_free(pba); }
static void skypeweb_free_xfer(PurpleXfer *xfer) { SkypeWebFileTransfer *swft; swft = purple_xfer_get_protocol_data(xfer); g_return_if_fail(swft != NULL); if (swft->info != NULL) json_object_unref(swft->info); if (swft->conn != NULL) purple_ssl_close(swft->conn); g_free(swft->url); g_free(swft->id); g_free(swft->from); g_free(swft); purple_xfer_set_protocol_data(xfer, NULL); }
static gboolean msn_soap_write_cb_internal(gpointer data, gint fd, PurpleInputCondition cond, gboolean initial) { MsnSoapConnection *conn = data; int written; if (cond != PURPLE_INPUT_WRITE) return TRUE; written = purple_ssl_write(conn->ssl, conn->buf->str + conn->handled_len, conn->buf->len - conn->handled_len); if (written < 0 && errno == EAGAIN) return TRUE; else if (written <= 0) { purple_ssl_close(conn->ssl); conn->ssl = NULL; if (!initial) msn_soap_connection_handle_next(conn); return FALSE; } conn->handled_len += written; if (conn->handled_len < conn->buf->len) return TRUE; /* we are done! */ g_string_free(conn->buf, TRUE); conn->buf = NULL; conn->handled_len = 0; conn->body_len = 0; conn->response_code = 0; conn->headers_done = FALSE; conn->close_when_done = FALSE; purple_input_remove(conn->event_handle); conn->event_handle = purple_input_add(conn->ssl->fd, PURPLE_INPUT_READ, msn_soap_read_cb, conn); return TRUE; }
void msn_nexus_destroy(MsnNexus *nexus) { if (nexus->gsc) purple_ssl_close(nexus->gsc); g_free(nexus->login_host); g_free(nexus->login_path); if (nexus->challenge_data != NULL) g_hash_table_destroy(nexus->challenge_data); if (nexus->input_handler > 0) purple_input_remove(nexus->input_handler); g_free(nexus->write_buf); g_free(nexus->read_buf); g_free(nexus); }
static void purple_socket_cancel(PurpleSocket *ps) { if (ps->inpa > 0) purple_input_remove(ps->inpa); ps->inpa = 0; if (ps->tls_connection != NULL) { purple_ssl_close(ps->tls_connection); ps->fd = -1; } ps->tls_connection = NULL; if (ps->raw_connection != NULL) purple_proxy_connect_cancel(ps->raw_connection); ps->raw_connection = NULL; if (ps->fd > 0) close(ps->fd); ps->fd = 0; }
static void jabber_bosh_http_connection_destroy(PurpleHTTPConnection *conn) { if (conn->read_buf) g_string_free(conn->read_buf, TRUE); if (conn->write_buf) purple_circ_buffer_destroy(conn->write_buf); if (conn->readh) purple_input_remove(conn->readh); if (conn->writeh) purple_input_remove(conn->writeh); if (conn->psc) purple_ssl_close(conn->psc); if (conn->fd >= 0) close(conn->fd); purple_proxy_connect_cancel_with_handle(conn); g_free(conn); }
/* * ssl_openssl_handshake_cb */ static void ssl_openssl_handshake_cb(gpointer data, gint source, PurpleInputCondition cond) { PurpleSslConnection *gsc = (PurpleSslConnection *)data; PurpleSslOpensslData *openssl_data = PURPLE_SSL_OPENSSL_DATA(gsc); int ret, ret2; purple_debug_info("openssl", "Connecting to %s\n", gsc->host); /* * do the negotiation that sets up the SSL connection between * here and there. */ ret = SSL_connect(openssl_data->ssl); if (ret <= 0) { ret2 = SSL_get_error(openssl_data->ssl, ret); if (ret2 == SSL_ERROR_WANT_READ || ret2 == SSL_ERROR_WANT_WRITE) return; purple_debug_error("openssl", "SSL_connect failed: %d\n", ret2); if (gsc->error_cb != NULL) gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); purple_ssl_close(gsc); return; } purple_input_remove(openssl_data->handshake_handler); openssl_data->handshake_handler = 0; purple_debug_info("openssl", "Connected to %s\n", gsc->host); /* SSL connected now */ gsc->connect_cb(gsc->connect_cb_data, gsc, cond); }
static void purple_ssl_connect_cb(gpointer data, gint source, const gchar *error_message) { PurpleSslConnection *gsc; PurpleSslOps *ops; gsc = data; gsc->connect_data = NULL; if (source < 0) { if (gsc->error_cb != NULL) gsc->error_cb(gsc, PURPLE_SSL_CONNECT_FAILED, gsc->connect_cb_data); purple_ssl_close(gsc); return; } gsc->fd = source; ops = purple_ssl_get_ops(); ops->connectfunc(gsc); }
static void irc_close(PurpleConnection *gc) { struct irc_conn *irc = gc->proto_data; if (irc == NULL) return; if (irc->gsc || (irc->fd >= 0)) irc_cmd_quit(irc, "quit", NULL, NULL); if (gc->inpa) purple_input_remove(gc->inpa); g_free(irc->inbuf); if (irc->gsc) { purple_ssl_close(irc->gsc); } else if (irc->fd >= 0) { close(irc->fd); } if (irc->timer) purple_timeout_remove(irc->timer); g_hash_table_destroy(irc->cmds); g_hash_table_destroy(irc->msgs); g_hash_table_destroy(irc->buddies); if (irc->motd) g_string_free(irc->motd, TRUE); g_free(irc->server); if (irc->writeh) purple_input_remove(irc->writeh); purple_circ_buffer_destroy(irc->outbuf); g_free(irc->mode_chars); g_free(irc); }
void flist_close(PurpleConnection *pc) { FListAccount *fla = pc->proto_data; if(!fla) return; if(fla->gsc) purple_ssl_close(fla->gsc); if(fla->username) g_free(fla->username); if(fla->character) g_free(fla->character); if(fla->password) g_free(fla->password); if(fla->proper_character) g_free(fla->proper_character); if(fla->ticket_request) flist_web_request_cancel(fla->ticket_request); if(fla->ticket_timer) purple_timeout_remove(fla->ticket_timer); if(fla->fls_cookie) g_free(fla->fls_cookie); g_free(fla->rx_buf); if(fla->ping_timeout_handle) purple_timeout_remove(fla->ping_timeout_handle); g_hash_table_destroy(fla->all_characters); if(fla->global_ops) g_hash_table_destroy(fla->global_ops); /* login options */ if(fla->server_address) g_free(fla->server_address); if(fla->input_request) purple_request_close_with_handle((void*) pc); flist_friends_unload(fla); flist_fetch_icon_cancel_all(fla); flist_global_kinks_unload(pc); flist_profile_unload(pc); flist_channel_subsystem_unload(fla); g_free(fla); pc->proto_data = NULL; }
static void query_cert_result(gboolean trusted, void *userdata) { struct query_cert_userdata *ud = (struct query_cert_userdata*)userdata; PurpleSslConnection *gsc = (PurpleSslConnection *)ud->gsc; CFRelease(ud->certs); free(ud->hostname); if (PURPLE_SSL_CONNECTION_IS_VALID(gsc)) { if (!trusted) { if (gsc->error_cb != NULL) gsc->error_cb(gsc, PURPLE_SSL_CERTIFICATE_INVALID, gsc->connect_cb_data); purple_ssl_close(ud->gsc); } else { purple_debug_info("cdsa", "SSL_connect complete\n"); /* SSL connected now */ ud->gsc->connect_cb(ud->gsc->connect_cb_data, ud->gsc, ud->cond); } } free(ud); }
void fb_mqtt_close(FbMqtt *mqtt) { FbMqttPrivate *priv; g_return_if_fail(FB_IS_MQTT(mqtt)); priv = mqtt->priv; if (priv->wev > 0) { purple_input_remove(priv->wev); priv->wev = 0; } if (priv->rev > 0) { purple_input_remove(priv->rev); priv->rev = 0; } if (priv->tev > 0) { purple_timeout_remove(priv->tev); priv->tev = 0; } if (priv->gsc != NULL) { purple_ssl_close(priv->gsc); priv->gsc = NULL; } if (priv->wbuf->len > 0) { fb_util_debug_warning("Closing with unwritten data"); } priv->connected = FALSE; g_byte_array_set_size(priv->rbuf, 0); g_byte_array_set_size(priv->wbuf, 0); }
static void ssl_cdsa_create_context(gpointer data) { PurpleSslConnection *gsc = (PurpleSslConnection *)data; PurpleAccount *account = gsc->account; PurpleSslCDSAData *cdsa_data; OSStatus err; bool requireFS = purple_account_get_bool(account, "require_forward_secrecy", FALSE); /* * allocate some memory to store variables for the cdsa connection. * the memory comes zero'd from g_new0 so we don't need to null the * pointers held in this struct. */ cdsa_data = g_new0(PurpleSslCDSAData, 1); gsc->private_data = cdsa_data; connections = g_list_append(connections, gsc); /* * allocate a new SSLContextRef object */ err = SSLNewContext(false, &cdsa_data->ssl_ctx); if (err != noErr) { purple_debug_error("cdsa", "SSLNewContext failed\n"); if (gsc->error_cb != NULL) gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); purple_ssl_close(gsc); return; } /* * Set up our callbacks for reading/writing the file descriptor */ err = SSLSetIOFuncs(cdsa_data->ssl_ctx, SocketRead, SocketWrite); if (err != noErr) { purple_debug_error("cdsa", "SSLSetIOFuncs failed\n"); if (gsc->error_cb != NULL) gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); purple_ssl_close(gsc); return; } /* * Pass the connection information to the connection to be used by our callbacks */ err = SSLSetConnection(cdsa_data->ssl_ctx, (SSLConnectionRef)(intptr_t)gsc->fd); if (err != noErr) { purple_debug_error("cdsa", "SSLSetConnection failed: %d\n", err); if (gsc->error_cb != NULL) gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); purple_ssl_close(gsc); return; } size_t numCiphers = 0; err = SSLGetNumberEnabledCiphers(cdsa_data->ssl_ctx, &numCiphers); if (err != noErr) { purple_debug_error("cdsa", "SSLGetNumberEnabledCiphers failed: %d\n", err); if (gsc->error_cb != NULL) gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); purple_ssl_close(gsc); return; } SSLCipherSuite ciphers[numCiphers]; err = SSLGetEnabledCiphers(cdsa_data->ssl_ctx, ciphers, &numCiphers); if (err != noErr) { purple_debug_error("cdsa", "SSLGetSupportedCiphers failed: %d\n", err); if (gsc->error_cb != NULL) gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); purple_ssl_close(gsc); return; } SSLCipherSuite enabledCiphers[numCiphers]; size_t numEnabledCiphers = 0; int i; for (i = 0; i < numCiphers; i++) { if (ssl_cdsa_use_cipher(ciphers[i], requireFS)) { enabledCiphers[numEnabledCiphers] = ciphers[i]; numEnabledCiphers++; } } err = SSLSetEnabledCiphers(cdsa_data->ssl_ctx, enabledCiphers, numEnabledCiphers); if (err != noErr) { purple_debug_error("cdsa", "SSLSetEnabledCiphers failed: %d\n", err); if (gsc->error_cb != NULL) gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); purple_ssl_close(gsc); return; } if (purple_account_get_bool(account, PURPLE_SSL_CDSA_BUGGY_TLS_WORKAROUND, false)) { purple_debug_info("cdsa", "Explicitly disabling TLS 1.1 and above to try and work around buggy TLS stacks\n"); OSStatus protoErr; protoErr = SSLSetProtocolVersionEnabled(cdsa_data->ssl_ctx, kSSLProtocolAll, false); if (protoErr != noErr) { purple_debug_error("cdsa", "SSLSetProtocolVersionEnabled failed to disable protocols\n"); if (gsc->error_cb != NULL) gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); purple_ssl_close(gsc); return; } protoErr = SSLSetProtocolVersionEnabled(cdsa_data->ssl_ctx, kSSLProtocol3, true); protoErr = SSLSetProtocolVersionEnabled(cdsa_data->ssl_ctx, kTLSProtocol1, true); } if(gsc->host) { /* * Set the peer's domain name so CDSA can check the certificate's CN */ err = SSLSetPeerDomainName(cdsa_data->ssl_ctx, gsc->host, strlen(gsc->host)); if (err != noErr) { purple_debug_error("cdsa", "SSLSetPeerDomainName failed\n"); if (gsc->error_cb != NULL) gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); purple_ssl_close(gsc); return; } } /* * Disable verifying the certificate chain. * We have to do that manually later on! This is the only way to be able to continue with a connection, even though the user * had to manually accept the certificate. */ err = SSLSetEnableCertVerify(cdsa_data->ssl_ctx, false); if (err != noErr) { purple_debug_error("cdsa", "SSLSetEnableCertVerify failed\n"); /* error is not fatal */ } cdsa_data->handshake_handler = purple_input_add(gsc->fd, PURPLE_INPUT_READ, ssl_cdsa_handshake_cb, gsc); }
/* * ssl_cdsa_handshake_cb */ static void ssl_cdsa_handshake_cb(gpointer data, gint source, PurpleInputCondition cond) { PurpleSslConnection *gsc = (PurpleSslConnection *)data; PurpleAccount *account = gsc->account; PurpleSslCDSAData *cdsa_data = PURPLE_SSL_CDSA_DATA(gsc); OSStatus err; purple_debug_info("cdsa", "Connecting\n"); /* * do the negotiation that sets up the SSL connection between * here and there. */ err = SSLHandshake(cdsa_data->ssl_ctx); if (err == errSSLPeerBadRecordMac && !purple_account_get_bool(account, PURPLE_SSL_CDSA_BUGGY_TLS_WORKAROUND, false) && !strcmp(purple_account_get_protocol_id(account),"prpl-jabber")) { /* * Set a flag so we know to explicitly disable TLS 1.1 and 1.2 on our next (immediate) connection attempt for this account. * Some XMPP servers use buggy TLS stacks that incorrectly report their capabilities, which breaks things with 10.8's new support * for TLS 1.1 and 1.2. */ purple_debug_info("cdsa", "SSLHandshake reported that the server rejected our MAC, which most likely means it lied about the TLS versions it supports."); purple_debug_info("cdsa", "Setting a flag in this account to only use TLS 1.0 and below on the next connection attempt."); purple_account_set_bool(account, PURPLE_SSL_CDSA_BUGGY_TLS_WORKAROUND, true); if (gsc->error_cb != NULL) gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); purple_ssl_close(gsc); return; } else if (err != noErr) { if(err == errSSLWouldBlock) return; fprintf(stderr,"cdsa: SSLHandshake failed with error %d\n",(int)err); purple_debug_error("cdsa", "SSLHandshake failed with error %d\n",(int)err); if (gsc->error_cb != NULL) gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); purple_ssl_close(gsc); return; } SSLCipherSuite cipher; SSLProtocol protocol; err = SSLGetNegotiatedCipher(cdsa_data->ssl_ctx, &cipher); if (err == noErr) { err = SSLGetNegotiatedProtocolVersion(cdsa_data->ssl_ctx, &protocol); purple_debug_info("cdsa", "Your connection is using %s with %s encryption, using %s for message authentication and %s key exchange (%X).\n", SSLVersionToString(protocol), SSLCipherName(cipher), SSLMACName(cipher), SSLKeyExchangeName(cipher), cipher); } purple_input_remove(cdsa_data->handshake_handler); cdsa_data->handshake_handler = 0; purple_debug_info("cdsa", "SSL_connect: verifying certificate\n"); if(certificate_ui_cb) { // does the application want to verify the certificate? struct query_cert_userdata *userdata = (struct query_cert_userdata*)malloc(sizeof(struct query_cert_userdata)); size_t hostnamelen = 0; SSLGetPeerDomainNameLength(cdsa_data->ssl_ctx, &hostnamelen); userdata->hostname = (char*)malloc(hostnamelen+1); SSLGetPeerDomainName(cdsa_data->ssl_ctx, userdata->hostname, &hostnamelen); userdata->hostname[hostnamelen] = '\0'; // just make sure it's zero-terminated userdata->cond = cond; userdata->gsc = gsc; SSLCopyPeerCertificates(cdsa_data->ssl_ctx, &userdata->certs); certificate_ui_cb(gsc, userdata->hostname, userdata->certs, query_cert_result, userdata); } else { purple_debug_info("cdsa", "SSL_connect complete (did not verify certificate)\n"); /* SSL connected now */ gsc->connect_cb(gsc->connect_cb_data, gsc, cond); } SSLCipherSuite suite; SSLGetNegotiatedCipher(cdsa_data->ssl_ctx, &suite); purple_debug_info("cdsa", "Using cipher %x.\n", suite); }