Fix for bug 537
[gnupg.git] / g10 / keylist.c
index f5578c2..95d452e 100644 (file)
@@ -1,6 +1,6 @@
-/* keylist.c
+/* keylist.c - print keys
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
- *               2004 Free Software Foundation, Inc.
+ *               2004, 2005 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -16,7 +16,8 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
  */
 
 #include <config.h>
 #include <errno.h>
 #include <assert.h>
 
+#include "gpg.h"
 #include "options.h"
 #include "packet.h"
 #include "errors.h"
 #include "keydb.h"
-#include "memory.h"
 #include "photoid.h"
 #include "util.h"
 #include "ttyio.h"
@@ -40,7 +41,7 @@
 #include "status.h"
 
 static void list_all(int);
-static void list_one( STRLIST names, int secret);
+static void list_one( strlist_t names, int secret);
 static void print_card_serialno (PKT_secret_key *sk);
 
 struct sig_stats
@@ -57,7 +58,7 @@ static FILE *attrib_fp=NULL;
  * If list is NULL, all available keys are listed
  */
 void
-public_key_list( STRLIST list )
+public_key_list( strlist_t list )
 {
   if(opt.with_colons)
     {
@@ -95,6 +96,13 @@ public_key_list( STRLIST list )
       printf("\n");
     }
 
+  /* We need to do the stale check right here because it might need to
+     update the keyring while we already have the keyring open.  This
+     is very bad for W32 because of a sharing violation. For real OSes
+     it might lead to false results if we are later listing a keyring
+     which is associated with the inode of a deleted file.  */
+  check_trustdb_stale ();
+
   if( !list )
     list_all(0);
   else
@@ -102,8 +110,10 @@ public_key_list( STRLIST list )
 }
 
 void
-secret_key_list( STRLIST list )
+secret_key_list( strlist_t list )
 {
+    check_trustdb_stale ();
+
     if( !list )
        list_all(1);
     else  /* List by user id */
@@ -124,7 +134,7 @@ print_seckey_info (PKT_secret_key *sk)
              pubkey_letter (sk->pubkey_algo),
              keystr(keyid), datestr_from_sk (sk), p);
     
-  m_free (p);
+  xfree (p);
 }
 
 /* Print information about the public key.  With FP passed as NULL,
@@ -155,7 +165,76 @@ print_pubkey_info (FILE *fp, PKT_public_key *pk)
                 nbits_from_pk (pk), pubkey_letter (pk->pubkey_algo),
                 keystr(keyid), datestr_from_pk (pk), p);
 
-  m_free (p);
+  xfree (p);
+}
+
+
+/* Print basic information of a secret key including the card serial
+   number information. */
+void
+print_card_key_info (FILE *fp, KBNODE keyblock)
+{
+  KBNODE node;
+  int i;
+
+  for (node = keyblock; node; node = node->next ) 
+    {
+      if (node->pkt->pkttype == PKT_SECRET_KEY
+          || (node->pkt->pkttype == PKT_SECRET_SUBKEY) )
+        {
+          PKT_secret_key *sk = node->pkt->pkt.secret_key;
+          
+          tty_fprintf (fp, "%s%c  %4u%c/%s  ",
+                      node->pkt->pkttype == PKT_SECRET_KEY? "sec":"ssb",
+                       (sk->protect.s2k.mode==1001)?'#':
+                       (sk->protect.s2k.mode==1002)?'>':' ',
+                      nbits_from_sk (sk),
+                      pubkey_letter (sk->pubkey_algo),
+                      keystr_from_sk(sk));
+          tty_fprintf (fp, _("created: %s"), datestr_from_sk (sk));
+          tty_fprintf (fp, "  ");
+          tty_fprintf (fp, _("expires: %s"), expirestr_from_sk (sk));
+          if (sk->is_protected && sk->protect.s2k.mode == 1002)
+            {
+              tty_fprintf (fp, "\n                      ");
+              tty_fprintf (fp, _("card-no: ")); 
+              if (sk->protect.ivlen == 16
+                  && !memcmp (sk->protect.iv, "\xD2\x76\x00\x01\x24\x01", 6))
+                { 
+                  /* This is an OpenPGP card. */
+                  for (i=8; i < 14; i++)
+                    {
+                      if (i == 10)
+                        tty_fprintf (fp, " ");
+                      tty_fprintf (fp, "%02X", sk->protect.iv[i]);
+                    }
+                }
+              else
+                { /* Something is wrong: Print all. */
+                  for (i=0; i < sk->protect.ivlen; i++)
+                    tty_fprintf (fp, "%02X", sk->protect.iv[i]);
+                }
+            }
+          tty_fprintf (fp, "\n");
+        }
+    }
+}
+
+
+
+/* Flags = 0x01 hashed 0x02 critical */
+static void
+status_one_subpacket(sigsubpkttype_t type,size_t len,int flags,const byte *buf)
+{
+  char status[40];
+
+  /* Don't print these. */
+  if(len>256)
+    return;
+
+  sprintf(status,"%d %u %u ",type,flags,(unsigned int)len);
+
+  write_status_text_and_buffer(STATUS_SIG_SUBPACKET,status,buf,len,0);
 }
 
 /*
@@ -170,7 +249,7 @@ show_policy_url(PKT_signature *sig,int indent,int mode)
   const byte *p;
   size_t len;
   int seq=0,crit;
-  FILE *fp=mode?log_stream():stdout;
+  FILE *fp=mode?log_get_stream():stdout;
 
   while((p=enum_sig_subpkt(sig->hashed,SIGSUBPKT_POLICY,&len,&seq,&crit)))
     {
@@ -211,7 +290,7 @@ show_keyserver_url(PKT_signature *sig,int indent,int mode)
   const byte *p;
   size_t len;
   int seq=0,crit;
-  FILE *fp=mode?log_stream():stdout;
+  FILE *fp=mode?log_get_stream():stdout;
 
   while((p=enum_sig_subpkt(sig->hashed,SIGSUBPKT_PREF_KS,&len,&seq,&crit)))
     {
@@ -235,7 +314,8 @@ show_keyserver_url(PKT_signature *sig,int indent,int mode)
          fprintf(fp,"\n");
        }
 
-      /* TODO: put in a status-fd tag for preferred keyservers */
+      if(mode)
+       status_one_subpacket(SIGSUBPKT_PREF_KS,len,(crit?0x02:0)|0x01,p);
     }
 }
 
@@ -252,71 +332,55 @@ show_keyserver_url(PKT_signature *sig,int indent,int mode)
 void
 show_notation(PKT_signature *sig,int indent,int mode,int which)
 {
-  const byte *p;
-  size_t len;
-  int seq=0,crit;
-  FILE *fp=mode?log_stream():stdout;
+  FILE *fp=mode?log_get_stream():stdout;
+  struct notation *nd,*notations;
 
   if(which==0)
     which=3;
 
-  /* There may be multiple notations in the same sig. */
-
-  while((p=enum_sig_subpkt(sig->hashed,SIGSUBPKT_NOTATION,&len,&seq,&crit)))
-    if(len>=8)
-      {
-       int n1,n2;
-
-       n1=(p[4]<<8)|p[5];
-       n2=(p[6]<<8)|p[7];
-
-       if(8+n1+n2!=len)
-         {
-           log_info(_("WARNING: invalid notation data found\n"));
-           continue;
-         }
+  notations=sig_to_notation(sig);
 
-       if(mode!=2)
-         {
-           int has_at=!!memchr(p+8,'@',n1);
+  /* There may be multiple notations in the same sig. */
+  for(nd=notations;nd;nd=nd->next)
+    {
+      if(mode!=2)
+       {
+         int has_at=!!strchr(nd->name,'@');
+
+         if((which&1 && !has_at) || (which&2 && has_at))
+           {
+             int i;
+             const char *str;
+
+             for(i=0;i<indent;i++)
+               putchar(' ');
+
+             if(nd->flags.critical)
+               str=_("Critical signature notation: ");
+             else
+               str=_("Signature notation: ");
+             if(mode)
+               log_info("%s",str);
+             else
+               printf("%s",str);
+             /* This is all UTF8 */
+             print_utf8_string(fp,nd->name,strlen(nd->name));
+             fprintf(fp,"=");
+             print_utf8_string(fp,nd->value,strlen(nd->value));
+             fprintf(fp,"\n");
+           }
+       }
 
-           if((which&1 && !has_at) || (which&2 && has_at))
-             {
-               int i;
-               const char *str;
-
-               for(i=0;i<indent;i++)
-                 putchar(' ');
-
-               /* This is UTF8 */
-               if(crit)
-                 str=_("Critical signature notation: ");
-               else
-                 str=_("Signature notation: ");
-               if(mode)
-                 log_info("%s",str);
-               else
-                 printf("%s",str);
-               print_utf8_string(fp,p+8,n1);
-               fprintf(fp,"=");
-
-               if(*p&0x80)
-                 print_utf8_string(fp,p+8+n1,n2);
-               else
-                 fprintf(fp,"[ %s ]",_("not human readable"));
-
-               fprintf(fp,"\n");
-             }
-         }
+      if(mode)
+       {
+         write_status_buffer(STATUS_NOTATION_NAME,
+                             nd->name,strlen(nd->name),0);
+         write_status_buffer(STATUS_NOTATION_DATA,
+                             nd->value,strlen(nd->value),50);
+       }
+    }
 
-       if(mode)
-         {
-           write_status_buffer ( STATUS_NOTATION_NAME, p+8   , n1, 0 );
-           write_status_buffer ( STATUS_NOTATION_DATA, p+8+n1, n2, 50 );
-         }
-      }
-  else
-    log_info(_("WARNING: invalid notation data found\n"));
+  free_notation(notations);
 }
 
 static void
@@ -398,7 +462,7 @@ list_all( int secret )
 
 
 static void
-list_one( STRLIST names, int secret )
+list_one( strlist_t names, int secret )
 {
     int rc = 0;
     KBNODE keyblock = NULL;
@@ -564,7 +628,7 @@ print_one_subpacket(sigsubpkttype_t type,size_t len,int flags,const byte *buf)
 {
   size_t i;
 
-  printf("spk:%d:%u:%u:",type,flags,len);
+  printf("spk:%d:%u:%u:",type,flags,(unsigned int)len);
 
   for(i=0;i<len;i++)
     {
@@ -651,7 +715,6 @@ list_keyblock_print ( KBNODE keyblock, int secret, int fpr, void *opaque )
     KBNODE node;
     PKT_public_key *pk;
     PKT_secret_key *sk;
-    int any=0;
     struct sig_stats *stats=opaque;
     int skip_sigs=0;
 
@@ -711,7 +774,7 @@ list_keyblock_print ( KBNODE keyblock, int secret, int fpr, void *opaque )
        else if(pk->has_expired)
          {
            printf(" [");
-           printf(_("expired: %s)"),expirestr_from_pk(pk));
+           printf(_("expired: %s"),expirestr_from_pk(pk));
            printf("]");
          }
        else if(pk->expiredate)
@@ -735,11 +798,17 @@ list_keyblock_print ( KBNODE keyblock, int secret, int fpr, void *opaque )
        printf("\n");
       }
 
+    if( fpr )
+      print_fingerprint( pk, sk, 0 );
+    print_card_serialno (sk);
+    if( opt.with_key_data )
+      print_key_data( pk );
+
     for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
        if( node->pkt->pkttype == PKT_USER_ID && !opt.fast_list_mode ) {
            PKT_user_id *uid=node->pkt->pkt.user_id;
 
-           if((uid->is_expired || uid->is_revoked)
+           if(pk && (uid->is_expired || uid->is_revoked)
               && !(opt.list_options&LIST_SHOW_UNUSABLE_UIDS))
              {
                skip_sigs=1;
@@ -757,33 +826,19 @@ list_keyblock_print ( KBNODE keyblock, int secret, int fpr, void *opaque )
                const char *validity;
                int indent;
 
-               if(uid->is_revoked)
-                 validity=_("revoked");
-               else if(uid->is_expired)
-                 validity=_("expired");
-               else
-                 validity=trust_value_to_string(get_validity(pk,uid));
-
-               indent=(keystrlen()+7)-strlen(validity);
+               validity=uid_trust_string_fixed(pk,uid);
+               indent=(keystrlen()+9)-atoi(uid_trust_string_fixed(NULL,NULL));
 
-               if(indent<0)
+               if(indent<0 || indent>40)
                  indent=0;
 
-               printf("uid%*s[%s] ",indent,"",validity);
+               printf("uid%*s%s ",indent,"",validity);
              }
            else
-             printf("uid%*s",keystrlen()+10,"");
+             printf("uid%*s", (int)keystrlen()+10,"");
 
             print_utf8_string( stdout, uid->name, uid->len );
            putchar('\n');
-           if( !any ) {
-               if( fpr )
-                   print_fingerprint( pk, sk, 0 );
-                print_card_serialno (sk);
-               if( opt.with_key_data )
-                   print_key_data( pk );
-               any = 1;
-           }
 
            if((opt.list_options&LIST_SHOW_PHOTOS) && uid->attribs!=NULL)
              show_photos(uid->attribs,uid->numattribs,pk,sk);
@@ -801,14 +856,6 @@ list_keyblock_print ( KBNODE keyblock, int secret, int fpr, void *opaque )
            else
              skip_sigs=0;
 
-           if( !any )
-             {
-               putchar('\n');
-               if( fpr )
-                 print_fingerprint( pk, sk, 0 ); /* of the main key */
-               any = 1;
-             }
-
             printf("sub   %4u%c/%s %s",
                   nbits_from_pk( pk2 ),pubkey_letter( pk2->pubkey_algo ),
                   keystr_from_pk(pk2),datestr_from_pk(pk2));
@@ -840,15 +887,6 @@ list_keyblock_print ( KBNODE keyblock, int secret, int fpr, void *opaque )
          {
            PKT_secret_key *sk2 = node->pkt->pkt.secret_key;
 
-           if( !any )
-             {
-               putchar('\n');
-               if( fpr )
-                 print_fingerprint( pk, sk, 0 ); /* of the main key */
-                print_card_serialno (sk);
-               any = 1;
-             }
-
             printf("ssb%c  %4u%c/%s %s",
                    (sk2->protect.s2k.mode==1001)?'#':
                    (sk2->protect.s2k.mode==1002)?'>':' ',
@@ -877,12 +915,13 @@ list_keyblock_print ( KBNODE keyblock, int secret, int fpr, void *opaque )
            if( stats ) {
                 /*fflush(stdout);*/
                rc = check_key_signature( keyblock, node, NULL );
-               switch( rc ) {
-                case 0:                 sigrc = '!'; break;
-                case G10ERR_BAD_SIGN:   stats->inv_sigs++; sigrc = '-'; break;
-                case G10ERR_NO_PUBKEY: 
-                case G10ERR_UNU_PUBKEY: stats->no_key++; continue;
-                default:                stats->oth_err++; sigrc = '%'; break;
+               switch( gpg_err_code (rc) ) {
+                case 0:                sigrc = '!'; break;
+                case GPG_ERR_BAD_SIGNATURE:
+                   stats->inv_sigs++; sigrc = '-'; break;
+                case GPG_ERR_NO_PUBKEY: 
+                case GPG_ERR_UNUSABLE_PUBKEY: stats->no_key++; continue;
+                default:               stats->oth_err++; sigrc = '%'; break;
                }
 
                /* TODO: Make sure a cached sig record here still has
@@ -894,25 +933,6 @@ list_keyblock_print ( KBNODE keyblock, int secret, int fpr, void *opaque )
                sigrc = ' ';
            }
 
-           if( !any ) { /* no user id, (maybe a revocation follows)*/
-             /* Check if the pk is really revoked - there could be a
-                 0x20 sig packet there even if we are not revoked
-                 (say, if a revocation key issued the packet, but the
-                 revocation key isn't present to verify it.) */
-               if( sig->sig_class == 0x20 && pk->is_revoked )
-                   puts("[revoked]");
-               else if( sig->sig_class == 0x18 )
-                   puts("[key binding]");
-               else if( sig->sig_class == 0x28 )
-                   puts("[subkey revoked]");
-               else
-                   putchar('\n');
-               if( fpr )
-                   print_fingerprint( pk, sk, 0 );
-                print_card_serialno (sk);
-               any=1;
-           }
-
            if( sig->sig_class == 0x20 || sig->sig_class == 0x28
                                       || sig->sig_class == 0x30 )
               sigstr = "rev";
@@ -951,7 +971,7 @@ list_keyblock_print ( KBNODE keyblock, int secret, int fpr, void *opaque )
                size_t n;
                char *p = get_user_id( sig->keyid, &n );
                 print_utf8_string( stdout, p, n );
-               m_free(p);
+               xfree(p);
            }
            putchar('\n');
 
@@ -974,6 +994,29 @@ list_keyblock_print ( KBNODE keyblock, int secret, int fpr, void *opaque )
     putchar('\n');
 }
 
+void
+print_revokers(PKT_public_key *pk)
+{
+  /* print the revoker record */
+  if( !pk->revkey && pk->numrevkeys )
+    BUG();
+  else
+    {
+      int i,j;
+
+      for (i=0; i < pk->numrevkeys; i++)
+       {
+         byte *p;
+
+         printf ("rvk:::%d::::::", pk->revkey[i].algid);
+         p = pk->revkey[i].fpr;
+         for (j=0; j < 20; j++, p++ )
+           printf ("%02X", *p);
+         printf (":%02x%s:\n", pk->revkey[i].class,
+                 (pk->revkey[i].class&0x40)?"s":"");
+       }
+    }
+}
 
 static void
 list_keyblock_colon( KBNODE keyblock, int secret, int fpr )
@@ -1038,7 +1081,7 @@ list_keyblock_colon( KBNODE keyblock, int secret, int fpr )
             putchar( get_ownertrust_info(pk) );
            putchar(':');
     }
-    
+
     if (opt.fixed_list_mode) {
         /* do not merge the first uid with the primary key */
         putchar(':');
@@ -1059,6 +1102,8 @@ list_keyblock_colon( KBNODE keyblock, int secret, int fpr )
           putchar(':'); /* End of field 15. */
         }
         putchar('\n');
+       if(pk)
+         print_revokers(pk);
         if( fpr )
             print_fingerprint( pk, sk, 0 );
         if( opt.with_key_data )
@@ -1066,7 +1111,6 @@ list_keyblock_colon( KBNODE keyblock, int secret, int fpr )
         any = 1;
     }
 
-
     for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
        if( node->pkt->pkttype == PKT_USER_ID && !opt.fast_list_mode ) {
            PKT_user_id *uid=node->pkt->pkt.user_id;
@@ -1258,16 +1302,16 @@ list_keyblock_colon( KBNODE keyblock, int secret, int fpr )
 
                fflush(stdout);
                if(opt.no_sig_cache)
-                 signer_pk=m_alloc_clear(sizeof(PKT_public_key));
+                 signer_pk=xmalloc_clear(sizeof(PKT_public_key));
 
                rc = check_key_signature2( keyblock, node, NULL, signer_pk,
                                           NULL, NULL, NULL );
-               switch( rc ) {
-                 case 0:                  sigrc = '!'; break;
-                 case G10ERR_BAD_SIGN:    sigrc = '-'; break;
-                 case G10ERR_NO_PUBKEY: 
-                 case G10ERR_UNU_PUBKEY:  sigrc = '?'; break;
-                 default:                 sigrc = '%'; break;
+               switch ( gpg_err_code (rc) ) {
+                 case 0:                       sigrc = '!'; break;
+                 case GPG_ERR_BAD_SIGNATURE:   sigrc = '-'; break;
+                 case GPG_ERR_NO_PUBKEY: 
+                 case GPG_ERR_UNUSABLE_PUBKEY: sigrc = '?'; break;
+                 default:                      sigrc = '%'; break;
                }
 
                if(opt.no_sig_cache)
@@ -1310,7 +1354,7 @@ list_keyblock_colon( KBNODE keyblock, int secret, int fpr )
                size_t n;
                char *p = get_user_id( sig->keyid, &n );
                 print_string( stdout, p, n, ':' );
-               m_free(p);
+               xfree(p);
            }
             printf(":%02x%c:", sig->sig_class,sig->flags.exportable?'x':'l');
 
@@ -1344,15 +1388,16 @@ list_keyblock_colon( KBNODE keyblock, int secret, int fpr )
  * Reorder the keyblock so that the primary user ID (and not attribute
  * packet) comes first.  Fixme: Replace this by a generic sort
  * function.  */
-void
-reorder_keyblock (KBNODE keyblock)
+static void
+do_reorder_keyblock (KBNODE keyblock,int attr)
 {
     KBNODE primary = NULL, primary0 = NULL, primary2 = NULL;
     KBNODE last, node;
 
     for (node=keyblock; node; primary0=node, node = node->next) {
        if( node->pkt->pkttype == PKT_USER_ID &&
-           !node->pkt->pkt.user_id->attrib_data &&
+           ((attr && node->pkt->pkt.user_id->attrib_data) ||
+            (!attr && !node->pkt->pkt.user_id->attrib_data)) &&
             node->pkt->pkt.user_id->is_primary ) {
             primary = primary2 = node;
             for (node=node->next; node; primary2=node, node = node->next ) {
@@ -1384,6 +1429,13 @@ reorder_keyblock (KBNODE keyblock)
 }
 
 void
+reorder_keyblock (KBNODE keyblock)
+{
+  do_reorder_keyblock(keyblock,1);
+  do_reorder_keyblock(keyblock,0);
+}
+
+void
 list_keyblock( KBNODE keyblock, int secret, int fpr, void *opaque )
 {
     reorder_keyblock (keyblock);
@@ -1434,14 +1486,14 @@ print_fingerprint (PKT_public_key *pk, PKT_secret_key *sk, int mode )
       {
        if(sk)
          {
-           PKT_secret_key *primary_sk=m_alloc_clear(sizeof(*primary_sk));
+           PKT_secret_key *primary_sk=xmalloc_clear(sizeof(*primary_sk));
            get_seckey(primary_sk,sk->main_keyid);
            print_fingerprint(NULL,primary_sk,mode|0x80);
            free_secret_key(primary_sk);
          }
        else
          {
-           PKT_public_key *primary_pk=m_alloc_clear(sizeof(*primary_pk));
+           PKT_public_key *primary_pk=xmalloc_clear(sizeof(*primary_pk));
            get_pubkey(primary_pk,pk->main_keyid);
            print_fingerprint(primary_pk,NULL,mode|0x80);
            free_public_key(primary_pk);
@@ -1449,7 +1501,7 @@ print_fingerprint (PKT_public_key *pk, PKT_secret_key *sk, int mode )
       }
 
     if (mode == 1) {
-        fp = log_stream ();
+        fp = log_get_stream ();
        if(primary)
          text = _("Primary key fingerprint:");
        else
@@ -1457,9 +1509,9 @@ print_fingerprint (PKT_public_key *pk, PKT_secret_key *sk, int mode )
     }
     else if (mode == 2) {
         fp = NULL; /* use tty */
-        /* Translators: this should fit into 24 bytes to that the fingerprint
-         * data is properly aligned with the user ID */
        if(primary)
+          /* TRANSLATORS: this should fit into 24 bytes to that the
+           * fingerprint data is properly aligned with the user ID */
          text = _(" Primary key fingerprint:");
        else
          text = _("      Subkey fingerprint:");
@@ -1535,7 +1587,7 @@ print_card_serialno (PKT_secret_key *sk)
   if (!sk->is_protected || sk->protect.s2k.mode != 1002) 
     return; /* Not a card. */
   if (opt.with_colons)
-    return; /* Handled elesewhere. */
+    return; /* Handled elsewhere. */
 
   fputs (_("      Card serial no. ="), stdout);
   putchar (' ');