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