4
* Copyright (C) 2004 - 2006 Stefan Walter
5
* Copyright (C) 2011 Collabora Ltd.
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.
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, write to the
18
* Free Software Foundation, Inc.,
19
* 59 Temple Place, Suite 330,
20
* Boston, MA 02111-1307, USA.
29
#include <glib/gi18n.h>
31
#include "seahorse-ldap-source.h"
33
#include "seahorse-pgp-key.h"
34
#include "seahorse-pgp-subkey.h"
35
#include "seahorse-pgp-uid.h"
37
#include "seahorse-object-list.h"
38
#include "seahorse-progress.h"
39
#include "seahorse-registry.h"
40
#include "seahorse-servers.h"
41
#include "seahorse-util.h"
46
#include <libsoup/soup-address.h>
51
#define DEBUG_FLAG SEAHORSE_DEBUG_LDAP
52
#include "seahorse-debug.h"
54
/* Amount of keys to load in a batch */
55
#define DEFAULT_LOAD_BATCH 30
57
/* -----------------------------------------------------------------------------
61
typedef struct _LDAPServerInfo {
62
gchar *base_dn; /* The base dn where PGP keys are found */
63
gchar *key_attr; /* The attribute of PGP key data */
64
guint version; /* The version of the PGP server software */
68
free_ldap_server_info (LDAPServerInfo *sinfo)
71
g_free (sinfo->base_dn);
72
g_free (sinfo->key_attr);
78
set_ldap_server_info (SeahorseLDAPSource *lsrc, LDAPServerInfo *sinfo)
80
g_object_set_data_full (G_OBJECT (lsrc), "server-info", sinfo,
81
(GDestroyNotify)free_ldap_server_info);
84
static LDAPServerInfo*
85
get_ldap_server_info (SeahorseLDAPSource *lsrc, gboolean force)
87
LDAPServerInfo *sinfo;
89
sinfo = g_object_get_data (G_OBJECT (lsrc), "server-info");
91
/* When we're asked to force getting the data, we fill in
93
if (!sinfo && force) {
94
sinfo = g_new0 (LDAPServerInfo, 1);
95
sinfo->base_dn = g_strdup ("OU=ACTIVE,O=PGP KEYSPACE,C=US");
96
sinfo->key_attr = g_strdup ("pgpKey");
98
set_ldap_server_info (lsrc, sinfo);
105
/* -----------------------------------------------------------------------------
109
#define LDAP_ERROR_DOMAIN (get_ldap_error_domain())
112
get_ldap_values (LDAP *ld, LDAPMessage *entry, const char *attribute)
119
bv = ldap_get_values_len (ld, entry, attribute);
123
array = g_array_new (TRUE, TRUE, sizeof (gchar*));
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);
130
return (gchar**)g_array_free (array, FALSE);
136
dump_ldap_entry (LDAP *ld, LDAPMessage *res)
143
t = ldap_get_dn (ld, res);
144
g_printerr ("dn: %s\n", t);
147
for (t = ldap_first_attribute (ld, res, &pos); t;
148
t = ldap_next_attribute (ld, res, pos)) {
150
values = get_ldap_values (ld, res, t);
151
for (v = values; *v; v++)
152
g_printerr ("%s: %s\n", t, *v);
161
#endif /* WITH_DEBUG */
164
get_ldap_error_domain ()
168
q = g_quark_from_static_string ("seahorse-ldap-error");
173
get_string_attribute (LDAP *ld, LDAPMessage *res, const char *attribute)
178
vals = get_ldap_values (ld, res, attribute);
181
v = vals[0] ? g_strdup (vals[0]) : NULL;
187
get_boolean_attribute (LDAP* ld, LDAPMessage *res, const char *attribute)
192
vals = get_ldap_values (ld, res, attribute);
195
b = vals[0] && atoi (vals[0]) == 1;
201
get_int_attribute (LDAP* ld, LDAPMessage *res, const char *attribute)
206
vals = get_ldap_values (ld, res, attribute);
209
d = vals[0] ? atoi (vals[0]) : 0;
215
get_date_attribute (LDAP* ld, LDAPMessage *res, const char *attribute)
221
vals = get_ldap_values (ld, res, attribute);
226
memset(&t, 0, sizeof (t));
228
/* YYYYMMDDHHmmssZ */
229
sscanf(vals[0], "%4d%2d%2d%2d%2d%2d",
230
&t.tm_year, &t.tm_mon, &t.tm_mday,
231
&t.tm_hour, &t.tm_min, &t.tm_sec);
245
get_algo_attribute (LDAP* ld, LDAPMessage *res, const char *attribute)
247
const gchar *a = NULL;
250
vals = get_ldap_values (ld, res, attribute);
255
if (g_ascii_strcasecmp (vals[0], "DH/DSS") == 0 ||
256
g_ascii_strcasecmp (vals[0], "Elg") == 0 ||
257
g_ascii_strcasecmp (vals[0], "Elgamal") == 0 ||
258
g_ascii_strcasecmp (vals[0], "DSS/DH") == 0)
260
if (g_ascii_strcasecmp (vals[0], "RSA") == 0)
262
if (g_ascii_strcasecmp (vals[0], "DSA") == 0)
271
* Escapes a value so it's safe to use in an LDAP filter. Also trims
272
* any spaces which cause problems with some LDAP servers.
275
escape_ldap_value (const gchar *v)
281
value = g_string_sized_new (strlen(v));
285
case '#': case ',': case '+': case '\\':
286
case '/': case '\"': case '<': case '>': case ';':
287
value = g_string_append_c (value, '\\');
288
value = g_string_append_c (value, *v);
292
if(*v < 32 || *v > 126) {
293
g_string_append_printf (value, "\\%02X", *v);
297
value = g_string_append_c (value, *v);
300
result = g_string_free (value, FALSE);
305
typedef gboolean (*SeahorseLdapCallback) (LDAPMessage *result,
312
GCancellable *cancellable;
315
} SeahorseLdapGSource;
318
seahorse_ldap_gsource_prepare (GSource *gsource,
321
SeahorseLdapGSource *ldap_gsource = (SeahorseLdapGSource *)gsource;
323
if (ldap_gsource->cancelled)
326
/* No other way, but to poll */
332
seahorse_ldap_gsource_check (GSource *gsource)
338
seahorse_ldap_gsource_dispatch (GSource *gsource,
339
GSourceFunc callback,
342
SeahorseLdapGSource *ldap_gsource = (SeahorseLdapGSource *)gsource;
343
struct timeval timeout;
348
if (ldap_gsource->cancelled) {
349
((SeahorseLdapCallback)callback) (NULL, user_data);
353
for (i = 0; i < DEFAULT_LOAD_BATCH; i++) {
355
/* This effects a poll */
359
rc = ldap_result (ldap_gsource->ldap, ldap_gsource->ldap_op,
360
0, &timeout, &result);
362
g_warning ("ldap_result failed with rc = %d, errno = %s",
363
rc, g_strerror (errno));
367
} else if (rc == 0) {
371
ret = ((SeahorseLdapCallback)callback) (result, user_data);
372
ldap_msgfree (result);
382
seahorse_ldap_gsource_finalize (GSource *gsource)
384
SeahorseLdapGSource *ldap_gsource = (SeahorseLdapGSource *)gsource;
385
g_cancellable_disconnect (ldap_gsource->cancellable,
386
ldap_gsource->cancelled_sig);
387
g_clear_object (&ldap_gsource->cancellable);
390
static GSourceFuncs seahorse_ldap_gsource_funcs = {
391
seahorse_ldap_gsource_prepare,
392
seahorse_ldap_gsource_check,
393
seahorse_ldap_gsource_dispatch,
394
seahorse_ldap_gsource_finalize,
398
on_ldap_gsource_cancelled (GCancellable *cancellable,
401
SeahorseLdapGSource *ldap_gsource = user_data;
402
ldap_gsource->cancelled = TRUE;
406
seahorse_ldap_gsource_new (LDAP *ldap,
408
GCancellable *cancellable)
411
SeahorseLdapGSource *ldap_gsource;
413
gsource = g_source_new (&seahorse_ldap_gsource_funcs,
414
sizeof (SeahorseLdapGSource));
416
ldap_gsource = (SeahorseLdapGSource *)gsource;
417
ldap_gsource->ldap = ldap;
418
ldap_gsource->ldap_op = ldap_op;
421
ldap_gsource->cancellable = g_object_ref (cancellable);
422
ldap_gsource->cancelled_sig = g_cancellable_connect (cancellable,
423
G_CALLBACK (on_ldap_gsource_cancelled),
431
seahorse_ldap_source_propagate_error (SeahorseLDAPSource *self,
432
int rc, GError **error)
436
if (rc == LDAP_SUCCESS)
439
g_object_get (self, "key-server", &server, NULL);
440
g_set_error (error, LDAP_ERROR_DOMAIN, rc, _("Couldn't communicate with '%s': %s"),
441
server, ldap_err2string (rc));
448
GCancellable *cancellable;
450
} source_connect_closure;
453
source_connect_free (gpointer data)
455
source_connect_closure *closure = data;
456
g_clear_object (&closure->cancellable);
458
ldap_unbind_ext (closure->ldap, NULL, NULL);
463
on_connect_server_info_completed (LDAPMessage *result,
466
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
467
source_connect_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
468
SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (g_async_result_get_source_object (user_data));
469
LDAPServerInfo *sinfo;
475
type = ldap_msgtype (result);
476
g_return_val_if_fail (type == LDAP_RES_SEARCH_ENTRY || type == LDAP_RES_SEARCH_RESULT, FALSE);
478
/* If we have results then fill in the server info */
479
if (type == LDAP_RES_SEARCH_ENTRY) {
481
seahorse_debug ("Server Info Result:");
483
if (seahorse_debugging)
484
dump_ldap_entry (closure->ldap, result);
487
/* NOTE: When adding attributes here make sure to add them to kServerAttributes */
488
sinfo = g_new0 (LDAPServerInfo, 1);
489
sinfo->version = get_int_attribute (closure->ldap, result, "version");
490
sinfo->base_dn = get_string_attribute (closure->ldap, result, "basekeyspacedn");
492
sinfo->base_dn = get_string_attribute (closure->ldap, result, "pgpbasekeyspacedn");
493
sinfo->key_attr = g_strdup (sinfo->version > 1 ? "pgpkeyv2" : "pgpkey");
494
set_ldap_server_info (self, sinfo);
496
return TRUE; /* callback again */
499
rc = ldap_parse_result (closure->ldap, result, &code, NULL,
500
&message, NULL, NULL, 0);
501
g_return_val_if_fail (rc == LDAP_SUCCESS, FALSE);
503
if (code != LDAP_SUCCESS)
504
g_warning ("operation to get LDAP server info failed: %s", message);
506
ldap_memfree (message);
508
g_simple_async_result_complete_in_idle (res);
509
seahorse_progress_end (closure->cancellable, res);
510
return FALSE; /* don't callback again */
514
static const char *SERVER_ATTRIBUTES[] = {
522
on_connect_bind_completed (LDAPMessage *result,
525
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
526
source_connect_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
527
SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (g_async_result_get_source_object (user_data));
528
LDAPServerInfo *sinfo;
529
GError *error = NULL;
535
g_return_val_if_fail (ldap_msgtype (result) == LDAP_RES_BIND, FALSE);
537
/* The result of the bind operation */
538
rc = ldap_parse_result (closure->ldap, result, &code, NULL, &message, NULL, NULL, 0);
539
g_return_val_if_fail (rc == LDAP_SUCCESS, FALSE);
540
ldap_memfree (message);
542
if (seahorse_ldap_source_propagate_error (self, rc, &error)) {
543
g_simple_async_result_take_error (res, error);
544
g_simple_async_result_complete_in_idle (res);
545
return FALSE; /* don't call this callback again */
548
/* Check if we need server info */
549
sinfo = get_ldap_server_info (self, FALSE);
551
g_simple_async_result_complete_in_idle (res);
552
seahorse_progress_end (closure->cancellable, res);
553
return FALSE; /* don't call this callback again */
556
/* Retrieve the server info */
557
rc = ldap_search_ext (closure->ldap, "cn=PGPServerInfo", LDAP_SCOPE_BASE,
558
"(objectclass=*)", (char **)SERVER_ATTRIBUTES, 0,
559
NULL, NULL, NULL, 0, &ldap_op);
561
if (seahorse_ldap_source_propagate_error (self, rc, &error)) {
562
g_simple_async_result_take_error (res, error);
563
g_simple_async_result_complete_in_idle (res);
564
return FALSE; /* don't call this callback again */
567
GSource *gsource = seahorse_ldap_gsource_new (closure->ldap, ldap_op,
568
closure->cancellable);
569
g_source_set_callback (gsource, (GSourceFunc)on_connect_server_info_completed,
570
g_object_ref (res), g_object_unref);
571
g_source_attach (gsource, g_main_context_default ());
572
g_source_unref (gsource);
575
return FALSE; /* don't call this callback again */
579
once_resolved_start_connect (SeahorseLDAPSource *self,
580
GSimpleAsyncResult *res,
581
const gchar *address)
583
source_connect_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
584
gchar *server = NULL;
585
GError *error = NULL;
586
gint port = LDAP_PORT;
593
/* Now that we've resolved our address, connect via IP */
594
g_object_get (self, "key-server", &server, NULL);
595
g_return_if_fail (server && server[0]);
597
if ((text = strchr (server, ':')) != NULL) {
601
if (port <= 0 || port >= G_MAXUINT16) {
602
g_warning ("invalid port number: %s (using default)", text);
607
url = g_strdup_printf ("ldap://%s:%u", address, port);
608
rc = ldap_initialize (&closure->ldap, url);
611
if (seahorse_ldap_source_propagate_error (self, rc, &error)) {
612
g_simple_async_result_take_error (res, error);
613
g_simple_async_result_complete_in_idle (res);
615
/* Start the bind operation */
620
rc = ldap_sasl_bind (closure->ldap, NULL, LDAP_SASL_SIMPLE, &cred,
621
NULL, NULL, &ldap_op);
622
if (seahorse_ldap_source_propagate_error (self, rc, &error)) {
623
g_simple_async_result_take_error (res, error);
624
g_simple_async_result_complete_in_idle (res);
627
GSource *gsource = seahorse_ldap_gsource_new (closure->ldap, ldap_op,
628
closure->cancellable);
629
g_source_set_callback (gsource, (GSourceFunc)on_connect_bind_completed,
630
g_object_ref (res), g_object_unref);
631
g_source_attach (gsource, g_main_context_default ());
632
g_source_unref (gsource);
640
on_address_resolved_complete (SoupAddress *address,
644
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
645
SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (g_async_result_get_source_object (user_data));
646
source_connect_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
649
g_object_get (self, "key-server", &server, NULL);
650
g_return_if_fail (server && server[0]);
651
seahorse_progress_update (closure->cancellable, res, _("Connecting to: %s"), server);
655
if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
656
g_simple_async_result_set_error (res, SEAHORSE_ERROR, -1,
657
_("Couldn't resolve address: %s"),
658
soup_address_get_name (address));
659
g_simple_async_result_complete_in_idle (res);
663
once_resolved_start_connect (self, res, soup_address_get_physical (address));
666
g_object_unref (res);
669
#endif /* WITH_SOUP */
672
seahorse_ldap_source_connect_async (SeahorseLDAPSource *source,
673
GCancellable *cancellable,
674
GAsyncReadyCallback callback,
677
GSimpleAsyncResult *res;
678
source_connect_closure *closure;
680
SoupAddress *address;
681
gchar *server = NULL;
685
res = g_simple_async_result_new (G_OBJECT (source), callback, user_data,
686
seahorse_ldap_source_connect_async);
687
closure = g_new0 (source_connect_closure, 1);
688
closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
689
g_simple_async_result_set_op_res_gpointer (res, closure, source_connect_free);
691
g_object_get (source, "key-server", &server, NULL);
692
g_return_if_fail (server && server[0]);
693
if ((pos = strchr (server, ':')) != NULL)
696
seahorse_progress_prep_and_begin (cancellable, res, NULL);
698
/* If we have libsoup, try and resolve asynchronously */
700
address = soup_address_new (server, LDAP_PORT);
701
seahorse_progress_update (cancellable, res, _("Resolving server address: %s"), server);
703
soup_address_resolve_async (address, NULL, cancellable,
704
on_address_resolved_complete,
706
g_object_unref (address);
708
#else /* !WITH_SOUP */
710
once_resolved_start_connect (self, res, server);
715
g_object_unref (res);
719
seahorse_ldap_source_connect_finish (SeahorseLDAPSource *source,
720
GAsyncResult *result,
723
source_connect_closure *closure;
726
g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
727
seahorse_ldap_source_connect_async), NULL);
729
if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
732
closure = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
733
ldap = closure->ldap;
734
closure->ldap = NULL;
744
static void seahorse_source_iface (SeahorseSourceIface *iface);
746
G_DEFINE_TYPE_EXTENDED (SeahorseLDAPSource, seahorse_ldap_source, SEAHORSE_TYPE_SERVER_SOURCE, 0,
747
G_IMPLEMENT_INTERFACE (SEAHORSE_TYPE_SOURCE, seahorse_source_iface));
750
seahorse_ldap_source_init (SeahorseLDAPSource *lsrc)
756
seahorse_ldap_source_get_property (GObject *object, guint prop_id, GValue *value,
760
case PROP_SOURCE_TAG:
761
g_value_set_uint (value, SEAHORSE_PGP);
763
case PROP_SOURCE_LOCATION:
764
g_value_set_enum (value, SEAHORSE_LOCATION_REMOTE);
769
/* Initialize the basic class stuff */
771
seahorse_ldap_source_class_init (SeahorseLDAPSourceClass *klass)
773
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
775
gobject_class->get_property = seahorse_ldap_source_get_property;
777
g_object_class_override_property (gobject_class, PROP_SOURCE_TAG, "source-tag");
778
g_object_class_override_property (gobject_class, PROP_SOURCE_LOCATION, "source-location");
780
seahorse_registry_register_type (NULL, SEAHORSE_TYPE_LDAP_SOURCE, "source", "remote", SEAHORSE_PGP_STR, NULL);
781
seahorse_servers_register_type ("ldap", _("LDAP Key Server"), seahorse_ldap_is_valid_uri);
782
seahorse_registry_register_function (NULL, seahorse_pgp_key_canonize_id, "canonize", SEAHORSE_PGP_STR, NULL);
786
GCancellable *cancellable;
790
} source_search_closure;
793
source_search_free (gpointer data)
795
source_search_closure *closure = data;
796
g_clear_object (&closure->cancellable);
797
g_list_free (closure->results);
798
g_free (closure->filter);
800
ldap_unbind_ext (closure->ldap, NULL, NULL);
804
static const char *PGP_ATTRIBUTES[] = {
817
add_key (SeahorseLDAPSource *ssrc, SeahorsePgpKey *key)
819
SeahorseObject *prev;
822
keyid = seahorse_pgp_key_canonize_id (seahorse_pgp_key_get_keyid (key));
823
prev = seahorse_context_get_object (SCTX_APP (), SEAHORSE_SOURCE (ssrc), keyid);
826
g_return_if_fail (SEAHORSE_IS_PGP_KEY (prev));
827
seahorse_pgp_key_set_uids (SEAHORSE_PGP_KEY (prev), seahorse_pgp_key_get_uids (key));
828
seahorse_pgp_key_set_subkeys (SEAHORSE_PGP_KEY (prev), seahorse_pgp_key_get_subkeys (key));
833
seahorse_object_set_source (SEAHORSE_OBJECT (key), SEAHORSE_SOURCE (ssrc));
834
seahorse_context_add_object (SCTX_APP (), SEAHORSE_OBJECT (key));
837
/* Add a key to the key source from an LDAP entry */
838
static SeahorseObject *
839
search_parse_key_from_ldap_entry (SeahorseLDAPSource *self,
843
SeahorseObject *result = NULL;
847
gchar *fpr, *fingerprint;
853
g_return_val_if_fail (ldap_msgtype (res) == LDAP_RES_SEARCH_ENTRY, NULL);
855
fpr = get_string_attribute (ldap, res, "pgpcertid");
856
uidstr = get_string_attribute (ldap, res, "pgpuserid");
857
revoked = get_boolean_attribute (ldap, res, "pgprevoked");
858
disabled = get_boolean_attribute (ldap, res, "pgpdisabled");
859
timestamp = get_date_attribute (ldap, res, "pgpkeycreatetime");
860
expires = get_date_attribute (ldap, res, "pgpkeyexpiretime");
861
algo = get_algo_attribute (ldap, res, "pgpkeytype");
862
length = get_int_attribute (ldap, res, "pgpkeysize");
865
SeahorsePgpSubkey *subkey;
871
/* Build up a subkey */
872
subkey = seahorse_pgp_subkey_new ();
873
seahorse_pgp_subkey_set_keyid (subkey, fpr);
874
fingerprint = seahorse_pgp_subkey_calc_fingerprint (fpr);
875
seahorse_pgp_subkey_set_fingerprint (subkey, fingerprint);
876
g_free (fingerprint);
877
seahorse_pgp_subkey_set_created (subkey, timestamp);
878
seahorse_pgp_subkey_set_expires (subkey, expires);
879
seahorse_pgp_subkey_set_algorithm (subkey, algo);
880
seahorse_pgp_subkey_set_length (subkey, length);
882
flags = SEAHORSE_FLAG_EXPORTABLE;
884
flags |= SEAHORSE_FLAG_REVOKED;
886
flags |= SEAHORSE_FLAG_DISABLED;
887
seahorse_pgp_subkey_set_flags (subkey, flags);
890
uid = seahorse_pgp_uid_new (uidstr);
892
seahorse_pgp_uid_set_validity (uid, SEAHORSE_VALIDITY_REVOKED);
894
/* Now build them into a key */
895
key = seahorse_pgp_key_new ();
896
list = g_list_prepend (NULL, uid);
897
seahorse_pgp_key_set_uids (key, list);
898
seahorse_object_list_free (list);
899
list = g_list_prepend (NULL, subkey);
900
seahorse_pgp_key_set_subkeys (key, list);
901
seahorse_object_list_free (list);
902
g_object_set (key, "location", SEAHORSE_LOCATION_REMOTE,
903
"flags", flags, NULL);
906
g_object_unref (key);
907
result = SEAHORSE_OBJECT (key);
917
on_search_search_completed (LDAPMessage *result,
920
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
921
source_search_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
922
SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (g_async_result_get_source_object (user_data));
923
GError *error = NULL;
930
type = ldap_msgtype (result);
931
g_return_val_if_fail (type == LDAP_RES_SEARCH_ENTRY || type == LDAP_RES_SEARCH_RESULT, FALSE);
934
if (type == LDAP_RES_SEARCH_ENTRY) {
935
seahorse_debug ("Retrieved Key Entry:");
937
if (seahorse_debugging)
938
dump_ldap_entry (closure->ldap, result);
941
key = search_parse_key_from_ldap_entry (self, closure->ldap, result);
943
closure->results = g_list_prepend (closure->results, key);
944
return TRUE; /* keep calling this callback */
946
/* All entries done */
948
rc = ldap_parse_result (closure->ldap, result, &code, NULL,
949
&message, NULL, NULL, 0);
950
g_return_val_if_fail (rc == LDAP_SUCCESS, FALSE);
952
/* Error codes that we ignore */
954
case LDAP_SIZELIMIT_EXCEEDED:
960
if (code != LDAP_SUCCESS)
961
g_simple_async_result_set_error (res, LDAP_ERROR_DOMAIN,
962
code, "%s", message);
963
else if (seahorse_ldap_source_propagate_error (self, code, &error))
964
g_simple_async_result_take_error (res, error);
966
ldap_memfree (message);
967
seahorse_progress_end (closure->cancellable, res);
968
g_simple_async_result_complete (res);
974
on_search_connect_completed (GObject *source,
975
GAsyncResult *result,
978
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
979
source_search_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
980
SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (source);
981
GError *error = NULL;
982
LDAPServerInfo *sinfo;
986
closure->ldap = seahorse_ldap_source_connect_finish (SEAHORSE_LDAP_SOURCE (source),
989
g_simple_async_result_take_error (res, error);
990
g_simple_async_result_complete (res);
991
g_object_unref (res);
995
sinfo = get_ldap_server_info (self, TRUE);
997
seahorse_debug ("Searching Server ... base: %s, filter: %s",
998
sinfo->base_dn, closure->filter);
1000
rc = ldap_search_ext (closure->ldap, sinfo->base_dn, LDAP_SCOPE_SUBTREE,
1001
closure->filter, (char **)PGP_ATTRIBUTES, 0,
1002
NULL, NULL, NULL, 0, &ldap_op);
1004
if (seahorse_ldap_source_propagate_error (self, rc, &error)) {
1005
g_simple_async_result_take_error (res, error);
1006
g_simple_async_result_complete (res);
1009
GSource *gsource = seahorse_ldap_gsource_new (closure->ldap, ldap_op,
1010
closure->cancellable);
1011
g_source_set_callback (gsource, (GSourceFunc)on_search_search_completed,
1012
g_object_ref (res), g_object_unref);
1013
g_source_attach (gsource, g_main_context_default ());
1014
g_source_unref (gsource);
1017
g_object_unref (res);
1022
seahorse_ldap_source_search_async (SeahorseSource *source,
1024
GCancellable *cancellable,
1025
GAsyncReadyCallback callback,
1028
SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (source);
1029
source_search_closure *closure;
1030
GSimpleAsyncResult *res;
1033
res = g_simple_async_result_new (G_OBJECT (source), callback, user_data,
1034
seahorse_ldap_source_search_async);
1035
closure = g_new0 (source_search_closure, 1);
1036
closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
1037
text = escape_ldap_value (match);
1038
closure->filter = g_strdup_printf ("(pgpuserid=*%s*)", text);
1040
g_simple_async_result_set_op_res_gpointer (res, closure, source_search_free);
1042
seahorse_progress_prep_and_begin (closure->cancellable, res, NULL);
1044
seahorse_ldap_source_connect_async (self, cancellable,
1045
on_search_connect_completed,
1046
g_object_ref (res));
1048
g_object_unref (res);
1052
seahorse_ldap_source_search_finish (SeahorseSource *source,
1053
GAsyncResult *result,
1056
source_search_closure *closure;
1059
g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
1060
seahorse_ldap_source_search_async), NULL);
1062
if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
1065
closure = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
1066
keys = closure->results;
1067
closure->results = NULL;
1074
GCancellable *cancellable;
1076
} source_import_closure;
1079
source_import_free (gpointer data)
1081
source_import_closure *closure = data;
1082
g_ptr_array_free (closure->keydata, TRUE);
1083
g_clear_object (&closure->cancellable);
1085
ldap_unbind_ext (closure->ldap, NULL, NULL);
1089
static void import_send_key (SeahorseLDAPSource *self,
1090
GSimpleAsyncResult *res);
1092
/* Called when results come in for a key send */
1094
on_import_add_completed (LDAPMessage *result,
1097
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1098
source_import_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
1099
SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (g_async_result_get_source_object (user_data));
1100
GError *error = NULL;
1105
g_return_val_if_fail (ldap_msgtype (result) == LDAP_RES_ADD, FALSE);
1107
rc = ldap_parse_result (closure->ldap, result, &code, NULL,
1108
&message, NULL, NULL, 0);
1109
g_return_val_if_fail (rc == LDAP_SUCCESS, FALSE);
1111
/* TODO: Somehow communicate this to the user */
1112
if (code == LDAP_ALREADY_EXISTS)
1113
code = LDAP_SUCCESS;
1115
ldap_memfree (message);
1117
if (seahorse_ldap_source_propagate_error (self, code, &error)) {
1118
g_simple_async_result_take_error (res, error);
1119
g_simple_async_result_complete (res);
1120
return FALSE; /* don't call for this source again */
1123
import_send_key (self, res);
1124
return FALSE; /* don't call for this source again */
1128
import_send_key (SeahorseLDAPSource *self,
1129
GSimpleAsyncResult *res)
1131
source_import_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
1132
LDAPServerInfo *sinfo;
1138
GError *error = NULL;
1143
if (closure->current_index >= 0) {
1144
keydata = closure->keydata->pdata[closure->current_index];
1145
seahorse_progress_end (closure->cancellable, keydata);
1148
closure->current_index++;
1150
/* All done, complete operation */
1151
if (closure->current_index == (gint)closure->keydata->len) {
1152
g_simple_async_result_complete (res);
1156
keydata = closure->keydata->pdata[closure->current_index];
1157
seahorse_progress_begin (closure->cancellable, keydata);
1158
values[0] = keydata;
1161
sinfo = get_ldap_server_info (self, TRUE);
1162
memset (&mod, 0, sizeof (mod));
1163
mod.mod_op = LDAP_MOD_ADD;
1164
mod.mod_type = sinfo->key_attr;
1165
mod.mod_values = values;
1170
base = g_strdup_printf ("pgpCertid=virtual,%s", sinfo->base_dn);
1171
rc = ldap_add_ext (closure->ldap, base, attrs, NULL, NULL, &ldap_op);
1175
if (seahorse_ldap_source_propagate_error (self, rc, &error)) {
1176
g_simple_async_result_complete (res);
1180
gsource = seahorse_ldap_gsource_new (closure->ldap, ldap_op,
1181
closure->cancellable);
1182
g_source_set_callback (gsource, (GSourceFunc)on_import_add_completed,
1183
g_object_ref (res), g_object_unref);
1184
g_source_attach (gsource, g_main_context_default ());
1185
g_source_unref (gsource);
1189
on_import_connect_completed (GObject *source,
1190
GAsyncResult *result,
1193
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1194
source_import_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
1195
GError *error = NULL;
1197
closure->ldap = seahorse_ldap_source_connect_finish (SEAHORSE_LDAP_SOURCE (source),
1199
if (error != NULL) {
1200
g_simple_async_result_take_error (res, error);
1201
g_simple_async_result_complete (res);
1203
import_send_key (SEAHORSE_LDAP_SOURCE (source), res);
1206
g_object_unref (res);
1210
seahorse_ldap_source_import_async (SeahorseSource *source,
1211
GInputStream *input,
1212
GCancellable *cancellable,
1213
GAsyncReadyCallback callback,
1216
SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (source);
1217
source_import_closure *closure;
1218
GSimpleAsyncResult *res;
1222
res = g_simple_async_result_new (G_OBJECT (source), callback, user_data,
1223
seahorse_ldap_source_import_async);
1224
closure = g_new0 (source_import_closure, 1);
1225
closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
1226
closure->current_index = -1;
1227
g_simple_async_result_set_op_res_gpointer (res, closure, source_import_free);
1229
closure->keydata =g_ptr_array_new_with_free_func (g_free);
1231
GString *buf = g_string_sized_new (2048);
1232
len = seahorse_util_read_data_block (buf, input, "-----BEGIN PGP PUBLIC KEY BLOCK-----",
1233
"-----END PGP PUBLIC KEY BLOCK-----");
1235
keydata = g_string_free (buf, FALSE);
1236
g_ptr_array_add (closure->keydata, keydata);
1237
seahorse_progress_prep (closure->cancellable, keydata, NULL);
1239
g_string_free (buf, TRUE);
1244
seahorse_ldap_source_connect_async (self, cancellable,
1245
on_import_connect_completed,
1246
g_object_ref (res));
1248
g_object_unref (res);
1252
seahorse_ldap_source_import_finish (SeahorseSource *source,
1253
GAsyncResult *result,
1256
g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
1257
seahorse_ldap_source_import_async), NULL);
1259
if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
1262
/* We don't know the keys that were imported, since this is a server */
1267
GPtrArray *fingerprints;
1269
GOutputStream *output;
1270
GCancellable *cancellable;
1272
} source_export_closure;
1275
source_export_free (gpointer data)
1277
source_export_closure *closure = data;
1278
g_ptr_array_free (closure->fingerprints, TRUE);
1279
g_object_unref (closure->output);
1280
g_clear_object (&closure->cancellable);
1282
ldap_unbind_ext (closure->ldap, NULL, NULL);
1286
static void export_retrieve_key (SeahorseLDAPSource *self,
1287
GSimpleAsyncResult *res);
1290
on_export_search_completed (LDAPMessage *result,
1293
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1294
source_export_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
1295
SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (g_async_result_get_source_object (G_ASYNC_RESULT (res)));
1296
LDAPServerInfo *sinfo;
1298
GError *error = NULL;
1306
type = ldap_msgtype (result);
1307
g_return_val_if_fail (type == LDAP_RES_SEARCH_ENTRY || type == LDAP_RES_SEARCH_RESULT, FALSE);
1308
sinfo = get_ldap_server_info (self, TRUE);
1311
if (type == LDAP_RES_SEARCH_ENTRY) {
1313
seahorse_debug ("Server Info Result:");
1315
if (seahorse_debugging)
1316
dump_ldap_entry (closure->ldap, result);
1319
key = get_string_attribute (closure->ldap, result, sinfo->key_attr);
1322
g_warning ("key server missing pgp key data");
1323
seahorse_ldap_source_propagate_error (self, LDAP_NO_SUCH_OBJECT, &error);
1324
g_simple_async_result_take_error (res, error);
1325
g_simple_async_result_complete (res);
1329
ret = g_output_stream_write_all (closure->output, key, strlen (key), &written, NULL, &error) &&
1330
g_output_stream_write_all (closure->output, "\n", 1, &written, NULL, &error) &&
1331
g_output_stream_flush (closure->output, NULL, &error);
1336
g_simple_async_result_take_error (res, error);
1337
g_simple_async_result_complete (res);
1343
/* No more entries, result */
1345
rc = ldap_parse_result (closure->ldap, result, &code, NULL,
1346
&message, NULL, NULL, 0);
1347
g_return_val_if_fail (rc == LDAP_SUCCESS, FALSE);
1349
if (seahorse_ldap_source_propagate_error (self, code, &error)) {
1350
g_simple_async_result_take_error (res, error);
1351
g_simple_async_result_complete (res);
1355
ldap_memfree (message);
1357
/* Process more keys if possible */
1358
export_retrieve_key (self, res);
1364
export_retrieve_key (SeahorseLDAPSource *self,
1365
GSimpleAsyncResult *res)
1367
source_export_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
1368
LDAPServerInfo *sinfo;
1372
const gchar *fingerprint;
1373
GError *error = NULL;
1377
if (closure->current_index > 0) {
1378
fingerprint = closure->fingerprints->pdata[closure->current_index];
1379
seahorse_progress_end (closure->cancellable, fingerprint);
1382
closure->current_index++;
1384
/* All done, complete operation */
1385
if (closure->current_index == (gint)closure->fingerprints->len) {
1386
g_simple_async_result_complete (res);
1390
fingerprint = closure->fingerprints->pdata[closure->current_index];
1391
seahorse_progress_begin (closure->cancellable, fingerprint);
1392
length = strlen (fingerprint);
1394
fingerprint += (length - 16);
1396
filter = g_strdup_printf ("(pgpcertid=%.16s)", fingerprint);
1397
sinfo = get_ldap_server_info (self, TRUE);
1399
attrs[0] = sinfo->key_attr;
1402
rc = ldap_search_ext (closure->ldap, sinfo->base_dn, LDAP_SCOPE_SUBTREE,
1404
NULL, NULL, NULL, 0, &ldap_op);
1407
if (seahorse_ldap_source_propagate_error (self, rc, &error)) {
1408
g_simple_async_result_take_error (res, error);
1409
g_simple_async_result_complete (res);
1413
gsource = seahorse_ldap_gsource_new (closure->ldap, ldap_op,
1414
closure->cancellable);
1415
g_source_set_callback (gsource, (GSourceFunc)on_export_search_completed,
1416
g_object_ref (res), g_object_unref);
1417
g_source_attach (gsource, g_main_context_default ());
1418
g_source_unref (gsource);
1422
on_export_connect_completed (GObject *source,
1423
GAsyncResult *result,
1426
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1427
source_export_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
1428
GError *error = NULL;
1430
closure->ldap = seahorse_ldap_source_connect_finish (SEAHORSE_LDAP_SOURCE (source),
1432
if (error != NULL) {
1433
g_simple_async_result_take_error (res, error);
1434
g_simple_async_result_complete (res);
1436
export_retrieve_key (SEAHORSE_LDAP_SOURCE (source), res);
1439
g_object_unref (res);
1443
seahorse_ldap_source_export_raw_async (SeahorseSource *source,
1445
GOutputStream *output,
1446
GCancellable *cancellable,
1447
GAsyncReadyCallback callback,
1450
SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (source);
1451
source_export_closure *closure;
1452
GSimpleAsyncResult *res;
1456
res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
1457
seahorse_ldap_source_export_raw_async);
1458
closure = g_new0 (source_export_closure, 1);
1459
closure->output = g_object_ref (output);
1460
closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
1461
closure->fingerprints = g_ptr_array_new_with_free_func (g_free);
1462
for (l = keyids; l; l = g_list_next (l)) {
1463
fingerprint = g_strdup (seahorse_pgp_key_calc_rawid (GPOINTER_TO_UINT (l->data)));
1464
g_ptr_array_add (closure->fingerprints, fingerprint);
1465
seahorse_progress_prep (closure->cancellable, fingerprint, NULL);
1467
closure->current_index = -1;
1468
g_simple_async_result_set_op_res_gpointer (res, closure, source_export_free);
1470
seahorse_ldap_source_connect_async (self, cancellable,
1471
on_export_connect_completed,
1472
g_object_ref (res));
1474
g_object_unref (res);
1477
static GOutputStream *
1478
seahorse_ldap_source_export_raw_finish (SeahorseSource *source,
1479
GAsyncResult *result,
1482
source_export_closure *closure;
1484
g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
1485
seahorse_ldap_source_export_raw_async), FALSE);
1487
if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
1490
closure = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
1491
return closure->output;
1495
seahorse_source_iface (SeahorseSourceIface *iface)
1497
iface->search_async = seahorse_ldap_source_search_async;
1498
iface->search_finish = seahorse_ldap_source_search_finish;
1499
iface->import_async = seahorse_ldap_source_import_async;
1500
iface->import_finish = seahorse_ldap_source_import_finish;
1501
iface->export_raw_async = seahorse_ldap_source_export_raw_async;
1502
iface->export_raw_finish = seahorse_ldap_source_export_raw_finish;
1506
* seahorse_ldap_source_new
1507
* @uri: The server to connect to
1509
* Creates a new key source for an LDAP PGP server.
1511
* Returns: A new LDAP Key Source
1514
seahorse_ldap_source_new (const gchar* uri, const gchar *host)
1516
g_return_val_if_fail (seahorse_ldap_is_valid_uri (uri), NULL);
1517
g_return_val_if_fail (host && *host, NULL);
1518
return g_object_new (SEAHORSE_TYPE_LDAP_SOURCE, "key-server", host,
1523
* seahorse_ldap_is_valid_uri
1524
* @uri: The uri to check
1526
* Returns: Whether the passed uri is valid for an ldap key source
1529
seahorse_ldap_is_valid_uri (const gchar *uri)
1534
g_return_val_if_fail (uri && *uri, FALSE);
1536
r = ldap_url_parse (uri, &url);
1537
if (r == LDAP_URL_SUCCESS) {
1539
/* Some checks to make sure it's a simple URI */
1540
if (!(url->lud_host && url->lud_host[0]) ||
1541
(url->lud_dn && url->lud_dn[0]) ||
1542
(url->lud_attrs || url->lud_attrs))
1543
r = LDAP_URL_ERR_PARAM;
1545
ldap_free_urldesc (url);
1548
return r == LDAP_URL_SUCCESS;
1551
#endif /* WITH_LDAP */