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 | } |