~ubuntu-branches/ubuntu/precise/seahorse/precise-proposed

« back to all changes in this revision

Viewing changes to .pc/03_broken_search.patch/pgp/seahorse-ldap-source.c

  • Committer: Package Import Robot
  • Author(s): Robert Ancell
  • Date: 2012-04-11 16:06:48 UTC
  • Revision ID: package-import@ubuntu.com-20120411160648-sw4j0gg17cngc3hy
Tags: 3.2.2-0ubuntu2
* debian/patches/02_broken_search_filter.patch:
  - Fix broken search filter (LP: #978600)
* debian/patches/03_broken_search.patch:
  - Fix broken search (LP: #925474)
* debian/patches/99_ltmain_as-needed.patch:
  - Dropped as it conflicts with dh-autoreconf.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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, write to the
 
18
 * Free Software Foundation, Inc.,
 
19
 * 59 Temple Place, Suite 330,
 
20
 * Boston, MA 02111-1307, USA.
 
21
 */
 
22
 
 
23
#include "config.h"
 
24
 
 
25
#include <string.h>
 
26
#include <stdlib.h>
 
27
#include <errno.h>
 
28
 
 
29
#include <glib/gi18n.h>
 
30
 
 
31
#include "seahorse-ldap-source.h"
 
32
 
 
33
#include "seahorse-pgp-key.h"
 
34
#include "seahorse-pgp-subkey.h"
 
35
#include "seahorse-pgp-uid.h"
 
36
 
 
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"
 
42
 
 
43
#include <ldap.h>
 
44
 
 
45
#ifdef WITH_SOUP
 
46
#include <libsoup/soup-address.h>
 
47
#endif
 
48
 
 
49
#ifdef WITH_LDAP
 
50
 
 
51
#define DEBUG_FLAG SEAHORSE_DEBUG_LDAP
 
52
#include "seahorse-debug.h"
 
53
 
 
54
/* Amount of keys to load in a batch */
 
55
#define DEFAULT_LOAD_BATCH 30
 
56
 
 
57
/* -----------------------------------------------------------------------------
 
58
 * SERVER INFO
 
59
 */
 
60
 
 
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 */
 
65
} LDAPServerInfo;
 
66
 
 
67
static void
 
68
free_ldap_server_info (LDAPServerInfo *sinfo)
 
69
{
 
70
    if (sinfo) {
 
71
        g_free (sinfo->base_dn);
 
72
        g_free (sinfo->key_attr);
 
73
        g_free (sinfo);
 
74
    }
 
75
}
 
76
 
 
77
static void
 
78
set_ldap_server_info (SeahorseLDAPSource *lsrc, LDAPServerInfo *sinfo)
 
79
{
 
80
    g_object_set_data_full (G_OBJECT (lsrc), "server-info", sinfo,
 
81
                            (GDestroyNotify)free_ldap_server_info);
 
82
}
 
83
 
 
84
static LDAPServerInfo*         
 
85
get_ldap_server_info (SeahorseLDAPSource *lsrc, gboolean force)
 
86
{
 
87
    LDAPServerInfo *sinfo;
 
88
    
 
89
    sinfo = g_object_get_data (G_OBJECT (lsrc), "server-info");
 
90
 
 
91
    /* When we're asked to force getting the data, we fill in 
 
92
     * some defaults */   
 
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");
 
97
        sinfo->version = 0;
 
98
        set_ldap_server_info (lsrc, sinfo);
 
99
    } 
 
100
    
 
101
    return sinfo;
 
102
}
 
103
                                                 
 
104
 
 
105
/* -----------------------------------------------------------------------------
 
106
 *  LDAP HELPERS
 
107
 */
 
108
 
 
109
#define LDAP_ERROR_DOMAIN (get_ldap_error_domain())
 
110
 
 
111
static gchar**
 
112
get_ldap_values (LDAP *ld, LDAPMessage *entry, const char *attribute)
 
113
{
 
114
    GArray *array;
 
115
    struct berval **bv;
 
116
    gchar *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 (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);
 
128
    }
 
129
 
 
130
    return (gchar**)g_array_free (array, FALSE);
 
131
}
 
132
 
 
133
#if WITH_DEBUG
 
134
 
 
135
static void
 
136
dump_ldap_entry (LDAP *ld, LDAPMessage *res)
 
137
{
 
138
    BerElement *pos;
 
139
    gchar **values;
 
140
    gchar **v;
 
141
    char *t;
 
142
    
 
143
    t = ldap_get_dn (ld, res);
 
144
    g_printerr ("dn: %s\n", t);
 
145
    ldap_memfree (t);
 
146
    
 
147
    for (t = ldap_first_attribute (ld, res, &pos); t; 
 
148
         t = ldap_next_attribute (ld, res, pos)) {
 
149
             
 
150
        values = get_ldap_values (ld, res, t);
 
151
        for (v = values; *v; v++) 
 
152
            g_printerr ("%s: %s\n", t, *v);
 
153
             
 
154
        g_strfreev (values);
 
155
        ldap_memfree (t);
 
156
    }
 
157
    
 
158
    ber_free (pos, 0);
 
159
}
 
160
 
 
161
#endif /* WITH_DEBUG */
 
162
 
 
163
static GQuark
 
164
get_ldap_error_domain ()
 
165
{
 
166
    static GQuark q = 0;
 
167
    if(q == 0)
 
168
        q = g_quark_from_static_string ("seahorse-ldap-error");
 
169
    return q;
 
170
}
 
171
 
 
172
static gchar*
 
173
get_string_attribute (LDAP *ld, LDAPMessage *res, const char *attribute)
 
174
{
 
175
    gchar **vals;
 
176
    gchar *v;
 
177
    
 
178
    vals = get_ldap_values (ld, res, attribute);
 
179
    if (!vals)
 
180
        return NULL; 
 
181
    v = vals[0] ? g_strdup (vals[0]) : NULL;
 
182
    g_strfreev (vals);
 
183
    return v;
 
184
}
 
185
 
 
186
static gboolean
 
187
get_boolean_attribute (LDAP* ld, LDAPMessage *res, const char *attribute)
 
188
{
 
189
    gchar **vals;
 
190
    gboolean b;
 
191
    
 
192
    vals = get_ldap_values (ld, res, attribute);
 
193
    if (!vals)
 
194
        return FALSE;
 
195
    b = vals[0] && atoi (vals[0]) == 1;
 
196
    g_strfreev (vals);
 
197
    return b;
 
198
}
 
199
 
 
200
static long int
 
201
get_int_attribute (LDAP* ld, LDAPMessage *res, const char *attribute)
 
202
{
 
203
    gchar **vals;
 
204
    long int d;
 
205
    
 
206
    vals = get_ldap_values (ld, res, attribute);
 
207
    if (!vals)
 
208
        return 0;
 
209
    d = vals[0] ? atoi (vals[0]) : 0;
 
210
    g_strfreev (vals);
 
211
    return d;         
 
212
}
 
213
 
 
214
static long int
 
215
get_date_attribute (LDAP* ld, LDAPMessage *res, const char *attribute)
 
216
{
 
217
    struct tm t;
 
218
    gchar **vals;
 
219
    long int d = 0;
 
220
    
 
221
    vals = get_ldap_values (ld, res, attribute);
 
222
    if (!vals)
 
223
        return 0;
 
224
        
 
225
    if (vals[0]) {
 
226
        memset(&t, 0, sizeof (t));
 
227
 
 
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);
 
232
 
 
233
        t.tm_year -= 1900;
 
234
        t.tm_isdst = -1;
 
235
        t.tm_mon--;
 
236
 
 
237
        d = mktime (&t);
 
238
    }        
 
239
 
 
240
    g_strfreev (vals);
 
241
    return d;         
 
242
}
 
243
 
 
244
static const gchar*
 
245
get_algo_attribute (LDAP* ld, LDAPMessage *res, const char *attribute)
 
246
{
 
247
        const gchar *a = NULL;
 
248
        gchar **vals;
 
249
    
 
250
        vals = get_ldap_values (ld, res, attribute);
 
251
        if (!vals)
 
252
                return 0;
 
253
    
 
254
        if (vals[0]) {
 
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)
 
259
                        a = "Elgamal";
 
260
                if (g_ascii_strcasecmp (vals[0], "RSA") == 0)
 
261
                        a = "RSA";
 
262
                if (g_ascii_strcasecmp (vals[0], "DSA") == 0)
 
263
                        a = "DSA";     
 
264
        }
 
265
    
 
266
        g_strfreev (vals);
 
267
        return a;
 
268
}
 
269
 
 
270
/* 
 
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.
 
273
 */
 
274
static gchar*
 
275
escape_ldap_value (const gchar *v)
 
276
{
 
277
    GString *value;
 
278
    gchar* result;
 
279
    
 
280
    g_assert (v);
 
281
    value = g_string_sized_new (strlen(v));
 
282
    
 
283
    for ( ; *v; v++) {
 
284
        switch(*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);
 
289
            continue;
 
290
        };  
 
291
 
 
292
        if(*v < 32 || *v > 126) {
 
293
            g_string_append_printf (value, "\\%02X", *v);
 
294
            continue;
 
295
        }
 
296
        
 
297
        value = g_string_append_c (value, *v);
 
298
    }
 
299
    
 
300
    result = g_string_free (value, FALSE);
 
301
    g_strstrip (result);
 
302
    return result;
 
303
}
 
304
 
 
305
typedef gboolean (*SeahorseLdapCallback)   (LDAPMessage *result,
 
306
                                            gpointer user_data);
 
307
 
 
308
typedef struct {
 
309
        GSource source;
 
310
        LDAP *ldap;
 
311
        int ldap_op;
 
312
        GCancellable *cancellable;
 
313
        gboolean cancelled;
 
314
        gint cancelled_sig;
 
315
} SeahorseLdapGSource;
 
316
 
 
317
static gboolean
 
318
seahorse_ldap_gsource_prepare (GSource *gsource,
 
319
                               gint *timeout)
 
320
{
 
321
        SeahorseLdapGSource *ldap_gsource = (SeahorseLdapGSource *)gsource;
 
322
 
 
323
        if (ldap_gsource->cancelled)
 
324
                return TRUE;
 
325
 
 
326
        /* No other way, but to poll */
 
327
        *timeout = 50;
 
328
        return FALSE;
 
329
}
 
330
 
 
331
static gboolean
 
332
seahorse_ldap_gsource_check (GSource *gsource)
 
333
{
 
334
        return TRUE;
 
335
}
 
336
 
 
337
static gboolean
 
338
seahorse_ldap_gsource_dispatch (GSource *gsource,
 
339
                                GSourceFunc callback,
 
340
                                gpointer user_data)
 
341
{
 
342
        SeahorseLdapGSource *ldap_gsource = (SeahorseLdapGSource *)gsource;
 
343
        struct timeval timeout;
 
344
        LDAPMessage *result;
 
345
        gboolean ret;
 
346
        int rc, i;
 
347
 
 
348
        if (ldap_gsource->cancelled) {
 
349
                ((SeahorseLdapCallback)callback) (NULL, user_data);
 
350
                return FALSE;
 
351
        }
 
352
 
 
353
        for (i = 0; i < DEFAULT_LOAD_BATCH; i++) {
 
354
 
 
355
                /* This effects a poll */
 
356
                timeout.tv_sec = 0;
 
357
                timeout.tv_usec = 0;
 
358
 
 
359
                rc = ldap_result (ldap_gsource->ldap, ldap_gsource->ldap_op,
 
360
                                  0, &timeout, &result);
 
361
                if (rc == -1) {
 
362
                        g_warning ("ldap_result failed with rc = %d, errno = %s",
 
363
                                   rc, g_strerror (errno));
 
364
                        return FALSE;
 
365
 
 
366
                /* Timeout */
 
367
                } else if (rc == 0) {
 
368
                        return TRUE;
 
369
                }
 
370
 
 
371
                ret = ((SeahorseLdapCallback)callback) (result, user_data);
 
372
                ldap_msgfree (result);
 
373
 
 
374
                if (!ret)
 
375
                        return FALSE;
 
376
        }
 
377
 
 
378
        return TRUE;
 
379
}
 
380
 
 
381
static void
 
382
seahorse_ldap_gsource_finalize (GSource *gsource)
 
383
{
 
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);
 
388
}
 
389
 
 
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,
 
395
};
 
396
 
 
397
static void
 
398
on_ldap_gsource_cancelled (GCancellable *cancellable,
 
399
                           gpointer user_data)
 
400
{
 
401
        SeahorseLdapGSource *ldap_gsource = user_data;
 
402
        ldap_gsource->cancelled = TRUE;
 
403
}
 
404
 
 
405
static GSource *
 
406
seahorse_ldap_gsource_new (LDAP *ldap,
 
407
                           int ldap_op,
 
408
                           GCancellable *cancellable)
 
409
{
 
410
        GSource *gsource;
 
411
        SeahorseLdapGSource *ldap_gsource;
 
412
 
 
413
        gsource = g_source_new (&seahorse_ldap_gsource_funcs,
 
414
                                sizeof (SeahorseLdapGSource));
 
415
 
 
416
        ldap_gsource = (SeahorseLdapGSource *)gsource;
 
417
        ldap_gsource->ldap = ldap;
 
418
        ldap_gsource->ldap_op = ldap_op;
 
419
 
 
420
        if (cancellable) {
 
421
                ldap_gsource->cancellable = g_object_ref (cancellable);
 
422
                ldap_gsource->cancelled_sig = g_cancellable_connect (cancellable,
 
423
                                                                     G_CALLBACK (on_ldap_gsource_cancelled),
 
424
                                                                     ldap_gsource, NULL);
 
425
        }
 
426
 
 
427
        return gsource;
 
428
}
 
429
 
 
430
static gboolean
 
431
seahorse_ldap_source_propagate_error (SeahorseLDAPSource *self,
 
432
                                      int rc, GError **error)
 
433
{
 
434
        gchar *server;
 
435
 
 
436
        if (rc == LDAP_SUCCESS)
 
437
                return FALSE;
 
438
 
 
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));
 
442
        g_free (server);
 
443
 
 
444
        return TRUE;
 
445
}
 
446
 
 
447
typedef struct {
 
448
        GCancellable *cancellable;
 
449
        LDAP *ldap;
 
450
} source_connect_closure;
 
451
 
 
452
static void
 
453
source_connect_free (gpointer data)
 
454
{
 
455
        source_connect_closure *closure = data;
 
456
        g_clear_object (&closure->cancellable);
 
457
        if (closure->ldap)
 
458
                ldap_unbind_ext (closure->ldap, NULL, NULL);
 
459
        g_free (closure);
 
460
}
 
461
 
 
462
static gboolean
 
463
on_connect_server_info_completed (LDAPMessage *result,
 
464
                                  gpointer user_data)
 
465
{
 
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;
 
470
        char *message;
 
471
        int code;
 
472
        int type;
 
473
        int rc;
 
474
 
 
475
        type = ldap_msgtype (result);
 
476
        g_return_val_if_fail (type == LDAP_RES_SEARCH_ENTRY || type == LDAP_RES_SEARCH_RESULT, FALSE);
 
477
 
 
478
        /* If we have results then fill in the server info */
 
479
        if (type == LDAP_RES_SEARCH_ENTRY) {
 
480
 
 
481
                seahorse_debug ("Server Info Result:");
 
482
#ifdef WITH_DEBUG
 
483
                if (seahorse_debugging)
 
484
                        dump_ldap_entry (closure->ldap, result);
 
485
#endif
 
486
 
 
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");
 
491
                if (!sinfo->base_dn)
 
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);
 
495
 
 
496
                return TRUE; /* callback again */
 
497
 
 
498
        } else {
 
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);
 
502
 
 
503
                if (code != LDAP_SUCCESS)
 
504
                        g_warning ("operation to get LDAP server info failed: %s", message);
 
505
 
 
506
                ldap_memfree (message);
 
507
 
 
508
                g_simple_async_result_complete_in_idle (res);
 
509
                seahorse_progress_end (closure->cancellable, res);
 
510
                return FALSE; /* don't callback again */
 
511
        }
 
512
}
 
513
 
 
514
static const char *SERVER_ATTRIBUTES[] = {
 
515
        "basekeyspacedn",
 
516
        "pgpbasekeyspacedn",
 
517
        "version",
 
518
        NULL
 
519
};
 
520
 
 
521
static gboolean
 
522
on_connect_bind_completed (LDAPMessage *result,
 
523
                           gpointer user_data)
 
524
{
 
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;
 
530
        char *message;
 
531
        int ldap_op;
 
532
        int code;
 
533
        int rc;
 
534
 
 
535
        g_return_val_if_fail (ldap_msgtype (result) == LDAP_RES_BIND, FALSE);
 
536
 
 
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);
 
541
 
 
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 */
 
546
        }
 
547
 
 
548
        /* Check if we need server info */
 
549
        sinfo = get_ldap_server_info (self, FALSE);
 
550
        if (sinfo != NULL) {
 
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 */
 
554
        }
 
555
 
 
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);
 
560
 
 
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 */
 
565
 
 
566
        } else {
 
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);
 
573
        }
 
574
 
 
575
        return FALSE; /* don't call this callback again */
 
576
}
 
577
 
 
578
static void
 
579
once_resolved_start_connect (SeahorseLDAPSource *self,
 
580
                             GSimpleAsyncResult *res,
 
581
                             const gchar *address)
 
582
{
 
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;
 
587
        struct berval cred;
 
588
        int ldap_op;
 
589
        gchar *url;
 
590
        gchar *text;
 
591
        int rc;
 
592
 
 
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]);
 
596
 
 
597
        if ((text = strchr (server, ':')) != NULL) {
 
598
                *text = 0;
 
599
                text++;
 
600
                port = atoi (text);
 
601
                if (port <= 0 || port >= G_MAXUINT16) {
 
602
                        g_warning ("invalid port number: %s (using default)", text);
 
603
                        port = LDAP_PORT;
 
604
                }
 
605
        }
 
606
 
 
607
        url = g_strdup_printf ("ldap://%s:%u", address, port);
 
608
        rc = ldap_initialize (&closure->ldap, url);
 
609
        g_free (url);
 
610
 
 
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);
 
614
 
 
615
        /* Start the bind operation */
 
616
        } else {
 
617
                cred.bv_val = "";
 
618
                cred.bv_len = 0;
 
619
 
 
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);
 
625
 
 
626
                } else {
 
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);
 
633
                }
 
634
        }
 
635
}
 
636
 
 
637
#ifdef WITH_SOUP
 
638
 
 
639
static void
 
640
on_address_resolved_complete (SoupAddress *address,
 
641
                              guint status,
 
642
                              gpointer user_data)
 
643
{
 
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);
 
647
        gchar *server;
 
648
 
 
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);
 
652
        g_free (server);
 
653
 
 
654
        /* DNS failed */
 
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);
 
660
 
 
661
        /* Yay resolved */
 
662
        } else {
 
663
                once_resolved_start_connect (self, res, soup_address_get_physical (address));
 
664
        }
 
665
 
 
666
        g_object_unref (res);
 
667
}
 
668
 
 
669
#endif /* WITH_SOUP */
 
670
 
 
671
static void
 
672
seahorse_ldap_source_connect_async (SeahorseLDAPSource *source,
 
673
                                    GCancellable *cancellable,
 
674
                                    GAsyncReadyCallback callback,
 
675
                                    gpointer user_data)
 
676
{
 
677
        GSimpleAsyncResult *res;
 
678
        source_connect_closure *closure;
 
679
#ifdef WITH_SOUP
 
680
        SoupAddress *address;
 
681
        gchar *server = NULL;
 
682
        gchar *pos;
 
683
#endif
 
684
 
 
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);
 
690
 
 
691
        g_object_get (source, "key-server", &server, NULL);
 
692
        g_return_if_fail (server && server[0]);
 
693
        if ((pos = strchr (server, ':')) != NULL)
 
694
                *pos = 0;
 
695
 
 
696
        seahorse_progress_prep_and_begin (cancellable, res, NULL);
 
697
 
 
698
        /* If we have libsoup, try and resolve asynchronously */
 
699
#ifdef WITH_SOUP
 
700
        address = soup_address_new (server, LDAP_PORT);
 
701
        seahorse_progress_update (cancellable, res, _("Resolving server address: %s"), server);
 
702
 
 
703
        soup_address_resolve_async (address, NULL, cancellable,
 
704
                                    on_address_resolved_complete,
 
705
                                    g_object_ref (res));
 
706
        g_object_unref (address);
 
707
 
 
708
#else /* !WITH_SOUP */
 
709
 
 
710
        once_resolved_start_connect (self, res, server);
 
711
 
 
712
#endif
 
713
 
 
714
        g_free (server);
 
715
        g_object_unref (res);
 
716
}
 
717
 
 
718
static LDAP *
 
719
seahorse_ldap_source_connect_finish (SeahorseLDAPSource *source,
 
720
                                     GAsyncResult *result,
 
721
                                     GError **error)
 
722
{
 
723
        source_connect_closure *closure;
 
724
        LDAP *ldap;
 
725
 
 
726
        g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
 
727
                              seahorse_ldap_source_connect_async), NULL);
 
728
 
 
729
        if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
 
730
                return NULL;
 
731
 
 
732
        closure = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
 
733
        ldap = closure->ldap;
 
734
        closure->ldap = NULL;
 
735
        return ldap;
 
736
}
 
737
 
 
738
enum {
 
739
        PROP_0,
 
740
        PROP_SOURCE_TAG,
 
741
        PROP_SOURCE_LOCATION
 
742
};
 
743
 
 
744
static void seahorse_source_iface (SeahorseSourceIface *iface);
 
745
 
 
746
G_DEFINE_TYPE_EXTENDED (SeahorseLDAPSource, seahorse_ldap_source, SEAHORSE_TYPE_SERVER_SOURCE, 0,
 
747
                        G_IMPLEMENT_INTERFACE (SEAHORSE_TYPE_SOURCE, seahorse_source_iface));
 
748
 
 
749
static void 
 
750
seahorse_ldap_source_init (SeahorseLDAPSource *lsrc)
 
751
{
 
752
 
 
753
}
 
754
 
 
755
static void 
 
756
seahorse_ldap_source_get_property (GObject *object, guint prop_id, GValue *value,
 
757
                                   GParamSpec *pspec)
 
758
{
 
759
    switch (prop_id) {
 
760
    case PROP_SOURCE_TAG:
 
761
        g_value_set_uint (value, SEAHORSE_PGP);
 
762
        break;
 
763
    case PROP_SOURCE_LOCATION:
 
764
        g_value_set_enum (value, SEAHORSE_LOCATION_REMOTE);
 
765
        break;
 
766
    };        
 
767
}
 
768
 
 
769
/* Initialize the basic class stuff */
 
770
static void
 
771
seahorse_ldap_source_class_init (SeahorseLDAPSourceClass *klass)
 
772
{
 
773
        GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
774
 
 
775
        gobject_class->get_property = seahorse_ldap_source_get_property;
 
776
 
 
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");
 
779
 
 
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);
 
783
}
 
784
 
 
785
typedef struct {
 
786
        GCancellable *cancellable;
 
787
        gchar *filter;
 
788
        LDAP *ldap;
 
789
        GList *results;
 
790
} source_search_closure;
 
791
 
 
792
static void
 
793
source_search_free (gpointer data)
 
794
{
 
795
        source_search_closure *closure = data;
 
796
        g_clear_object (&closure->cancellable);
 
797
        g_list_free (closure->results);
 
798
        g_free (closure->filter);
 
799
        if (closure->ldap)
 
800
                ldap_unbind_ext (closure->ldap, NULL, NULL);
 
801
        g_free (closure);
 
802
}
 
803
 
 
804
static const char *PGP_ATTRIBUTES[] = {
 
805
        "pgpcertid",
 
806
        "pgpuserid",
 
807
        "pgprevoked",
 
808
        "pgpdisabled",
 
809
        "pgpkeycreatetime",
 
810
        "pgpkeyexpiretime"
 
811
        "pgpkeysize",
 
812
        "pgpkeytype",
 
813
        NULL
 
814
};
 
815
 
 
816
static void
 
817
add_key (SeahorseLDAPSource *ssrc, SeahorsePgpKey *key)
 
818
{
 
819
        SeahorseObject *prev;
 
820
        GQuark keyid;
 
821
 
 
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);
 
824
 
 
825
        if (prev != NULL) {
 
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));
 
829
                return;
 
830
        }
 
831
 
 
832
        /* Add to context */
 
833
        seahorse_object_set_source (SEAHORSE_OBJECT (key), SEAHORSE_SOURCE (ssrc));
 
834
        seahorse_context_add_object (SCTX_APP (), SEAHORSE_OBJECT (key));
 
835
}
 
836
 
 
837
/* Add a key to the key source from an LDAP entry */
 
838
static SeahorseObject *
 
839
search_parse_key_from_ldap_entry (SeahorseLDAPSource *self,
 
840
                                  LDAP *ldap,
 
841
                                  LDAPMessage *res)
 
842
{
 
843
        SeahorseObject *result = NULL;
 
844
        const gchar *algo;
 
845
        long int timestamp;
 
846
        long int expires;
 
847
        gchar *fpr, *fingerprint;
 
848
        gchar *uidstr;
 
849
        gboolean revoked;
 
850
        gboolean disabled;
 
851
        int length;
 
852
 
 
853
        g_return_val_if_fail (ldap_msgtype (res) == LDAP_RES_SEARCH_ENTRY, NULL);
 
854
 
 
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");
 
863
 
 
864
        if (fpr && uidstr) {
 
865
                SeahorsePgpSubkey *subkey;
 
866
                SeahorsePgpKey *key;
 
867
                SeahorsePgpUid *uid;
 
868
                GList *list;
 
869
                guint flags;
 
870
 
 
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);
 
881
 
 
882
                flags = SEAHORSE_FLAG_EXPORTABLE;
 
883
                if (revoked)
 
884
                        flags |= SEAHORSE_FLAG_REVOKED;
 
885
                if (disabled)
 
886
                        flags |= SEAHORSE_FLAG_DISABLED;
 
887
                seahorse_pgp_subkey_set_flags (subkey, flags);
 
888
 
 
889
                /* Build up a uid */
 
890
                uid = seahorse_pgp_uid_new (uidstr);
 
891
                if (revoked)
 
892
                        seahorse_pgp_uid_set_validity (uid, SEAHORSE_VALIDITY_REVOKED);
 
893
 
 
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);
 
904
 
 
905
                add_key (self, key);
 
906
                g_object_unref (key);
 
907
                result = SEAHORSE_OBJECT (key);
 
908
        }
 
909
 
 
910
        g_free (fpr);
 
911
        g_free (uidstr);
 
912
 
 
913
        return result;
 
914
}
 
915
 
 
916
static gboolean
 
917
on_search_search_completed (LDAPMessage *result,
 
918
                            gpointer user_data)
 
919
{
 
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;
 
924
        SeahorseObject *key;
 
925
        char *message;
 
926
        int code;
 
927
        int type;
 
928
        int rc;
 
929
 
 
930
        type = ldap_msgtype (result);
 
931
        g_return_val_if_fail (type == LDAP_RES_SEARCH_ENTRY || type == LDAP_RES_SEARCH_RESULT, FALSE);
 
932
 
 
933
        /* An LDAP entry */
 
934
        if (type == LDAP_RES_SEARCH_ENTRY) {
 
935
                seahorse_debug ("Retrieved Key Entry:");
 
936
#ifdef WITH_DEBUG
 
937
                if (seahorse_debugging)
 
938
                        dump_ldap_entry (closure->ldap, result);
 
939
#endif
 
940
 
 
941
                key = search_parse_key_from_ldap_entry (self, closure->ldap, result);
 
942
                if (key != NULL)
 
943
                        closure->results = g_list_prepend (closure->results, key);
 
944
                return TRUE; /* keep calling this callback */
 
945
 
 
946
        /* All entries done */
 
947
        } else {
 
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);
 
951
 
 
952
                /* Error codes that we ignore */
 
953
                switch (code) {
 
954
                case LDAP_SIZELIMIT_EXCEEDED:
 
955
                        code = LDAP_SUCCESS;
 
956
                        break;
 
957
                };
 
958
 
 
959
                /* Failure */
 
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);
 
965
 
 
966
                ldap_memfree (message);
 
967
                seahorse_progress_end (closure->cancellable, res);
 
968
                g_simple_async_result_complete (res);
 
969
                return FALSE;
 
970
        }
 
971
}
 
972
 
 
973
static void
 
974
on_search_connect_completed (GObject *source,
 
975
                             GAsyncResult *result,
 
976
                             gpointer user_data)
 
977
{
 
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;
 
983
        int ldap_op;
 
984
        int rc;
 
985
 
 
986
        closure->ldap = seahorse_ldap_source_connect_finish (SEAHORSE_LDAP_SOURCE (source),
 
987
                                                             result, &error);
 
988
        if (error != NULL) {
 
989
                g_simple_async_result_take_error (res, error);
 
990
                g_simple_async_result_complete (res);
 
991
                g_object_unref (res);
 
992
                return;
 
993
        }
 
994
 
 
995
        sinfo = get_ldap_server_info (self, TRUE);
 
996
 
 
997
        seahorse_debug ("Searching Server ... base: %s, filter: %s",
 
998
                        sinfo->base_dn, closure->filter);
 
999
 
 
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);
 
1003
 
 
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);
 
1007
 
 
1008
        } else {
 
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);
 
1015
        }
 
1016
 
 
1017
        g_object_unref (res);
 
1018
}
 
1019
 
 
1020
 
 
1021
static void
 
1022
seahorse_ldap_source_search_async (SeahorseSource *source,
 
1023
                                   const gchar *match,
 
1024
                                   GCancellable *cancellable,
 
1025
                                   GAsyncReadyCallback callback,
 
1026
                                   gpointer user_data)
 
1027
{
 
1028
        SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (source);
 
1029
        source_search_closure *closure;
 
1030
        GSimpleAsyncResult *res;
 
1031
        gchar *text;
 
1032
 
 
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);
 
1039
        g_free (text);
 
1040
        g_simple_async_result_set_op_res_gpointer (res, closure, source_search_free);
 
1041
 
 
1042
        seahorse_progress_prep_and_begin (closure->cancellable, res, NULL);
 
1043
 
 
1044
        seahorse_ldap_source_connect_async (self, cancellable,
 
1045
                                            on_search_connect_completed,
 
1046
                                            g_object_ref (res));
 
1047
 
 
1048
        g_object_unref (res);
 
1049
}
 
1050
 
 
1051
static GList *
 
1052
seahorse_ldap_source_search_finish (SeahorseSource *source,
 
1053
                                    GAsyncResult *result,
 
1054
                                    GError **error)
 
1055
{
 
1056
        source_search_closure *closure;
 
1057
        GList *keys;
 
1058
 
 
1059
        g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
 
1060
                              seahorse_ldap_source_search_async), NULL);
 
1061
 
 
1062
        if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
 
1063
                return NULL;
 
1064
 
 
1065
        closure = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
 
1066
        keys = closure->results;
 
1067
        closure->results = NULL;
 
1068
        return keys;
 
1069
}
 
1070
 
 
1071
typedef struct {
 
1072
        GPtrArray *keydata;
 
1073
        gint current_index;
 
1074
        GCancellable *cancellable;
 
1075
        LDAP *ldap;
 
1076
} source_import_closure;
 
1077
 
 
1078
static void
 
1079
source_import_free (gpointer data)
 
1080
{
 
1081
        source_import_closure *closure = data;
 
1082
        g_ptr_array_free (closure->keydata, TRUE);
 
1083
        g_clear_object (&closure->cancellable);
 
1084
        if (closure->ldap)
 
1085
                ldap_unbind_ext (closure->ldap, NULL, NULL);
 
1086
        g_free (closure);
 
1087
}
 
1088
 
 
1089
static void       import_send_key       (SeahorseLDAPSource *self,
 
1090
                                         GSimpleAsyncResult *res);
 
1091
 
 
1092
/* Called when results come in for a key send */
 
1093
static gboolean
 
1094
on_import_add_completed (LDAPMessage *result,
 
1095
                         gpointer user_data)
 
1096
{
 
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;
 
1101
        char *message;
 
1102
        int code;
 
1103
        int rc;
 
1104
 
 
1105
        g_return_val_if_fail (ldap_msgtype (result) == LDAP_RES_ADD, FALSE);
 
1106
 
 
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);
 
1110
 
 
1111
        /* TODO: Somehow communicate this to the user */
 
1112
        if (code == LDAP_ALREADY_EXISTS)
 
1113
                code = LDAP_SUCCESS;
 
1114
 
 
1115
        ldap_memfree (message);
 
1116
 
 
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 */
 
1121
        }
 
1122
 
 
1123
        import_send_key (self, res);
 
1124
        return FALSE; /* don't call for this source again */
 
1125
}
 
1126
 
 
1127
static void
 
1128
import_send_key (SeahorseLDAPSource *self,
 
1129
                 GSimpleAsyncResult *res)
 
1130
{
 
1131
        source_import_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
 
1132
        LDAPServerInfo *sinfo;
 
1133
        gchar *base;
 
1134
        LDAPMod mod;
 
1135
        LDAPMod *attrs[2];
 
1136
        char *values[2];
 
1137
        GSource *gsource;
 
1138
        GError *error = NULL;
 
1139
        gchar *keydata;
 
1140
        int ldap_op;
 
1141
        int rc;
 
1142
 
 
1143
        if (closure->current_index >= 0) {
 
1144
                keydata = closure->keydata->pdata[closure->current_index];
 
1145
                seahorse_progress_end (closure->cancellable, keydata);
 
1146
        }
 
1147
 
 
1148
        closure->current_index++;
 
1149
 
 
1150
        /* All done, complete operation */
 
1151
        if (closure->current_index == (gint)closure->keydata->len) {
 
1152
                g_simple_async_result_complete (res);
 
1153
                return;
 
1154
        }
 
1155
 
 
1156
        keydata = closure->keydata->pdata[closure->current_index];
 
1157
        seahorse_progress_begin (closure->cancellable, keydata);
 
1158
        values[0] = keydata;
 
1159
        values[1] = NULL;
 
1160
 
 
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;
 
1166
 
 
1167
        attrs[0] = &mod;
 
1168
        attrs[1] = NULL;
 
1169
 
 
1170
        base = g_strdup_printf ("pgpCertid=virtual,%s", sinfo->base_dn);
 
1171
        rc = ldap_add_ext (closure->ldap, base, attrs, NULL, NULL, &ldap_op);
 
1172
 
 
1173
        g_free (base);
 
1174
 
 
1175
        if (seahorse_ldap_source_propagate_error (self, rc, &error)) {
 
1176
                g_simple_async_result_complete (res);
 
1177
                return;
 
1178
        }
 
1179
 
 
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);
 
1186
}
 
1187
 
 
1188
static void
 
1189
on_import_connect_completed (GObject *source,
 
1190
                             GAsyncResult *result,
 
1191
                             gpointer user_data)
 
1192
{
 
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;
 
1196
 
 
1197
        closure->ldap = seahorse_ldap_source_connect_finish (SEAHORSE_LDAP_SOURCE (source),
 
1198
                                                             result, &error);
 
1199
        if (error != NULL) {
 
1200
                g_simple_async_result_take_error (res, error);
 
1201
                g_simple_async_result_complete (res);
 
1202
        } else {
 
1203
                import_send_key (SEAHORSE_LDAP_SOURCE (source), res);
 
1204
        }
 
1205
 
 
1206
        g_object_unref (res);
 
1207
}
 
1208
 
 
1209
static void
 
1210
seahorse_ldap_source_import_async (SeahorseSource *source,
 
1211
                                   GInputStream *input,
 
1212
                                   GCancellable *cancellable,
 
1213
                                   GAsyncReadyCallback callback,
 
1214
                                   gpointer user_data)
 
1215
{
 
1216
        SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (source);
 
1217
        source_import_closure *closure;
 
1218
        GSimpleAsyncResult *res;
 
1219
        gchar *keydata;
 
1220
        guint len;
 
1221
 
 
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);
 
1228
 
 
1229
        closure->keydata =g_ptr_array_new_with_free_func (g_free);
 
1230
        for (;;) {
 
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-----");
 
1234
                if (len > 0) {
 
1235
                        keydata = g_string_free (buf, FALSE);
 
1236
                        g_ptr_array_add (closure->keydata, keydata);
 
1237
                        seahorse_progress_prep (closure->cancellable, keydata, NULL);
 
1238
                } else {
 
1239
                        g_string_free (buf, TRUE);
 
1240
                        break;
 
1241
                }
 
1242
        }
 
1243
 
 
1244
        seahorse_ldap_source_connect_async (self, cancellable,
 
1245
                                            on_import_connect_completed,
 
1246
                                            g_object_ref (res));
 
1247
 
 
1248
        g_object_unref (res);
 
1249
}
 
1250
 
 
1251
static GList *
 
1252
seahorse_ldap_source_import_finish (SeahorseSource *source,
 
1253
                                    GAsyncResult *result,
 
1254
                                    GError **error)
 
1255
{
 
1256
        g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
 
1257
                              seahorse_ldap_source_import_async), NULL);
 
1258
 
 
1259
        if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
 
1260
                return NULL;
 
1261
 
 
1262
        /* We don't know the keys that were imported, since this is a server */
 
1263
        return NULL;
 
1264
}
 
1265
 
 
1266
typedef struct {
 
1267
        GPtrArray *fingerprints;
 
1268
        gint current_index;
 
1269
        GOutputStream *output;
 
1270
        GCancellable *cancellable;
 
1271
        LDAP *ldap;
 
1272
} source_export_closure;
 
1273
 
 
1274
static void
 
1275
source_export_free (gpointer data)
 
1276
{
 
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);
 
1281
        if (closure->ldap)
 
1282
                ldap_unbind_ext (closure->ldap, NULL, NULL);
 
1283
        g_free (closure);
 
1284
}
 
1285
 
 
1286
static void     export_retrieve_key     (SeahorseLDAPSource *self,
 
1287
                                         GSimpleAsyncResult *res);
 
1288
 
 
1289
static gboolean
 
1290
on_export_search_completed (LDAPMessage *result,
 
1291
                            gpointer user_data)
 
1292
{
 
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;
 
1297
        char *message;
 
1298
        GError *error = NULL;
 
1299
        gboolean ret;
 
1300
        gchar *key;
 
1301
        gsize written;
 
1302
        int code;
 
1303
        int type;
 
1304
        int rc;
 
1305
 
 
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);
 
1309
 
 
1310
        /* An LDAP Entry */
 
1311
        if (type == LDAP_RES_SEARCH_ENTRY) {
 
1312
 
 
1313
                seahorse_debug ("Server Info Result:");
 
1314
#ifdef WITH_DEBUG
 
1315
                if (seahorse_debugging)
 
1316
                        dump_ldap_entry (closure->ldap, result);
 
1317
#endif
 
1318
 
 
1319
                key = get_string_attribute (closure->ldap, result, sinfo->key_attr);
 
1320
 
 
1321
                if (key == NULL) {
 
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);
 
1326
                        return FALSE;
 
1327
                }
 
1328
 
 
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);
 
1332
 
 
1333
                g_free (key);
 
1334
 
 
1335
                if (!ret) {
 
1336
                        g_simple_async_result_take_error (res, error);
 
1337
                        g_simple_async_result_complete (res);
 
1338
                        return FALSE;
 
1339
                }
 
1340
 
 
1341
                return TRUE;
 
1342
 
 
1343
        /* No more entries, result */
 
1344
        } else {
 
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);
 
1348
 
 
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);
 
1352
                        return FALSE;
 
1353
                }
 
1354
 
 
1355
                ldap_memfree (message);
 
1356
 
 
1357
                /* Process more keys if possible */
 
1358
                export_retrieve_key (self, res);
 
1359
                return FALSE;
 
1360
        }
 
1361
}
 
1362
 
 
1363
static void
 
1364
export_retrieve_key (SeahorseLDAPSource *self,
 
1365
                     GSimpleAsyncResult *res)
 
1366
{
 
1367
        source_export_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
 
1368
        LDAPServerInfo *sinfo;
 
1369
        gchar *filter;
 
1370
        char *attrs[2];
 
1371
        GSource *gsource;
 
1372
        const gchar *fingerprint;
 
1373
        GError *error = NULL;
 
1374
        int length, rc;
 
1375
        int ldap_op;
 
1376
 
 
1377
        if (closure->current_index > 0) {
 
1378
                fingerprint = closure->fingerprints->pdata[closure->current_index];
 
1379
                seahorse_progress_end (closure->cancellable, fingerprint);
 
1380
        }
 
1381
 
 
1382
        closure->current_index++;
 
1383
 
 
1384
        /* All done, complete operation */
 
1385
        if (closure->current_index == (gint)closure->fingerprints->len) {
 
1386
                g_simple_async_result_complete (res);
 
1387
                return;
 
1388
        }
 
1389
 
 
1390
        fingerprint = closure->fingerprints->pdata[closure->current_index];
 
1391
        seahorse_progress_begin (closure->cancellable, fingerprint);
 
1392
        length = strlen (fingerprint);
 
1393
        if (length > 16)
 
1394
                fingerprint += (length - 16);
 
1395
 
 
1396
        filter = g_strdup_printf ("(pgpcertid=%.16s)", fingerprint);
 
1397
        sinfo = get_ldap_server_info (self, TRUE);
 
1398
 
 
1399
        attrs[0] = sinfo->key_attr;
 
1400
        attrs[1] = NULL;
 
1401
 
 
1402
        rc = ldap_search_ext (closure->ldap, sinfo->base_dn, LDAP_SCOPE_SUBTREE,
 
1403
                              filter, attrs, 0,
 
1404
                              NULL, NULL, NULL, 0, &ldap_op);
 
1405
        g_free (filter);
 
1406
 
 
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);
 
1410
                return;
 
1411
        }
 
1412
 
 
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);
 
1419
}
 
1420
 
 
1421
static void
 
1422
on_export_connect_completed (GObject *source,
 
1423
                             GAsyncResult *result,
 
1424
                             gpointer user_data)
 
1425
{
 
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;
 
1429
 
 
1430
        closure->ldap = seahorse_ldap_source_connect_finish (SEAHORSE_LDAP_SOURCE (source),
 
1431
                                                             result, &error);
 
1432
        if (error != NULL) {
 
1433
                g_simple_async_result_take_error (res, error);
 
1434
                g_simple_async_result_complete (res);
 
1435
        } else {
 
1436
                export_retrieve_key (SEAHORSE_LDAP_SOURCE (source), res);
 
1437
        }
 
1438
 
 
1439
        g_object_unref (res);
 
1440
}
 
1441
 
 
1442
static void
 
1443
seahorse_ldap_source_export_raw_async (SeahorseSource *source,
 
1444
                                       GList *keyids,
 
1445
                                       GOutputStream *output,
 
1446
                                       GCancellable *cancellable,
 
1447
                                       GAsyncReadyCallback callback,
 
1448
                                       gpointer user_data)
 
1449
{
 
1450
        SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (source);
 
1451
        source_export_closure *closure;
 
1452
        GSimpleAsyncResult *res;
 
1453
        gchar *fingerprint;
 
1454
        GList *l;
 
1455
 
 
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);
 
1466
        }
 
1467
        closure->current_index = -1;
 
1468
        g_simple_async_result_set_op_res_gpointer (res, closure, source_export_free);
 
1469
 
 
1470
        seahorse_ldap_source_connect_async (self, cancellable,
 
1471
                                            on_export_connect_completed,
 
1472
                                            g_object_ref (res));
 
1473
 
 
1474
        g_object_unref (res);
 
1475
}
 
1476
 
 
1477
static GOutputStream *
 
1478
seahorse_ldap_source_export_raw_finish (SeahorseSource *source,
 
1479
                                        GAsyncResult *result,
 
1480
                                        GError **error)
 
1481
{
 
1482
        source_export_closure *closure;
 
1483
 
 
1484
        g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
 
1485
                              seahorse_ldap_source_export_raw_async), FALSE);
 
1486
 
 
1487
        if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
 
1488
                return FALSE;
 
1489
 
 
1490
        closure = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
 
1491
        return closure->output;
 
1492
}
 
1493
 
 
1494
static void 
 
1495
seahorse_source_iface (SeahorseSourceIface *iface)
 
1496
{
 
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;
 
1503
}
 
1504
 
 
1505
/**
 
1506
 * seahorse_ldap_source_new
 
1507
 * @uri: The server to connect to 
 
1508
 * 
 
1509
 * Creates a new key source for an LDAP PGP server.
 
1510
 * 
 
1511
 * Returns: A new LDAP Key Source
 
1512
 */
 
1513
SeahorseLDAPSource*   
 
1514
seahorse_ldap_source_new (const gchar* uri, const gchar *host)
 
1515
{
 
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, 
 
1519
                         "uri", uri, NULL);
 
1520
}
 
1521
 
 
1522
/**
 
1523
 * seahorse_ldap_is_valid_uri
 
1524
 * @uri: The uri to check
 
1525
 * 
 
1526
 * Returns: Whether the passed uri is valid for an ldap key source
 
1527
 */
 
1528
gboolean              
 
1529
seahorse_ldap_is_valid_uri (const gchar *uri)
 
1530
{
 
1531
    LDAPURLDesc *url;
 
1532
    int r;
 
1533
    
 
1534
    g_return_val_if_fail (uri && *uri, FALSE);
 
1535
    
 
1536
    r = ldap_url_parse (uri, &url);
 
1537
    if (r == LDAP_URL_SUCCESS) {
 
1538
        
 
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;
 
1544
        
 
1545
        ldap_free_urldesc (url);
 
1546
    }
 
1547
        
 
1548
    return r == LDAP_URL_SUCCESS;
 
1549
}
 
1550
 
 
1551
#endif /* WITH_LDAP */