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