1/* GIO - GLib Input, Output and Streaming Library
2 *
3 * Copyright (C) 2011 Collabora, Ltd.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 *
18 * Author: Stef Walter <stefw@collabora.co.uk>
19 */
20
21#include "config.h"
22
23#include <string.h>
24
25#include "gtlscertificate.h"
26#include "gtlsconnection.h"
27#include "gtlsinteraction.h"
28#include "gtlspassword.h"
29#include "gasyncresult.h"
30#include "gcancellable.h"
31#include "gtask.h"
32#include "gioenumtypes.h"
33#include "glibintl.h"
34
35
36/**
37 * SECTION:gtlsinteraction
38 * @short_description: Interaction with the user during TLS operations.
39 * @include: gio/gio.h
40 *
41 * #GTlsInteraction provides a mechanism for the TLS connection and database
42 * code to interact with the user. It can be used to ask the user for passwords.
43 *
44 * To use a #GTlsInteraction with a TLS connection use
45 * g_tls_connection_set_interaction().
46 *
47 * Callers should instantiate a derived class that implements the various
48 * interaction methods to show the required dialogs.
49 *
50 * Callers should use the 'invoke' functions like
51 * g_tls_interaction_invoke_ask_password() to run interaction methods. These
52 * functions make sure that the interaction is invoked in the main loop
53 * and not in the current thread, if the current thread is not running the
54 * main loop.
55 *
56 * Derived classes can choose to implement whichever interactions methods they'd
57 * like to support by overriding those virtual methods in their class
58 * initialization function. Any interactions not implemented will return
59 * %G_TLS_INTERACTION_UNHANDLED. If a derived class implements an async method,
60 * it must also implement the corresponding finish method.
61 */
62
63/**
64 * GTlsInteraction:
65 *
66 * An object representing interaction that the TLS connection and database
67 * might have with the user.
68 *
69 * Since: 2.30
70 */
71
72/**
73 * GTlsInteractionClass:
74 * @ask_password: ask for a password synchronously. If the implementation
75 * returns %G_TLS_INTERACTION_HANDLED, then the password argument should
76 * have been filled in by using g_tls_password_set_value() or a similar
77 * function.
78 * @ask_password_async: ask for a password asynchronously.
79 * @ask_password_finish: complete operation to ask for a password asynchronously.
80 * If the implementation returns %G_TLS_INTERACTION_HANDLED, then the
81 * password argument of the async method should have been filled in by using
82 * g_tls_password_set_value() or a similar function.
83 * @request_certificate: ask for a certificate synchronously. If the
84 * implementation returns %G_TLS_INTERACTION_HANDLED, then the connection
85 * argument should have been filled in by using
86 * g_tls_connection_set_certificate().
87 * @request_certificate_async: ask for a certificate asynchronously.
88 * @request_certificate_finish: complete operation to ask for a certificate
89 * asynchronously. If the implementation returns %G_TLS_INTERACTION_HANDLED,
90 * then the connection argument of the async method should have been
91 * filled in by using g_tls_connection_set_certificate().
92 *
93 * The class for #GTlsInteraction. Derived classes implement the various
94 * virtual interaction methods to handle TLS interactions.
95 *
96 * Derived classes can choose to implement whichever interactions methods they'd
97 * like to support by overriding those virtual methods in their class
98 * initialization function. If a derived class implements an async method,
99 * it must also implement the corresponding finish method.
100 *
101 * The synchronous interaction methods should implement to display modal dialogs,
102 * and the asynchronous methods to display modeless dialogs.
103 *
104 * If the user cancels an interaction, then the result should be
105 * %G_TLS_INTERACTION_FAILED and the error should be set with a domain of
106 * %G_IO_ERROR and code of %G_IO_ERROR_CANCELLED.
107 *
108 * Since: 2.30
109 */
110
111struct _GTlsInteractionPrivate {
112 GMainContext *context;
113};
114
115G_DEFINE_TYPE_WITH_PRIVATE (GTlsInteraction, g_tls_interaction, G_TYPE_OBJECT)
116
117typedef struct {
118 GMutex mutex;
119
120 /* Input arguments */
121 GTlsInteraction *interaction;
122 GObject *argument;
123 GCancellable *cancellable;
124
125 /* Used when we're invoking async interactions */
126 GAsyncReadyCallback callback;
127 gpointer user_data;
128
129 /* Used when we expect results */
130 GTlsInteractionResult result;
131 GError *error;
132 gboolean complete;
133 GCond cond;
134} InvokeClosure;
135
136static void
137invoke_closure_free (gpointer data)
138{
139 InvokeClosure *closure = data;
140 g_assert (closure);
141 g_object_unref (object: closure->interaction);
142 g_clear_object (&closure->argument);
143 g_clear_object (&closure->cancellable);
144 g_cond_clear (cond: &closure->cond);
145 g_mutex_clear (mutex: &closure->mutex);
146 g_clear_error (err: &closure->error);
147
148 /* Insurance that we've actually used these before freeing */
149 g_assert (closure->callback == NULL);
150 g_assert (closure->user_data == NULL);
151
152 g_free (mem: closure);
153}
154
155static InvokeClosure *
156invoke_closure_new (GTlsInteraction *interaction,
157 GObject *argument,
158 GCancellable *cancellable)
159{
160 InvokeClosure *closure = g_new0 (InvokeClosure, 1);
161 closure->interaction = g_object_ref (interaction);
162 closure->argument = argument ? g_object_ref (argument) : NULL;
163 closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
164 g_mutex_init (mutex: &closure->mutex);
165 g_cond_init (cond: &closure->cond);
166 closure->result = G_TLS_INTERACTION_UNHANDLED;
167 return closure;
168}
169
170static GTlsInteractionResult
171invoke_closure_wait_and_free (InvokeClosure *closure,
172 GError **error)
173{
174 GTlsInteractionResult result;
175
176 g_mutex_lock (mutex: &closure->mutex);
177
178 while (!closure->complete)
179 g_cond_wait (cond: &closure->cond, mutex: &closure->mutex);
180
181 g_mutex_unlock (mutex: &closure->mutex);
182
183 if (closure->error)
184 {
185 g_propagate_error (dest: error, src: closure->error);
186 closure->error = NULL;
187 }
188 result = closure->result;
189
190 invoke_closure_free (data: closure);
191 return result;
192}
193
194static GTlsInteractionResult
195invoke_closure_complete_and_free (GTlsInteraction *interaction,
196 InvokeClosure *closure,
197 GError **error)
198{
199 GTlsInteractionResult result;
200 gboolean complete;
201
202 /*
203 * Handle the case where we've been called from within the main context
204 * or in the case where the main context is not running. This approximates
205 * the behavior of a modal dialog.
206 */
207 if (g_main_context_acquire (context: interaction->priv->context))
208 {
209 for (;;)
210 {
211 g_mutex_lock (mutex: &closure->mutex);
212 complete = closure->complete;
213 g_mutex_unlock (mutex: &closure->mutex);
214 if (complete)
215 break;
216 g_main_context_iteration (context: interaction->priv->context, TRUE);
217 }
218
219 g_main_context_release (context: interaction->priv->context);
220
221 if (closure->error)
222 {
223 g_propagate_error (dest: error, src: closure->error);
224 closure->error = NULL;
225 }
226
227 result = closure->result;
228 invoke_closure_free (data: closure);
229 }
230
231 /*
232 * Handle the case where we're in a different thread than the main
233 * context and a main loop is running.
234 */
235 else
236 {
237 result = invoke_closure_wait_and_free (closure, error);
238 }
239
240 return result;
241}
242
243static void
244g_tls_interaction_init (GTlsInteraction *interaction)
245{
246 interaction->priv = g_tls_interaction_get_instance_private (self: interaction);
247 interaction->priv->context = g_main_context_ref_thread_default ();
248}
249
250static void
251g_tls_interaction_finalize (GObject *object)
252{
253 GTlsInteraction *interaction = G_TLS_INTERACTION (object);
254
255 g_main_context_unref (context: interaction->priv->context);
256
257 G_OBJECT_CLASS (g_tls_interaction_parent_class)->finalize (object);
258}
259
260static void
261g_tls_interaction_class_init (GTlsInteractionClass *klass)
262{
263 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
264
265 gobject_class->finalize = g_tls_interaction_finalize;
266}
267
268static gboolean
269on_invoke_ask_password_sync (gpointer user_data)
270{
271 InvokeClosure *closure = user_data;
272 GTlsInteractionClass *klass;
273
274 g_mutex_lock (mutex: &closure->mutex);
275
276 klass = G_TLS_INTERACTION_GET_CLASS (closure->interaction);
277 g_assert (klass->ask_password);
278
279 closure->result = klass->ask_password (closure->interaction,
280 G_TLS_PASSWORD (closure->argument),
281 closure->cancellable,
282 &closure->error);
283
284 closure->complete = TRUE;
285 g_cond_signal (cond: &closure->cond);
286 g_mutex_unlock (mutex: &closure->mutex);
287
288 return FALSE; /* don't call again */
289}
290
291static void
292on_ask_password_complete (GObject *source,
293 GAsyncResult *result,
294 gpointer user_data)
295{
296 InvokeClosure *closure = user_data;
297 GTlsInteractionClass *klass;
298
299 g_mutex_lock (mutex: &closure->mutex);
300
301 klass = G_TLS_INTERACTION_GET_CLASS (closure->interaction);
302 g_assert (klass->ask_password_finish);
303
304 closure->result = klass->ask_password_finish (closure->interaction,
305 result,
306 &closure->error);
307
308 closure->complete = TRUE;
309 g_cond_signal (cond: &closure->cond);
310 g_mutex_unlock (mutex: &closure->mutex);
311}
312
313static gboolean
314on_invoke_ask_password_async_as_sync (gpointer user_data)
315{
316 InvokeClosure *closure = user_data;
317 GTlsInteractionClass *klass;
318
319 g_mutex_lock (mutex: &closure->mutex);
320
321 klass = G_TLS_INTERACTION_GET_CLASS (closure->interaction);
322 g_assert (klass->ask_password_async);
323
324 klass->ask_password_async (closure->interaction,
325 G_TLS_PASSWORD (closure->argument),
326 closure->cancellable,
327 on_ask_password_complete,
328 closure);
329
330 /* Note that we've used these */
331 closure->callback = NULL;
332 closure->user_data = NULL;
333
334 g_mutex_unlock (mutex: &closure->mutex);
335
336 return FALSE; /* don't call again */
337}
338
339/**
340 * g_tls_interaction_invoke_ask_password:
341 * @interaction: a #GTlsInteraction object
342 * @password: a #GTlsPassword object
343 * @cancellable: an optional #GCancellable cancellation object
344 * @error: an optional location to place an error on failure
345 *
346 * Invoke the interaction to ask the user for a password. It invokes this
347 * interaction in the main loop, specifically the #GMainContext returned by
348 * g_main_context_get_thread_default() when the interaction is created. This
349 * is called by called by #GTlsConnection or #GTlsDatabase to ask the user
350 * for a password.
351 *
352 * Derived subclasses usually implement a password prompt, although they may
353 * also choose to provide a password from elsewhere. The @password value will
354 * be filled in and then @callback will be called. Alternatively the user may
355 * abort this password request, which will usually abort the TLS connection.
356 *
357 * The implementation can either be a synchronous (eg: modal dialog) or an
358 * asynchronous one (eg: modeless dialog). This function will take care of
359 * calling which ever one correctly.
360 *
361 * If the interaction is cancelled by the cancellation object, or by the
362 * user then %G_TLS_INTERACTION_FAILED will be returned with an error that
363 * contains a %G_IO_ERROR_CANCELLED error code. Certain implementations may
364 * not support immediate cancellation.
365 *
366 * Returns: The status of the ask password interaction.
367 *
368 * Since: 2.30
369 */
370GTlsInteractionResult
371g_tls_interaction_invoke_ask_password (GTlsInteraction *interaction,
372 GTlsPassword *password,
373 GCancellable *cancellable,
374 GError **error)
375{
376 GTlsInteractionResult result;
377 InvokeClosure *closure;
378 GTlsInteractionClass *klass;
379
380 g_return_val_if_fail (G_IS_TLS_INTERACTION (interaction), G_TLS_INTERACTION_UNHANDLED);
381 g_return_val_if_fail (G_IS_TLS_PASSWORD (password), G_TLS_INTERACTION_UNHANDLED);
382 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), G_TLS_INTERACTION_UNHANDLED);
383
384 klass = G_TLS_INTERACTION_GET_CLASS (interaction);
385
386 if (klass->ask_password)
387 {
388 closure = invoke_closure_new (interaction, G_OBJECT (password), cancellable);
389 g_main_context_invoke (context: interaction->priv->context,
390 function: on_invoke_ask_password_sync, data: closure);
391 result = invoke_closure_wait_and_free (closure, error);
392 }
393 else if (klass->ask_password_async)
394 {
395 g_return_val_if_fail (klass->ask_password_finish, G_TLS_INTERACTION_UNHANDLED);
396
397 closure = invoke_closure_new (interaction, G_OBJECT (password), cancellable);
398 g_main_context_invoke (context: interaction->priv->context,
399 function: on_invoke_ask_password_async_as_sync, data: closure);
400
401 result = invoke_closure_complete_and_free (interaction, closure, error);
402 }
403 else
404 {
405 result = G_TLS_INTERACTION_UNHANDLED;
406 }
407
408 return result;
409}
410
411/**
412 * g_tls_interaction_ask_password:
413 * @interaction: a #GTlsInteraction object
414 * @password: a #GTlsPassword object
415 * @cancellable: an optional #GCancellable cancellation object
416 * @error: an optional location to place an error on failure
417 *
418 * Run synchronous interaction to ask the user for a password. In general,
419 * g_tls_interaction_invoke_ask_password() should be used instead of this
420 * function.
421 *
422 * Derived subclasses usually implement a password prompt, although they may
423 * also choose to provide a password from elsewhere. The @password value will
424 * be filled in and then @callback will be called. Alternatively the user may
425 * abort this password request, which will usually abort the TLS connection.
426 *
427 * If the interaction is cancelled by the cancellation object, or by the
428 * user then %G_TLS_INTERACTION_FAILED will be returned with an error that
429 * contains a %G_IO_ERROR_CANCELLED error code. Certain implementations may
430 * not support immediate cancellation.
431 *
432 * Returns: The status of the ask password interaction.
433 *
434 * Since: 2.30
435 */
436GTlsInteractionResult
437g_tls_interaction_ask_password (GTlsInteraction *interaction,
438 GTlsPassword *password,
439 GCancellable *cancellable,
440 GError **error)
441{
442 GTlsInteractionClass *klass;
443
444 g_return_val_if_fail (G_IS_TLS_INTERACTION (interaction), G_TLS_INTERACTION_UNHANDLED);
445 g_return_val_if_fail (G_IS_TLS_PASSWORD (password), G_TLS_INTERACTION_UNHANDLED);
446 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), G_TLS_INTERACTION_UNHANDLED);
447
448 klass = G_TLS_INTERACTION_GET_CLASS (interaction);
449 if (klass->ask_password)
450 return (klass->ask_password) (interaction, password, cancellable, error);
451 else
452 return G_TLS_INTERACTION_UNHANDLED;
453}
454
455/**
456 * g_tls_interaction_ask_password_async:
457 * @interaction: a #GTlsInteraction object
458 * @password: a #GTlsPassword object
459 * @cancellable: an optional #GCancellable cancellation object
460 * @callback: (nullable): will be called when the interaction completes
461 * @user_data: (nullable): data to pass to the @callback
462 *
463 * Run asynchronous interaction to ask the user for a password. In general,
464 * g_tls_interaction_invoke_ask_password() should be used instead of this
465 * function.
466 *
467 * Derived subclasses usually implement a password prompt, although they may
468 * also choose to provide a password from elsewhere. The @password value will
469 * be filled in and then @callback will be called. Alternatively the user may
470 * abort this password request, which will usually abort the TLS connection.
471 *
472 * If the interaction is cancelled by the cancellation object, or by the
473 * user then %G_TLS_INTERACTION_FAILED will be returned with an error that
474 * contains a %G_IO_ERROR_CANCELLED error code. Certain implementations may
475 * not support immediate cancellation.
476 *
477 * Certain implementations may not support immediate cancellation.
478 *
479 * Since: 2.30
480 */
481void
482g_tls_interaction_ask_password_async (GTlsInteraction *interaction,
483 GTlsPassword *password,
484 GCancellable *cancellable,
485 GAsyncReadyCallback callback,
486 gpointer user_data)
487{
488 GTlsInteractionClass *klass;
489 GTask *task;
490
491 g_return_if_fail (G_IS_TLS_INTERACTION (interaction));
492 g_return_if_fail (G_IS_TLS_PASSWORD (password));
493 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
494
495 klass = G_TLS_INTERACTION_GET_CLASS (interaction);
496 if (klass->ask_password_async)
497 {
498 g_return_if_fail (klass->ask_password_finish);
499 (klass->ask_password_async) (interaction, password, cancellable,
500 callback, user_data);
501 }
502 else
503 {
504 task = g_task_new (source_object: interaction, cancellable, callback, callback_data: user_data);
505 g_task_set_source_tag (task, g_tls_interaction_ask_password_async);
506 g_task_return_int (task, result: G_TLS_INTERACTION_UNHANDLED);
507 g_object_unref (object: task);
508 }
509}
510
511/**
512 * g_tls_interaction_ask_password_finish:
513 * @interaction: a #GTlsInteraction object
514 * @result: the result passed to the callback
515 * @error: an optional location to place an error on failure
516 *
517 * Complete an ask password user interaction request. This should be once
518 * the g_tls_interaction_ask_password_async() completion callback is called.
519 *
520 * If %G_TLS_INTERACTION_HANDLED is returned, then the #GTlsPassword passed
521 * to g_tls_interaction_ask_password() will have its password filled in.
522 *
523 * If the interaction is cancelled by the cancellation object, or by the
524 * user then %G_TLS_INTERACTION_FAILED will be returned with an error that
525 * contains a %G_IO_ERROR_CANCELLED error code.
526 *
527 * Returns: The status of the ask password interaction.
528 *
529 * Since: 2.30
530 */
531GTlsInteractionResult
532g_tls_interaction_ask_password_finish (GTlsInteraction *interaction,
533 GAsyncResult *result,
534 GError **error)
535{
536 GTlsInteractionClass *klass;
537
538 g_return_val_if_fail (G_IS_TLS_INTERACTION (interaction), G_TLS_INTERACTION_UNHANDLED);
539 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), G_TLS_INTERACTION_UNHANDLED);
540
541 klass = G_TLS_INTERACTION_GET_CLASS (interaction);
542 if (klass->ask_password_finish)
543 {
544 g_return_val_if_fail (klass->ask_password_async != NULL, G_TLS_INTERACTION_UNHANDLED);
545
546 return (klass->ask_password_finish) (interaction, result, error);
547 }
548 else
549 {
550 g_return_val_if_fail (g_async_result_is_tagged (result, g_tls_interaction_ask_password_async), G_TLS_INTERACTION_UNHANDLED);
551
552 return g_task_propagate_int (G_TASK (result), error);
553 }
554}
555
556static gboolean
557on_invoke_request_certificate_sync (gpointer user_data)
558{
559 InvokeClosure *closure = user_data;
560 GTlsInteractionClass *klass;
561
562 g_mutex_lock (mutex: &closure->mutex);
563
564 klass = G_TLS_INTERACTION_GET_CLASS (closure->interaction);
565 g_assert (klass->request_certificate != NULL);
566
567 closure->result = klass->request_certificate (closure->interaction,
568 G_TLS_CONNECTION (closure->argument),
569 0,
570 closure->cancellable,
571 &closure->error);
572
573 closure->complete = TRUE;
574 g_cond_signal (cond: &closure->cond);
575 g_mutex_unlock (mutex: &closure->mutex);
576
577 return FALSE; /* don't call again */
578}
579
580static void
581on_request_certificate_complete (GObject *source,
582 GAsyncResult *result,
583 gpointer user_data)
584{
585 InvokeClosure *closure = user_data;
586 GTlsInteractionClass *klass;
587
588 g_mutex_lock (mutex: &closure->mutex);
589
590 klass = G_TLS_INTERACTION_GET_CLASS (closure->interaction);
591 g_assert (klass->request_certificate_finish != NULL);
592
593 closure->result = klass->request_certificate_finish (closure->interaction,
594 result, &closure->error);
595
596 closure->complete = TRUE;
597 g_cond_signal (cond: &closure->cond);
598 g_mutex_unlock (mutex: &closure->mutex);
599}
600
601static gboolean
602on_invoke_request_certificate_async_as_sync (gpointer user_data)
603{
604 InvokeClosure *closure = user_data;
605 GTlsInteractionClass *klass;
606
607 g_mutex_lock (mutex: &closure->mutex);
608
609 klass = G_TLS_INTERACTION_GET_CLASS (closure->interaction);
610 g_assert (klass->request_certificate_async);
611
612 klass->request_certificate_async (closure->interaction,
613 G_TLS_CONNECTION (closure->argument), 0,
614 closure->cancellable,
615 on_request_certificate_complete,
616 closure);
617
618 /* Note that we've used these */
619 closure->callback = NULL;
620 closure->user_data = NULL;
621
622 g_mutex_unlock (mutex: &closure->mutex);
623
624 return FALSE; /* don't call again */
625}
626
627/**
628 * g_tls_interaction_invoke_request_certificate:
629 * @interaction: a #GTlsInteraction object
630 * @connection: a #GTlsConnection object
631 * @flags: flags providing more information about the request
632 * @cancellable: an optional #GCancellable cancellation object
633 * @error: an optional location to place an error on failure
634 *
635 * Invoke the interaction to ask the user to choose a certificate to
636 * use with the connection. It invokes this interaction in the main
637 * loop, specifically the #GMainContext returned by
638 * g_main_context_get_thread_default() when the interaction is
639 * created. This is called by called by #GTlsConnection when the peer
640 * requests a certificate during the handshake.
641 *
642 * Derived subclasses usually implement a certificate selector,
643 * although they may also choose to provide a certificate from
644 * elsewhere. Alternatively the user may abort this certificate
645 * request, which may or may not abort the TLS connection.
646 *
647 * The implementation can either be a synchronous (eg: modal dialog) or an
648 * asynchronous one (eg: modeless dialog). This function will take care of
649 * calling which ever one correctly.
650 *
651 * If the interaction is cancelled by the cancellation object, or by the
652 * user then %G_TLS_INTERACTION_FAILED will be returned with an error that
653 * contains a %G_IO_ERROR_CANCELLED error code. Certain implementations may
654 * not support immediate cancellation.
655 *
656 * Returns: The status of the certificate request interaction.
657 *
658 * Since: 2.40
659 */
660GTlsInteractionResult
661g_tls_interaction_invoke_request_certificate (GTlsInteraction *interaction,
662 GTlsConnection *connection,
663 GTlsCertificateRequestFlags flags,
664 GCancellable *cancellable,
665 GError **error)
666{
667 GTlsInteractionResult result;
668 InvokeClosure *closure;
669 GTlsInteractionClass *klass;
670
671 g_return_val_if_fail (G_IS_TLS_INTERACTION (interaction), G_TLS_INTERACTION_UNHANDLED);
672 g_return_val_if_fail (G_IS_TLS_CONNECTION (connection), G_TLS_INTERACTION_UNHANDLED);
673 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), G_TLS_INTERACTION_UNHANDLED);
674
675 klass = G_TLS_INTERACTION_GET_CLASS (interaction);
676
677 if (klass->request_certificate)
678 {
679 closure = invoke_closure_new (interaction, G_OBJECT (connection), cancellable);
680 g_main_context_invoke (context: interaction->priv->context,
681 function: on_invoke_request_certificate_sync, data: closure);
682 result = invoke_closure_wait_and_free (closure, error);
683 }
684 else if (klass->request_certificate_async)
685 {
686 g_return_val_if_fail (klass->request_certificate_finish, G_TLS_INTERACTION_UNHANDLED);
687
688 closure = invoke_closure_new (interaction, G_OBJECT (connection), cancellable);
689 g_main_context_invoke (context: interaction->priv->context,
690 function: on_invoke_request_certificate_async_as_sync, data: closure);
691
692 result = invoke_closure_complete_and_free (interaction, closure, error);
693 }
694 else
695 {
696 result = G_TLS_INTERACTION_UNHANDLED;
697 }
698
699 return result;
700}
701
702/**
703 * g_tls_interaction_request_certificate:
704 * @interaction: a #GTlsInteraction object
705 * @connection: a #GTlsConnection object
706 * @flags: flags providing more information about the request
707 * @cancellable: an optional #GCancellable cancellation object
708 * @error: an optional location to place an error on failure
709 *
710 * Run synchronous interaction to ask the user to choose a certificate to use
711 * with the connection. In general, g_tls_interaction_invoke_request_certificate()
712 * should be used instead of this function.
713 *
714 * Derived subclasses usually implement a certificate selector, although they may
715 * also choose to provide a certificate from elsewhere. Alternatively the user may
716 * abort this certificate request, which will usually abort the TLS connection.
717 *
718 * If %G_TLS_INTERACTION_HANDLED is returned, then the #GTlsConnection
719 * passed to g_tls_interaction_request_certificate() will have had its
720 * #GTlsConnection:certificate filled in.
721 *
722 * If the interaction is cancelled by the cancellation object, or by the
723 * user then %G_TLS_INTERACTION_FAILED will be returned with an error that
724 * contains a %G_IO_ERROR_CANCELLED error code. Certain implementations may
725 * not support immediate cancellation.
726 *
727 * Returns: The status of the request certificate interaction.
728 *
729 * Since: 2.40
730 */
731GTlsInteractionResult
732g_tls_interaction_request_certificate (GTlsInteraction *interaction,
733 GTlsConnection *connection,
734 GTlsCertificateRequestFlags flags,
735 GCancellable *cancellable,
736 GError **error)
737{
738 GTlsInteractionClass *klass;
739
740 g_return_val_if_fail (G_IS_TLS_INTERACTION (interaction), G_TLS_INTERACTION_UNHANDLED);
741 g_return_val_if_fail (G_IS_TLS_CONNECTION (connection), G_TLS_INTERACTION_UNHANDLED);
742 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), G_TLS_INTERACTION_UNHANDLED);
743
744 klass = G_TLS_INTERACTION_GET_CLASS (interaction);
745 if (klass->request_certificate)
746 return (klass->request_certificate) (interaction, connection, flags, cancellable, error);
747 else
748 return G_TLS_INTERACTION_UNHANDLED;
749}
750
751/**
752 * g_tls_interaction_request_certificate_async:
753 * @interaction: a #GTlsInteraction object
754 * @connection: a #GTlsConnection object
755 * @flags: flags providing more information about the request
756 * @cancellable: an optional #GCancellable cancellation object
757 * @callback: (nullable): will be called when the interaction completes
758 * @user_data: (nullable): data to pass to the @callback
759 *
760 * Run asynchronous interaction to ask the user for a certificate to use with
761 * the connection. In general, g_tls_interaction_invoke_request_certificate() should
762 * be used instead of this function.
763 *
764 * Derived subclasses usually implement a certificate selector, although they may
765 * also choose to provide a certificate from elsewhere. @callback will be called
766 * when the operation completes. Alternatively the user may abort this certificate
767 * request, which will usually abort the TLS connection.
768 *
769 * Since: 2.40
770 */
771void
772g_tls_interaction_request_certificate_async (GTlsInteraction *interaction,
773 GTlsConnection *connection,
774 GTlsCertificateRequestFlags flags,
775 GCancellable *cancellable,
776 GAsyncReadyCallback callback,
777 gpointer user_data)
778{
779 GTlsInteractionClass *klass;
780 GTask *task;
781
782 g_return_if_fail (G_IS_TLS_INTERACTION (interaction));
783 g_return_if_fail (G_IS_TLS_CONNECTION (connection));
784 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
785
786 klass = G_TLS_INTERACTION_GET_CLASS (interaction);
787 if (klass->request_certificate_async)
788 {
789 g_return_if_fail (klass->request_certificate_finish);
790 (klass->request_certificate_async) (interaction, connection, flags,
791 cancellable, callback, user_data);
792 }
793 else
794 {
795 task = g_task_new (source_object: interaction, cancellable, callback, callback_data: user_data);
796 g_task_set_source_tag (task, g_tls_interaction_request_certificate_async);
797 g_task_return_int (task, result: G_TLS_INTERACTION_UNHANDLED);
798 g_object_unref (object: task);
799 }
800}
801
802/**
803 * g_tls_interaction_request_certificate_finish:
804 * @interaction: a #GTlsInteraction object
805 * @result: the result passed to the callback
806 * @error: an optional location to place an error on failure
807 *
808 * Complete a request certificate user interaction request. This should be once
809 * the g_tls_interaction_request_certificate_async() completion callback is called.
810 *
811 * If %G_TLS_INTERACTION_HANDLED is returned, then the #GTlsConnection
812 * passed to g_tls_interaction_request_certificate_async() will have had its
813 * #GTlsConnection:certificate filled in.
814 *
815 * If the interaction is cancelled by the cancellation object, or by the
816 * user then %G_TLS_INTERACTION_FAILED will be returned with an error that
817 * contains a %G_IO_ERROR_CANCELLED error code.
818 *
819 * Returns: The status of the request certificate interaction.
820 *
821 * Since: 2.40
822 */
823GTlsInteractionResult
824g_tls_interaction_request_certificate_finish (GTlsInteraction *interaction,
825 GAsyncResult *result,
826 GError **error)
827{
828 GTlsInteractionClass *klass;
829
830 g_return_val_if_fail (G_IS_TLS_INTERACTION (interaction), G_TLS_INTERACTION_UNHANDLED);
831 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), G_TLS_INTERACTION_UNHANDLED);
832
833 klass = G_TLS_INTERACTION_GET_CLASS (interaction);
834 if (klass->request_certificate_finish)
835 {
836 g_return_val_if_fail (klass->request_certificate_async != NULL, G_TLS_INTERACTION_UNHANDLED);
837
838 return (klass->request_certificate_finish) (interaction, result, error);
839 }
840 else
841 {
842 g_return_val_if_fail (g_async_result_is_tagged (result, g_tls_interaction_request_certificate_async), G_TLS_INTERACTION_UNHANDLED);
843
844 return g_task_propagate_int (G_TASK (result), error);
845 }
846}
847

source code of gtk/subprojects/glib/gio/gtlsinteraction.c