added option file handling
[gnupg.git] / g10 / ringedit.c
1 /* ringedit.c -  Function for key ring editing
2  *      Copyright (c) 1997 by Werner Koch (dd9jn)
3  *
4  * This file is part of G10.
5  *
6  * G10 is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * G10 is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21
22 /****************
23  * This module supplies function for:
24  *
25  *  - Search for a key block (pubkey and all other stuff) and return a
26  *    handle for it.
27  *
28  *  - Lock/Unlock a key block
29  *
30  *  - Read a key block into a tree
31  *
32  *  - Update a key block
33  *
34  *  - Insert a new key block
35  *
36  *  - Delete a key block
37  *
38  * FIXME:  Add backup stuff
39  * FIXME:  Keep track of all nodes, so that a change is propagated
40  *         to all nodes. (or use shallow copies and ref-counting?)
41  */
42
43
44
45 #include <config.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <assert.h>
50 #include "util.h"
51 #include "packet.h"
52 #include "memory.h"
53 #include "mpi.h"
54 #include "iobuf.h"
55 #include "keydb.h"
56
57
58 struct resource_table_struct {
59     int used;
60     char *fname;
61     IOBUF iobuf;
62 };
63
64 #define MAX_RESOURCES 10
65 static struct resource_table_struct resource_table[MAX_RESOURCES];
66
67
68 static int keyring_search( PACKET *pkt, KBPOS *kbpos, IOBUF iobuf );
69 static int keyring_read( KBPOS *kbpos, KBNODE *ret_root );
70 static int keyring_insert( KBPOS *kbpos, KBNODE root );
71 static int keyring_delete( KBPOS *kbpos );
72
73
74
75 static int
76 check_pos( KBPOS *kbpos )
77 {
78     if( kbpos->resno < 0 || kbpos->resno >= MAX_RESOURCES )
79         return G10ERR_GENERAL;
80     if( !resource_table[kbpos->resno].used )
81         return G10ERR_GENERAL;
82     return 0;
83 }
84
85
86
87 /****************************************************************
88  ****************** public functions ****************************
89  ****************************************************************/
90
91 /****************
92  * Register a resource (which currently may ionly be a keyring file).
93  */
94 int
95 add_keyblock_resource( const char *filename )
96 {
97     IOBUF iobuf;
98     int i;
99
100     for(i=0; i < MAX_RESOURCES; i++ )
101         if( !resource_table[i].used )
102             break;
103     if( i == MAX_RESOURCES )
104         return G10ERR_RESOURCE_LIMIT;
105
106     iobuf = iobuf_open( filename );
107     if( !iobuf )
108         return G10ERR_OPEN_FILE;
109     resource_table[i].used = 1;
110     resource_table[i].fname = m_strdup(filename);
111     resource_table[i].iobuf = iobuf;
112     return 0;
113 }
114
115
116 /****************
117  * Get a keyblock handle KBPOS from a filename. This can be used
118  * to get a handle for insert_keyblock for a new keyblock.
119  */
120 int
121 get_keyblock_handle( const char *filename, KBPOS *kbpos )
122 {
123     int i;
124
125     for(i=0; i < MAX_RESOURCES; i++ )
126         if( resource_table[i].used ) {
127             /* fixme: dos needs case insensitive file compare */
128             if( !strcmp( resource_table[i].fname, filename ) ) {
129                 memset( kbpos, 0, sizeof *kbpos );
130                 kbpos->resno = i;
131                 return 0;
132             }
133         }
134     return -1; /* not found */
135 }
136
137 /****************
138  * Search a keyblock which starts with the given packet and put all
139  * informations into KBPOS, which can be used later to access this key block.
140  * This function looks into all registered keyblock sources.
141  * PACKET must be a packet with either a secret_cert or a public_cert
142  *
143  * This function is intended to check wether a given certificate
144  * is already in a keyring or to prepare it for editing.
145  *
146  * Returns: 0 if found, -1 if not found or an errorcode.
147  */
148 int
149 search_keyblock( PACKET *pkt, KBPOS *kbpos )
150 {
151     int i, rc, last_rc=-1;
152
153     for(i=0; i < MAX_RESOURCES; i++ ) {
154         if( resource_table[i].used ) {
155             /* note: here we have to add different search functions,
156              * depending on the type of the resource */
157             rc = keyring_search( pkt, kbpos, resource_table[i].iobuf );
158             if( !rc ) {
159                 kbpos->resno = i;
160                 return 0;
161             }
162             if( rc != -1 ) {
163                 log_error("error searching resource %d: %s\n",
164                                                   i, g10_errstr(rc));
165                 last_rc = rc;
166             }
167         }
168     }
169     return last_rc;
170 }
171
172
173
174 /****************
175  * Lock the keyblock; wait until it's available
176  * This function may change the internal data in kbpos, in cases
177  * when the to be locked keyblock has been modified.
178  * fixme: remove this function and add an option to search_keyblock()?
179  */
180 int
181 lock_keyblock( KBPOS *kbpos )
182 {
183     int rc;
184
185     if( (rc=check_pos(kbpos)) )
186         return rc;
187     return 0;
188 }
189
190 /****************
191  * Release a lock on a keyblock
192  */
193 int
194 unlock_keyblock( KBPOS *kbpos )
195 {
196     int rc;
197
198     if( (rc=check_pos(kbpos)) )
199         return rc;
200     return 0;
201 }
202
203 /****************
204  * Read a complete keyblock and return the root in ret_root.
205  */
206 int
207 read_keyblock( KBPOS *kbpos, KBNODE *ret_root )
208 {
209     int rc;
210
211     if( (rc=check_pos(kbpos)) )
212         return rc;
213     return keyring_read( kbpos, ret_root );
214 }
215
216 /****************
217  * Insert the keyblock described by ROOT into the keyring described
218  * by KBPOS.  This actually appends the data to the keyfile.
219  */
220 int
221 insert_keyblock( KBPOS *kbpos, KBNODE root )
222 {
223     int rc;
224
225     if( (rc=check_pos(kbpos)) )
226         return rc;
227
228     rc = keyring_insert( kbpos, root );
229
230     return rc;
231 }
232
233 /****************
234  * Delete the keyblock described by KBPOS.
235  * The current code simply changes the keyblock in the keyring
236  * to packet of type 0 with the correct length.  To help detecting errors,
237  * zero bytes are written.
238  */
239 int
240 delete_keyblock( KBPOS *kbpos )
241 {
242     int rc;
243
244     if( (rc=check_pos(kbpos)) )
245         return rc;
246
247     rc = keyring_delete( kbpos );
248
249     return rc;
250 }
251
252
253 /****************
254  * Update the keyblock at KBPOS with the one in ROOT.
255  */
256 int
257 update_keyblock( KBPOS *kbpos, KBNODE root )
258 {
259     int rc;
260     KBPOS kbpos2;
261
262     /* we do it the simple way: */
263     memset( &kbpos2, 0, sizeof kbpos2 );
264     kbpos2.resno = kbpos->resno;
265     rc = insert_keyblock( &kbpos2, root );
266     if( !rc )
267         rc = delete_keyblock( kbpos );
268
269     return rc;
270 }
271
272
273 /****************************************************************
274  ********** Functions which operates on regular keyrings ********
275  ****************************************************************/
276
277
278 /****************
279  * search one keyring, return 0 if found, -1 if not found or an errorcode.
280  */
281 static int
282 keyring_search( PACKET *req, KBPOS *kbpos, IOBUF iobuf )
283 {
284     int rc;
285     PACKET pkt;
286     int save_mode;
287     ulong offset;
288     int pkttype = req->pkttype;
289     PKT_public_cert *req_pkc = req->pkt.public_cert;
290     PKT_secret_cert *req_skc = req->pkt.secret_cert;
291
292     init_packet(&pkt);
293     save_mode = set_packet_list_mode(0);
294
295     if( iobuf_seek( iobuf, 0 ) ) {
296         log_error("can't rewind keyring file: %s\n", g10_errstr(rc));
297         rc = G10ERR_KEYRING_OPEN;
298         goto leave;
299     }
300
301     while( !(rc=search_packet(iobuf, &pkt, pkttype, &offset)) ) {
302         if( pkt.pkttype == PKT_SECRET_CERT ) {
303             PKT_secret_cert *skc = pkt.pkt.secret_cert;
304
305             if(   req_skc->timestamp == skc->timestamp
306                && req_skc->valid_days == skc->valid_days
307                && req_skc->pubkey_algo == skc->pubkey_algo
308                && (   ( skc->pubkey_algo == PUBKEY_ALGO_ELGAMAL
309                         && !mpi_cmp( req_skc->d.elg.p, skc->d.elg.p )
310                         && !mpi_cmp( req_skc->d.elg.g, skc->d.elg.g )
311                         && !mpi_cmp( req_skc->d.elg.y, skc->d.elg.y )
312                         && !mpi_cmp( req_skc->d.elg.x, skc->d.elg.x )
313                       )
314                    || ( skc->pubkey_algo == PUBKEY_ALGO_RSA
315                         && !mpi_cmp( req_skc->d.rsa.rsa_n, skc->d.rsa.rsa_n )
316                         && !mpi_cmp( req_skc->d.rsa.rsa_e, skc->d.rsa.rsa_e )
317                         && !mpi_cmp( req_skc->d.rsa.rsa_d, skc->d.rsa.rsa_d )
318                       )
319                   )
320               )
321                 break; /* found */
322         }
323         else if( pkt.pkttype == PKT_PUBLIC_CERT ) {
324             PKT_public_cert *pkc = pkt.pkt.public_cert;
325
326             if(   req_pkc->timestamp == pkc->timestamp
327                && req_pkc->valid_days == pkc->valid_days
328                && req_pkc->pubkey_algo == pkc->pubkey_algo
329                && (   ( pkc->pubkey_algo == PUBKEY_ALGO_ELGAMAL
330                         && !mpi_cmp( req_pkc->d.elg.p, pkc->d.elg.p )
331                         && !mpi_cmp( req_pkc->d.elg.g, pkc->d.elg.g )
332                         && !mpi_cmp( req_pkc->d.elg.y, pkc->d.elg.y )
333                       )
334                    || ( pkc->pubkey_algo == PUBKEY_ALGO_RSA
335                         && !mpi_cmp( req_pkc->d.rsa.rsa_n, pkc->d.rsa.rsa_n )
336                         && !mpi_cmp( req_pkc->d.rsa.rsa_e, pkc->d.rsa.rsa_e )
337                       )
338                   )
339               )
340                 break; /* found */
341         }
342         else
343             log_bug(NULL);
344         free_packet(&pkt);
345     }
346     if( !rc )
347         kbpos->offset = offset;
348
349   leave:
350     free_packet(&pkt);
351     set_packet_list_mode(save_mode);
352     return rc;
353 }
354
355
356 static int
357 keyring_read( KBPOS *kbpos, KBNODE *ret_root )
358 {
359     PACKET *pkt;
360     int rc;
361     KBNODE root = NULL;
362     KBNODE node, n1, n2;
363     IOBUF a;
364
365     if( (rc=check_pos(kbpos)) )
366         return rc;
367     a = resource_table[kbpos->resno].iobuf;
368
369     pkt = m_alloc( sizeof *pkt );
370     init_packet(pkt);
371     while( (rc=parse_packet(a, pkt)) != -1 ) {
372         if( rc ) {  /* ignore errors */
373             free_packet( pkt );
374             continue;
375         }
376         switch( pkt->pkttype ) {
377           case PKT_PUBLIC_CERT:
378           case PKT_SECRET_CERT:
379             if( root )
380                 break;
381             root = new_kbnode( pkt );
382             pkt = m_alloc( sizeof *pkt );
383             init_packet(pkt);
384             break;
385
386           case PKT_USER_ID:
387             if( !root ) {
388                 log_error("read_keyblock: orphaned user id\n" );
389                 rc = G10ERR_INV_KEYRING; /* or wron kbpos */
390                 break;
391             }
392             /* append the user id */
393             node = new_kbnode( pkt );
394             if( !(n1=root->child) )
395                 root->child = node;
396             else {
397                 for( ; n1->next; n1 = n1->next)
398                     ;
399                 n1->next = node;
400             }
401             pkt = m_alloc( sizeof *pkt );
402             init_packet(pkt);
403             break;
404
405           case PKT_SIGNATURE:
406             if( !root ) {
407                 log_error("read_keyblock: no root for signature\n" );
408                 rc = G10ERR_INV_KEYRING; /* or wrong kbpos */
409                 break;
410             }
411             if( !root->child ) {
412                 log_error("read_keyblock: no userid for signature\n" );
413                 rc = G10ERR_INV_KEYRING;
414                 break;
415             }
416             /* goto the last user id */
417             for(n1=root->child; n1->next; n1 = n1->next )
418                 ;
419             /* append the signature node */
420             node = new_kbnode( pkt );
421             if( !(n2=n1->child) )
422                 n1->child = node;
423             else {
424                 for( ; n2->next; n2 = n2->next)
425                     ;
426                 n2->next = node;
427             }
428             pkt = m_alloc( sizeof *pkt );
429             init_packet(pkt);
430             break;
431
432           default: /* ignore all other packets. FIXME: we should not do this */
433             free_packet( pkt );
434             break;
435         }
436     }
437     kbpos->last_block = rc == -1; /* flag, that this is the last block */
438     if( rc == -1 && root )
439         rc = 0;
440
441     if( rc )
442         release_kbnode( root );
443     else {
444         *ret_root = root;
445         kbpos->length = iobuf_tell( a ) - kbpos->offset;
446     }
447     free_packet( pkt );
448     m_free( pkt );
449     return rc;
450 }
451
452
453 static int
454 keyring_insert( KBPOS *kbpos, KBNODE root )
455 {
456     return -1;
457 }
458
459 static int
460 keyring_delete( KBPOS *kbpos )
461 {
462     return -1;
463 }
464
465
466 /****************************************************************
467  ********** Functions which operates on databases ***************
468  ****************************************************************/
469