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