Coverage Report

Created: 2026-01-17 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnupg/g10/call-keyboxd.c
Line
Count
Source
1
/* call-keyboxd.c - Access to the keyboxd storage server
2
 * Copyright (C) 2019, 2024  g10 Code GmbH
3
 *
4
 * This file is part of GnuPG.
5
 *
6
 * GnuPG is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * GnuPG is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, see <https://www.gnu.org/licenses/>.
18
 * SPDX-License-Identifier: GPL-3.0-or-later
19
 */
20
21
#include <config.h>
22
#include <stdio.h>
23
#include <stdlib.h>
24
#include <string.h>
25
#include <errno.h>
26
#include <unistd.h>
27
#include <time.h>
28
#ifdef HAVE_LOCALE_H
29
# include <locale.h>
30
#endif
31
#include <npth.h>
32
33
#include "gpg.h"
34
#include <assuan.h>
35
#include "../common/util.h"
36
#include "../common/membuf.h"
37
#include "options.h"
38
#include "../common/i18n.h"
39
#include "../common/asshelp.h"
40
#include "../common/host2net.h"
41
#include "../common/status.h"
42
#include "../kbx/kbx-client-util.h"
43
#include "keydb.h"
44
45
#include "keydb-private.h"  /* For struct keydb_handle_s */
46
47
48
/* Data used to keep track of keybox daemon sessions.  This allows us
49
 * to use several sessions with the keyboxd and also to reuse already
50
 * established sessions.  Note that gpg.h defines the type
51
 * keyboxd_local_t for this structure. */
52
struct keyboxd_local_s
53
{
54
  /* Link to other keyboxd contexts which are used simultaneously.  */
55
  struct keyboxd_local_s *next;
56
57
  /* The active Assuan context. */
58
  assuan_context_t ctx;
59
60
  /* The client data helper context.  */
61
  kbx_client_data_t kcd;
62
63
  /* I/O buffer with the last search result or NULL.  Used if
64
   * D-lines are used to convey the keyblocks. */
65
  iobuf_t search_result;
66
67
  /* This flag set while an operation is running on this context.  */
68
  unsigned int is_active : 1;
69
70
  /* Flag indicating that a search reset is required.  */
71
  unsigned int need_search_reset : 1;
72
73
};
74
75
76
/* Flag indicating that for example bulk import is enabled.  */
77
static unsigned int in_transaction;
78
79
80
81

82
/* Deinitialize all session resources pertaining to the keyboxd.  */
83
void
84
gpg_keyboxd_deinit_session_data (ctrl_t ctrl)
85
0
{
86
0
  keyboxd_local_t kbl;
87
0
  gpg_error_t err;
88
89
0
  while ((kbl = ctrl->keyboxd_local))
90
0
    {
91
0
      ctrl->keyboxd_local = kbl->next;
92
0
      if (kbl->is_active)
93
0
        log_error ("oops: trying to cleanup an active keyboxd context\n");
94
0
      else
95
0
        {
96
0
          if (kbl->ctx && in_transaction)
97
0
            {
98
              /* This is our hack to commit the changes done during a
99
               * bulk import.  If we won't do that the loss of the
100
               * connection would trigger a rollback in keyboxd.  Note
101
               * that transactions are not associated with a
102
               * connection. */
103
0
              err = assuan_transact (kbl->ctx, "TRANSACTION commit",
104
0
                                     NULL, NULL, NULL, NULL, NULL, NULL);
105
0
              if (err)
106
0
                log_error ("error committing last transaction: %s\n",
107
0
                            gpg_strerror (err));
108
0
              in_transaction = 0;
109
0
            }
110
0
          assuan_release (kbl->ctx);
111
0
          kbl->ctx = NULL;
112
          /*
113
           * Since there may be pipe output FD sent to the server (so
114
           * that it can receive data through the pipe), we should
115
           * release the assuan connection before releasing KBL->KCD.
116
           * This way, the data receiving thread can finish cleanly,
117
           * and we can join the thread.
118
           */
119
0
          kbx_client_data_release (kbl->kcd);
120
0
          kbl->kcd = NULL;
121
0
        }
122
0
      xfree (kbl);
123
0
    }
124
0
}
125
126
127
/* Print a warning if the server's version number is less than our
128
   version number.  Returns an error code on a connection problem.  */
129
static gpg_error_t
130
warn_version_mismatch (assuan_context_t ctx, const char *servername)
131
0
{
132
0
  return warn_server_version_mismatch (ctx, servername, 0,
133
0
                                       write_status_strings2, NULL,
134
0
                                       !opt.quiet);
135
0
}
136
137
138
/* Connect to the keybox daemon and launch it if necessary.  Handle
139
 * the server's initial greeting and set global options.  Returns a
140
 * new assuan context or an error.  */
141
static gpg_error_t
142
create_new_context (ctrl_t ctrl, assuan_context_t *r_ctx)
143
0
{
144
0
  gpg_error_t err;
145
0
  assuan_context_t ctx;
146
147
0
  *r_ctx = NULL;
148
149
0
  err = start_new_keyboxd (&ctx,
150
0
                           GPG_ERR_SOURCE_DEFAULT,
151
0
                           opt.keyboxd_program,
152
0
                           opt.autostart?ASSHELP_FLAG_AUTOSTART:0,
153
0
                           opt.verbose, DBG_IPC,
154
0
                           NULL, ctrl);
155
0
  if (!opt.autostart && gpg_err_code (err) == GPG_ERR_NO_KEYBOXD)
156
0
    {
157
0
      static int shown;
158
159
0
      if (!shown)
160
0
        {
161
0
          shown = 1;
162
0
          log_info (_("no keyboxd running in this session\n"));
163
0
        }
164
0
    }
165
0
  else if (!err && !(err = warn_version_mismatch (ctx, KEYBOXD_NAME)))
166
0
    {
167
      /* Place to emit global options.  */
168
169
0
      if ((opt.import_options & IMPORT_BULK) && !in_transaction)
170
0
        {
171
0
          err = assuan_transact (ctx, "TRANSACTION begin",
172
0
                                 NULL, NULL, NULL, NULL, NULL, NULL);
173
0
          if (err)
174
0
            {
175
0
              log_error ("error enabling bulk import option: %s\n",
176
0
                         gpg_strerror (err));
177
0
            }
178
0
          else
179
0
            in_transaction = 1;
180
0
        }
181
182
0
    }
183
184
0
  if (err)
185
0
    assuan_release (ctx);
186
0
  else
187
0
    *r_ctx = ctx;
188
189
0
  return err;
190
0
}
191
192
193
194
195
/* Get a context for accessing keyboxd.  If no context is available a
196
 * new one is created and if necessary keyboxd is started.  R_KBL
197
 * receives a pointer to the local context object.  */
198
static gpg_error_t
199
open_context (ctrl_t ctrl, keyboxd_local_t *r_kbl)
200
0
{
201
0
  gpg_error_t err;
202
0
  keyboxd_local_t kbl;
203
204
0
  *r_kbl = NULL;
205
0
  for (;;)
206
0
    {
207
0
      for (kbl = ctrl->keyboxd_local; kbl && kbl->is_active; kbl = kbl->next)
208
0
        ;
209
0
      if (kbl)
210
0
        {
211
          /* Found an inactive keyboxd session - return that.  */
212
0
          log_assert (!kbl->is_active);
213
214
0
          kbl->is_active = 1;
215
0
          kbl->need_search_reset = 1;
216
217
0
          *r_kbl = kbl;
218
0
          return 0;
219
0
        }
220
221
      /* None found.  Create a new session and retry.  */
222
0
      kbl = xtrycalloc (1, sizeof *kbl);
223
0
      if (!kbl)
224
0
        return gpg_error_from_syserror ();
225
226
0
      err = create_new_context (ctrl, &kbl->ctx);
227
0
      if (err)
228
0
        {
229
0
          xfree (kbl);
230
0
          return err;
231
0
        }
232
233
0
      err = kbx_client_data_new (&kbl->kcd, kbl->ctx, 0);
234
0
      if (err)
235
0
        {
236
0
          assuan_release (kbl->ctx);
237
0
          xfree (kbl);
238
0
          return err;
239
0
        }
240
241
      /* For thread-saftey we add it to the list and retry; this is
242
       * easier than to employ a lock.  */
243
0
      kbl->next = ctrl->keyboxd_local;
244
0
      ctrl->keyboxd_local = kbl;
245
0
    }
246
  /*NOTREACHED*/
247
0
}
248
249
250

251
/* Create a new database handle.  A database handle is similar to a
252
 * file handle: it contains a local file position.  This is used when
253
 * searching: subsequent searches resume where the previous search
254
 * left off.  To rewind the position, use keydb_search_reset().  This
255
 * function returns NULL on error, sets ERRNO, and prints an error
256
 * diagnostic.  Depending on --use-keyboxd either the old internal
257
 * keydb code is used (keydb.c) or, if set, the processing is diverted
258
 * to the keyboxd. */
259
/* FIXME: We should change the interface to return a gpg_error_t.  */
260
KEYDB_HANDLE
261
keydb_new (ctrl_t ctrl)
262
1.63k
{
263
1.63k
  gpg_error_t err;
264
1.63k
  KEYDB_HANDLE hd;
265
266
1.63k
  if (DBG_CLOCK)
267
1.63k
    log_clock ("keydb_new");
268
269
1.63k
  hd = xtrycalloc (1, sizeof *hd);
270
1.63k
  if (!hd)
271
0
    {
272
0
      err = gpg_error_from_syserror ();
273
0
      goto leave;
274
0
    }
275
276
1.63k
  if (!opt.use_keyboxd)
277
1.63k
    {
278
1.63k
      err = internal_keydb_init (hd);
279
1.63k
      goto leave;
280
1.63k
    }
281
0
  hd->use_keyboxd = 1;
282
0
  hd->ctrl = ctrl;
283
284
0
  err = open_context (ctrl, &hd->kbl);
285
286
1.63k
 leave:
287
1.63k
  if (err)
288
0
    {
289
0
      int rc;
290
0
      log_error (_("error opening key DB: %s\n"), gpg_strerror (err));
291
0
      xfree (hd);
292
0
      hd = NULL;
293
0
      if (!(rc = gpg_err_code_to_errno (err)))
294
0
        rc = gpg_err_code_to_errno (GPG_ERR_EIO);
295
0
      gpg_err_set_errno (rc);
296
0
    }
297
1.63k
  return hd;
298
0
}
299
300
301
/* Release a keydb handle.  */
302
void
303
keydb_release (KEYDB_HANDLE hd)
304
13.1k
{
305
13.1k
  keyboxd_local_t kbl;
306
307
13.1k
  if (!hd)
308
11.5k
    return;
309
310
1.63k
  if (DBG_CLOCK)
311
1.63k
    log_clock ("keydb_release");
312
1.63k
  if (!hd->use_keyboxd)
313
1.63k
    internal_keydb_deinit (hd);
314
0
  else
315
0
    {
316
0
      kbl = hd->kbl;
317
0
      if (DBG_CLOCK)
318
0
        log_clock ("close_context (found)");
319
0
      if (!kbl->is_active)
320
0
        log_fatal ("closing inactive keyboxd context %p\n", kbl);
321
0
      kbl->is_active = 0;
322
0
      hd->kbl = NULL;
323
0
      hd->ctrl = NULL;
324
0
    }
325
1.63k
  xfree (hd);
326
1.63k
}
327
328
329
/* Return the keyblock last found by keydb_search() in *RET_KB.
330
 *
331
 * On success, the function returns 0 and the caller must free *RET_KB
332
 * using release_kbnode().  Otherwise, the function returns an error
333
 * code.
334
 *
335
 * The returned keyblock has the kbnode flag bit 0 set for the node
336
 * with the public key used to locate the keyblock or flag bit 1 set
337
 * for the user ID node.  */
338
gpg_error_t
339
keydb_get_keyblock (KEYDB_HANDLE hd, kbnode_t *ret_kb)
340
0
{
341
0
  gpg_error_t err;
342
343
0
  *ret_kb = NULL;
344
345
0
  if (!hd)
346
0
    return gpg_error (GPG_ERR_INV_ARG);
347
348
0
  if (DBG_CLOCK)
349
0
    log_clock ("%s enter", __func__);
350
351
0
  if (!hd->use_keyboxd)
352
0
    {
353
0
      err = internal_keydb_get_keyblock (hd, ret_kb);
354
0
      goto leave;
355
0
    }
356
357
0
  if (hd->kbl->search_result)
358
0
    {
359
0
      err = keydb_parse_keyblock (hd->kbl->search_result,
360
0
                                  hd->last_ubid_valid? hd->last_pk_no  : 0,
361
0
                                  hd->last_ubid_valid? hd->last_uid_no : 0,
362
0
                                  ret_kb);
363
      /* In contrast to the old code we close the iobuf here and thus
364
       * this function may be called only once to get a keyblock.  */
365
0
      iobuf_close (hd->kbl->search_result);
366
0
      hd->kbl->search_result = NULL;
367
0
    }
368
0
  else
369
0
    {
370
0
      err = gpg_error (GPG_ERR_VALUE_NOT_FOUND);
371
0
      goto leave;
372
0
    }
373
374
0
 leave:
375
0
  if (DBG_CLOCK)
376
0
    log_clock ("%s leave%s", __func__, err? " (failed)":"");
377
0
  return err;
378
0
}
379
380
381
/* Default status callback used to show diagnostics from the keyboxd  */
382
static gpg_error_t
383
keydb_default_status_cb (void *opaque, const char *line)
384
0
{
385
0
  const char *s;
386
387
0
  (void)opaque;
388
389
0
  if ((s = has_leading_keyword (line, "NOTE")))
390
0
    log_info (_("Note: %s\n"), s);
391
0
  else if ((s = has_leading_keyword (line, "WARNING")))
392
0
    log_info (_("WARNING: %s\n"), s);
393
394
0
  return 0;
395
0
}
396
397
398

399
/* Communication object for STORE commands.  */
400
struct store_parm_s
401
{
402
  assuan_context_t ctx;
403
  const void *data;   /* The key in OpenPGP binary format.  */
404
  size_t datalen;     /* The length of DATA.  */
405
};
406
407
408
/* Handle the inquiries from the STORE command.  */
409
static gpg_error_t
410
store_inq_cb (void *opaque, const char *line)
411
0
{
412
0
  struct store_parm_s *parm = opaque;
413
0
  gpg_error_t err = 0;
414
415
0
  if (has_leading_keyword (line, "BLOB"))
416
0
    {
417
0
      if (parm->data)
418
0
        err = assuan_send_data (parm->ctx, parm->data, parm->datalen);
419
0
    }
420
0
  else
421
0
    return gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
422
423
0
  return err;
424
0
}
425
426
427
/* Update the keyblock KB (i.e., extract the fingerprint and find the
428
 * corresponding keyblock in the keyring).
429
 *
430
 * This doesn't do anything if --dry-run was specified.
431
 *
432
 * Returns 0 on success.  Otherwise, it returns an error code.  Note:
433
 * if there isn't a keyblock in the keyring corresponding to KB, then
434
 * this function returns GPG_ERR_VALUE_NOT_FOUND.
435
 *
436
 * This function selects the matching record and modifies the current
437
 * file position to point to the record just after the selected entry.
438
 * Thus, if you do a subsequent search using HD, you should first do a
439
 * keydb_search_reset.  Further, if the selected record is important,
440
 * you should use keydb_push_found_state and keydb_pop_found_state to
441
 * save and restore it.  */
442
gpg_error_t
443
keydb_update_keyblock (ctrl_t ctrl, KEYDB_HANDLE hd, kbnode_t kb)
444
0
{
445
0
  gpg_error_t err;
446
0
  iobuf_t iobuf = NULL;
447
0
  struct store_parm_s parm = {NULL};
448
449
0
  log_assert (kb);
450
0
  log_assert (kb->pkt->pkttype == PKT_PUBLIC_KEY);
451
452
0
  if (!hd)
453
0
    return gpg_error (GPG_ERR_INV_ARG);
454
455
0
  if (!hd->use_keyboxd)
456
0
    {
457
0
      err = internal_keydb_update_keyblock (ctrl, hd, kb);
458
0
      goto leave;
459
0
    }
460
461
0
  if (opt.dry_run)
462
0
    {
463
0
      err = 0;
464
0
      goto leave;
465
0
    }
466
467
0
  err = build_keyblock_image (kb, &iobuf);
468
0
  if (err)
469
0
    goto leave;
470
471
0
  parm.ctx = hd->kbl->ctx;
472
0
  parm.data = iobuf_get_temp_buffer (iobuf);
473
0
  parm.datalen = iobuf_get_temp_length (iobuf);
474
0
  err = assuan_transact (hd->kbl->ctx, "STORE --update",
475
0
                         NULL, NULL,
476
0
                         store_inq_cb, &parm,
477
0
                         keydb_default_status_cb, hd);
478
479
480
0
 leave:
481
0
  iobuf_close (iobuf);
482
0
  return err;
483
0
}
484
485
486
/* Insert a keyblock into one of the underlying keyrings or keyboxes.
487
 *
488
 * By default, the keyring / keybox from which the last search result
489
 * came is used.  If there was no previous search result (or
490
 * keydb_search_reset was called), then the keyring / keybox where the
491
 * next search would start is used (i.e., the current file position).
492
 * In keyboxd mode the keyboxd decides where to store it.
493
 *
494
 * Note: this doesn't do anything if --dry-run was specified.
495
 *
496
 * Returns 0 on success.  Otherwise, it returns an error code.  */
497
gpg_error_t
498
keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
499
0
{
500
0
  gpg_error_t err;
501
0
  iobuf_t iobuf = NULL;
502
0
  struct store_parm_s parm = {NULL};
503
504
0
  if (!hd)
505
0
    return gpg_error (GPG_ERR_INV_ARG);
506
507
0
  if (!hd->use_keyboxd)
508
0
    {
509
0
      err = internal_keydb_insert_keyblock (hd, kb);
510
0
      goto leave;
511
0
    }
512
513
0
  if (opt.dry_run)
514
0
    {
515
0
      err = 0;
516
0
      goto leave;
517
0
    }
518
519
0
  err = build_keyblock_image (kb, &iobuf);
520
0
  if (err)
521
0
    goto leave;
522
523
0
  parm.ctx = hd->kbl->ctx;
524
0
  parm.data = iobuf_get_temp_buffer (iobuf);
525
0
  parm.datalen = iobuf_get_temp_length (iobuf);
526
0
  err = assuan_transact (hd->kbl->ctx, "STORE --insert",
527
0
                         NULL, NULL,
528
0
                         store_inq_cb, &parm,
529
0
                         keydb_default_status_cb, hd);
530
531
0
 leave:
532
0
  iobuf_close (iobuf);
533
0
  return err;
534
0
}
535
536
537
/* Delete the currently selected keyblock.  If you haven't done a
538
 * search yet on this database handle (or called keydb_search_reset),
539
 * then this function returns an error.
540
 *
541
 * Returns 0 on success or an error code, if an error occurred.  */
542
gpg_error_t
543
keydb_delete_keyblock (KEYDB_HANDLE hd)
544
0
{
545
0
  gpg_error_t err;
546
0
  unsigned char hexubid[UBID_LEN * 2 + 1];
547
0
  char line[ASSUAN_LINELENGTH];
548
549
0
  if (!hd)
550
0
    return gpg_error (GPG_ERR_INV_ARG);
551
552
0
  if (!hd->use_keyboxd)
553
0
    {
554
0
      err = internal_keydb_delete_keyblock (hd);
555
0
      goto leave;
556
0
    }
557
558
0
  if (opt.dry_run)
559
0
    {
560
0
      err = 0;
561
0
      goto leave;
562
0
    }
563
564
0
  if (!hd->last_ubid_valid)
565
0
    {
566
0
      err = gpg_error (GPG_ERR_VALUE_NOT_FOUND);
567
0
      goto leave;
568
0
    }
569
570
0
  bin2hex (hd->last_ubid, UBID_LEN, hexubid);
571
0
  snprintf (line, sizeof line, "DELETE %s", hexubid);
572
0
  err = assuan_transact (hd->kbl->ctx, line,
573
0
                         NULL, NULL,
574
0
                         NULL, NULL,
575
0
                         keydb_default_status_cb, hd);
576
577
0
 leave:
578
0
  return err;
579
0
}
580
581
582
/* Clears the current search result and resets the handle's position
583
 * so that the next search starts at the beginning of the database.
584
 *
585
 * Returns 0 on success and an error code if an error occurred.  */
586
gpg_error_t
587
keydb_search_reset (KEYDB_HANDLE hd)
588
6.47k
{
589
6.47k
  gpg_error_t err;
590
591
6.47k
  if (!hd)
592
0
    return gpg_error (GPG_ERR_INV_ARG);
593
594
6.47k
  if (DBG_CLOCK)
595
6.47k
    log_clock ("%s", __func__);
596
6.47k
  if (DBG_CACHE)
597
6.47k
    log_debug ("%s (hd=%p)", __func__, hd);
598
599
6.47k
  if (!hd->use_keyboxd)
600
6.47k
    {
601
6.47k
      err = internal_keydb_search_reset (hd);
602
6.47k
      goto leave;
603
6.47k
    }
604
605
  /* All we need is to tell search that a reset is pending.  Note that
606
   * keydb_new sets this flag as well.  To comply with the
607
   * specification of keydb_delete_keyblock we also need to clear the
608
   * ubid flag so that after a reset a delete can't be performed.  */
609
0
  hd->kbl->need_search_reset = 1;
610
0
  hd->last_ubid_valid = 0;
611
0
  err = 0;
612
613
6.47k
 leave:
614
6.47k
  return err;
615
0
}
616
617
618
619
/* Status callback for SEARCH and NEXT operations.  */
620
static gpg_error_t
621
search_status_cb (void *opaque, const char *line)
622
0
{
623
0
  KEYDB_HANDLE hd = opaque;
624
0
  gpg_error_t err = 0;
625
0
  const char *s;
626
0
  unsigned int n;
627
628
0
  if ((s = has_leading_keyword (line, "PUBKEY_INFO")))
629
0
    {
630
0
      if (atoi (s) != PUBKEY_TYPE_OPGP)
631
0
        err = gpg_error (GPG_ERR_WRONG_BLOB_TYPE);
632
0
      else
633
0
        {
634
0
          hd->last_ubid_valid = 0;
635
0
          while (*s && !spacep (s))
636
0
            s++;
637
0
          if (!(n=hex2fixedbuf (s, hd->last_ubid, sizeof hd->last_ubid)))
638
0
            err = gpg_error (GPG_ERR_INV_VALUE);
639
0
          else
640
0
            {
641
0
              hd->last_ubid_valid = 1;
642
0
              hd->last_uid_no = 0;
643
0
              hd->last_pk_no = 0;
644
0
              s += n;
645
0
              while (*s && !spacep (s))
646
0
                s++;
647
0
              while (spacep (s))
648
0
                s++;
649
0
              if (*s)
650
0
                {
651
0
                  hd->last_uid_no = atoi (s);
652
0
                  while (*s && !spacep (s))
653
0
                    s++;
654
0
                  while (spacep (s))
655
0
                    s++;
656
0
                  if (*s)
657
0
                    {
658
0
                      hd->last_pk_no = atoi (s);
659
                      /* Keyboxd returns 0 for invalid but also for
660
                       * the primary key and 1 for the first subkey.
661
                       * That does not match our use and thus we
662
                       * increment it despite that this maps an
663
                       * invalid index to the primary key.  */
664
0
                      if (hd->last_pk_no >= 0)
665
0
                        hd->last_pk_no++;
666
0
                    }
667
668
0
                }
669
0
            }
670
0
        }
671
0
    }
672
0
  else
673
0
    err = keydb_default_status_cb (opaque, line);
674
675
0
  return err;
676
0
}
677
678
679
/* Search the database for keys matching the search description.  If
680
 * the DB contains any legacy keys, these are silently ignored.
681
 *
682
 * DESC is an array of search terms with NDESC entries.  The search
683
 * terms are or'd together.  That is, the next entry in the DB that
684
 * matches any of the descriptions will be returned.
685
 *
686
 * Note: this function resumes searching where the last search left
687
 * off (i.e., at the current file position).  If you want to search
688
 * from the start of the database, then you need to first call
689
 * keydb_search_reset().
690
 *
691
 * If no key matches the search description, returns
692
 * GPG_ERR_NOT_FOUND.  If there was a match, returns 0.  If an error
693
 * occurred, returns an error code.
694
 *
695
 * The returned key is considered to be selected and the raw data can,
696
 * for instance, be returned by calling keydb_get_keyblock().  */
697
gpg_error_t
698
keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
699
              size_t ndesc, size_t *descindex)
700
8.11k
{
701
8.11k
  gpg_error_t err;
702
8.11k
  int i;
703
8.11k
  char line[ASSUAN_LINELENGTH];
704
8.11k
  char *buffer;
705
8.11k
  size_t len;
706
707
8.11k
  if (!hd)
708
0
    return gpg_error (GPG_ERR_INV_ARG);
709
710
8.11k
  if (descindex)
711
0
    *descindex = 0; /* Make sure it is always set on return.  */
712
713
8.11k
  if (DBG_CLOCK)
714
8.11k
    log_clock ("%s enter", __func__);
715
716
8.11k
  if (DBG_KEYDB)
717
0
    {
718
0
      log_debug ("%s: %zu search descriptions:\n", __func__, ndesc);
719
0
      for (i = 0; i < ndesc; i ++)
720
0
        {
721
0
          char *t = keydb_search_desc_dump (&desc[i]);
722
0
          log_debug ("%s   %d: %s\n", __func__, i, t);
723
0
          xfree (t);
724
0
        }
725
0
    }
726
727
8.11k
  if (!hd->use_keyboxd)
728
8.11k
    {
729
8.11k
      err = internal_keydb_search (hd, desc, ndesc, descindex);
730
8.11k
      goto leave;
731
8.11k
    }
732
733
  /* Clear the result objects.  */
734
0
  if (hd->kbl->search_result)
735
0
    {
736
0
      iobuf_close (hd->kbl->search_result);
737
0
      hd->kbl->search_result = NULL;
738
0
    }
739
740
  /* Check whether this is a NEXT search.  */
741
0
  if (!hd->kbl->need_search_reset)
742
0
    {
743
      /* No reset requested thus continue the search.  The keyboxd
744
       * keeps the context of the search and thus the NEXT operates on
745
       * the last search pattern.  This is how we always used the
746
       * keydb.c functions.  In theory we were able to modify the
747
       * search pattern between searches but that is not anymore
748
       * supported by keyboxd and a cursory check does not show that
749
       * we actually made used of that misfeature.  */
750
0
      snprintf (line, sizeof line, "NEXT");
751
0
      goto do_search;
752
0
    }
753
754
0
  hd->kbl->need_search_reset = 0;
755
756
0
  if (!ndesc)
757
0
    {
758
0
      err = gpg_error (GPG_ERR_INV_ARG);
759
0
      goto leave;
760
0
    }
761
0
  for (i = 0; i < ndesc; i++)
762
0
    if (desc->mode == KEYDB_SEARCH_MODE_FIRST)
763
0
      {
764
        /* If any description has mode FIRST, this item trumps all
765
         * other descriptions.  */
766
0
        snprintf (line, sizeof line, "SEARCH --openpgp");
767
0
        goto do_search;
768
0
      }
769
770
0
  for ( ; ndesc; desc++, ndesc--)
771
0
    {
772
0
      const char *more = ndesc > 1 ? "--openpgp --more" : "--openpgp";
773
774
0
      switch (desc->mode)
775
0
        {
776
0
        case KEYDB_SEARCH_MODE_EXACT:
777
0
          snprintf (line, sizeof line, "SEARCH %s -- =%s", more, desc->u.name);
778
0
          break;
779
780
0
        case KEYDB_SEARCH_MODE_SUBSTR:
781
0
          snprintf (line, sizeof line, "SEARCH %s -- *%s", more, desc->u.name);
782
0
          break;
783
784
0
        case KEYDB_SEARCH_MODE_MAIL:
785
0
          snprintf (line, sizeof line, "SEARCH %s -- <%s",
786
0
                    more, desc->u.name+(desc->u.name[0] == '<') );
787
0
          break;
788
789
0
        case KEYDB_SEARCH_MODE_MAILSUB:
790
0
          snprintf (line, sizeof line, "SEARCH %s -- @%s", more, desc->u.name);
791
0
          break;
792
793
0
        case KEYDB_SEARCH_MODE_MAILEND:
794
0
          snprintf (line, sizeof line, "SEARCH %s -- .%s", more, desc->u.name);
795
0
          break;
796
797
0
        case KEYDB_SEARCH_MODE_WORDS:
798
0
          snprintf (line, sizeof line, "SEARCH %s -- +%s", more, desc->u.name);
799
0
          break;
800
801
0
        case KEYDB_SEARCH_MODE_SHORT_KID:
802
0
          snprintf (line, sizeof line, "SEARCH %s -- 0x%08lX", more,
803
0
                    (ulong)desc->u.kid[1]);
804
0
          break;
805
806
0
        case KEYDB_SEARCH_MODE_LONG_KID:
807
0
          snprintf (line, sizeof line, "SEARCH %s -- 0x%08lX%08lX", more,
808
0
                    (ulong)desc->u.kid[0], (ulong)desc->u.kid[1]);
809
0
          break;
810
811
0
        case KEYDB_SEARCH_MODE_FPR:
812
0
          {
813
0
            unsigned char hexfpr[MAX_FINGERPRINT_LEN * 2 + 1];
814
0
            log_assert (desc->fprlen <= MAX_FINGERPRINT_LEN);
815
0
            bin2hex (desc->u.fpr, desc->fprlen, hexfpr);
816
0
            snprintf (line, sizeof line, "SEARCH %s -- 0x%s", more, hexfpr);
817
0
          }
818
0
          break;
819
820
0
        case KEYDB_SEARCH_MODE_ISSUER:
821
0
          snprintf (line, sizeof line, "SEARCH %s -- #/%s", more, desc->u.name);
822
0
          break;
823
824
0
        case KEYDB_SEARCH_MODE_ISSUER_SN:
825
0
        case KEYDB_SEARCH_MODE_SN:
826
0
          snprintf (line, sizeof line, "SEARCH %s -- #%s", more, desc->u.name);
827
0
          break;
828
829
0
        case KEYDB_SEARCH_MODE_SUBJECT:
830
0
          snprintf (line, sizeof line, "SEARCH %s -- /%s", more, desc->u.name);
831
0
          break;
832
833
0
        case KEYDB_SEARCH_MODE_KEYGRIP:
834
0
          {
835
0
            unsigned char hexgrip[KEYGRIP_LEN * 2 + 1];
836
0
            bin2hex (desc->u.grip, KEYGRIP_LEN, hexgrip);
837
0
            snprintf (line, sizeof line, "SEARCH %s -- &%s", more, hexgrip);
838
0
          }
839
0
          break;
840
841
0
        case KEYDB_SEARCH_MODE_UBID:
842
0
          {
843
0
            unsigned char hexubid[UBID_LEN * 2 + 1];
844
0
            bin2hex (desc->u.ubid, UBID_LEN, hexubid);
845
0
            snprintf (line, sizeof line, "SEARCH %s -- ^%s", more, hexubid);
846
0
          }
847
0
          break;
848
849
0
        case KEYDB_SEARCH_MODE_NEXT:
850
0
          log_debug ("%s: mode next - we should not get to here!\n", __func__);
851
0
          snprintf (line, sizeof line, "NEXT");
852
0
          break;
853
854
0
        case KEYDB_SEARCH_MODE_FIRST:
855
0
          log_debug ("%s: mode first - we should not get to here!\n", __func__);
856
          /*fallthru*/
857
0
        default:
858
0
          err = gpg_error (GPG_ERR_INV_ARG);
859
0
          goto leave;
860
0
        }
861
862
0
      if (ndesc > 1)
863
0
        {
864
0
          err = kbx_client_data_simple (hd->kbl->kcd, line);
865
0
          if (err)
866
0
            goto leave;
867
0
        }
868
0
    }
869
870
871
0
 do_search:
872
0
  hd->last_ubid_valid = 0;
873
0
  err = kbx_client_data_cmd (hd->kbl->kcd, line, search_status_cb, hd);
874
0
  if (!err && !(err = kbx_client_data_wait (hd->kbl->kcd, &buffer, &len)))
875
0
    {
876
0
      int any;
877
0
      u32 kid[2];
878
879
0
      for (any = i = 0; i < ndesc && !any; i++)
880
0
        if (desc[i].skipfnc)
881
0
          any = 1;
882
883
0
      if (any)
884
0
        {
885
0
          err = kbx_get_first_opgp_keyid (buffer, len, kid);
886
0
          if (err)
887
0
            {
888
0
              log_info ("error getting keyid for skipping callback: %s\n",
889
0
                        gpg_strerror (err));
890
0
              goto leave;
891
0
            }
892
0
          for (i = 0; i < ndesc; i++)
893
0
            if (desc[i].skipfnc (desc[i].skipfncvalue, kid, hd->last_uid_no))
894
0
              { /* Callback told us to skip this one.  */
895
0
                if (DBG_KEYDB && hd->last_ubid_valid)
896
0
                  log_printhex (hd->last_ubid, 20, "skipped UBID (%d,%d):",
897
0
                                hd->last_uid_no, hd->last_pk_no);
898
0
                snprintf (line, sizeof line, "NEXT");
899
0
                goto do_search;  /* again */
900
0
              }
901
0
        }
902
903
0
      hd->kbl->search_result = iobuf_temp_with_content (buffer, len);
904
0
      xfree (buffer);
905
0
      if (DBG_KEYDB && hd->last_ubid_valid)
906
0
        log_printhex (hd->last_ubid, 20, "found UBID (%d,%d):",
907
0
                      hd->last_uid_no, hd->last_pk_no);
908
0
    }
909
910
8.11k
 leave:
911
8.11k
  if (DBG_CLOCK)
912
8.11k
    log_clock ("%s leave (%sfound)", __func__, err? "not ":"");
913
8.11k
  return err;
914
0
}