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