Coverage Report

Created: 2026-03-03 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnupg/g10/objcache.c
Line
Count
Source
1
/* objcache.c - Caching functions for keys and user ids.
2
 * Copyright (C) 2019 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
26
#include "gpg.h"
27
#include "../common/util.h"
28
#include "packet.h"
29
#include "keydb.h"
30
#include "options.h"
31
#include "objcache.h"
32
33
/* Note that max value for uid_items is actually the threshold when
34
 * we start to look for items which can be removed.  */
35
1
#define NO_OF_UID_ITEM_BUCKETS    107
36
1
#define MAX_UID_ITEMS_PER_BUCKET  20
37
38
1
#define NO_OF_KEY_ITEM_BUCKETS    383
39
1
#define MAX_KEY_ITEMS_PER_BUCKET  20
40
41
42
/* An object to store a user id.  This describes an item in the linked
43
 * lists of a bucket in hash table.  The reference count will
44
 * eventually be used to remove items from the table.  */
45
typedef struct uid_item_s
46
{
47
  struct uid_item_s *next;
48
  unsigned int refcount;  /* The reference count for this item.   */
49
  unsigned int namelen;   /* The length of the UID sans the nul.  */
50
  char name[1];
51
} *uid_item_t;
52
53
static uid_item_t *uid_table; /* Hash table for with user ids.  */
54
static size_t uid_table_size; /* Number of allocated buckets.   */
55
static unsigned int uid_table_max;    /* Max. # of items in a bucket.  */
56
static unsigned int uid_table_added;  /* # of items added.   */
57
static unsigned int uid_table_dropped;/* # of items dropped.  */
58
59
60
/* An object to store properties of a key.  Note that this can be used
61
 * for a primary or a subkey.  The key is linked to a user if that
62
 * exists.  */
63
typedef struct key_item_s
64
{
65
  struct key_item_s *next;
66
  unsigned int usecount;
67
  byte fprlen;
68
  char fpr[MAX_FINGERPRINT_LEN];
69
  u32 keyid[2];
70
  uid_item_t ui;          /* NULL of a ref'ed user id item.      */
71
} *key_item_t;
72
73
static key_item_t *key_table; /* Hash table with the keys.      */
74
static size_t key_table_size; /* Number of allocated buckents.  */
75
static unsigned int key_table_max;    /* Max. # of items in a bucket.  */
76
static unsigned int key_table_added;  /* # of items added.   */
77
static unsigned int key_table_dropped;/* # of items dropped.  */
78
static key_item_t key_item_attic;     /* List of freed items.  */
79
80
81

82
/* Dump stats.  */
83
void
84
objcache_dump_stats (void)
85
0
{
86
0
  unsigned int idx;
87
0
  int len, minlen, maxlen;
88
0
  unsigned int count, attic, empty;
89
0
  key_item_t ki;
90
0
  uid_item_t ui;
91
92
0
  count = empty = 0;
93
0
  minlen = -1;
94
0
  maxlen = 0;
95
0
  for (idx = 0; idx < key_table_size; idx++)
96
0
    {
97
0
      len = 0;
98
0
      for (ki = key_table[idx]; ki; ki = ki->next)
99
0
        {
100
0
          count++;
101
0
          len++;
102
          /* log_debug ("key bucket %u: kid=%08lX used=%u ui=%p\n", */
103
          /*            idx, (ulong)ki->keyid[0], ki->usecount, ki->ui); */
104
0
        }
105
0
      if (len > maxlen)
106
0
        maxlen = len;
107
108
0
      if (!len)
109
0
        empty++;
110
0
      else if (minlen == -1 || len < minlen)
111
0
        minlen = len;
112
0
    }
113
0
  for (attic=0, ki = key_item_attic; ki; ki = ki->next)
114
0
    attic++;
115
0
  log_info ("objcache: keys=%u/%u/%u chains=%u,%d..%d buckets=%zu/%u"
116
0
            " attic=%u\n",
117
0
            count, key_table_added, key_table_dropped,
118
0
            empty, minlen > 0? minlen : 0, maxlen,
119
0
            key_table_size, key_table_max, attic);
120
121
0
  count = empty = 0;
122
0
  minlen = -1;
123
0
  maxlen = 0;
124
0
  for (idx = 0; idx < uid_table_size; idx++)
125
0
    {
126
0
      len = 0;
127
0
      for (ui = uid_table[idx]; ui; ui = ui->next)
128
0
        {
129
0
          count++;
130
0
          len++;
131
          /* log_debug ("uid bucket %u: %p ref=%u l=%u (%.20s)\n", */
132
          /*            idx, ui, ui->refcount, ui->namelen, ui->name); */
133
0
        }
134
0
      if (len > maxlen)
135
0
        maxlen = len;
136
137
0
      if (!len)
138
0
        empty++;
139
0
      else if (minlen == -1 || len < minlen)
140
0
        minlen = len;
141
0
    }
142
0
  log_info ("objcache: uids=%u/%u/%u chains=%u,%d..%d buckets=%zu/%u\n",
143
0
            count, uid_table_added, uid_table_dropped,
144
0
            empty, minlen > 0? minlen : 0, maxlen,
145
0
            uid_table_size, uid_table_max);
146
0
}
147
148
149

150
/* The hash function we use for the uid_table.  Must not call a system
151
 * function.  */
152
static inline unsigned int
153
uid_table_hasher (const char *name, unsigned namelen)
154
34
{
155
34
  const unsigned char *s = (const unsigned char*)name;
156
34
  unsigned int hashval = 0;
157
34
  unsigned int carry;
158
159
949
  for (; namelen; namelen--, s++)
160
915
    {
161
915
      hashval = (hashval << 4) + *s;
162
915
      if ((carry = (hashval & 0xf0000000)))
163
677
        {
164
677
          hashval ^= (carry >> 24);
165
677
          hashval ^= carry;
166
677
        }
167
915
    }
168
169
34
  return hashval % uid_table_size;
170
34
}
171
172
173
/* Run time allocation of the uid table.  This allows us to eventually
174
 * add an option to gpg to control the size.  */
175
static void
176
uid_table_init (void)
177
1
{
178
1
  if (uid_table)
179
0
    return;
180
1
  uid_table_size = NO_OF_UID_ITEM_BUCKETS;
181
1
  uid_table_max = MAX_UID_ITEMS_PER_BUCKET;
182
1
  uid_table = xcalloc (uid_table_size, sizeof *uid_table);
183
1
}
184
185
186
static uid_item_t
187
uid_item_ref (uid_item_t ui)
188
52
{
189
52
  if (ui)
190
52
    ui->refcount++;
191
52
  return ui;
192
52
}
193
194
static void
195
uid_item_unref (uid_item_t uid)
196
4.10k
{
197
4.10k
  if (!uid)
198
4.06k
    return;
199
34
  if (!uid->refcount)
200
34
    log_fatal ("too many unrefs for uid_item\n");
201
202
34
  uid->refcount--;
203
  /* We do not release the item here because that would require that
204
   * we locate the head of the list which has this item.  This will
205
   * take too long and thus the item is removed when we need to purge
206
   * some items for the list during uid_item_put.  */
207
34
}
208
209
210
/* Put (NAME,NAMELEN) into the UID_TABLE and return the item.  The
211
 * reference count for that item is incremented.  NULL is return on an
212
 * allocation error.  The caller should release the returned item
213
 * using uid_item_unref.  */
214
static uid_item_t
215
uid_table_put (const char *name, unsigned int namelen)
216
34
{
217
34
  unsigned int hash;
218
34
  uid_item_t ui;
219
34
  unsigned int count;
220
221
34
  if (!uid_table)
222
1
    uid_table_init ();
223
224
34
  hash = uid_table_hasher (name, namelen);
225
35
  for (ui = uid_table[hash], count = 0; ui; ui = ui->next, count++)
226
7
    if (ui->namelen == namelen && !memcmp (ui->name, name, namelen))
227
6
      return uid_item_ref (ui);  /* Found.  */
228
229
  /* If the bucket is full remove all unrefed items.  */
230
28
  if (count >= uid_table_max)
231
0
    {
232
0
      uid_item_t ui_next, ui_prev, list_head, drop_head;
233
234
      /* No syscalls from here .. */
235
0
      list_head = uid_table[hash];
236
0
      drop_head = NULL;
237
0
      while (list_head && !list_head->refcount)
238
0
        {
239
0
          ui = list_head;
240
0
          list_head = ui->next;
241
0
          ui->next = drop_head;
242
0
          drop_head = ui;
243
0
        }
244
0
      if ((ui_prev = list_head))
245
0
        for (ui = ui_prev->next; ui; ui = ui_next)
246
0
          {
247
0
            ui_next = ui->next;
248
0
            if (!ui->refcount)
249
0
              {
250
0
                ui->next = drop_head;
251
0
                drop_head = ui;
252
0
                ui_prev->next = ui_next;
253
0
              }
254
0
            else
255
0
              ui_prev = ui;
256
0
          }
257
0
      uid_table[hash] = list_head;
258
      /* ... to here */
259
260
0
      for (ui = drop_head; ui; ui = ui_next)
261
0
        {
262
0
          ui_next = ui->next;
263
0
          xfree (ui);
264
0
          uid_table_dropped++;
265
0
        }
266
0
    }
267
268
28
  count = uid_table_added + uid_table_dropped;
269
28
  ui = xtrycalloc (1, sizeof *ui + namelen);
270
28
  if (!ui)
271
0
    return NULL;  /* Out of core.  */
272
28
  if (count != uid_table_added + uid_table_dropped)
273
0
    {
274
      /* During the malloc another thread added an item.  Thus we need
275
       * to check again.  */
276
0
      uid_item_t ui_new = ui;
277
0
      for (ui = uid_table[hash]; ui; ui = ui->next)
278
0
        if (ui->namelen == namelen && !memcmp (ui->name, name, namelen))
279
0
          {
280
            /* Found.  */
281
0
            xfree (ui_new);
282
0
            return uid_item_ref (ui);
283
0
          }
284
0
      ui = ui_new;
285
0
    }
286
287
28
  memcpy (ui->name, name, namelen);
288
28
  ui->name[namelen] = 0; /* Extra Nul so we can use it as a string.  */
289
28
  ui->namelen = namelen;
290
28
  ui->refcount = 1;
291
28
  ui->next = uid_table[hash];
292
28
  uid_table[hash] = ui;
293
28
  uid_table_added++;
294
28
  return ui;
295
28
}
296
297
298

299
/* The hash function we use for the key_table.  Must not call a system
300
 * function.  */
301
static inline unsigned int
302
key_table_hasher (u32 *keyid)
303
188k
{
304
  /* A fingerprint could be used directly as a hash value.  However,
305
   * we use the keyid here because it is used in encrypted packets and
306
   * older signatures to identify a key.  Since v4 keys the keyid is
307
   * anyway a part of the fingerprint so it quickly extracted from a
308
   * fingerprint.  Note that v3 keys are not supported by gpg.  */
309
188k
  return keyid[0] % key_table_size;
310
188k
}
311
312
313
/* Run time allocation of the key table.  This allows us to eventually
314
 * add an option to gpg to control the size.  */
315
static void
316
key_table_init (void)
317
1
{
318
1
  if (key_table)
319
0
    return;
320
1
  key_table_size = NO_OF_KEY_ITEM_BUCKETS;
321
1
  key_table_max  = MAX_KEY_ITEMS_PER_BUCKET;
322
1
  key_table = xcalloc (key_table_size, sizeof *key_table);
323
1
}
324
325
326
static void
327
key_item_free (key_item_t ki)
328
0
{
329
0
  if (!ki)
330
0
    return;
331
0
  uid_item_unref (ki->ui);
332
0
  ki->ui = NULL;
333
0
  ki->next = key_item_attic;
334
0
  key_item_attic = ki;
335
0
}
336
337
338
/* Get a key item from PK or if that is NULL from KEYID.  The
339
 * reference count for that item is incremented.  NULL is return if it
340
 * was not found.  */
341
static key_item_t
342
key_table_get (PKT_public_key *pk, u32 *keyid)
343
185k
{
344
185k
  unsigned int hash;
345
185k
  key_item_t ki, ki2;
346
347
185k
  if (!key_table)
348
1
    key_table_init ();
349
350
185k
  if (pk)
351
185k
    {
352
185k
      byte fpr[MAX_FINGERPRINT_LEN];
353
185k
      size_t fprlen;
354
185k
      u32 tmpkeyid[2];
355
356
185k
      fingerprint_from_pk (pk, fpr, &fprlen);
357
185k
      keyid_from_pk (pk, tmpkeyid);
358
185k
      hash = key_table_hasher (tmpkeyid);
359
187k
      for (ki = key_table[hash]; ki; ki = ki->next)
360
187k
        if (ki->fprlen == fprlen && !memcmp (ki->fpr, fpr, fprlen))
361
185k
          return ki; /* Found */
362
185k
    }
363
77
  else if (keyid)
364
77
    {
365
77
      hash = key_table_hasher (keyid);
366
79
      for (ki = key_table[hash]; ki; ki = ki->next)
367
79
        if (ki->keyid[0] == keyid[0] && ki->keyid[1] == keyid[1])
368
77
          {
369
            /* Found.  We need to check for dups.  */
370
77
            for (ki2 = ki->next; ki2; ki2 = ki2->next)
371
0
              if (ki2->keyid[0] == keyid[0] && ki2->keyid[1] == keyid[1])
372
0
                return NULL;  /* Duplicated keyid - return NULL.  */
373
374
            /* This is the only one - return it.  */
375
77
            return ki;
376
77
          }
377
77
    }
378
34
  return NULL;
379
185k
}
380
381
382
/* Helper for the qsort in key_table_put.  */
383
static int
384
compare_key_items (const void *arg_a, const void *arg_b)
385
0
{
386
0
  const key_item_t a = *(const key_item_t *)arg_a;
387
0
  const key_item_t b = *(const key_item_t *)arg_b;
388
389
  /* Reverse sort on the usecount.  */
390
0
  if (a->usecount > b->usecount)
391
0
    return -1;
392
0
  else if (a->usecount == b->usecount)
393
0
    return 0;
394
0
  else
395
0
    return 1;
396
0
}
397
398
399
/* Put PK into the KEY_TABLE and return a key item.  The reference
400
 * count for that item is incremented.  If UI is given it is put into
401
 * the entry.  NULL is return on an allocation error.  */
402
static key_item_t
403
key_table_put (PKT_public_key *pk, uid_item_t ui)
404
53
{
405
53
  unsigned int hash;
406
53
  key_item_t ki;
407
53
  u32 keyid[2];
408
53
  byte fpr[MAX_FINGERPRINT_LEN];
409
53
  size_t fprlen;
410
53
  unsigned int count, n;
411
412
53
  if (!key_table)
413
0
    key_table_init ();
414
415
53
  fingerprint_from_pk (pk, fpr, &fprlen);
416
53
  keyid_from_pk (pk, keyid);
417
53
  hash = key_table_hasher (keyid);
418
56
  for (ki = key_table[hash], count=0; ki; ki = ki->next, count++)
419
10
    if (ki->fprlen == fprlen && !memcmp (ki->fpr, fpr, fprlen))
420
7
      return ki;  /* Found  */
421
422
  /* If the bucket is full remove a couple of items. */
423
46
  if (count >= key_table_max)
424
0
    {
425
0
      key_item_t list_head, *list_tailp, ki_next;
426
0
      key_item_t *array;
427
0
      int narray, idx;
428
429
      /* Unlink from the global list so that other threads don't
430
       * disturb us.  If another thread adds or removes something only
431
       * one will be the winner.  Bad luck for the drooped cache items
432
       * but after all it is just a cache.  */
433
0
      list_head = key_table[hash];
434
0
      key_table[hash] = NULL;
435
436
      /* Put all items into an array for sorting.  */
437
0
      array = xtrycalloc (count, sizeof *array);
438
0
      if (!array)
439
0
        {
440
          /* That's bad; give up all  items of the bucket.  */
441
0
          log_info ("Note: malloc failed while purging from the key_tabe: %s\n",
442
0
                    gpg_strerror (gpg_error_from_syserror ()));
443
0
          goto leave_drop;
444
0
        }
445
0
      narray = 0;
446
0
      for (ki = list_head; ki; ki = ki_next)
447
0
        {
448
0
          ki_next = ki->next;
449
0
          array[narray++] = ki;
450
0
          ki->next = NULL;
451
0
        }
452
0
      log_assert (narray == count);
453
454
      /* Sort the array and put half of it onto a new list.  */
455
0
      qsort (array, narray, sizeof *array, compare_key_items);
456
0
      list_head = NULL;
457
0
      list_tailp = &list_head;
458
0
      for (idx=0; idx < narray/2; idx++)
459
0
        {
460
0
          *list_tailp = array[idx];
461
0
          list_tailp = &array[idx]->next;
462
0
        }
463
464
      /* Put the new list into the bucket.  */
465
0
      ki = key_table[hash];
466
0
      key_table[hash] = list_head;
467
0
      list_head = ki;
468
469
      /* Free the remaining items and the array.  */
470
0
      for (; idx < narray; idx++)
471
0
        {
472
0
          key_item_free (array[idx]);
473
0
          key_table_dropped++;
474
0
        }
475
0
      xfree (array);
476
477
0
    leave_drop:
478
      /* Free any items added in the meantime by other threads.  This
479
       * is also used in case of a malloc problem (which won't update
480
       * the counters, though). */
481
0
      for ( ; list_head; list_head = ki_next)
482
0
        {
483
0
          ki_next = list_head->next;
484
0
          key_item_free (list_head);
485
0
        }
486
0
    }
487
488
  /* Add an item to the bucket.  We allocate a whole block of items
489
   * for cache performance reasons.  */
490
46
  if (!key_item_attic)
491
1
    {
492
1
      key_item_t kiblock;
493
1
      int kiblocksize = 256;
494
495
1
      kiblock = xtrymalloc (kiblocksize * sizeof *kiblock);
496
1
      if (!kiblock)
497
0
        return NULL;  /* Out of core.  */
498
257
      for (n = 0; n < kiblocksize; n++)
499
256
        {
500
256
          ki = kiblock + n;
501
256
          ki->next = key_item_attic;
502
256
          key_item_attic = ki;
503
256
        }
504
505
      /* During the malloc another thread may have changed the bucket.
506
       * Thus we need to check again.  */
507
1
      for (ki = key_table[hash]; ki; ki = ki->next)
508
0
        if (ki->fprlen == fprlen && !memcmp (ki->fpr, fpr, fprlen))
509
0
          return ki;  /* Found  */
510
1
    }
511
512
  /* We now know that there is an item in the attic.  */
513
46
  ki = key_item_attic;
514
46
  key_item_attic = ki->next;
515
46
  ki->next = NULL;
516
517
46
  memcpy (ki->fpr, fpr, fprlen);
518
46
  ki->fprlen = fprlen;
519
46
  ki->keyid[0] = keyid[0];
520
46
  ki->keyid[1] = keyid[1];
521
46
  ki->ui = uid_item_ref (ui);
522
46
  ki->usecount = 0;
523
46
  ki->next = key_table[hash];
524
46
  key_table[hash] = ki;
525
46
  key_table_added++;
526
46
  return ki;
527
46
}
528
529
530

531
/* Return the user ID from the given keyblock.  We use the primary uid
532
 * flag which should have already been set.  The returned value is
533
 * only valid as long as the given keyblock is not changed. */
534
static const char *
535
primary_uid_from_keyblock (kbnode_t keyblock, size_t *uidlen)
536
34
{
537
34
  kbnode_t k;
538
539
71
  for (k = keyblock; k; k = k->next)
540
71
    {
541
71
      if (k->pkt->pkttype == PKT_USER_ID
542
34
    && !k->pkt->pkt.user_id->attrib_data
543
34
    && k->pkt->pkt.user_id->flags.primary)
544
34
  {
545
34
    *uidlen = k->pkt->pkt.user_id->len;
546
34
    return k->pkt->pkt.user_id->name;
547
34
  }
548
71
    }
549
0
  return NULL;
550
34
}
551
552
553
/* Store the associations of keyid/fingerprint and userid.  Only
554
 * public keys should be fed to this function.  */
555
void
556
cache_put_keyblock (kbnode_t keyblock)
557
4.10k
{
558
4.10k
  uid_item_t ui = NULL;
559
4.10k
  kbnode_t k;
560
561
4.13k
 restart:
562
4.13M
  for (k = keyblock; k; k = k->next)
563
4.12M
    {
564
4.12M
      if (k->pkt->pkttype == PKT_PUBLIC_KEY
565
4.12M
    || k->pkt->pkttype == PKT_PUBLIC_SUBKEY)
566
185k
  {
567
185k
          if (!ui)
568
185k
            {
569
              /* Initially we just test for an entry to avoid the need
570
               * to create a user id item for a put.  Only if we miss
571
               * key in the cache we create a user id and restart.  */
572
185k
              if (!key_table_get (k->pkt->pkt.public_key, NULL))
573
34
                {
574
34
                  const char *uid;
575
34
                  size_t uidlen;
576
577
34
                  uid = primary_uid_from_keyblock (keyblock, &uidlen);
578
34
                  if (uid)
579
34
                    {
580
34
                      ui = uid_table_put (uid, uidlen);
581
34
                      if (!ui)
582
0
                        {
583
0
                          log_info ("Note: failed to cache a user id: %s\n",
584
0
                                    gpg_strerror (gpg_error_from_syserror ()));
585
0
                          goto leave;
586
0
                        }
587
34
                      goto restart;
588
34
                    }
589
34
                }
590
185k
            }
591
53
          else /* With a UID we use the update cache mode.  */
592
53
            {
593
53
              if (!key_table_put (k->pkt->pkt.public_key, ui))
594
0
                {
595
0
                  log_info ("Note: failed to cache a key: %s\n",
596
0
                            gpg_strerror (gpg_error_from_syserror ()));
597
0
                  goto leave;
598
0
                }
599
53
            }
600
185k
        }
601
4.12M
    }
602
603
4.10k
 leave:
604
4.10k
  uid_item_unref (ui);
605
4.10k
}
606
607
608
/* Return the user id string for KEYID.  If a user id is not found (or
609
 * on malloc error) NULL is returned.  If R_LENGTH is not NULL the
610
 * length of the user id is stored there; this does not included the
611
 * always appended nul.  Note that a user id may include an internal
612
 * nul which can be detected by the caller by comparing to the
613
 * returned length.  */
614
char *
615
cache_get_uid_bykid (u32 *keyid, unsigned int *r_length)
616
77
{
617
77
  key_item_t ki;
618
77
  char *p;
619
620
77
  if (r_length)
621
77
    *r_length = 0;
622
623
77
  ki = key_table_get (NULL, keyid);
624
77
  if (!ki)
625
0
    return NULL; /* Not found or duplicate keyid.  */
626
627
77
  if (!ki->ui)
628
0
    p = NULL;  /* No user id known for key.  */
629
77
  else
630
77
    {
631
77
      p = xtrymalloc (ki->ui->namelen + 1);
632
77
      if (p)
633
77
        {
634
77
          memcpy (p, ki->ui->name, ki->ui->namelen + 1);
635
77
          if (r_length)
636
77
            *r_length = ki->ui->namelen;
637
77
          ki->usecount++;
638
77
        }
639
77
    }
640
641
77
  return p;
642
77
}
643
644
645
/* Return the user id string for FPR with FPRLEN.  If a user id is not
646
 * found (or on malloc error) NULL is returned.  If R_LENGTH is not
647
 * NULL the length of the user id is stored there; this does not
648
 * included the always appended nul.  Note that a user id may include
649
 * an internal nul which can be detected by the caller by comparing to
650
 * the returned length.  */
651
char *
652
cache_get_uid_byfpr (const byte *fpr, size_t fprlen, size_t *r_length)
653
2.62k
{
654
2.62k
  char *p;
655
2.62k
  unsigned int hash;
656
2.62k
  u32 keyid[2];
657
2.62k
  key_item_t ki;
658
659
2.62k
  if (r_length)
660
2.62k
    *r_length = 0;
661
662
2.62k
  if (!key_table)
663
1
    return NULL;
664
665
2.62k
  keyid_from_fingerprint (NULL, fpr, fprlen, keyid);
666
2.62k
  hash = key_table_hasher (keyid);
667
4.33k
  for (ki = key_table[hash]; ki; ki = ki->next)
668
4.30k
    if (ki->fprlen == fprlen && !memcmp (ki->fpr, fpr, fprlen))
669
2.59k
      break; /* Found */
670
671
2.62k
  if (!ki)
672
30
    return NULL; /* Not found.  */
673
674
2.59k
  if (!ki->ui)
675
0
    p = NULL;  /* No user id known for key.  */
676
2.59k
  else
677
2.59k
    {
678
2.59k
      p = xtrymalloc (ki->ui->namelen + 1);
679
2.59k
      if (p)
680
2.59k
        {
681
2.59k
          memcpy (p, ki->ui->name, ki->ui->namelen + 1);
682
2.59k
          if (r_length)
683
2.59k
            *r_length = ki->ui->namelen;
684
2.59k
          ki->usecount++;
685
2.59k
        }
686
2.59k
    }
687
688
2.59k
  return p;
689
2.62k
}