* import.c (import_keys_internal): Missed one s/inp/inp2/.
[gnupg.git] / g10 / keylist.c
1 /* keylist.c
2  * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <assert.h>
27
28 #include "options.h"
29 #include "packet.h"
30 #include "errors.h"
31 #include "keydb.h"
32 #include "memory.h"
33 #include "photoid.h"
34 #include "util.h"
35 #include "ttyio.h"
36 #include "trustdb.h"
37 #include "main.h"
38 #include "i18n.h"
39 #include "status.h"
40
41 static void list_all(int);
42 static void list_one( STRLIST names, int secret);
43
44 struct sig_stats
45 {
46   int inv_sigs;
47   int no_key;
48   int oth_err;
49 };
50
51 static FILE *attrib_fp=NULL;
52
53 /****************
54  * List the keys
55  * If list is NULL, all available keys are listed
56  */
57 void
58 public_key_list( STRLIST list )
59 {
60     if( !list )
61         list_all(0);
62     else
63         list_one( list, 0 );
64 }
65
66 void
67 secret_key_list( STRLIST list )
68 {
69     if( !list )
70         list_all(1);
71     else  /* List by user id */
72         list_one( list, 1 );
73 }
74
75 void
76 show_policy_url(PKT_signature *sig,int indent)
77 {
78   const byte *p;
79   size_t len;
80   int seq=0,crit;
81
82   while((p=enum_sig_subpkt(sig->hashed,SIGSUBPKT_POLICY,&len,&seq,&crit)))
83     {
84       int i;
85
86       for(i=0;i<indent;i++)
87         putchar(' ');
88
89       /* This isn't UTF8 as it is a URL(?) */
90       if(crit)
91         printf(_("Critical signature policy: "));
92       else
93         printf(_("Signature policy: "));
94       print_string(stdout,p,len,0);
95       printf("\n");
96     }
97 }
98
99 void
100 show_notation(PKT_signature *sig,int indent)
101 {
102   const byte *p;
103   size_t len;
104   int seq=0,crit;
105
106   /* There may be multiple notations in the same sig. */
107
108   while((p=enum_sig_subpkt(sig->hashed,SIGSUBPKT_NOTATION,&len,&seq,&crit)))
109     if(len>=8)
110       {
111         int n1,n2,i;
112
113         n1=(p[4]<<8)|p[5];
114         n2=(p[6]<<8)|p[7];
115
116         if(8+n1+n2!=len)
117           {
118             log_info(_("WARNING: invalid notation data found\n"));
119             return;
120           }
121
122         for(i=0;i<indent;i++)
123           putchar(' ');
124
125         /* This is UTF8 */
126         if(crit)
127           printf(_("Critical signature notation: "));
128         else
129           printf(_("Signature notation: "));
130         print_utf8_string(stdout,p+8,n1);
131         printf("=");
132
133         if(*p&0x80)
134           print_utf8_string(stdout,p+8+n1,n2);
135         else
136           printf("[ %s ]",_("not human readable"));
137
138         printf("\n");
139       }
140   else
141     log_info(_("WARNING: invalid notation data found\n"));
142 }
143
144 static void
145 print_signature_stats(struct sig_stats *s)
146 {
147   if( s->inv_sigs == 1 )
148     tty_printf(_("1 bad signature\n") );
149   else if( s->inv_sigs )
150     tty_printf(_("%d bad signatures\n"), s->inv_sigs );
151   if( s->no_key == 1 )
152     tty_printf(_("1 signature not checked due to a missing key\n") );
153   else if( s->no_key )
154     tty_printf(_("%d signatures not checked due to missing keys\n"),s->no_key);
155   if( s->oth_err == 1 )
156     tty_printf(_("1 signature not checked due to an error\n") );
157   else if( s->oth_err )
158     tty_printf(_("%d signatures not checked due to errors\n"), s->oth_err );
159 }
160
161 static void
162 list_all( int secret )
163 {
164     KEYDB_HANDLE hd;
165     KBNODE keyblock = NULL;
166     int rc=0;
167     const char *lastresname, *resname;
168     struct sig_stats stats;
169
170     memset(&stats,0,sizeof(stats));
171
172     hd = keydb_new (secret);
173     if (!hd)
174         rc = G10ERR_GENERAL;
175     else
176         rc = keydb_search_first (hd);
177     if( rc ) {
178         if( rc != -1 )
179             log_error("keydb_search_first failed: %s\n", g10_errstr(rc) );
180         goto leave;
181     }
182
183     lastresname = NULL;
184     do {
185         rc = keydb_get_keyblock (hd, &keyblock);
186         if (rc) {
187             log_error ("keydb_get_keyblock failed: %s\n", g10_errstr(rc));
188             goto leave;
189         }
190         resname = keydb_get_resource_name (hd);
191         if (lastresname != resname ) {
192             int i;
193
194             printf("%s\n", resname );
195             for(i=strlen(resname); i; i-- )
196                 putchar('-');
197             putchar('\n');
198             lastresname = resname;
199         }
200         merge_keys_and_selfsig( keyblock );
201         list_keyblock( keyblock, secret, opt.fingerprint,
202                        opt.check_sigs?&stats:NULL);
203         release_kbnode( keyblock ); 
204         keyblock = NULL;
205     } while (!(rc = keydb_search_next (hd)));
206     if( rc && rc != -1 )
207         log_error ("keydb_search_next failed: %s\n", g10_errstr(rc));
208
209     if(opt.check_sigs && !opt.with_colons)
210       print_signature_stats(&stats);
211
212   leave:
213     release_kbnode (keyblock);
214     keydb_release (hd);
215 }
216
217
218 static void
219 list_one( STRLIST names, int secret )
220 {
221     int rc = 0;
222     KBNODE keyblock = NULL;
223     GETKEY_CTX ctx;
224     const char *resname;
225     char *keyring_str = N_("Keyring");
226     int i;
227     struct sig_stats stats;
228
229     memset(&stats,0,sizeof(stats));
230
231     /* fixme: using the bynames function has the disadvantage that we
232      * don't know wether one of the names given was not found.  OTOH,
233      * this function has the advantage to list the names in the
234      * sequence as defined by the keyDB and does not duplicate
235      * outputs.  A solution could be do test whether all given have
236      * been listed (this needs a way to use the keyDB search
237      * functions) or to have the search function return indicators for
238      * found names.  Yet another way is to use the keydb search
239      * facilities directly. */
240     if( secret ) {
241         rc = get_seckey_bynames( &ctx, NULL, names, &keyblock );
242         if( rc ) {
243             log_error("error reading key: %s\n",  g10_errstr(rc) );
244             get_seckey_end( ctx );
245             return;
246         }
247         do {
248             if (opt.show_keyring) {
249                 resname = keydb_get_resource_name (get_ctx_handle(ctx));
250                 printf("%s: %s\n", keyring_str, resname);
251                 for(i = strlen(resname) + strlen(keyring_str) + 2; i; i-- )
252                     putchar('-');
253                 putchar('\n');
254             }
255             list_keyblock( keyblock, 1, opt.fingerprint, NULL );
256             release_kbnode( keyblock );
257         } while( !get_seckey_next( ctx, NULL, &keyblock ) );
258         get_seckey_end( ctx );
259     }
260     else {
261         rc = get_pubkey_bynames( &ctx, NULL, names, &keyblock );
262         if( rc ) {
263             log_error("error reading key: %s\n", g10_errstr(rc) );
264             get_pubkey_end( ctx );
265             return;
266         }
267         do {
268             if (opt.show_keyring) {
269                 resname = keydb_get_resource_name (get_ctx_handle(ctx));
270                 printf("%s: %s\n", keyring_str, resname);
271                 for(i = strlen(resname) + strlen(keyring_str) + 2; i; i-- )
272                     putchar('-');
273                 putchar('\n');
274             }
275             list_keyblock( keyblock, 0, opt.fingerprint,
276                            opt.check_sigs?&stats:NULL );
277             release_kbnode( keyblock );
278         } while( !get_pubkey_next( ctx, NULL, &keyblock ) );
279         get_pubkey_end( ctx );
280     }
281
282     if(opt.check_sigs && !opt.with_colons)
283       print_signature_stats(&stats);
284 }
285
286 static void
287 print_key_data( PKT_public_key *pk, u32 *keyid )
288 {
289     int n = pk ? pubkey_get_npkey( pk->pubkey_algo ) : 0;
290     int i;
291
292     for(i=0; i < n; i++ ) {
293         printf("pkd:%d:%u:", i, mpi_get_nbits( pk->pkey[i] ) );
294         mpi_print(stdout, pk->pkey[i], 1 );
295         putchar(':');
296         putchar('\n');
297     }
298 }
299
300 static void
301 print_capabilities (PKT_public_key *pk, PKT_secret_key *sk, KBNODE keyblock)
302 {
303   if(pk || (sk && sk->protect.s2k.mode!=1001))
304     {
305       unsigned int use = pk? pk->pubkey_usage : sk->pubkey_usage;
306     
307       if ( use & PUBKEY_USAGE_ENC )
308         putchar ('e');
309
310       if ( use & PUBKEY_USAGE_SIG )
311         {
312           putchar ('s');
313           if( pk? pk->is_primary : sk->is_primary )
314             putchar ('c');
315         }
316     }
317
318     if ( keyblock ) { /* figure our the usable capabilities */
319         KBNODE k;
320         int enc=0, sign=0, cert=0;
321
322         for (k=keyblock; k; k = k->next ) {
323             if ( k->pkt->pkttype == PKT_PUBLIC_KEY 
324                  || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
325                 pk = k->pkt->pkt.public_key;
326                 if ( pk->is_valid && !pk->is_revoked && !pk->has_expired ) {
327                     if ( pk->pubkey_usage & PUBKEY_USAGE_ENC )
328                         enc = 1;
329                     if ( pk->pubkey_usage & PUBKEY_USAGE_SIG )
330                       {
331                         sign = 1;
332                         if(pk->is_primary)
333                           cert = 1;
334                       }
335                 }
336             }
337             else if ( k->pkt->pkttype == PKT_SECRET_KEY 
338                       || k->pkt->pkttype == PKT_SECRET_SUBKEY ) {
339                 sk = k->pkt->pkt.secret_key;
340                 if ( sk->is_valid && !sk->is_revoked && !sk->has_expired
341                      && sk->protect.s2k.mode!=1001 ) {
342                     if ( sk->pubkey_usage & PUBKEY_USAGE_ENC )
343                         enc = 1;
344                     if ( sk->pubkey_usage & PUBKEY_USAGE_SIG )
345                       {
346                         sign = 1;
347                         if(sk->is_primary)
348                           cert = 1;
349                       }
350                 }
351             }
352         }
353         if (enc)
354             putchar ('E');
355         if (sign)
356             putchar ('S');
357         if (cert)
358             putchar ('C');
359     }
360     putchar(':');
361 }
362
363 static void dump_attribs(const PKT_user_id *uid,
364                          PKT_public_key *pk,PKT_secret_key *sk)
365 {
366   int i;
367
368   if(!attrib_fp)
369     BUG();
370
371   for(i=0;i<uid->numattribs;i++)
372     {
373       if(is_status_enabled())
374         {
375           byte array[MAX_FINGERPRINT_LEN], *p;
376           char buf[(MAX_FINGERPRINT_LEN*2)+90];
377           size_t j,n;
378
379           if(pk)
380             fingerprint_from_pk( pk, array, &n );
381           else if(sk)
382             fingerprint_from_sk( sk, array, &n );
383           else
384             BUG();
385
386           p = array;
387           for(j=0; j < n ; j++, p++ )
388             sprintf(buf+2*j, "%02X", *p );
389
390           sprintf(buf+strlen(buf)," %lu %u %u %u %lu %lu %u",
391                   (ulong)uid->attribs[i].len,uid->attribs[i].type,i+1,
392                   uid->numattribs,(ulong)uid->created,(ulong)uid->expiredate,
393                   ((uid->is_primary?0x01:0)|
394                    (uid->is_revoked?0x02:0)|
395                    (uid->is_expired?0x04:0)));
396           write_status_text(STATUS_ATTRIBUTE,buf);
397         }
398
399       fwrite(uid->attribs[i].data,uid->attribs[i].len,1,attrib_fp);
400     }
401 }
402
403 static void
404 list_keyblock_print ( KBNODE keyblock, int secret, int fpr, void *opaque )
405 {
406     int rc = 0;
407     KBNODE kbctx;
408     KBNODE node;
409     PKT_public_key *pk;
410     PKT_secret_key *sk;
411     u32 keyid[2];
412     int any=0;
413     struct sig_stats *stats=opaque;
414
415     /* get the keyid from the keyblock */
416     node = find_kbnode( keyblock, secret? PKT_SECRET_KEY : PKT_PUBLIC_KEY );
417     if( !node ) {
418         log_error("Oops; key lost!\n");
419         dump_kbnode( keyblock );
420         return;
421     }
422
423     if( secret ) {
424         pk = NULL;
425         sk = node->pkt->pkt.secret_key;
426         keyid_from_sk( sk, keyid );
427         printf("sec%c %4u%c/%08lX %s ", (sk->protect.s2k.mode==1001)?'#':' ',
428                                         nbits_from_sk( sk ),
429                                         pubkey_letter( sk->pubkey_algo ),
430                                         (ulong)keyid[1],
431                                         datestr_from_sk( sk ) );
432     }
433     else {
434         pk = node->pkt->pkt.public_key;
435         sk = NULL;
436         keyid_from_pk( pk, keyid );
437         printf("pub  %4u%c/%08lX %s ", nbits_from_pk( pk ),
438                                        pubkey_letter( pk->pubkey_algo ),
439                                        (ulong)keyid[1],
440                                        datestr_from_pk( pk ) );
441     }
442
443     for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
444         if( node->pkt->pkttype == PKT_USER_ID && !opt.fast_list_mode ) {
445             if(attrib_fp && node->pkt->pkt.user_id->attrib_data!=NULL)
446               dump_attribs(node->pkt->pkt.user_id,pk,sk);
447             /* don't list revoked or expired UIDS unless we are in
448              * verbose mode and signature listing has not been
449              * requested */
450             if ( !opt.verbose && !opt.list_sigs &&
451                  (node->pkt->pkt.user_id->is_revoked ||
452                   node->pkt->pkt.user_id->is_expired ))
453                 continue; 
454
455             if( any ) 
456                 printf("uid%*s", 28, "");
457
458             if ( node->pkt->pkt.user_id->is_revoked )
459                 fputs ("[revoked] ", stdout);
460             if ( node->pkt->pkt.user_id->is_expired )
461                 fputs ("[expired] ", stdout);
462             print_utf8_string( stdout,  node->pkt->pkt.user_id->name,
463                                node->pkt->pkt.user_id->len );
464             putchar('\n');
465             if( !any ) {
466                 if( fpr )
467                     print_fingerprint( pk, sk, 0 );
468                 if( opt.with_key_data )
469                     print_key_data( pk, keyid );
470                 any = 1;
471             }
472
473             if(opt.show_photos && node->pkt->pkt.user_id->attribs!=NULL)
474               show_photos(node->pkt->pkt.user_id->attribs,
475                           node->pkt->pkt.user_id->numattribs,pk,sk);
476         }
477         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
478             u32 keyid2[2];
479             PKT_public_key *pk2 = node->pkt->pkt.public_key;
480
481             if( !any ) {
482                 putchar('\n');
483                 if( fpr )
484                     print_fingerprint( pk, sk, 0 ); /* of the main key */
485                 any = 1;
486             }
487
488             keyid_from_pk( pk2, keyid2 );
489             printf("sub  %4u%c/%08lX %s", nbits_from_pk( pk2 ),
490                    pubkey_letter( pk2->pubkey_algo ),
491                    (ulong)keyid2[1],
492                    datestr_from_pk( pk2 ) );
493             if( pk2->expiredate ) {
494                 printf(_(" [expires: %s]"), expirestr_from_pk( pk2 ) );
495             }
496             putchar('\n');
497             if( fpr > 1 )
498                 print_fingerprint( pk2, NULL, 0 );
499             if( opt.with_key_data )
500                 print_key_data( pk2, keyid2 );
501         }
502         else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
503             u32 keyid2[2];
504             PKT_secret_key *sk2 = node->pkt->pkt.secret_key;
505
506             if( !any ) {
507                 putchar('\n');
508                 if( fpr )
509                     print_fingerprint( pk, sk, 0 ); /* of the main key */
510                 any = 1;
511             }
512
513             keyid_from_sk( sk2, keyid2 );
514             printf("ssb  %4u%c/%08lX %s\n", nbits_from_sk( sk2 ),
515                                            pubkey_letter( sk2->pubkey_algo ),
516                                            (ulong)keyid2[1],
517                                            datestr_from_sk( sk2 ) );
518             if( fpr > 1 )
519                 print_fingerprint( NULL, sk2, 0 );
520         }
521         else if( opt.list_sigs && node->pkt->pkttype == PKT_SIGNATURE ) {
522             PKT_signature *sig = node->pkt->pkt.signature;
523             int sigrc;
524             char *sigstr;
525
526             if( stats ) {
527                 /*fflush(stdout);*/
528                 rc = check_key_signature( keyblock, node, NULL );
529                 switch( rc ) {
530                  case 0:                 sigrc = '!'; break;
531                  case G10ERR_BAD_SIGN:   stats->inv_sigs++; sigrc = '-'; break;
532                  case G10ERR_NO_PUBKEY: 
533                  case G10ERR_UNU_PUBKEY: stats->no_key++; continue;
534                  default:                stats->oth_err++; sigrc = '%'; break;
535                 }
536
537                 /* TODO: Make sure a cached sig record here still has
538                    the pk that issued it.  See also
539                    keyedit.c:print_and_check_one_sig */
540
541             }
542             else {
543                 rc = 0;
544                 sigrc = ' ';
545             }
546
547             if( !any ) { /* no user id, (maybe a revocation follows)*/
548               /* Check if the pk is really revoked - there could be a
549                  0x20 sig packet there even if we are not revoked
550                  (say, if a revocation key issued the packet, but the
551                  revocation key isn't present to verify it.) */
552                 if( sig->sig_class == 0x20 && pk->is_revoked )
553                     puts("[revoked]");
554                 else if( sig->sig_class == 0x18 )
555                     puts("[key binding]");
556                 else if( sig->sig_class == 0x28 )
557                     puts("[subkey revoked]");
558                 else
559                     putchar('\n');
560                 if( fpr )
561                     print_fingerprint( pk, sk, 0 );
562                 any=1;
563             }
564
565             if( sig->sig_class == 0x20 || sig->sig_class == 0x28
566                                        || sig->sig_class == 0x30 )
567                sigstr = "rev";
568             else if( (sig->sig_class&~3) == 0x10 )
569                sigstr = "sig";
570             else if( sig->sig_class == 0x18 )
571                sigstr = "sig";
572             else if( sig->sig_class == 0x1F )
573                sigstr = "sig";
574             else {
575                 printf("sig                             "
576                        "[unexpected signature class 0x%02x]\n",sig->sig_class );
577                 continue;
578             }
579
580             fputs( sigstr, stdout );
581             printf("%c%c %c%c%c%c%c %08lX %s   ",
582                    sigrc,(sig->sig_class-0x10>0 &&
583                           sig->sig_class-0x10<4)?'0'+sig->sig_class-0x10:' ',
584                    sig->flags.exportable?' ':'L',
585                    sig->flags.revocable?' ':'R',
586                    sig->flags.policy_url?'P':' ',
587                    sig->flags.notation?'N':' ',
588                    sig->flags.expired?'X':' ',
589                    (ulong)sig->keyid[1], datestr_from_sig(sig));
590             if( sigrc == '%' )
591                 printf("[%s] ", g10_errstr(rc) );
592             else if( sigrc == '?' )
593                 ;
594             else if ( !opt.fast_list_mode ) {
595                 size_t n;
596                 char *p = get_user_id( sig->keyid, &n );
597                 print_utf8_string( stdout, p, n );
598                 m_free(p);
599             }
600             putchar('\n');
601
602             if(sig->flags.policy_url && opt.show_policy_url)
603               show_policy_url(sig,3);
604
605             if(sig->flags.notation && opt.show_notation)
606               show_notation(sig,3);
607
608             /* fixme: check or list other sigs here */
609         }
610     }
611     putchar('\n');
612 }
613
614
615 static void
616 list_keyblock_colon( KBNODE keyblock, int secret, int fpr )
617 {
618     int rc = 0;
619     KBNODE kbctx;
620     KBNODE node;
621     PKT_public_key *pk;
622     PKT_secret_key *sk;
623     u32 keyid[2];
624     int any=0;
625     int trustletter = 0;
626     int ulti_hack = 0;
627
628     /* get the keyid from the keyblock */
629     node = find_kbnode( keyblock, secret? PKT_SECRET_KEY : PKT_PUBLIC_KEY );
630     if( !node ) {
631         log_error("Oops; key lost!\n");
632         dump_kbnode( keyblock );
633         return;
634     }
635
636     if( secret ) {
637         pk = NULL;
638         sk = node->pkt->pkt.secret_key;
639         keyid_from_sk( sk, keyid );
640         printf("sec:u:%u:%d:%08lX%08lX:%s:%s:::",
641                     nbits_from_sk( sk ),
642                     sk->pubkey_algo,
643                     (ulong)keyid[0],(ulong)keyid[1],
644                     colon_datestr_from_sk( sk ),
645                     colon_strtime (sk->expiredate)
646                     /* fixme: add LID here */ );
647     }
648     else {
649         pk = node->pkt->pkt.public_key;
650         sk = NULL;
651         keyid_from_pk( pk, keyid );
652         fputs( "pub:", stdout );
653         trustletter = 0;
654         if ( !pk->is_valid )
655             putchar ('i');
656         else if ( pk->is_revoked )
657             putchar ('r');
658         else if ( pk->has_expired )
659             putchar ('e');
660         else if ( opt.fast_list_mode || opt.no_expensive_trust_checks ) 
661             ;
662         else {
663             trustletter = get_validity_info ( pk, NULL );
664             if( trustletter == 'u' )
665                 ulti_hack = 1;
666             putchar(trustletter);
667         }
668         printf(":%u:%d:%08lX%08lX:%s:%s:",
669                     nbits_from_pk( pk ),
670                     pk->pubkey_algo,
671                     (ulong)keyid[0],(ulong)keyid[1],
672                     colon_datestr_from_pk( pk ),
673                     colon_strtime (pk->expiredate) );
674         if( pk->local_id )
675             printf("%lu", pk->local_id );
676         putchar(':');
677         if( !opt.fast_list_mode && !opt.no_expensive_trust_checks  )
678             putchar( get_ownertrust_info(pk) );
679             putchar(':');
680     }
681     
682     if (opt.fixed_list_mode) {
683         /* do not merge the first uid with the primary key */
684         putchar(':');
685         putchar(':');
686         print_capabilities (pk, sk, keyblock);
687         putchar('\n');
688         if( fpr )
689             print_fingerprint( pk, sk, 0 );
690         if( opt.with_key_data )
691             print_key_data( pk, keyid );
692         any = 1;
693     }
694
695
696     for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
697         if( node->pkt->pkttype == PKT_USER_ID && !opt.fast_list_mode ) {
698             if(attrib_fp && node->pkt->pkt.user_id->attrib_data!=NULL)
699               dump_attribs(node->pkt->pkt.user_id,pk,sk);
700             /*
701              * Fixme: We need a is_valid flag here too 
702              */
703             if( any ) {
704                 char *str=node->pkt->pkt.user_id->attrib_data?"uat":"uid";
705                 if ( node->pkt->pkt.user_id->is_revoked )
706                     printf("%s:r::::::::",str);
707                 else if ( node->pkt->pkt.user_id->is_expired )
708                     printf("%s:e::::::::",str);
709                 else if ( opt.no_expensive_trust_checks ) {
710                     printf("%s:::::::::",str);
711                 }
712                 else {
713                     byte namehash[20];
714
715                     if( pk && !ulti_hack ) {
716                         if( node->pkt->pkt.user_id->attrib_data )
717                             rmd160_hash_buffer( namehash,
718                                            node->pkt->pkt.user_id->attrib_data,
719                                            node->pkt->pkt.user_id->attrib_len);
720                         else
721                             rmd160_hash_buffer( namehash,
722                                             node->pkt->pkt.user_id->name,
723                                             node->pkt->pkt.user_id->len  );
724                         trustletter = get_validity_info( pk, namehash );
725                     }
726                     else
727                         trustletter = 'u';
728                     printf("%s:%c::::::::",str,trustletter);
729                 }
730             }
731             if(node->pkt->pkt.user_id->attrib_data)
732               printf("%u %lu",
733                      node->pkt->pkt.user_id->numattribs,
734                      node->pkt->pkt.user_id->attrib_len);
735             else
736               print_string( stdout,  node->pkt->pkt.user_id->name,
737                             node->pkt->pkt.user_id->len, ':' );
738             putchar(':');
739             if (any)
740                 putchar('\n');
741             else {
742                 putchar(':');
743                 print_capabilities (pk, sk, keyblock);
744                 putchar('\n');
745                 if( fpr )
746                     print_fingerprint( pk, sk, 0 );
747                 if( opt.with_key_data )
748                     print_key_data( pk, keyid );
749                 any = 1;
750             }
751         }
752         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
753             u32 keyid2[2];
754             PKT_public_key *pk2 = node->pkt->pkt.public_key;
755
756             if( !any ) {
757                 putchar(':');
758                 putchar(':');
759                 print_capabilities (pk, sk, keyblock);
760                 putchar('\n');
761                 if( fpr )
762                     print_fingerprint( pk, sk, 0 ); /* of the main key */
763                 any = 1;
764             }
765
766             keyid_from_pk( pk2, keyid2 );
767             fputs ("sub:", stdout );
768             if ( !pk2->is_valid )
769                 putchar ('i');
770             else if ( pk2->is_revoked )
771                 putchar ('r');
772             else if ( pk2->has_expired )
773                 putchar ('e');
774             else if ( opt.fast_list_mode || opt.no_expensive_trust_checks )
775                 ;
776             else {
777                 printf("%c", trustletter );
778             }
779             printf(":%u:%d:%08lX%08lX:%s:%s:",
780                         nbits_from_pk( pk2 ),
781                         pk2->pubkey_algo,
782                         (ulong)keyid2[0],(ulong)keyid2[1],
783                         colon_datestr_from_pk( pk2 ),
784                         colon_strtime (pk2->expiredate)
785                         /* fixme: add LID and ownertrust here */
786                                                 );
787             if( pk->local_id ) /* use the local_id of the main key??? */
788                 printf("%lu", pk->local_id );
789             putchar(':');
790             putchar(':');
791             putchar(':');
792             putchar(':');
793             print_capabilities (pk2, NULL, NULL);
794             putchar('\n');
795             if( fpr > 1 )
796                 print_fingerprint( pk2, NULL, 0 );
797             if( opt.with_key_data )
798                 print_key_data( pk2, keyid2 );
799         }
800         else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
801             u32 keyid2[2];
802             PKT_secret_key *sk2 = node->pkt->pkt.secret_key;
803
804             if( !any ) {
805                 putchar(':');
806                 putchar(':');
807                 print_capabilities (pk, sk, keyblock);
808                 putchar('\n');
809                 if( fpr )
810                     print_fingerprint( pk, sk, 0 ); /* of the main key */
811                 any = 1;
812             }
813
814             keyid_from_sk( sk2, keyid2 );
815             printf("ssb::%u:%d:%08lX%08lX:%s:%s:::::",
816                         nbits_from_sk( sk2 ),
817                         sk2->pubkey_algo,
818                         (ulong)keyid2[0],(ulong)keyid2[1],
819                         colon_datestr_from_sk( sk2 ),
820                         colon_strtime (sk2->expiredate)
821                    /* fixme: add LID */ );
822             print_capabilities (NULL, sk2, NULL);
823             putchar ('\n');
824             if( fpr > 1 )
825                 print_fingerprint( NULL, sk2, 0 );
826         }
827         else if( opt.list_sigs && node->pkt->pkttype == PKT_SIGNATURE ) {
828             PKT_signature *sig = node->pkt->pkt.signature;
829             int sigrc;
830             char *sigstr;
831
832             if( !any ) { /* no user id, (maybe a revocation follows)*/
833                 if( sig->sig_class == 0x20 )
834                     fputs("[revoked]:", stdout);
835                 else if( sig->sig_class == 0x18 )
836                     fputs("[key binding]:", stdout);
837                 else if( sig->sig_class == 0x28 )
838                     fputs("[subkey revoked]:", stdout);
839                 else
840                     putchar (':');
841                 putchar(':');
842                 print_capabilities (pk, sk, keyblock);
843                 putchar('\n');
844                 if( fpr )
845                     print_fingerprint( pk, sk, 0 );
846                 any=1;
847             }
848
849             if( sig->sig_class == 0x20 || sig->sig_class == 0x28
850                                        || sig->sig_class == 0x30 )
851                sigstr = "rev";
852             else if( (sig->sig_class&~3) == 0x10 )
853                sigstr = "sig";
854             else if( sig->sig_class == 0x18 )
855                sigstr = "sig";
856             else if( sig->sig_class == 0x1F )
857                sigstr = "sig";
858             else {
859                 printf ("sig::::::::::%02x%c:\n",
860                         sig->sig_class, sig->flags.exportable?'x':'l');
861                 continue;
862             }
863             if( opt.check_sigs ) {
864                 fflush(stdout);
865                 rc = check_key_signature( keyblock, node, NULL );
866                 switch( rc ) {
867                   case 0:                  sigrc = '!'; break;
868                   case G10ERR_BAD_SIGN:    sigrc = '-'; break;
869                   case G10ERR_NO_PUBKEY: 
870                   case G10ERR_UNU_PUBKEY:  sigrc = '?'; break;
871                   default:                 sigrc = '%'; break;
872                 }
873             }
874             else {
875                 rc = 0;
876                 sigrc = ' ';
877             }
878             fputs( sigstr, stdout );
879             putchar(':');
880             if( sigrc != ' ' )
881                 putchar(sigrc);
882             printf("::%d:%08lX%08lX:%s:%s:::", sig->pubkey_algo,
883                                                  (ulong)sig->keyid[0],
884                            (ulong)sig->keyid[1], colon_datestr_from_sig(sig),
885                            colon_expirestr_from_sig(sig));
886             if( sigrc == '%' )
887                 printf("[%s] ", g10_errstr(rc) );
888             else if( sigrc == '?' )
889                 ;
890             else if ( !opt.fast_list_mode ) {
891                 size_t n;
892                 char *p = get_user_id( sig->keyid, &n );
893                 print_string( stdout, p, n, ':' );
894                 m_free(p);
895             }
896             printf(":%02x%c:\n", sig->sig_class,sig->flags.exportable?'x':'l');
897             /* fixme: check or list other sigs here */
898         }
899     }
900     if( !any ) {/* oops, no user id */
901         putchar(':');
902         putchar(':');
903         print_capabilities (pk, sk, keyblock);
904         putchar('\n');
905     }
906 }
907
908 /*
909  * Reorder the keyblock so that the primary user ID (and not attribute
910  * packet) comes first.  Fixme: Replace this by a generic sort
911  * function.  */
912 static void
913 reorder_keyblock (KBNODE keyblock)
914 {
915     KBNODE primary = NULL, primary0 = NULL, primary2 = NULL;
916     KBNODE last, node;
917
918     for (node=keyblock; node; primary0=node, node = node->next) {
919         if( node->pkt->pkttype == PKT_USER_ID &&
920             !node->pkt->pkt.user_id->attrib_data &&
921             node->pkt->pkt.user_id->is_primary ) {
922             primary = primary2 = node;
923             for (node=node->next; node; primary2=node, node = node->next ) {
924                 if( node->pkt->pkttype == PKT_USER_ID 
925                     || node->pkt->pkttype == PKT_PUBLIC_SUBKEY 
926                     || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
927                     break;
928                 }
929             }
930             break;
931         }
932     }
933     if ( !primary )
934         return;  /* no primary key flag found (should not happen) */
935
936     for (last=NULL, node=keyblock; node; last = node, node = node->next) {
937         if( node->pkt->pkttype == PKT_USER_ID )
938             break;
939     }
940     assert (node);
941     assert (last); /* the user ID is never the first packet */
942     assert (primary0);  /* ditto (this is the node before primary) */
943     if ( node == primary )
944         return; /* already the first one */
945
946     last->next = primary;
947     primary0->next = primary2->next;
948     primary2->next = node;
949 }
950
951 void
952 list_keyblock( KBNODE keyblock, int secret, int fpr, void *opaque )
953 {
954     reorder_keyblock (keyblock);
955     if (opt.with_colons)
956         list_keyblock_colon (keyblock, secret, fpr );
957     else
958         list_keyblock_print (keyblock, secret, fpr, opaque );
959 }
960
961 /*
962  * standard function to print the finperprint.
963  * mode 0: as used in key listings, opt.with_colons is honored
964  *      1: print using log_info ()
965  *      2: direct use of tty
966  *      3: direct use of tty but only primary key.
967  * modes 1 and 2 will try and print both subkey and primary key fingerprints
968  */
969 void
970 print_fingerprint (PKT_public_key *pk, PKT_secret_key *sk, int mode )
971 {
972     byte array[MAX_FINGERPRINT_LEN], *p;
973     size_t i, n;
974     FILE *fp;
975     const char *text;
976     int primary=0;
977
978     if(sk)
979       {
980         if(sk->main_keyid[0]==sk->keyid[0] && sk->main_keyid[1]==sk->keyid[1])
981           primary=1;
982       }
983     else
984       {
985         if(pk->main_keyid[0]==pk->keyid[0] && pk->main_keyid[1]==pk->keyid[1])
986           primary=1;
987       }
988
989     /* Just to be safe */
990     if(mode&0x80 && !primary)
991       {
992         log_error("primary key is not really primary!\n");
993         return;
994       }
995
996     mode&=~0x80;
997
998     if(!primary && (mode==1 || mode==2))
999       {
1000         if(sk)
1001           {
1002             PKT_secret_key *primary_sk=m_alloc_clear(sizeof(*primary_sk));
1003             get_seckey(primary_sk,sk->main_keyid);
1004             print_fingerprint(NULL,primary_sk,mode|0x80);
1005             free_secret_key(primary_sk);
1006           }
1007         else
1008           {
1009             PKT_public_key *primary_pk=m_alloc_clear(sizeof(*primary_pk));
1010             get_pubkey(primary_pk,pk->main_keyid);
1011             print_fingerprint(primary_pk,NULL,mode|0x80);
1012             free_public_key(primary_pk);
1013           }
1014       }
1015
1016     if (mode == 1) {
1017         fp = log_stream ();
1018         if(primary)
1019           text = _("Primary key fingerprint:");
1020         else
1021           text = _("     Subkey fingerprint:");
1022     }
1023     else if (mode == 2) {
1024         fp = NULL; /* use tty */
1025         /* Translators: this should fit into 24 bytes to that the fingerprint
1026          * data is properly aligned with the user ID */
1027         if(primary)
1028           text = _(" Primary key fingerprint:");
1029         else
1030           text = _("      Subkey fingerprint:");
1031     }
1032     else if (mode == 3) {
1033         fp = NULL; /* use tty */
1034         text = _("     Key fingerprint =");
1035     }
1036     else {
1037         fp = stdout;
1038         text = _("     Key fingerprint =");
1039     }
1040   
1041     if (sk)
1042         fingerprint_from_sk (sk, array, &n);
1043     else
1044         fingerprint_from_pk (pk, array, &n);
1045     p = array;
1046     if (opt.with_colons && !mode) {
1047         fprintf (fp, "fpr:::::::::");
1048         for (i=0; i < n ; i++, p++ )
1049             fprintf (fp, "%02X", *p );
1050         putc(':', fp);
1051     }
1052     else {
1053         if (fp)
1054             fputs (text, fp);
1055         else
1056             tty_printf ("%s", text);
1057         if (n == 20) {
1058             for (i=0; i < n ; i++, i++, p += 2 ) {
1059                 if (fp) {
1060                     if (i == 10 )
1061                         putc(' ', fp);
1062                     fprintf (fp, " %02X%02X", *p, p[1] );
1063                 }
1064                 else {
1065                     if (i == 10 )
1066                         tty_printf (" ");
1067                     tty_printf (" %02X%02X", *p, p[1]);
1068                 }
1069             }
1070         }
1071         else {
1072             for (i=0; i < n ; i++, p++ ) {
1073                 if (fp) {
1074                     if (i && !(i%8) )
1075                         putc (' ', fp);
1076                     fprintf (fp, " %02X", *p );
1077                 }
1078                 else {
1079                     if (i && !(i%8) )
1080                         tty_printf (" ");
1081                     tty_printf (" %02X", *p );
1082                 }
1083             }
1084         }
1085     }
1086     if (fp)
1087         putc ('\n', fp);
1088     else
1089         tty_printf ("\n");
1090 }
1091
1092 void set_attrib_fd(int fd)
1093 {
1094   static int last_fd=-1;
1095
1096   if ( fd != -1 && last_fd == fd )
1097     return;
1098
1099   if ( attrib_fp && attrib_fp != stdout && attrib_fp != stderr )
1100     fclose (attrib_fp);
1101   attrib_fp = NULL;
1102   if ( fd == -1 ) 
1103     return;
1104
1105   if( fd == 1 )
1106     attrib_fp = stdout;
1107   else if( fd == 2 )
1108     attrib_fp = stderr;
1109   else
1110     attrib_fp = fdopen( fd, "w" );
1111   if( !attrib_fp ) {
1112     log_fatal("can't open fd %d for attribute output: %s\n",
1113               fd, strerror(errno));
1114   }
1115   last_fd = fd;
1116 }