Coverage Report

Created: 2022-12-08 06:10

/src/gnupg/g10/kbnode.c
Line
Count
Source (jump to first uncovered line)
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
5.27k
{
54
5.27k
  kbnode_t n;
55
56
5.27k
  n = unused_nodes;
57
5.27k
  if (n)
58
4.66k
    unused_nodes = n->next;
59
608
  else
60
608
    {
61
608
      if (!cleanup_registered)
62
1
        {
63
1
          cleanup_registered = 1;
64
1
          register_mem_cleanup_func (release_unused_nodes);
65
1
        }
66
608
      n = xmalloc (sizeof *n);
67
608
    }
68
5.27k
  n->next = NULL;
69
5.27k
  n->pkt = NULL;
70
5.27k
  n->flag = 0;
71
5.27k
  n->tag = 0;
72
5.27k
  n->private_flag=0;
73
5.27k
  return n;
74
5.27k
}
75
76
static void
77
free_node( KBNODE n )
78
5.27k
{
79
5.27k
  if (n)
80
5.27k
    {
81
5.27k
#if USE_UNUSED_NODES
82
5.27k
      n->next = unused_nodes;
83
5.27k
      unused_nodes = n;
84
#else
85
      xfree (n);
86
#endif
87
5.27k
    }
88
5.27k
}
89
90
91
92
KBNODE
93
new_kbnode( PACKET *pkt )
94
5.08k
{
95
5.08k
    KBNODE n = alloc_node();
96
5.08k
    n->pkt = pkt;
97
5.08k
    return n;
98
5.08k
}
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
340
{
106
340
  kbnode_t n;
107
108
340
  n = new_kbnode (pkt);
109
340
  n->next = list;
110
340
  return n;
111
340
}
112
113
114
KBNODE
115
clone_kbnode( KBNODE node )
116
187
{
117
187
    KBNODE n = alloc_node();
118
119
187
    n->pkt = node->pkt;
120
187
    n->private_flag = node->private_flag | 2; /* mark cloned */
121
187
    return n;
122
187
}
123
124
125
void
126
release_kbnode( KBNODE n )
127
6.64k
{
128
6.64k
    KBNODE n2;
129
130
9.25k
    while( n ) {
131
2.61k
  n2 = n->next;
132
2.61k
  if( !is_cloned_kbnode(n) ) {
133
2.60k
            free_packet (n->pkt, NULL);
134
2.60k
            xfree( n->pkt );
135
2.60k
  }
136
2.61k
  free_node( n );
137
2.61k
  n = n2;
138
2.61k
    }
139
6.64k
}
140
141
142
/****************
143
 * Delete NODE.
144
 * Note: This only works with walk_kbnode!!
145
 */
146
void
147
delete_kbnode( KBNODE node )
148
2.79k
{
149
2.79k
    node->private_flag |= 1;
150
2.79k
}
151
152
/****************
153
 * Append NODE to ROOT.  ROOT must exist!
154
 */
155
void
156
add_kbnode( KBNODE root, KBNODE node )
157
0
{
158
0
    KBNODE n1;
159
160
0
    for(n1=root; n1->next; n1 = n1->next)
161
0
  ;
162
0
    n1->next = node;
163
0
}
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
15
{
173
15
    if( !pkttype ) {
174
4
  node->next = root->next;
175
4
  root->next = node;
176
4
    }
177
11
    else {
178
11
  KBNODE n1;
179
180
51
  for(n1=root; n1->next; n1 = n1->next)
181
44
      if( pkttype != n1->next->pkt->pkttype ) {
182
4
    node->next = n1->next;
183
4
    n1->next = node;
184
4
    return;
185
4
      }
186
  /* no such packet, append */
187
7
  node->next = NULL;
188
7
  n1->next = node;
189
7
    }
190
15
}
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
153
{
200
153
    KBNODE n1;
201
202
43.5k
    for (n1=NULL; root && root != node; root = root->next ) {
203
43.4k
        if (!pkttype ||root->pkt->pkttype == pkttype)
204
25
            n1 = root;
205
43.4k
    }
206
153
    return n1;
207
153
}
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
4.77k
{
220
5.68k
    for( node=node->next ; node; node = node->next ) {
221
4.73k
  if( !pkttype )
222
2.86k
      return node;
223
1.87k
  else if( pkttype == PKT_USER_ID
224
1.87k
     && ( node->pkt->pkttype == PKT_PUBLIC_KEY
225
1.87k
         || node->pkt->pkttype == PKT_SECRET_KEY ) )
226
0
      return NULL;
227
1.87k
  else if( pkttype == PKT_SIGNATURE
228
1.87k
     && ( node->pkt->pkttype == PKT_USER_ID
229
0
         || node->pkt->pkttype == PKT_PUBLIC_KEY
230
0
         || node->pkt->pkttype == PKT_SECRET_KEY ) )
231
0
      return NULL;
232
1.87k
  else if( node->pkt->pkttype == pkttype )
233
959
      return node;
234
4.73k
    }
235
956
    return NULL;
236
4.77k
}
237
238
239
KBNODE
240
find_kbnode( KBNODE node, int pkttype )
241
1.15k
{
242
1.15k
    for( ; node; node = node->next ) {
243
1.15k
  if( node->pkt->pkttype == pkttype )
244
1.15k
      return node;
245
1.15k
    }
246
0
    return NULL;
247
1.15k
}
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
752
{
260
752
    KBNODE n;
261
262
752
    do {
263
752
  if( !*context ) {
264
183
      *context = root;
265
183
      n = root;
266
183
  }
267
569
  else {
268
569
      n = (*context)->next;
269
569
      *context = n;
270
569
  }
271
752
    } while( !all && n && is_deleted_kbnode(n) );
272
273
752
    return n;
274
752
}
275
276
void
277
clear_kbnode_flags( KBNODE n )
278
948
{
279
5.18k
    for( ; n; n = n->next ) {
280
4.23k
  n->flag = 0;
281
4.23k
    }
282
948
}
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
943
{
294
943
    KBNODE n, nl;
295
943
    int changed = 0;
296
297
4.97k
    for( n = *root, nl=NULL; n; n = nl->next ) {
298
4.02k
  if( is_deleted_kbnode(n) ) {
299
2.65k
      if( n == *root )
300
0
    *root = nl = n->next;
301
2.65k
      else
302
2.65k
    nl->next = n->next;
303
2.65k
      if( !is_cloned_kbnode(n) ) {
304
2.48k
                free_packet (n->pkt, NULL);
305
2.48k
    xfree( n->pkt );
306
2.48k
      }
307
2.65k
      free_node( n );
308
2.65k
      changed = 1;
309
2.65k
  }
310
1.37k
  else
311
1.37k
      nl = n;
312
4.02k
    }
313
943
    return changed;
314
943
}
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
0
{
377
0
  for (; node; node = node->next )
378
0
    {
379
0
      const char *s;
380
0
      switch (node->pkt->pkttype)
381
0
        {
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
0
        case PKT_SIGNATURE: s="signature"; break;
388
0
        case PKT_ONEPASS_SIG: s="onepass-sig"; break;
389
0
        case PKT_USER_ID: s="user-id"; break;
390
0
        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
0
        case PKT_GPG_CONTROL: s="gpg-control"; break;
397
0
        default:    s="unknown"; break;
398
0
  }
399
0
      log_debug ("node %p %02x/%02x type=%s",
400
0
                 node, node->flag, node->private_flag, s);
401
0
      if (node->pkt->pkttype == PKT_USER_ID)
402
0
        {
403
0
          PKT_user_id *uid = node->pkt->pkt.user_id;
404
0
          log_printf ("  \"");
405
0
          es_write_sanitized (log_get_stream (), uid->name, uid->len,
406
0
                              NULL, NULL);
407
0
          log_printf ("\" %c%c%c%c\n",
408
0
                      uid->flags.expired? 'e':'.',
409
0
                      uid->flags.revoked? 'r':'.',
410
0
                      uid->created?    'v':'.',
411
0
                      uid->flags.primary? 'p':'.' );
412
0
        }
413
0
      else if (node->pkt->pkttype == PKT_SIGNATURE)
414
0
        {
415
0
          log_printf ("  class=%02x keyid=%08lX ts=%lu\n",
416
0
                      node->pkt->pkt.signature->sig_class,
417
0
                      (ulong)node->pkt->pkt.signature->keyid[1],
418
0
                      (ulong)node->pkt->pkt.signature->timestamp);
419
0
        }
420
0
      else if (node->pkt->pkttype == PKT_GPG_CONTROL)
421
0
        {
422
0
          log_printf (" ctrl=%d len=%u\n",
423
0
                      node->pkt->pkt.gpg_control->control,
424
0
                      (unsigned int)node->pkt->pkt.gpg_control->datalen);
425
0
        }
426
0
      else if (node->pkt->pkttype == PKT_PUBLIC_KEY
427
0
               || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
428
0
        {
429
0
          PKT_public_key *pk = node->pkt->pkt.public_key;
430
431
0
          log_printf ("  keyid=%08lX a=%d u=%d %c%c%c%c%c\n",
432
0
                      (ulong)keyid_from_pk( pk, NULL ),
433
0
                      pk->pubkey_algo, pk->pubkey_usage,
434
0
                      pk->has_expired? 'e':'.',
435
0
                      pk->flags.revoked? 'r':'.',
436
0
                      pk->flags.valid?    'v':'.',
437
0
                      pk->flags.mdc?   'm':'.',
438
0
                      pk->flags.aead?  'a':'.');
439
0
        }
440
0
      else
441
0
        log_printf ("\n");
442
443
0
      log_flush ();
444
0
    }
445
0
}