~ubuntu-branches/ubuntu/jaunty/gnupg2/jaunty

« back to all changes in this revision

Viewing changes to g10/keyedit.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Mueller
  • Date: 2005-03-29 10:30:32 UTC
  • Revision ID: james.westby@ubuntu.com-20050329103032-sj42n2ain3ipx310
Tags: upstream-1.9.15
ImportĀ upstreamĀ versionĀ 1.9.15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* keyedit.c - keyedit stuff
 
2
 * Copyright (C) 1998, 1999, 2000, 2001, 2002,
 
3
 *               2003 Free Software Foundation, Inc.
 
4
 *
 
5
 * This file is part of GnuPG.
 
6
 *
 
7
 * GnuPG is free software; you can redistribute it and/or modify
 
8
 * it under the terms of the GNU General Public License as published by
 
9
 * the Free Software Foundation; either version 2 of the License, or
 
10
 * (at your option) any later version.
 
11
 *
 
12
 * GnuPG is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 * GNU General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; if not, write to the Free Software
 
19
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 
20
 */
 
21
 
 
22
#include <config.h>
 
23
#include <stdio.h>
 
24
#include <stdlib.h>
 
25
#include <string.h>
 
26
#include <errno.h>
 
27
#include <assert.h>
 
28
#include <ctype.h>
 
29
 
 
30
#include "gpg.h"
 
31
#include "options.h"
 
32
#include "packet.h"
 
33
#include "errors.h"
 
34
#include "iobuf.h"
 
35
#include "keydb.h"
 
36
#include "memory.h"
 
37
#include "photoid.h"
 
38
#include "util.h"
 
39
#include "main.h"
 
40
#include "trustdb.h"
 
41
#include "filter.h"
 
42
#include "ttyio.h"
 
43
#include "status.h"
 
44
#include "i18n.h"
 
45
 
 
46
static void show_prefs( PKT_user_id *uid, int verbose );
 
47
static void show_key_with_all_names( KBNODE keyblock, int only_marked,
 
48
            int with_revoker, int with_fpr, int with_subkeys, int with_prefs );
 
49
static void show_key_and_fingerprint( KBNODE keyblock );
 
50
static int menu_adduid( KBNODE keyblock, KBNODE sec_keyblock, int photo );
 
51
static void menu_deluid( KBNODE pub_keyblock, KBNODE sec_keyblock );
 
52
static int  menu_delsig( KBNODE pub_keyblock );
 
53
static void menu_delkey( KBNODE pub_keyblock, KBNODE sec_keyblock );
 
54
static int menu_addrevoker( KBNODE pub_keyblock,
 
55
                            KBNODE sec_keyblock, int sensitive );
 
56
static int menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock );
 
57
static int menu_set_primary_uid( KBNODE pub_keyblock, KBNODE sec_keyblock );
 
58
static int menu_set_preferences( KBNODE pub_keyblock, KBNODE sec_keyblock );
 
59
static int menu_set_keyserver_url (KBNODE pub_keyblock, KBNODE sec_keyblock );
 
60
static int menu_select_uid( KBNODE keyblock, int idx );
 
61
static int menu_select_key( KBNODE keyblock, int idx );
 
62
static int count_uids( KBNODE keyblock );
 
63
static int count_uids_with_flag( KBNODE keyblock, unsigned flag );
 
64
static int count_keys_with_flag( KBNODE keyblock, unsigned flag );
 
65
static int count_selected_uids( KBNODE keyblock );
 
66
static int real_uids_left( KBNODE keyblock );
 
67
static int count_selected_keys( KBNODE keyblock );
 
68
static int menu_revsig( KBNODE keyblock );
 
69
static int menu_revuid( KBNODE keyblock, KBNODE sec_keyblock );
 
70
static int menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock );
 
71
static int enable_disable_key( KBNODE keyblock, int disable );
 
72
static void menu_showphoto( KBNODE keyblock );
 
73
 
 
74
static int update_trust=0;
 
75
 
 
76
#define CONTROL_D ('D' - 'A' + 1)
 
77
 
 
78
#define NODFLG_BADSIG (1<<0)  /* bad signature */
 
79
#define NODFLG_NOKEY  (1<<1)  /* no public key */
 
80
#define NODFLG_SIGERR (1<<2)  /* other sig error */
 
81
 
 
82
#define NODFLG_MARK_A (1<<4)  /* temporary mark */
 
83
#define NODFLG_DELSIG (1<<5)  /* to be deleted */
 
84
 
 
85
#define NODFLG_SELUID (1<<8)  /* indicate the selected userid */
 
86
#define NODFLG_SELKEY (1<<9)  /* indicate the selected key */
 
87
#define NODFLG_SELSIG (1<<10) /* indicate a selected signature */
 
88
 
 
89
struct sign_attrib {
 
90
    int non_exportable,non_revocable;
 
91
    struct revocation_reason_info *reason;
 
92
    byte trust_depth,trust_value;
 
93
    char *trust_regexp;
 
94
};
 
95
 
 
96
/****************
 
97
 * Print information about a signature, check it and return true
 
98
 * if the signature is okay. NODE must be a signature packet.
 
99
 */
 
100
static int
 
101
print_and_check_one_sig( KBNODE keyblock, KBNODE node,
 
102
                         int *inv_sigs, int *no_key, int *oth_err,
 
103
                        int *is_selfsig, int print_without_key )
 
104
{
 
105
    PKT_signature *sig = node->pkt->pkt.signature;
 
106
    int rc, sigrc;
 
107
    int is_rev = sig->sig_class == 0x30;
 
108
 
 
109
    /* TODO: Make sure a cached sig record here still has the pk that
 
110
       issued it.  See also keylist.c:list_keyblock_print */
 
111
 
 
112
    rc = check_key_signature (keyblock, node, is_selfsig);
 
113
    switch ( gpg_err_code (rc) ) {
 
114
      case 0:
 
115
        node->flag &= ~(NODFLG_BADSIG|NODFLG_NOKEY|NODFLG_SIGERR);
 
116
        sigrc = '!';
 
117
        break;
 
118
      case GPG_ERR_BAD_SIGNATURE:
 
119
        node->flag = NODFLG_BADSIG;
 
120
        sigrc = '-';
 
121
        if( inv_sigs )
 
122
            ++*inv_sigs;
 
123
        break;
 
124
      case GPG_ERR_NO_PUBKEY:
 
125
      case GPG_ERR_UNUSABLE_PUBKEY:
 
126
        node->flag = NODFLG_NOKEY;
 
127
        sigrc = '?';
 
128
        if( no_key )
 
129
            ++*no_key;
 
130
        break;
 
131
      default:
 
132
        node->flag = NODFLG_SIGERR;
 
133
        sigrc = '%';
 
134
        if( oth_err )
 
135
            ++*oth_err;
 
136
        break;
 
137
    }
 
138
    if( sigrc != '?' || print_without_key ) {
 
139
        tty_printf("%s%c%c %c%c%c%c%c%c ",
 
140
                   is_rev? "rev":"sig",sigrc,
 
141
                   (sig->sig_class-0x10>0 &&
 
142
                    sig->sig_class-0x10<4)?'0'+sig->sig_class-0x10:' ',
 
143
                   sig->flags.exportable?' ':'L',
 
144
                   sig->flags.revocable?' ':'R',
 
145
                   sig->flags.policy_url?'P':' ',
 
146
                   sig->flags.notation?'N':' ',
 
147
                   sig->flags.expired?'X':' ',
 
148
                   (sig->trust_depth>9)?'T':
 
149
                   (sig->trust_depth>0)?'0'+sig->trust_depth:' ');
 
150
        if(opt.list_options&LIST_SHOW_LONG_KEYID)
 
151
          tty_printf("%08lX%08lX",(ulong)sig->keyid[0],(ulong)sig->keyid[1]);
 
152
        else
 
153
          tty_printf("%08lX",(ulong)sig->keyid[1]);
 
154
        tty_printf(" %s", datestr_from_sig(sig));
 
155
        if(opt.list_options&LIST_SHOW_SIG_EXPIRE)
 
156
          tty_printf(" %s",expirestr_from_sig(sig));
 
157
        tty_printf("  ");
 
158
        if( sigrc == '%' )
 
159
            tty_printf("[%s] ", gpg_strerror (rc) );
 
160
        else if( sigrc == '?' )
 
161
            ;
 
162
        else if( *is_selfsig ) {
 
163
            tty_printf( is_rev? _("[revocation]")
 
164
                              : _("[self-signature]") );
 
165
        }
 
166
        else {
 
167
            size_t n;
 
168
            char *p = get_user_id( sig->keyid, &n );
 
169
            tty_print_utf8_string2( p, n, 40 );
 
170
            xfree (p);
 
171
        }
 
172
        tty_printf("\n");
 
173
 
 
174
        if(sig->flags.policy_url && (opt.list_options&LIST_SHOW_POLICY))
 
175
          show_policy_url(sig,3,0);
 
176
 
 
177
        if(sig->flags.notation && (opt.list_options&LIST_SHOW_NOTATION))
 
178
          show_notation(sig,3,0);
 
179
 
 
180
        if(sig->flags.pref_ks && (opt.list_options&LIST_SHOW_KEYSERVER))
 
181
          show_keyserver_url(sig,3,0);
 
182
    }
 
183
 
 
184
    return (sigrc == '!');
 
185
}
 
186
 
 
187
 
 
188
 
 
189
/****************
 
190
 * Check the keysigs and set the flags to indicate errors.
 
191
 * Returns true if error found.
 
192
 */
 
193
static int
 
194
check_all_keysigs( KBNODE keyblock, int only_selected )
 
195
{
 
196
    KBNODE kbctx;
 
197
    KBNODE node;
 
198
    int inv_sigs = 0;
 
199
    int no_key = 0;
 
200
    int oth_err = 0;
 
201
    int has_selfsig = 0;
 
202
    int mis_selfsig = 0;
 
203
    int selected = !only_selected;
 
204
    int anyuid = 0;
 
205
 
 
206
    for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
 
207
        if( node->pkt->pkttype == PKT_USER_ID ) {
 
208
            PKT_user_id *uid = node->pkt->pkt.user_id;
 
209
 
 
210
            if( only_selected )
 
211
                selected = (node->flag & NODFLG_SELUID);
 
212
            if( selected ) {
 
213
                tty_printf("uid  ");
 
214
                tty_print_utf8_string( uid->name, uid->len );
 
215
                tty_printf("\n");
 
216
                if( anyuid && !has_selfsig )
 
217
                    mis_selfsig++;
 
218
                has_selfsig = 0;
 
219
                anyuid = 1;
 
220
            }
 
221
        }
 
222
        else if( selected && node->pkt->pkttype == PKT_SIGNATURE
 
223
                 && ( (node->pkt->pkt.signature->sig_class&~3) == 0x10
 
224
                     || node->pkt->pkt.signature->sig_class == 0x30 )  ) {
 
225
            int selfsig;
 
226
 
 
227
            if( print_and_check_one_sig( keyblock, node, &inv_sigs,
 
228
                                        &no_key, &oth_err, &selfsig, 0 ) ) {
 
229
                if( selfsig )
 
230
                    has_selfsig = 1;
 
231
            }
 
232
            /* Hmmm: should we update the trustdb here? */
 
233
        }
 
234
    }
 
235
    if( !has_selfsig )
 
236
        mis_selfsig++;
 
237
    if( inv_sigs == 1 )
 
238
        tty_printf(_("1 bad signature\n") );
 
239
    else if( inv_sigs )
 
240
        tty_printf(_("%d bad signatures\n"), inv_sigs );
 
241
    if( no_key == 1 )
 
242
        tty_printf(_("1 signature not checked due to a missing key\n") );
 
243
    else if( no_key )
 
244
        tty_printf(_("%d signatures not checked due to missing keys\n"), no_key );
 
245
    if( oth_err == 1 )
 
246
        tty_printf(_("1 signature not checked due to an error\n") );
 
247
    else if( oth_err )
 
248
        tty_printf(_("%d signatures not checked due to errors\n"), oth_err );
 
249
    if( mis_selfsig == 1 )
 
250
        tty_printf(_("1 user ID without valid self-signature detected\n"));
 
251
    else if( mis_selfsig  )
 
252
        tty_printf(_("%d user IDs without valid self-signatures detected\n"),
 
253
                                                                    mis_selfsig);
 
254
 
 
255
    return inv_sigs || no_key || oth_err || mis_selfsig;
 
256
}
 
257
 
 
258
 
 
259
 
 
260
 
 
261
static int
 
262
sign_mk_attrib( PKT_signature *sig, void *opaque )
 
263
{
 
264
    struct sign_attrib *attrib = opaque;
 
265
    byte buf[8];
 
266
 
 
267
    if( attrib->non_exportable ) {
 
268
        buf[0] = 0; /* not exportable */
 
269
        build_sig_subpkt( sig, SIGSUBPKT_EXPORTABLE, buf, 1 );
 
270
    }
 
271
 
 
272
    if( attrib->non_revocable ) {
 
273
        buf[0] = 0; /* not revocable */
 
274
        build_sig_subpkt( sig, SIGSUBPKT_REVOCABLE, buf, 1 );
 
275
    }
 
276
 
 
277
    if( attrib->reason )
 
278
        revocation_reason_build_cb( sig, attrib->reason );
 
279
 
 
280
    if(attrib->trust_depth)
 
281
      {
 
282
        /* Not critical.  If someone doesn't understand trust sigs,
 
283
           this can still be a valid regular signature. */
 
284
        buf[0] = attrib->trust_depth;
 
285
        buf[1] = attrib->trust_value;
 
286
        build_sig_subpkt(sig,SIGSUBPKT_TRUST,buf,2);
 
287
 
 
288
        /* Critical.  If someone doesn't understands regexps, this
 
289
           whole sig should be invalid.  Note the +1 for the length -
 
290
           regexps are null terminated. */
 
291
        if(attrib->trust_regexp)
 
292
          build_sig_subpkt(sig,SIGSUBPKT_FLAG_CRITICAL|SIGSUBPKT_REGEXP,
 
293
                           attrib->trust_regexp,
 
294
                           strlen(attrib->trust_regexp)+1);
 
295
      }
 
296
 
 
297
    return 0;
 
298
}
 
299
 
 
300
static void
 
301
trustsig_prompt(byte *trust_value, byte *trust_depth, char **regexp)
 
302
{
 
303
  char *p;
 
304
 
 
305
  *trust_value=0;
 
306
  *trust_depth=0;
 
307
  *regexp=NULL;
 
308
 
 
309
  tty_printf("\n");
 
310
  /* Same string as pkclist.c:do_edit_ownertrust */
 
311
  tty_printf(_(
 
312
               "Please decide how far you trust this user to correctly\n"
 
313
               "verify other users' keys (by looking at passports,\n"
 
314
               "checking fingerprints from different sources...)?\n\n"));
 
315
  tty_printf (_("   (%d) I trust marginally\n"), 1);
 
316
  tty_printf (_("   (%d) I trust fully\n"), 2);
 
317
  tty_printf("\n");
 
318
 
 
319
  while(*trust_value==0)
 
320
    {
 
321
      p = cpr_get("trustsig_prompt.trust_value",_("Your selection? "));
 
322
      trim_spaces(p);
 
323
      cpr_kill_prompt();
 
324
      /* 60 and 120 are as per RFC2440 */
 
325
      if(p[0]=='1' && !p[1])
 
326
        *trust_value=60;
 
327
      else if(p[0]=='2' && !p[1])
 
328
        *trust_value=120;
 
329
      xfree (p);
 
330
    }
 
331
 
 
332
  tty_printf("\n");
 
333
 
 
334
  tty_printf(_(
 
335
              "Please enter the depth of this trust signature.\n"
 
336
              "A depth greater than 1 allows the key you are signing to make\n"
 
337
              "trust signatures on your behalf.\n"));
 
338
  tty_printf("\n");
 
339
 
 
340
  while(*trust_depth==0)
 
341
    {
 
342
      p = cpr_get("trustsig_prompt.trust_depth",_("Your selection? "));
 
343
      trim_spaces(p);
 
344
      cpr_kill_prompt();
 
345
      *trust_depth=atoi(p);
 
346
      xfree (p);
 
347
      if(*trust_depth < 1 )
 
348
        *trust_depth=0;
 
349
    }
 
350
 
 
351
  tty_printf("\n");
 
352
 
 
353
  tty_printf(_("Please enter a domain to restrict this signature, "
 
354
               "or enter for none.\n"));
 
355
 
 
356
  tty_printf("\n");
 
357
 
 
358
  p=cpr_get("trustsig_prompt.trust_regexp",_("Your selection? "));
 
359
  trim_spaces(p);
 
360
  cpr_kill_prompt();
 
361
 
 
362
  if(strlen(p)>0)
 
363
    {
 
364
      char *q=p;
 
365
      int regexplen=100,ind;
 
366
 
 
367
      *regexp=xmalloc (regexplen);
 
368
 
 
369
      /* Now mangle the domain the user entered into a regexp.  To do
 
370
         this, \-escape everything that isn't alphanumeric, and attach
 
371
         "<[^>]+[@.]" to the front, and ">$" to the end. */
 
372
 
 
373
      strcpy(*regexp,"<[^>]+[@.]");
 
374
      ind=strlen(*regexp);
 
375
 
 
376
      while(*q)
 
377
        {
 
378
          if(!((*q>='A' && *q<='Z')
 
379
               || (*q>='a' && *q<='z') || (*q>='0' && *q<='9')))
 
380
            (*regexp)[ind++]='\\';
 
381
 
 
382
          (*regexp)[ind++]=*q;
 
383
 
 
384
          if((regexplen-ind)<3)
 
385
            {
 
386
              regexplen+=100;
 
387
              *regexp=xrealloc(*regexp,regexplen);
 
388
            }
 
389
 
 
390
          q++;
 
391
        }
 
392
 
 
393
      (*regexp)[ind]='\0';
 
394
      strcat(*regexp,">$");
 
395
    }
 
396
 
 
397
  xfree (p);
 
398
  tty_printf("\n");
 
399
}
 
400
 
 
401
/****************
 
402
 * Loop over all locusr and and sign the uids after asking.
 
403
 * If no user id is marked, all user ids will be signed;
 
404
 * if some user_ids are marked those will be signed.
 
405
 */
 
406
static int
 
407
sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified,
 
408
           int local, int nonrevocable, int trust )
 
409
{
 
410
    int rc = 0;
 
411
    SK_LIST sk_list = NULL;
 
412
    SK_LIST sk_rover = NULL;
 
413
    PKT_secret_key *sk = NULL;
 
414
    KBNODE node, uidnode;
 
415
    PKT_public_key *primary_pk=NULL;
 
416
    int select_all = !count_selected_uids(keyblock);
 
417
    int all_v3=1;
 
418
 
 
419
    /* Are there any non-v3 sigs on this key already? */
 
420
    if(PGP2)
 
421
      for(node=keyblock;node;node=node->next)
 
422
        if(node->pkt->pkttype==PKT_SIGNATURE &&
 
423
           node->pkt->pkt.signature->version>3)
 
424
          {
 
425
            all_v3=0;
 
426
            break;
 
427
          }
 
428
 
 
429
    /* build a list of all signators.
 
430
     *    
 
431
     * We use the CERT flag to request the primary which must always
 
432
     * be one which is capable of signing keys.  I can't see a reason
 
433
     * why to sign keys using a subkey.  Implementation of USAGE_CERT
 
434
     * is just a hack in getkey.c and does not mean that a subkey
 
435
     * marked as certification capable will be used */
 
436
    rc=build_sk_list( locusr, &sk_list, 0, PUBKEY_USAGE_SIG|PUBKEY_USAGE_CERT);
 
437
    if( rc )
 
438
        goto leave;
 
439
 
 
440
    /* loop over all signators */
 
441
    for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
 
442
        u32 sk_keyid[2],pk_keyid[2];
 
443
        size_t n;
 
444
        char *p,*trust_regexp=NULL;
 
445
        int force_v4=0,class=0,selfsig=0;
 
446
        u32 duration=0,timestamp=0;
 
447
        byte trust_depth=0,trust_value=0;
 
448
 
 
449
        if(local || nonrevocable || trust ||
 
450
           opt.cert_policy_url || opt.cert_notation_data)
 
451
          force_v4=1;
 
452
 
 
453
        /* we have to use a copy of the sk, because make_keysig_packet
 
454
         * may remove the protection from sk and if we did other
 
455
         * changes to the secret key, we would save the unprotected
 
456
         * version */
 
457
        if( sk )
 
458
            free_secret_key(sk);
 
459
        sk = copy_secret_key( NULL, sk_rover->sk );
 
460
        keyid_from_sk( sk, sk_keyid );
 
461
        /* set mark A for all selected user ids */
 
462
        for( node=keyblock; node; node = node->next ) {
 
463
            if( select_all || (node->flag & NODFLG_SELUID) )
 
464
                node->flag |= NODFLG_MARK_A;
 
465
            else
 
466
                node->flag &= ~NODFLG_MARK_A;
 
467
        }
 
468
        /* reset mark for uids which are already signed */
 
469
        uidnode = NULL;
 
470
        for( node=keyblock; node; node = node->next ) {
 
471
            if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
 
472
                primary_pk=node->pkt->pkt.public_key;
 
473
                keyid_from_pk( primary_pk, pk_keyid );
 
474
 
 
475
                /* Is this a self-sig? */
 
476
                if(pk_keyid[0]==sk_keyid[0] && pk_keyid[1]==sk_keyid[1])
 
477
                  {
 
478
                    selfsig=1;
 
479
                    /* Do not force a v4 sig here, otherwise it would
 
480
                       be difficult to remake a v3 selfsig.  If this
 
481
                       is a v3->v4 promotion case, then we set
 
482
                       force_v4 later anyway. */
 
483
                    force_v4=0;
 
484
                  }
 
485
            }
 
486
            else if( node->pkt->pkttype == PKT_USER_ID ) {
 
487
                uidnode = (node->flag & NODFLG_MARK_A)? node : NULL;
 
488
                if(uidnode)
 
489
                  {
 
490
                    char *user=utf8_to_native(uidnode->pkt->pkt.user_id->name,
 
491
                                              uidnode->pkt->pkt.user_id->len,
 
492
                                              0);
 
493
 
 
494
                    if(uidnode->pkt->pkt.user_id->is_revoked)
 
495
                      {
 
496
                        tty_printf(_("User ID \"%s\" is revoked."),user);
 
497
 
 
498
                        if(opt.expert)
 
499
                          {
 
500
                            tty_printf("\n");
 
501
                            /* No, so remove the mark and continue */
 
502
                            if(!cpr_get_answer_is_yes("sign_uid.revoke_okay",
 
503
                                                      _("Are you sure you "
 
504
                                                        "still want to sign "
 
505
                                                        "it? (y/N) ")))
 
506
                              uidnode->flag &= ~NODFLG_MARK_A;
 
507
                          }
 
508
                        else
 
509
                          {
 
510
                            uidnode->flag &= ~NODFLG_MARK_A;
 
511
                            tty_printf(_("  Unable to sign.\n"));
 
512
                          }
 
513
                      }
 
514
                    else if(uidnode->pkt->pkt.user_id->is_expired)
 
515
                      {
 
516
                        tty_printf(_("User ID \"%s\" is expired."),user);
 
517
 
 
518
                        if(opt.expert)
 
519
                          {
 
520
                            tty_printf("\n");
 
521
                            /* No, so remove the mark and continue */
 
522
                            if(!cpr_get_answer_is_yes("sign_uid.expire_okay",
 
523
                                                      _("Are you sure you "
 
524
                                                        "still want to sign "
 
525
                                                        "it? (y/N) ")))
 
526
                              uidnode->flag &= ~NODFLG_MARK_A;
 
527
                          }
 
528
                        else
 
529
                          {
 
530
                            uidnode->flag &= ~NODFLG_MARK_A;
 
531
                            tty_printf(_("  Unable to sign.\n"));
 
532
                          }
 
533
                      }
 
534
                    else if(!uidnode->pkt->pkt.user_id->created && !selfsig)
 
535
                      {
 
536
                        tty_printf(_("User ID \"%s\" is not self-signed."),
 
537
                                   user);
 
538
 
 
539
                        if(opt.expert)
 
540
                          {
 
541
                            tty_printf("\n");
 
542
                            /* No, so remove the mark and continue */
 
543
                            if(!cpr_get_answer_is_yes("sign_uid.nosig_okay",
 
544
                                                      _("Are you sure you "
 
545
                                                        "still want to sign "
 
546
                                                        "it? (y/N) ")))
 
547
                              uidnode->flag &= ~NODFLG_MARK_A;
 
548
                          }
 
549
                        else
 
550
                          {
 
551
                            uidnode->flag &= ~NODFLG_MARK_A;
 
552
                            tty_printf(_("  Unable to sign.\n"));
 
553
                          }
 
554
                      }
 
555
                    xfree (user);
 
556
                  }
 
557
            }
 
558
            else if( uidnode && node->pkt->pkttype == PKT_SIGNATURE
 
559
                && (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) {
 
560
                if( sk_keyid[0] == node->pkt->pkt.signature->keyid[0]
 
561
                    && sk_keyid[1] == node->pkt->pkt.signature->keyid[1] ) {
 
562
                    char buf[50];
 
563
                    char *user=utf8_to_native(uidnode->pkt->pkt.user_id->name,
 
564
                                              uidnode->pkt->pkt.user_id->len,
 
565
                                              0);
 
566
 
 
567
                    /* It's a v3 self-sig.  Make it into a v4 self-sig? */
 
568
                    if(node->pkt->pkt.signature->version<4 && selfsig)
 
569
                      {
 
570
                        tty_printf(_("The self-signature on \"%s\"\n"
 
571
                                     "is a PGP 2.x-style signature.\n"),user);
 
572
 
 
573
                        /* Note that the regular PGP2 warning below
 
574
                           still applies if there are no v4 sigs on
 
575
                           this key at all. */
 
576
 
 
577
                        if(opt.expert)
 
578
                          if(cpr_get_answer_is_yes("sign_uid.v4_promote_okay",
 
579
                                                   _("Do you want to promote "
 
580
                                                     "it to an OpenPGP self-"
 
581
                                                     "signature? (y/N) ")))
 
582
                            {
 
583
                              force_v4=1;
 
584
                              node->flag|=NODFLG_DELSIG;
 
585
                              xfree (user);
 
586
                              continue;
 
587
                            }
 
588
                      }
 
589
 
 
590
                    /* Is the current signature expired? */
 
591
                    if(node->pkt->pkt.signature->flags.expired)
 
592
                      {
 
593
                        tty_printf(_("Your current signature on \"%s\"\n"
 
594
                                     "has expired.\n"),user);
 
595
 
 
596
                        if(cpr_get_answer_is_yes("sign_uid.replace_expired_okay",
 
597
                                                 _("Do you want to issue a "
 
598
                                                   "new signature to replace "
 
599
                                                   "the expired one? (y/N) ")))
 
600
                          {
 
601
                            /* Mark these for later deletion.  We
 
602
                               don't want to delete them here, just in
 
603
                               case the replacement signature doesn't
 
604
                               happen for some reason.  We only delete
 
605
                               these after the replacement is already
 
606
                               in place. */
 
607
 
 
608
                            node->flag|=NODFLG_DELSIG;
 
609
                            xfree (user);
 
610
                            continue;
 
611
                          }
 
612
                      }
 
613
 
 
614
                    if(!node->pkt->pkt.signature->flags.exportable && !local)
 
615
                      {
 
616
                        /* It's a local sig, and we want to make a
 
617
                           exportable sig. */
 
618
                        tty_printf(_("Your current signature on \"%s\"\n"
 
619
                                     "is a local signature.\n"),user);
 
620
 
 
621
                        if(cpr_get_answer_is_yes("sign_uid.local_promote_okay",
 
622
                                                 _("Do you want to promote "
 
623
                                                   "it to a full exportable "
 
624
                                                   "signature? (y/N) ")))
 
625
                          {
 
626
                            /* Mark these for later deletion.  We
 
627
                               don't want to delete them here, just in
 
628
                               case the replacement signature doesn't
 
629
                               happen for some reason.  We only delete
 
630
                               these after the replacement is already
 
631
                               in place. */
 
632
 
 
633
                            node->flag|=NODFLG_DELSIG;
 
634
                            xfree (user);
 
635
                            continue;
 
636
                          }
 
637
                      }
 
638
 
 
639
                    /* Fixme: see whether there is a revocation in which
 
640
                     * case we should allow to sign it again. */
 
641
                    if (!node->pkt->pkt.signature->flags.exportable && local)
 
642
                      tty_printf(_(
 
643
                         "\"%s\" was already locally signed by key %08lX\n"),
 
644
                                 user,(ulong)sk_keyid[1] );
 
645
                    else
 
646
                      tty_printf(_(
 
647
                         "\"%s\" was already signed by key %08lX\n"),
 
648
                                 user,(ulong)sk_keyid[1] );
 
649
 
 
650
                    if(opt.expert
 
651
                       && cpr_get_answer_is_yes("sign_uid.dupe_okay",
 
652
                                                _("Do you want to sign it "
 
653
                                                  "again anyway? (y/N) ")))
 
654
                      {
 
655
                        /* Don't delete the old sig here since this is
 
656
                           an --expert thing. */
 
657
                        xfree (user);
 
658
                        continue;
 
659
                      }
 
660
 
 
661
                    sprintf (buf, "%08lX%08lX",
 
662
                             (ulong)sk->keyid[0], (ulong)sk->keyid[1] );
 
663
                    write_status_text (STATUS_ALREADY_SIGNED, buf);
 
664
                    uidnode->flag &= ~NODFLG_MARK_A; /* remove mark */
 
665
 
 
666
                    xfree (user);
 
667
                }
 
668
            }
 
669
        }
 
670
        /* check whether any uids are left for signing */
 
671
        if( !count_uids_with_flag(keyblock, NODFLG_MARK_A) ) {
 
672
            tty_printf(_("Nothing to sign with key %08lX\n"),
 
673
                                                  (ulong)sk_keyid[1] );
 
674
            continue;
 
675
        }
 
676
        /* Ask whether we really should sign these user id(s) */
 
677
        tty_printf("\n");
 
678
        show_key_with_all_names( keyblock, 1, 0, 1, 0, 0 );
 
679
        tty_printf("\n");
 
680
 
 
681
        if(primary_pk->expiredate && !selfsig)
 
682
          {
 
683
            u32 now=make_timestamp();
 
684
 
 
685
            if(primary_pk->expiredate<=now)
 
686
              {
 
687
                tty_printf(_("This key has expired!"));
 
688
 
 
689
                if(opt.expert)
 
690
                  {
 
691
                    tty_printf("  ");
 
692
                    if(!cpr_get_answer_is_yes("sign_uid.expired_okay",
 
693
                                              _("Are you sure you still "
 
694
                                                "want to sign it? (y/N) ")))
 
695
                      continue;
 
696
                  }
 
697
                else
 
698
                  {
 
699
                    tty_printf(_("  Unable to sign.\n"));
 
700
                    continue;
 
701
                  }
 
702
              }
 
703
            else
 
704
              {
 
705
                char *answer;
 
706
 
 
707
                tty_printf(_("This key is due to expire on %s.\n"),
 
708
                           expirestr_from_pk(primary_pk));
 
709
 
 
710
                answer=cpr_get("sign_uid.expire",
 
711
                               _("Do you want your signature to "
 
712
                                 "expire at the same time? (Y/n) "));
 
713
                if(answer_is_yes_no_default(answer,1))
 
714
                  {
 
715
                    /* This fixes the signature timestamp we're going
 
716
                       to make as now.  This is so the expiration date
 
717
                       is exactly correct, and not a few seconds off
 
718
                       (due to the time it takes to answer the
 
719
                       questions, enter the passphrase, etc). */
 
720
                    timestamp=now;
 
721
                    duration=primary_pk->expiredate-now;
 
722
                    force_v4=1;
 
723
                  }
 
724
 
 
725
                cpr_kill_prompt();
 
726
                xfree (answer);
 
727
              }
 
728
          }
 
729
 
 
730
        /* Only ask for duration if we haven't already set it to match
 
731
           the expiration of the pk */
 
732
        if(opt.ask_cert_expire && !duration && !selfsig)
 
733
          duration=ask_expire_interval(1);
 
734
 
 
735
        if(duration)
 
736
          force_v4=1;
 
737
 
 
738
        /* Is --pgp2 on, it's a v3 key, all the sigs on the key are
 
739
           currently v3 and we're about to sign it with a v4 sig?  If
 
740
           so, danger! */
 
741
        if(PGP2 && all_v3 &&
 
742
           (sk->version>3 || force_v4) && primary_pk->version<=3)
 
743
          {
 
744
            tty_printf(_("You may not make an OpenPGP signature on a "
 
745
                         "PGP 2.x key while in --pgp2 mode.\n"));
 
746
            tty_printf(_("This would make the key unusable in PGP 2.x.\n"));
 
747
 
 
748
            if(opt.expert)
 
749
              {
 
750
                if(!cpr_get_answer_is_yes("sign_uid.v4_on_v3_okay",
 
751
                                          _("Are you sure you still "
 
752
                                            "want to sign it? (y/N) ")))
 
753
                  continue;
 
754
 
 
755
                all_v3=0;
 
756
              }
 
757
            else
 
758
              continue;
 
759
          }
 
760
 
 
761
        if(selfsig)
 
762
          ;
 
763
        else
 
764
          {
 
765
            if(opt.batch)
 
766
              class=0x10+opt.def_cert_check_level;
 
767
            else
 
768
              {
 
769
                char *answer;
 
770
 
 
771
                tty_printf(_("How carefully have you verified the key you are "
 
772
                             "about to sign actually belongs\nto the person "
 
773
                             "named above?  If you don't know what to "
 
774
                             "answer, enter \"0\".\n"));
 
775
                tty_printf("\n");
 
776
                tty_printf(_("   (0) I will not answer.%s\n"),
 
777
                           opt.def_cert_check_level==0?" (default)":"");
 
778
                tty_printf(_("   (1) I have not checked at all.%s\n"),
 
779
                           opt.def_cert_check_level==1?" (default)":"");
 
780
                tty_printf(_("   (2) I have done casual checking.%s\n"),
 
781
                           opt.def_cert_check_level==2?" (default)":"");
 
782
                tty_printf(_("   (3) I have done very careful checking.%s\n"),
 
783
                           opt.def_cert_check_level==3?" (default)":"");
 
784
                tty_printf("\n");
 
785
 
 
786
                while(class==0)
 
787
                  {
 
788
                    answer = cpr_get("sign_uid.class",_("Your selection? "
 
789
                                        "(enter '?' for more information): "));
 
790
 
 
791
                    if(answer[0]=='\0')
 
792
                      class=0x10+opt.def_cert_check_level; /* Default */
 
793
                    else if(ascii_strcasecmp(answer,"0")==0)
 
794
                      class=0x10; /* Generic */
 
795
                    else if(ascii_strcasecmp(answer,"1")==0)
 
796
                      class=0x11; /* Persona */
 
797
                    else if(ascii_strcasecmp(answer,"2")==0)
 
798
                      class=0x12; /* Casual */
 
799
                    else if(ascii_strcasecmp(answer,"3")==0)
 
800
                      class=0x13; /* Positive */
 
801
                    else
 
802
                      tty_printf(_("Invalid selection.\n"));
 
803
 
 
804
                    xfree (answer);
 
805
                  }
 
806
              }
 
807
 
 
808
            if(trust)
 
809
              trustsig_prompt(&trust_value,&trust_depth,&trust_regexp);
 
810
          }
 
811
 
 
812
        tty_printf(_("Are you really sure that you want to sign this key\n"
 
813
                     "with your key: \""));
 
814
        p = get_user_id( sk_keyid, &n );
 
815
        tty_print_utf8_string( p, n );
 
816
        xfree (p); p = NULL;
 
817
        tty_printf("\" (%08lX)\n",(ulong)sk_keyid[1]);
 
818
 
 
819
        if(selfsig)
 
820
          {
 
821
            tty_printf(_("\nThis will be a self-signature.\n"));
 
822
 
 
823
            if( local )
 
824
              tty_printf(
 
825
                         _("\nWARNING: the signature will not be marked "
 
826
                           "as non-exportable.\n"));
 
827
 
 
828
            if( nonrevocable )
 
829
              tty_printf(
 
830
                         _("\nWARNING: the signature will not be marked "
 
831
                           "as non-revocable.\n"));
 
832
          }
 
833
        else
 
834
          {
 
835
            if( local )
 
836
              tty_printf(
 
837
                     _("\nThe signature will be marked as non-exportable.\n"));
 
838
 
 
839
            if( nonrevocable )
 
840
              tty_printf(
 
841
                      _("\nThe signature will be marked as non-revocable.\n"));
 
842
 
 
843
            switch(class)
 
844
              {
 
845
              case 0x11:
 
846
                tty_printf(_("\nI have not checked this key at all.\n"));
 
847
                break;
 
848
 
 
849
              case 0x12:
 
850
                tty_printf(_("\nI have checked this key casually.\n"));
 
851
                break;
 
852
 
 
853
              case 0x13:
 
854
                tty_printf(_("\nI have checked this key very carefully.\n"));
 
855
                break;
 
856
              }
 
857
          }
 
858
 
 
859
        tty_printf("\n");
 
860
 
 
861
        if( opt.batch && opt.answer_yes )
 
862
          ;
 
863
        else if( !cpr_get_answer_is_yes("sign_uid.okay", _("Really sign? ")) )
 
864
            continue;
 
865
 
 
866
        /* now we can sign the user ids */
 
867
      reloop: /* (must use this, because we are modifing the list) */
 
868
        primary_pk = NULL;
 
869
        for( node=keyblock; node; node = node->next ) {
 
870
            if( node->pkt->pkttype == PKT_PUBLIC_KEY )
 
871
                primary_pk = node->pkt->pkt.public_key;
 
872
            else if( node->pkt->pkttype == PKT_USER_ID
 
873
                     && (node->flag & NODFLG_MARK_A) ) {
 
874
                PACKET *pkt;
 
875
                PKT_signature *sig;
 
876
                struct sign_attrib attrib;
 
877
 
 
878
                assert( primary_pk );
 
879
                memset( &attrib, 0, sizeof attrib );
 
880
                attrib.non_exportable = local;
 
881
                attrib.non_revocable = nonrevocable;
 
882
                attrib.trust_depth = trust_depth;
 
883
                attrib.trust_value = trust_value;
 
884
                attrib.trust_regexp = trust_regexp;
 
885
                node->flag &= ~NODFLG_MARK_A;
 
886
 
 
887
                /* we force creation of a v4 signature for local
 
888
                 * signatures, otherwise we would not generate the
 
889
                 * subpacket with v3 keys and the signature becomes
 
890
                 * exportable */
 
891
 
 
892
                if(selfsig)
 
893
                  rc = make_keysig_packet( &sig, primary_pk,
 
894
                                           node->pkt->pkt.user_id,
 
895
                                           NULL,
 
896
                                           sk,
 
897
                                           0x13, 0, force_v4?4:0, 0, 0,
 
898
                                           keygen_add_std_prefs, primary_pk);
 
899
                else
 
900
                  rc = make_keysig_packet( &sig, primary_pk,
 
901
                                           node->pkt->pkt.user_id,
 
902
                                           NULL,
 
903
                                           sk,
 
904
                                           class, 0, force_v4?4:0,
 
905
                                           timestamp, duration,
 
906
                                           sign_mk_attrib, &attrib );
 
907
                if( rc ) {
 
908
                    log_error(_("signing failed: %s\n"), gpg_strerror (rc));
 
909
                    goto leave;
 
910
                }
 
911
 
 
912
                *ret_modified = 1; /* we changed the keyblock */
 
913
                update_trust = 1;
 
914
 
 
915
                pkt = xcalloc (1, sizeof *pkt );
 
916
                pkt->pkttype = PKT_SIGNATURE;
 
917
                pkt->pkt.signature = sig;
 
918
                insert_kbnode( node, new_kbnode(pkt), PKT_SIGNATURE );
 
919
                goto reloop;
 
920
            }
 
921
        }
 
922
 
 
923
        /* Delete any sigs that got promoted */
 
924
        for( node=keyblock; node; node = node->next )
 
925
          if( node->flag & NODFLG_DELSIG)
 
926
            delete_kbnode(node);
 
927
    } /* end loop over signators */
 
928
 
 
929
  leave:
 
930
    release_sk_list( sk_list );
 
931
    if( sk )
 
932
        free_secret_key(sk);
 
933
    return rc;
 
934
}
 
935
 
 
936
 
 
937
 
 
938
/****************
 
939
 * Change the passphrase of the primary and all secondary keys.
 
940
 * We use only one passphrase for all keys.
 
941
 */
 
942
static int
 
943
change_passphrase( KBNODE keyblock )
 
944
{
 
945
    int rc = 0;
 
946
    int changed=0;
 
947
    KBNODE node;
 
948
    PKT_secret_key *sk;
 
949
    char *passphrase = NULL;
 
950
    int no_primary_secrets = 0;
 
951
 
 
952
    node = find_kbnode( keyblock, PKT_SECRET_KEY );
 
953
    if( !node ) {
 
954
        log_error("Oops; secret key not found anymore!\n");
 
955
        goto leave;
 
956
    }
 
957
    sk = node->pkt->pkt.secret_key;
 
958
 
 
959
    switch( is_secret_key_protected( sk ) ) {
 
960
      case -1:
 
961
        rc = GPG_ERR_PUBKEY_ALGO;
 
962
        break;
 
963
      case 0:
 
964
        tty_printf(_("This key is not protected.\n"));
 
965
        break;
 
966
      default:
 
967
        if( sk->protect.s2k.mode == 1001 ) {
 
968
            tty_printf(_("Secret parts of primary key are not available.\n"));
 
969
            no_primary_secrets = 1;
 
970
        }
 
971
        else if( sk->protect.s2k.mode == 1002 ) {
 
972
            tty_printf(_("Secret key is actually stored on a card.\n"));
 
973
            goto leave;
 
974
        }
 
975
        else {
 
976
            tty_printf(_("Key is protected.\n"));
 
977
            rc = check_secret_key( sk, 0 );
 
978
            if( !rc )
 
979
                passphrase = get_last_passphrase();
 
980
        }
 
981
        break;
 
982
    }
 
983
 
 
984
    /* unprotect all subkeys (use the supplied passphrase or ask)*/
 
985
    for(node=keyblock; !rc && node; node = node->next ) {
 
986
        if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
 
987
            PKT_secret_key *subsk = node->pkt->pkt.secret_key;
 
988
            set_next_passphrase( passphrase );
 
989
            rc = check_secret_key( subsk, 0 );
 
990
            if( !rc && !passphrase )
 
991
                passphrase = get_last_passphrase();
 
992
        }
 
993
    }
 
994
 
 
995
    if( rc )
 
996
        tty_printf(_("Can't edit this key: %s\n"), gpg_strerror (rc));
 
997
    else {
 
998
        DEK *dek = NULL;
 
999
        STRING2KEY *s2k = xmalloc_secure ( sizeof *s2k );
 
1000
        const char *errtext = NULL;
 
1001
 
 
1002
        tty_printf(_("Enter the new passphrase for this secret key.\n\n") );
 
1003
 
 
1004
        set_next_passphrase( NULL );
 
1005
        for(;;) {
 
1006
            s2k->mode = opt.s2k_mode;
 
1007
            s2k->hash_algo = opt.s2k_digest_algo;
 
1008
            dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo,
 
1009
                                     s2k, 2, errtext, NULL);
 
1010
            if( !dek ) {
 
1011
                errtext = N_("passphrase not correctly repeated; try again");
 
1012
                tty_printf ("%s.\n", _(errtext));
 
1013
            }
 
1014
            else if( !dek->keylen ) {
 
1015
                rc = 0;
 
1016
                tty_printf(_( "You don't want a passphrase -"
 
1017
                            " this is probably a *bad* idea!\n\n"));
 
1018
                if( cpr_get_answer_is_yes("change_passwd.empty.okay",
 
1019
                               _("Do you really want to do this? ")))
 
1020
                  {
 
1021
                    changed++;
 
1022
                    break;
 
1023
                  }
 
1024
            }
 
1025
            else { /* okay */
 
1026
                rc = 0;
 
1027
                if( !no_primary_secrets ) {
 
1028
                    sk->protect.algo = dek->algo;
 
1029
                    sk->protect.s2k = *s2k;
 
1030
                    rc = protect_secret_key( sk, dek );
 
1031
                }
 
1032
                for(node=keyblock; !rc && node; node = node->next ) {
 
1033
                    if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
 
1034
                        PKT_secret_key *subsk = node->pkt->pkt.secret_key;
 
1035
                        subsk->protect.algo = dek->algo;
 
1036
                        subsk->protect.s2k = *s2k;
 
1037
                        rc = protect_secret_key( subsk, dek );
 
1038
                    }
 
1039
                }
 
1040
                if( rc )
 
1041
                    log_error("protect_secret_key failed: %s\n", gpg_strerror (rc) );
 
1042
                else
 
1043
                    changed++;
 
1044
                break;
 
1045
            }
 
1046
        }
 
1047
        xfree (s2k);
 
1048
        xfree (dek);
 
1049
    }
 
1050
 
 
1051
  leave:
 
1052
    xfree ( passphrase );
 
1053
    set_next_passphrase( NULL );
 
1054
    return changed && !rc;
 
1055
}
 
1056
 
 
1057
 
 
1058
/****************
 
1059
 * There are some keys out (due to a bug in gnupg), where the sequence
 
1060
 * of the packets is wrong.  This function fixes that.
 
1061
 * Returns: true if the keyblock has been fixed.
 
1062
 *
 
1063
 * Note:  This function does not work if there is more than one user ID.
 
1064
 */
 
1065
static int
 
1066
fix_keyblock( KBNODE keyblock )
 
1067
{
 
1068
    KBNODE node, last, subkey;
 
1069
    int fixed=0;
 
1070
 
 
1071
    /* locate key signatures of class 0x10..0x13 behind sub key packets */
 
1072
    for( subkey=last=NULL, node = keyblock; node;
 
1073
                                            last=node, node = node->next ) {
 
1074
        switch( node->pkt->pkttype ) {
 
1075
          case PKT_PUBLIC_SUBKEY:
 
1076
          case PKT_SECRET_SUBKEY:
 
1077
            if( !subkey )
 
1078
                subkey = last; /* actually it is the one before the subkey */
 
1079
            break;
 
1080
          case PKT_SIGNATURE:
 
1081
            if( subkey ) {
 
1082
                PKT_signature *sig = node->pkt->pkt.signature;
 
1083
                if( sig->sig_class >= 0x10 && sig->sig_class <= 0x13 ) {
 
1084
                    log_info(_(
 
1085
                        "moving a key signature to the correct place\n"));
 
1086
                    last->next = node->next;
 
1087
                    node->next = subkey->next;
 
1088
                    subkey->next = node;
 
1089
                    node = last;
 
1090
                    fixed=1;
 
1091
                }
 
1092
            }
 
1093
            break;
 
1094
          default: break;
 
1095
        }
 
1096
    }
 
1097
 
 
1098
    return fixed;
 
1099
}
 
1100
 
 
1101
/****************
 
1102
 * Menu driven key editor.  If sign_mode is true semi-automatical signing
 
1103
 * will be performed. commands are ignore in this case
 
1104
 *
 
1105
 * Note: to keep track of some selection we use node->mark MARKBIT_xxxx.
 
1106
 */
 
1107
 
 
1108
void
 
1109
keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
 
1110
                                                    int sign_mode )
 
1111
{
 
1112
    enum cmdids { cmdNONE = 0,
 
1113
           cmdQUIT, cmdHELP, cmdFPR, cmdLIST, cmdSELUID, cmdCHECK, cmdSIGN,
 
1114
           cmdTSIGN, cmdLSIGN, cmdNRSIGN, cmdNRLSIGN, cmdREVSIG, cmdREVKEY,
 
1115
           cmdREVUID, cmdDELSIG, cmdPRIMARY, cmdDEBUG, cmdSAVE, cmdADDUID,
 
1116
           cmdADDPHOTO, cmdDELUID, cmdADDKEY, cmdDELKEY, cmdADDREVOKER,
 
1117
           cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF, cmdEXPIRE,
 
1118
           cmdENABLEKEY, cmdDISABLEKEY, cmdSHOWPREF, cmdSETPREF, cmdUPDPREF,
 
1119
           cmdPREFKS, cmdINVCMD, cmdSHOWPHOTO, cmdUPDTRUST, cmdCHKTRUST,
 
1120
           cmdNOP };
 
1121
    static struct { const char *name;
 
1122
                    enum cmdids id;
 
1123
                    int need_sk;
 
1124
                    int not_with_sk;
 
1125
                    int signmode;
 
1126
                    const char *desc;
 
1127
                  } cmds[] = {
 
1128
        { N_("quit")    , cmdQUIT      , 0,0,1, N_("quit this menu") },
 
1129
        { N_("q")       , cmdQUIT      , 0,0,1, NULL   },
 
1130
        { N_("save")    , cmdSAVE      , 0,0,1, N_("save and quit") },
 
1131
        { N_("help")    , cmdHELP      , 0,0,1, N_("show this help") },
 
1132
        {    "?"        , cmdHELP      , 0,0,1, NULL   },
 
1133
        { N_("fpr")     , cmdFPR       , 0,0,1, N_("show fingerprint") },
 
1134
        { N_("list")    , cmdLIST      , 0,0,1, N_("list key and user IDs") },
 
1135
        { N_("l")       , cmdLIST      , 0,0,1, NULL   },
 
1136
        { N_("uid")     , cmdSELUID    , 0,0,1, N_("select user ID N") },
 
1137
        { N_("key")     , cmdSELKEY    , 0,0,0, N_("select secondary key N") },
 
1138
        { N_("check")   , cmdCHECK     , 0,0,1, N_("list signatures") },
 
1139
        { N_("c")       , cmdCHECK     , 0,0,1, NULL },
 
1140
        { N_("sign")    , cmdSIGN      , 0,1,1, N_("sign the key") },
 
1141
        { N_("s")       , cmdSIGN      , 0,1,1, NULL },
 
1142
        { N_("tsign")   , cmdTSIGN     , 0,1,1, N_("make a trust signature")},
 
1143
        { N_("lsign")   , cmdLSIGN     , 0,1,1, N_("sign the key locally") },
 
1144
        { N_("nrsign")  , cmdNRSIGN    , 0,1,1, N_("sign the key non-revocably") },
 
1145
        { N_("nrlsign") , cmdNRLSIGN   , 0,1,1, N_("sign the key locally and non-revocably") },
 
1146
        { N_("debug")   , cmdDEBUG     , 0,0,0, NULL },
 
1147
        { N_("adduid")  , cmdADDUID    , 1,1,0, N_("add a user ID") },
 
1148
        { N_("addphoto"), cmdADDPHOTO  , 1,1,0, N_("add a photo ID") },
 
1149
        { N_("deluid")  , cmdDELUID    , 0,1,0, N_("delete user ID") },
 
1150
        /* delphoto is really deluid in disguise */
 
1151
        { N_("delphoto"), cmdDELUID    , 0,1,0, NULL },
 
1152
        { N_("addkey")  , cmdADDKEY    , 1,1,0, N_("add a secondary key") },
 
1153
        { N_("delkey")  , cmdDELKEY    , 0,1,0, N_("delete a secondary key") },
 
1154
        { N_("addrevoker"),cmdADDREVOKER,1,1,0, N_("add a revocation key") },
 
1155
        { N_("delsig")  , cmdDELSIG    , 0,1,0, N_("delete signatures") },
 
1156
        { N_("expire")  , cmdEXPIRE    , 1,1,0, N_("change the expire date") },
 
1157
        { N_("primary") , cmdPRIMARY   , 1,1,0, N_("flag user ID as primary")},
 
1158
        { N_("toggle")  , cmdTOGGLE    , 1,0,0, N_("toggle between secret "
 
1159
                                                   "and public key listing") },
 
1160
        { N_("t"     )  , cmdTOGGLE    , 1,0,0, NULL },
 
1161
        { N_("pref")    , cmdPREF      , 0,1,0,
 
1162
                                         N_("list preferences (expert)")},
 
1163
        { N_("showpref"), cmdSHOWPREF  , 0,1,0,
 
1164
                                         N_("list preferences (verbose)")},
 
1165
        { N_("setpref") , cmdSETPREF   , 1,1,0, N_("set preference list") },
 
1166
        { N_("updpref") , cmdUPDPREF   , 1,1,0, N_("updated preferences") },
 
1167
        { N_("keyserver"),cmdPREFKS    , 1,1,0,
 
1168
                                         N_("set preferred keyserver URL")},
 
1169
        { N_("passwd")  , cmdPASSWD    , 1,1,0, N_("change the passphrase") },
 
1170
        { N_("trust")   , cmdTRUST     , 0,1,0, N_("change the ownertrust") },
 
1171
        { N_("revsig")  , cmdREVSIG    , 0,1,0, N_("revoke signatures") },
 
1172
        { N_("revuid")  , cmdREVUID    , 1,1,0, N_("revoke a user ID") },
 
1173
        { N_("revkey")  , cmdREVKEY    , 1,1,0, N_("revoke a secondary key") },
 
1174
        { N_("disable") , cmdDISABLEKEY, 0,1,0, N_("disable a key") },
 
1175
        { N_("enable")  , cmdENABLEKEY , 0,1,0, N_("enable a key") },
 
1176
        { N_("showphoto"),cmdSHOWPHOTO , 0,0,0, N_("show photo ID") },
 
1177
 
 
1178
    { NULL, cmdNONE } };
 
1179
    enum cmdids cmd = 0;
 
1180
    int rc = 0;
 
1181
    KBNODE keyblock = NULL;
 
1182
    KEYDB_HANDLE kdbhd = NULL;
 
1183
    KBNODE sec_keyblock = NULL;
 
1184
    KEYDB_HANDLE sec_kdbhd = NULL;
 
1185
    KBNODE cur_keyblock;
 
1186
    char *answer = NULL;
 
1187
    int redisplay = 1;
 
1188
    int modified = 0;
 
1189
    int sec_modified = 0;
 
1190
    int toggle;
 
1191
    int have_commands = !!commands;
 
1192
 
 
1193
    if ( opt.command_fd != -1 )
 
1194
        ;
 
1195
    else if( opt.batch && !have_commands  ) {
 
1196
        log_error(_("can't do that in batchmode\n"));
 
1197
        goto leave;
 
1198
    }
 
1199
 
 
1200
    if( sign_mode ) {
 
1201
        commands = NULL;
 
1202
        append_to_strlist( &commands, sign_mode == 1? "sign":
 
1203
                           sign_mode == 2?"lsign":
 
1204
                           sign_mode == 3?"nrsign":"nrlsign");
 
1205
        have_commands = 1;
 
1206
    }
 
1207
 
 
1208
    /* get the public key */
 
1209
    rc = get_pubkey_byname (NULL, username, &keyblock, &kdbhd, 1);
 
1210
    if( rc )
 
1211
        goto leave;
 
1212
    if( fix_keyblock( keyblock ) )
 
1213
        modified++;
 
1214
    if( collapse_uids( &keyblock ) )
 
1215
        modified++;
 
1216
    reorder_keyblock(keyblock);
 
1217
 
 
1218
    if( !sign_mode ) {/* see whether we have a matching secret key */
 
1219
        PKT_public_key *pk = keyblock->pkt->pkt.public_key;
 
1220
 
 
1221
        sec_kdbhd = keydb_new (1);
 
1222
        {
 
1223
            byte afp[MAX_FINGERPRINT_LEN];
 
1224
            size_t an;
 
1225
 
 
1226
            fingerprint_from_pk (pk, afp, &an);
 
1227
            while (an < MAX_FINGERPRINT_LEN) 
 
1228
                afp[an++] = 0;
 
1229
            rc = keydb_search_fpr (sec_kdbhd, afp);
 
1230
        }
 
1231
        if (!rc) {
 
1232
            rc = keydb_get_keyblock (sec_kdbhd, &sec_keyblock);
 
1233
            if (rc) {
 
1234
                log_error (_("error reading secret keyblock `%s': %s\n"),
 
1235
                                                username, gpg_strerror (rc));
 
1236
            }
 
1237
            else {
 
1238
                merge_keys_and_selfsig( sec_keyblock );
 
1239
                if( fix_keyblock( sec_keyblock ) )
 
1240
                    sec_modified++;
 
1241
            }
 
1242
        }
 
1243
 
 
1244
        if (rc) {
 
1245
            sec_keyblock = NULL;
 
1246
            keydb_release (sec_kdbhd); sec_kdbhd = NULL;
 
1247
            rc = 0;
 
1248
        }
 
1249
    }
 
1250
 
 
1251
    if( sec_keyblock ) { 
 
1252
        tty_printf(_("Secret key is available.\n"));
 
1253
    }
 
1254
 
 
1255
    toggle = 0;
 
1256
    cur_keyblock = keyblock;
 
1257
    for(;;) { /* main loop */
 
1258
        int i, arg_number, photo;
 
1259
        const char *arg_string = "";
 
1260
        char *p;
 
1261
        PKT_public_key *pk=keyblock->pkt->pkt.public_key;
 
1262
 
 
1263
        tty_printf("\n");
 
1264
        if( redisplay ) {
 
1265
            show_key_with_all_names( cur_keyblock, 0, 1, 0, 1, 0 );
 
1266
            tty_printf("\n");
 
1267
            redisplay = 0;
 
1268
        }
 
1269
        do {
 
1270
            xfree (answer);
 
1271
            if( have_commands ) {
 
1272
                if( commands ) {
 
1273
                    answer = xstrdup ( commands->d );
 
1274
                    commands = commands->next;
 
1275
                }
 
1276
                else if( opt.batch ) {
 
1277
                    answer = xstrdup ("quit");
 
1278
                }
 
1279
                else
 
1280
                    have_commands = 0;
 
1281
            }
 
1282
            if( !have_commands ) {
 
1283
                answer = cpr_get_no_help("keyedit.prompt", _("Command> "));
 
1284
                cpr_kill_prompt();
 
1285
            }
 
1286
            trim_spaces(answer);
 
1287
        } while( *answer == '#' );
 
1288
 
 
1289
        arg_number = 0; /* Yes, here is the init which egcc complains about */
 
1290
        photo = 0; /* This too */
 
1291
        if( !*answer )
 
1292
            cmd = cmdLIST;
 
1293
        else if( *answer == CONTROL_D )
 
1294
            cmd = cmdQUIT;
 
1295
        else if( digitp( answer ) ) {
 
1296
            cmd = cmdSELUID;
 
1297
            arg_number = atoi(answer);
 
1298
        }
 
1299
        else {
 
1300
            if( (p=strchr(answer,' ')) ) {
 
1301
                *p++ = 0;
 
1302
                trim_spaces(answer);
 
1303
                trim_spaces(p);
 
1304
                arg_number = atoi(p);
 
1305
                arg_string = p;
 
1306
            }
 
1307
 
 
1308
            for(i=0; cmds[i].name; i++ ) {
 
1309
                if( !ascii_strcasecmp( answer, cmds[i].name ) )
 
1310
                    break;
 
1311
            }
 
1312
            if( sign_mode && !cmds[i].signmode )
 
1313
                cmd = cmdINVCMD;
 
1314
            else if( cmds[i].need_sk && !sec_keyblock ) {
 
1315
                tty_printf(_("Need the secret key to do this.\n"));
 
1316
                cmd = cmdNOP;
 
1317
            }
 
1318
            else if( cmds[i].not_with_sk && sec_keyblock && toggle ) {
 
1319
                tty_printf(_("Please use the command \"toggle\" first.\n"));
 
1320
                cmd = cmdNOP;
 
1321
            }
 
1322
            else
 
1323
                cmd = cmds[i].id;
 
1324
        }
 
1325
        switch( cmd )  {
 
1326
          case cmdHELP:
 
1327
            for(i=0; cmds[i].name; i++ ) {
 
1328
                if( sign_mode && !cmds[i].signmode )
 
1329
                    ;
 
1330
                else if( cmds[i].need_sk && !sec_keyblock )
 
1331
                    ; /* skip if we do not have the secret key */
 
1332
                else if( cmds[i].desc )
 
1333
                    tty_printf("%-10s %s\n", cmds[i].name, _(cmds[i].desc) );
 
1334
            }
 
1335
            break;
 
1336
 
 
1337
          case cmdLIST:
 
1338
            redisplay = 1;
 
1339
            break;
 
1340
 
 
1341
          case cmdFPR:
 
1342
            show_key_and_fingerprint( keyblock );
 
1343
            break;
 
1344
 
 
1345
          case cmdSELUID:
 
1346
            if( menu_select_uid( cur_keyblock, arg_number ) )
 
1347
                redisplay = 1;
 
1348
            break;
 
1349
 
 
1350
          case cmdSELKEY:
 
1351
            if( menu_select_key( cur_keyblock, arg_number ) )
 
1352
                redisplay = 1;
 
1353
            break;
 
1354
 
 
1355
          case cmdCHECK:
 
1356
            /* we can only do this with the public key becuase the
 
1357
             * check functions can't cope with secret keys and it
 
1358
             * is questionable whether this would make sense at all */
 
1359
            check_all_keysigs( keyblock, count_selected_uids(keyblock) );
 
1360
            break;
 
1361
 
 
1362
          case cmdSIGN: /* sign (only the public key) */
 
1363
          case cmdLSIGN: /* sign (only the public key) */
 
1364
          case cmdNRSIGN: /* sign (only the public key) */
 
1365
          case cmdNRLSIGN: /* sign (only the public key) */
 
1366
          case cmdTSIGN:
 
1367
            if( pk->is_revoked )
 
1368
              {
 
1369
                tty_printf(_("Key is revoked."));
 
1370
 
 
1371
                if(opt.expert)
 
1372
                  {
 
1373
                    tty_printf("  ");
 
1374
                    if(!cpr_get_answer_is_yes("keyedit.sign_revoked.okay",
 
1375
                                              _("Are you sure you still want "
 
1376
                                                "to sign it? (y/N) ")))
 
1377
                      break;
 
1378
                  }
 
1379
                else
 
1380
                  {
 
1381
                    tty_printf(_("  Unable to sign.\n"));
 
1382
                    break;
 
1383
                  }
 
1384
              }
 
1385
 
 
1386
            if( count_uids(keyblock) > 1 && !count_selected_uids(keyblock) ) {
 
1387
                if( !cpr_get_answer_is_yes("keyedit.sign_all.okay",
 
1388
                                           _("Really sign all user IDs? ")) ) {
 
1389
                    tty_printf(_("Hint: Select the user IDs to sign\n"));
 
1390
                    break;
 
1391
                }
 
1392
            }
 
1393
            if( !sign_uids( keyblock, locusr, &modified,
 
1394
                            (cmd == cmdLSIGN) || (cmd == cmdNRLSIGN),
 
1395
                            (cmd == cmdNRSIGN) || (cmd==cmdNRLSIGN),
 
1396
                            (cmd == cmdTSIGN))
 
1397
                && sign_mode )
 
1398
                goto do_cmd_save;
 
1399
            break;
 
1400
 
 
1401
          case cmdDEBUG:
 
1402
            dump_kbnode( cur_keyblock );
 
1403
            break;
 
1404
 
 
1405
          case cmdTOGGLE:
 
1406
            toggle = !toggle;
 
1407
            cur_keyblock = toggle? sec_keyblock : keyblock;
 
1408
            redisplay = 1;
 
1409
            break;
 
1410
 
 
1411
          case cmdADDPHOTO:
 
1412
            if (RFC2440 || RFC1991 || PGP2)
 
1413
              {
 
1414
                tty_printf(
 
1415
                   _("This command is not allowed while in %s mode.\n"),
 
1416
                   RFC2440?"OpenPGP":PGP2?"PGP2":"RFC-1991");
 
1417
                break;
 
1418
              }
 
1419
            photo=1;
 
1420
            /* fall through */
 
1421
 
 
1422
          case cmdADDUID:
 
1423
            if( menu_adduid( keyblock, sec_keyblock, photo ) ) {
 
1424
                redisplay = 1;
 
1425
                sec_modified = modified = 1;
 
1426
                merge_keys_and_selfsig( sec_keyblock );
 
1427
                merge_keys_and_selfsig( keyblock );
 
1428
            }
 
1429
            break;
 
1430
 
 
1431
          case cmdDELUID: {
 
1432
                int n1;
 
1433
 
 
1434
                if( !(n1=count_selected_uids(keyblock)) )
 
1435
                    tty_printf(_("You must select at least one user ID.\n"));
 
1436
                else if( real_uids_left(keyblock) < 1 )
 
1437
                    tty_printf(_("You can't delete the last user ID!\n"));
 
1438
                else if( cpr_get_answer_is_yes(
 
1439
                            "keyedit.remove.uid.okay",
 
1440
                        n1 > 1? _("Really remove all selected user IDs? ")
 
1441
                              : _("Really remove this user ID? ")
 
1442
                       ) ) {
 
1443
                    menu_deluid( keyblock, sec_keyblock );
 
1444
                    redisplay = 1;
 
1445
                    modified = 1;
 
1446
                    if( sec_keyblock )
 
1447
                       sec_modified = 1;
 
1448
                }
 
1449
            }
 
1450
            break;
 
1451
 
 
1452
          case cmdDELSIG: {
 
1453
                int n1;
 
1454
 
 
1455
                if( !(n1=count_selected_uids(keyblock)) )
 
1456
                    tty_printf(_("You must select at least one user ID.\n"));
 
1457
                else if( menu_delsig( keyblock ) ) {
 
1458
                    /* no redisplay here, because it may scroll away some
 
1459
                     * status output of delsig */
 
1460
                    modified = 1;
 
1461
                }
 
1462
            }
 
1463
            break;
 
1464
 
 
1465
          case cmdADDKEY:
 
1466
            if( generate_subkeypair( keyblock, sec_keyblock ) ) {
 
1467
                redisplay = 1;
 
1468
                sec_modified = modified = 1;
 
1469
                merge_keys_and_selfsig( sec_keyblock );
 
1470
                merge_keys_and_selfsig( keyblock );
 
1471
            }
 
1472
            break;
 
1473
 
 
1474
 
 
1475
          case cmdDELKEY: {
 
1476
                int n1;
 
1477
 
 
1478
                if( !(n1=count_selected_keys( keyblock )) )
 
1479
                    tty_printf(_("You must select at least one key.\n"));
 
1480
                else if( sec_keyblock && !cpr_get_answer_is_yes(
 
1481
                            "keyedit.remove.subkey.okay",
 
1482
                       n1 > 1?
 
1483
                        _("Do you really want to delete the selected keys? "):
 
1484
                        _("Do you really want to delete this key? ")
 
1485
                       ))
 
1486
                    ;
 
1487
                else {
 
1488
                    menu_delkey( keyblock, sec_keyblock );
 
1489
                    redisplay = 1;
 
1490
                    modified = 1;
 
1491
                    if( sec_keyblock )
 
1492
                       sec_modified = 1;
 
1493
                }
 
1494
            }
 
1495
            break;
 
1496
 
 
1497
          case cmdADDREVOKER:
 
1498
            {
 
1499
              int sensitive=0;
 
1500
 
 
1501
              if(arg_string && ascii_strcasecmp(arg_string,"sensitive")==0)
 
1502
                sensitive=1;
 
1503
              if( menu_addrevoker( keyblock, sec_keyblock, sensitive ) ) {
 
1504
                redisplay = 1;
 
1505
                sec_modified = modified = 1;
 
1506
                merge_keys_and_selfsig( sec_keyblock );
 
1507
                merge_keys_and_selfsig( keyblock );
 
1508
              }
 
1509
            }
 
1510
            break;
 
1511
 
 
1512
          case cmdREVUID: {
 
1513
                int n1;
 
1514
 
 
1515
                if( !(n1=count_selected_uids(keyblock)) )
 
1516
                    tty_printf(_("You must select at least one user ID.\n"));
 
1517
                else if( cpr_get_answer_is_yes(
 
1518
                            "keyedit.revoke.uid.okay",
 
1519
                        n1 > 1? _("Really revoke all selected user IDs? ")
 
1520
                              : _("Really revoke this user ID? ")
 
1521
                       ) ) {
 
1522
                  if(menu_revuid(keyblock,sec_keyblock))
 
1523
                    {
 
1524
                      modified=1;
 
1525
                      redisplay=1;
 
1526
                    }
 
1527
                }
 
1528
            }
 
1529
            break;
 
1530
 
 
1531
          case cmdREVKEY: {
 
1532
                int n1;
 
1533
 
 
1534
                if( !(n1=count_selected_keys( keyblock )) )
 
1535
                    tty_printf(_("You must select at least one key.\n"));
 
1536
                else if( sec_keyblock && !cpr_get_answer_is_yes(
 
1537
                            "keyedit.revoke.subkey.okay",
 
1538
                       n1 > 1?
 
1539
                        _("Do you really want to revoke the selected keys? "):
 
1540
                        _("Do you really want to revoke this key? ")
 
1541
                       ))
 
1542
                    ;
 
1543
                else {
 
1544
                    if( menu_revkey( keyblock, sec_keyblock ) ) {
 
1545
                        modified = 1;
 
1546
                        /*sec_modified = 1;*/
 
1547
                    }
 
1548
                    redisplay = 1;
 
1549
                }
 
1550
            }
 
1551
            break;
 
1552
 
 
1553
          case cmdEXPIRE:
 
1554
            if( menu_expire( keyblock, sec_keyblock ) ) {
 
1555
                merge_keys_and_selfsig( sec_keyblock );
 
1556
                merge_keys_and_selfsig( keyblock );
 
1557
                sec_modified = 1;
 
1558
                modified = 1;
 
1559
                redisplay = 1;
 
1560
            }
 
1561
            break;
 
1562
 
 
1563
          case cmdPRIMARY:
 
1564
            if( menu_set_primary_uid ( keyblock, sec_keyblock ) ) {
 
1565
                merge_keys_and_selfsig( keyblock );
 
1566
                modified = 1;
 
1567
                redisplay = 1;
 
1568
            }
 
1569
            break;
 
1570
 
 
1571
          case cmdPASSWD:
 
1572
            if( change_passphrase( sec_keyblock ) )
 
1573
                sec_modified = 1;
 
1574
            break;
 
1575
 
 
1576
          case cmdTRUST:
 
1577
            show_key_with_all_names( keyblock, 0, 0, 0, 1, 0 );
 
1578
            tty_printf("\n");
 
1579
            if( edit_ownertrust( find_kbnode( keyblock,
 
1580
                                 PKT_PUBLIC_KEY )->pkt->pkt.public_key, 1 ) ) {
 
1581
                redisplay = 1;
 
1582
                /* No real need to set update_trust here as
 
1583
                   edit_ownertrust() calls revalidation_mark()
 
1584
                   anyway. */
 
1585
                update_trust=1;
 
1586
            }
 
1587
            break;
 
1588
 
 
1589
          case cmdPREF:
 
1590
            show_key_with_all_names( keyblock, 0, 0, 0, 0, 1 );
 
1591
            break;
 
1592
 
 
1593
          case cmdSHOWPREF:
 
1594
            show_key_with_all_names( keyblock, 0, 0, 0, 0, 2 );
 
1595
            break;
 
1596
 
 
1597
          case cmdSETPREF:
 
1598
            keygen_set_std_prefs ( !*arg_string? "default" : arg_string, 0);
 
1599
            break;
 
1600
 
 
1601
          case cmdUPDPREF: 
 
1602
            {
 
1603
              PKT_user_id *temp=keygen_get_std_prefs();
 
1604
              tty_printf(_("Current preference list:\n"));
 
1605
              show_prefs(temp,1);
 
1606
              xfree (temp);
 
1607
            }
 
1608
            if (cpr_get_answer_is_yes ("keyedit.updpref.okay",
 
1609
                                        count_selected_uids (keyblock)?
 
1610
                                        _("Really update the preferences"
 
1611
                                          " for the selected user IDs? "):
 
1612
                                       _("Really update the preferences? "))){
 
1613
 
 
1614
                if ( menu_set_preferences (keyblock, sec_keyblock) ) {
 
1615
                    merge_keys_and_selfsig (keyblock);
 
1616
                    modified = 1;
 
1617
                    redisplay = 1;
 
1618
                }
 
1619
            }
 
1620
            break;
 
1621
 
 
1622
          case cmdPREFKS:
 
1623
            if( menu_set_keyserver_url ( keyblock, sec_keyblock ) ) {
 
1624
                merge_keys_and_selfsig( keyblock );
 
1625
                modified = 1;
 
1626
                redisplay = 1;
 
1627
            }
 
1628
            break;
 
1629
 
 
1630
          case cmdNOP:
 
1631
            break;
 
1632
 
 
1633
          case cmdREVSIG:
 
1634
            if( menu_revsig( keyblock ) ) {
 
1635
                redisplay = 1;
 
1636
                modified = 1;
 
1637
            }
 
1638
            break;
 
1639
 
 
1640
          case cmdENABLEKEY:
 
1641
          case cmdDISABLEKEY:
 
1642
            if( enable_disable_key( keyblock, cmd == cmdDISABLEKEY ) ) {
 
1643
                redisplay = 1;
 
1644
                modified = 1;
 
1645
            }
 
1646
            break;
 
1647
 
 
1648
         case cmdSHOWPHOTO:
 
1649
           menu_showphoto(keyblock);
 
1650
           break;
 
1651
 
 
1652
          case cmdQUIT:
 
1653
            if( have_commands )
 
1654
                goto leave;
 
1655
            if( !modified && !sec_modified )
 
1656
                goto leave;
 
1657
            if( !cpr_get_answer_is_yes("keyedit.save.okay",
 
1658
                                        _("Save changes? ")) ) {
 
1659
                if( cpr_enabled()
 
1660
                    || cpr_get_answer_is_yes("keyedit.cancel.okay",
 
1661
                                             _("Quit without saving? ")) )
 
1662
                    goto leave;
 
1663
                break;
 
1664
            }
 
1665
            /* fall thru */
 
1666
          case cmdSAVE:
 
1667
          do_cmd_save:
 
1668
            if( modified || sec_modified  ) {
 
1669
                if( modified ) {
 
1670
                    rc = keydb_update_keyblock (kdbhd, keyblock);
 
1671
                    if( rc ) {
 
1672
                        log_error(_("update failed: %s\n"), gpg_strerror (rc) );
 
1673
                        break;
 
1674
                    }
 
1675
                }
 
1676
                if( sec_modified ) {
 
1677
                    rc = keydb_update_keyblock (sec_kdbhd, sec_keyblock );
 
1678
                    if( rc ) {
 
1679
                        log_error( _("update secret failed: %s\n"),
 
1680
                                   gpg_strerror (rc) );
 
1681
                        break;
 
1682
                    }
 
1683
                }
 
1684
            }
 
1685
            else
 
1686
                tty_printf(_("Key not changed so no update needed.\n"));
 
1687
 
 
1688
            if( update_trust )
 
1689
              {
 
1690
                revalidation_mark ();
 
1691
                update_trust=0;
 
1692
              }
 
1693
            goto leave;
 
1694
 
 
1695
          case cmdINVCMD:
 
1696
          default:
 
1697
            tty_printf("\n");
 
1698
            tty_printf(_("Invalid command  (try \"help\")\n"));
 
1699
            break;
 
1700
        }
 
1701
    } /* end main loop */
 
1702
 
 
1703
  leave:
 
1704
    release_kbnode( keyblock );
 
1705
    release_kbnode( sec_keyblock );
 
1706
    keydb_release (kdbhd);
 
1707
    xfree (answer);
 
1708
}
 
1709
 
 
1710
 
 
1711
/****************
 
1712
 * show preferences of a public keyblock.
 
1713
 */
 
1714
static void
 
1715
show_prefs (PKT_user_id *uid, int verbose)
 
1716
{
 
1717
    const prefitem_t fake={0,0};
 
1718
    const prefitem_t *prefs;
 
1719
    int i;
 
1720
 
 
1721
    if( !uid )
 
1722
        return;
 
1723
 
 
1724
    if( uid->prefs )
 
1725
        prefs=uid->prefs;
 
1726
    else if(verbose)
 
1727
        prefs=&fake;
 
1728
    else
 
1729
      return;
 
1730
 
 
1731
    if (verbose) {
 
1732
        int any, des_seen=0, sha1_seen=0, uncomp_seen=0;
 
1733
        tty_printf ("     ");
 
1734
        tty_printf (_("Cipher: "));
 
1735
        for(i=any=0; prefs[i].type; i++ ) {
 
1736
            if( prefs[i].type == PREFTYPE_SYM ) {
 
1737
                const char *s = gcry_cipher_algo_name (prefs[i].value);
 
1738
                
 
1739
                if (any)
 
1740
                    tty_printf (", ");
 
1741
                any = 1;
 
1742
                /* We don't want to display strings for experimental algos */
 
1743
                if (s && prefs[i].value < 100 )
 
1744
                    tty_printf ("%s", s );
 
1745
                else
 
1746
                    tty_printf ("[%d]", prefs[i].value);
 
1747
                if (prefs[i].value == CIPHER_ALGO_3DES )
 
1748
                    des_seen = 1;
 
1749
            }    
 
1750
        }
 
1751
        if (!des_seen) {
 
1752
            if (any)
 
1753
                tty_printf (", ");
 
1754
            tty_printf ("%s", gcry_cipher_algo_name (CIPHER_ALGO_3DES));
 
1755
        }
 
1756
        tty_printf ("\n     ");
 
1757
        tty_printf (_("Digest: "));
 
1758
        for(i=any=0; prefs[i].type; i++ ) {
 
1759
            if( prefs[i].type == PREFTYPE_HASH ) {
 
1760
                const char *s = gcry_md_algo_name (prefs[i].value);
 
1761
                
 
1762
                if (any)
 
1763
                    tty_printf (", ");
 
1764
                any = 1;
 
1765
                /* We don't want to display strings for experimental algos */
 
1766
                if (s && prefs[i].value < 100 )
 
1767
                    tty_printf ("%s", s );
 
1768
                else
 
1769
                    tty_printf ("[%d]", prefs[i].value);
 
1770
                if (prefs[i].value == DIGEST_ALGO_SHA1 )
 
1771
                    sha1_seen = 1;
 
1772
            }
 
1773
        }
 
1774
        if (!sha1_seen) {
 
1775
            if (any)
 
1776
                tty_printf (", ");
 
1777
            tty_printf ("%s", gcry_md_algo_name (DIGEST_ALGO_SHA1));
 
1778
        }
 
1779
        tty_printf ("\n     ");
 
1780
        tty_printf (_("Compression: "));
 
1781
        for(i=any=0; prefs[i].type; i++ ) {
 
1782
            if( prefs[i].type == PREFTYPE_ZIP ) {
 
1783
                const char *s=compress_algo_to_string(prefs[i].value);
 
1784
                
 
1785
                if (any)
 
1786
                    tty_printf (", ");
 
1787
                any = 1;
 
1788
                /* We don't want to display strings for experimental algos */
 
1789
                if (s && prefs[i].value < 100 )
 
1790
                    tty_printf ("%s", s );
 
1791
                else
 
1792
                    tty_printf ("[%d]", prefs[i].value);
 
1793
                if (prefs[i].value == 0 )
 
1794
                    uncomp_seen = 1;
 
1795
            }
 
1796
        }
 
1797
        if (!uncomp_seen) {
 
1798
            if (any)
 
1799
                tty_printf (", ");
 
1800
            else {
 
1801
              tty_printf ("%s",compress_algo_to_string(1));
 
1802
              tty_printf (", ");
 
1803
            }
 
1804
            tty_printf ("%s",compress_algo_to_string(0));
 
1805
        }
 
1806
        if(uid->mdc_feature || !uid->ks_modify)
 
1807
          {
 
1808
            tty_printf ("\n     ");
 
1809
            tty_printf (_("Features: "));
 
1810
            any=0;
 
1811
            if(uid->mdc_feature)
 
1812
              {
 
1813
                tty_printf ("MDC");
 
1814
                any=1;
 
1815
              }
 
1816
            if(!uid->ks_modify)
 
1817
              {
 
1818
                if(any)
 
1819
                  tty_printf (", ");
 
1820
                tty_printf (_("Keyserver no-modify"));
 
1821
              }
 
1822
          }
 
1823
        tty_printf("\n");
 
1824
    }
 
1825
    else {
 
1826
        tty_printf("    ");
 
1827
        for(i=0; prefs[i].type; i++ ) {
 
1828
            tty_printf( " %c%d", prefs[i].type == PREFTYPE_SYM   ? 'S' :
 
1829
                                 prefs[i].type == PREFTYPE_HASH  ? 'H' :
 
1830
                                 prefs[i].type == PREFTYPE_ZIP ? 'Z':'?',
 
1831
                                 prefs[i].value);
 
1832
        }
 
1833
        if (uid->mdc_feature)
 
1834
            tty_printf (" [mdc]");
 
1835
        if (!uid->ks_modify)
 
1836
            tty_printf (" [no-ks-modify]");
 
1837
        tty_printf("\n");
 
1838
    }
 
1839
}
 
1840
 
 
1841
 
 
1842
/* This is the version of show_key_with_all_names used when
 
1843
   opt.with_colons is used.  It prints all available data in a easy to
 
1844
   parse format and does not translate utf8 */
 
1845
static void
 
1846
show_key_with_all_names_colon (KBNODE keyblock)
 
1847
{
 
1848
  KBNODE node;
 
1849
  int i, j, ulti_hack=0;
 
1850
  byte pk_version=0;
 
1851
  PKT_public_key *primary=NULL;
 
1852
 
 
1853
  /* the keys */
 
1854
  for ( node = keyblock; node; node = node->next )
 
1855
    {
 
1856
      if (node->pkt->pkttype == PKT_PUBLIC_KEY
 
1857
          || (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) )
 
1858
        {
 
1859
          PKT_public_key *pk = node->pkt->pkt.public_key;
 
1860
          u32 keyid[2];
 
1861
 
 
1862
          if (node->pkt->pkttype == PKT_PUBLIC_KEY)
 
1863
            {
 
1864
              pk_version = pk->version;
 
1865
              primary=pk;
 
1866
            }
 
1867
 
 
1868
          keyid_from_pk (pk, keyid);
 
1869
 
 
1870
          fputs (node->pkt->pkttype == PKT_PUBLIC_KEY?"pub:":"sub:", stdout);
 
1871
          if (!pk->is_valid)
 
1872
            putchar ('i');
 
1873
          else if (pk->is_revoked)
 
1874
            putchar ('r');
 
1875
          else if (pk->has_expired)
 
1876
            putchar ('e');
 
1877
          else if (!(opt.fast_list_mode || opt.no_expensive_trust_checks ))
 
1878
            {
 
1879
              int trust = get_validity_info (pk, NULL);
 
1880
              if(trust=='u')
 
1881
                ulti_hack=1;
 
1882
              putchar (trust);
 
1883
            }
 
1884
 
 
1885
          printf (":%u:%d:%08lX%08lX:%lu:%lu:",
 
1886
                  nbits_from_pk (pk),
 
1887
                  pk->pubkey_algo,
 
1888
                  (ulong)keyid[0], (ulong)keyid[1],
 
1889
                  (ulong)pk->timestamp,
 
1890
                  (ulong)pk->expiredate );
 
1891
          if (pk->local_id)
 
1892
            printf ("%lu", pk->local_id);
 
1893
          putchar (':');
 
1894
          if (node->pkt->pkttype==PKT_PUBLIC_KEY
 
1895
              && !(opt.fast_list_mode || opt.no_expensive_trust_checks ))
 
1896
            putchar(get_ownertrust_info (pk));
 
1897
          putchar(':');
 
1898
          putchar('\n');
 
1899
          
 
1900
          print_fingerprint (pk, NULL, 0);
 
1901
 
 
1902
          /* print the revoker record */
 
1903
          if( !pk->revkey && pk->numrevkeys )
 
1904
            BUG();
 
1905
          else
 
1906
            {
 
1907
              for (i=0; i < pk->numrevkeys; i++)
 
1908
                {
 
1909
                  byte *p;
 
1910
 
 
1911
                  printf ("rvk:::%d::::::", pk->revkey[i].algid);
 
1912
                  p = pk->revkey[i].fpr;
 
1913
                  for (j=0; j < 20; j++, p++ )
 
1914
                    printf ("%02X", *p);
 
1915
                  printf (":%02x%s:\n", pk->revkey[i].class,
 
1916
                          (pk->revkey[i].class&0x40)?"s":"");
 
1917
                }
 
1918
            }
 
1919
        }
 
1920
    }
 
1921
  
 
1922
    /* the user ids */
 
1923
    i = 0;
 
1924
    for (node = keyblock; node; node = node->next) 
 
1925
      {
 
1926
        if ( node->pkt->pkttype == PKT_USER_ID )
 
1927
          {
 
1928
            PKT_user_id *uid = node->pkt->pkt.user_id;
 
1929
 
 
1930
            ++i;
 
1931
 
 
1932
            if(uid->attrib_data)
 
1933
              printf("uat:");
 
1934
            else
 
1935
              printf("uid:");
 
1936
 
 
1937
            if ( uid->is_revoked )
 
1938
              printf("r::::::::");
 
1939
            else if ( uid->is_expired )
 
1940
              printf("e::::::::");
 
1941
            else if ( opt.fast_list_mode || opt.no_expensive_trust_checks )
 
1942
              printf("::::::::");
 
1943
            else
 
1944
              {
 
1945
                int uid_validity;
 
1946
 
 
1947
                if( primary && !ulti_hack )
 
1948
                  uid_validity = get_validity_info( primary, uid );
 
1949
                else
 
1950
                  uid_validity = 'u';
 
1951
                printf("%c::::::::",uid_validity);
 
1952
              }
 
1953
 
 
1954
            if(uid->attrib_data)
 
1955
              printf ("%u %lu",uid->numattribs,uid->attrib_len);
 
1956
            else
 
1957
              print_string (stdout, uid->name, uid->len, ':');
 
1958
 
 
1959
            putchar (':');
 
1960
            /* signature class */
 
1961
            putchar (':');
 
1962
            /* capabilities */
 
1963
            putchar (':');
 
1964
            /* preferences */
 
1965
            if (pk_version>3 || uid->selfsigversion>3)
 
1966
              {
 
1967
                const prefitem_t *prefs = uid->prefs;
 
1968
                
 
1969
                for (j=0; prefs && prefs[j].type; j++)
 
1970
                  {
 
1971
                    if (j)
 
1972
                      putchar (' ');
 
1973
                    printf ("%c%d", prefs[j].type == PREFTYPE_SYM   ? 'S' :
 
1974
                            prefs[j].type == PREFTYPE_HASH  ? 'H' :
 
1975
                            prefs[j].type == PREFTYPE_ZIP ? 'Z':'?',
 
1976
                            prefs[j].value);
 
1977
                  } 
 
1978
                if (uid->mdc_feature)
 
1979
                  printf (",mdc");
 
1980
                if (!uid->ks_modify)
 
1981
                  printf (",no-ks-modify");
 
1982
              } 
 
1983
            putchar (':');
 
1984
            /* flags */
 
1985
            printf ("%d,", i);
 
1986
            if (uid->is_primary)
 
1987
              putchar ('p');
 
1988
            if (uid->is_revoked)
 
1989
              putchar ('r');
 
1990
            if (uid->is_expired)
 
1991
              putchar ('e');
 
1992
            if ((node->flag & NODFLG_SELUID))
 
1993
              putchar ('s');
 
1994
            if ((node->flag & NODFLG_MARK_A))
 
1995
              putchar ('m');
 
1996
            putchar (':');
 
1997
            putchar('\n');
 
1998
          }
 
1999
      }
 
2000
}
 
2001
 
 
2002
 
 
2003
/****************
 
2004
 * Display the key a the user ids, if only_marked is true, do only
 
2005
 * so for user ids with mark A flag set and dont display the index number
 
2006
 */
 
2007
static void
 
2008
show_key_with_all_names( KBNODE keyblock, int only_marked, int with_revoker,
 
2009
                         int with_fpr, int with_subkeys, int with_prefs )
 
2010
{
 
2011
    KBNODE node;
 
2012
    int i, rc;
 
2013
    int do_warn = 0;
 
2014
    byte pk_version=0;
 
2015
    PKT_public_key *primary=NULL;
 
2016
 
 
2017
    if (opt.with_colons)
 
2018
      {
 
2019
        show_key_with_all_names_colon (keyblock);
 
2020
        return;
 
2021
      }
 
2022
 
 
2023
    /* the keys */
 
2024
    for( node = keyblock; node; node = node->next ) {
 
2025
        if( node->pkt->pkttype == PKT_PUBLIC_KEY
 
2026
            || (with_subkeys && node->pkt->pkttype == PKT_PUBLIC_SUBKEY) ) {
 
2027
            PKT_public_key *pk = node->pkt->pkt.public_key;
 
2028
            const char *otrust="err",*trust="err";
 
2029
 
 
2030
            if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
 
2031
                /* do it here, so that debug messages don't clutter the
 
2032
                 * output */
 
2033
                static int did_warn = 0;
 
2034
 
 
2035
                trust = get_validity_string (pk, NULL);
 
2036
                otrust = get_ownertrust_string (pk);
 
2037
 
 
2038
                /* Show a warning once */
 
2039
                if (!did_warn
 
2040
                    && (get_validity (pk, NULL) & TRUST_FLAG_PENDING_CHECK)) {
 
2041
                    did_warn = 1;
 
2042
                    do_warn = 1;
 
2043
                }
 
2044
 
 
2045
                pk_version = pk->version;
 
2046
                primary = pk;
 
2047
            }
 
2048
 
 
2049
            if(with_revoker) {
 
2050
                if( !pk->revkey && pk->numrevkeys )
 
2051
                    BUG();
 
2052
                else
 
2053
                    for(i=0;i<pk->numrevkeys;i++) {
 
2054
                        u32 r_keyid[2];
 
2055
                        char *user;
 
2056
                        const char *algo=
 
2057
                                  gcry_pk_algo_name (pk->revkey[i].algid);
 
2058
 
 
2059
                        keyid_from_fingerprint(pk->revkey[i].fpr,
 
2060
                                               MAX_FINGERPRINT_LEN,r_keyid);
 
2061
                        
 
2062
                        user=get_user_id_string (r_keyid);
 
2063
                        tty_printf (_("This key may be revoked by %s key "),
 
2064
                                    algo?algo:"?");
 
2065
                        tty_print_utf8_string (user, strlen (user));
 
2066
                        if ((pk->revkey[i].class&0x40))
 
2067
                          tty_printf (_(" (sensitive)"));
 
2068
                        tty_printf ("\n");
 
2069
                        xfree (user);
 
2070
                      }
 
2071
            }
 
2072
 
 
2073
            keyid_from_pk(pk,NULL);
 
2074
            tty_printf("%s%c %4u%c/",
 
2075
                       node->pkt->pkttype == PKT_PUBLIC_KEY? "pub":"sub",
 
2076
                       (node->flag & NODFLG_SELKEY)? '*':' ',
 
2077
                       nbits_from_pk( pk ),
 
2078
                       pubkey_letter( pk->pubkey_algo ));
 
2079
 
 
2080
            if(opt.list_options&LIST_SHOW_LONG_KEYID)
 
2081
              tty_printf("%08lX",(ulong)pk->keyid[0]);
 
2082
 
 
2083
            tty_printf("%08lX  ",(ulong)pk->keyid[1]);
 
2084
            tty_printf(_("created: %s expires: %s"),
 
2085
                       datestr_from_pk(pk),
 
2086
                       expirestr_from_pk(pk) );
 
2087
            tty_printf("\n");
 
2088
 
 
2089
            if( node->pkt->pkttype == PKT_PUBLIC_KEY )
 
2090
              {
 
2091
                tty_printf("                     ");
 
2092
                if(opt.list_options&LIST_SHOW_LONG_KEYID)
 
2093
                  tty_printf("        ");
 
2094
                tty_printf(_("trust: %-13s"), otrust);
 
2095
                tty_printf(_("validity: %s"), trust );
 
2096
                tty_printf("\n");
 
2097
                if( node->pkt->pkttype == PKT_PUBLIC_KEY
 
2098
                    && (get_ownertrust (pk)&TRUST_FLAG_DISABLED))
 
2099
                  {
 
2100
                    tty_printf("*** ");
 
2101
                    tty_printf(_("This key has been disabled"));
 
2102
                    tty_printf("\n");
 
2103
                  }
 
2104
              }
 
2105
 
 
2106
            if( node->pkt->pkttype == PKT_PUBLIC_KEY && with_fpr )
 
2107
              {
 
2108
                print_fingerprint ( pk, NULL, 2 );
 
2109
                tty_printf("\n");
 
2110
              }
 
2111
        }
 
2112
        else if( node->pkt->pkttype == PKT_SECRET_KEY
 
2113
            || (with_subkeys && node->pkt->pkttype == PKT_SECRET_SUBKEY) ) {
 
2114
            PKT_secret_key *sk = node->pkt->pkt.secret_key;
 
2115
            tty_printf(_("%s%c %4u%c/%08lX  created: %s expires: %s"),
 
2116
                          node->pkt->pkttype == PKT_SECRET_KEY? "sec":"ssb",
 
2117
                          (node->flag & NODFLG_SELKEY)? '*':' ',
 
2118
                          nbits_from_sk( sk ),
 
2119
                          pubkey_letter( sk->pubkey_algo ),
 
2120
                          (ulong)keyid_from_sk(sk,NULL),
 
2121
                          datestr_from_sk(sk),
 
2122
                          expirestr_from_sk(sk) );
 
2123
            tty_printf("\n");
 
2124
            if (sk->is_protected && sk->protect.s2k.mode == 1002)
 
2125
              {
 
2126
                tty_printf("                     ");
 
2127
                tty_printf(_("card-no: ")); 
 
2128
                if (sk->protect.ivlen == 16
 
2129
                    && !memcmp (sk->protect.iv, "\xD2\x76\x00\x01\x24\x01", 6))
 
2130
                  { /* This is an OpenPGP card. */
 
2131
                    for (i=8; i < 14; i++)
 
2132
                      {
 
2133
                        if (i == 10)
 
2134
                          tty_printf (" ");
 
2135
                        tty_printf ("%02X", sk->protect.iv[i]);
 
2136
                      }
 
2137
                  }
 
2138
                else
 
2139
                  { /* Something is wrong: Print all. */
 
2140
                    for (i=0; i < sk->protect.ivlen; i++)
 
2141
                      tty_printf ("%02X", sk->protect.iv[i]);
 
2142
                  }
 
2143
                tty_printf ("\n");
 
2144
              }
 
2145
        }
 
2146
        else if( with_subkeys && node->pkt->pkttype == PKT_SIGNATURE
 
2147
                 && node->pkt->pkt.signature->sig_class == 0x28       ) {
 
2148
            PKT_signature *sig = node->pkt->pkt.signature;
 
2149
 
 
2150
            rc = check_key_signature( keyblock, node, NULL );
 
2151
            if( !rc )
 
2152
                tty_printf( _("rev! subkey has been revoked: %s\n"),
 
2153
                            datestr_from_sig( sig ) );
 
2154
            else if( gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE )
 
2155
                tty_printf( _("rev- faked revocation found\n") );
 
2156
            else if( rc )
 
2157
                tty_printf( _("rev? problem checking revocation: %s\n"),
 
2158
                                                         gpg_strerror (rc) );
 
2159
        }
 
2160
    }
 
2161
    /* the user ids */
 
2162
    i = 0;
 
2163
    for( node = keyblock; node; node = node->next ) {
 
2164
        if( node->pkt->pkttype == PKT_USER_ID ) {
 
2165
            PKT_user_id *uid = node->pkt->pkt.user_id;
 
2166
            ++i;
 
2167
            if( !only_marked || (only_marked && (node->flag & NODFLG_MARK_A))){
 
2168
                if(opt.list_options&LIST_SHOW_VALIDITY && primary)
 
2169
                  tty_printf("[%8.8s] ",
 
2170
                             trust_value_to_string(get_validity(primary,uid)));
 
2171
                if( only_marked )
 
2172
                   tty_printf("     ");
 
2173
                else if( node->flag & NODFLG_SELUID )
 
2174
                   tty_printf("(%d)* ", i);
 
2175
                else if( uid->is_primary )
 
2176
                   tty_printf("(%d). ", i);
 
2177
                else
 
2178
                   tty_printf("(%d)  ", i);
 
2179
                if ( uid->is_revoked )
 
2180
                    tty_printf (_("[revoked] "));
 
2181
                if ( uid->is_expired )
 
2182
                    tty_printf (_("[expired] "));
 
2183
                tty_print_utf8_string( uid->name, uid->len );
 
2184
                tty_printf("\n");
 
2185
                if( with_prefs )
 
2186
                  {
 
2187
                    if(pk_version>3 || uid->selfsigversion>3)
 
2188
                      show_prefs (uid, with_prefs == 2);
 
2189
                    else
 
2190
                      tty_printf(_("There are no preferences on a "
 
2191
                                   "PGP 2.x-style user ID.\n"));
 
2192
                  }
 
2193
            }
 
2194
        }
 
2195
    }
 
2196
 
 
2197
    if (do_warn)
 
2198
        tty_printf (_("Please note that the shown key validity "
 
2199
                      "is not necessarily correct\n"
 
2200
                      "unless you restart the program.\n")); 
 
2201
 
 
2202
}
 
2203
 
 
2204
 
 
2205
/* Display basic key information.  This fucntion is suitable to show
 
2206
   information on the key without any dependencies on the trustdb or
 
2207
   any other internal GnuPG stuff.  KEYBLOCK may either be a public or
 
2208
   a secret key.*/
 
2209
void
 
2210
show_basic_key_info ( KBNODE keyblock )
 
2211
{
 
2212
  KBNODE node;
 
2213
  int i;
 
2214
 
 
2215
  /* The primary key */
 
2216
  for (node = keyblock; node; node = node->next)
 
2217
    {
 
2218
      if (node->pkt->pkttype == PKT_PUBLIC_KEY)
 
2219
        {
 
2220
          PKT_public_key *pk = node->pkt->pkt.public_key;
 
2221
          
 
2222
          /* Note, we use the same format string as in other show
 
2223
             functions to make the translation job easier. */
 
2224
          tty_printf (_("%s%c %4u%c/%08lX  created: %s expires: %s"),
 
2225
                      node->pkt->pkttype == PKT_PUBLIC_KEY? "pub":"sub",
 
2226
                      ' ',
 
2227
                      nbits_from_pk( pk ),
 
2228
                      pubkey_letter( pk->pubkey_algo ),
 
2229
                      (ulong)keyid_from_pk(pk,NULL),
 
2230
                      datestr_from_pk(pk),
 
2231
                      expirestr_from_pk(pk) );
 
2232
          tty_printf("\n");
 
2233
          print_fingerprint ( pk, NULL, 3 );
 
2234
          tty_printf("\n");
 
2235
        }
 
2236
      else if (node->pkt->pkttype == PKT_SECRET_KEY)
 
2237
        {
 
2238
          PKT_secret_key *sk = node->pkt->pkt.secret_key;
 
2239
          tty_printf(_("%s%c %4u%c/%08lX  created: %s expires: %s"),
 
2240
                     node->pkt->pkttype == PKT_SECRET_KEY? "sec":"ssb",
 
2241
                     ' ',
 
2242
                     nbits_from_sk( sk ),
 
2243
                     pubkey_letter( sk->pubkey_algo ),
 
2244
                     (ulong)keyid_from_sk(sk,NULL),
 
2245
                     datestr_from_sk(sk),
 
2246
                     expirestr_from_sk(sk) );
 
2247
          tty_printf("\n");
 
2248
          print_fingerprint (NULL, sk, 3 );
 
2249
          tty_printf("\n");
 
2250
        }
 
2251
    }
 
2252
 
 
2253
  /* The user IDs. */
 
2254
  for (i=0, node = keyblock; node; node = node->next)
 
2255
    {
 
2256
      if (node->pkt->pkttype == PKT_USER_ID)
 
2257
        {
 
2258
          PKT_user_id *uid = node->pkt->pkt.user_id;
 
2259
          ++i;
 
2260
     
 
2261
          tty_printf ("     ");
 
2262
          if (uid->is_revoked)
 
2263
            tty_printf ("[revoked] ");
 
2264
          if ( uid->is_expired )
 
2265
            tty_printf ("[expired] ");
 
2266
          tty_print_utf8_string (uid->name, uid->len);
 
2267
          tty_printf ("\n");
 
2268
        }
 
2269
    }
 
2270
}
 
2271
 
 
2272
static void
 
2273
show_key_and_fingerprint( KBNODE keyblock )
 
2274
{
 
2275
    KBNODE node;
 
2276
    PKT_public_key *pk = NULL;
 
2277
 
 
2278
    for( node = keyblock; node; node = node->next ) {
 
2279
        if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
 
2280
            pk = node->pkt->pkt.public_key;
 
2281
            tty_printf("pub   %4u%c/%08lX %s ",
 
2282
                          nbits_from_pk( pk ),
 
2283
                          pubkey_letter( pk->pubkey_algo ),
 
2284
                          (ulong)keyid_from_pk(pk,NULL),
 
2285
                          datestr_from_pk(pk) );
 
2286
        }
 
2287
        else if( node->pkt->pkttype == PKT_USER_ID ) {
 
2288
            PKT_user_id *uid = node->pkt->pkt.user_id;
 
2289
            tty_print_utf8_string( uid->name, uid->len );
 
2290
            break;
 
2291
        }
 
2292
    }
 
2293
    tty_printf("\n");
 
2294
    if( pk )
 
2295
        print_fingerprint( pk, NULL, 2 );
 
2296
}
 
2297
 
 
2298
 
 
2299
/* Show a warning if no uids on the key have the primary uid flag
 
2300
   set. */
 
2301
static void
 
2302
no_primary_warning(KBNODE keyblock, int uids)
 
2303
{
 
2304
  KBNODE node;
 
2305
  int select_all=1,have_uid=0,uid_count=0;
 
2306
 
 
2307
  if(uids)
 
2308
    select_all=!count_selected_uids(keyblock);
 
2309
 
 
2310
  /* TODO: if we ever start behaving differently with a primary or
 
2311
     non-primary attribute ID, we will need to check for attributes
 
2312
     here as well. */
 
2313
 
 
2314
  for(node=keyblock; node; node = node->next)
 
2315
    {
 
2316
      if(node->pkt->pkttype==PKT_USER_ID
 
2317
         && node->pkt->pkt.user_id->attrib_data==NULL)
 
2318
        {
 
2319
          uid_count++;
 
2320
 
 
2321
          if((select_all || (node->flag & NODFLG_SELUID))
 
2322
             && node->pkt->pkt.user_id->is_primary==2)
 
2323
            have_uid|=2;
 
2324
          else
 
2325
            have_uid|=1;
 
2326
        }
 
2327
    }
 
2328
 
 
2329
  if(uid_count>1 && have_uid&1 && !(have_uid&2))
 
2330
    log_info(_("WARNING: no user ID has been marked as primary.  This command "
 
2331
               "may\n              cause a different user ID to become the assumed primary.\n"));
 
2332
}
 
2333
 
 
2334
/****************
 
2335
 * Ask for a new user id, do the selfsignature and put it into
 
2336
 * both keyblocks.
 
2337
 * Return true if there is a new user id
 
2338
 */
 
2339
static int
 
2340
menu_adduid( KBNODE pub_keyblock, KBNODE sec_keyblock, int photo)
 
2341
{
 
2342
    PKT_user_id *uid;
 
2343
    PKT_public_key *pk=NULL;
 
2344
    PKT_secret_key *sk=NULL;
 
2345
    PKT_signature *sig=NULL;
 
2346
    PACKET *pkt;
 
2347
    KBNODE node;
 
2348
    KBNODE pub_where=NULL, sec_where=NULL;
 
2349
    int rc;
 
2350
 
 
2351
    for( node = pub_keyblock; node; pub_where = node, node = node->next ) {
 
2352
        if( node->pkt->pkttype == PKT_PUBLIC_KEY )
 
2353
            pk = node->pkt->pkt.public_key;
 
2354
        else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
 
2355
            break;
 
2356
    }
 
2357
    if( !node ) /* no subkey */
 
2358
        pub_where = NULL;
 
2359
    for( node = sec_keyblock; node; sec_where = node, node = node->next ) {
 
2360
        if( node->pkt->pkttype == PKT_SECRET_KEY )
 
2361
            sk = copy_secret_key( NULL, node->pkt->pkt.secret_key);
 
2362
        else if( node->pkt->pkttype == PKT_SECRET_SUBKEY )
 
2363
            break;
 
2364
    }
 
2365
    if( !node ) /* no subkey */
 
2366
        sec_where = NULL;
 
2367
    assert(pk && sk);
 
2368
 
 
2369
    if(photo) {
 
2370
      int hasattrib=0;
 
2371
 
 
2372
      for( node = pub_keyblock; node; node = node->next )
 
2373
        if( node->pkt->pkttype == PKT_USER_ID &&
 
2374
            node->pkt->pkt.user_id->attrib_data!=NULL)
 
2375
          {
 
2376
            hasattrib=1;
 
2377
            break;
 
2378
          }
 
2379
 
 
2380
      /* It is legal but bad for compatibility to add a photo ID to a
 
2381
         v3 key as it means that PGP2 will not be able to use that key
 
2382
         anymore.  Also, PGP may not expect a photo on a v3 key.
 
2383
         Don't bother to ask this if the key already has a photo - any
 
2384
         damage has already been done at that point. -dms */
 
2385
      if(pk->version==3 && !hasattrib)
 
2386
        {
 
2387
          if(opt.expert)
 
2388
            {
 
2389
              tty_printf(_("WARNING: This is a PGP2-style key.  "
 
2390
                           "Adding a photo ID may cause some versions\n"
 
2391
                           "         of PGP to reject this key.\n"));
 
2392
 
 
2393
              if(!cpr_get_answer_is_yes("keyedit.v3_photo.okay",
 
2394
                                        _("Are you sure you still want "
 
2395
                                          "to add it? (y/N) ")))
 
2396
                return 0;
 
2397
            }
 
2398
          else
 
2399
            {
 
2400
              tty_printf(_("You may not add a photo ID to "
 
2401
                           "a PGP2-style key.\n"));
 
2402
              return 0;
 
2403
            }
 
2404
        }
 
2405
 
 
2406
      uid = generate_photo_id(pk);
 
2407
    } else
 
2408
      uid = generate_user_id();
 
2409
    if( !uid )
 
2410
        return 0;
 
2411
 
 
2412
    rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0, 0, 0, 0,
 
2413
                             keygen_add_std_prefs, pk );
 
2414
    free_secret_key( sk );
 
2415
    if( rc ) {
 
2416
        log_error("signing failed: %s\n", gpg_strerror (rc) );
 
2417
        free_user_id(uid);
 
2418
        return 0;
 
2419
    }
 
2420
 
 
2421
    /* insert/append to secret keyblock */
 
2422
    pkt = xcalloc (1, sizeof *pkt );
 
2423
    pkt->pkttype = PKT_USER_ID;
 
2424
    pkt->pkt.user_id = scopy_user_id(uid);
 
2425
    node = new_kbnode(pkt);
 
2426
    if( sec_where )
 
2427
        insert_kbnode( sec_where, node, 0 );
 
2428
    else
 
2429
        add_kbnode( sec_keyblock, node );
 
2430
    pkt = xcalloc (1, sizeof *pkt );
 
2431
    pkt->pkttype = PKT_SIGNATURE;
 
2432
    pkt->pkt.signature = copy_signature(NULL, sig);
 
2433
    if( sec_where )
 
2434
        insert_kbnode( node, new_kbnode(pkt), 0 );
 
2435
    else
 
2436
        add_kbnode( sec_keyblock, new_kbnode(pkt) );
 
2437
    /* insert/append to public keyblock */
 
2438
    pkt = xcalloc (1, sizeof *pkt );
 
2439
    pkt->pkttype = PKT_USER_ID;
 
2440
    pkt->pkt.user_id = uid;
 
2441
    node = new_kbnode(pkt);
 
2442
    if( pub_where )
 
2443
        insert_kbnode( pub_where, node, 0 );
 
2444
    else
 
2445
        add_kbnode( pub_keyblock, node );
 
2446
    pkt = xcalloc (1, sizeof *pkt );
 
2447
    pkt->pkttype = PKT_SIGNATURE;
 
2448
    pkt->pkt.signature = copy_signature(NULL, sig);
 
2449
    if( pub_where )
 
2450
        insert_kbnode( node, new_kbnode(pkt), 0 );
 
2451
    else
 
2452
        add_kbnode( pub_keyblock, new_kbnode(pkt) );
 
2453
    return 1;
 
2454
}
 
2455
 
 
2456
 
 
2457
/****************
 
2458
 * Remove all selceted userids from the keyrings
 
2459
 */
 
2460
static void
 
2461
menu_deluid( KBNODE pub_keyblock, KBNODE sec_keyblock )
 
2462
{
 
2463
    KBNODE node;
 
2464
    int selected=0;
 
2465
 
 
2466
    for( node = pub_keyblock; node; node = node->next ) {
 
2467
        if( node->pkt->pkttype == PKT_USER_ID ) {
 
2468
            selected = node->flag & NODFLG_SELUID;
 
2469
            if( selected ) {
 
2470
                /* Only cause a trust update if we delete a
 
2471
                   non-revoked user id */
 
2472
                if(!node->pkt->pkt.user_id->is_revoked)
 
2473
                  update_trust=1;
 
2474
                delete_kbnode( node );
 
2475
                if( sec_keyblock ) {
 
2476
                    KBNODE snode;
 
2477
                    int s_selected = 0;
 
2478
                    PKT_user_id *uid = node->pkt->pkt.user_id;
 
2479
                    for( snode = sec_keyblock; snode; snode = snode->next ) {
 
2480
                        if( snode->pkt->pkttype == PKT_USER_ID ) {
 
2481
                            PKT_user_id *suid = snode->pkt->pkt.user_id;
 
2482
 
 
2483
                            s_selected =
 
2484
                                (uid->len == suid->len
 
2485
                                 && !memcmp( uid->name, suid->name, uid->len));
 
2486
                            if( s_selected )
 
2487
                                delete_kbnode( snode );
 
2488
                        }
 
2489
                        else if( s_selected
 
2490
                                 && snode->pkt->pkttype == PKT_SIGNATURE )
 
2491
                            delete_kbnode( snode );
 
2492
                        else if( snode->pkt->pkttype == PKT_SECRET_SUBKEY )
 
2493
                            s_selected = 0;
 
2494
                    }
 
2495
                }
 
2496
            }
 
2497
        }
 
2498
        else if( selected && node->pkt->pkttype == PKT_SIGNATURE )
 
2499
            delete_kbnode( node );
 
2500
        else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
 
2501
            selected = 0;
 
2502
    }
 
2503
    commit_kbnode( &pub_keyblock );
 
2504
    if( sec_keyblock )
 
2505
        commit_kbnode( &sec_keyblock );
 
2506
}
 
2507
 
 
2508
 
 
2509
static int
 
2510
menu_delsig( KBNODE pub_keyblock )
 
2511
{
 
2512
    KBNODE node;
 
2513
    PKT_user_id *uid = NULL;
 
2514
    int changed=0;
 
2515
 
 
2516
    for( node = pub_keyblock; node; node = node->next ) {
 
2517
        if( node->pkt->pkttype == PKT_USER_ID ) {
 
2518
            uid = (node->flag & NODFLG_SELUID)? node->pkt->pkt.user_id : NULL;
 
2519
        }
 
2520
        else if( uid && node->pkt->pkttype == PKT_SIGNATURE ) {
 
2521
           int okay, valid, selfsig, inv_sig, no_key, other_err;
 
2522
 
 
2523
            tty_printf("uid  ");
 
2524
            tty_print_utf8_string( uid->name, uid->len );
 
2525
            tty_printf("\n");
 
2526
 
 
2527
           okay = inv_sig = no_key = other_err = 0;
 
2528
            valid = print_and_check_one_sig( pub_keyblock, node,
 
2529
                                            &inv_sig, &no_key, &other_err,
 
2530
                                            &selfsig, 1 );
 
2531
 
 
2532
           if( valid ) {
 
2533
               okay = cpr_get_answer_yes_no_quit(
 
2534
                   "keyedit.delsig.valid",
 
2535
                   _("Delete this good signature? (y/N/q)"));
 
2536
 
 
2537
               /* Only update trust if we delete a good signature.
 
2538
                  The other two cases do not affect trust. */
 
2539
               if(okay)
 
2540
                 update_trust=1;
 
2541
           }
 
2542
           else if( inv_sig || other_err )
 
2543
               okay = cpr_get_answer_yes_no_quit(
 
2544
                   "keyedit.delsig.invalid",
 
2545
                   _("Delete this invalid signature? (y/N/q)"));
 
2546
           else if( no_key )
 
2547
               okay = cpr_get_answer_yes_no_quit(
 
2548
                   "keyedit.delsig.unknown",
 
2549
                   _("Delete this unknown signature? (y/N/q)"));
 
2550
 
 
2551
            if( okay == -1 )
 
2552
                break;
 
2553
           if( okay && selfsig && !cpr_get_answer_is_yes(
 
2554
                               "keyedit.delsig.selfsig",
 
2555
                              _("Really delete this self-signature? (y/N)") ))
 
2556
                okay = 0;
 
2557
            if( okay ) {
 
2558
                delete_kbnode( node );
 
2559
                changed++;
 
2560
            }
 
2561
 
 
2562
        }
 
2563
        else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
 
2564
            uid = NULL;
 
2565
    }
 
2566
 
 
2567
    if( changed ) {
 
2568
        commit_kbnode( &pub_keyblock );
 
2569
        tty_printf( changed == 1? _("Deleted %d signature.\n")
 
2570
                                : _("Deleted %d signatures.\n"), changed );
 
2571
    }
 
2572
    else
 
2573
        tty_printf( _("Nothing deleted.\n") );
 
2574
 
 
2575
    return changed;
 
2576
}
 
2577
 
 
2578
 
 
2579
/****************
 
2580
 * Remove some of the secondary keys
 
2581
 */
 
2582
static void
 
2583
menu_delkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
 
2584
{
 
2585
    KBNODE node;
 
2586
    int selected=0;
 
2587
 
 
2588
    for( node = pub_keyblock; node; node = node->next ) {
 
2589
        if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
 
2590
            selected = node->flag & NODFLG_SELKEY;
 
2591
            if( selected ) {
 
2592
                delete_kbnode( node );
 
2593
                if( sec_keyblock ) {
 
2594
                    KBNODE snode;
 
2595
                    int s_selected = 0;
 
2596
                    u32 ki[2];
 
2597
 
 
2598
                    keyid_from_pk( node->pkt->pkt.public_key, ki );
 
2599
                    for( snode = sec_keyblock; snode; snode = snode->next ) {
 
2600
                        if( snode->pkt->pkttype == PKT_SECRET_SUBKEY ) {
 
2601
                            u32 ki2[2];
 
2602
 
 
2603
                            keyid_from_sk( snode->pkt->pkt.secret_key, ki2 );
 
2604
                            s_selected = (ki[0] == ki2[0] && ki[1] == ki2[1]);
 
2605
                            if( s_selected )
 
2606
                                delete_kbnode( snode );
 
2607
                        }
 
2608
                        else if( s_selected
 
2609
                                 && snode->pkt->pkttype == PKT_SIGNATURE )
 
2610
                            delete_kbnode( snode );
 
2611
                        else
 
2612
                            s_selected = 0;
 
2613
                    }
 
2614
                }
 
2615
            }
 
2616
        }
 
2617
        else if( selected && node->pkt->pkttype == PKT_SIGNATURE )
 
2618
            delete_kbnode( node );
 
2619
        else
 
2620
            selected = 0;
 
2621
    }
 
2622
    commit_kbnode( &pub_keyblock );
 
2623
    if( sec_keyblock )
 
2624
        commit_kbnode( &sec_keyblock );
 
2625
 
 
2626
    /* No need to set update_trust here since signing keys are no
 
2627
       longer used to certify other keys, so there is no change in
 
2628
       trust when revoking/removing them */
 
2629
}
 
2630
 
 
2631
 
 
2632
/****************
 
2633
 * Ask for a new revoker, do the selfsignature and put it into
 
2634
 * both keyblocks.
 
2635
 * Return true if there is a new revoker
 
2636
 */
 
2637
static int
 
2638
menu_addrevoker( KBNODE pub_keyblock, KBNODE sec_keyblock, int sensitive )
 
2639
{
 
2640
  PKT_public_key *pk=NULL,*revoker_pk=NULL;
 
2641
  PKT_secret_key *sk=NULL;
 
2642
  PKT_signature *sig=NULL;
 
2643
  PACKET *pkt;
 
2644
  struct revocation_key revkey;
 
2645
  size_t fprlen;
 
2646
  int rc;
 
2647
 
 
2648
  assert(pub_keyblock->pkt->pkttype==PKT_PUBLIC_KEY);
 
2649
  assert(sec_keyblock->pkt->pkttype==PKT_SECRET_KEY);
 
2650
 
 
2651
  pk=pub_keyblock->pkt->pkt.public_key;
 
2652
 
 
2653
  if(pk->numrevkeys==0 && pk->version==3)
 
2654
    {
 
2655
      /* It is legal but bad for compatibility to add a revoker to a
 
2656
         v3 key as it means that PGP2 will not be able to use that key
 
2657
         anymore.  Also, PGP may not expect a revoker on a v3 key.
 
2658
         Don't bother to ask this if the key already has a revoker -
 
2659
         any damage has already been done at that point. -dms */
 
2660
      if(opt.expert)
 
2661
        {
 
2662
          tty_printf(_("WARNING: This is a PGP 2.x-style key.  "
 
2663
                       "Adding a designated revoker may cause\n"
 
2664
                       "         some versions of PGP to reject this key.\n"));
 
2665
 
 
2666
          if(!cpr_get_answer_is_yes("keyedit.v3_revoker.okay",
 
2667
                                    _("Are you sure you still want "
 
2668
                                      "to add it? (y/N) ")))
 
2669
            return 0;
 
2670
        }
 
2671
      else
 
2672
        {
 
2673
          tty_printf(_("You may not add a designated revoker to "
 
2674
                       "a PGP 2.x-style key.\n"));
 
2675
          return 0;
 
2676
        }
 
2677
    }
 
2678
 
 
2679
  sk=copy_secret_key(NULL,sec_keyblock->pkt->pkt.secret_key);
 
2680
 
 
2681
  for(;;)
 
2682
    {
 
2683
      char *answer;
 
2684
      u32 keyid[2];
 
2685
      char *p;
 
2686
      size_t n;
 
2687
 
 
2688
      if(revoker_pk)
 
2689
        free_public_key(revoker_pk);
 
2690
 
 
2691
      revoker_pk=xcalloc (1,sizeof(*revoker_pk));
 
2692
 
 
2693
      tty_printf("\n");
 
2694
 
 
2695
      answer=cpr_get_utf8("keyedit.add_revoker",
 
2696
                          _("Enter the user ID of the designated revoker: "));
 
2697
      if(answer[0]=='\0' || answer[0]=='\004')
 
2698
        {
 
2699
          xfree(answer); answer = NULL;
 
2700
          goto fail;
 
2701
        }
 
2702
      
 
2703
      rc=get_pubkey_byname(revoker_pk,answer,NULL,NULL,1);
 
2704
 
 
2705
      if(rc)
 
2706
        {
 
2707
          log_error (_("key `%s' not found: %s\n"),answer,gpg_strerror (rc));
 
2708
          xfree (answer); answer = NULL;
 
2709
          continue;
 
2710
        }
 
2711
 
 
2712
      xfree (answer); answer = NULL;
 
2713
      
 
2714
 
 
2715
      fingerprint_from_pk(revoker_pk,revkey.fpr,&fprlen);
 
2716
      if(fprlen!=20)
 
2717
        {
 
2718
          log_error(_("cannot appoint a PGP 2.x style key as a "
 
2719
                      "designated revoker\n"));
 
2720
          continue;
 
2721
        }
 
2722
 
 
2723
      revkey.class=0x80;
 
2724
      if(sensitive)
 
2725
        revkey.class|=0x40;
 
2726
      revkey.algid=revoker_pk->pubkey_algo;
 
2727
 
 
2728
      if(cmp_public_keys(revoker_pk,pk)==0)
 
2729
        {
 
2730
          /* This actually causes no harm (after all, a key that
 
2731
             designates itself as a revoker is the same as a
 
2732
             regular key), but it's easy enough to check. */
 
2733
          log_error(_("you cannot appoint a key as its own "
 
2734
                      "designated revoker\n"));
 
2735
 
 
2736
          continue;
 
2737
        }
 
2738
 
 
2739
      keyid_from_pk(pk,NULL);
 
2740
 
 
2741
      /* Does this revkey already exist? */
 
2742
      if(!pk->revkey && pk->numrevkeys)
 
2743
        BUG();
 
2744
      else
 
2745
        {
 
2746
          int i;
 
2747
 
 
2748
          for(i=0;i<pk->numrevkeys;i++)
 
2749
            {
 
2750
              if(memcmp(&pk->revkey[i],&revkey,
 
2751
                        sizeof(struct revocation_key))==0)
 
2752
                {
 
2753
                  char buf[50];
 
2754
 
 
2755
                  log_error(_("this key has already been designated "
 
2756
                              "as a revoker\n"));
 
2757
 
 
2758
                  sprintf(buf,"%08lX%08lX",
 
2759
                          (ulong)pk->keyid[0],(ulong)pk->keyid[1]);
 
2760
                  write_status_text(STATUS_ALREADY_SIGNED,buf);
 
2761
 
 
2762
                  break;
 
2763
                }
 
2764
            }
 
2765
 
 
2766
          if(i<pk->numrevkeys)
 
2767
            continue;
 
2768
        }
 
2769
 
 
2770
      keyid_from_pk(revoker_pk,keyid);
 
2771
 
 
2772
      tty_printf("\npub   %4u%c/%08lX %s   ",
 
2773
                 nbits_from_pk( revoker_pk ),
 
2774
                 pubkey_letter( revoker_pk->pubkey_algo ),
 
2775
                 (ulong)keyid[1], datestr_from_pk(pk) );
 
2776
 
 
2777
      p = get_user_id( keyid, &n );
 
2778
      tty_print_utf8_string( p, n );
 
2779
      xfree (p);
 
2780
      tty_printf("\n");
 
2781
      print_fingerprint(revoker_pk,NULL,2);
 
2782
      tty_printf("\n");
 
2783
 
 
2784
      tty_printf(_("WARNING: appointing a key as a designated revoker "
 
2785
                   "cannot be undone!\n"));
 
2786
 
 
2787
      tty_printf("\n");
 
2788
 
 
2789
      if(!cpr_get_answer_is_yes("keyedit.add_revoker.okay",
 
2790
                                _("Are you sure you want to appoint this "
 
2791
                                  "key as a designated revoker? (y/N): ")))
 
2792
        continue;
 
2793
 
 
2794
      free_public_key(revoker_pk);
 
2795
      revoker_pk=NULL;
 
2796
      break;
 
2797
    }
 
2798
 
 
2799
  /* The 1F signature must be at least v4 to carry the revocation key
 
2800
     subpacket. */
 
2801
  rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x1F, 0, 4, 0, 0,
 
2802
                           keygen_add_revkey,&revkey );
 
2803
  if( rc )
 
2804
    {
 
2805
      log_error("signing failed: %s\n", gpg_strerror (rc) );
 
2806
      goto fail;
 
2807
    }
 
2808
 
 
2809
  free_secret_key(sk);
 
2810
  sk=NULL;
 
2811
 
 
2812
  /* insert into secret keyblock */
 
2813
  pkt = xcalloc (1, sizeof *pkt );
 
2814
  pkt->pkttype = PKT_SIGNATURE;
 
2815
  pkt->pkt.signature = copy_signature(NULL, sig);
 
2816
  insert_kbnode( sec_keyblock, new_kbnode(pkt), PKT_SIGNATURE );
 
2817
 
 
2818
  /* insert into public keyblock */
 
2819
  pkt = xcalloc (1, sizeof *pkt );
 
2820
  pkt->pkttype = PKT_SIGNATURE;
 
2821
  pkt->pkt.signature = sig;
 
2822
  insert_kbnode( pub_keyblock, new_kbnode(pkt), PKT_SIGNATURE );
 
2823
 
 
2824
  return 1;
 
2825
 
 
2826
 fail:
 
2827
  if(sk)
 
2828
    free_secret_key(sk);
 
2829
  if(sig)
 
2830
    free_seckey_enc(sig);
 
2831
  if(revoker_pk)
 
2832
    free_public_key(revoker_pk);
 
2833
 
 
2834
  return 0;
 
2835
}
 
2836
 
 
2837
 
 
2838
static int
 
2839
menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock )
 
2840
{
 
2841
    int n1, signumber, rc;
 
2842
    u32 expiredate;
 
2843
    int mainkey=0;
 
2844
    PKT_secret_key *sk;    /* copy of the main sk */
 
2845
    PKT_public_key *main_pk, *sub_pk;
 
2846
    PKT_user_id *uid;
 
2847
    KBNODE node;
 
2848
    u32 keyid[2];
 
2849
 
 
2850
    if( count_selected_keys( sec_keyblock ) ) {
 
2851
        tty_printf(_("Please remove selections from the secret keys.\n"));
 
2852
        return 0;
 
2853
    }
 
2854
 
 
2855
    n1 = count_selected_keys( pub_keyblock );
 
2856
    if( n1 > 1 ) {
 
2857
        tty_printf(_("Please select at most one secondary key.\n"));
 
2858
        return 0;
 
2859
    }
 
2860
    else if( n1 )
 
2861
        tty_printf(_("Changing expiration time for a secondary key.\n"));
 
2862
    else {
 
2863
        tty_printf(_("Changing expiration time for the primary key.\n"));
 
2864
        mainkey=1;
 
2865
    }
 
2866
 
 
2867
    no_primary_warning(pub_keyblock,0);
 
2868
 
 
2869
    expiredate = ask_expiredate();
 
2870
    node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
 
2871
    sk = copy_secret_key( NULL, node->pkt->pkt.secret_key);
 
2872
 
 
2873
    /* Now we can actually change the self signature(s) */
 
2874
    main_pk = sub_pk = NULL;
 
2875
    uid = NULL;
 
2876
    signumber = 0;
 
2877
    for( node=pub_keyblock; node; node = node->next ) {
 
2878
        if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
 
2879
            main_pk = node->pkt->pkt.public_key;
 
2880
            keyid_from_pk( main_pk, keyid );
 
2881
            main_pk->expiredate = expiredate;
 
2882
        }
 
2883
        else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
 
2884
                 && (node->flag & NODFLG_SELKEY ) ) {
 
2885
            sub_pk = node->pkt->pkt.public_key;
 
2886
            sub_pk->expiredate = expiredate;
 
2887
        }
 
2888
        else if( node->pkt->pkttype == PKT_USER_ID )
 
2889
            uid = node->pkt->pkt.user_id;
 
2890
        else if( main_pk && node->pkt->pkttype == PKT_SIGNATURE
 
2891
                 && ( mainkey || sub_pk ) ) {
 
2892
            PKT_signature *sig = node->pkt->pkt.signature;
 
2893
            if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
 
2894
                && (    (mainkey && uid
 
2895
                         && uid->created && (sig->sig_class&~3) == 0x10)
 
2896
                     || (!mainkey && sig->sig_class == 0x18)  ) ) {
 
2897
                /* this is a selfsignature which is to be replaced */
 
2898
                PKT_signature *newsig;
 
2899
                PACKET *newpkt;
 
2900
                KBNODE sn;
 
2901
                int signumber2 = 0;
 
2902
 
 
2903
                signumber++;
 
2904
 
 
2905
                if( (mainkey && main_pk->version < 4)
 
2906
                    || (!mainkey && sub_pk->version < 4 ) ) {
 
2907
                    log_info(_(
 
2908
                        "You can't change the expiration date of a v3 key\n"));
 
2909
                    free_secret_key( sk );
 
2910
                    return 0;
 
2911
                }
 
2912
 
 
2913
                /* find the corresponding secret self-signature */
 
2914
                for( sn=sec_keyblock; sn; sn = sn->next ) {
 
2915
                    if( sn->pkt->pkttype == PKT_SIGNATURE ) {
 
2916
                        PKT_signature *b = sn->pkt->pkt.signature;
 
2917
                        if( keyid[0] == b->keyid[0] && keyid[1] == b->keyid[1]
 
2918
                            && sig->sig_class == b->sig_class
 
2919
                            && ++signumber2 == signumber )
 
2920
                            break;
 
2921
                    }
 
2922
                }
 
2923
                if( !sn )
 
2924
                    log_info(_("No corresponding signature in secret ring\n"));
 
2925
 
 
2926
                if( mainkey )
 
2927
                  rc = update_keysig_packet(&newsig, sig, main_pk, uid, NULL,
 
2928
                                            sk, keygen_add_key_expire, main_pk);
 
2929
                else
 
2930
                  rc = update_keysig_packet(&newsig, sig, main_pk, NULL, sub_pk,
 
2931
                                            sk, keygen_add_key_expire, sub_pk );
 
2932
                if( rc ) {
 
2933
                    log_error("make_keysig_packet failed: %s\n",
 
2934
                                                    gpg_strerror (rc));
 
2935
                    free_secret_key( sk );
 
2936
                    return 0;
 
2937
                }
 
2938
                /* replace the packet */
 
2939
                newpkt = xcalloc (1, sizeof *newpkt );
 
2940
                newpkt->pkttype = PKT_SIGNATURE;
 
2941
                newpkt->pkt.signature = newsig;
 
2942
                free_packet( node->pkt );
 
2943
                xfree ( node->pkt );
 
2944
                node->pkt = newpkt;
 
2945
                if( sn ) {
 
2946
                    newpkt = xcalloc (1, sizeof *newpkt );
 
2947
                    newpkt->pkttype = PKT_SIGNATURE;
 
2948
                    newpkt->pkt.signature = copy_signature( NULL, newsig );
 
2949
                    free_packet( sn->pkt );
 
2950
                    xfree ( sn->pkt );
 
2951
                    sn->pkt = newpkt;
 
2952
                }
 
2953
                sub_pk = NULL;
 
2954
            }
 
2955
        }
 
2956
    }
 
2957
 
 
2958
    free_secret_key( sk );
 
2959
    update_trust=1;
 
2960
    return 1;
 
2961
}
 
2962
 
 
2963
static int
 
2964
change_primary_uid_cb ( PKT_signature *sig, void *opaque )
 
2965
{
 
2966
    byte buf[1];
 
2967
 
 
2968
    /* first clear all primary uid flags so that we are sure none are
 
2969
     * lingering around */
 
2970
    delete_sig_subpkt (sig->hashed,   SIGSUBPKT_PRIMARY_UID);
 
2971
    delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PRIMARY_UID);
 
2972
 
 
2973
    /* if opaque is set,we want to set the primary id */
 
2974
    if (opaque) { 
 
2975
        buf[0] = 1;
 
2976
        build_sig_subpkt (sig, SIGSUBPKT_PRIMARY_UID, buf, 1 );
 
2977
    }
 
2978
 
 
2979
    return 0;
 
2980
}
 
2981
 
 
2982
 
 
2983
/*
 
2984
 * Set the primary uid flag for the selected UID.  We will also reset
 
2985
 * all other primary uid flags.  For this to work with have to update
 
2986
 * all the signature timestamps.  If we would do this with the current
 
2987
 * time, we lose quite a lot of information, so we use a a kludge to
 
2988
 * do this: Just increment the timestamp by one second which is
 
2989
 * sufficient to updated a signature during import.
 
2990
 */
 
2991
static int
 
2992
menu_set_primary_uid ( KBNODE pub_keyblock, KBNODE sec_keyblock )
 
2993
{
 
2994
    PKT_secret_key *sk;    /* copy of the main sk */
 
2995
    PKT_public_key *main_pk;
 
2996
    PKT_user_id *uid;
 
2997
    KBNODE node;
 
2998
    u32 keyid[2];
 
2999
    int selected;
 
3000
    int attribute = 0;
 
3001
    int modified = 0;
 
3002
 
 
3003
    if ( count_selected_uids (pub_keyblock) != 1 ) {
 
3004
        tty_printf(_("Please select exactly one user ID.\n"));
 
3005
        return 0;
 
3006
    }
 
3007
 
 
3008
    node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
 
3009
    sk = copy_secret_key( NULL, node->pkt->pkt.secret_key);
 
3010
 
 
3011
    /* Now we can actually change the self signature(s) */
 
3012
    main_pk = NULL;
 
3013
    uid = NULL;
 
3014
    selected = 0;
 
3015
 
 
3016
    /* Is our selected uid an attribute packet? */
 
3017
    for ( node=pub_keyblock; node; node = node->next )
 
3018
      if (node->pkt->pkttype == PKT_USER_ID && node->flag & NODFLG_SELUID)
 
3019
        attribute = (node->pkt->pkt.user_id->attrib_data!=NULL);
 
3020
 
 
3021
    for ( node=pub_keyblock; node; node = node->next ) {
 
3022
        if ( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
 
3023
            break; /* ready */
 
3024
 
 
3025
        if ( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
 
3026
            main_pk = node->pkt->pkt.public_key;
 
3027
            keyid_from_pk( main_pk, keyid );
 
3028
        }
 
3029
        else if ( node->pkt->pkttype == PKT_USER_ID ) {
 
3030
            uid = node->pkt->pkt.user_id;
 
3031
            selected = node->flag & NODFLG_SELUID;
 
3032
        }
 
3033
        else if ( main_pk && uid && node->pkt->pkttype == PKT_SIGNATURE ) {
 
3034
            PKT_signature *sig = node->pkt->pkt.signature;
 
3035
            if ( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
 
3036
                && (uid && (sig->sig_class&~3) == 0x10)
 
3037
                && attribute == (uid->attrib_data!=NULL)) {
 
3038
              if(sig->version < 4) {
 
3039
                char *user=utf8_to_native(uid->name,strlen(uid->name),0);
 
3040
 
 
3041
                log_info(_("skipping v3 self-signature on user id \"%s\"\n"),
 
3042
                         user);
 
3043
                xfree (user);
 
3044
              }
 
3045
              else {
 
3046
                /* This is a selfsignature which is to be replaced.
 
3047
                   We can just ignore v3 signatures because they are
 
3048
                   not able to carry the primary ID flag.  We also
 
3049
                   ignore self-sigs on user IDs that are not of the
 
3050
                   same type that we are making primary.  That is, if
 
3051
                   we are making a user ID primary, we alter user IDs.
 
3052
                   If we are making an attribute packet primary, we
 
3053
                   alter attribute packets. */
 
3054
 
 
3055
                /* FIXME: We must make sure that we only have one
 
3056
                   self-signature per user ID here (not counting
 
3057
                   revocations) */
 
3058
                PKT_signature *newsig;
 
3059
                PACKET *newpkt;
 
3060
                const byte *p;
 
3061
                int action;
 
3062
 
 
3063
                /* see whether this signature has the primary UID flag */
 
3064
                p = parse_sig_subpkt (sig->hashed,
 
3065
                                      SIGSUBPKT_PRIMARY_UID, NULL );
 
3066
                if ( !p )
 
3067
                    p = parse_sig_subpkt (sig->unhashed,
 
3068
                                          SIGSUBPKT_PRIMARY_UID, NULL );
 
3069
                if ( p && *p ) /* yes */
 
3070
                    action = selected? 0 : -1;
 
3071
                else /* no */
 
3072
                    action = selected? 1 : 0;
 
3073
 
 
3074
                if (action) {
 
3075
                    int rc = update_keysig_packet (&newsig, sig,
 
3076
                                               main_pk, uid, NULL,
 
3077
                                               sk,
 
3078
                                               change_primary_uid_cb,
 
3079
                                               action > 0? "x":NULL );
 
3080
                    if( rc ) {
 
3081
                        log_error ("update_keysig_packet failed: %s\n",
 
3082
                                   gpg_strerror (rc));
 
3083
                        free_secret_key( sk );
 
3084
                        return 0;
 
3085
                    }
 
3086
                    /* replace the packet */
 
3087
                    newpkt = xcalloc (1, sizeof *newpkt );
 
3088
                    newpkt->pkttype = PKT_SIGNATURE;
 
3089
                    newpkt->pkt.signature = newsig;
 
3090
                    free_packet( node->pkt );
 
3091
                    xfree ( node->pkt );
 
3092
                    node->pkt = newpkt;
 
3093
                    modified = 1;
 
3094
                }
 
3095
              }
 
3096
            }
 
3097
        }
 
3098
    }
 
3099
 
 
3100
    free_secret_key( sk );
 
3101
    return modified;
 
3102
}
 
3103
 
 
3104
 
 
3105
/* 
 
3106
 * Set preferences to new values for the selected user IDs
 
3107
 */
 
3108
static int
 
3109
menu_set_preferences (KBNODE pub_keyblock, KBNODE sec_keyblock )
 
3110
{
 
3111
    PKT_secret_key *sk;    /* copy of the main sk */
 
3112
    PKT_public_key *main_pk;
 
3113
    PKT_user_id *uid;
 
3114
    KBNODE node;
 
3115
    u32 keyid[2];
 
3116
    int selected, select_all;
 
3117
    int modified = 0;
 
3118
 
 
3119
    no_primary_warning(pub_keyblock,1);
 
3120
 
 
3121
    select_all = !count_selected_uids (pub_keyblock);
 
3122
 
 
3123
    node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
 
3124
    sk = copy_secret_key( NULL, node->pkt->pkt.secret_key);
 
3125
 
 
3126
    /* Now we can actually change the self signature(s) */
 
3127
    main_pk = NULL;
 
3128
    uid = NULL;
 
3129
    selected = 0;
 
3130
    for ( node=pub_keyblock; node; node = node->next ) {
 
3131
        if ( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
 
3132
            break; /* ready */
 
3133
 
 
3134
        if ( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
 
3135
            main_pk = node->pkt->pkt.public_key;
 
3136
            keyid_from_pk( main_pk, keyid );
 
3137
        }
 
3138
        else if ( node->pkt->pkttype == PKT_USER_ID ) {
 
3139
            uid = node->pkt->pkt.user_id;
 
3140
            selected = select_all || (node->flag & NODFLG_SELUID);
 
3141
        }
 
3142
        else if ( main_pk && uid && selected
 
3143
                  && node->pkt->pkttype == PKT_SIGNATURE ) {
 
3144
            PKT_signature *sig = node->pkt->pkt.signature;
 
3145
            if ( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
 
3146
                 && (uid && (sig->sig_class&~3) == 0x10) ) {
 
3147
              if( sig->version < 4 ) {
 
3148
                char *user=utf8_to_native(uid->name,strlen(uid->name),0);
 
3149
 
 
3150
                log_info(_("skipping v3 self-signature on user id \"%s\"\n"),
 
3151
                         user);
 
3152
                xfree (user);
 
3153
              }
 
3154
              else {
 
3155
                /* This is a selfsignature which is to be replaced 
 
3156
                 * We have to ignore v3 signatures because they are
 
3157
                 * not able to carry the preferences */
 
3158
                PKT_signature *newsig;
 
3159
                PACKET *newpkt;
 
3160
                int rc;
 
3161
 
 
3162
                rc = update_keysig_packet (&newsig, sig,
 
3163
                                           main_pk, uid, NULL,
 
3164
                                           sk,
 
3165
                                           keygen_upd_std_prefs,
 
3166
                                           NULL );
 
3167
                if( rc ) {
 
3168
                    log_error ("update_keysig_packet failed: %s\n",
 
3169
                               gpg_strerror (rc));
 
3170
                    free_secret_key( sk );
 
3171
                    return 0;
 
3172
                }
 
3173
                /* replace the packet */
 
3174
                newpkt = xcalloc (1, sizeof *newpkt );
 
3175
                newpkt->pkttype = PKT_SIGNATURE;
 
3176
                newpkt->pkt.signature = newsig;
 
3177
                free_packet( node->pkt );
 
3178
                xfree ( node->pkt );
 
3179
                node->pkt = newpkt;
 
3180
                modified = 1;
 
3181
              }
 
3182
            }
 
3183
        }
 
3184
    }
 
3185
    
 
3186
    free_secret_key( sk );
 
3187
    return modified;
 
3188
}
 
3189
 
 
3190
 
 
3191
 
 
3192
static int
 
3193
menu_set_keyserver_url (KBNODE pub_keyblock, KBNODE sec_keyblock )
 
3194
{
 
3195
    PKT_secret_key *sk;    /* copy of the main sk */
 
3196
    PKT_public_key *main_pk;
 
3197
    PKT_user_id *uid;
 
3198
    KBNODE node;
 
3199
    u32 keyid[2];
 
3200
    int selected, select_all;
 
3201
    int modified = 0;
 
3202
    char *answer;
 
3203
 
 
3204
    no_primary_warning(pub_keyblock,1);
 
3205
 
 
3206
    answer=cpr_get_utf8("keyedit.add_keyserver",
 
3207
                        _("Enter your preferred keyserver URL: "));
 
3208
    if(answer[0]=='\0' || answer[0]=='\004')
 
3209
      {
 
3210
        xfree(answer);
 
3211
        return 0;
 
3212
      }
 
3213
 
 
3214
    select_all = !count_selected_uids (pub_keyblock);
 
3215
 
 
3216
    node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
 
3217
    sk = copy_secret_key( NULL, node->pkt->pkt.secret_key);
 
3218
 
 
3219
    /* Now we can actually change the self signature(s) */
 
3220
    main_pk = NULL;
 
3221
    uid = NULL;
 
3222
    selected = 0;
 
3223
    for ( node=pub_keyblock; node; node = node->next ) {
 
3224
        if ( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
 
3225
            break; /* ready */
 
3226
 
 
3227
        if ( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
 
3228
            main_pk = node->pkt->pkt.public_key;
 
3229
            keyid_from_pk( main_pk, keyid );
 
3230
        }
 
3231
        else if ( node->pkt->pkttype == PKT_USER_ID ) {
 
3232
            uid = node->pkt->pkt.user_id;
 
3233
            selected = select_all || (node->flag & NODFLG_SELUID);
 
3234
        }
 
3235
        else if ( main_pk && uid && selected
 
3236
                  && node->pkt->pkttype == PKT_SIGNATURE ) {
 
3237
            PKT_signature *sig = node->pkt->pkt.signature;
 
3238
            if ( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
 
3239
                 && (uid && (sig->sig_class&~3) == 0x10) ) {
 
3240
              if( sig->version < 4 ) {
 
3241
                char *user=utf8_to_native(uid->name,strlen(uid->name),0);
 
3242
 
 
3243
                log_info(_("skipping v3 self-signature on user id \"%s\"\n"),
 
3244
                         user);
 
3245
                xfree(user);
 
3246
              }
 
3247
              else {
 
3248
                /* This is a selfsignature which is to be replaced 
 
3249
                 * We have to ignore v3 signatures because they are
 
3250
                 * not able to carry the preferences */
 
3251
                PKT_signature *newsig;
 
3252
                PACKET *newpkt;
 
3253
                int rc;
 
3254
 
 
3255
                rc = update_keysig_packet (&newsig, sig,
 
3256
                                           main_pk, uid, NULL,
 
3257
                                           sk,
 
3258
                                           keygen_add_keyserver_url,
 
3259
                                           answer );
 
3260
                if( rc ) {
 
3261
                    log_error ("update_keysig_packet failed: %s\n",
 
3262
                               gpg_strerror (rc));
 
3263
                    xfree(answer);
 
3264
                    free_secret_key( sk );
 
3265
                    return 0;
 
3266
                }
 
3267
                /* replace the packet */
 
3268
                newpkt = xcalloc (1, sizeof *newpkt );
 
3269
                newpkt->pkttype = PKT_SIGNATURE;
 
3270
                newpkt->pkt.signature = newsig;
 
3271
                free_packet( node->pkt );
 
3272
                xfree (node->pkt);
 
3273
                node->pkt = newpkt;
 
3274
                modified = 1;
 
3275
              }
 
3276
            }
 
3277
        }
 
3278
    }
 
3279
 
 
3280
    xfree(answer);
 
3281
    free_secret_key( sk );
 
3282
    return modified;
 
3283
}
 
3284
 
 
3285
 
 
3286
/****************
 
3287
 * Select one user id or remove all selection if index is 0.
 
3288
 * Returns: True if the selection changed;
 
3289
 */
 
3290
static int
 
3291
menu_select_uid( KBNODE keyblock, int idx )
 
3292
{
 
3293
    KBNODE node;
 
3294
    int i;
 
3295
 
 
3296
    /* first check that the index is valid */
 
3297
    if( idx ) {
 
3298
        for( i=0, node = keyblock; node; node = node->next ) {
 
3299
            if( node->pkt->pkttype == PKT_USER_ID ) {
 
3300
                if( ++i == idx )
 
3301
                    break;
 
3302
            }
 
3303
        }
 
3304
        if( !node ) {
 
3305
            tty_printf(_("No user ID with index %d\n"), idx );
 
3306
            return 0;
 
3307
        }
 
3308
    }
 
3309
    else { /* reset all */
 
3310
        for( i=0, node = keyblock; node; node = node->next ) {
 
3311
            if( node->pkt->pkttype == PKT_USER_ID )
 
3312
                node->flag &= ~NODFLG_SELUID;
 
3313
        }
 
3314
        return 1;
 
3315
    }
 
3316
    /* and toggle the new index */
 
3317
    for( i=0, node = keyblock; node; node = node->next ) {
 
3318
        if( node->pkt->pkttype == PKT_USER_ID ) {
 
3319
            if( ++i == idx ) {
 
3320
                if( (node->flag & NODFLG_SELUID) )
 
3321
                    node->flag &= ~NODFLG_SELUID;
 
3322
                else
 
3323
                    node->flag |= NODFLG_SELUID;
 
3324
            }
 
3325
        }
 
3326
    }
 
3327
 
 
3328
    return 1;
 
3329
}
 
3330
 
 
3331
/****************
 
3332
 * Select secondary keys
 
3333
 * Returns: True if the selection changed;
 
3334
 */
 
3335
static int
 
3336
menu_select_key( KBNODE keyblock, int idx )
 
3337
{
 
3338
    KBNODE node;
 
3339
    int i;
 
3340
 
 
3341
    /* first check that the index is valid */
 
3342
    if( idx ) {
 
3343
        for( i=0, node = keyblock; node; node = node->next ) {
 
3344
            if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
 
3345
                || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
 
3346
                if( ++i == idx )
 
3347
                    break;
 
3348
            }
 
3349
        }
 
3350
        if( !node ) {
 
3351
            tty_printf(_("No secondary key with index %d\n"), idx );
 
3352
            return 0;
 
3353
        }
 
3354
    }
 
3355
    else { /* reset all */
 
3356
        for( i=0, node = keyblock; node; node = node->next ) {
 
3357
            if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
 
3358
                || node->pkt->pkttype == PKT_SECRET_SUBKEY )
 
3359
                node->flag &= ~NODFLG_SELKEY;
 
3360
        }
 
3361
        return 1;
 
3362
    }
 
3363
    /* and set the new index */
 
3364
    for( i=0, node = keyblock; node; node = node->next ) {
 
3365
        if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
 
3366
            || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
 
3367
            if( ++i == idx ) {
 
3368
                if( (node->flag & NODFLG_SELKEY) )
 
3369
                    node->flag &= ~NODFLG_SELKEY;
 
3370
                else
 
3371
                    node->flag |= NODFLG_SELKEY;
 
3372
            }
 
3373
        }
 
3374
    }
 
3375
 
 
3376
    return 1;
 
3377
}
 
3378
 
 
3379
 
 
3380
static int
 
3381
count_uids_with_flag( KBNODE keyblock, unsigned flag )
 
3382
{
 
3383
    KBNODE node;
 
3384
    int i=0;
 
3385
 
 
3386
    for( node = keyblock; node; node = node->next )
 
3387
        if( node->pkt->pkttype == PKT_USER_ID && (node->flag & flag) )
 
3388
            i++;
 
3389
    return i;
 
3390
}
 
3391
 
 
3392
static int
 
3393
count_keys_with_flag( KBNODE keyblock, unsigned flag )
 
3394
{
 
3395
    KBNODE node;
 
3396
    int i=0;
 
3397
 
 
3398
    for( node = keyblock; node; node = node->next )
 
3399
        if( ( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
 
3400
              || node->pkt->pkttype == PKT_SECRET_SUBKEY)
 
3401
            && (node->flag & flag) )
 
3402
            i++;
 
3403
    return i;
 
3404
}
 
3405
 
 
3406
static int
 
3407
count_uids( KBNODE keyblock )
 
3408
{
 
3409
    KBNODE node;
 
3410
    int i=0;
 
3411
 
 
3412
    for( node = keyblock; node; node = node->next )
 
3413
        if( node->pkt->pkttype == PKT_USER_ID )
 
3414
            i++;
 
3415
    return i;
 
3416
}
 
3417
 
 
3418
 
 
3419
/****************
 
3420
 * Returns true if there is at least one selected user id
 
3421
 */
 
3422
static int
 
3423
count_selected_uids( KBNODE keyblock )
 
3424
{
 
3425
    return count_uids_with_flag( keyblock, NODFLG_SELUID);
 
3426
}
 
3427
 
 
3428
static int
 
3429
count_selected_keys( KBNODE keyblock )
 
3430
{
 
3431
    return count_keys_with_flag( keyblock, NODFLG_SELKEY);
 
3432
}
 
3433
 
 
3434
/* returns how many real (i.e. not attribute) uids are unmarked */
 
3435
static int
 
3436
real_uids_left( KBNODE keyblock )
 
3437
{
 
3438
  KBNODE node;
 
3439
  int real=0;
 
3440
 
 
3441
  for(node=keyblock;node;node=node->next)
 
3442
    if(node->pkt->pkttype==PKT_USER_ID && !(node->flag&NODFLG_SELUID) &&
 
3443
       !node->pkt->pkt.user_id->attrib_data)
 
3444
      real++;
 
3445
 
 
3446
  return real;
 
3447
}
 
3448
 
 
3449
/*
 
3450
 * Ask whether the signature should be revoked.  If the user commits this,
 
3451
 * flag bit MARK_A is set on the signature and the user ID.
 
3452
 */
 
3453
static void
 
3454
ask_revoke_sig( KBNODE keyblock, KBNODE node )
 
3455
{
 
3456
    int doit=0;
 
3457
    PKT_signature *sig = node->pkt->pkt.signature;
 
3458
    KBNODE unode = find_prev_kbnode( keyblock, node, PKT_USER_ID );
 
3459
 
 
3460
    if( !unode ) {
 
3461
        log_error("Oops: no user ID for signature\n");
 
3462
        return;
 
3463
    }
 
3464
 
 
3465
    tty_printf(_("user ID: \""));
 
3466
    tty_print_utf8_string( unode->pkt->pkt.user_id->name,
 
3467
                           unode->pkt->pkt.user_id->len );
 
3468
 
 
3469
    if(sig->flags.exportable)
 
3470
      tty_printf(_("\"\nsigned with your key %08lX at %s\n"),
 
3471
                 (ulong)sig->keyid[1], datestr_from_sig(sig) );
 
3472
    else
 
3473
      tty_printf(_("\"\nlocally signed with your key %08lX at %s\n"),
 
3474
                 (ulong)sig->keyid[1], datestr_from_sig(sig) );
 
3475
 
 
3476
    if(sig->flags.expired)
 
3477
      {
 
3478
        tty_printf(_("This signature expired on %s.\n"),
 
3479
                   expirestr_from_sig(sig));
 
3480
        /* Use a different question so we can have different help text */
 
3481
        doit=cpr_get_answer_is_yes("ask_revoke_sig.expired",
 
3482
                        _("Are you sure you still want to revoke it? (y/N) "));
 
3483
      }
 
3484
    else
 
3485
      doit=cpr_get_answer_is_yes("ask_revoke_sig.one",
 
3486
              _("Create a revocation certificate for this signature? (y/N) "));
 
3487
 
 
3488
    if(doit) {
 
3489
      node->flag |= NODFLG_MARK_A;
 
3490
      unode->flag |= NODFLG_MARK_A;
 
3491
    }
 
3492
}
 
3493
 
 
3494
/****************
 
3495
 * Display all user ids of the current public key together with signatures
 
3496
 * done by one of our keys.  Then walk over all this sigs and ask the user
 
3497
 * whether he wants to revoke this signature.
 
3498
 * Return: True when the keyblock has changed.
 
3499
 */
 
3500
static int
 
3501
menu_revsig( KBNODE keyblock )
 
3502
{
 
3503
    PKT_signature *sig;
 
3504
    PKT_public_key *primary_pk;
 
3505
    KBNODE node;
 
3506
    int changed = 0;
 
3507
    int rc, any, skip=1, all=!count_selected_uids(keyblock);
 
3508
    struct revocation_reason_info *reason = NULL;
 
3509
 
 
3510
    /* FIXME: detect duplicates here  */
 
3511
    tty_printf(_("You have signed these user IDs:\n"));
 
3512
    for( node = keyblock; node; node = node->next ) {
 
3513
        node->flag &= ~(NODFLG_SELSIG | NODFLG_MARK_A);
 
3514
        if( node->pkt->pkttype == PKT_USER_ID ) {
 
3515
            if( node->flag&NODFLG_SELUID || all ) {
 
3516
              PKT_user_id *uid = node->pkt->pkt.user_id;
 
3517
              /* Hmmm: Should we show only UIDs with a signature? */
 
3518
              tty_printf("     ");
 
3519
              tty_print_utf8_string( uid->name, uid->len );
 
3520
              tty_printf("\n");
 
3521
              skip=0;
 
3522
            }
 
3523
            else
 
3524
              skip=1;
 
3525
        }
 
3526
        else if( !skip && node->pkt->pkttype == PKT_SIGNATURE
 
3527
                && ((sig = node->pkt->pkt.signature),
 
3528
                     !seckey_available(sig->keyid)  ) ) {
 
3529
            if( (sig->sig_class&~3) == 0x10 ) {
 
3530
                tty_printf(_("   signed by %08lX at %s%s%s\n"),
 
3531
                           (ulong)sig->keyid[1], datestr_from_sig(sig),
 
3532
                           sig->flags.exportable?"":" (non-exportable)",
 
3533
                           sig->flags.revocable?"":" (non-revocable)");
 
3534
                if(sig->flags.revocable)
 
3535
                  node->flag |= NODFLG_SELSIG;
 
3536
            }
 
3537
            else if( sig->sig_class == 0x30 ) {
 
3538
                tty_printf(_("   revoked by %08lX at %s\n"),
 
3539
                            (ulong)sig->keyid[1], datestr_from_sig(sig) );
 
3540
            }
 
3541
        }
 
3542
    }
 
3543
 
 
3544
    /* ask */
 
3545
    for( node = keyblock; node; node = node->next ) {
 
3546
        if( !(node->flag & NODFLG_SELSIG) )
 
3547
            continue;
 
3548
        ask_revoke_sig( keyblock, node );
 
3549
    }
 
3550
 
 
3551
    /* present selected */
 
3552
    any = 0;
 
3553
    for( node = keyblock; node; node = node->next ) {
 
3554
        if( !(node->flag & NODFLG_MARK_A) )
 
3555
            continue;
 
3556
        if( !any ) {
 
3557
            any = 1;
 
3558
            tty_printf(_("You are about to revoke these signatures:\n"));
 
3559
        }
 
3560
        if( node->pkt->pkttype == PKT_USER_ID ) {
 
3561
            PKT_user_id *uid = node->pkt->pkt.user_id;
 
3562
            tty_printf("     ");
 
3563
            tty_print_utf8_string( uid->name, uid->len );
 
3564
            tty_printf("\n");
 
3565
        }
 
3566
        else if( node->pkt->pkttype == PKT_SIGNATURE ) {
 
3567
            sig = node->pkt->pkt.signature;
 
3568
            tty_printf(_("   signed by %08lX at %s%s\n"),
 
3569
                       (ulong)sig->keyid[1], datestr_from_sig(sig),
 
3570
                       sig->flags.exportable?"":_(" (non-exportable)") );
 
3571
        }
 
3572
    }
 
3573
    if( !any )
 
3574
        return 0; /* none selected */
 
3575
 
 
3576
    if( !cpr_get_answer_is_yes("ask_revoke_sig.okay",
 
3577
         _("Really create the revocation certificates? (y/N) ")) )
 
3578
        return 0; /* forget it */
 
3579
 
 
3580
    reason = ask_revocation_reason( 0, 1, 0 );
 
3581
    if( !reason ) { /* user decided to cancel */
 
3582
        return 0;
 
3583
    }
 
3584
 
 
3585
    /* now we can sign the user ids */
 
3586
  reloop: /* (must use this, because we are modifing the list) */
 
3587
    primary_pk = keyblock->pkt->pkt.public_key;
 
3588
    for( node=keyblock; node; node = node->next ) {
 
3589
        KBNODE unode;
 
3590
        PACKET *pkt;
 
3591
        struct sign_attrib attrib;
 
3592
        PKT_secret_key *sk;
 
3593
 
 
3594
        if( !(node->flag & NODFLG_MARK_A)
 
3595
            || node->pkt->pkttype != PKT_SIGNATURE )
 
3596
            continue;
 
3597
        unode = find_prev_kbnode( keyblock, node, PKT_USER_ID );
 
3598
        assert( unode ); /* we already checked this */
 
3599
 
 
3600
        memset( &attrib, 0, sizeof attrib );
 
3601
        attrib.reason = reason;
 
3602
        attrib.non_exportable=!node->pkt->pkt.signature->flags.exportable;
 
3603
 
 
3604
        node->flag &= ~NODFLG_MARK_A;
 
3605
        sk = xcalloc_secure (1, sizeof *sk );
 
3606
        if( get_seckey( sk, node->pkt->pkt.signature->keyid ) ) {
 
3607
            log_info(_("no secret key\n"));
 
3608
            continue;
 
3609
        }
 
3610
        rc = make_keysig_packet( &sig, primary_pk,
 
3611
                                       unode->pkt->pkt.user_id,
 
3612
                                       NULL,
 
3613
                                       sk,
 
3614
                                       0x30, 0, 0, 0, 0,
 
3615
                                       sign_mk_attrib,
 
3616
                                       &attrib );
 
3617
        free_secret_key(sk);
 
3618
        if( rc ) {
 
3619
            log_error(_("signing failed: %s\n"), gpg_strerror (rc));
 
3620
            release_revocation_reason_info( reason );
 
3621
            return changed;
 
3622
        }
 
3623
        changed = 1; /* we changed the keyblock */
 
3624
        update_trust = 1;
 
3625
        /* Are we revoking our own uid? */
 
3626
        if(primary_pk->keyid[0]==sig->keyid[0] &&
 
3627
           primary_pk->keyid[1]==sig->keyid[1])
 
3628
          unode->pkt->pkt.user_id->is_revoked=1;
 
3629
        pkt = xcalloc (1, sizeof *pkt );
 
3630
        pkt->pkttype = PKT_SIGNATURE;
 
3631
        pkt->pkt.signature = sig;
 
3632
        insert_kbnode( unode, new_kbnode(pkt), 0 );
 
3633
        goto reloop;
 
3634
    }
 
3635
 
 
3636
    release_revocation_reason_info( reason );
 
3637
    return changed;
 
3638
}
 
3639
 
 
3640
/* Revoke a user ID (i.e. revoke a user ID selfsig).  Return true if
 
3641
   keyblock changed. */
 
3642
static int
 
3643
menu_revuid( KBNODE pub_keyblock, KBNODE sec_keyblock )
 
3644
{
 
3645
  PKT_public_key *pk = pub_keyblock->pkt->pkt.public_key;
 
3646
  PKT_secret_key *sk = copy_secret_key( NULL,
 
3647
                                        sec_keyblock->pkt->pkt.secret_key );
 
3648
  KBNODE node;
 
3649
  int changed = 0;
 
3650
  int rc;
 
3651
  struct revocation_reason_info *reason = NULL;
 
3652
 
 
3653
  /* Note that this is correct as per the RFCs, but nevertheless
 
3654
     somewhat meaningless in the real world.  1991 did define the 0x30
 
3655
     sig class, but PGP 2.x did not actually implement it, so it would
 
3656
     probably be safe to use v4 revocations everywhere. -ds */
 
3657
 
 
3658
  for( node = pub_keyblock; node; node = node->next )
 
3659
    if(pk->version>3 || (node->pkt->pkttype==PKT_USER_ID &&
 
3660
                         node->pkt->pkt.user_id->selfsigversion>3))
 
3661
      {
 
3662
        if((reason = ask_revocation_reason( 0, 1, 4 )))
 
3663
          break;
 
3664
        else
 
3665
          goto leave;
 
3666
      }
 
3667
 
 
3668
 reloop: /* (better this way because we are modifing the keyring) */
 
3669
  for( node = pub_keyblock; node; node = node->next )
 
3670
    if(node->pkt->pkttype == PKT_USER_ID && (node->flag & NODFLG_SELUID))
 
3671
      {
 
3672
        PKT_user_id *uid=node->pkt->pkt.user_id;
 
3673
 
 
3674
        if(uid->is_revoked)
 
3675
          {
 
3676
            char *user=utf8_to_native(uid->name,uid->len,0);
 
3677
            log_info(_("user ID \"%s\" is already revoked\n"),user);
 
3678
            xfree (user);
 
3679
          }
 
3680
        else
 
3681
          {
 
3682
            PACKET *pkt;
 
3683
            PKT_signature *sig;
 
3684
            struct sign_attrib attrib;
 
3685
            u32 timestamp=make_timestamp();
 
3686
 
 
3687
            if(uid->created>=timestamp)
 
3688
              {
 
3689
                /* Okay, this is a problem.  The user ID selfsig was
 
3690
                   created in the future, so we need to warn the user and
 
3691
                   set our revocation timestamp one second after that so
 
3692
                   everything comes out clean. */
 
3693
 
 
3694
                log_info(_("WARNING: a user ID signature is dated %d"
 
3695
                           " seconds in the future\n"),uid->created-timestamp);
 
3696
 
 
3697
                timestamp=uid->created+1;
 
3698
              }
 
3699
 
 
3700
            memset( &attrib, 0, sizeof attrib );
 
3701
            attrib.reason = reason;
 
3702
 
 
3703
            node->flag &= ~NODFLG_SELUID;
 
3704
 
 
3705
            rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x30, 0,
 
3706
                                     (reason==NULL)?3:0, timestamp, 0,
 
3707
                                     sign_mk_attrib, &attrib );
 
3708
            if( rc )
 
3709
              {
 
3710
                log_error(_("signing failed: %s\n"), gpg_strerror (rc));
 
3711
                goto leave;
 
3712
              }
 
3713
            else
 
3714
              {
 
3715
                pkt = xcalloc (1, sizeof *pkt );
 
3716
                pkt->pkttype = PKT_SIGNATURE;
 
3717
                pkt->pkt.signature = sig;
 
3718
                insert_kbnode( node, new_kbnode(pkt), 0 );
 
3719
 
 
3720
                /* If the trustdb has an entry for this key+uid then the
 
3721
                   trustdb needs an update. */
 
3722
                if(!update_trust
 
3723
                   && (get_validity(pk,uid)&TRUST_MASK)>=TRUST_UNDEFINED)
 
3724
                  update_trust=1;
 
3725
 
 
3726
                changed = 1;
 
3727
                node->pkt->pkt.user_id->is_revoked=1;
 
3728
 
 
3729
                goto reloop;
 
3730
              }
 
3731
          }
 
3732
      }
 
3733
 
 
3734
  if(changed)
 
3735
    commit_kbnode( &pub_keyblock );
 
3736
 
 
3737
 leave:
 
3738
  free_secret_key(sk);
 
3739
  release_revocation_reason_info( reason );
 
3740
  return changed;
 
3741
}
 
3742
 
 
3743
/****************
 
3744
 * Revoke some of the secondary keys.
 
3745
 * Hmmm: Should we add a revocation to the secret keyring too?
 
3746
 *       Does its all make sense to duplicate most of the information?
 
3747
 */
 
3748
static int
 
3749
menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
 
3750
{
 
3751
    PKT_public_key *mainpk;
 
3752
    KBNODE node;
 
3753
    int changed = 0;
 
3754
    int rc;
 
3755
    struct revocation_reason_info *reason = NULL;
 
3756
 
 
3757
    reason = ask_revocation_reason( 1, 0, 0 );
 
3758
    if( !reason ) { /* user decided to cancel */
 
3759
        return 0;
 
3760
    }
 
3761
 
 
3762
  reloop: /* (better this way because we are modifing the keyring) */
 
3763
    mainpk = pub_keyblock->pkt->pkt.public_key;
 
3764
    for( node = pub_keyblock; node; node = node->next ) {
 
3765
        if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
 
3766
            && (node->flag & NODFLG_SELKEY) ) {
 
3767
            PACKET *pkt;
 
3768
            PKT_signature *sig;
 
3769
            PKT_secret_key *sk;
 
3770
            PKT_public_key *subpk = node->pkt->pkt.public_key;
 
3771
            struct sign_attrib attrib;
 
3772
 
 
3773
            memset( &attrib, 0, sizeof attrib );
 
3774
            attrib.reason = reason;
 
3775
 
 
3776
            node->flag &= ~NODFLG_SELKEY;
 
3777
            sk = copy_secret_key( NULL, sec_keyblock->pkt->pkt.secret_key );
 
3778
            rc = make_keysig_packet( &sig, mainpk, NULL, subpk, sk,
 
3779
                                     0x28, 0, 0, 0, 0,
 
3780
                                     sign_mk_attrib, &attrib );
 
3781
            free_secret_key(sk);
 
3782
            if( rc ) {
 
3783
                log_error(_("signing failed: %s\n"), gpg_strerror (rc));
 
3784
                release_revocation_reason_info( reason );
 
3785
                return changed;
 
3786
            }
 
3787
            changed = 1; /* we changed the keyblock */
 
3788
 
 
3789
            pkt = xcalloc (1, sizeof *pkt );
 
3790
            pkt->pkttype = PKT_SIGNATURE;
 
3791
            pkt->pkt.signature = sig;
 
3792
            insert_kbnode( node, new_kbnode(pkt), 0 );
 
3793
            goto reloop;
 
3794
        }
 
3795
    }
 
3796
    commit_kbnode( &pub_keyblock );
 
3797
    /*commit_kbnode( &sec_keyblock );*/
 
3798
 
 
3799
    /* No need to set update_trust here since signing keys no longer
 
3800
       are used to certify other keys, so there is no change in trust
 
3801
       when revoking/removing them */
 
3802
 
 
3803
    release_revocation_reason_info( reason );
 
3804
    return changed;
 
3805
}
 
3806
 
 
3807
/* Note that update_ownertrust is going to mark the trustdb dirty when
 
3808
   enabling or disabling a key.  This is arguably sub-optimal as
 
3809
   disabled keys are still counted in the web of trust, but perhaps
 
3810
   not worth adding extra complexity to change. -ds */
 
3811
static int
 
3812
enable_disable_key( KBNODE keyblock, int disable )
 
3813
{
 
3814
    PKT_public_key *pk = find_kbnode( keyblock, PKT_PUBLIC_KEY )
 
3815
                            ->pkt->pkt.public_key;
 
3816
    unsigned int trust, newtrust;
 
3817
 
 
3818
    trust = newtrust = get_ownertrust (pk);
 
3819
    newtrust &= ~TRUST_FLAG_DISABLED;
 
3820
    if( disable )
 
3821
        newtrust |= TRUST_FLAG_DISABLED;
 
3822
    if( trust == newtrust )
 
3823
        return 0; /* already in that state */
 
3824
    update_ownertrust(pk, newtrust );
 
3825
    return 0;
 
3826
}
 
3827
 
 
3828
 
 
3829
static void
 
3830
menu_showphoto( KBNODE keyblock )
 
3831
{
 
3832
  KBNODE node;
 
3833
  int select_all = !count_selected_uids(keyblock);
 
3834
  int count=0;
 
3835
  PKT_public_key *pk=NULL;
 
3836
  u32 keyid[2];
 
3837
 
 
3838
  /* Look for the public key first.  We have to be really, really,
 
3839
     explicit as to which photo this is, and what key it is a UID on
 
3840
     since people may want to sign it. */
 
3841
 
 
3842
  for( node = keyblock; node; node = node->next )
 
3843
    {
 
3844
      if( node->pkt->pkttype == PKT_PUBLIC_KEY )
 
3845
        {
 
3846
          pk = node->pkt->pkt.public_key;
 
3847
          keyid_from_pk(pk, keyid);
 
3848
        }
 
3849
      else if( node->pkt->pkttype == PKT_USER_ID )
 
3850
        {
 
3851
          PKT_user_id *uid = node->pkt->pkt.user_id;
 
3852
          count++;
 
3853
 
 
3854
          if((select_all || (node->flag & NODFLG_SELUID)) &&
 
3855
             uid->attribs!=NULL)
 
3856
            {
 
3857
              int i;
 
3858
 
 
3859
              for(i=0;i<uid->numattribs;i++)
 
3860
                {
 
3861
                  byte type;
 
3862
                  u32 size;
 
3863
 
 
3864
                  if(uid->attribs[i].type==ATTRIB_IMAGE &&
 
3865
                     parse_image_header(&uid->attribs[i],&type,&size))
 
3866
                    {
 
3867
                      tty_printf(_("Displaying %s photo ID of size %ld for "
 
3868
                                   "key 0x%08lX (uid %d)\n"),
 
3869
                                 image_type_to_string(type,1),
 
3870
                                 (ulong)size,(ulong)keyid[1],count);
 
3871
                      show_photos(&uid->attribs[i],1,pk,NULL);
 
3872
                    }
 
3873
                }
 
3874
            }
 
3875
        }
 
3876
    }
 
3877
}