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