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