Coverage Report

Created: 2025-07-23 08:13

/src/pango/subprojects/glib/gio/gtlsinteraction.c
Line
Count
Source (jump to first uncovered line)
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
0
{
132
0
  InvokeClosure *closure = data;
133
0
  g_assert (closure);
134
0
  g_object_unref (closure->interaction);
135
0
  g_clear_object (&closure->argument);
136
0
  g_clear_object (&closure->cancellable);
137
0
  g_cond_clear (&closure->cond);
138
0
  g_mutex_clear (&closure->mutex);
139
0
  g_clear_error (&closure->error);
140
141
  /* Insurance that we've actually used these before freeing */
142
0
  g_assert (closure->callback == NULL);
143
0
  g_assert (closure->user_data == NULL);
144
145
0
  g_free (closure);
146
0
}
147
148
static InvokeClosure *
149
invoke_closure_new (GTlsInteraction *interaction,
150
                    GObject         *argument,
151
                    GCancellable    *cancellable)
152
0
{
153
0
  InvokeClosure *closure = g_new0 (InvokeClosure, 1);
154
0
  closure->interaction = g_object_ref (interaction);
155
0
  closure->argument = argument ? g_object_ref (argument) : NULL;
156
0
  closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
157
0
  g_mutex_init (&closure->mutex);
158
0
  g_cond_init (&closure->cond);
159
0
  closure->result = G_TLS_INTERACTION_UNHANDLED;
160
0
  return closure;
161
0
}
162
163
static GTlsInteractionResult
164
invoke_closure_wait_and_free (InvokeClosure *closure,
165
                              GError       **error)
166
0
{
167
0
  GTlsInteractionResult result;
168
169
0
  g_mutex_lock (&closure->mutex);
170
171
0
  while (!closure->complete)
172
0
    g_cond_wait (&closure->cond, &closure->mutex);
173
174
0
  g_mutex_unlock (&closure->mutex);
175
176
0
  if (closure->error)
177
0
    {
178
0
      g_propagate_error (error, closure->error);
179
0
      closure->error = NULL;
180
0
    }
181
0
  result = closure->result;
182
183
0
  invoke_closure_free (closure);
184
0
  return result;
185
0
}
186
187
static GTlsInteractionResult
188
invoke_closure_complete_and_free (GTlsInteraction *interaction,
189
                                  InvokeClosure *closure,
190
                                  GError **error)
191
0
{
192
0
  GTlsInteractionResult result;
193
0
  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
0
  if (g_main_context_acquire (interaction->priv->context))
201
0
    {
202
0
      for (;;)
203
0
        {
204
0
          g_mutex_lock (&closure->mutex);
205
0
          complete = closure->complete;
206
0
          g_mutex_unlock (&closure->mutex);
207
0
          if (complete)
208
0
            break;
209
0
          g_main_context_iteration (interaction->priv->context, TRUE);
210
0
        }
211
212
0
      g_main_context_release (interaction->priv->context);
213
214
0
      if (closure->error)
215
0
        {
216
0
          g_propagate_error (error, closure->error);
217
0
          closure->error = NULL;
218
0
        }
219
220
0
      result = closure->result;
221
0
      invoke_closure_free (closure);
222
0
    }
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
0
  else
229
0
    {
230
0
      result = invoke_closure_wait_and_free (closure, error);
231
0
    }
232
233
0
  return result;
234
0
}
235
236
static void
237
g_tls_interaction_init (GTlsInteraction *interaction)
238
0
{
239
0
  interaction->priv = g_tls_interaction_get_instance_private (interaction);
240
0
  interaction->priv->context = g_main_context_ref_thread_default ();
241
0
}
242
243
static void
244
g_tls_interaction_finalize (GObject *object)
245
0
{
246
0
  GTlsInteraction *interaction = G_TLS_INTERACTION (object);
247
248
0
  g_main_context_unref (interaction->priv->context);
249
250
0
  G_OBJECT_CLASS (g_tls_interaction_parent_class)->finalize (object);
251
0
}
252
253
static void
254
g_tls_interaction_class_init (GTlsInteractionClass *klass)
255
0
{
256
0
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
257
258
0
  gobject_class->finalize = g_tls_interaction_finalize;
259
0
}
260
261
static gboolean
262
on_invoke_ask_password_sync (gpointer user_data)
263
0
{
264
0
  InvokeClosure *closure = user_data;
265
0
  GTlsInteractionClass *klass;
266
267
0
  g_mutex_lock (&closure->mutex);
268
269
0
  klass = G_TLS_INTERACTION_GET_CLASS (closure->interaction);
270
0
  g_assert (klass->ask_password);
271
272
0
  closure->result = klass->ask_password (closure->interaction,
273
0
                                         G_TLS_PASSWORD (closure->argument),
274
0
                                         closure->cancellable,
275
0
                                         &closure->error);
276
277
0
  closure->complete = TRUE;
278
0
  g_cond_signal (&closure->cond);
279
0
  g_mutex_unlock (&closure->mutex);
280
281
0
  return FALSE; /* don't call again */
282
0
}
283
284
static void
285
on_ask_password_complete (GObject      *source,
286
                          GAsyncResult *result,
287
                          gpointer      user_data)
288
0
{
289
0
  InvokeClosure *closure = user_data;
290
0
  GTlsInteractionClass *klass;
291
292
0
  g_mutex_lock (&closure->mutex);
293
294
0
  klass = G_TLS_INTERACTION_GET_CLASS (closure->interaction);
295
0
  g_assert (klass->ask_password_finish);
296
297
0
  closure->result = klass->ask_password_finish (closure->interaction,
298
0
                                                result,
299
0
                                                &closure->error);
300
301
0
  closure->complete = TRUE;
302
0
  g_cond_signal (&closure->cond);
303
0
  g_mutex_unlock (&closure->mutex);
304
0
}
305
306
static gboolean
307
on_invoke_ask_password_async_as_sync (gpointer user_data)
308
0
{
309
0
  InvokeClosure *closure = user_data;
310
0
  GTlsInteractionClass *klass;
311
312
0
  g_mutex_lock (&closure->mutex);
313
314
0
  klass = G_TLS_INTERACTION_GET_CLASS (closure->interaction);
315
0
  g_assert (klass->ask_password_async);
316
317
0
  klass->ask_password_async (closure->interaction,
318
0
                             G_TLS_PASSWORD (closure->argument),
319
0
                             closure->cancellable,
320
0
                             on_ask_password_complete,
321
0
                             closure);
322
323
  /* Note that we've used these */
324
0
  closure->callback = NULL;
325
0
  closure->user_data = NULL;
326
327
0
  g_mutex_unlock (&closure->mutex);
328
329
0
  return FALSE; /* don't call again */
330
0
}
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
0
{
369
0
  GTlsInteractionResult result;
370
0
  InvokeClosure *closure;
371
0
  GTlsInteractionClass *klass;
372
373
0
  g_return_val_if_fail (G_IS_TLS_INTERACTION (interaction), G_TLS_INTERACTION_UNHANDLED);
374
0
  g_return_val_if_fail (G_IS_TLS_PASSWORD (password), G_TLS_INTERACTION_UNHANDLED);
375
0
  g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), G_TLS_INTERACTION_UNHANDLED);
376
377
0
  klass = G_TLS_INTERACTION_GET_CLASS (interaction);
378
379
0
  if (klass->ask_password)
380
0
    {
381
0
      closure = invoke_closure_new (interaction, G_OBJECT (password), cancellable);
382
0
      g_main_context_invoke (interaction->priv->context,
383
0
                             on_invoke_ask_password_sync, closure);
384
0
      result = invoke_closure_wait_and_free (closure, error);
385
0
    }
386
0
  else if (klass->ask_password_async)
387
0
    {
388
0
      g_return_val_if_fail (klass->ask_password_finish, G_TLS_INTERACTION_UNHANDLED);
389
390
0
      closure = invoke_closure_new (interaction, G_OBJECT (password), cancellable);
391
0
      g_main_context_invoke (interaction->priv->context,
392
0
                             on_invoke_ask_password_async_as_sync, closure);
393
394
0
      result = invoke_closure_complete_and_free (interaction, closure, error);
395
0
    }
396
0
  else
397
0
    {
398
0
      result = G_TLS_INTERACTION_UNHANDLED;
399
0
    }
400
401
0
  return result;
402
0
}
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
0
{
435
0
  GTlsInteractionClass *klass;
436
437
0
  g_return_val_if_fail (G_IS_TLS_INTERACTION (interaction), G_TLS_INTERACTION_UNHANDLED);
438
0
  g_return_val_if_fail (G_IS_TLS_PASSWORD (password), G_TLS_INTERACTION_UNHANDLED);
439
0
  g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), G_TLS_INTERACTION_UNHANDLED);
440
441
0
  klass = G_TLS_INTERACTION_GET_CLASS (interaction);
442
0
  if (klass->ask_password)
443
0
    return (klass->ask_password) (interaction, password, cancellable, error);
444
0
  else
445
0
    return G_TLS_INTERACTION_UNHANDLED;
446
0
}
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
0
{
481
0
  GTlsInteractionClass *klass;
482
0
  GTask *task;
483
484
0
  g_return_if_fail (G_IS_TLS_INTERACTION (interaction));
485
0
  g_return_if_fail (G_IS_TLS_PASSWORD (password));
486
0
  g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
487
488
0
  klass = G_TLS_INTERACTION_GET_CLASS (interaction);
489
0
  if (klass->ask_password_async)
490
0
    {
491
0
      g_return_if_fail (klass->ask_password_finish);
492
0
      (klass->ask_password_async) (interaction, password, cancellable,
493
0
                                   callback, user_data);
494
0
    }
495
0
  else
496
0
    {
497
0
      task = g_task_new (interaction, cancellable, callback, user_data);
498
0
      g_task_set_source_tag (task, g_tls_interaction_ask_password_async);
499
0
      g_task_return_int (task, G_TLS_INTERACTION_UNHANDLED);
500
0
      g_object_unref (task);
501
0
    }
502
0
}
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
0
{
529
0
  GTlsInteractionClass *klass;
530
531
0
  g_return_val_if_fail (G_IS_TLS_INTERACTION (interaction), G_TLS_INTERACTION_UNHANDLED);
532
0
  g_return_val_if_fail (G_IS_ASYNC_RESULT (result), G_TLS_INTERACTION_UNHANDLED);
533
534
0
  klass = G_TLS_INTERACTION_GET_CLASS (interaction);
535
0
  if (klass->ask_password_finish)
536
0
    {
537
0
      g_return_val_if_fail (klass->ask_password_async != NULL, G_TLS_INTERACTION_UNHANDLED);
538
539
0
      return (klass->ask_password_finish) (interaction, result, error);
540
0
    }
541
0
  else
542
0
    {
543
0
      g_return_val_if_fail (g_async_result_is_tagged (result, g_tls_interaction_ask_password_async), G_TLS_INTERACTION_UNHANDLED);
544
545
0
      return g_task_propagate_int (G_TASK (result), error);
546
0
    }
547
0
}
548
549
static gboolean
550
on_invoke_request_certificate_sync (gpointer user_data)
551
0
{
552
0
  InvokeClosure *closure = user_data;
553
0
  GTlsInteractionClass *klass;
554
555
0
  g_mutex_lock (&closure->mutex);
556
557
0
  klass = G_TLS_INTERACTION_GET_CLASS (closure->interaction);
558
0
  g_assert (klass->request_certificate != NULL);
559
560
0
  closure->result = klass->request_certificate (closure->interaction,
561
0
                                                G_TLS_CONNECTION (closure->argument),
562
0
                                                0,
563
0
                                                closure->cancellable,
564
0
                                                &closure->error);
565
566
0
  closure->complete = TRUE;
567
0
  g_cond_signal (&closure->cond);
568
0
  g_mutex_unlock (&closure->mutex);
569
570
0
  return FALSE; /* don't call again */
571
0
}
572
573
static void
574
on_request_certificate_complete (GObject      *source,
575
                                 GAsyncResult *result,
576
                                 gpointer      user_data)
577
0
{
578
0
  InvokeClosure *closure = user_data;
579
0
  GTlsInteractionClass *klass;
580
581
0
  g_mutex_lock (&closure->mutex);
582
583
0
  klass = G_TLS_INTERACTION_GET_CLASS (closure->interaction);
584
0
  g_assert (klass->request_certificate_finish != NULL);
585
586
0
  closure->result = klass->request_certificate_finish (closure->interaction,
587
0
                                                       result, &closure->error);
588
589
0
  closure->complete = TRUE;
590
0
  g_cond_signal (&closure->cond);
591
0
  g_mutex_unlock (&closure->mutex);
592
0
}
593
594
static gboolean
595
on_invoke_request_certificate_async_as_sync (gpointer user_data)
596
0
{
597
0
  InvokeClosure *closure = user_data;
598
0
  GTlsInteractionClass *klass;
599
600
0
  g_mutex_lock (&closure->mutex);
601
602
0
  klass = G_TLS_INTERACTION_GET_CLASS (closure->interaction);
603
0
  g_assert (klass->request_certificate_async);
604
605
0
  klass->request_certificate_async (closure->interaction,
606
0
                                    G_TLS_CONNECTION (closure->argument), 0,
607
0
                                    closure->cancellable,
608
0
                                    on_request_certificate_complete,
609
0
                                    closure);
610
611
  /* Note that we've used these */
612
0
  closure->callback = NULL;
613
0
  closure->user_data = NULL;
614
615
0
  g_mutex_unlock (&closure->mutex);
616
617
0
  return FALSE; /* don't call again */
618
0
}
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
0
{
660
0
  GTlsInteractionResult result;
661
0
  InvokeClosure *closure;
662
0
  GTlsInteractionClass *klass;
663
664
0
  g_return_val_if_fail (G_IS_TLS_INTERACTION (interaction), G_TLS_INTERACTION_UNHANDLED);
665
0
  g_return_val_if_fail (G_IS_TLS_CONNECTION (connection), G_TLS_INTERACTION_UNHANDLED);
666
0
  g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), G_TLS_INTERACTION_UNHANDLED);
667
668
0
  klass = G_TLS_INTERACTION_GET_CLASS (interaction);
669
670
0
  if (klass->request_certificate)
671
0
    {
672
0
      closure = invoke_closure_new (interaction, G_OBJECT (connection), cancellable);
673
0
      g_main_context_invoke (interaction->priv->context,
674
0
                             on_invoke_request_certificate_sync, closure);
675
0
      result = invoke_closure_wait_and_free (closure, error);
676
0
    }
677
0
  else if (klass->request_certificate_async)
678
0
    {
679
0
      g_return_val_if_fail (klass->request_certificate_finish, G_TLS_INTERACTION_UNHANDLED);
680
681
0
      closure = invoke_closure_new (interaction, G_OBJECT (connection), cancellable);
682
0
      g_main_context_invoke (interaction->priv->context,
683
0
                             on_invoke_request_certificate_async_as_sync, closure);
684
685
0
      result = invoke_closure_complete_and_free (interaction, closure, error);
686
0
    }
687
0
  else
688
0
    {
689
0
      result = G_TLS_INTERACTION_UNHANDLED;
690
0
    }
691
692
0
  return result;
693
0
}
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
0
{
731
0
  GTlsInteractionClass *klass;
732
733
0
  g_return_val_if_fail (G_IS_TLS_INTERACTION (interaction), G_TLS_INTERACTION_UNHANDLED);
734
0
  g_return_val_if_fail (G_IS_TLS_CONNECTION (connection), G_TLS_INTERACTION_UNHANDLED);
735
0
  g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), G_TLS_INTERACTION_UNHANDLED);
736
737
0
  klass = G_TLS_INTERACTION_GET_CLASS (interaction);
738
0
  if (klass->request_certificate)
739
0
    return (klass->request_certificate) (interaction, connection, flags, cancellable, error);
740
0
  else
741
0
    return G_TLS_INTERACTION_UNHANDLED;
742
0
}
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
0
{
772
0
  GTlsInteractionClass *klass;
773
0
  GTask *task;
774
775
0
  g_return_if_fail (G_IS_TLS_INTERACTION (interaction));
776
0
  g_return_if_fail (G_IS_TLS_CONNECTION (connection));
777
0
  g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
778
779
0
  klass = G_TLS_INTERACTION_GET_CLASS (interaction);
780
0
  if (klass->request_certificate_async)
781
0
    {
782
0
      g_return_if_fail (klass->request_certificate_finish);
783
0
      (klass->request_certificate_async) (interaction, connection, flags,
784
0
                                          cancellable, callback, user_data);
785
0
    }
786
0
  else
787
0
    {
788
0
      task = g_task_new (interaction, cancellable, callback, user_data);
789
0
      g_task_set_source_tag (task, g_tls_interaction_request_certificate_async);
790
0
      g_task_return_int (task, G_TLS_INTERACTION_UNHANDLED);
791
0
      g_object_unref (task);
792
0
    }
793
0
}
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
0
{
821
0
  GTlsInteractionClass *klass;
822
823
0
  g_return_val_if_fail (G_IS_TLS_INTERACTION (interaction), G_TLS_INTERACTION_UNHANDLED);
824
0
  g_return_val_if_fail (G_IS_ASYNC_RESULT (result), G_TLS_INTERACTION_UNHANDLED);
825
826
0
  klass = G_TLS_INTERACTION_GET_CLASS (interaction);
827
0
  if (klass->request_certificate_finish)
828
0
    {
829
0
      g_return_val_if_fail (klass->request_certificate_async != NULL, G_TLS_INTERACTION_UNHANDLED);
830
831
0
      return (klass->request_certificate_finish) (interaction, result, error);
832
0
    }
833
0
  else
834
0
    {
835
0
      g_return_val_if_fail (g_async_result_is_tagged (result, g_tls_interaction_request_certificate_async), G_TLS_INTERACTION_UNHANDLED);
836
837
0
      return g_task_propagate_int (G_TASK (result), error);
838
0
    }
839
0
}