• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
111 struct _GTlsInteractionPrivate {
112   GMainContext *context;
113 };
114 
115 G_DEFINE_TYPE_WITH_PRIVATE (GTlsInteraction, g_tls_interaction, G_TYPE_OBJECT)
116 
117 typedef 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 
136 static void
invoke_closure_free(gpointer data)137 invoke_closure_free (gpointer data)
138 {
139   InvokeClosure *closure = data;
140   g_assert (closure);
141   g_object_unref (closure->interaction);
142   g_clear_object (&closure->argument);
143   g_clear_object (&closure->cancellable);
144   g_cond_clear (&closure->cond);
145   g_mutex_clear (&closure->mutex);
146   g_clear_error (&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 (closure);
153 }
154 
155 static InvokeClosure *
invoke_closure_new(GTlsInteraction * interaction,GObject * argument,GCancellable * cancellable)156 invoke_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 (&closure->mutex);
165   g_cond_init (&closure->cond);
166   closure->result = G_TLS_INTERACTION_UNHANDLED;
167   return closure;
168 }
169 
170 static GTlsInteractionResult
invoke_closure_wait_and_free(InvokeClosure * closure,GError ** error)171 invoke_closure_wait_and_free (InvokeClosure *closure,
172                               GError       **error)
173 {
174   GTlsInteractionResult result;
175 
176   g_mutex_lock (&closure->mutex);
177 
178   while (!closure->complete)
179     g_cond_wait (&closure->cond, &closure->mutex);
180 
181   g_mutex_unlock (&closure->mutex);
182 
183   if (closure->error)
184     {
185       g_propagate_error (error, closure->error);
186       closure->error = NULL;
187     }
188   result = closure->result;
189 
190   invoke_closure_free (closure);
191   return result;
192 }
193 
194 static GTlsInteractionResult
invoke_closure_complete_and_free(GTlsInteraction * interaction,InvokeClosure * closure,GError ** error)195 invoke_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 (interaction->priv->context))
208     {
209       for (;;)
210         {
211           g_mutex_lock (&closure->mutex);
212           complete = closure->complete;
213           g_mutex_unlock (&closure->mutex);
214           if (complete)
215             break;
216           g_main_context_iteration (interaction->priv->context, TRUE);
217         }
218 
219       g_main_context_release (interaction->priv->context);
220 
221       if (closure->error)
222         {
223           g_propagate_error (error, closure->error);
224           closure->error = NULL;
225         }
226 
227       result = closure->result;
228       invoke_closure_free (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 
243 static void
g_tls_interaction_init(GTlsInteraction * interaction)244 g_tls_interaction_init (GTlsInteraction *interaction)
245 {
246   interaction->priv = g_tls_interaction_get_instance_private (interaction);
247   interaction->priv->context = g_main_context_ref_thread_default ();
248 }
249 
250 static void
g_tls_interaction_finalize(GObject * object)251 g_tls_interaction_finalize (GObject *object)
252 {
253   GTlsInteraction *interaction = G_TLS_INTERACTION (object);
254 
255   g_main_context_unref (interaction->priv->context);
256 
257   G_OBJECT_CLASS (g_tls_interaction_parent_class)->finalize (object);
258 }
259 
260 static void
g_tls_interaction_class_init(GTlsInteractionClass * klass)261 g_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 
268 static gboolean
on_invoke_ask_password_sync(gpointer user_data)269 on_invoke_ask_password_sync (gpointer user_data)
270 {
271   InvokeClosure *closure = user_data;
272   GTlsInteractionClass *klass;
273 
274   g_mutex_lock (&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 (&closure->cond);
286   g_mutex_unlock (&closure->mutex);
287 
288   return FALSE; /* don't call again */
289 }
290 
291 static void
on_ask_password_complete(GObject * source,GAsyncResult * result,gpointer user_data)292 on_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 (&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 (&closure->cond);
310   g_mutex_unlock (&closure->mutex);
311 }
312 
313 static gboolean
on_invoke_ask_password_async_as_sync(gpointer user_data)314 on_invoke_ask_password_async_as_sync (gpointer user_data)
315 {
316   InvokeClosure *closure = user_data;
317   GTlsInteractionClass *klass;
318 
319   g_mutex_lock (&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 (&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  */
370 GTlsInteractionResult
g_tls_interaction_invoke_ask_password(GTlsInteraction * interaction,GTlsPassword * password,GCancellable * cancellable,GError ** error)371 g_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 (interaction->priv->context,
390                              on_invoke_ask_password_sync, 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 (interaction->priv->context,
399                              on_invoke_ask_password_async_as_sync, 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  */
436 GTlsInteractionResult
g_tls_interaction_ask_password(GTlsInteraction * interaction,GTlsPassword * password,GCancellable * cancellable,GError ** error)437 g_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  */
481 void
g_tls_interaction_ask_password_async(GTlsInteraction * interaction,GTlsPassword * password,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)482 g_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 (interaction, cancellable, callback, user_data);
505       g_task_set_source_tag (task, g_tls_interaction_ask_password_async);
506       g_task_return_int (task, G_TLS_INTERACTION_UNHANDLED);
507       g_object_unref (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  */
531 GTlsInteractionResult
g_tls_interaction_ask_password_finish(GTlsInteraction * interaction,GAsyncResult * result,GError ** error)532 g_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 
556 static gboolean
on_invoke_request_certificate_sync(gpointer user_data)557 on_invoke_request_certificate_sync (gpointer user_data)
558 {
559   InvokeClosure *closure = user_data;
560   GTlsInteractionClass *klass;
561 
562   g_mutex_lock (&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 (&closure->cond);
575   g_mutex_unlock (&closure->mutex);
576 
577   return FALSE; /* don't call again */
578 }
579 
580 static void
on_request_certificate_complete(GObject * source,GAsyncResult * result,gpointer user_data)581 on_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 (&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 (&closure->cond);
598   g_mutex_unlock (&closure->mutex);
599 }
600 
601 static gboolean
on_invoke_request_certificate_async_as_sync(gpointer user_data)602 on_invoke_request_certificate_async_as_sync (gpointer user_data)
603 {
604   InvokeClosure *closure = user_data;
605   GTlsInteractionClass *klass;
606 
607   g_mutex_lock (&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 (&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  */
660 GTlsInteractionResult
g_tls_interaction_invoke_request_certificate(GTlsInteraction * interaction,GTlsConnection * connection,GTlsCertificateRequestFlags flags,GCancellable * cancellable,GError ** error)661 g_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 (interaction->priv->context,
681                              on_invoke_request_certificate_sync, 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 (interaction->priv->context,
690                              on_invoke_request_certificate_async_as_sync, 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  */
731 GTlsInteractionResult
g_tls_interaction_request_certificate(GTlsInteraction * interaction,GTlsConnection * connection,GTlsCertificateRequestFlags flags,GCancellable * cancellable,GError ** error)732 g_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  */
771 void
g_tls_interaction_request_certificate_async(GTlsInteraction * interaction,GTlsConnection * connection,GTlsCertificateRequestFlags flags,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)772 g_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 (interaction, cancellable, callback, user_data);
796       g_task_set_source_tag (task, g_tls_interaction_request_certificate_async);
797       g_task_return_int (task, G_TLS_INTERACTION_UNHANDLED);
798       g_object_unref (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  */
823 GTlsInteractionResult
g_tls_interaction_request_certificate_finish(GTlsInteraction * interaction,GAsyncResult * result,GError ** error)824 g_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