Coverage Report

Created: 2026-09-03 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnupg/g10/kbnode.c
Line
Count
Source
1
/* kbnode.c -  keyblock node utility functions
2
 * Copyright (C) 1998, 1999, 2000, 2001, 2002,
3
 *               2005, 2010 Free Software Foundation, Inc.
4
 *
5
 * This file is part of GnuPG.
6
 *
7
 * GnuPG 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 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * GnuPG 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.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, see <https://www.gnu.org/licenses/>.
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 "../common/init.h"
29
#include "packet.h"
30
#include "keydb.h"
31
32
#define USE_UNUSED_NODES 1
33
34
static int cleanup_registered;
35
static KBNODE unused_nodes;
36
37
static void
38
release_unused_nodes (void)
39
0
{
40
0
#if USE_UNUSED_NODES
41
0
  while (unused_nodes)
42
0
    {
43
0
      kbnode_t next = unused_nodes->next;
44
0
      xfree (unused_nodes);
45
0
      unused_nodes = next;
46
0
    }
47
0
#endif /*USE_UNUSED_NODES*/
48
0
}
49
50
51
static kbnode_t
52
alloc_node (void)
53
23.9M
{
54
23.9M
  kbnode_t n;
55
56
23.9M
  n = unused_nodes;
57
23.9M
  if (n)
58
23.9M
    unused_nodes = n->next;
59
21.0k
  else
60
21.0k
    {
61
21.0k
      if (!cleanup_registered)
62
4
        {
63
4
          cleanup_registered = 1;
64
4
          register_mem_cleanup_func (release_unused_nodes);
65
4
        }
66
21.0k
      n = xmalloc (sizeof *n);
67
21.0k
    }
68
23.9M
  n->next = NULL;
69
23.9M
  n->pkt = NULL;
70
23.9M
  n->flag = 0;
71
23.9M
  n->tag = 0;
72
23.9M
  n->private_flag=0;
73
23.9M
  return n;
74
23.9M
}
75
76
static void
77
free_node( KBNODE n )
78
23.9M
{
79
23.9M
  if (n)
80
23.9M
    {
81
23.9M
#if USE_UNUSED_NODES
82
23.9M
      n->next = unused_nodes;
83
23.9M
      unused_nodes = n;
84
#else
85
      xfree (n);
86
#endif
87
23.9M
    }
88
23.9M
}
89
90
91
92
KBNODE
93
new_kbnode( PACKET *pkt )
94
23.9M
{
95
23.9M
    KBNODE n = alloc_node();
96
23.9M
    n->pkt = pkt;
97
23.9M
    return n;
98
23.9M
}
99
100
101
/* Same as new_kbnode but insert the new node in front of LIST.  Returns
102
 * the new list.  */
103
kbnode_t
104
new_kbnode2 (kbnode_t list, PACKET *pkt)
105
3.10k
{
106
3.10k
  kbnode_t n;
107
108
3.10k
  n = new_kbnode (pkt);
109
3.10k
  n->next = list;
110
3.10k
  return n;
111
3.10k
}
112
113
114
KBNODE
115
clone_kbnode( KBNODE node )
116
15.3k
{
117
15.3k
    KBNODE n = alloc_node();
118
119
15.3k
    n->pkt = node->pkt;
120
15.3k
    n->private_flag = node->private_flag | 2; /* mark cloned */
121
15.3k
    return n;
122
15.3k
}
123
124
125
void
126
release_kbnode( KBNODE n )
127
3.60M
{
128
3.60M
    KBNODE n2;
129
130
27.5M
    while( n ) {
131
23.9M
  n2 = n->next;
132
23.9M
  if( !is_cloned_kbnode(n) ) {
133
23.9M
            free_packet (n->pkt, NULL);
134
23.9M
            xfree( n->pkt );
135
23.9M
  }
136
23.9M
  free_node( n );
137
23.9M
  n = n2;
138
23.9M
    }
139
3.60M
}
140
141
142
/****************
143
 * Delete NODE.
144
 * Note: This only works with walk_kbnode!!
145
 */
146
void
147
delete_kbnode( KBNODE node )
148
47.1k
{
149
47.1k
    node->private_flag |= 1;
150
47.1k
}
151
152
/****************
153
 * Append NODE to ROOT.  ROOT must exist!
154
 */
155
void
156
add_kbnode( KBNODE root, KBNODE node )
157
656k
{
158
656k
    KBNODE n1;
159
160
169M
    for(n1=root; n1->next; n1 = n1->next)
161
169M
  ;
162
656k
    n1->next = node;
163
656k
}
164
165
/****************
166
 * Insert NODE into the list after root but before a packet which is not of
167
 * type PKTTYPE
168
 * (only if PKTTYPE != 0)
169
 */
170
void
171
insert_kbnode( KBNODE root, KBNODE node, int pkttype )
172
4.39k
{
173
4.39k
    if( !pkttype ) {
174
665
  node->next = root->next;
175
665
  root->next = node;
176
665
    }
177
3.72k
    else {
178
3.72k
  KBNODE n1;
179
180
2.37M
  for(n1=root; n1->next; n1 = n1->next)
181
2.37M
      if( pkttype != n1->next->pkt->pkttype ) {
182
3.49k
    node->next = n1->next;
183
3.49k
    n1->next = node;
184
3.49k
    return;
185
3.49k
      }
186
  /* no such packet, append */
187
237
  node->next = NULL;
188
237
  n1->next = node;
189
237
    }
190
4.39k
}
191
192
193
/****************
194
 * Find the previous node (if PKTTYPE = 0) or the previous node
195
 * with pkttype PKTTYPE in the list starting with ROOT of NODE.
196
 */
197
KBNODE
198
find_prev_kbnode( KBNODE root, KBNODE node, int pkttype )
199
23.3k
{
200
23.3k
    KBNODE n1;
201
202
1.43M
    for (n1=NULL; root && root != node; root = root->next ) {
203
1.40M
        if (!pkttype ||root->pkt->pkttype == pkttype)
204
338k
            n1 = root;
205
1.40M
    }
206
23.3k
    return n1;
207
23.3k
}
208
209
/****************
210
 * Ditto, but find the next packet.  The behaviour is trivial if
211
 * PKTTYPE is 0 but if it is specified, the next node with a packet
212
 * of this type is returned.  The function has some knowledge about
213
 * the valid ordering of packets: e.g. if the next signature packet
214
 * is requested, the function will not return one if it encounters
215
 * a user-id.
216
 */
217
KBNODE
218
find_next_kbnode( KBNODE node, int pkttype )
219
1.10M
{
220
1.34M
    for( node=node->next ; node; node = node->next ) {
221
618k
  if( !pkttype )
222
47.6k
      return node;
223
571k
  else if( pkttype == PKT_USER_ID
224
24.8k
     && ( node->pkt->pkttype == PKT_PUBLIC_KEY
225
24.8k
         || node->pkt->pkttype == PKT_SECRET_KEY ) )
226
0
      return NULL;
227
571k
  else if( pkttype == PKT_SIGNATURE
228
546k
     && ( node->pkt->pkttype == PKT_USER_ID
229
545k
         || node->pkt->pkttype == PKT_PUBLIC_KEY
230
545k
         || node->pkt->pkttype == PKT_SECRET_KEY ) )
231
1.09k
      return NULL;
232
570k
  else if( node->pkt->pkttype == pkttype )
233
335k
      return node;
234
618k
    }
235
721k
    return NULL;
236
1.10M
}
237
238
239
KBNODE
240
find_kbnode( KBNODE node, int pkttype )
241
16.7k
{
242
16.7k
    for( ; node; node = node->next ) {
243
16.7k
  if( node->pkt->pkttype == pkttype )
244
16.7k
      return node;
245
16.7k
    }
246
0
    return NULL;
247
16.7k
}
248
249
250
251
/****************
252
 * Walk through a list of kbnodes. This function returns
253
 * the next kbnode for each call; before using the function the first
254
 * time, the caller must set CONTEXT to NULL (This has simply the effect
255
 * to start with ROOT).
256
 */
257
KBNODE
258
walk_kbnode( KBNODE root, KBNODE *context, int all )
259
4.60M
{
260
4.60M
    KBNODE n;
261
262
4.60M
    do {
263
4.60M
  if( !*context ) {
264
3.37k
      *context = root;
265
3.37k
      n = root;
266
3.37k
  }
267
4.59M
  else {
268
4.59M
      n = (*context)->next;
269
4.59M
      *context = n;
270
4.59M
  }
271
4.60M
    } while( !all && n && is_deleted_kbnode(n) );
272
273
4.60M
    return n;
274
4.60M
}
275
276
void
277
clear_kbnode_flags( KBNODE n )
278
15.9k
{
279
4.69M
    for( ; n; n = n->next ) {
280
4.67M
  n->flag = 0;
281
4.67M
    }
282
15.9k
}
283
284
285
/****************
286
 * Commit changes made to the kblist at ROOT. Note that ROOT my change,
287
 * and it is therefore passed by reference.
288
 * The function has the effect of removing all nodes marked as deleted.
289
 * returns true if any node has been changed
290
 */
291
int
292
commit_kbnode( KBNODE *root )
293
13.8k
{
294
13.8k
    KBNODE n, nl;
295
13.8k
    int changed = 0;
296
297
983k
    for( n = *root, nl=NULL; n; n = nl->next ) {
298
969k
  if( is_deleted_kbnode(n) ) {
299
46.0k
      if( n == *root )
300
0
    *root = nl = n->next;
301
46.0k
      else
302
46.0k
    nl->next = n->next;
303
46.0k
      if( !is_cloned_kbnode(n) ) {
304
38.0k
                free_packet (n->pkt, NULL);
305
38.0k
    xfree( n->pkt );
306
38.0k
      }
307
46.0k
      free_node( n );
308
46.0k
      changed = 1;
309
46.0k
  }
310
923k
  else
311
923k
      nl = n;
312
969k
    }
313
13.8k
    return changed;
314
13.8k
}
315
316
void
317
remove_kbnode( KBNODE *root, KBNODE node )
318
0
{
319
0
    KBNODE n, nl;
320
321
0
    for( n = *root, nl=NULL; n; n = nl->next ) {
322
0
  if( n == node ) {
323
0
      if( n == *root )
324
0
    *root = nl = n->next;
325
0
      else
326
0
    nl->next = n->next;
327
0
      if( !is_cloned_kbnode(n) ) {
328
0
                free_packet (n->pkt, NULL);
329
0
    xfree( n->pkt );
330
0
      }
331
0
      free_node( n );
332
0
  }
333
0
  else
334
0
      nl = n;
335
0
    }
336
0
}
337
338
339
/****************
340
 * Move NODE behind right after WHERE or to the beginning if WHERE is NULL.
341
 */
342
void
343
move_kbnode( KBNODE *root, KBNODE node, KBNODE where )
344
0
{
345
0
    KBNODE tmp, prev;
346
347
0
    if( !root || !*root || !node )
348
0
  return;  /* sanity check */
349
0
    for( prev = *root; prev && prev->next != node; prev = prev->next )
350
0
  ;
351
0
    if( !prev )
352
0
  return; /* node is not in the list */
353
354
0
    if( !where ) {  /* move node before root */
355
0
  if( node == *root ) /* move to itself */
356
0
      return;
357
0
  prev->next = node->next;
358
0
  node->next = *root;
359
0
  *root = node;
360
0
  return;
361
0
    }
362
    /* move it after where */
363
0
    if( node == where )
364
0
  return;
365
0
    tmp = node->next;
366
0
    node->next = where->next;
367
0
    where->next = node;
368
0
    prev->next = tmp;
369
0
}
370
371
372
373
374
void
375
dump_kbnode (KBNODE node)
376
656
{
377
5.87k
  for (; node; node = node->next )
378
5.22k
    {
379
5.22k
      const char *s;
380
5.22k
      switch (node->pkt->pkttype)
381
5.22k
        {
382
0
        case 0:   s="empty"; break;
383
0
        case PKT_PUBLIC_KEY:  s="public-key"; break;
384
0
        case PKT_SECRET_KEY:  s="secret-key"; break;
385
0
        case PKT_SECRET_SUBKEY: s= "secret-subkey"; break;
386
0
        case PKT_PUBKEY_ENC:  s="public-enc"; break;
387
102
        case PKT_SIGNATURE: s="signature"; break;
388
0
        case PKT_ONEPASS_SIG: s="onepass-sig"; break;
389
2.80k
        case PKT_USER_ID: s="user-id"; break;
390
96
        case PKT_PUBLIC_SUBKEY: s="public-subkey"; break;
391
0
        case PKT_COMMENT: s="comment"; break;
392
0
        case PKT_RING_TRUST:  s="trust"; break;
393
0
        case PKT_PLAINTEXT: s="plaintext"; break;
394
0
        case PKT_COMPRESSED:  s="compressed"; break;
395
0
        case PKT_ENCRYPTED: s="encrypted"; break;
396
2.21k
        case PKT_GPG_CONTROL: s="gpg-control"; break;
397
0
        default:    s="unknown"; break;
398
5.22k
  }
399
5.22k
      log_debug ("node %p %02x/%02x type=%s",
400
5.22k
                 node, node->flag, node->private_flag, s);
401
5.22k
      if (node->pkt->pkttype == PKT_USER_ID)
402
2.80k
        {
403
2.80k
          PKT_user_id *uid = node->pkt->pkt.user_id;
404
2.80k
          log_printf ("  \"");
405
2.80k
          es_write_sanitized (log_get_stream (), uid->name, uid->len,
406
2.80k
                              NULL, NULL);
407
2.80k
          log_printf ("\" %c%c%c%c\n",
408
2.80k
                      uid->flags.expired? 'e':'.',
409
2.80k
                      uid->flags.revoked? 'r':'.',
410
2.80k
                      uid->created?    'v':'.',
411
2.80k
                      uid->flags.primary? 'p':'.' );
412
2.80k
        }
413
2.41k
      else if (node->pkt->pkttype == PKT_SIGNATURE)
414
102
        {
415
102
          log_printf ("  class=%02x keyid=%08lX ts=%lu\n",
416
102
                      node->pkt->pkt.signature->sig_class,
417
102
                      (ulong)node->pkt->pkt.signature->keyid[1],
418
102
                      (ulong)node->pkt->pkt.signature->timestamp);
419
102
        }
420
2.31k
      else if (node->pkt->pkttype == PKT_GPG_CONTROL)
421
2.21k
        {
422
2.21k
          log_printf (" ctrl=%d len=%u\n",
423
2.21k
                      node->pkt->pkt.gpg_control->control,
424
2.21k
                      (unsigned int)node->pkt->pkt.gpg_control->datalen);
425
2.21k
        }
426
96
      else if (node->pkt->pkttype == PKT_PUBLIC_KEY
427
96
               || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
428
96
        {
429
96
          PKT_public_key *pk = node->pkt->pkt.public_key;
430
431
96
          log_printf ("  keyid=%08lX a=%d u=%d %c%c%c%c%c\n",
432
96
                      (ulong)keyid_from_pk( pk, NULL ),
433
96
                      pk->pubkey_algo, pk->pubkey_usage,
434
96
                      pk->has_expired? 'e':'.',
435
96
                      pk->flags.revoked? 'r':'.',
436
96
                      pk->flags.valid?    'v':'.',
437
96
                      pk->flags.mdc?   'm':'.',
438
96
                      pk->flags.aead?  'a':'.');
439
96
        }
440
0
      else
441
96
        log_printf ("\n");
442
443
      log_flush ();
444
5.22k
    }
445
656
}