1 /*
2 * Seahorse
3 *
4 * Copyright (C) 2004 - 2006 Stefan Walter
5 * Copyright (C) 2011 Collabora Ltd.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program 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.
15 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see
18 * <http://www.gnu.org/licenses/>.
19 */
20
21 #include "config.h"
22
23 #include <string.h>
24 #include <stdlib.h>
25 #include <errno.h>
26
27 #include <glib/gi18n.h>
28
29 #include "seahorse-ldap-source.h"
30
31 #include "seahorse-pgp-key.h"
32 #include "seahorse-pgp-subkey.h"
33 #include "seahorse-pgp-uid.h"
34
35 #include "seahorse-common.h"
36
37 #include "libseahorse/seahorse-progress.h"
38 #include "libseahorse/seahorse-util.h"
39
40 #include <ldap.h>
41
42 #ifdef WITH_LDAP
43
44 /* Amount of keys to load in a batch */
45 #define DEFAULT_LOAD_BATCH 30
46
47 struct _SeahorseLDAPSource {
48 SeahorseServerSource parent;
49 };
50
51 /* -----------------------------------------------------------------------------
52 * SERVER INFO
53 */
54
55 typedef struct _LDAPServerInfo {
56 char *base_dn; /* The base dn where PGP keys are found */
57 char *key_attr; /* The attribute of PGP key data */
58 guint version; /* The version of the PGP server software */
59 } LDAPServerInfo;
60
61 static void
free_ldap_server_info(LDAPServerInfo * sinfo)62 free_ldap_server_info (LDAPServerInfo *sinfo)
63 {
64 if (sinfo) {
65 g_free (sinfo->base_dn);
66 g_free (sinfo->key_attr);
67 g_free (sinfo);
68 }
69 }
70
71 static void
set_ldap_server_info(SeahorseLDAPSource * lsrc,LDAPServerInfo * sinfo)72 set_ldap_server_info (SeahorseLDAPSource *lsrc, LDAPServerInfo *sinfo)
73 {
74 g_object_set_data_full (G_OBJECT (lsrc), "server-info", sinfo,
75 (GDestroyNotify)free_ldap_server_info);
76 }
77
78 static LDAPServerInfo*
get_ldap_server_info(SeahorseLDAPSource * lsrc,gboolean force)79 get_ldap_server_info (SeahorseLDAPSource *lsrc, gboolean force)
80 {
81 LDAPServerInfo *sinfo;
82
83 sinfo = g_object_get_data (G_OBJECT (lsrc), "server-info");
84
85 /* When we're asked to force getting the data, we fill in
86 * some defaults */
87 if (!sinfo && force) {
88 sinfo = g_new0 (LDAPServerInfo, 1);
89 sinfo->base_dn = g_strdup ("OU=ACTIVE,O=PGP KEYSPACE,C=US");
90 sinfo->key_attr = g_strdup ("pgpKey");
91 sinfo->version = 0;
92 set_ldap_server_info (lsrc, sinfo);
93 }
94
95 return sinfo;
96 }
97
98 static void
destroy_ldap(gpointer data)99 destroy_ldap (gpointer data)
100 {
101 if (data)
102 ldap_unbind_ext ((LDAP *) data, NULL, NULL);
103 }
104
105 /* -----------------------------------------------------------------------------
106 * LDAP HELPERS
107 */
108
109 #define LDAP_ERROR_DOMAIN (get_ldap_error_domain())
110
111 static char**
get_ldap_values(LDAP * ld,LDAPMessage * entry,const char * attribute)112 get_ldap_values (LDAP *ld, LDAPMessage *entry, const char *attribute)
113 {
114 GArray *array;
115 struct berval **bv;
116 char *value;
117 int num, i;
118
119 bv = ldap_get_values_len (ld, entry, attribute);
120 if (!bv)
121 return NULL;
122
123 array = g_array_new (TRUE, TRUE, sizeof (char*));
124 num = ldap_count_values_len (bv);
125 for(i = 0; i < num; i++) {
126 value = g_strndup (bv[i]->bv_val, bv[i]->bv_len);
127 g_array_append_val(array, value);
128 }
129
130 return (char**)g_array_free (array, FALSE);
131 }
132
133 #ifdef WITH_DEBUG
134
135 static void
dump_ldap_entry(LDAP * ld,LDAPMessage * res)136 dump_ldap_entry (LDAP *ld, LDAPMessage *res)
137 {
138 BerElement *pos;
139 char *t;
140
141 t = ldap_get_dn (ld, res);
142 g_debug ("dn: %s", t);
143 ldap_memfree (t);
144
145 for (t = ldap_first_attribute (ld, res, &pos); t;
146 t = ldap_next_attribute (ld, res, pos)) {
147 g_auto(GStrv) values = NULL;
148
149 values = get_ldap_values (ld, res, t);
150 for (char **v = values; *v; v++)
151 g_debug ("%s: %s", t, *v);
152
153 ldap_memfree (t);
154 }
155
156 ber_free (pos, 0);
157 }
158
159 #endif /* WITH_DEBUG */
160
161 static GQuark
get_ldap_error_domain()162 get_ldap_error_domain ()
163 {
164 static GQuark q = 0;
165 if(q == 0)
166 q = g_quark_from_static_string ("seahorse-ldap-error");
167 return q;
168 }
169
170 static char*
get_string_attribute(LDAP * ld,LDAPMessage * res,const char * attribute)171 get_string_attribute (LDAP *ld, LDAPMessage *res, const char *attribute)
172 {
173 g_auto(GStrv) vals = NULL;
174 char *v;
175
176 vals = get_ldap_values (ld, res, attribute);
177 if (!vals)
178 return NULL;
179 v = vals[0] ? g_strdup (vals[0]) : NULL;
180 return v;
181 }
182
183 static gboolean
get_boolean_attribute(LDAP * ld,LDAPMessage * res,const char * attribute)184 get_boolean_attribute (LDAP* ld, LDAPMessage *res, const char *attribute)
185 {
186 g_auto(GStrv) vals = NULL;
187 gboolean b;
188
189 vals = get_ldap_values (ld, res, attribute);
190 if (!vals)
191 return FALSE;
192 b = vals[0] && atoi (vals[0]) == 1;
193 return b;
194 }
195
196 static long int
get_int_attribute(LDAP * ld,LDAPMessage * res,const char * attribute)197 get_int_attribute (LDAP* ld, LDAPMessage *res, const char *attribute)
198 {
199 g_auto(GStrv) vals = NULL;
200 long int d;
201
202 vals = get_ldap_values (ld, res, attribute);
203 if (!vals)
204 return 0;
205 d = vals[0] ? atoi (vals[0]) : 0;
206 return d;
207 }
208
209 static long int
get_date_attribute(LDAP * ld,LDAPMessage * res,const char * attribute)210 get_date_attribute (LDAP* ld, LDAPMessage *res, const char *attribute)
211 {
212 g_auto(GStrv) vals = NULL;
213 struct tm t;
214 long int d = 0;
215
216 vals = get_ldap_values (ld, res, attribute);
217 if (!vals)
218 return 0;
219
220 if (vals[0]) {
221 memset(&t, 0, sizeof (t));
222
223 /* YYYYMMDDHHmmssZ */
224 sscanf(vals[0], "%4d%2d%2d%2d%2d%2d",
225 &t.tm_year, &t.tm_mon, &t.tm_mday,
226 &t.tm_hour, &t.tm_min, &t.tm_sec);
227
228 t.tm_year -= 1900;
229 t.tm_isdst = -1;
230 t.tm_mon--;
231
232 d = mktime (&t);
233 }
234
235 return d;
236 }
237
238 static const char*
get_algo_attribute(LDAP * ld,LDAPMessage * res,const char * attribute)239 get_algo_attribute (LDAP* ld, LDAPMessage *res, const char *attribute)
240 {
241 g_auto(GStrv) vals = NULL;
242 const char *a = NULL;
243
244 vals = get_ldap_values (ld, res, attribute);
245 if (!vals)
246 return 0;
247
248 if (vals[0]) {
249 if (g_ascii_strcasecmp (vals[0], "DH/DSS") == 0 ||
250 g_ascii_strcasecmp (vals[0], "Elg") == 0 ||
251 g_ascii_strcasecmp (vals[0], "Elgamal") == 0 ||
252 g_ascii_strcasecmp (vals[0], "DSS/DH") == 0)
253 a = "Elgamal";
254 if (g_ascii_strcasecmp (vals[0], "RSA") == 0)
255 a = "RSA";
256 if (g_ascii_strcasecmp (vals[0], "DSA") == 0)
257 a = "DSA";
258 }
259
260 return a;
261 }
262
263 /*
264 * Escapes a value so it's safe to use in an LDAP filter. Also trims
265 * any spaces which cause problems with some LDAP servers.
266 */
267 static char*
escape_ldap_value(const char * v)268 escape_ldap_value (const char *v)
269 {
270 GString *value;
271 char* result;
272
273 g_assert (v);
274 value = g_string_sized_new (strlen(v));
275
276 for ( ; *v; v++) {
277 switch(*v) {
278 case '#': case ',': case '+': case '\\':
279 case '/': case '\"': case '<': case '>': case ';':
280 value = g_string_append_c (value, '\\');
281 value = g_string_append_c (value, *v);
282 continue;
283 };
284
285 if(*v < 32 || *v > 126) {
286 g_string_append_printf (value, "\\%02X", *v);
287 continue;
288 }
289
290 value = g_string_append_c (value, *v);
291 }
292
293 result = g_string_free (value, FALSE);
294 g_strstrip (result);
295 return result;
296 }
297
298 typedef gboolean (*SeahorseLdapCallback) (LDAPMessage *result,
299 gpointer user_data);
300
301 typedef struct {
302 GSource source;
303 LDAP *ldap;
304 int ldap_op;
305 GCancellable *cancellable;
306 gboolean cancelled;
307 int cancelled_sig;
308 } SeahorseLdapGSource;
309
310 static gboolean
seahorse_ldap_gsource_prepare(GSource * gsource,int * timeout)311 seahorse_ldap_gsource_prepare (GSource *gsource,
312 int *timeout)
313 {
314 SeahorseLdapGSource *ldap_gsource = (SeahorseLdapGSource *)gsource;
315
316 if (ldap_gsource->cancelled)
317 return TRUE;
318
319 /* No other way, but to poll */
320 *timeout = 50;
321 return FALSE;
322 }
323
324 static gboolean
seahorse_ldap_gsource_check(GSource * gsource)325 seahorse_ldap_gsource_check (GSource *gsource)
326 {
327 return TRUE;
328 }
329
330 static gboolean
seahorse_ldap_gsource_dispatch(GSource * gsource,GSourceFunc callback,gpointer user_data)331 seahorse_ldap_gsource_dispatch (GSource *gsource,
332 GSourceFunc callback,
333 gpointer user_data)
334 {
335 SeahorseLdapGSource *ldap_gsource = (SeahorseLdapGSource *)gsource;
336 struct timeval timeout;
337 LDAPMessage *result;
338 gboolean ret;
339 int rc, i;
340
341 if (ldap_gsource->cancelled) {
342 ((SeahorseLdapCallback)callback) (NULL, user_data);
343 return FALSE;
344 }
345
346 for (i = 0; i < DEFAULT_LOAD_BATCH; i++) {
347
348 /* This effects a poll */
349 timeout.tv_sec = 0;
350 timeout.tv_usec = 0;
351
352 rc = ldap_result (ldap_gsource->ldap, ldap_gsource->ldap_op,
353 0, &timeout, &result);
354 if (rc == -1) {
355 g_warning ("ldap_result failed with rc = %d, errno = %s",
356 rc, g_strerror (errno));
357 return G_SOURCE_REMOVE;
358 }
359
360 /* Timeout */
361 if (rc == 0)
362 return G_SOURCE_CONTINUE;
363
364 ret = ((SeahorseLdapCallback)callback) (result, user_data);
365 ldap_msgfree (result);
366
367 if (!ret)
368 return G_SOURCE_REMOVE;
369 }
370
371 return G_SOURCE_CONTINUE;
372 }
373
374 static void
seahorse_ldap_gsource_finalize(GSource * gsource)375 seahorse_ldap_gsource_finalize (GSource *gsource)
376 {
377 SeahorseLdapGSource *ldap_gsource = (SeahorseLdapGSource *)gsource;
378 g_cancellable_disconnect (ldap_gsource->cancellable,
379 ldap_gsource->cancelled_sig);
380 g_clear_object (&ldap_gsource->cancellable);
381 }
382
383 static GSourceFuncs seahorse_ldap_gsource_funcs = {
384 seahorse_ldap_gsource_prepare,
385 seahorse_ldap_gsource_check,
386 seahorse_ldap_gsource_dispatch,
387 seahorse_ldap_gsource_finalize,
388 };
389
390 static void
on_ldap_gsource_cancelled(GCancellable * cancellable,gpointer user_data)391 on_ldap_gsource_cancelled (GCancellable *cancellable,
392 gpointer user_data)
393 {
394 SeahorseLdapGSource *ldap_gsource = user_data;
395 ldap_gsource->cancelled = TRUE;
396 }
397
398 static GSource *
seahorse_ldap_gsource_new(LDAP * ldap,int ldap_op,GCancellable * cancellable)399 seahorse_ldap_gsource_new (LDAP *ldap,
400 int ldap_op,
401 GCancellable *cancellable)
402 {
403 GSource *gsource;
404 SeahorseLdapGSource *ldap_gsource;
405
406 gsource = g_source_new (&seahorse_ldap_gsource_funcs,
407 sizeof (SeahorseLdapGSource));
408
409 ldap_gsource = (SeahorseLdapGSource *)gsource;
410 ldap_gsource->ldap = ldap;
411 ldap_gsource->ldap_op = ldap_op;
412
413 if (cancellable) {
414 ldap_gsource->cancellable = g_object_ref (cancellable);
415 ldap_gsource->cancelled_sig = g_cancellable_connect (cancellable,
416 G_CALLBACK (on_ldap_gsource_cancelled),
417 ldap_gsource, NULL);
418 }
419
420 return gsource;
421 }
422
423 static gboolean
seahorse_ldap_source_propagate_error(SeahorseLDAPSource * self,int rc,GError ** error)424 seahorse_ldap_source_propagate_error (SeahorseLDAPSource *self,
425 int rc, GError **error)
426 {
427 g_autofree char *uri = NULL;
428
429 if (rc == LDAP_SUCCESS)
430 return FALSE;
431
432 uri = seahorse_place_get_uri (SEAHORSE_PLACE (self));
433 g_set_error (error, LDAP_ERROR_DOMAIN, rc, _("Couldn’t communicate with %s: %s"),
434 uri, ldap_err2string (rc));
435
436 return TRUE;
437 }
438
439 typedef struct {
440 LDAP *ldap;
441 } ConnectClosure;
442
443 static void
connect_closure_free(gpointer data)444 connect_closure_free (gpointer data)
445 {
446 ConnectClosure *closure = data;
447 if (closure->ldap)
448 ldap_unbind_ext (closure->ldap, NULL, NULL);
449 g_free (closure);
450 }
451
452 static gboolean
on_connect_server_info_completed(LDAPMessage * result,gpointer user_data)453 on_connect_server_info_completed (LDAPMessage *result,
454 gpointer user_data)
455 {
456 GTask *task = G_TASK (user_data);
457 ConnectClosure *closure = g_task_get_task_data (task);
458 GCancellable *cancellable = g_task_get_cancellable (task);
459 SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (g_task_get_source_object (task));
460 char *message;
461 int code;
462 int type;
463 int rc;
464
465 type = ldap_msgtype (result);
466 g_return_val_if_fail (type == LDAP_RES_SEARCH_ENTRY || type == LDAP_RES_SEARCH_RESULT, FALSE);
467
468 /* If we have results then fill in the server info */
469 if (type == LDAP_RES_SEARCH_ENTRY) {
470 LDAPServerInfo *sinfo;
471
472 g_debug ("Server Info Result");
473 #ifdef WITH_DEBUG
474 dump_ldap_entry (closure->ldap, result);
475 #endif
476
477 /* NOTE: When adding attributes here make sure to add them to kServerAttributes */
478 sinfo = g_new0 (LDAPServerInfo, 1);
479 sinfo->version = get_int_attribute (closure->ldap, result, "version");
480 sinfo->base_dn = get_string_attribute (closure->ldap, result, "basekeyspacedn");
481 if (!sinfo->base_dn)
482 sinfo->base_dn = get_string_attribute (closure->ldap, result, "pgpbasekeyspacedn");
483 sinfo->key_attr = g_strdup (sinfo->version > 1 ? "pgpkeyv2" : "pgpkey");
484 set_ldap_server_info (self, sinfo);
485
486 return G_SOURCE_CONTINUE;
487 }
488
489 rc = ldap_parse_result (closure->ldap, result, &code, NULL, &message,
490 NULL, NULL, 0);
491 g_return_val_if_fail (rc == LDAP_SUCCESS, FALSE);
492
493 if (code != LDAP_SUCCESS)
494 g_warning ("operation to get LDAP server info failed: %s", message);
495
496 ldap_memfree (message);
497
498 g_task_return_pointer (task, g_steal_pointer (&closure->ldap), destroy_ldap);
499 seahorse_progress_end (cancellable, task);
500 return G_SOURCE_REMOVE;
501 }
502
503 static const char *SERVER_ATTRIBUTES[] = {
504 "basekeyspacedn",
505 "pgpbasekeyspacedn",
506 "version",
507 NULL
508 };
509
510 static gboolean
on_connect_bind_completed(LDAPMessage * result,gpointer user_data)511 on_connect_bind_completed (LDAPMessage *result,
512 gpointer user_data)
513 {
514 GTask *task = G_TASK (user_data);
515 ConnectClosure *closure = g_task_get_task_data (task);
516 GCancellable *cancellable = g_task_get_cancellable (task);
517 SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (g_task_get_source_object (task));
518 LDAPServerInfo *sinfo;
519 g_autoptr(GError) error = NULL;
520 char *message;
521 int ldap_op;
522 int code;
523 int rc;
524 g_autoptr(GSource) gsource = NULL;
525
526 g_return_val_if_fail (ldap_msgtype (result) == LDAP_RES_BIND, FALSE);
527
528 /* The result of the bind operation */
529 rc = ldap_parse_result (closure->ldap, result, &code, NULL, &message,
530 NULL, NULL, 0);
531 g_return_val_if_fail (rc == LDAP_SUCCESS, FALSE);
532 ldap_memfree (message);
533
534 if (seahorse_ldap_source_propagate_error (self, rc, &error)) {
535 g_task_return_error (task, g_steal_pointer (&error));
536 return G_SOURCE_REMOVE;
537 }
538
539 /* Check if we need server info */
540 sinfo = get_ldap_server_info (self, FALSE);
541 if (sinfo != NULL) {
542 g_task_return_pointer (task, g_steal_pointer (&closure->ldap), destroy_ldap);
543 seahorse_progress_end (cancellable, task);
544 return G_SOURCE_REMOVE;
545 }
546
547 /* Retrieve the server info */
548 rc = ldap_search_ext (closure->ldap, "cn=PGPServerInfo", LDAP_SCOPE_BASE,
549 "(objectclass=*)", (char **)SERVER_ATTRIBUTES, 0,
550 NULL, NULL, NULL, 0, &ldap_op);
551
552 if (seahorse_ldap_source_propagate_error (self, rc, &error)) {
553 g_task_return_error (task, g_steal_pointer (&error));
554 return G_SOURCE_REMOVE;
555 }
556
557 gsource = seahorse_ldap_gsource_new (closure->ldap, ldap_op, cancellable);
558 g_source_set_callback (gsource,
559 G_SOURCE_FUNC (on_connect_server_info_completed),
560 g_object_ref (task), g_object_unref);
561 g_source_attach (gsource, g_main_context_default ());
562
563 return G_SOURCE_REMOVE;
564 }
565
566 static void
on_address_resolved(GObject * src_object,GAsyncResult * res,gpointer user_data)567 on_address_resolved (GObject *src_object,
568 GAsyncResult *res,
569 gpointer user_data)
570 {
571 GSocketAddressEnumerator *enumer = G_SOCKET_ADDRESS_ENUMERATOR (src_object);
572 g_autoptr(GTask) task = user_data;
573 SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (g_task_get_source_object (task));
574 ConnectClosure *closure = g_task_get_task_data (task);
575 GCancellable *cancellable = g_task_get_cancellable (task);
576 g_autofree char *uri = NULL;
577 g_autoptr(GSocketAddress) addr = NULL;
578 g_autoptr(GError) error = NULL;
579 g_autofree char *addr_str = NULL;
580 g_autofree char *resolved_url = NULL;
581 int rc;
582 struct berval cred;
583 int ldap_op;
584 g_autoptr(GSource) gsource = NULL;
585
586 /* Note: this is the original (unresolved) URI */
587 uri = seahorse_place_get_uri (SEAHORSE_PLACE (self));
588
589 /* Get the resolved IP */
590 addr = g_socket_address_enumerator_next_finish (enumer, res, &error);
591 if (!addr) {
592 g_task_return_new_error (task, SEAHORSE_ERROR, -1,
593 _("Couldn’t resolve address %s"), uri);
594 return;
595 }
596
597 /* Now that we've resolved our address, connect via IP */
598 seahorse_progress_update (cancellable, task, _("Connecting to: %s"), uri);
599
600 /* Re-create the URL with the resolved IP */
601 addr_str = g_socket_connectable_to_string (G_SOCKET_CONNECTABLE (addr));
602 resolved_url = g_strdup_printf ("ldap://%s", addr_str);
603 rc = ldap_initialize (&closure->ldap, resolved_url);
604
605 if (seahorse_ldap_source_propagate_error (self, rc, &error)) {
606 g_task_return_error (task, g_steal_pointer (&error));
607 return;
608 }
609
610 /* Start the bind operation */
611 cred.bv_val = "";
612 cred.bv_len = 0;
613
614 rc = ldap_sasl_bind (closure->ldap, NULL, LDAP_SASL_SIMPLE, &cred, NULL,
615 NULL, &ldap_op);
616 if (seahorse_ldap_source_propagate_error (self, rc, &error)) {
617 g_task_return_error (task, g_steal_pointer (&error));
618 return;
619 }
620
621 gsource = seahorse_ldap_gsource_new (closure->ldap, ldap_op, cancellable);
622 g_source_set_callback (gsource, G_SOURCE_FUNC (on_connect_bind_completed),
623 g_object_ref (task), g_object_unref);
624 g_source_attach (gsource, g_main_context_default ());
625 }
626
627 static void
seahorse_ldap_source_connect_async(SeahorseLDAPSource * source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)628 seahorse_ldap_source_connect_async (SeahorseLDAPSource *source,
629 GCancellable *cancellable,
630 GAsyncReadyCallback callback,
631 gpointer user_data)
632 {
633 g_autoptr(GTask) task = NULL;
634 ConnectClosure *closure;
635 g_autofree char *uri = NULL;
636 g_autoptr(GSocketConnectable) addr = NULL;
637 g_autoptr(GSocketAddressEnumerator) addr_enumer = NULL;
638 g_autoptr(GError) error = NULL;
639
640 task = g_task_new (source, cancellable, callback, user_data);
641 g_task_set_source_tag (task, seahorse_ldap_source_connect_async);
642
643 closure = g_new0 (ConnectClosure, 1);
644 g_task_set_task_data (task, closure, connect_closure_free);
645
646 /* Take the URI & turn it into a GNetworkAddress, to do address resolving */
647 uri = seahorse_place_get_uri (SEAHORSE_PLACE (source));
648 g_return_if_fail (uri && uri[0]);
649
650 addr = g_network_address_parse_uri (uri, LDAP_PORT, &error);
651 if (!addr) {
652 g_task_return_new_error (task, SEAHORSE_ERROR, -1,
653 _("Invalid URI: %s"), uri);
654 return;
655 }
656
657 seahorse_progress_prep_and_begin (cancellable, task, NULL);
658
659 /* Now get a GSocketAddressEnumerator to do the resolving */
660 seahorse_progress_update (cancellable, task,
661 _("Resolving server address: %s"), uri);
662
663 addr_enumer = g_socket_connectable_enumerate (addr);
664 g_socket_address_enumerator_next_async (addr_enumer,
665 cancellable,
666 on_address_resolved,
667 g_steal_pointer (&task));
668 }
669
670 static LDAP *
seahorse_ldap_source_connect_finish(SeahorseLDAPSource * source,GAsyncResult * result,GError ** error)671 seahorse_ldap_source_connect_finish (SeahorseLDAPSource *source,
672 GAsyncResult *result,
673 GError **error)
674 {
675 g_return_val_if_fail (g_task_is_valid (result, source), NULL);
676 g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) ==
677 seahorse_ldap_source_connect_async, NULL);
678
679 return g_task_propagate_pointer (G_TASK (result), error);
680 }
681
682 G_DEFINE_TYPE (SeahorseLDAPSource, seahorse_ldap_source, SEAHORSE_TYPE_SERVER_SOURCE);
683
684 static void
seahorse_ldap_source_init(SeahorseLDAPSource * self)685 seahorse_ldap_source_init (SeahorseLDAPSource *self)
686 {
687 }
688
689 typedef struct {
690 char *filter;
691 LDAP *ldap;
692 GcrSimpleCollection *results;
693 } SearchClosure;
694
695 static void
search_closure_free(gpointer data)696 search_closure_free (gpointer data)
697 {
698 SearchClosure *closure = data;
699 g_clear_object (&closure->results);
700 g_free (closure->filter);
701 if (closure->ldap)
702 ldap_unbind_ext (closure->ldap, NULL, NULL);
703 g_free (closure);
704 }
705
706 static const char *PGP_ATTRIBUTES[] = {
707 "pgpcertid",
708 "pgpuserid",
709 "pgprevoked",
710 "pgpdisabled",
711 "pgpkeycreatetime",
712 "pgpkeyexpiretime"
713 "pgpkeysize",
714 "pgpkeytype",
715 NULL
716 };
717
718 /* Add a key to the key source from an LDAP entry */
719 static void
search_parse_key_from_ldap_entry(SeahorseLDAPSource * self,GcrSimpleCollection * results,LDAP * ldap,LDAPMessage * res)720 search_parse_key_from_ldap_entry (SeahorseLDAPSource *self,
721 GcrSimpleCollection *results,
722 LDAP *ldap,
723 LDAPMessage *res)
724 {
725 const char *algo;
726 long int timestamp;
727 long int expires;
728 g_autofree char *fpr = NULL;
729 g_autofree char *uidstr = NULL;
730 gboolean revoked;
731 gboolean disabled;
732 int length;
733
734 g_return_if_fail (ldap_msgtype (res) == LDAP_RES_SEARCH_ENTRY);
735
736 fpr = get_string_attribute (ldap, res, "pgpcertid");
737 uidstr = get_string_attribute (ldap, res, "pgpuserid");
738 revoked = get_boolean_attribute (ldap, res, "pgprevoked");
739 disabled = get_boolean_attribute (ldap, res, "pgpdisabled");
740 timestamp = get_date_attribute (ldap, res, "pgpkeycreatetime");
741 expires = get_date_attribute (ldap, res, "pgpkeyexpiretime");
742 algo = get_algo_attribute (ldap, res, "pgpkeytype");
743 length = get_int_attribute (ldap, res, "pgpkeysize");
744
745 if (fpr && uidstr) {
746 g_autoptr (SeahorsePgpSubkey) subkey = NULL;
747 g_autoptr(SeahorsePgpKey) key = NULL;
748 g_autofree char *fingerprint = NULL;
749 g_autoptr(SeahorsePgpUid) uid = NULL;
750 guint flags;
751
752 /* Build up a subkey */
753 subkey = seahorse_pgp_subkey_new ();
754 seahorse_pgp_subkey_set_keyid (subkey, fpr);
755 fingerprint = seahorse_pgp_subkey_calc_fingerprint (fpr);
756 seahorse_pgp_subkey_set_fingerprint (subkey, fingerprint);
757 seahorse_pgp_subkey_set_algorithm (subkey, algo);
758 seahorse_pgp_subkey_set_length (subkey, length);
759
760 if (timestamp > 0) {
761 g_autoptr(GDateTime) created_date = NULL;
762 created_date = g_date_time_new_from_unix_utc (timestamp);
763 seahorse_pgp_subkey_set_created (subkey, created_date);
764 }
765 if (expires > 0) {
766 g_autoptr(GDateTime) expires_date = NULL;
767 expires_date = g_date_time_new_from_unix_utc (expires);
768 seahorse_pgp_subkey_set_expires (subkey, expires_date);
769 }
770
771 flags = SEAHORSE_FLAG_EXPORTABLE;
772 if (revoked)
773 flags |= SEAHORSE_FLAG_REVOKED;
774 if (disabled)
775 flags |= SEAHORSE_FLAG_DISABLED;
776 seahorse_pgp_subkey_set_flags (subkey, flags);
777
778 key = seahorse_pgp_key_new ();
779
780 /* Build up a uid */
781 uid = seahorse_pgp_uid_new (key, uidstr);
782 if (revoked)
783 seahorse_pgp_uid_set_validity (uid, SEAHORSE_VALIDITY_REVOKED);
784 seahorse_pgp_key_add_uid (key, uid);
785
786 /* Now build them into a key */
787 seahorse_pgp_key_add_subkey (key, subkey);
788 g_object_set (key,
789 "object-flags", flags,
790 "place", self,
791 NULL);
792
793 seahorse_pgp_key_realize (key);
794 gcr_simple_collection_add (results, G_OBJECT (key));
795 }
796 }
797
798 static gboolean
on_search_search_completed(LDAPMessage * result,gpointer user_data)799 on_search_search_completed (LDAPMessage *result,
800 gpointer user_data)
801 {
802 GTask *task = G_TASK (user_data);
803 SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (g_task_get_source_object (task));
804 SearchClosure *closure = g_task_get_task_data (task);
805 GCancellable *cancellable = g_task_get_cancellable (task);
806 g_autoptr(GError) error = NULL;
807 int type;
808 int rc;
809 int code;
810 char *message;
811
812 type = ldap_msgtype (result);
813 g_return_val_if_fail (type == LDAP_RES_SEARCH_ENTRY || type == LDAP_RES_SEARCH_RESULT, FALSE);
814
815 /* An LDAP entry */
816 if (type == LDAP_RES_SEARCH_ENTRY) {
817 g_debug ("Retrieved Key Entry");
818 #ifdef WITH_DEBUG
819 dump_ldap_entry (closure->ldap, result);
820 #endif
821
822 search_parse_key_from_ldap_entry (self, closure->results,
823 closure->ldap, result);
824 return G_SOURCE_CONTINUE;
825 }
826
827 /* All entries done */
828 rc = ldap_parse_result (closure->ldap, result, &code, NULL,
829 &message, NULL, NULL, 0);
830 g_return_val_if_fail (rc == LDAP_SUCCESS, FALSE);
831
832 /* Error codes that we ignore */
833 switch (code) {
834 case LDAP_SIZELIMIT_EXCEEDED:
835 code = LDAP_SUCCESS;
836 break;
837 };
838
839 if (code != LDAP_SUCCESS)
840 g_task_return_new_error (task, LDAP_ERROR_DOMAIN, code, "%s", message);
841 else if (seahorse_ldap_source_propagate_error (self, code, &error))
842 g_task_return_error (task, g_steal_pointer (&error));
843 else
844 g_task_return_boolean (task, TRUE);
845
846 ldap_memfree (message);
847 seahorse_progress_end (cancellable, task);
848
849 return G_SOURCE_REMOVE;
850 }
851
852 static void
on_search_connect_completed(GObject * source,GAsyncResult * result,gpointer user_data)853 on_search_connect_completed (GObject *source,
854 GAsyncResult *result,
855 gpointer user_data)
856 {
857 SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (source);
858 g_autoptr(GTask) task = G_TASK (user_data);
859 SearchClosure *closure = g_task_get_task_data (task);
860 GCancellable *cancellable = g_task_get_cancellable (task);
861 g_autoptr(GError) error = NULL;
862 LDAPServerInfo *sinfo;
863 int ldap_op;
864 int rc;
865 g_autoptr(GSource) gsource = NULL;
866
867 closure->ldap = seahorse_ldap_source_connect_finish (self, result, &error);
868 if (error != NULL) {
869 g_task_return_error (task, g_steal_pointer (&error));
870 return;
871 }
872
873 sinfo = get_ldap_server_info (self, TRUE);
874
875 g_debug ("Searching Server ... base: %s, filter: %s",
876 sinfo->base_dn, closure->filter);
877
878 rc = ldap_search_ext (closure->ldap, sinfo->base_dn, LDAP_SCOPE_SUBTREE,
879 closure->filter, (char **)PGP_ATTRIBUTES, 0,
880 NULL, NULL, NULL, 0, &ldap_op);
881
882 if (seahorse_ldap_source_propagate_error (self, rc, &error)) {
883 g_task_return_error (task, g_steal_pointer (&error));
884 return;
885 }
886
887 gsource = seahorse_ldap_gsource_new (closure->ldap, ldap_op, cancellable);
888 g_source_set_callback (gsource, G_SOURCE_FUNC (on_search_search_completed),
889 g_steal_pointer (&task), g_object_unref);
890 g_source_attach (gsource, g_main_context_default ());
891 }
892
893
894 static void
seahorse_ldap_source_search_async(SeahorseServerSource * source,const char * match,GcrSimpleCollection * results,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)895 seahorse_ldap_source_search_async (SeahorseServerSource *source,
896 const char *match,
897 GcrSimpleCollection *results,
898 GCancellable *cancellable,
899 GAsyncReadyCallback callback,
900 gpointer user_data)
901 {
902 SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (source);
903 SearchClosure *closure;
904 g_autoptr(GTask) task = NULL;
905 g_autofree char *text = NULL;
906
907 task = g_task_new (source, cancellable, callback, user_data);
908 g_task_set_source_tag (task, seahorse_ldap_source_search_async);
909 closure = g_new0 (SearchClosure, 1);
910 closure->results = g_object_ref (results);
911 text = escape_ldap_value (match);
912 closure->filter = g_strdup_printf ("(pgpuserid=*%s*)", text);
913 g_task_set_task_data (task, closure, search_closure_free);
914
915 seahorse_progress_prep_and_begin (cancellable, task, NULL);
916
917 seahorse_ldap_source_connect_async (self, cancellable,
918 on_search_connect_completed,
919 g_steal_pointer (&task));
920 }
921
922 static gboolean
seahorse_ldap_source_search_finish(SeahorseServerSource * source,GAsyncResult * result,GError ** error)923 seahorse_ldap_source_search_finish (SeahorseServerSource *source,
924 GAsyncResult *result,
925 GError **error)
926 {
927 g_return_val_if_fail (SEAHORSE_IS_LDAP_SOURCE (source), FALSE);
928 g_return_val_if_fail (g_task_is_valid (result, source), FALSE);
929
930 return g_task_propagate_boolean (G_TASK (result), error);
931 }
932
933 typedef struct {
934 GPtrArray *keydatas;
935 int current_index;
936 LDAP *ldap;
937 } ImportClosure;
938
939 static void
import_closure_free(gpointer data)940 import_closure_free (gpointer data)
941 {
942 ImportClosure *closure = data;
943 g_ptr_array_free (closure->keydatas, TRUE);
944 if (closure->ldap)
945 ldap_unbind_ext (closure->ldap, NULL, NULL);
946 g_free (closure);
947 }
948
949 static void import_send_key (SeahorseLDAPSource *self, GTask *task);
950
951 /* Called when results come in for a key send */
952 static gboolean
on_import_add_completed(LDAPMessage * result,gpointer user_data)953 on_import_add_completed (LDAPMessage *result,
954 gpointer user_data)
955 {
956 GTask *task = G_TASK (user_data);
957 ImportClosure *closure = g_task_get_task_data (task);
958 SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (g_task_get_source_object (task));
959 GError *error = NULL;
960 char *message;
961 int code;
962 int rc;
963
964 g_return_val_if_fail (ldap_msgtype (result) == LDAP_RES_ADD, FALSE);
965
966 rc = ldap_parse_result (closure->ldap, result, &code, NULL,
967 &message, NULL, NULL, 0);
968 g_return_val_if_fail (rc == LDAP_SUCCESS, FALSE);
969
970 /* TODO: Somehow communicate this to the user */
971 if (code == LDAP_ALREADY_EXISTS)
972 code = LDAP_SUCCESS;
973
974 ldap_memfree (message);
975
976 if (seahorse_ldap_source_propagate_error (self, code, &error)) {
977 g_task_return_error (task, g_steal_pointer (&error));
978 return G_SOURCE_REMOVE;
979 }
980
981 import_send_key (self, task);
982 return G_SOURCE_REMOVE;
983 }
984
985 static void
import_send_key(SeahorseLDAPSource * self,GTask * task)986 import_send_key (SeahorseLDAPSource *self, GTask *task)
987 {
988 ImportClosure *closure = g_task_get_task_data (task);
989 GCancellable *cancellable = g_task_get_cancellable (task);
990 LDAPServerInfo *sinfo;
991 g_autofree char *base = NULL;
992 LDAPMod mod;
993 LDAPMod *attrs[2];
994 char *values[2];
995 g_autoptr(GSource) gsource = NULL;
996 GError *error = NULL;
997 char *keydata;
998 int ldap_op;
999 int rc;
1000
1001 if (closure->current_index >= 0) {
1002 keydata = g_ptr_array_index (closure->keydatas, closure->current_index);
1003 seahorse_progress_end (cancellable, keydata);
1004 }
1005
1006 closure->current_index++;
1007
1008 /* All done, complete operation */
1009 if (closure->current_index == (int) closure->keydatas->len) {
1010 g_task_return_boolean (task, TRUE);
1011 return;
1012 }
1013
1014 keydata = g_ptr_array_index (closure->keydatas, closure->current_index);
1015 seahorse_progress_begin (cancellable, keydata);
1016 values[0] = keydata;
1017 values[1] = NULL;
1018
1019 sinfo = get_ldap_server_info (self, TRUE);
1020 memset (&mod, 0, sizeof (mod));
1021 mod.mod_op = LDAP_MOD_ADD;
1022 mod.mod_type = sinfo->key_attr;
1023 mod.mod_values = values;
1024
1025 attrs[0] = &mod;
1026 attrs[1] = NULL;
1027
1028 base = g_strdup_printf ("pgpCertid=virtual,%s", sinfo->base_dn);
1029 rc = ldap_add_ext (closure->ldap, base, attrs, NULL, NULL, &ldap_op);
1030
1031 if (seahorse_ldap_source_propagate_error (self, rc, &error)) {
1032 g_task_return_error (task, g_steal_pointer (&error));
1033 return;
1034 }
1035
1036 gsource = seahorse_ldap_gsource_new (closure->ldap, ldap_op, cancellable);
1037 g_source_set_callback (gsource, G_SOURCE_FUNC (on_import_add_completed),
1038 g_object_ref (task), g_object_unref);
1039 g_source_attach (gsource, g_main_context_default ());
1040 }
1041
1042 static void
on_import_connect_completed(GObject * source,GAsyncResult * result,gpointer user_data)1043 on_import_connect_completed (GObject *source,
1044 GAsyncResult *result,
1045 gpointer user_data)
1046 {
1047 g_autoptr(GTask) task = G_TASK (user_data);
1048 ImportClosure *closure = g_task_get_task_data (task);
1049 SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (source);
1050 g_autoptr(GError) error = NULL;
1051
1052 closure->ldap = seahorse_ldap_source_connect_finish (self, result, &error);
1053 if (error != NULL) {
1054 g_task_return_error (task, g_steal_pointer (&error));
1055 return;
1056 }
1057
1058 import_send_key (self, task);
1059 }
1060
1061 static void
seahorse_ldap_source_import_async(SeahorseServerSource * source,GInputStream * input,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1062 seahorse_ldap_source_import_async (SeahorseServerSource *source,
1063 GInputStream *input,
1064 GCancellable *cancellable,
1065 GAsyncReadyCallback callback,
1066 gpointer user_data)
1067 {
1068 SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (source);
1069 g_autoptr(GTask) task = NULL;
1070 ImportClosure *closure;
1071
1072 task = g_task_new (source, cancellable, callback, user_data);
1073 g_task_set_source_tag (task, seahorse_ldap_source_import_async);
1074
1075 closure = g_new0 (ImportClosure, 1);
1076 closure->current_index = -1;
1077 g_task_set_task_data (task, closure, import_closure_free);
1078
1079 closure->keydatas = g_ptr_array_new_with_free_func (g_free);
1080 for (;;) {
1081 g_autoptr(GString) buf = g_string_sized_new (2048);
1082 guint len;
1083 g_autofree char *keydata = NULL;
1084
1085 len = seahorse_util_read_data_block (buf, input, "-----BEGIN PGP PUBLIC KEY BLOCK-----",
1086 "-----END PGP PUBLIC KEY BLOCK-----");
1087 if (len <= 0)
1088 break;
1089
1090 keydata = g_string_free (g_steal_pointer (&buf), FALSE);
1091 seahorse_progress_prep (cancellable, keydata, NULL);
1092 g_ptr_array_add (closure->keydatas, g_steal_pointer (&keydata));
1093 }
1094
1095 seahorse_ldap_source_connect_async (self, cancellable,
1096 on_import_connect_completed,
1097 g_steal_pointer (&task));
1098 }
1099
1100 static GList *
seahorse_ldap_source_import_finish(SeahorseServerSource * source,GAsyncResult * result,GError ** error)1101 seahorse_ldap_source_import_finish (SeahorseServerSource *source,
1102 GAsyncResult *result,
1103 GError **error)
1104 {
1105 g_return_val_if_fail (g_task_is_valid (result, source), NULL);
1106 g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) ==
1107 seahorse_ldap_source_import_async, NULL);
1108
1109 if (!g_task_propagate_boolean (G_TASK (result), error))
1110 return NULL;
1111
1112 /* We don't know the keys that were imported, since this is a server */
1113 return NULL;
1114 }
1115
1116 typedef struct {
1117 GPtrArray *fingerprints;
1118 int current_index;
1119 GString *data;
1120 LDAP *ldap;
1121 } ExportClosure;
1122
1123 static void
export_closure_free(gpointer data)1124 export_closure_free (gpointer data)
1125 {
1126 ExportClosure *closure = data;
1127 g_ptr_array_free (closure->fingerprints, TRUE);
1128 if (closure->data)
1129 g_string_free (closure->data, TRUE);
1130 if (closure->ldap)
1131 ldap_unbind_ext (closure->ldap, NULL, NULL);
1132 g_free (closure);
1133 }
1134
1135 static void export_retrieve_key (SeahorseLDAPSource *self,
1136 GTask *task);
1137
1138 static gboolean
on_export_search_completed(LDAPMessage * result,gpointer user_data)1139 on_export_search_completed (LDAPMessage *result,
1140 gpointer user_data)
1141 {
1142 GTask *task = G_TASK (user_data);
1143 ExportClosure *closure = g_task_get_task_data (task);
1144 SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (g_task_get_source_object (task));
1145 LDAPServerInfo *sinfo;
1146 char *message;
1147 GError *error = NULL;
1148 int code;
1149 int type;
1150 int rc;
1151
1152 type = ldap_msgtype (result);
1153 g_return_val_if_fail (type == LDAP_RES_SEARCH_ENTRY || type == LDAP_RES_SEARCH_RESULT, FALSE);
1154 sinfo = get_ldap_server_info (self, TRUE);
1155
1156 /* An LDAP Entry */
1157 if (type == LDAP_RES_SEARCH_ENTRY) {
1158 g_autofree char *key = NULL;
1159
1160 g_debug ("Server Info Result");
1161 #ifdef WITH_DEBUG
1162 dump_ldap_entry (closure->ldap, result);
1163 #endif
1164
1165 key = get_string_attribute (closure->ldap, result, sinfo->key_attr);
1166 if (key == NULL) {
1167 g_warning ("key server missing pgp key data");
1168 seahorse_ldap_source_propagate_error (self, LDAP_NO_SUCH_OBJECT, &error);
1169 g_task_return_error (task, g_steal_pointer (&error));
1170 return G_SOURCE_REMOVE;
1171 }
1172
1173 g_string_append (closure->data, key);
1174 g_string_append_c (closure->data, '\n');
1175
1176 return G_SOURCE_CONTINUE;
1177 }
1178
1179 /* No more entries, result */
1180 rc = ldap_parse_result (closure->ldap, result, &code, NULL,
1181 &message, NULL, NULL, 0);
1182 g_return_val_if_fail (rc == LDAP_SUCCESS, FALSE);
1183
1184 if (seahorse_ldap_source_propagate_error (self, code, &error)) {
1185 g_task_return_error (task, g_steal_pointer (&error));
1186 return G_SOURCE_REMOVE;
1187 }
1188
1189 ldap_memfree (message);
1190
1191 /* Process more keys if possible */
1192 export_retrieve_key (self, task);
1193 return G_SOURCE_REMOVE;
1194 }
1195
1196 static void
export_retrieve_key(SeahorseLDAPSource * self,GTask * task)1197 export_retrieve_key (SeahorseLDAPSource *self,
1198 GTask *task)
1199 {
1200 ExportClosure *closure = g_task_get_task_data (task);
1201 GCancellable *cancellable = g_task_get_cancellable (task);
1202 LDAPServerInfo *sinfo;
1203 g_autofree char *filter = NULL;
1204 char *attrs[2];
1205 g_autoptr(GSource) gsource = NULL;
1206 const char *fingerprint;
1207 g_autoptr(GError) error = NULL;
1208 int length, rc;
1209 int ldap_op;
1210
1211 if (closure->current_index > 0) {
1212 fingerprint = g_ptr_array_index (closure->fingerprints,
1213 closure->current_index);
1214 seahorse_progress_end (cancellable, fingerprint);
1215 }
1216
1217 closure->current_index++;
1218
1219 /* All done, complete operation */
1220 if (closure->current_index == (int) closure->fingerprints->len) {
1221 g_task_return_boolean (task, TRUE);
1222 return;
1223 }
1224
1225 fingerprint = g_ptr_array_index (closure->fingerprints,
1226 closure->current_index);
1227 seahorse_progress_begin (cancellable, fingerprint);
1228 length = strlen (fingerprint);
1229 if (length > 16)
1230 fingerprint += (length - 16);
1231
1232 filter = g_strdup_printf ("(pgpcertid=%.16s)", fingerprint);
1233 sinfo = get_ldap_server_info (self, TRUE);
1234
1235 attrs[0] = sinfo->key_attr;
1236 attrs[1] = NULL;
1237
1238 rc = ldap_search_ext (closure->ldap, sinfo->base_dn, LDAP_SCOPE_SUBTREE,
1239 filter, attrs, 0,
1240 NULL, NULL, NULL, 0, &ldap_op);
1241
1242 if (seahorse_ldap_source_propagate_error (self, rc, &error)) {
1243 g_task_return_error (task, g_steal_pointer (&error));
1244 return;
1245 }
1246
1247 gsource = seahorse_ldap_gsource_new (closure->ldap, ldap_op, cancellable);
1248 g_source_set_callback (gsource, (GSourceFunc)on_export_search_completed,
1249 g_object_ref (task), g_object_unref);
1250 g_source_attach (gsource, g_main_context_default ());
1251 }
1252
1253 static void
on_export_connect_completed(GObject * source,GAsyncResult * result,gpointer user_data)1254 on_export_connect_completed (GObject *source,
1255 GAsyncResult *result,
1256 gpointer user_data)
1257 {
1258 SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (source);
1259 g_autoptr(GTask) task = G_TASK (user_data);
1260 ExportClosure *closure = g_task_get_task_data (task);
1261 g_autoptr(GError) error = NULL;
1262
1263 closure->ldap = seahorse_ldap_source_connect_finish (self, result, &error);
1264 if (error != NULL) {
1265 g_task_return_error (task, g_steal_pointer (&error));
1266 return;
1267 }
1268
1269 export_retrieve_key (self, task);
1270 }
1271
1272 static void
seahorse_ldap_source_export_async(SeahorseServerSource * source,const char ** keyids,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1273 seahorse_ldap_source_export_async (SeahorseServerSource *source,
1274 const char **keyids,
1275 GCancellable *cancellable,
1276 GAsyncReadyCallback callback,
1277 gpointer user_data)
1278 {
1279 SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (source);
1280 ExportClosure *closure;
1281 g_autoptr(GTask) task = NULL;
1282
1283 task = g_task_new (self, cancellable, callback, user_data);
1284 g_task_set_source_tag (task, seahorse_ldap_source_export_async);
1285
1286 closure = g_new0 (ExportClosure, 1);
1287 closure->data = g_string_sized_new (1024);
1288 closure->fingerprints = g_ptr_array_new_with_free_func (g_free);
1289 for (int i = 0; keyids[i] != NULL; i++) {
1290 char *fingerprint = g_strdup (keyids[i]);
1291
1292 g_ptr_array_add (closure->fingerprints, fingerprint);
1293 seahorse_progress_prep (cancellable, fingerprint, NULL);
1294 }
1295 closure->current_index = -1;
1296 g_task_set_task_data (task, closure, export_closure_free);
1297
1298 seahorse_ldap_source_connect_async (self, cancellable,
1299 on_export_connect_completed,
1300 g_steal_pointer (&task));
1301 }
1302
1303 static gpointer
seahorse_ldap_source_export_finish(SeahorseServerSource * source,GAsyncResult * result,gsize * size,GError ** error)1304 seahorse_ldap_source_export_finish (SeahorseServerSource *source,
1305 GAsyncResult *result,
1306 gsize *size,
1307 GError **error)
1308 {
1309 ExportClosure *closure;
1310 gpointer output;
1311
1312 g_return_val_if_fail (size != NULL, NULL);
1313 g_return_val_if_fail (g_task_is_valid (result, source), NULL);
1314
1315 if (!g_task_propagate_boolean (G_TASK (result), error))
1316 return NULL;
1317
1318 closure = g_task_get_task_data (G_TASK (result));
1319 *size = closure->data->len;
1320 output = g_string_free (closure->data, FALSE);
1321 closure->data = NULL;
1322 return output;
1323 }
1324
1325 /* Initialize the basic class stuff */
1326 static void
seahorse_ldap_source_class_init(SeahorseLDAPSourceClass * klass)1327 seahorse_ldap_source_class_init (SeahorseLDAPSourceClass *klass)
1328 {
1329 SeahorseServerSourceClass *server_class = SEAHORSE_SERVER_SOURCE_CLASS (klass);
1330
1331 server_class->search_async = seahorse_ldap_source_search_async;
1332 server_class->search_finish = seahorse_ldap_source_search_finish;
1333 server_class->export_async = seahorse_ldap_source_export_async;
1334 server_class->export_finish = seahorse_ldap_source_export_finish;
1335 server_class->import_async = seahorse_ldap_source_import_async;
1336 server_class->import_finish = seahorse_ldap_source_import_finish;
1337 }
1338
1339 /**
1340 * seahorse_ldap_source_new
1341 * @uri: The server to connect to
1342 *
1343 * Creates a new key source for an LDAP PGP server.
1344 *
1345 * Returns: A new LDAP Key Source
1346 */
1347 SeahorseLDAPSource *
seahorse_ldap_source_new(const char * uri)1348 seahorse_ldap_source_new (const char *uri)
1349 {
1350 g_return_val_if_fail (seahorse_ldap_is_valid_uri (uri), NULL);
1351
1352 return g_object_new (SEAHORSE_TYPE_LDAP_SOURCE, "uri", uri, NULL);
1353 }
1354
1355 /**
1356 * seahorse_ldap_is_valid_uri
1357 * @uri: The uri to check
1358 *
1359 * Returns: Whether the passed uri is valid for an ldap key source
1360 */
1361 gboolean
seahorse_ldap_is_valid_uri(const char * uri)1362 seahorse_ldap_is_valid_uri (const char *uri)
1363 {
1364 LDAPURLDesc *url;
1365 int r;
1366
1367 g_return_val_if_fail (uri && *uri, FALSE);
1368
1369 r = ldap_url_parse (uri, &url);
1370 if (r == LDAP_URL_SUCCESS) {
1371 /* Some checks to make sure it's a simple URI */
1372 if (!(url->lud_host && url->lud_host[0]) ||
1373 (url->lud_dn && url->lud_dn[0]) ||
1374 (url->lud_attrs || url->lud_attrs))
1375 r = LDAP_URL_ERR_PARAM;
1376
1377 ldap_free_urldesc (url);
1378 }
1379
1380 return r == LDAP_URL_SUCCESS;
1381 }
1382
1383 #endif /* WITH_LDAP */
1384