started with shm coprocesses
[gnupg.git] / g10 / keyedit.c
1 /* keyedit.c - keyedit stuff
2  *      Copyright (C) 1998 Free Software Foundation, Inc.
3  *
4  * This file is part of GNUPG.
5  *
6  * GNUPG 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  * GNUPG 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 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <assert.h>
27 #include <ctype.h>
28
29 #include "options.h"
30 #include "packet.h"
31 #include "errors.h"
32 #include "iobuf.h"
33 #include "keydb.h"
34 #include "memory.h"
35 #include "util.h"
36 #include "main.h"
37 #include "trustdb.h"
38 #include "filter.h"
39 #include "ttyio.h"
40 #include "i18n.h"
41
42 static void show_key_with_all_names( KBNODE keyblock,
43                 int only_marked, int with_fpr, int with_subkeys );
44 static void show_key_and_fingerprint( KBNODE keyblock );
45 static void show_fingerprint( PKT_public_key *pk );
46 static int menu_adduid( KBNODE keyblock, KBNODE sec_keyblock );
47 static void menu_deluid( KBNODE pub_keyblock, KBNODE sec_keyblock );
48 static void menu_delkey( KBNODE pub_keyblock, KBNODE sec_keyblock );
49 static int menu_select_uid( KBNODE keyblock, int index );
50 static int menu_select_key( KBNODE keyblock, int index );
51 static int count_uids( KBNODE keyblock );
52 static int count_uids_with_flag( KBNODE keyblock, unsigned flag );
53 static int count_keys_with_flag( KBNODE keyblock, unsigned flag );
54 static int count_selected_uids( KBNODE keyblock );
55 static int count_selected_keys( KBNODE keyblock );
56
57
58
59 #define NODFLG_BADSIG (1<<0)  /* bad signature */
60 #define NODFLG_NOKEY  (1<<1)  /* no public key */
61 #define NODFLG_SIGERR (1<<2)  /* other sig error */
62
63 #define NODFLG_MARK_A (1<<4)  /* temporary mark */
64
65 #define NODFLG_SELUID (1<<8)  /* indicate the selected userid */
66 #define NODFLG_SELKEY (1<<9)  /* indicate the selected key */
67
68
69 static int
70 get_keyblock_byname( KBNODE *keyblock, KBPOS *kbpos, const char *username )
71 {
72     int rc;
73
74     *keyblock = NULL;
75     /* search the userid */
76     rc = find_keyblock_byname( kbpos, username );
77     if( rc ) {
78         log_error(_("%s: user not found\n"), username );
79         return rc;
80     }
81
82     /* read the keyblock */
83     rc = read_keyblock( kbpos, keyblock );
84     if( rc )
85         log_error("%s: keyblock read problem: %s\n", username, g10_errstr(rc));
86     return rc;
87 }
88
89
90 /****************
91  * Check the keysigs and set the flags to indicate errors.
92  * Returns true if error found.
93  */
94 static int
95 check_all_keysigs( KBNODE keyblock, int only_selected )
96 {
97     KBNODE kbctx;
98     KBNODE node;
99     int rc;
100     int inv_sigs = 0;
101     int no_key = 0;
102     int oth_err = 0;
103     int has_selfsig = 0;
104     int mis_selfsig = 0;
105     int selected = !only_selected;
106     int anyuid = 0;
107
108     for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
109         if( node->pkt->pkttype == PKT_USER_ID ) {
110             PKT_user_id *uid = node->pkt->pkt.user_id;
111
112             if( only_selected )
113                 selected = (node->flag & NODFLG_SELUID);
114             if( selected ) {
115                 tty_printf("uid  ");
116                 tty_print_string( uid->name, uid->len );
117                 tty_printf("\n");
118                 if( anyuid && !has_selfsig )
119                     mis_selfsig++;
120                 has_selfsig = 0;
121                 anyuid = 1;
122             }
123         }
124         else if( selected && node->pkt->pkttype == PKT_SIGNATURE
125                  && (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) {
126             PKT_signature *sig = node->pkt->pkt.signature;
127             int sigrc, selfsig;
128
129             switch( (rc = check_key_signature( keyblock, node, &selfsig)) ) {
130               case 0:
131                 node->flag &= ~(NODFLG_BADSIG|NODFLG_NOKEY|NODFLG_SIGERR);
132                 sigrc = '!';
133                 break;
134               case G10ERR_BAD_SIGN:
135                 node->flag = NODFLG_BADSIG;
136                 sigrc = '-';
137                 inv_sigs++;
138                 break;
139               case G10ERR_NO_PUBKEY:
140                 node->flag = NODFLG_NOKEY;
141                 sigrc = '?';
142                 no_key++;
143                 break;
144               default:
145                 node->flag = NODFLG_SIGERR;
146                 sigrc = '%';
147                 oth_err++;
148                 break;
149             }
150             if( sigrc != '?' ) {
151                 tty_printf("sig%c       %08lX %s   ",
152                         sigrc, sig->keyid[1], datestr_from_sig(sig));
153                 if( sigrc == '%' )
154                     tty_printf("[%s] ", g10_errstr(rc) );
155                 else if( sigrc == '?' )
156                     ;
157                 else if( selfsig ) {
158                     tty_printf( _("[self-signature]") );
159                     if( sigrc == '!' )
160                         has_selfsig = 1;
161                 }
162                 else {
163                     size_t n;
164                     char *p = get_user_id( sig->keyid, &n );
165                     tty_print_string( p, n > 40? 40 : n );
166                     m_free(p);
167                 }
168                 tty_printf("\n");
169                 /* fixme: Should we update the trustdb here */
170             }
171         }
172     }
173     if( !has_selfsig )
174         mis_selfsig++;
175     if( inv_sigs == 1 )
176         tty_printf(_("1 bad signature\n"), inv_sigs );
177     else if( inv_sigs )
178         tty_printf(_("%d bad signatures\n"), inv_sigs );
179     if( no_key == 1 )
180         tty_printf(_("1 signature not checked due to a missing key\n") );
181     else if( no_key )
182         tty_printf(_("%d signatures not checked due to missing keys\n"), no_key );
183     if( oth_err == 1 )
184         tty_printf(_("1 signature not checked due to an error\n") );
185     else if( oth_err )
186         tty_printf(_("%d signatures not checked due to errors\n"), oth_err );
187     if( mis_selfsig == 1 )
188         tty_printf(_("1 user id without valid self-signature detected\n"));
189     else if( mis_selfsig  )
190         tty_printf(_("%d user ids without valid self-signatures detected\n"),
191                                                                     mis_selfsig);
192
193     return inv_sigs || no_key || oth_err || mis_selfsig;
194 }
195
196
197
198 /****************
199  * Loop over all locusr and and sign the uids after asking.
200  * If no user id is marked, all user ids will be signed;
201  * if some user_ids are marked those will be signed.
202  *
203  * fixme: Add support for our proposed sign-all scheme
204  */
205 static int
206 sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified )
207 {
208     int rc = 0;
209     SK_LIST sk_list = NULL;
210     SK_LIST sk_rover = NULL;
211     KBNODE node, uidnode;
212     PKT_public_key *primary_pk;
213     int select_all = !count_selected_uids(keyblock);
214
215     /* build a list of all signators */
216     rc=build_sk_list( locusr, &sk_list, 0, 1 );
217     if( rc )
218         goto leave;
219
220     /* loop over all signaturs */
221     for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
222         u32 sk_keyid[2];
223         size_t n;
224         char *p;
225
226         keyid_from_sk( sk_rover->sk, sk_keyid );
227         /* set mark A for all selected user ids */
228         for( node=keyblock; node; node = node->next ) {
229             if( select_all || (node->flag & NODFLG_SELUID) )
230                 node->flag |= NODFLG_MARK_A;
231             else
232                 node->flag &= ~NODFLG_MARK_A;
233         }
234         /* reset mark for uids which are already signed */
235         uidnode = NULL;
236         for( node=keyblock; node; node = node->next ) {
237             if( node->pkt->pkttype == PKT_USER_ID ) {
238                 uidnode = (node->flag & NODFLG_MARK_A)? node : NULL;
239             }
240             else if( uidnode && node->pkt->pkttype == PKT_SIGNATURE
241                 && (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) {
242                 if( sk_keyid[0] == node->pkt->pkt.signature->keyid[0]
243                     && sk_keyid[1] == node->pkt->pkt.signature->keyid[1] ) {
244                     tty_printf(_("Already signed by key %08lX\n"),
245                                                         (ulong)sk_keyid[1] );
246                     uidnode->flag &= ~NODFLG_MARK_A; /* remove mark */
247                 }
248             }
249         }
250         /* check whether any uids are left for signing */
251         if( !count_uids_with_flag(keyblock, NODFLG_MARK_A) ) {
252             tty_printf(_("Nothing to sign with key %08lX\n"),
253                                                   (ulong)sk_keyid[1] );
254             continue;
255         }
256         /* Ask whether we realy should sign these user id(s) */
257         tty_printf("\n");
258         show_key_with_all_names( keyblock, 1, 1, 0 );
259         tty_printf("\n");
260         tty_printf(_(
261              "Are you really sure that you want to sign this key\n"
262              "with your key: \""));
263         p = get_user_id( sk_keyid, &n );
264         tty_print_string( p, n );
265         tty_printf("\"\n\n");
266         m_free(p);
267         p = tty_get(_("Really sign? "));
268         tty_kill_prompt();
269         if( !answer_is_yes(p) ) {
270             m_free(p);
271             continue; /* No */
272         }
273         m_free(p);
274         /* now we can sign the user ids */
275       reloop: /* (must use this, because we are modifing the list) */
276         primary_pk = NULL;
277         for( node=keyblock; node; node = node->next ) {
278             if( node->pkt->pkttype == PKT_PUBLIC_KEY )
279                 primary_pk = node->pkt->pkt.public_key;
280             else if( node->pkt->pkttype == PKT_USER_ID
281                      && (node->flag & NODFLG_MARK_A) ) {
282                 PACKET *pkt;
283                 PKT_signature *sig;
284
285                 assert( primary_pk );
286                 node->flag &= ~NODFLG_MARK_A;
287                 rc = make_keysig_packet( &sig, primary_pk,
288                                                node->pkt->pkt.user_id,
289                                                NULL,
290                                                sk_rover->sk,
291                                                0x10, 0, NULL, NULL );
292                 if( rc ) {
293                     log_error(_("signing failed: %s\n"), g10_errstr(rc));
294                     goto leave;
295                 }
296                 *ret_modified = 1; /* we changed the keyblock */
297
298                 pkt = m_alloc_clear( sizeof *pkt );
299                 pkt->pkttype = PKT_SIGNATURE;
300                 pkt->pkt.signature = sig;
301                 insert_kbnode( node, new_kbnode(pkt), PKT_SIGNATURE );
302                 goto reloop;
303             }
304         }
305     } /* end loop over signators */
306
307   leave:
308     release_sk_list( sk_list );
309     return rc;
310 }
311
312
313
314
315 /****************
316  * Delete a public or secret key from a keyring.
317  */
318 int
319 delete_key( const char *username, int secret )
320 {
321     int rc = 0;
322     KBNODE keyblock = NULL;
323     KBNODE node;
324     KBPOS kbpos;
325     PKT_public_key *pk = NULL;
326     PKT_secret_key *sk = NULL;
327     u32 keyid[2];
328     int okay=0;
329
330     /* search the userid */
331     rc = secret? find_secret_keyblock_byname( &kbpos, username )
332                : find_keyblock_byname( &kbpos, username );
333     if( rc ) {
334         log_error(_("%s: user not found\n"), username );
335         goto leave;
336     }
337
338     /* read the keyblock */
339     rc = read_keyblock( &kbpos, &keyblock );
340     if( rc ) {
341         log_error("%s: read problem: %s\n", username, g10_errstr(rc) );
342         goto leave;
343     }
344
345     /* get the keyid from the keyblock */
346     node = find_kbnode( keyblock, secret? PKT_SECRET_KEY:PKT_PUBLIC_KEY );
347     if( !node ) {
348         log_error("Oops; key not found anymore!\n");
349         rc = G10ERR_GENERAL;
350         goto leave;
351     }
352
353     if( secret ) {
354         sk = node->pkt->pkt.secret_key;
355         keyid_from_sk( sk, keyid );
356     }
357     else {
358         pk = node->pkt->pkt.public_key;
359         keyid_from_pk( pk, keyid );
360         rc = seckey_available( keyid );
361         if( !rc ) {
362             log_error(_(
363             "there is a secret key for this public key!\n"));
364             log_info(_(
365             "use option \"--delete-secret-key\" to delete it first.\n"));
366             rc = -1;
367         }
368         else if( rc != G10ERR_NO_SECKEY )
369             log_error("%s: get secret key: %s\n", username, g10_errstr(rc) );
370         else
371             rc = 0;
372     }
373
374     if( rc )
375         rc = 0;
376     else if( opt.batch && secret )
377         log_error(_("can't do that in batch-mode\n"));
378     else if( opt.batch && opt.answer_yes )
379         okay++;
380     else if( opt.batch )
381         log_error(_("can't do that in batch-mode without \"--yes\"\n"));
382     else {
383         char *p;
384         size_t n;
385
386         if( secret )
387             tty_printf("sec  %4u%c/%08lX %s   ",
388                       nbits_from_sk( sk ),
389                       pubkey_letter( sk->pubkey_algo ),
390                       keyid[1], datestr_from_sk(sk) );
391         else
392             tty_printf("pub  %4u%c/%08lX %s   ",
393                       nbits_from_pk( pk ),
394                       pubkey_letter( pk->pubkey_algo ),
395                       keyid[1], datestr_from_pk(pk) );
396         p = get_user_id( keyid, &n );
397         tty_print_string( p, n );
398         m_free(p);
399         tty_printf("\n\n");
400
401         p = tty_get(_("Delete this key from the keyring? "));
402         tty_kill_prompt();
403         if( secret && answer_is_yes(p)) {
404             /* I think it is not required to check a passphrase; if
405              * the user is so stupid as to let others access his secret keyring
406              * (and has no backup) - it is up him to read some very
407              * basic texts about security.
408              */
409             m_free(p);
410             p = tty_get(_("This is a secret key! - really delete? "));
411         }
412         if( answer_is_yes(p) )
413             okay++;
414         m_free(p);
415     }
416
417
418     if( okay ) {
419         rc = delete_keyblock( &kbpos );
420         if( rc ) {
421             log_error("delete_keyblock failed: %s\n", g10_errstr(rc) );
422             goto leave;
423         }
424     }
425
426   leave:
427     release_kbnode( keyblock );
428     return rc;
429 }
430
431
432 /****************
433  * Change the passphrase of the primary and all secondary keys.
434  * We use only one passphrase for all keys.
435  */
436 static int
437 change_passphrase( KBNODE keyblock )
438 {
439     int rc = 0;
440     int changed=0;
441     KBNODE node;
442     PKT_secret_key *sk;
443     char *passphrase = NULL;
444
445     node = find_kbnode( keyblock, PKT_SECRET_KEY );
446     if( !node ) {
447         log_error("Oops; secret key not found anymore!\n");
448         goto leave;
449     }
450     sk = node->pkt->pkt.secret_key;
451
452     switch( is_secret_key_protected( sk ) ) {
453       case -1:
454         rc = G10ERR_PUBKEY_ALGO;
455         break;
456       case 0:
457         tty_printf(_("This key is not protected.\n"));
458         break;
459       default:
460         tty_printf(_("Key is protected.\n"));
461         rc = check_secret_key( sk );
462         if( !rc )
463             passphrase = get_last_passphrase();
464         break;
465     }
466
467     /* unprotect all subkeys (use the supplied passphrase or ask)*/
468     for(node=keyblock; !rc && node; node = node->next ) {
469         if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
470             PKT_secret_key *subsk = node->pkt->pkt.secret_key;
471             set_next_passphrase( passphrase );
472             rc = check_secret_key( subsk );
473         }
474     }
475
476     if( rc )
477         tty_printf(_("Can't edit this key: %s\n"), g10_errstr(rc));
478     else {
479         DEK *dek = NULL;
480         STRING2KEY *s2k = m_alloc_secure( sizeof *s2k );
481
482         tty_printf(_("Enter the new passphrase for this secret key.\n\n") );
483
484         set_next_passphrase( NULL );
485         for(;;) {
486             s2k->mode = 1;
487             s2k->hash_algo = DIGEST_ALGO_RMD160;
488             dek = passphrase_to_dek( NULL, CIPHER_ALGO_BLOWFISH, s2k, 2 );
489             if( !dek ) {
490                 tty_printf(_("passphrase not correctly repeated; try again.\n"));
491             }
492             else if( !dek->keylen ) {
493                 rc = 0;
494                 tty_printf(_( "You don't want a passphrase -"
495                             " this is probably a *bad* idea!\n\n"));
496                 if( tty_get_answer_is_yes(_(
497                                 "Do you really want to do this? ")))
498                     changed++;
499                 break;
500             }
501             else { /* okay */
502                 sk->protect.algo = dek->algo;
503                 sk->protect.s2k = *s2k;
504                 rc = protect_secret_key( sk, dek );
505                 for(node=keyblock; !rc && node; node = node->next ) {
506                     if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
507                         PKT_secret_key *subsk = node->pkt->pkt.secret_key;
508                         subsk->protect.algo = dek->algo;
509                         subsk->protect.s2k = *s2k;
510                         rc = protect_secret_key( subsk, dek );
511                     }
512                 }
513                 if( rc )
514                     log_error("protect_secret_key failed: %s\n", g10_errstr(rc) );
515                 else
516                     changed++;
517                 break;
518             }
519         }
520         m_free(s2k);
521         m_free(dek);
522     }
523
524   leave:
525     m_free( passphrase );
526     set_next_passphrase( NULL );
527     return changed && !rc;
528 }
529
530
531
532
533 /****************
534  * Menu driven key editor
535  *
536  * Note: to keep track of some selection we use node->mark MARKBIT_xxxx.
537  */
538
539 void
540 keyedit_menu( const char *username, STRLIST locusr )
541 {
542     enum cmdids { cmdNONE = 0,
543            cmdQUIT, cmdHELP, cmdFPR, cmdLIST, cmdSELUID, cmdCHECK, cmdSIGN,
544            cmdDEBUG, cmdSAVE, cmdADDUID, cmdDELUID, cmdADDKEY, cmdDELKEY,
545            cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST,
546            cmdNOP };
547     static struct { const char *name;
548                     enum cmdids id;
549                     int need_sk;
550                     const char *desc;
551                   } cmds[] = {
552         { N_("quit")    , cmdQUIT   , 0, N_("quit this menu") },
553         { N_("q")       , cmdQUIT   , 0, NULL   },
554         { N_("save")    , cmdSAVE   , 0, N_("save and quit") },
555         { N_("help")    , cmdHELP   , 0, N_("show this help") },
556         {    "?"        , cmdHELP   , 0, NULL   },
557         { N_("fpr")     , cmdFPR    , 0, N_("show fingerprint") },
558         { N_("list")    , cmdLIST   , 0, N_("list key and user ids") },
559         { N_("l")       , cmdLIST   , 0, NULL   },
560         { N_("uid")     , cmdSELUID , 0, N_("select user id N") },
561         { N_("key")     , cmdSELKEY , 0, N_("select secondary key N") },
562         { N_("check")   , cmdCHECK  , 0, N_("list signatures") },
563         { N_("c")       , cmdCHECK  , 0, NULL },
564         { N_("sign")    , cmdSIGN   , 0, N_("sign the key") },
565         { N_("s")       , cmdSIGN   , 0, NULL },
566         { N_("debug")   , cmdDEBUG  , 0, NULL },
567         { N_("adduid")  , cmdADDUID , 1, N_("add a user id") },
568         { N_("deluid")  , cmdDELUID , 0, N_("delete user id") },
569         { N_("addkey")  , cmdADDKEY , 1, N_("add a secondary key") },
570         { N_("delkey")  , cmdDELKEY , 0, N_("delete a secondary key") },
571         { N_("toggle")  , cmdTOGGLE , 1, N_("toggle between secret "
572                                             "and public key listing") },
573         { N_("t"     )  , cmdTOGGLE , 1, NULL },
574         { N_("passwd")  , cmdPASSWD , 1, N_("change the passphrase") },
575         { N_("trust")   , cmdTRUST , 0, N_("change the ownertrust") },
576
577     { NULL, cmdNONE } };
578     enum cmdids cmd;
579     int rc = 0;
580     KBNODE keyblock = NULL;
581     KBPOS keyblockpos;
582     KBNODE sec_keyblock = NULL;
583     KBPOS sec_keyblockpos;
584     KBNODE cur_keyblock;
585     char *answer = NULL;
586     int redisplay = 1;
587     int modified = 0;
588     int sec_modified = 0;
589     int toggle;
590
591
592     if( opt.batch ) {
593         log_error(_("can't do that in batch-mode\n"));
594         goto leave;
595     }
596
597     /* first try to locate it as secret key */
598     rc = find_secret_keyblock_byname( &sec_keyblockpos, username );
599     if( !rc ) {
600         rc = read_keyblock( &sec_keyblockpos, &sec_keyblock );
601         if( rc ) {
602             log_error("%s: secret keyblock read problem: %s\n",
603                                             username, g10_errstr(rc));
604             goto leave;
605         }
606     }
607
608     /* and now get the public key */
609     rc = get_keyblock_byname( &keyblock, &keyblockpos, username );
610     if( rc )
611         goto leave;
612
613     if( sec_keyblock ) { /* check that they match */
614         /* FIXME: check that they both match */
615         tty_printf(_("Secret key is available.\n"));
616     }
617
618     toggle = 0;
619     cur_keyblock = keyblock;
620     for(;;) { /* main loop */
621         int i, arg_number;
622         char *p;
623
624         tty_printf("\n");
625         if( redisplay ) {
626             show_key_with_all_names( cur_keyblock, 0, 0, 1 );
627             tty_printf("\n");
628             redisplay = 0;
629         }
630         m_free(answer);
631         answer = tty_get(_("Command> "));
632         tty_kill_prompt();
633         trim_spaces(answer);
634
635         arg_number = 0;
636         if( !*answer )
637             cmd = cmdLIST;
638         else if( isdigit( *answer ) ) {
639             cmd = cmdSELUID;
640             arg_number = atoi(answer);
641         }
642         else {
643             if( (p=strchr(answer,' ')) ) {
644                 *p++ = 0;
645                 trim_spaces(answer);
646                 trim_spaces(p);
647                 arg_number = atoi(p);
648             }
649
650             for(i=0; cmds[i].name; i++ )
651                 if( !stricmp( answer, cmds[i].name ) )
652                     break;
653             if( cmds[i].need_sk && !sec_keyblock ) {
654                 tty_printf(_("Need the secret key to to this.\n"));
655                 cmd = cmdNOP;
656             }
657             else
658                 cmd = cmds[i].id;
659         }
660         switch( cmd )  {
661           case cmdHELP:
662             for(i=0; cmds[i].name; i++ ) {
663                 if( cmds[i].need_sk && !sec_keyblock )
664                     ; /* skip if we do not have the secret key */
665                 else if( cmds[i].desc )
666                     tty_printf("%-10s %s\n", cmds[i].name, cmds[i].desc );
667             }
668             break;
669
670           case cmdQUIT:
671             if( !modified )
672                 goto leave;
673             m_free(answer);
674             answer = tty_get(_("Save changes? "));
675             if( !answer_is_yes(answer) )  {
676                 m_free(answer);
677                 answer = tty_get(_("Quit without saving? "));
678                 if( answer_is_yes(answer) )
679                     goto leave;
680                 break;
681             }
682             /* fall thru */
683           case cmdSAVE:
684             if( modified ) {
685                 rc = update_keyblock( &keyblockpos, keyblock );
686                 if( rc ) {
687                     log_error(_("update failed: %s\n"), g10_errstr(rc) );
688                     break;
689                 }
690                 if( sec_modified ) {
691                     rc = update_keyblock( &sec_keyblockpos, sec_keyblock );
692                     if( rc ) {
693                         log_error(_("update secret failed: %s\n"),
694                                                             g10_errstr(rc) );
695                         break;
696                     }
697                 }
698                 /* FIXME: UPDATE/INVALIDATE trustdb !! */
699             }
700             else
701                 tty_printf(_("Key not changed so no update needed.\n"));
702             goto leave;
703
704           case cmdLIST:
705             redisplay = 1;
706             break;
707
708           case cmdFPR:
709             show_key_and_fingerprint( keyblock );
710             break;
711
712           case cmdSELUID:
713             if( menu_select_uid( cur_keyblock, arg_number ) )
714                 redisplay = 1;
715             break;
716
717           case cmdSELKEY:
718             if( menu_select_key( cur_keyblock, arg_number ) )
719                 redisplay = 1;
720             break;
721
722           case cmdCHECK:
723             /* we can only do this with the public key becuase the
724              * check functions can't cope with secret keys and it
725              * is questionable whether this would make sense at all */
726             check_all_keysigs( keyblock, count_selected_uids(keyblock) );
727             break;
728
729           case cmdSIGN: /* sign (only the public key) */
730             if( count_uids(keyblock) > 1 && !count_selected_uids(keyblock) ) {
731                 if( !tty_get_answer_is_yes(_("Really sign all user ids? ")) ) {
732                     tty_printf(_("Hint: Select the user ids to sign\n"));
733                     break;
734                 }
735             }
736             sign_uids( keyblock, locusr, &modified );
737             break;
738
739           case cmdDEBUG:
740             dump_kbnode( cur_keyblock );
741             break;
742
743           case cmdTOGGLE:
744             toggle = !toggle;
745             cur_keyblock = toggle? sec_keyblock : keyblock;
746             redisplay = 1;
747             break;
748
749           case cmdADDUID:
750             if( menu_adduid( keyblock, sec_keyblock ) ) {
751                 redisplay = 1;
752                 sec_modified = modified = 1;
753             }
754             break;
755
756           case cmdDELUID: {
757                 int n1;
758
759                 if( !(n1=count_selected_uids(keyblock)) )
760                     tty_printf(_("You must select at least one user id.\n"));
761                 else if( count_uids(keyblock) - n1 < 1 )
762                     tty_printf(_("You can't delete the last user id!\n"));
763                 else if( tty_get_answer_is_yes(
764                         n1 > 1? _("Really remove all selected user ids? ")
765                               : _("Really remove this user id? ")
766                        ) ) {
767                     menu_deluid( keyblock, sec_keyblock );
768                     redisplay = 1;
769                     modified = 1;
770                     if( sec_keyblock )
771                        sec_modified = 1;
772                 }
773             }
774             break;
775
776           case cmdADDKEY:
777             if( generate_subkeypair( keyblock, sec_keyblock ) ) {
778                 redisplay = 1;
779                 sec_modified = modified = 1;
780             }
781             break;
782
783
784           case cmdDELKEY: {
785                 int n1;
786
787                 if( !(n1=count_selected_keys( keyblock )) )
788                     tty_printf(_("You must select at least one key.\n"));
789                 else if( sec_keyblock && !tty_get_answer_is_yes(
790                        n1 > 1?
791                         _("Do you really want to delete the selected keys? "):
792                         _("Do you really want to delete this key? ")
793                        ))
794                     ;
795                 else {
796                     menu_delkey( keyblock, sec_keyblock );
797                     redisplay = 1;
798                     modified = 1;
799                     if( sec_keyblock )
800                        sec_modified = 1;
801                 }
802             }
803             break;
804
805           case cmdPASSWD:
806             if( change_passphrase( sec_keyblock ) )
807                 sec_modified = 1;
808             break;
809
810           case cmdTRUST:
811             show_key_with_all_names( keyblock, 0, 0, 1 );
812             tty_printf("\n");
813             if( edit_ownertrust( find_kbnode( keyblock,
814                       PKT_PUBLIC_KEY )->pkt->pkt.public_key->local_id, 1 ) )
815                 redisplay = 1;
816             /* we don't need to set modified here, as the trustvalues
817              * are updated immediately */
818             break;
819
820           case cmdNOP:
821             break;
822
823           default:
824             tty_printf("\n");
825             tty_printf(_("Invalid command  (try \"help\")\n"));
826             break;
827         }
828     } /* end main loop */
829
830   leave:
831     release_kbnode( keyblock );
832     release_kbnode( sec_keyblock );
833     m_free(answer);
834 }
835
836
837
838 /****************
839  * Display the key a the user ids, if only_marked is true, do only
840  * so for user ids with mark A flag set and dont display the index number
841  */
842 static void
843 show_key_with_all_names( KBNODE keyblock, int only_marked,
844                          int with_fpr, int with_subkeys )
845 {
846     KBNODE node;
847     int i;
848
849     /* the keys */
850     for( node = keyblock; node; node = node->next ) {
851         if( node->pkt->pkttype == PKT_PUBLIC_KEY
852             || (with_subkeys && node->pkt->pkttype == PKT_PUBLIC_SUBKEY) ) {
853             PKT_public_key *pk = node->pkt->pkt.public_key;
854             tty_printf("%s%c %4u%c/%08lX  created: %s expires: %s",
855                           node->pkt->pkttype == PKT_PUBLIC_KEY? "pub":"sub",
856                           (node->flag & NODFLG_SELKEY)? '*':' ',
857                           nbits_from_pk( pk ),
858                           pubkey_letter( pk->pubkey_algo ),
859                           (ulong)keyid_from_pk(pk,NULL),
860                           datestr_from_pk(pk),
861                           expirestr_from_pk(pk) );
862             if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
863                 int otrust, trust;
864                 trust = query_trust_info(pk);
865                 otrust = get_ownertrust_info( pk->local_id );
866                 tty_printf(" trust: %c/%c", otrust, trust );
867                 if( with_fpr  )
868                     show_fingerprint( pk );
869             }
870             tty_printf("\n");
871         }
872         else if( node->pkt->pkttype == PKT_SECRET_KEY
873             || (with_subkeys && node->pkt->pkttype == PKT_SECRET_SUBKEY) ) {
874             PKT_secret_key *sk = node->pkt->pkt.secret_key;
875             tty_printf("%s%c %4u%c/%08lX  created: %s expires: %s\n",
876                           node->pkt->pkttype == PKT_SECRET_KEY? "sec":"sbb",
877                           (node->flag & NODFLG_SELKEY)? '*':' ',
878                           nbits_from_sk( sk ),
879                           pubkey_letter( sk->pubkey_algo ),
880                           (ulong)keyid_from_sk(sk,NULL),
881                           datestr_from_sk(sk),
882                           expirestr_from_sk(sk) );
883         }
884     }
885     /* the user ids */
886     i = 0;
887     for( node = keyblock; node; node = node->next ) {
888         if( node->pkt->pkttype == PKT_USER_ID ) {
889             PKT_user_id *uid = node->pkt->pkt.user_id;
890             ++i;
891             if( !only_marked || (only_marked && (node->flag & NODFLG_MARK_A))){
892                 if( only_marked )
893                    tty_printf("     ");
894                 else if( node->flag & NODFLG_SELUID )
895                    tty_printf("(%d)* ", i);
896                 else
897                    tty_printf("(%d)  ", i);
898                 tty_print_string( uid->name, uid->len );
899                 tty_printf("\n");
900             }
901         }
902     }
903 }
904
905 static void
906 show_key_and_fingerprint( KBNODE keyblock )
907 {
908     KBNODE node;
909     PKT_public_key *pk = NULL;
910
911     for( node = keyblock; node; node = node->next ) {
912         if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
913             pk = node->pkt->pkt.public_key;
914             tty_printf("pub  %4u%c/%08lX %s ",
915                           nbits_from_pk( pk ),
916                           pubkey_letter( pk->pubkey_algo ),
917                           (ulong)keyid_from_pk(pk,NULL),
918                           datestr_from_pk(pk) );
919         }
920         else if( node->pkt->pkttype == PKT_USER_ID ) {
921             PKT_user_id *uid = node->pkt->pkt.user_id;
922             tty_print_string( uid->name, uid->len );
923             break;
924         }
925     }
926     tty_printf("\n");
927     if( pk )
928         show_fingerprint( pk );
929 }
930
931
932 static void
933 show_fingerprint( PKT_public_key *pk )
934 {
935     byte *array, *p;
936     size_t i, n;
937
938     p = array = fingerprint_from_pk( pk, NULL, &n );
939     tty_printf("             Fingerprint:");
940     if( n == 20 ) {
941         for(i=0; i < n ; i++, i++, p += 2 ) {
942             if( i == 10 )
943                 tty_printf(" ");
944             tty_printf(" %02X%02X", *p, p[1] );
945         }
946     }
947     else {
948         for(i=0; i < n ; i++, p++ ) {
949             if( i && !(i%8) )
950                 tty_printf(" ");
951             tty_printf(" %02X", *p );
952         }
953     }
954     tty_printf("\n");
955     m_free(array);
956 }
957
958
959 /****************
960  * Ask for a new user id , do the selfsignature and put it into
961  * both keyblocks.
962  * Return true if there is a new user id
963  */
964 static int
965 menu_adduid( KBNODE pub_keyblock, KBNODE sec_keyblock )
966 {
967     PKT_user_id *uid;
968     PKT_public_key *pk=NULL;
969     PKT_secret_key *sk=NULL;
970     PKT_signature *sig=NULL;
971     PACKET *pkt;
972     KBNODE node;
973     KBNODE pub_where=NULL, sec_where=NULL;
974     int rc;
975
976     uid = generate_user_id();
977     if( !uid )
978         return 0;
979
980     for( node = pub_keyblock; node; pub_where = node, node = node->next ) {
981         if( node->pkt->pkttype == PKT_PUBLIC_KEY )
982             pk = node->pkt->pkt.public_key;
983         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
984             break;
985     }
986     if( !node ) /* no subkey */
987         pub_where = NULL;
988     for( node = sec_keyblock; node; sec_where = node, node = node->next ) {
989         if( node->pkt->pkttype == PKT_SECRET_KEY )
990             sk = node->pkt->pkt.secret_key;
991         else if( node->pkt->pkttype == PKT_SECRET_SUBKEY )
992             break;
993     }
994     if( !node ) /* no subkey */
995         sec_where = NULL;
996     assert(pk && sk );
997
998     rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0,
999                              keygen_add_std_prefs, sk );
1000     if( rc ) {
1001         log_error("signing failed: %s\n", g10_errstr(rc) );
1002         free_user_id(uid);
1003         return 0;
1004     }
1005
1006     /* insert/append to secret keyblock */
1007     pkt = m_alloc_clear( sizeof *pkt );
1008     pkt->pkttype = PKT_USER_ID;
1009     pkt->pkt.user_id = copy_user_id(NULL, uid);
1010     node = new_kbnode(pkt);
1011     if( sec_where )
1012         insert_kbnode( sec_where, node, 0 );
1013     else
1014         add_kbnode( sec_keyblock, node );
1015     pkt = m_alloc_clear( sizeof *pkt );
1016     pkt->pkttype = PKT_SIGNATURE;
1017     pkt->pkt.signature = copy_signature(NULL, sig);
1018     if( sec_where )
1019         insert_kbnode( node, new_kbnode(pkt), 0 );
1020     else
1021         add_kbnode( sec_keyblock, new_kbnode(pkt) );
1022     /* insert/append to public keyblock */
1023     pkt = m_alloc_clear( sizeof *pkt );
1024     pkt->pkttype = PKT_USER_ID;
1025     pkt->pkt.user_id = uid;
1026     node = new_kbnode(pkt);
1027     if( pub_where )
1028         insert_kbnode( pub_where, node, 0 );
1029     else
1030         add_kbnode( pub_keyblock, node );
1031     pkt = m_alloc_clear( sizeof *pkt );
1032     pkt->pkttype = PKT_SIGNATURE;
1033     pkt->pkt.signature = copy_signature(NULL, sig);
1034     if( pub_where )
1035         insert_kbnode( node, new_kbnode(pkt), 0 );
1036     else
1037         add_kbnode( pub_keyblock, new_kbnode(pkt) );
1038     return 1;
1039 }
1040
1041
1042 /****************
1043  * Remove all selceted userids from the keyrings
1044  */
1045 static void
1046 menu_deluid( KBNODE pub_keyblock, KBNODE sec_keyblock )
1047 {
1048     KBNODE node;
1049     int selected=0;
1050
1051     for( node = pub_keyblock; node; node = node->next ) {
1052         if( node->pkt->pkttype == PKT_USER_ID ) {
1053             selected = node->flag & NODFLG_SELUID;
1054             if( selected ) {
1055                 delete_kbnode( node );
1056                 if( sec_keyblock ) {
1057                     KBNODE snode;
1058                     int s_selected = 0;
1059                     PKT_user_id *uid = node->pkt->pkt.user_id;
1060                     for( snode = sec_keyblock; snode; snode = snode->next ) {
1061                         if( snode->pkt->pkttype == PKT_USER_ID ) {
1062                             PKT_user_id *suid = snode->pkt->pkt.user_id;
1063
1064                             s_selected =
1065                                 (uid->len == suid->len
1066                                  && !memcmp( uid->name, suid->name, uid->len));
1067                             if( s_selected )
1068                                 delete_kbnode( snode );
1069                         }
1070                         else if( s_selected
1071                                  && snode->pkt->pkttype == PKT_SIGNATURE )
1072                             delete_kbnode( snode );
1073                         else if( snode->pkt->pkttype == PKT_SECRET_SUBKEY )
1074                             s_selected = 0;
1075                     }
1076                 }
1077             }
1078         }
1079         else if( selected && node->pkt->pkttype == PKT_SIGNATURE )
1080             delete_kbnode( node );
1081         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
1082             selected = 0;
1083     }
1084     commit_kbnode( &pub_keyblock );
1085     if( sec_keyblock )
1086         commit_kbnode( &sec_keyblock );
1087 }
1088
1089
1090 /****************
1091  * Remove some of the secondary keys
1092  */
1093 static void
1094 menu_delkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
1095 {
1096     KBNODE node;
1097     int selected=0;
1098
1099     for( node = pub_keyblock; node; node = node->next ) {
1100         if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
1101             selected = node->flag & NODFLG_SELKEY;
1102             if( selected ) {
1103                 delete_kbnode( node );
1104                 if( sec_keyblock ) {
1105                     KBNODE snode;
1106                     int s_selected = 0;
1107                     u32 ki[2];
1108
1109                     keyid_from_pk( node->pkt->pkt.public_key, ki );
1110                     for( snode = sec_keyblock; snode; snode = snode->next ) {
1111                         if( snode->pkt->pkttype == PKT_SECRET_SUBKEY ) {
1112                             u32 ki2[2];
1113
1114                             keyid_from_sk( snode->pkt->pkt.secret_key, ki2 );
1115                             s_selected = (ki[0] == ki2[0] && ki[1] == ki2[1]);
1116                             if( s_selected )
1117                                 delete_kbnode( snode );
1118                         }
1119                         else if( s_selected
1120                                  && snode->pkt->pkttype == PKT_SIGNATURE )
1121                             delete_kbnode( snode );
1122                         else
1123                             s_selected = 0;
1124                     }
1125                 }
1126             }
1127         }
1128         else if( selected && node->pkt->pkttype == PKT_SIGNATURE )
1129             delete_kbnode( node );
1130         else
1131             selected = 0;
1132     }
1133     commit_kbnode( &pub_keyblock );
1134     if( sec_keyblock )
1135         commit_kbnode( &sec_keyblock );
1136 }
1137
1138
1139 /****************
1140  * Select one user id or remove all selection if index is 0.
1141  * Returns: True if the selection changed;
1142  */
1143 static int
1144 menu_select_uid( KBNODE keyblock, int index )
1145 {
1146     KBNODE node;
1147     int i;
1148
1149     /* first check that the index is valid */
1150     if( index ) {
1151         for( i=0, node = keyblock; node; node = node->next ) {
1152             if( node->pkt->pkttype == PKT_USER_ID ) {
1153                 if( ++i == index )
1154                     break;
1155             }
1156         }
1157         if( !node ) {
1158             tty_printf(_("No user id with index %d\n"), index );
1159             return 0;
1160         }
1161     }
1162     else { /* reset all */
1163         for( i=0, node = keyblock; node; node = node->next ) {
1164             if( node->pkt->pkttype == PKT_USER_ID )
1165                 node->flag &= ~NODFLG_SELUID;
1166         }
1167         return 1;
1168     }
1169     /* and toggle the new index */
1170     for( i=0, node = keyblock; node; node = node->next ) {
1171         if( node->pkt->pkttype == PKT_USER_ID ) {
1172             if( ++i == index )
1173                 if( (node->flag & NODFLG_SELUID) )
1174                     node->flag &= ~NODFLG_SELUID;
1175                 else
1176                     node->flag |= NODFLG_SELUID;
1177         }
1178     }
1179
1180     return 1;
1181 }
1182
1183 /****************
1184  * Select secondary keys
1185  * Returns: True if the selection changed;
1186  */
1187 static int
1188 menu_select_key( KBNODE keyblock, int index )
1189 {
1190     KBNODE node;
1191     int i;
1192
1193     /* first check that the index is valid */
1194     if( index ) {
1195         for( i=0, node = keyblock; node; node = node->next ) {
1196             if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1197                 || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
1198                 if( ++i == index )
1199                     break;
1200             }
1201         }
1202         if( !node ) {
1203             tty_printf(_("No secondary key with index %d\n"), index );
1204             return 0;
1205         }
1206     }
1207     else { /* reset all */
1208         for( i=0, node = keyblock; node; node = node->next ) {
1209             if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1210                 || node->pkt->pkttype == PKT_SECRET_SUBKEY )
1211                 node->flag &= ~NODFLG_SELKEY;
1212         }
1213         return 1;
1214     }
1215     /* and set the new index */
1216     for( i=0, node = keyblock; node; node = node->next ) {
1217         if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1218             || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
1219             if( ++i == index )
1220                 if( (node->flag & NODFLG_SELKEY) )
1221                     node->flag &= ~NODFLG_SELKEY;
1222                 else
1223                     node->flag |= NODFLG_SELKEY;
1224         }
1225     }
1226
1227     return 1;
1228 }
1229
1230
1231 static int
1232 count_uids_with_flag( KBNODE keyblock, unsigned flag )
1233 {
1234     KBNODE node;
1235     int i=0;
1236
1237     for( node = keyblock; node; node = node->next )
1238         if( node->pkt->pkttype == PKT_USER_ID && (node->flag & flag) )
1239             i++;
1240     return i;
1241 }
1242
1243 static int
1244 count_keys_with_flag( KBNODE keyblock, unsigned flag )
1245 {
1246     KBNODE node;
1247     int i=0;
1248
1249     for( node = keyblock; node; node = node->next )
1250         if( ( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1251               || node->pkt->pkttype == PKT_SECRET_SUBKEY)
1252             && (node->flag & flag) )
1253             i++;
1254     return i;
1255 }
1256
1257 static int
1258 count_uids( KBNODE keyblock )
1259 {
1260     KBNODE node;
1261     int i=0;
1262
1263     for( node = keyblock; node; node = node->next )
1264         if( node->pkt->pkttype == PKT_USER_ID )
1265             i++;
1266     return i;
1267 }
1268
1269
1270 /****************
1271  * Returns true if there is at least one selected user id
1272  */
1273 static int
1274 count_selected_uids( KBNODE keyblock )
1275 {
1276     return count_uids_with_flag( keyblock, NODFLG_SELUID);
1277 }
1278
1279 static int
1280 count_selected_keys( KBNODE keyblock )
1281 {
1282     return count_keys_with_flag( keyblock, NODFLG_SELKEY);
1283 }
1284