(root)/
glib-2.79.0/
gio/
gtlsinteraction.c
       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  }