184
204
g_object_class_install_property(object_class, PROP_PORT, pspec);
186
signals[STATUS_CHANGED] = g_signal_new("status-changed",
206
pspec = g_param_spec_object("tls-manager", "TLS Manager",
207
"TLS manager for interactive certificate checking",
208
IDLE_TYPE_SERVER_TLS_MANAGER,
210
G_PARAM_STATIC_STRINGS);
212
g_object_class_install_property(object_class, PROP_TLS_MANAGER, pspec);
214
signals[DISCONNECTED] = g_signal_new("disconnected",
187
215
G_OBJECT_CLASS_TYPE(klass),
188
216
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
191
219
g_cclosure_marshal_generic,
192
G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
220
G_TYPE_NONE, 1, G_TYPE_UINT);
194
222
signals[RECEIVED] = g_signal_new("received",
195
223
G_OBJECT_CLASS_TYPE(klass),
207
235
if (state == priv->state)
210
IDLE_DEBUG("emitting status-changed, state %u, reason %u", state, reason);
238
IDLE_DEBUG("moving to state %u, reason %u", state, reason);
212
239
priv->state = state;
213
g_signal_emit(conn, signals[STATUS_CHANGED], 0, state, reason);
241
if (state == SERVER_CONNECTION_STATE_NOT_CONNECTED)
242
g_signal_emit(conn, signals[DISCONNECTED], 0, reason);
216
245
static void _input_stream_read(IdleServerConnection *conn, GInputStream *input_stream, GAsyncReadyCallback callback) {
266
295
GError *error = NULL;
268
socket_connection = g_socket_client_connect_to_host_finish(socket_client, res, &error);
269
if (socket_connection == NULL) {
297
if (g_simple_async_result_propagate_error (task, &error)) {
270
298
IDLE_DEBUG("g_socket_client_connect_to_host failed: %s", error->message);
271
299
g_simple_async_result_set_error(result, TP_ERROR, TP_ERROR_NETWORK_ERROR, "%s", error->message);
272
300
g_error_free(error);
293
322
g_simple_async_result_complete(result);
294
323
g_object_unref(result);
324
g_object_unref(task);
328
#define CERT_ACCEPTED 1
329
#define CERT_REJECTED 2
331
IdleServerConnection *self;
332
GTlsCertificate *certificate;
335
static void _certificate_verified (GObject *source, GAsyncResult *res, gpointer user_data)
337
IdleServerConnection *self = user_data;
338
IdleServerConnectionPrivate *priv = IDLE_SERVER_CONNECTION_GET_PRIVATE(self);
341
ret = idle_server_tls_manager_verify_finish (IDLE_SERVER_TLS_MANAGER (source), res, NULL);
342
g_async_queue_push (priv->certificate_queue, GINT_TO_POINTER (ret ? CERT_ACCEPTED : CERT_REJECTED));
346
_check_certificate_interactively (gpointer data) {
347
struct CertData *d = data;
348
IdleServerConnectionPrivate *priv = IDLE_SERVER_CONNECTION_GET_PRIVATE(d->self);
350
idle_server_tls_manager_verify_async (priv->tls_manager, d->certificate, priv->host, _certificate_verified, d->self);
354
static gboolean _accept_certificate_request (GTlsConnection *tls_connection, GTlsCertificate *peer_cert, GTlsCertificateFlags errors, IdleServerConnection *conn)
356
IdleServerConnectionPrivate *priv = IDLE_SERVER_CONNECTION_GET_PRIVATE(conn);
360
/* Requested to check the extra errors from an ssl certificate,
361
* Need to bounce this back into the main thread so we can ask the UI
363
IDLE_DEBUG ("Requested to validate certificate");
366
d.certificate = peer_cert;
368
g_idle_add (_check_certificate_interactively, &d);
369
result = g_async_queue_pop (priv->certificate_queue);
371
return GPOINTER_TO_INT (result) == CERT_ACCEPTED;
374
static void _connect_event_cb (GSocketClient *client, GSocketClientEvent event, GSocketConnectable *connectable, GIOStream *connection, gpointer user_data)
376
if (event != G_SOCKET_CLIENT_TLS_HANDSHAKING)
379
g_signal_connect (connection, "accept-certificate", G_CALLBACK (_accept_certificate_request), user_data);
382
static void _connect_in_thread (GSimpleAsyncResult *task, GObject *source_object, GCancellable *cancellable)
384
IdleServerConnection *conn = IDLE_SERVER_CONNECTION (source_object);
385
IdleServerConnectionPrivate *priv = IDLE_SERVER_CONNECTION_GET_PRIVATE(conn);
386
GError *error = NULL;
387
GSocketConnection *socket_connection;
390
event_id = g_signal_connect (priv->socket_client, "event",
391
G_CALLBACK (_connect_event_cb), conn);
392
socket_connection = g_socket_client_connect_to_host (priv->socket_client, priv->host, priv->port, cancellable, &error);
393
g_signal_handler_disconnect (priv->socket_client, event_id);
395
if (socket_connection != NULL)
396
g_simple_async_result_set_op_res_gpointer (task, socket_connection, g_object_unref);
398
g_simple_async_result_take_error (task, error);
297
401
void idle_server_connection_connect_async(IdleServerConnection *conn, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) {
298
402
IdleServerConnectionPrivate *priv = IDLE_SERVER_CONNECTION_GET_PRIVATE(conn);
299
403
GSimpleAsyncResult *result;
404
GSimpleAsyncResult *task;
301
406
if (priv->state != SERVER_CONNECTION_STATE_NOT_CONNECTED) {
302
407
IDLE_DEBUG("already connecting or connected!");
328
433
result = g_simple_async_result_new(G_OBJECT(conn), callback, user_data, idle_server_connection_connect_async);
329
g_socket_client_connect_to_host_async(priv->socket_client, priv->host, priv->port, cancellable, _connect_to_host_ready, result);
435
task = g_simple_async_result_new (G_OBJECT (conn), _connect_to_host_ready, result, NULL);
436
g_simple_async_result_run_in_thread (task, _connect_in_thread, G_PRIORITY_DEFAULT, cancellable);
330
438
change_state(conn, SERVER_CONNECTION_STATE_CONNECTING, SERVER_CONNECTION_STATE_REASON_REQUESTED);
497
605
return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT(result), error);
500
IdleServerConnectionState idle_server_connection_get_state(IdleServerConnection *conn) {
608
gboolean idle_server_connection_is_connected(IdleServerConnection *conn) {
501
609
IdleServerConnectionPrivate *priv = IDLE_SERVER_CONNECTION_GET_PRIVATE(conn);
611
return priv->state == SERVER_CONNECTION_STATE_CONNECTED;
505
614
void idle_server_connection_set_tls(IdleServerConnection *conn, gboolean tls) {
506
615
IdleServerConnectionPrivate *priv = IDLE_SERVER_CONNECTION_GET_PRIVATE(conn);
507
616
g_socket_client_set_tls(priv->socket_client, tls);
509
/* The regression tests don't have a CA-issued certificate,
511
if (!tp_strdiff (g_getenv ("IDLE_TEST_BE_VULNERABLE_TO_MAN_IN_THE_MIDDLE_ATTACKS"), "vulnerable")) {
512
g_socket_client_set_tls_validation_flags(priv->socket_client,
513
G_TLS_CERTIFICATE_VALIDATE_ALL
514
& ~G_TLS_CERTIFICATE_UNKNOWN_CA
515
& ~G_TLS_CERTIFICATE_BAD_IDENTITY
516
& ~G_TLS_CERTIFICATE_EXPIRED);