Line data Source code
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 "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 1063 : release_unused_nodes (void)
39 : {
40 : #if USE_UNUSED_NODES
41 10429 : while (unused_nodes)
42 : {
43 8303 : kbnode_t next = unused_nodes->next;
44 8303 : xfree (unused_nodes);
45 8303 : unused_nodes = next;
46 : }
47 : #endif /*USE_UNUSED_NODES*/
48 1063 : }
49 :
50 :
51 : static kbnode_t
52 21484 : alloc_node (void)
53 : {
54 : kbnode_t n;
55 :
56 21484 : n = unused_nodes;
57 21484 : if (n)
58 12832 : unused_nodes = n->next;
59 : else
60 : {
61 8652 : if (!cleanup_registered)
62 : {
63 1065 : cleanup_registered = 1;
64 1065 : register_mem_cleanup_func (release_unused_nodes);
65 : }
66 8652 : n = xmalloc (sizeof *n);
67 : }
68 21484 : n->next = NULL;
69 21484 : n->pkt = NULL;
70 21484 : n->flag = 0;
71 21484 : n->private_flag=0;
72 21484 : n->recno = 0;
73 21484 : return n;
74 : }
75 :
76 : static void
77 21155 : free_node( KBNODE n )
78 : {
79 21155 : if (n)
80 : {
81 : #if USE_UNUSED_NODES
82 21155 : n->next = unused_nodes;
83 21155 : unused_nodes = n;
84 : #else
85 : xfree (n);
86 : #endif
87 : }
88 21155 : }
89 :
90 :
91 :
92 : KBNODE
93 21422 : new_kbnode( PACKET *pkt )
94 : {
95 21422 : KBNODE n = alloc_node();
96 21422 : n->pkt = pkt;
97 21422 : return n;
98 : }
99 :
100 :
101 : KBNODE
102 62 : clone_kbnode( KBNODE node )
103 : {
104 62 : KBNODE n = alloc_node();
105 :
106 62 : n->pkt = node->pkt;
107 62 : n->private_flag = node->private_flag | 2; /* mark cloned */
108 62 : return n;
109 : }
110 :
111 :
112 : void
113 8004 : release_kbnode( KBNODE n )
114 : {
115 : KBNODE n2;
116 :
117 37096 : while( n ) {
118 21088 : n2 = n->next;
119 21088 : if( !is_cloned_kbnode(n) ) {
120 21026 : free_packet( n->pkt );
121 21026 : xfree( n->pkt );
122 : }
123 21088 : free_node( n );
124 21088 : n = n2;
125 : }
126 8004 : }
127 :
128 :
129 : /****************
130 : * Delete NODE.
131 : * Note: This only works with walk_kbnode!!
132 : */
133 : void
134 67 : delete_kbnode( KBNODE node )
135 : {
136 67 : node->private_flag |= 1;
137 67 : }
138 :
139 : /****************
140 : * Append NODE to ROOT. ROOT must exist!
141 : */
142 : void
143 1976 : add_kbnode( KBNODE root, KBNODE node )
144 : {
145 : KBNODE n1;
146 :
147 1976 : for(n1=root; n1->next; n1 = n1->next)
148 : ;
149 1976 : n1->next = node;
150 1976 : }
151 :
152 : /****************
153 : * Insert NODE into the list after root but before a packet which is not of
154 : * type PKTTYPE
155 : * (only if PKTTYPE != 0)
156 : */
157 : void
158 15 : insert_kbnode( KBNODE root, KBNODE node, int pkttype )
159 : {
160 15 : if( !pkttype ) {
161 8 : node->next = root->next;
162 8 : root->next = node;
163 : }
164 : else {
165 : KBNODE n1;
166 :
167 14 : for(n1=root; n1->next; n1 = n1->next)
168 14 : if( pkttype != n1->next->pkt->pkttype ) {
169 7 : node->next = n1->next;
170 7 : n1->next = node;
171 22 : return;
172 : }
173 : /* no such packet, append */
174 0 : node->next = NULL;
175 0 : n1->next = node;
176 : }
177 : }
178 :
179 :
180 : /****************
181 : * Find the previous node (if PKTTYPE = 0) or the previous node
182 : * with pkttype PKTTYPE in the list starting with ROOT of NODE.
183 : */
184 : KBNODE
185 1108 : find_prev_kbnode( KBNODE root, KBNODE node, int pkttype )
186 : {
187 : KBNODE n1;
188 :
189 6013 : for (n1=NULL; root && root != node; root = root->next ) {
190 4905 : if (!pkttype ||root->pkt->pkttype == pkttype)
191 1573 : n1 = root;
192 : }
193 1108 : return n1;
194 : }
195 :
196 : /****************
197 : * Ditto, but find the next packet. The behaviour is trivial if
198 : * PKTTYPE is 0 but if it is specified, the next node with a packet
199 : * of this type is returned. The function has some knowledge about
200 : * the valid ordering of packets: e.g. if the next signature packet
201 : * is requested, the function will not return one if it encounters
202 : * a user-id.
203 : */
204 : KBNODE
205 2352 : find_next_kbnode( KBNODE node, int pkttype )
206 : {
207 3324 : for( node=node->next ; node; node = node->next ) {
208 2677 : if( !pkttype )
209 992 : return node;
210 1685 : else if( pkttype == PKT_USER_ID
211 1101 : && ( node->pkt->pkttype == PKT_PUBLIC_KEY
212 1101 : || node->pkt->pkttype == PKT_SECRET_KEY ) )
213 0 : return NULL;
214 1685 : else if( pkttype == PKT_SIGNATURE
215 358 : && ( node->pkt->pkttype == PKT_USER_ID
216 358 : || node->pkt->pkttype == PKT_PUBLIC_KEY
217 358 : || node->pkt->pkttype == PKT_SECRET_KEY ) )
218 0 : return NULL;
219 1685 : else if( node->pkt->pkttype == pkttype )
220 713 : return node;
221 : }
222 647 : return NULL;
223 : }
224 :
225 :
226 : KBNODE
227 449 : find_kbnode( KBNODE node, int pkttype )
228 : {
229 463 : for( ; node; node = node->next ) {
230 463 : if( node->pkt->pkttype == pkttype )
231 449 : return node;
232 : }
233 0 : return NULL;
234 : }
235 :
236 :
237 :
238 : /****************
239 : * Walk through a list of kbnodes. This function returns
240 : * the next kbnode for each call; before using the function the first
241 : * time, the caller must set CONTEXT to NULL (This has simply the effect
242 : * to start with ROOT).
243 : */
244 : KBNODE
245 6344 : walk_kbnode( KBNODE root, KBNODE *context, int all )
246 : {
247 : KBNODE n;
248 :
249 : do {
250 6344 : if( !*context ) {
251 919 : *context = root;
252 919 : n = root;
253 : }
254 : else {
255 5425 : n = (*context)->next;
256 5425 : *context = n;
257 : }
258 6344 : } while( !all && n && is_deleted_kbnode(n) );
259 :
260 6338 : return n;
261 : }
262 :
263 : void
264 316 : clear_kbnode_flags( KBNODE n )
265 : {
266 2116 : for( ; n; n = n->next ) {
267 1800 : n->flag = 0;
268 : }
269 316 : }
270 :
271 :
272 : /****************
273 : * Commit changes made to the kblist at ROOT. Note that ROOT my change,
274 : * and it is therefore passed by reference.
275 : * The function has the effect of removing all nodes marked as deleted.
276 : * returns true if any node has been changed
277 : */
278 : int
279 605 : commit_kbnode( KBNODE *root )
280 : {
281 : KBNODE n, nl;
282 605 : int changed = 0;
283 :
284 4234 : for( n = *root, nl=NULL; n; n = nl->next ) {
285 3629 : if( is_deleted_kbnode(n) ) {
286 67 : if( n == *root )
287 3 : *root = nl = n->next;
288 : else
289 64 : nl->next = n->next;
290 67 : if( !is_cloned_kbnode(n) ) {
291 67 : free_packet( n->pkt );
292 67 : xfree( n->pkt );
293 : }
294 67 : free_node( n );
295 67 : changed = 1;
296 : }
297 : else
298 3562 : nl = n;
299 : }
300 605 : return changed;
301 : }
302 :
303 : void
304 0 : remove_kbnode( KBNODE *root, KBNODE node )
305 : {
306 : KBNODE n, nl;
307 :
308 0 : for( n = *root, nl=NULL; n; n = nl->next ) {
309 0 : if( n == node ) {
310 0 : if( n == *root )
311 0 : *root = nl = n->next;
312 : else
313 0 : nl->next = n->next;
314 0 : if( !is_cloned_kbnode(n) ) {
315 0 : free_packet( n->pkt );
316 0 : xfree( n->pkt );
317 : }
318 0 : free_node( n );
319 : }
320 : else
321 0 : nl = n;
322 : }
323 0 : }
324 :
325 :
326 : /****************
327 : * Move NODE behind right after WHERE or to the beginning if WHERE is NULL.
328 : */
329 : void
330 0 : move_kbnode( KBNODE *root, KBNODE node, KBNODE where )
331 : {
332 : KBNODE tmp, prev;
333 :
334 0 : if( !root || !*root || !node )
335 0 : return; /* sanity check */
336 0 : for( prev = *root; prev && prev->next != node; prev = prev->next )
337 : ;
338 0 : if( !prev )
339 0 : return; /* node is not in the list */
340 :
341 0 : if( !where ) { /* move node before root */
342 0 : if( node == *root ) /* move to itself */
343 0 : return;
344 0 : prev->next = node->next;
345 0 : node->next = *root;
346 0 : *root = node;
347 0 : return;
348 : }
349 : /* move it after where */
350 0 : if( node == where )
351 0 : return;
352 0 : tmp = node->next;
353 0 : node->next = where->next;
354 0 : where->next = node;
355 0 : prev->next = tmp;
356 : }
357 :
358 :
359 :
360 :
361 : void
362 0 : dump_kbnode (KBNODE node)
363 : {
364 0 : for (; node; node = node->next )
365 : {
366 : const char *s;
367 0 : switch (node->pkt->pkttype)
368 : {
369 0 : case 0: s="empty"; break;
370 0 : case PKT_PUBLIC_KEY: s="public-key"; break;
371 0 : case PKT_SECRET_KEY: s="secret-key"; break;
372 0 : case PKT_SECRET_SUBKEY: s= "secret-subkey"; break;
373 0 : case PKT_PUBKEY_ENC: s="public-enc"; break;
374 0 : case PKT_SIGNATURE: s="signature"; break;
375 0 : case PKT_ONEPASS_SIG: s="onepass-sig"; break;
376 0 : case PKT_USER_ID: s="user-id"; break;
377 0 : case PKT_PUBLIC_SUBKEY: s="public-subkey"; break;
378 0 : case PKT_COMMENT: s="comment"; break;
379 0 : case PKT_RING_TRUST: s="trust"; break;
380 0 : case PKT_PLAINTEXT: s="plaintext"; break;
381 0 : case PKT_COMPRESSED: s="compressed"; break;
382 0 : case PKT_ENCRYPTED: s="encrypted"; break;
383 0 : case PKT_GPG_CONTROL: s="gpg-control"; break;
384 0 : default: s="unknown"; break;
385 : }
386 0 : log_debug ("node %p %02x/%02x type=%s",
387 : node, node->flag, node->private_flag, s);
388 0 : if (node->pkt->pkttype == PKT_USER_ID)
389 : {
390 0 : PKT_user_id *uid = node->pkt->pkt.user_id;
391 0 : log_printf (" \"");
392 0 : es_write_sanitized (log_get_stream (), uid->name, uid->len,
393 : NULL, NULL);
394 0 : log_printf ("\" %c%c%c%c\n",
395 0 : uid->is_expired? 'e':'.',
396 0 : uid->is_revoked? 'r':'.',
397 0 : uid->created? 'v':'.',
398 0 : uid->is_primary? 'p':'.' );
399 : }
400 0 : else if (node->pkt->pkttype == PKT_SIGNATURE)
401 : {
402 0 : log_printf (" class=%02x keyid=%08lX ts=%lu\n",
403 0 : node->pkt->pkt.signature->sig_class,
404 0 : (ulong)node->pkt->pkt.signature->keyid[1],
405 0 : (ulong)node->pkt->pkt.signature->timestamp);
406 : }
407 0 : else if (node->pkt->pkttype == PKT_GPG_CONTROL)
408 : {
409 0 : log_printf (" ctrl=%d len=%u\n",
410 0 : node->pkt->pkt.gpg_control->control,
411 0 : (unsigned int)node->pkt->pkt.gpg_control->datalen);
412 : }
413 0 : else if (node->pkt->pkttype == PKT_PUBLIC_KEY
414 0 : || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
415 0 : {
416 0 : PKT_public_key *pk = node->pkt->pkt.public_key;
417 :
418 0 : log_printf (" keyid=%08lX a=%d u=%d %c%c%c%c\n",
419 0 : (ulong)keyid_from_pk( pk, NULL ),
420 0 : pk->pubkey_algo, pk->pubkey_usage,
421 0 : pk->has_expired? 'e':'.',
422 0 : pk->flags.revoked? 'r':'.',
423 0 : pk->flags.valid? 'v':'.',
424 0 : pk->flags.mdc? 'm':'.');
425 : }
426 : else
427 0 : log_printf ("\n");
428 :
429 0 : log_flush ();
430 : }
431 0 : }
|