141d8cf7f9371a93c15bf871c536fa8a8ec82b62
[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:  Keep track of all nodes, so that a change is propagated
39  *         to all nodes. (or use shallow copies and ref-counting?)
40  */
41
42
43
44 #include <config.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <errno.h>
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 #include <assert.h>
52 #include "util.h"
53 #include "packet.h"
54 #include "memory.h"
55 #include "mpi.h"
56 #include "iobuf.h"
57 #include "keydb.h"
58 #include <unistd.h> /* for truncate */
59
60
61 struct resource_table_struct {
62     int used;
63     int secret; /* this is a secret keyring */
64     char *fname;
65     IOBUF iobuf;
66 };
67 typedef struct resource_table_struct RESTBL;
68
69 #define MAX_RESOURCES 10
70 static RESTBL resource_table[MAX_RESOURCES];
71
72
73 static int search( PACKET *pkt, KBPOS *kbpos, int secret );
74
75
76 static int keyring_search( PACKET *pkt, KBPOS *kbpos, IOBUF iobuf );
77 static int keyring_search2( PUBKEY_FIND_INFO info, KBPOS *kbpos,
78                                                    const char *fname);
79 static int keyring_read( KBPOS *kbpos, KBNODE *ret_root );
80 static int keyring_copy( KBPOS *kbpos, int mode, KBNODE root );
81
82
83
84 static RESTBL *
85 check_pos( KBPOS *kbpos )
86 {
87     if( kbpos->resno < 0 || kbpos->resno >= MAX_RESOURCES )
88         return NULL;
89     if( !resource_table[kbpos->resno].used )
90         return NULL;
91     return resource_table + kbpos->resno;
92 }
93
94
95
96 /****************************************************************
97  ****************** public functions ****************************
98  ****************************************************************/
99
100 /****************
101  * Register a resource (which currently may ionly be a keyring file).
102  */
103 int
104 add_keyblock_resource( const char *filename, int force, int secret )
105 {
106     IOBUF iobuf;
107     int i;
108
109     for(i=0; i < MAX_RESOURCES; i++ )
110         if( !resource_table[i].used )
111             break;
112     if( i == MAX_RESOURCES )
113         return G10ERR_RESOURCE_LIMIT;
114
115     iobuf = iobuf_open( filename );
116     if( !iobuf && !force )
117         return G10ERR_OPEN_FILE;
118     resource_table[i].used = 1;
119     resource_table[i].secret = !!secret;
120     resource_table[i].fname = m_strdup(filename);
121     resource_table[i].iobuf = iobuf;
122     return 0;
123 }
124
125
126 /****************
127  * Get a keyblock handle KBPOS from a filename. This can be used
128  * to get a handle for insert_keyblock for a new keyblock.
129  */
130 int
131 get_keyblock_handle( const char *filename, int secret, KBPOS *kbpos )
132 {
133     int i;
134
135     for(i=0; i < MAX_RESOURCES; i++ )
136         if( resource_table[i].used && !resource_table[i].secret == !secret ) {
137             /* fixme: dos needs case insensitive file compare */
138             if( !strcmp( resource_table[i].fname, filename ) ) {
139                 memset( kbpos, 0, sizeof *kbpos );
140                 kbpos->resno = i;
141                 return 0;
142             }
143         }
144     return -1; /* not found */
145 }
146
147
148 /****************
149  * Find a keyblock from the informations provided in INFO
150  * This can only be used fro public keys
151  */
152 int
153 find_keyblock( PUBKEY_FIND_INFO info, KBPOS *kbpos )
154 {
155     int i, rc, last_rc=-1;
156
157     for(i=0; i < MAX_RESOURCES; i++ ) {
158         if( resource_table[i].used && !resource_table[i].secret ) {
159             /* note: here we have to add different search functions,
160              * depending on the type of the resource */
161             rc = keyring_search2( info, kbpos, resource_table[i].fname );
162             if( !rc ) {
163                 kbpos->resno = i;
164                 return 0;
165             }
166             if( rc != -1 ) {
167                 log_error("error searching resource %d: %s\n",
168                                                   i, g10_errstr(rc));
169                 last_rc = rc;
170             }
171         }
172     }
173     return last_rc;
174 }
175
176
177
178 /****************
179  * Search a keyblock which starts with the given packet and put all
180  * informations into KBPOS, which can be used later to access this key block.
181  * This function looks into all registered keyblock sources.
182  * PACKET must be a packet with either a secret_cert or a public_cert
183  *
184  * This function is intended to check wether a given certificate
185  * is already in a keyring or to prepare it for editing.
186  *
187  * Returns: 0 if found, -1 if not found or an errorcode.
188  */
189 static int
190 search( PACKET *pkt, KBPOS *kbpos, int secret )
191 {
192     int i, rc, last_rc=-1;
193
194     for(i=0; i < MAX_RESOURCES; i++ ) {
195         if( resource_table[i].used && !resource_table[i].secret == !secret ) {
196             /* note: here we have to add different search functions,
197              * depending on the type of the resource */
198             rc = keyring_search( pkt, kbpos, resource_table[i].iobuf );
199             if( !rc ) {
200                 kbpos->resno = i;
201                 return 0;
202             }
203             if( rc != -1 ) {
204                 log_error("error searching resource %d: %s\n",
205                                                   i, g10_errstr(rc));
206                 last_rc = rc;
207             }
208         }
209     }
210     return last_rc;
211 }
212
213
214 /****************
215  * Combined function to search for a username and get the position
216  * of the keyblock.
217  */
218 int
219 find_keyblock_byname( KBPOS *kbpos, const char *username )
220 {
221     PACKET pkt;
222     PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc );
223     int rc;
224
225     rc = get_pubkey_byname( pkc, username );
226     if( rc ) {
227         free_public_cert(pkc);
228         return rc;
229     }
230
231     init_packet( &pkt );
232     pkt.pkttype = PKT_PUBLIC_CERT;
233     pkt.pkt.public_cert = pkc;
234     rc = search( &pkt, kbpos, 0 );
235     free_public_cert(pkc);
236     return rc;
237 }
238
239 /****************
240  * Combined function to search for a username and get the position
241  * of the keyblock. This function does not unprotect the secret key.
242  */
243 int
244 find_secret_keyblock_byname( KBPOS *kbpos, const char *username )
245 {
246     PACKET pkt;
247     PKT_secret_cert *skc = m_alloc_clear( sizeof *skc );
248     int rc;
249
250     rc = get_seckey_byname( skc, username, 0 );
251     if( rc ) {
252         free_secret_cert(skc);
253         return rc;
254     }
255
256     init_packet( &pkt );
257     pkt.pkttype = PKT_SECRET_CERT;
258     pkt.pkt.secret_cert = skc;
259     rc = search( &pkt, kbpos, 1 );
260     free_secret_cert(skc);
261     return rc;
262 }
263
264
265 /****************
266  * Lock the keyblock; wait until it's available
267  * This function may change the internal data in kbpos, in cases
268  * when the to be locked keyblock has been modified.
269  * fixme: remove this function and add an option to search()?
270  */
271 int
272 lock_keyblock( KBPOS *kbpos )
273 {
274     if( !check_pos(kbpos) )
275         return G10ERR_GENERAL;
276     return 0;
277 }
278
279 /****************
280  * Release a lock on a keyblock
281  */
282 void
283 unlock_keyblock( KBPOS *kbpos )
284 {
285     if( !check_pos(kbpos) )
286         BUG();
287 }
288
289 /****************
290  * Read a complete keyblock and return the root in ret_root.
291  */
292 int
293 read_keyblock( KBPOS *kbpos, KBNODE *ret_root )
294 {
295     if( !check_pos(kbpos) )
296         return G10ERR_GENERAL;
297     return keyring_read( kbpos, ret_root );
298 }
299
300 /****************
301  * Insert the keyblock described by ROOT into the keyring described
302  * by KBPOS.  This actually appends the data to the keyfile.
303  */
304 int
305 insert_keyblock( KBPOS *kbpos, KBNODE root )
306 {
307     int rc;
308
309     if( !check_pos(kbpos) )
310         return G10ERR_GENERAL;
311
312     rc = keyring_copy( kbpos, 1, root );
313
314     return rc;
315 }
316
317 /****************
318  * Delete the keyblock described by KBPOS.
319  * The current code simply changes the keyblock in the keyring
320  * to packet of type 0 with the correct length.  To help detecting errors,
321  * zero bytes are written.
322  */
323 int
324 delete_keyblock( KBPOS *kbpos )
325 {
326     int rc;
327
328     if( !check_pos(kbpos) )
329         return G10ERR_GENERAL;
330
331     rc = keyring_copy( kbpos, 2, NULL );
332
333     return rc;
334 }
335
336
337 /****************
338  * Update the keyblock at KBPOS with the one in ROOT.
339  */
340 int
341 update_keyblock( KBPOS *kbpos, KBNODE root )
342 {
343     int rc;
344
345     if( !check_pos(kbpos) )
346         return G10ERR_GENERAL;
347
348     rc = keyring_copy( kbpos, 3, root );
349
350     return rc;
351 }
352
353
354 /****************************************************************
355  ********** Functions which operates on regular keyrings ********
356  ****************************************************************/
357
358
359 /****************
360  * search one keyring, return 0 if found, -1 if not found or an errorcode.
361  */
362 static int
363 keyring_search( PACKET *req, KBPOS *kbpos, IOBUF iobuf )
364 {
365     int rc;
366     PACKET pkt;
367     int save_mode;
368     ulong offset;
369     int pkttype = req->pkttype;
370     PKT_public_cert *req_pkc = req->pkt.public_cert;
371     PKT_secret_cert *req_skc = req->pkt.secret_cert;
372
373     init_packet(&pkt);
374     save_mode = set_packet_list_mode(0);
375
376     if( iobuf_seek( iobuf, 0 ) ) {
377         log_error("can't rewind keyring file: %s\n", g10_errstr(rc));
378         rc = G10ERR_KEYRING_OPEN;
379         goto leave;
380     }
381
382     while( !(rc=search_packet(iobuf, &pkt, pkttype, &offset)) ) {
383         if( pkt.pkttype == PKT_SECRET_CERT ) {
384             PKT_secret_cert *skc = pkt.pkt.secret_cert;
385
386             if(   req_skc->timestamp == skc->timestamp
387                && req_skc->valid_days == skc->valid_days
388                && req_skc->pubkey_algo == skc->pubkey_algo
389                && (   ( skc->pubkey_algo == PUBKEY_ALGO_ELGAMAL
390                         && !mpi_cmp( req_skc->d.elg.p, skc->d.elg.p )
391                         && !mpi_cmp( req_skc->d.elg.g, skc->d.elg.g )
392                         && !mpi_cmp( req_skc->d.elg.y, skc->d.elg.y )
393                         && !mpi_cmp( req_skc->d.elg.x, skc->d.elg.x )
394                       )
395                    || ( skc->pubkey_algo == PUBKEY_ALGO_RSA
396                         && !mpi_cmp( req_skc->d.rsa.rsa_n, skc->d.rsa.rsa_n )
397                         && !mpi_cmp( req_skc->d.rsa.rsa_e, skc->d.rsa.rsa_e )
398                         && !mpi_cmp( req_skc->d.rsa.rsa_d, skc->d.rsa.rsa_d )
399                       )
400                   )
401               )
402                 break; /* found */
403         }
404         else if( pkt.pkttype == PKT_PUBLIC_CERT ) {
405             PKT_public_cert *pkc = pkt.pkt.public_cert;
406
407             if(   req_pkc->timestamp == pkc->timestamp
408                && req_pkc->valid_days == pkc->valid_days
409                && req_pkc->pubkey_algo == pkc->pubkey_algo
410                && (   ( pkc->pubkey_algo == PUBKEY_ALGO_ELGAMAL
411                         && !mpi_cmp( req_pkc->d.elg.p, pkc->d.elg.p )
412                         && !mpi_cmp( req_pkc->d.elg.g, pkc->d.elg.g )
413                         && !mpi_cmp( req_pkc->d.elg.y, pkc->d.elg.y )
414                       )
415                    || ( pkc->pubkey_algo == PUBKEY_ALGO_RSA
416                         && !mpi_cmp( req_pkc->d.rsa.rsa_n, pkc->d.rsa.rsa_n )
417                         && !mpi_cmp( req_pkc->d.rsa.rsa_e, pkc->d.rsa.rsa_e )
418                       )
419                   )
420               )
421                 break; /* found */
422         }
423         else
424             BUG();
425         free_packet(&pkt);
426     }
427     if( !rc )
428         kbpos->offset = offset;
429
430   leave:
431     free_packet(&pkt);
432     set_packet_list_mode(save_mode);
433     return rc;
434 }
435
436 /****************
437  * search one keyring, return 0 if found, -1 if not found or an errorcode.
438  * this version uses the finger print and other informations
439  */
440 static int
441 keyring_search2( PUBKEY_FIND_INFO info, KBPOS *kbpos, const char *fname )
442 {
443     int rc;
444     PACKET pkt;
445     int save_mode;
446     ulong offset;
447     IOBUF iobuf;
448
449     init_packet(&pkt);
450     save_mode = set_packet_list_mode(0);
451
452     iobuf = iobuf_open( fname );
453     if( !iobuf ) {
454         log_error("can't open '%s'\n", fname );
455         rc = G10ERR_OPEN_FILE;
456         goto leave;
457     }
458
459     while( !(rc=search_packet(iobuf, &pkt, PKT_PUBLIC_CERT, &offset)) ) {
460         PKT_public_cert *pkc = pkt.pkt.public_cert;
461         u32 keyid[2];
462
463         assert( pkt.pkttype == PKT_PUBLIC_CERT );
464         keyid_from_pkc( pkc, keyid );
465         if( keyid[0] == info->keyid[0] && keyid[1] == info->keyid[1]
466             && pkc->pubkey_algo == info->pubkey_algo ) {
467             /* fixme: shall we check nbits too? (good for rsa keys) */
468             /* fixme: check userid???? */
469             size_t len;
470             byte *fp = fingerprint_from_pkc( pkc, &len );
471
472             if( !memcmp( fp, info->fingerprint, len ) ) {
473                 m_free(fp);
474                 break; /* found */
475             }
476             m_free(fp);
477         }
478         free_packet(&pkt);
479     }
480     if( !rc )
481         kbpos->offset = offset;
482
483   leave:
484     iobuf_close(iobuf);
485     free_packet(&pkt);
486     set_packet_list_mode(save_mode);
487     return rc;
488 }
489
490
491 static int
492 keyring_read( KBPOS *kbpos, KBNODE *ret_root )
493 {
494     PACKET *pkt;
495     int rc;
496     RESTBL *rentry;
497     KBNODE root = NULL;
498     IOBUF a;
499     int in_cert = 0;
500
501     if( !(rentry=check_pos(kbpos)) )
502         return G10ERR_GENERAL;
503
504     a = iobuf_open( rentry->fname );
505     if( !a ) {
506         log_error("can't open '%s'\n", rentry->fname );
507         return G10ERR_OPEN_FILE;
508     }
509
510     if( iobuf_seek( a, kbpos->offset ) ) {
511         log_error("can't seek to %lu: %s\n", kbpos->offset, g10_errstr(rc));
512         iobuf_close(a);
513         return G10ERR_KEYRING_OPEN;
514     }
515
516     pkt = m_alloc( sizeof *pkt );
517     init_packet(pkt);
518     kbpos->count=0;
519     while( (rc=parse_packet(a, pkt)) != -1 ) {
520         if( rc ) {  /* ignore errors */
521             if( rc != G10ERR_UNKNOWN_PACKET ) {
522                 log_error("read_keyblock: read error: %s\n", g10_errstr(rc) );
523                 rc = G10ERR_INV_KEYRING;
524                 goto ready;
525             }
526             kbpos->count++;
527             free_packet( pkt );
528             continue;
529         }
530         /* make a linked list of all packets */
531         switch( pkt->pkttype ) {
532           case PKT_PUBLIC_CERT:
533           case PKT_SECRET_CERT:
534             if( in_cert )
535                 goto ready;
536             in_cert = 1;
537           default:
538             kbpos->count++;
539             if( !root )
540                 root = new_kbnode( pkt );
541             else
542                 add_kbnode( root, new_kbnode( pkt ) );
543             pkt = m_alloc( sizeof *pkt );
544             init_packet(pkt);
545             break;
546         }
547     }
548   ready:
549     if( rc == -1 && root )
550         rc = 0;
551
552     if( rc )
553         release_kbnode( root );
554     else {
555         *ret_root = root;
556     }
557     free_packet( pkt );
558     m_free( pkt );
559     iobuf_close(a);
560     return rc;
561 }
562
563
564
565 /****************
566  * Peromf insert/delete/update operation.
567  * mode 1 = insert
568  *      2 = delete
569  *      3 = update
570  */
571 static int
572 keyring_copy( KBPOS *kbpos, int mode, KBNODE root )
573 {
574     RESTBL *rentry;
575     IOBUF fp, newfp;
576     int rc;
577     char *bakfname = NULL;
578     char *tmpfname = NULL;
579
580     if( !(rentry = check_pos( kbpos )) )
581         return G10ERR_GENERAL;
582
583     /* open the source file */
584     fp = iobuf_open( rentry->fname );
585     if( mode == 1 && !fp && errno == ENOENT ) { /* no file yet */
586         KBNODE kbctx, node;
587
588         /* insert: create a new file */
589         newfp = iobuf_create( rentry->fname );
590         if( !newfp ) {
591             log_error("%s: can't create: %s\n", rentry->fname, strerror(errno));
592             return G10ERR_OPEN_FILE;
593         }
594
595         kbctx=NULL;
596         while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
597             if( (rc = build_packet( newfp, node->pkt )) ) {
598                 log_error("build_packet(%d) failed: %s\n",
599                             node->pkt->pkttype, g10_errstr(rc) );
600                 iobuf_cancel(newfp);
601                 return G10ERR_WRITE_FILE;
602             }
603         }
604         if( iobuf_close(newfp) ) {
605             log_error("%s: close failed: %s\n", rentry->fname, strerror(errno));
606             return G10ERR_CLOSE_FILE;
607         }
608         if( chmod( rentry->fname, S_IRUSR | S_IWUSR ) ) {
609             log_error("%s: chmod failed: %s\n",
610                                     rentry->fname, strerror(errno) );
611             return G10ERR_WRITE_FILE;
612         }
613         return 0;
614     }
615     if( !fp ) {
616         log_error("%s: can't open: %s\n", rentry->fname, strerror(errno) );
617         rc = G10ERR_OPEN_FILE;
618         goto leave;
619     }
620
621     /* create the new file */
622     bakfname = m_alloc( strlen( rentry->fname ) + 2 );
623     strcpy(stpcpy(bakfname,rentry->fname),"~");
624     tmpfname = m_alloc( strlen( rentry->fname ) + 5 );
625     strcpy(stpcpy(tmpfname,rentry->fname),".tmp");
626     newfp = iobuf_create( tmpfname );
627     if( !newfp ) {
628         log_error("%s: can't create: %s\n", tmpfname, strerror(errno) );
629         iobuf_close(fp);
630         rc = G10ERR_OPEN_FILE;
631         goto leave;
632     }
633
634     if( mode == 1 ) { /* insert */
635         /* copy everything to the new file */
636         rc = copy_all_packets( fp, newfp );
637         if( rc != -1 ) {
638             log_error("%s: copy to %s failed: %s\n",
639                       rentry->fname, tmpfname, g10_errstr(rc) );
640             iobuf_close(fp);
641             iobuf_cancel(newfp);
642             goto leave;
643         }
644         rc = 0;
645     }
646
647     if( mode == 2 || mode == 3 ) { /* delete or update */
648         /* copy first part to the new file */
649         rc = copy_some_packets( fp, newfp, kbpos->offset );
650         if( rc ) { /* should never get EOF here */
651             log_error("%s: copy to %s failed: %s\n",
652                       rentry->fname, tmpfname, g10_errstr(rc) );
653             iobuf_close(fp);
654             iobuf_cancel(newfp);
655             goto leave;
656         }
657         /* skip this keyblock */
658         assert( kbpos->count );
659         rc = skip_some_packets( fp, kbpos->count );
660         if( rc ) {
661             log_error("%s: skipping %u packets failed: %s\n",
662                             rentry->fname, kbpos->count, g10_errstr(rc));
663             iobuf_close(fp);
664             iobuf_cancel(newfp);
665             goto leave;
666         }
667     }
668
669     if( mode == 1 || mode == 3 ) { /* insert or update */
670         KBNODE kbctx, node;
671
672         /* append the new data */
673         kbctx=NULL;
674         while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
675             if( (rc = build_packet( newfp, node->pkt )) ) {
676                 log_error("build_packet(%d) failed: %s\n",
677                             node->pkt->pkttype, g10_errstr(rc) );
678                 iobuf_close(fp);
679                 iobuf_cancel(newfp);
680                 rc = G10ERR_WRITE_FILE;
681                 goto leave;
682             }
683         }
684     }
685
686     if( mode == 2 || mode == 3 ) { /* delete or update */
687         /* copy the rest */
688         rc = copy_all_packets( fp, newfp );
689         if( rc != -1 ) {
690             log_error("%s: copy to %s failed: %s\n",
691                       rentry->fname, tmpfname, g10_errstr(rc) );
692             iobuf_close(fp);
693             iobuf_cancel(newfp);
694             goto leave;
695         }
696         rc = 0;
697     }
698
699     /* close both files */
700     iobuf_close(fp);
701     if( iobuf_close(newfp) ) {
702         log_error("%s: close failed: %s\n", tmpfname, strerror(errno) );
703         rc = G10ERR_CLOSE_FILE;
704         goto leave;
705     }
706     /* if the new file is a secring, restrict the permissions */
707     if( rentry->secret ) {
708         if( chmod( tmpfname, S_IRUSR | S_IWUSR ) ) {
709             log_error("%s: chmod failed: %s\n",
710                                     tmpfname, strerror(errno) );
711             rc = G10ERR_WRITE_FILE;
712             goto leave;
713         }
714     }
715     /* rename and make backup file */
716     if( rename( rentry->fname, bakfname ) ) {
717         log_error("%s: rename to %s failed: %s\n",
718                                 rentry->fname, bakfname, strerror(errno) );
719         rc = G10ERR_RENAME_FILE;
720         goto leave;
721     }
722     if( rename( tmpfname, rentry->fname ) ) {
723         log_error("%s: rename to %s failed: %s\n",
724                             tmpfname, rentry->fname,strerror(errno) );
725         rc = G10ERR_RENAME_FILE;
726         goto leave;
727     }
728
729   leave:
730     m_free(bakfname);
731     m_free(tmpfname);
732     return rc;
733 }
734
735
736 /****************************************************************
737  ********** Functions which operates on databases ***************
738  ****************************************************************/
739