Example #1
0
static void
list_one( STRLIST names, int secret )
{
    int rc = 0;
    KBNODE keyblock = NULL;
    GETKEY_CTX ctx;

    if( secret ) {
	rc = get_seckey_bynames( &ctx, NULL, names, &keyblock );
	if( rc ) {
	    log_error("error reading key: %s\n",  g10_errstr(rc) );
	    get_seckey_end( ctx );
	    return;
	}
	do {
	    list_keyblock( keyblock, 1 );
	    release_kbnode( keyblock );
	} while( !get_seckey_next( ctx, NULL, &keyblock ) );
	get_seckey_end( ctx );
    }
    else {
	rc = get_pubkey_bynames( &ctx, NULL, names, &keyblock );
	if( rc ) {
	    log_error("error reading key: %s\n", g10_errstr(rc) );
	    get_pubkey_end( ctx );
	    return;
	}
	do {
	    list_keyblock( keyblock, 0 );
	    release_kbnode( keyblock );
	} while( !get_pubkey_next( ctx, NULL, &keyblock ) );
	get_pubkey_end( ctx );
    }
}
Example #2
0
/*
 * Rebuild the caches of all key resources.
 */
void
keydb_rebuild_caches (int noisy)
{
  int i, rc;

  for (i=0; i < used_resources; i++)
    {
      if (all_resources[i].secret)
        continue;
      if (!keyring_is_writable (all_resources[i].token))
        continue;
      switch (all_resources[i].type)
        {
        case KEYDB_RESOURCE_TYPE_NONE: /* ignore */
        case KEYDB_RESOURCE_TYPE_KEYBOX: /* ignore */
          break;
        case KEYDB_RESOURCE_TYPE_KEYRING:
          rc = keyring_rebuild_cache (all_resources[i].token,noisy);
          if (rc)
            log_error (_("failed to rebuild keyring cache: %s\n"),
                       g10_errstr (rc));
          break;
        }
    }
}
static int
write_symkey_enc(STRING2KEY *symkey_s2k,DEK *symkey_dek,DEK *dek,IOBUF out)
{
  int rc,seskeylen=cipher_get_keylen(dek->algo)/8;

  PKT_symkey_enc *enc;
  byte enckey[33];
  PACKET pkt;

  enc=xmalloc_clear(sizeof(PKT_symkey_enc)+seskeylen+1);
  encode_seskey(symkey_dek,&dek,enckey);

  enc->version = 4;
  enc->cipher_algo = opt.s2k_cipher_algo;
  enc->s2k = *symkey_s2k;
  enc->seskeylen = seskeylen + 1; /* algo id */
  memcpy( enc->seskey, enckey, seskeylen + 1 );

  pkt.pkttype = PKT_SYMKEY_ENC;
  pkt.pkt.symkey_enc = enc;

  if((rc=build_packet(out,&pkt)))
    log_error("build symkey_enc packet failed: %s\n",g10_errstr(rc));

  xfree(enc);
  return rc;
}
Example #4
0
/****************
 * Delete a public or secret key from a keyring.
 */
int
delete_keys( STRLIST names, int secret, int allow_both )
{
    int rc, avail, force=(!allow_both && !secret && opt.expert);

    /* Force allows us to delete a public key even if a secret key
       exists. */

    for(; names; names=names->next) {
        rc = do_delete_key (names->d, secret, force, &avail );
        if ( rc && avail ) {
            if ( allow_both ) {
                rc = do_delete_key (names->d, 1, 0, &avail );
                if ( !rc )
                    rc = do_delete_key (names->d, 0, 0, &avail );
            }
            else {
                log_error(_(
                              "there is a secret key for public key \"%s\"!\n"),names->d);
                log_info(_(
                             "use option \"--delete-secret-keys\" to delete it first.\n"));
                write_status_text( STATUS_DELETE_PROBLEM, "2" );
                return rc;
            }
        }

        if(rc) {
            log_error("%s: delete key failed: %s\n", names->d, g10_errstr(rc) );
            return rc;
        }
    }

    return 0;
}
int
tdbio_delete_record( ulong recnum )
{
    TRUSTREC vr, rec;
    int rc;

    /* Must read the record fist, so we can drop it from the hash tables */
    rc = tdbio_read_record( recnum, &rec, 0 );
    if( rc )
	;
    else if( rec.rectype == RECTYPE_TRUST ) {
         rc = drop_from_hashtable( get_trusthashrec(),
				   rec.r.trust.fingerprint, 20, rec.recnum );
    }

    if( rc )
	return rc;

    /* now we can chnage it to a free record */
    rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
    if( rc )
	log_fatal( _("%s: error reading version record: %s\n"),
				       db_name, g10_errstr(rc) );

    rec.recnum = recnum;
    rec.rectype = RECTYPE_FREE;
    rec.r.free.next = vr.r.ver.firstfree;
    vr.r.ver.firstfree = recnum;
    rc = tdbio_write_record( &rec );
    if( !rc )
	rc = tdbio_write_record( &vr );
    return rc;
}
void
encode_crypt_files(int nfiles, char **files, STRLIST remusr)
{
  int rc = 0;

  if (opt.outfile)
    {
      log_error(_("--output doesn't work for this command\n"));
      return;        
    }
    
  if (!nfiles)
    {
      char line[2048];
      unsigned int lno = 0;
      while ( fgets(line, DIM(line), stdin) )
        {
          lno++;
          if (!*line || line[strlen(line)-1] != '\n')
            {
              log_error("input line %u too long or missing LF\n", lno);
              return;
            }
          line[strlen(line)-1] = '\0';
          print_file_status(STATUS_FILE_START, line, 2);
          if ( (rc = encode_crypt(line, remusr, 0)) )
            log_error("encryption of `%s' failed: %s\n",
                      print_fname_stdin(line), g10_errstr(rc) );
          write_status( STATUS_FILE_DONE );
          iobuf_ioctl( NULL, 2, 0, NULL); /* Invalidate entire cache. */
        }
    }
  else
    {
      while (nfiles--)
        {
          print_file_status(STATUS_FILE_START, *files, 2);
          if ( (rc = encode_crypt(*files, remusr, 0)) )
            log_error("encryption of `%s' failed: %s\n",
                      print_fname_stdin(*files), g10_errstr(rc) );
          write_status( STATUS_FILE_DONE );
          iobuf_ioctl( NULL, 2, 0, NULL); /* Invalidate entire cache. */
          files++;
        }
    }
}
Example #7
0
/****************
 * Make a hash value from the public key certificate
 */
void
hash_public_key( MD_HANDLE md, PKT_public_key *pk )
{
    PACKET pkt;
    int rc = 0;
    int ctb;
    ulong pktlen;
    int c;
    IOBUF a = iobuf_temp();
  #if 0
    FILE *fp = fopen("dump.pk", "a");
    int i=0;

    fprintf(fp, "\nHashing PK (v%d):\n", pk->version);
  #endif

    /* build the packet */
    init_packet(&pkt);
    pkt.pkttype = PKT_PUBLIC_KEY;
    pkt.pkt.public_key = pk;
    if( (rc = build_packet( a, &pkt )) )
	log_fatal("build public_key for hashing failed: %s\n", g10_errstr(rc));

    if( !(pk->version == 3 && pk->pubkey_algo == 16) ) {
	/* skip the constructed header but don't do this for our very old
	 * v3 ElG keys */
	ctb = iobuf_get_noeof(a);
	pktlen = 0;
	if( (ctb & 0x40) ) {
	    c = iobuf_get_noeof(a);
	    if( c < 192 )
		pktlen = c;
	    else if( c < 224 ) {
		pktlen = (c - 192) * 256;
		c = iobuf_get_noeof(a);
		pktlen += c + 192;
	    }
	    else if( c == 255 ) {
		pktlen	= iobuf_get_noeof(a) << 24;
		pktlen |= iobuf_get_noeof(a) << 16;
		pktlen |= iobuf_get_noeof(a) << 8;
		pktlen |= iobuf_get_noeof(a);
	    }
	}
	else {
	    int lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));
	    for( ; lenbytes; lenbytes-- ) {
		pktlen <<= 8;
		pktlen |= iobuf_get_noeof(a);
	    }
	}
	/* hash a header */
	md_putc( md, 0x99 );
	pktlen &= 0xffff; /* can't handle longer packets */
	md_putc( md, pktlen >> 8 );
	md_putc( md, pktlen & 0xff );
    }
byte
tdbio_read_model(void)
{
  TRUSTREC vr;
  int rc;
 
  rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
  if( rc )
    log_fatal( _("%s: error reading version record: %s\n"),
	       db_name, g10_errstr(rc) );
  return vr.r.ver.trust_model;
}
/****************
 * Return the nextstamp value.
 */
ulong
tdbio_read_nextcheck ()
{
    TRUSTREC vr;
    int rc;

    rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
    if( rc )
	log_fatal( _("%s: error reading version record: %s\n"),
						    db_name, g10_errstr(rc) );
    return vr.r.ver.nextcheck;
}
/* Return true when the stamp was actually changed. */
int
tdbio_write_nextcheck (ulong stamp)
{
    TRUSTREC vr;
    int rc;

    rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
    if( rc )
	log_fatal( _("%s: error reading version record: %s\n"),
				       db_name, g10_errstr(rc) );

    if (vr.r.ver.nextcheck == stamp)
      return 0;

    vr.r.ver.nextcheck = stamp;
    rc = tdbio_write_record( &vr );
    if( rc )
	log_fatal( _("%s: error writing version record: %s\n"),
				       db_name, g10_errstr(rc) );
    return 1;
}
Example #11
0
static void
list_all( int secret )
{
    KBPOS kbpos;
    KBNODE keyblock = NULL;
    int rc=0;
    int lastresno;

    rc = enum_keyblocks( secret? 5:0, &kbpos, &keyblock );
    if( rc ) {
	if( rc != -1 )
	    log_error("enum_keyblocks(open) failed: %s\n", g10_errstr(rc) );
	goto leave;
    }

    lastresno = -1;
    while( !(rc = enum_keyblocks( 1, &kbpos, &keyblock )) ) {
	if( lastresno != kbpos.resno ) {
	    const char *s = keyblock_resource_name( &kbpos );
	    int i;

	    lastresno = kbpos.resno;
	    printf("%s\n", s );
	    for(i=strlen(s); i; i-- )
		putchar('-');
	    putchar('\n');
	}
        merge_keys_and_selfsig( keyblock );
	list_keyblock( keyblock, secret );
	release_kbnode( keyblock ); keyblock = NULL;
    }

    if( rc && rc != -1 )
	log_error("enum_keyblocks(read) failed: %s\n", g10_errstr(rc));

  leave:
    enum_keyblocks( 2, &kbpos, &keyblock ); /* close */
    release_kbnode( keyblock );
}
/****************
 * Make a hashtable: type 0 = trust hash
 */
static void
create_hashtable( TRUSTREC *vr, int type )
{
    TRUSTREC rec;
    off_t offset;
    ulong recnum;
    int i, n, rc;

    offset = lseek( db_fd, 0, SEEK_END );
    if( offset == -1 )
	log_fatal("trustdb: lseek to end failed: %s\n", strerror(errno) );
    recnum = offset / TRUST_RECORD_LEN;
    assert(recnum); /* this is will never be the first record */

    if( !type )
	vr->r.ver.trusthashtbl = recnum;

    /* Now write the records */
    n = (256+ITEMS_PER_HTBL_RECORD-1) / ITEMS_PER_HTBL_RECORD;
    for(i=0; i < n; i++, recnum++ ) {
	 memset( &rec, 0, sizeof rec );
	 rec.rectype = RECTYPE_HTBL;
	 rec.recnum = recnum;
	 rc = tdbio_write_record( &rec );
	 if( rc )
	     log_fatal( _("%s: failed to create hashtable: %s\n"),
					db_name, g10_errstr(rc));
    }
    /* update the version record */
    rc = tdbio_write_record( vr );
    if( !rc )
	rc = tdbio_sync();
    if( rc )
	log_fatal( _("%s: error updating version record: %s\n"),
						  db_name, g10_errstr(rc));
}
Example #13
0
int
keyring_update_keyblock (KEYRING_HANDLE hd, KBNODE kb)
{
    int rc;

    if (!hd->found.kr)
        return -1; /* no successful prior search */

    if (hd->found.kr->readonly)
      return gpg_error (GPG_ERR_EACCES);

    if (!hd->found.n_packets) {
        /* need to know the number of packets - do a dummy get_keyblock*/
        rc = keyring_get_keyblock (hd, NULL);
        if (rc) {
            log_error ("re-reading keyblock failed: %s\n", g10_errstr (rc));
            return rc;
        }
        if (!hd->found.n_packets)
            BUG ();
    }

    /* The open iobuf isn't needed anymore and in fact is a problem when
       it comes to renaming the keyring files on some operating systems,
       so close it here */
    iobuf_close(hd->current.iobuf);
    hd->current.iobuf = NULL;

    /* do the update */
    rc = do_copy (3, hd->found.kr->fname, kb, hd->secret,
                  hd->found.offset, hd->found.n_packets );
    if (!rc) {
      if (!hd->secret && kr_offtbl)
        {
          update_offset_hash_table_from_kb (kr_offtbl, kb, 0);
        }
      /* better reset the found info */
      hd->found.kr = NULL;
      hd->found.offset = 0;
    }
    return rc;
}
/****************
 * Return the record number of the trusthash tbl or create a new one.
 */
static ulong
get_trusthashrec(void)
{
    static ulong trusthashtbl; /* record number of the trust hashtable */

    if( !trusthashtbl ) {
	TRUSTREC vr;
	int rc;

	rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
	if( rc )
	    log_fatal( _("%s: error reading version record: %s\n"),
					    db_name, g10_errstr(rc) );
	if( !vr.r.ver.trusthashtbl )
	    create_hashtable( &vr, 0 );

	trusthashtbl = vr.r.ver.trusthashtbl;
    }
    return trusthashtbl;
}
Example #15
0
int
keyring_delete_keyblock (KEYRING_HANDLE hd)
{
    int rc;

    if (!hd->found.kr)
        return -1; /* no successful prior search */

    if (hd->found.kr->readonly)
      return gpg_error (GPG_ERR_EACCES);

    if (!hd->found.n_packets) {
        /* need to know the number of packets - do a dummy get_keyblock*/
        rc = keyring_get_keyblock (hd, NULL);
        if (rc) {
            log_error ("re-reading keyblock failed: %s\n", g10_errstr (rc));
            return rc;
        }
        if (!hd->found.n_packets)
            BUG ();
    }

    /* close this one otherwise we will lose the position for
     * a next search.  Fixme: it would be better to adjust the position
     * after the write opertions.
     */
    iobuf_close (hd->current.iobuf);
    hd->current.iobuf = NULL;

    /* do the delete */
    rc = do_copy (2, hd->found.kr->fname, NULL, hd->secret,
                  hd->found.offset, hd->found.n_packets );
    if (!rc) {
        /* better reset the found info */
        hd->found.kr = NULL;
        hd->found.offset = 0;
        /* Delete is a rare operations, so we don't remove the keys
         * from the offset table */
    }
    return rc;
}
int
tdbio_db_matches_options()
{
  static int yes_no = -1;

  if( yes_no == -1 )
    {
      TRUSTREC vr;
      int rc;

      rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
      if( rc )
	log_fatal( _("%s: error reading version record: %s\n"),
		   db_name, g10_errstr(rc) );

      yes_no = vr.r.ver.marginals == opt.marginals_needed
	&& vr.r.ver.completes == opt.completes_needed
	&& vr.r.ver.cert_depth == opt.max_cert_depth
	&& vr.r.ver.trust_model == opt.trust_model;
    }

  return yes_no;
}
Example #17
0
int
write_comment( IOBUF out, const char *s )
{
    PACKET pkt;
    size_t n = strlen(s);
    int rc=0;

    pkt.pkttype = PKT_COMMENT;
    if( *s != '#' ) {
       pkt.pkt.comment = m_alloc( sizeof *pkt.pkt.comment + n );
       pkt.pkt.comment->len = n+1;
       *pkt.pkt.comment->data = '#';
       strcpy(pkt.pkt.comment->data+1, s);
    }
    else {
       pkt.pkt.comment = m_alloc( sizeof *pkt.pkt.comment + n - 1 );
       pkt.pkt.comment->len = n;
       strcpy(pkt.pkt.comment->data, s);
    }
    if( (rc = build_packet( out, &pkt )) )
	log_error("build_packet(comment) failed: %s\n", g10_errstr(rc) );
    free_packet( &pkt );
    return rc;
}
Example #18
0
/****************
 * Decrypt the data, specified by ED with the key DEK.
 */
int
decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek )
{
  decode_filter_ctx_t dfx;
  byte *p;
  int rc=0, c, i;
  byte temp[32];
  unsigned blocksize;
  unsigned nprefix;
  
  dfx = xtrycalloc (1, sizeof *dfx);
  if (!dfx)
    return gpg_error_from_syserror ();
  dfx->refcount = 1;

  if ( opt.verbose && !dek->algo_info_printed )
    {
      if (!openpgp_cipher_test_algo (dek->algo))
        log_info (_("%s encrypted data\n"), 
                  openpgp_cipher_algo_name (dek->algo));
      else
        log_info (_("encrypted with unknown algorithm %d\n"), dek->algo );
      dek->algo_info_printed = 1;
    }
  rc = openpgp_cipher_test_algo (dek->algo);
  if (rc)
    goto leave;
  blocksize = openpgp_cipher_get_algo_blklen (dek->algo);
  if ( !blocksize || blocksize > 16 )
    log_fatal ("unsupported blocksize %u\n", blocksize );
  nprefix = blocksize;
  if ( ed->len && ed->len < (nprefix+2) )
    BUG();

  if ( ed->mdc_method ) 
    {
      if (gcry_md_open (&dfx->mdc_hash, ed->mdc_method, 0 ))
        BUG ();
      if ( DBG_HASHING )
        gcry_md_start_debug (dfx->mdc_hash, "checkmdc");
    }

  rc = openpgp_cipher_open (&dfx->cipher_hd, dek->algo,
			    GCRY_CIPHER_MODE_CFB,
			    (GCRY_CIPHER_SECURE
			     | ((ed->mdc_method || dek->algo >= 100)?
				0 : GCRY_CIPHER_ENABLE_SYNC)));
  if (rc)
    {
      /* We should never get an error here cause we already checked
       * that the algorithm is available.  */
      BUG();
    }


  /* log_hexdump( "thekey", dek->key, dek->keylen );*/
  rc = gcry_cipher_setkey (dfx->cipher_hd, dek->key, dek->keylen);
  if ( gpg_err_code (rc) == GPG_ERR_WEAK_KEY )
    {
      log_info(_("WARNING: message was encrypted with"
                 " a weak key in the symmetric cipher.\n"));
      rc=0;
    }
  else if( rc )
    {
      log_error("key setup failed: %s\n", g10_errstr(rc) );
      goto leave;
    }

  if (!ed->buf) 
    {
      log_error(_("problem handling encrypted packet\n"));
      goto leave;
    }

  gcry_cipher_setiv (dfx->cipher_hd, NULL, 0);

  if ( ed->len )
    {
      for (i=0; i < (nprefix+2) && ed->len; i++, ed->len-- ) 
        {
          if ( (c=iobuf_get(ed->buf)) == -1 )
            break;
          else
            temp[i] = c;
        }
    }
  else 
    {
      for (i=0; i < (nprefix+2); i++ )
        if ( (c=iobuf_get(ed->buf)) == -1 )
          break;
        else
          temp[i] = c;
    }
  
  gcry_cipher_decrypt (dfx->cipher_hd, temp, nprefix+2, NULL, 0);
  gcry_cipher_sync (dfx->cipher_hd);
  p = temp;
  /* log_hexdump( "prefix", temp, nprefix+2 ); */
  if (dek->symmetric
      && (p[nprefix-2] != p[nprefix] || p[nprefix-1] != p[nprefix+1]) )
    {
      rc = gpg_error (GPG_ERR_BAD_KEY);
      goto leave;
    }
  
  if ( dfx->mdc_hash )
    gcry_md_write (dfx->mdc_hash, temp, nprefix+2);

  dfx->refcount++;
  if ( ed->mdc_method )
    iobuf_push_filter ( ed->buf, mdc_decode_filter, dfx );
  else
    iobuf_push_filter ( ed->buf, decode_filter, dfx );

  proc_packets ( procctx, ed->buf );
  ed->buf = NULL;
  if ( ed->mdc_method && dfx->eof_seen == 2 )
    rc = gpg_error (GPG_ERR_INV_PACKET);
  else if ( ed->mdc_method )
    { 
      /* We used to let parse-packet.c handle the MDC packet but this
         turned out to be a problem with compressed packets: With old
         style packets there is no length information available and
         the decompressor uses an implicit end.  However we can't know
         this implicit end beforehand (:-) and thus may feed the
         decompressor with more bytes than actually needed.  It would
         be possible to unread the extra bytes but due to our weird
         iobuf system any unread is non reliable due to filters
         already popped off.  The easy and sane solution is to care
         about the MDC packet only here and never pass it to the
         packet parser.  Fortunatley the OpenPGP spec requires a
         strict format for the MDC packet so that we know that 22
         bytes are appended.  */
      int datalen = gcry_md_get_algo_dlen (ed->mdc_method);

      assert (dfx->cipher_hd);
      assert (dfx->mdc_hash);
      gcry_cipher_decrypt (dfx->cipher_hd, dfx->defer, 22, NULL, 0);
      gcry_md_write (dfx->mdc_hash, dfx->defer, 2);
      gcry_md_final (dfx->mdc_hash);

      if (dfx->defer[0] != '\xd3' || dfx->defer[1] != '\x14' )
        {
          log_error("mdc_packet with invalid encoding\n");
          rc = gpg_error (GPG_ERR_INV_PACKET);
        }
      else if (datalen != 20
               || memcmp (gcry_md_read (dfx->mdc_hash, 0),
                          dfx->defer+2,datalen ))
        rc = gpg_error (GPG_ERR_BAD_SIGNATURE);
      /* log_printhex("MDC message:", dfx->defer, 22); */
      /* log_printhex("MDC calc:", gcry_md_read (dfx->mdc_hash,0), datalen); */
    }
  
  
 leave:
  release_dfx_context (dfx);
  return rc;
}
/*
 * Return the last found keyring.  Caller must free it.
 * The returned keyblock has the kbode flag bit 0 set for the node with
 * the public key used to locate the keyblock or flag bit 1 set for 
 * the user ID node.
 */
int
keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
{
    PACKET *pkt;
    int rc;
    KBNODE keyblock = NULL, node, lastnode;
    IOBUF a;
    int in_cert = 0;
    int pk_no = 0;
    int uid_no = 0;
    int save_mode;

    if (ret_kb)
        *ret_kb = NULL;

    if (!hd->found.kr)
        return -1; /* no successful search */

    a = iobuf_open (hd->found.kr->fname);
    if (!a)
      {
	log_error(_("can't open `%s'\n"), hd->found.kr->fname);
	return G10ERR_KEYRING_OPEN;
      }

    if (iobuf_seek (a, hd->found.offset) ) {
        log_error ("can't seek `%s'\n", hd->found.kr->fname);
	iobuf_close(a);
	return G10ERR_KEYRING_OPEN;
    }

    pkt = xmalloc (sizeof *pkt);
    init_packet (pkt);
    hd->found.n_packets = 0;;
    lastnode = NULL;
    save_mode = set_packet_list_mode(0);
    while ((rc=parse_packet (a, pkt)) != -1) {
        hd->found.n_packets++;
        if (rc == G10ERR_UNKNOWN_PACKET) {
	    free_packet (pkt);
	    init_packet (pkt);
	    continue;
	}
	if (rc) {  
            log_error ("keyring_get_keyblock: read error: %s\n",
                       g10_errstr(rc) );
            rc = G10ERR_INV_KEYRING;
            break;
        }
	if (pkt->pkttype == PKT_COMPRESSED) {
	    log_error ("skipped compressed packet in keyring\n");
	    free_packet(pkt);
	    init_packet(pkt);
	    continue;
        }

        if (in_cert && (pkt->pkttype == PKT_PUBLIC_KEY
                        || pkt->pkttype == PKT_SECRET_KEY)) {
            hd->found.n_packets--; /* fix counter */
            break; /* ready */
        }

        in_cert = 1;
        if (pkt->pkttype == PKT_RING_TRUST) {
            /*(this code is duplicated after the loop)*/
            if ( lastnode 
                 && lastnode->pkt->pkttype == PKT_SIGNATURE
                 && (pkt->pkt.ring_trust->sigcache & 1) ) {
                /* this is a ring trust packet with a checked signature 
                 * status cache following directly a signature paket.
                 * Set the cache status into that signature packet */
                PKT_signature *sig = lastnode->pkt->pkt.signature;
                
                sig->flags.checked = 1;
                sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2);
            }
            /* reset lastnode, so that we set the cache status only from
             * the ring trust packet immediately folling a signature */
            lastnode = NULL;
        }
        else {
            node = lastnode = new_kbnode (pkt);
            if (!keyblock)
                keyblock = node;
            else
                add_kbnode (keyblock, node);

            if ( pkt->pkttype == PKT_PUBLIC_KEY
                 || pkt->pkttype == PKT_PUBLIC_SUBKEY
                 || pkt->pkttype == PKT_SECRET_KEY
                 || pkt->pkttype == PKT_SECRET_SUBKEY) {
                if (++pk_no == hd->found.pk_no)
                    node->flag |= 1;
            }
            else if ( pkt->pkttype == PKT_USER_ID) {
                if (++uid_no == hd->found.uid_no)
                    node->flag |= 2;
            }
        }

        pkt = xmalloc (sizeof *pkt);
        init_packet(pkt);
    }
    set_packet_list_mode(save_mode);

    if (rc == -1 && keyblock) 
	rc = 0; /* got the entire keyblock */

    if (rc || !ret_kb)
	release_kbnode (keyblock);
    else {
        /*(duplicated form the loop body)*/
        if ( pkt && pkt->pkttype == PKT_RING_TRUST
             && lastnode 
             && lastnode->pkt->pkttype == PKT_SIGNATURE
             && (pkt->pkt.ring_trust->sigcache & 1) ) {
            PKT_signature *sig = lastnode->pkt->pkt.signature;
            sig->flags.checked = 1;
            sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2);
        }
	*ret_kb = keyblock;
    }
    free_packet (pkt);
    xfree (pkt);
    iobuf_close(a);

    /* Make sure that future search operations fail immediately when
     * we know that we are working on a invalid keyring 
     */
    if (rc == G10ERR_INV_KEYRING)
        hd->current.error = rc;

    return rc;
}
Example #20
0
CURLcode
curl_easy_perform(CURL *curl)
{
  int rc;
  CURLcode err=CURLE_OK;
  const char *errstr=NULL;
  char *proxy=NULL;
  struct http_srv srv;

  memset(&srv,0,sizeof(srv));

  /* Emulate the libcurl proxy behavior.  If the calling program set a
     proxy, use it.  If it didn't set a proxy or set it to NULL, check
     for one in the environment.  If the calling program explicitly
     set a null-string proxy the http code doesn't use a proxy at
     all. */

  if(curl->proxy)
    proxy=curl->proxy;
  else
    proxy=getenv(HTTP_PROXY_ENV);

  if(curl->srvtag)
    srv.srvtag=curl->srvtag;

  if(curl->flags.verbose)
    {
      fprintf(curl->errors,"* HTTP proxy is \"%s\"\n",proxy?proxy:"null");
      fprintf(curl->errors,"* HTTP URL is \"%s\"\n",curl->url);
      if(srv.srvtag)
	fprintf(curl->errors,
		"* SRV tag is \"%s\": host and port may be overridden\n",
		srv.srvtag);
      fprintf(curl->errors,"* HTTP auth is \"%s\"\n",
	      curl->auth?curl->auth:"null");
      fprintf(curl->errors,"* HTTP method is %s\n",
	      curl->flags.post?"POST":"GET");
    }

  if(curl->flags.post)
    {
      rc=http_open(&curl->hd,HTTP_REQ_POST,curl->url,curl->auth,0,proxy,
		   &srv,curl->headers?curl->headers->list:NULL);
      if(rc==0)
	{
	  char content_len[50];
	  unsigned int post_len=strlen(curl->postfields);

	  if(curl->flags.verbose && srv.used_server && srv.used_port)
	    fprintf (curl->errors, "* HTTP host:port post-SRV is \"%s:%hu\"\n",
		     srv.used_server, srv.used_port);

	  iobuf_writestr(curl->hd.fp_write,
			 "Content-Type: application/x-www-form-urlencoded\r\n");
	  sprintf(content_len,"Content-Length: %u\r\n",post_len);

	  iobuf_writestr(curl->hd.fp_write,content_len);

	  http_start_data(&curl->hd);
	  iobuf_write(curl->hd.fp_write,curl->postfields,post_len);
	  rc=http_wait_response(&curl->hd,&curl->status);
	  if(rc==0 && curl->flags.failonerror && curl->status>=300)
	    err=CURLE_HTTP_RETURNED_ERROR;
	}
    }
  else
    {
      rc=http_open(&curl->hd,HTTP_REQ_GET,curl->url,curl->auth,0,proxy,
		   &srv,curl->headers?curl->headers->list:NULL);
      if(rc==0)
	{
	  if(curl->flags.verbose && srv.used_server && srv.used_port)
	    fprintf (curl->errors, "* HTTP host:port post-SRV is \"%s:%hu\"\n",
		     srv.used_server, srv.used_port);

	  rc=http_wait_response(&curl->hd,&curl->status);
	  if(rc==0)
	    {
	      if(curl->flags.failonerror && curl->status>=300)
		err=CURLE_HTTP_RETURNED_ERROR;
	      else
		{
		  unsigned int maxlen=1024,buflen,len;
		  byte *line=NULL;

		  while((len=iobuf_read_line(curl->hd.fp_read,
					     &line,&buflen,&maxlen)))
		    {
		      size_t ret;

		      maxlen=1024;

		      ret=(curl->writer)(line,len,1,curl->file);
		      if(ret!=len)
			{
			  err=CURLE_WRITE_ERROR;
			  break;
			}
		    }

		  xfree(line);
		  http_close(&curl->hd);
		}
	    }
	  else
	    http_close(&curl->hd);
	}
    }

  free (srv.used_server);

  switch(rc)
    {
    case 0:
      break;

    case G10ERR_INVALID_URI:
      err=CURLE_UNSUPPORTED_PROTOCOL;
      break;

    case G10ERR_NETWORK:
      errstr=strerror(errno);
      err=CURLE_COULDNT_CONNECT;
      break;

    default:
      errstr=g10_errstr(rc);
      err=CURLE_COULDNT_CONNECT;
      break;
    }
      
  return handle_error(curl,err,errstr);
}
Example #21
0
int
build_sk_list( strlist_t locusr, SK_LIST *ret_sk_list,
               int unlock, unsigned int use )
{
    SK_LIST sk_list = NULL;
    int rc;

    if( !locusr )
      { /* use the default one */
	PKT_secret_key *sk;

	sk = xmalloc_clear( sizeof *sk );
	sk->req_usage = use;
	if( (rc = get_seckey_byname( sk, NULL, unlock )) ) {
	  free_secret_key( sk ); sk = NULL;
	  log_error("no default secret key: %s\n", g10_errstr(rc) );
          write_status_text (STATUS_INV_SGNR,
                             get_inv_recpsgnr_code (GPG_ERR_NO_SECKEY));
	}
	else if( !(rc=openpgp_pk_test_algo2 (sk->pubkey_algo, use)) )
	  {
	    SK_LIST r;

	    if( random_is_faked() && !is_insecure( sk ) )
	      {
		log_info(_("key is not flagged as insecure - "
			   "can't use it with the faked RNG!\n"));
		free_secret_key( sk ); sk = NULL;
                write_status_text (STATUS_INV_SGNR, 
                                   get_inv_recpsgnr_code (GPG_ERR_NOT_TRUSTED));
	      }
	    else
	      {
		r = xmalloc( sizeof *r );
		r->sk = sk; sk = NULL;
		r->next = sk_list;
		r->mark = 0;
		sk_list = r;
	      }
	  }
	else
	  {
	    free_secret_key( sk ); sk = NULL;
	    log_error("invalid default secret key: %s\n", g10_errstr(rc) );
            write_status_text (STATUS_INV_SGNR, get_inv_recpsgnr_code (rc));
	  }
      }
    else {
        strlist_t locusr_orig = locusr;
	for(; locusr; locusr = locusr->next ) {
	    PKT_secret_key *sk;
            
            rc = 0;
            /* Do an early check agains duplicated entries.  However this
             * won't catch all duplicates because the user IDs may be
             * specified in different ways.
             */
            if ( is_duplicated_entry ( locusr_orig, locusr ) )
	      {
		log_info (_("skipped \"%s\": duplicated\n"), locusr->d );
                continue;
	      }
	    sk = xmalloc_clear( sizeof *sk );
	    sk->req_usage = use;
	    if( (rc = get_seckey_byname( sk, locusr->d, 0 )) )
	      {
		free_secret_key( sk ); sk = NULL;
		log_error(_("skipped \"%s\": %s\n"),
			  locusr->d, g10_errstr(rc) );
                write_status_text_and_buffer 
                  (STATUS_INV_SGNR, get_inv_recpsgnr_code (rc), 
                   locusr->d, strlen (locusr->d), -1);
	      }
            else if ( key_present_in_sk_list(sk_list, sk) == 0) {
                free_secret_key(sk); sk = NULL;
                log_info(_("skipped: secret key already present\n"));
            }
            else if ( unlock && (rc = check_secret_key( sk, 0 )) )
	      {
		free_secret_key( sk ); sk = NULL;
		log_error(_("skipped \"%s\": %s\n"),
			  locusr->d, g10_errstr(rc) );
                write_status_text_and_buffer 
                  (STATUS_INV_SGNR, get_inv_recpsgnr_code (rc), 
                   locusr->d, strlen (locusr->d), -1);
	      }
	    else if( !(rc=openpgp_pk_test_algo2 (sk->pubkey_algo, use)) ) {
		SK_LIST r;

		if( sk->version == 4 && (use & PUBKEY_USAGE_SIG)
		    && sk->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E )
		  {
		    log_info(_("skipped \"%s\": %s\n"),locusr->d,
			     _("this is a PGP generated Elgamal key which"
			       " is not secure for signatures!"));
		    free_secret_key( sk ); sk = NULL;
                    write_status_text_and_buffer 
                      (STATUS_INV_SGNR, 
                       get_inv_recpsgnr_code (GPG_ERR_WRONG_KEY_USAGE), 
                       locusr->d, strlen (locusr->d), -1);
		  }
		else if( random_is_faked() && !is_insecure( sk ) ) {
		    log_info(_("key is not flagged as insecure - "
			       "can't use it with the faked RNG!\n"));
		    free_secret_key( sk ); sk = NULL;
                    write_status_text_and_buffer 
                      (STATUS_INV_SGNR, 
                       get_inv_recpsgnr_code (GPG_ERR_NOT_TRUSTED), 
                       locusr->d, strlen (locusr->d), -1);
		}
		else {
		    r = xmalloc( sizeof *r );
		    r->sk = sk; sk = NULL;
		    r->next = sk_list;
		    r->mark = 0;
		    sk_list = r;
		}
	    }
	    else {
		free_secret_key( sk ); sk = NULL;
		log_error("skipped \"%s\": %s\n", locusr->d, g10_errstr(rc) );
                write_status_text_and_buffer 
                  (STATUS_INV_SGNR, get_inv_recpsgnr_code (rc), 
                   locusr->d, strlen (locusr->d), -1);
	    }
	}
    }


    if( !rc && !sk_list ) {
	log_error("no valid signators\n");
        write_status_text (STATUS_NO_SGNR, "0");
	rc = G10ERR_NO_USER_ID;
    }

    if( rc )
	release_sk_list( sk_list );
    else
	*ret_sk_list = sk_list;
    return rc;
}
/****************
 * Update a hashtable.
 * table gives the start of the table, key and keylen is the key,
 * newrecnum is the record number to insert.
 */
static int
upd_hashtable( ulong table, byte *key, int keylen, ulong newrecnum )
{
    TRUSTREC lastrec, rec;
    ulong hashrec, item;
    int msb;
    int level=0;
    int rc, i;

    hashrec = table;
  next_level:
    msb = key[level];
    hashrec += msb / ITEMS_PER_HTBL_RECORD;
    rc = tdbio_read_record( hashrec, &rec, RECTYPE_HTBL );
    if( rc ) {
	log_error("upd_hashtable: read failed: %s\n",	g10_errstr(rc) );
	return rc;
    }

    item = rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD];
    if( !item ) { /* insert a new item into the hash table */
	rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = newrecnum;
	rc = tdbio_write_record( &rec );
	if( rc ) {
	    log_error("upd_hashtable: write htbl failed: %s\n",
							    g10_errstr(rc) );
	    return rc;
	}
    }
    else if( item != newrecnum ) {  /* must do an update */
	lastrec = rec;
	rc = tdbio_read_record( item, &rec, 0 );
	if( rc ) {
	    log_error( "upd_hashtable: read item failed: %s\n",
							    g10_errstr(rc) );
	    return rc;
	}

	if( rec.rectype == RECTYPE_HTBL ) {
	    hashrec = item;
	    level++;
	    if( level >= keylen ) {
		log_error( "hashtable has invalid indirections.\n");
		return G10ERR_TRUSTDB;
	    }
	    goto next_level;
	}
	else if( rec.rectype == RECTYPE_HLST ) { /* extend list */
	    /* see whether the key is already in this list */
	    for(;;) {
		for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
		    if( rec.r.hlst.rnum[i] == newrecnum ) {
			return 0; /* okay, already in the list */
		    }
		}
		if( rec.r.hlst.next ) {
		    rc = tdbio_read_record( rec.r.hlst.next,
						       &rec, RECTYPE_HLST);
		    if( rc ) {
			log_error( "upd_hashtable: read hlst failed: %s\n",
							     g10_errstr(rc) );
			return rc;
		    }
		}
		else
		    break; /* not there */
	    }
	    /* find the next free entry and put it in */
	    for(;;) {
		for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
		    if( !rec.r.hlst.rnum[i] ) {
			rec.r.hlst.rnum[i] = newrecnum;
			rc = tdbio_write_record( &rec );
			if( rc )
			    log_error( "upd_hashtable: write hlst failed: %s\n",
							      g10_errstr(rc) );
			return rc; /* done */
		    }
		}
		if( rec.r.hlst.next ) {
		    rc = tdbio_read_record( rec.r.hlst.next,
						      &rec, RECTYPE_HLST );
		    if( rc ) {
			log_error( "upd_hashtable: read hlst failed: %s\n",
							     g10_errstr(rc) );
			return rc;
		    }
		}
		else { /* add a new list record */
		    rec.r.hlst.next = item = tdbio_new_recnum();
		    rc = tdbio_write_record( &rec );
		    if( rc ) {
			log_error( "upd_hashtable: write hlst failed: %s\n",
							  g10_errstr(rc) );
			return rc;
		    }
		    memset( &rec, 0, sizeof rec );
		    rec.rectype = RECTYPE_HLST;
		    rec.recnum = item;
		    rec.r.hlst.rnum[0] = newrecnum;
		    rc = tdbio_write_record( &rec );
		    if( rc )
			log_error( "upd_hashtable: write ext hlst failed: %s\n",
							  g10_errstr(rc) );
		    return rc; /* done */
		}
	    } /* end loop over hlst slots */
	}
	else if( rec.rectype == RECTYPE_TRUST ) { /* insert a list record */
	    if( rec.recnum == newrecnum ) {
		return 0;
	    }
	    item = rec.recnum; /* save number of key record */
	    memset( &rec, 0, sizeof rec );
	    rec.rectype = RECTYPE_HLST;
	    rec.recnum = tdbio_new_recnum();
	    rec.r.hlst.rnum[0] = item;	     /* old keyrecord */
	    rec.r.hlst.rnum[1] = newrecnum; /* and new one */
	    rc = tdbio_write_record( &rec );
	    if( rc ) {
		log_error( "upd_hashtable: write new hlst failed: %s\n",
						  g10_errstr(rc) );
		return rc;
	    }
	    /* update the hashtable record */
	    lastrec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = rec.recnum;
	    rc = tdbio_write_record( &lastrec );
	    if( rc )
		log_error( "upd_hashtable: update htbl failed: %s\n",
							     g10_errstr(rc) );
	    return rc; /* ready */
	}
	else {
	    log_error( "hashtbl %lu: %lu/%d points to an invalid record %lu\n",
		       table, hashrec, (msb % ITEMS_PER_HTBL_RECORD), item);
	    list_trustdb(NULL);
	    return G10ERR_TRUSTDB;
	}
    }

    return 0;
}
/****************
 * Drop an entry from a hashtable
 * table gives the start of the table, key and keylen is the key,
 */
static int
drop_from_hashtable( ulong table, byte *key, int keylen, ulong recnum )
{
    TRUSTREC rec;
    ulong hashrec, item;
    int msb;
    int level=0;
    int rc, i;

    hashrec = table;
  next_level:
    msb = key[level];
    hashrec += msb / ITEMS_PER_HTBL_RECORD;
    rc = tdbio_read_record( hashrec, &rec, RECTYPE_HTBL );
    if( rc ) {
	log_error("drop_from_hashtable: read failed: %s\n",
							g10_errstr(rc) );
	return rc;
    }

    item = rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD];
    if( !item )  /* not found - forget about it  */
	return 0;

    if( item == recnum ) {  /* tables points direct to the record */
	rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = 0;
	rc = tdbio_write_record( &rec );
	if( rc )
	    log_error("drop_from_hashtable: write htbl failed: %s\n",
							    g10_errstr(rc) );
	return rc;
    }

    rc = tdbio_read_record( item, &rec, 0 );
    if( rc ) {
	log_error( "drop_from_hashtable: read item failed: %s\n",
							g10_errstr(rc) );
	return rc;
    }

    if( rec.rectype == RECTYPE_HTBL ) {
	hashrec = item;
	level++;
	if( level >= keylen ) {
	    log_error( "hashtable has invalid indirections.\n");
	    return G10ERR_TRUSTDB;
	}
	goto next_level;
    }

    if( rec.rectype == RECTYPE_HLST ) {
	for(;;) {
	    for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
		if( rec.r.hlst.rnum[i] == recnum ) {
		    rec.r.hlst.rnum[i] = 0; /* drop */
		    rc = tdbio_write_record( &rec );
		    if( rc )
			log_error("drop_from_hashtable: write htbl failed: %s\n",
									g10_errstr(rc) );
		    return rc;
		}
	    }
	    if( rec.r.hlst.next ) {
		rc = tdbio_read_record( rec.r.hlst.next,
						   &rec, RECTYPE_HLST);
		if( rc ) {
		    log_error( "drop_from_hashtable: read hlst failed: %s\n",
							 g10_errstr(rc) );
		    return rc;
		}
	    }
	    else
		return 0; /* key not in table */
	}
    }

    log_error( "hashtbl %lu: %lu/%d points to wrong record %lu\n",
		    table, hashrec, (msb % ITEMS_PER_HTBL_RECORD), item);
    return G10ERR_TRUSTDB;
}
/****************
 * Encrypt the file with the given userids (or ask if none
 * is supplied).
 */
int
encode_crypt( const char *filename, STRLIST remusr, int use_symkey )
{
    IOBUF inp = NULL, out = NULL;
    PACKET pkt;
    PKT_plaintext *pt = NULL;
    DEK *symkey_dek = NULL;
    STRING2KEY *symkey_s2k = NULL;
    int rc = 0, rc2 = 0;
    u32 filesize;
    cipher_filter_context_t cfx;
    armor_filter_context_t afx;
    compress_filter_context_t zfx;
    text_filter_context_t tfx;
    progress_filter_context_t pfx;
    PK_LIST pk_list,work_list;
    int do_compress = opt.compress_algo && !RFC1991;

    memset( &cfx, 0, sizeof cfx);
    memset( &afx, 0, sizeof afx);
    memset( &zfx, 0, sizeof zfx);
    memset( &tfx, 0, sizeof tfx);
    init_packet(&pkt);

    if(use_symkey
       && (rc=setup_symkey(&symkey_s2k,&symkey_dek)))
      return rc;

    if( (rc=build_pk_list( remusr, &pk_list, PUBKEY_USAGE_ENC)) )
	return rc;

    if(PGP2) {
      for(work_list=pk_list; work_list; work_list=work_list->next)
	if(!(is_RSA(work_list->pk->pubkey_algo) &&
	     nbits_from_pk(work_list->pk)<=2048))
	  {
	    log_info(_("you can only encrypt to RSA keys of 2048 bits or "
		       "less in --pgp2 mode\n"));
	    compliance_failure();
	    break;
	  }
    }

    /* prepare iobufs */
    inp = iobuf_open(filename);
    if (inp)
      iobuf_ioctl (inp,3,1,NULL); /* disable fd caching */
    if (inp && is_secured_file (iobuf_get_fd (inp)))
      {
        iobuf_close (inp);
        inp = NULL;
        errno = EPERM;
      }
    if( !inp ) {
	log_error(_("can't open `%s': %s\n"), filename? filename: "[stdin]",
					strerror(errno) );
	rc = G10ERR_OPEN_FILE;
	goto leave;
    }
    else if( opt.verbose )
	log_info(_("reading from `%s'\n"), filename? filename: "[stdin]");

    handle_progress (&pfx, inp, filename);

    if( opt.textmode )
	iobuf_push_filter( inp, text_filter, &tfx );

    if( (rc = open_outfile( filename, opt.armor? 1:0, &out )) )
	goto leave;

    if( opt.armor )
	iobuf_push_filter( out, armor_filter, &afx );

    /* create a session key */
    cfx.dek = xmalloc_secure_clear (sizeof *cfx.dek);
    if( !opt.def_cipher_algo ) { /* try to get it from the prefs */
	cfx.dek->algo = select_algo_from_prefs(pk_list,PREFTYPE_SYM,-1,NULL);
	/* The only way select_algo_from_prefs can fail here is when
           mixing v3 and v4 keys, as v4 keys have an implicit
           preference entry for 3DES, and the pk_list cannot be empty.
           In this case, use 3DES anyway as it's the safest choice -
           perhaps the v3 key is being used in an OpenPGP
           implementation and we know that the implementation behind
           any v4 key can handle 3DES. */
	if( cfx.dek->algo == -1 ) {
	    cfx.dek->algo = CIPHER_ALGO_3DES;

	    if( PGP2 ) {
	      log_info(_("unable to use the IDEA cipher for all of the keys "
			 "you are encrypting to.\n"));
	      compliance_failure();
	    }
	}
    }
    else {
      if(!opt.expert &&
	 select_algo_from_prefs(pk_list,PREFTYPE_SYM,
				opt.def_cipher_algo,NULL)!=opt.def_cipher_algo)
	log_info(_("WARNING: forcing symmetric cipher %s (%d)"
		   " violates recipient preferences\n"),
		 cipher_algo_to_string(opt.def_cipher_algo),
		 opt.def_cipher_algo);

      cfx.dek->algo = opt.def_cipher_algo;
    }

    cfx.dek->use_mdc=use_mdc(pk_list,cfx.dek->algo);

    /* Only do the is-file-already-compressed check if we are using a
       MDC.  This forces compressed files to be re-compressed if we do
       not have a MDC to give some protection against chosen
       ciphertext attacks. */

    if (do_compress && cfx.dek->use_mdc && is_file_compressed(filename, &rc2) )
      {
        if (opt.verbose)
          log_info(_("`%s' already compressed\n"), filename);
        do_compress = 0;        
      }
    if (rc2)
      {
        rc = rc2;
        goto leave;
      }

    make_session_key( cfx.dek );
    if( DBG_CIPHER )
	log_hexdump("DEK is: ", cfx.dek->key, cfx.dek->keylen );

    rc = write_pubkey_enc_from_list( pk_list, cfx.dek, out );
    if( rc  )
	goto leave;

    /* We put the passphrase (if any) after any public keys as this
       seems to be the most useful on the recipient side - there is no
       point in prompting a user for a passphrase if they have the
       secret key needed to decrypt. */
    if(use_symkey && (rc=write_symkey_enc(symkey_s2k,symkey_dek,cfx.dek,out)))
      goto leave;

    if (!opt.no_literal) {
	/* setup the inner packet */
	if( filename || opt.set_filename ) {
	    char *s = make_basename( opt.set_filename ? opt.set_filename
						      : filename,
				     iobuf_get_real_fname( inp ) );
	    pt = xmalloc( sizeof *pt + strlen(s) - 1 );
	    pt->namelen = strlen(s);
	    memcpy(pt->name, s, pt->namelen );
	    xfree(s);
	}
	else { /* no filename */
	    pt = xmalloc( sizeof *pt - 1 );
	    pt->namelen = 0;
	}
    }

    if (!iobuf_is_pipe_filename (filename) && *filename && !opt.textmode )
      {
        off_t tmpsize;
        int overflow;

	if ( !(tmpsize = iobuf_get_filelength(inp, &overflow))
             && !overflow )
          log_info(_("WARNING: `%s' is an empty file\n"), filename );
        /* We can't encode the length of very large files because
           OpenPGP uses only 32 bit for file sizes.  So if the the
           size of a file is larger than 2^32 minus some bytes for
           packet headers, we switch to partial length encoding. */
        if (tmpsize < (IOBUF_FILELENGTH_LIMIT - 65536) )
          filesize = tmpsize;
        else
          filesize = 0;
      }
    else
      filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */

    if (!opt.no_literal) {
	pt->timestamp = make_timestamp();
	pt->mode = opt.textmode ? 't' : 'b';
	pt->len = filesize;
	pt->new_ctb = !pt->len && !RFC1991;
	pt->buf = inp;
	pkt.pkttype = PKT_PLAINTEXT;
	pkt.pkt.plaintext = pt;
	cfx.datalen = filesize && !do_compress? calc_packet_length( &pkt ) : 0;
    }
    else
	cfx.datalen = filesize && !do_compress ? filesize : 0;

    /* register the cipher filter */
    iobuf_push_filter( out, cipher_filter, &cfx );

    /* register the compress filter */
    if( do_compress ) {
	int compr_algo = opt.compress_algo;

	if(compr_algo==-1)
	  {
	    if((compr_algo=
		select_algo_from_prefs(pk_list,PREFTYPE_ZIP,-1,NULL))==-1)
	      compr_algo=DEFAULT_COMPRESS_ALGO;
	    /* Theoretically impossible to get here since uncompressed
	       is implicit. */
	  }
	else if(!opt.expert &&
		select_algo_from_prefs(pk_list,PREFTYPE_ZIP,
				       compr_algo,NULL)!=compr_algo)
	  log_info(_("WARNING: forcing compression algorithm %s (%d)"
		     " violates recipient preferences\n"),
		   compress_algo_to_string(compr_algo),compr_algo);

	/* algo 0 means no compression */
	if( compr_algo )
	  {
            if (cfx.dek && cfx.dek->use_mdc)
              zfx.new_ctb = 1;
	    push_compress_filter(out,&zfx,compr_algo);
	  }
    }

    /* do the work */
    if (!opt.no_literal) {
	if( (rc = build_packet( out, &pkt )) )
	    log_error("build_packet failed: %s\n", g10_errstr(rc) );
    }
    else {
	/* user requested not to create a literal packet, so we copy
           the plain data */
	byte copy_buffer[4096];
	int  bytes_copied;
	while ((bytes_copied = iobuf_read(inp, copy_buffer, 4096)) != -1)
	    if (iobuf_write(out, copy_buffer, bytes_copied) == -1) {
		rc = G10ERR_WRITE_FILE;
		log_error("copying input to output failed: %s\n",
                          g10_errstr(rc) );
		break;
	    }
	wipememory(copy_buffer, 4096); /* burn buffer */
    }

    /* finish the stuff */
  leave:
    iobuf_close(inp);
    if( rc )
	iobuf_cancel(out);
    else {
	iobuf_close(out); /* fixme: check returncode */
        write_status( STATUS_END_ENCRYPTION );
    }
    if( pt )
	pt->buf = NULL;
    free_packet(&pkt);
    xfree(cfx.dek);
    xfree(symkey_dek);
    xfree(symkey_s2k);
    release_pk_list( pk_list );
    return rc;
}
/* We don't want to use use_seskey yet because older gnupg versions
   can't handle it, and there isn't really any point unless we're
   making a message that can be decrypted by a public key or
   passphrase. */
static int
encode_simple( const char *filename, int mode, int use_seskey )
{
    IOBUF inp, out;
    PACKET pkt;
    PKT_plaintext *pt = NULL;
    STRING2KEY *s2k = NULL;
    byte enckey[33];
    int rc = 0;
    int seskeylen = 0;
    u32 filesize;
    cipher_filter_context_t cfx;
    armor_filter_context_t afx;
    compress_filter_context_t zfx;
    text_filter_context_t tfx;
    progress_filter_context_t pfx;
    int do_compress = !RFC1991 && default_compress_algo();

    memset( &cfx, 0, sizeof cfx);
    memset( &afx, 0, sizeof afx);
    memset( &zfx, 0, sizeof zfx);
    memset( &tfx, 0, sizeof tfx);
    init_packet(&pkt);
    
    /* prepare iobufs */
    inp = iobuf_open(filename);
    if (inp)
      iobuf_ioctl (inp,3,1,NULL); /* disable fd caching */
    if (inp && is_secured_file (iobuf_get_fd (inp)))
      {
        iobuf_close (inp);
        inp = NULL;
        errno = EPERM;
      }
    if( !inp ) {
	log_error(_("can't open `%s': %s\n"), filename? filename: "[stdin]",
                  strerror(errno) );
	return G10ERR_OPEN_FILE;
    }

    handle_progress (&pfx, inp, filename);

    if( opt.textmode )
	iobuf_push_filter( inp, text_filter, &tfx );

    /* Due the the fact that we use don't use an IV to encrypt the
       session key we can't use the new mode with RFC1991 because
       it has no S2K salt. RFC1991 always uses simple S2K. */
    if ( RFC1991 && use_seskey )
        use_seskey = 0;
    
    cfx.dek = NULL;
    if( mode ) {
	s2k = xmalloc_clear( sizeof *s2k );
	s2k->mode = RFC1991? 0:opt.s2k_mode;
	s2k->hash_algo=S2K_DIGEST_ALGO;
	cfx.dek = passphrase_to_dek( NULL, 0,
				     default_cipher_algo(), s2k, 2,
                                     NULL, NULL);
	if( !cfx.dek || !cfx.dek->keylen ) {
	    rc = G10ERR_PASSPHRASE;
	    xfree(cfx.dek);
	    xfree(s2k);
	    iobuf_close(inp);
	    log_error(_("error creating passphrase: %s\n"), g10_errstr(rc) );
	    return rc;
	}
        if (use_seskey && s2k->mode != 1 && s2k->mode != 3) {
            use_seskey = 0;
            log_info (_("can't use a symmetric ESK packet "
                        "due to the S2K mode\n"));
        }

        if ( use_seskey )
	  {
	    DEK *dek = NULL;
            seskeylen = cipher_get_keylen( default_cipher_algo() ) / 8;
            encode_seskey( cfx.dek, &dek, enckey );
            xfree( cfx.dek ); cfx.dek = dek;
	  }

	if(opt.verbose)
	  log_info(_("using cipher %s\n"),
		   cipher_algo_to_string(cfx.dek->algo));

	cfx.dek->use_mdc=use_mdc(NULL,cfx.dek->algo);
    }

    if (do_compress && cfx.dek && cfx.dek->use_mdc
	&& is_file_compressed(filename, &rc))
      {
        if (opt.verbose)
          log_info(_("`%s' already compressed\n"), filename);
        do_compress = 0;        
      }

    if( rc || (rc = open_outfile( filename, opt.armor? 1:0, &out )) ) {
	iobuf_cancel(inp);
	xfree(cfx.dek);
	xfree(s2k);
	return rc;
    }

    if( opt.armor )
	iobuf_push_filter( out, armor_filter, &afx );

    if( s2k && !RFC1991 ) {
	PKT_symkey_enc *enc = xmalloc_clear( sizeof *enc + seskeylen + 1 );
	enc->version = 4;
	enc->cipher_algo = cfx.dek->algo;
	enc->s2k = *s2k;
        if ( use_seskey && seskeylen ) {
            enc->seskeylen = seskeylen + 1; /* algo id */
            memcpy( enc->seskey, enckey, seskeylen + 1 );
        }
	pkt.pkttype = PKT_SYMKEY_ENC;
	pkt.pkt.symkey_enc = enc;
	if( (rc = build_packet( out, &pkt )) )
	    log_error("build symkey packet failed: %s\n", g10_errstr(rc) );
	xfree(enc);
    }

    if (!opt.no_literal)
      pt=setup_plaintext_name(filename,inp);

    /* Note that PGP 5 has problems decrypting symmetrically encrypted
       data if the file length is in the inner packet. It works when
       only partial length headers are use.  In the past, we always
       used partial body length here, but since PGP 2, PGP 6, and PGP
       7 need the file length, and nobody should be using PGP 5
       nowadays anyway, this is now set to the file length.  Note also
       that this only applies to the RFC-1991 style symmetric
       messages, and not the RFC-2440 style.  PGP 6 and 7 work with
       either partial length or fixed length with the new style
       messages. */

    if ( !iobuf_is_pipe_filename (filename) && *filename && !opt.textmode )
      {
        off_t tmpsize;
        int overflow;

	if ( !(tmpsize = iobuf_get_filelength(inp, &overflow))
             && !overflow )
          log_info(_("WARNING: `%s' is an empty file\n"), filename );
        /* We can't encode the length of very large files because
           OpenPGP uses only 32 bit for file sizes.  So if the the
           size of a file is larger than 2^32 minus some bytes for
           packet headers, we switch to partial length encoding. */
        if ( tmpsize < (IOBUF_FILELENGTH_LIMIT - 65536) )
          filesize = tmpsize;
        else
          filesize = 0;
      }
    else
      filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */

    if (!opt.no_literal) {
	pt->timestamp = make_timestamp();
	pt->mode = opt.textmode? 't' : 'b';
	pt->len = filesize;
	pt->new_ctb = !pt->len && !RFC1991;
	pt->buf = inp;
	pkt.pkttype = PKT_PLAINTEXT;
	pkt.pkt.plaintext = pt;
	cfx.datalen = filesize && !do_compress ? calc_packet_length( &pkt ) : 0;
    }
    else
      {
        cfx.datalen = filesize && !do_compress ? filesize : 0;
        pkt.pkttype = 0;
        pkt.pkt.generic = NULL;
      }

    /* register the cipher filter */
    if( mode )
	iobuf_push_filter( out, cipher_filter, &cfx );
    /* register the compress filter */
    if( do_compress )
      {
        if (cfx.dek && cfx.dek->use_mdc)
          zfx.new_ctb = 1;
	push_compress_filter(out,&zfx,default_compress_algo());
      }

    /* do the work */
    if (!opt.no_literal) {
	if( (rc = build_packet( out, &pkt )) )
	    log_error("build_packet failed: %s\n", g10_errstr(rc) );
    }
    else {
	/* user requested not to create a literal packet,
	 * so we copy the plain data */
	byte copy_buffer[4096];
	int  bytes_copied;
	while ((bytes_copied = iobuf_read(inp, copy_buffer, 4096)) != -1)
	    if (iobuf_write(out, copy_buffer, bytes_copied) == -1) {
		rc = G10ERR_WRITE_FILE;
		log_error("copying input to output failed: %s\n", g10_errstr(rc) );
		break;
	    }
	wipememory(copy_buffer, 4096); /* burn buffer */
    }

    /* finish the stuff */
    iobuf_close(inp);
    if (rc)
	iobuf_cancel(out);
    else {
	iobuf_close(out); /* fixme: check returncode */
        if (mode)
            write_status( STATUS_END_ENCRYPTION );
    }
    if (pt)
	pt->buf = NULL;
    free_packet(&pkt);
    xfree(cfx.dek);
    xfree(s2k);
    return rc;
}
/****************
 * Write pubkey-enc packets from the list of PKs to OUT.
 */
static int
write_pubkey_enc_from_list( PK_LIST pk_list, DEK *dek, IOBUF out )
{
    PACKET pkt;
    PKT_public_key *pk;
    PKT_pubkey_enc  *enc;
    int rc;

    for( ; pk_list; pk_list = pk_list->next ) {
	MPI frame;

	pk = pk_list->pk;

	print_pubkey_algo_note( pk->pubkey_algo );
	enc = xmalloc_clear( sizeof *enc );
	enc->pubkey_algo = pk->pubkey_algo;
	keyid_from_pk( pk, enc->keyid );
	enc->throw_keyid = (opt.throw_keyid || (pk_list->flags&1));

	if(opt.throw_keyid && (PGP2 || PGP6 || PGP7 || PGP8))
	  {
	    log_info(_("you may not use %s while in %s mode\n"),
		     "--throw-keyid",compliance_option_string());
	    compliance_failure();
	  }

	/* Okay, what's going on: We have the session key somewhere in
	 * the structure DEK and want to encode this session key in
	 * an integer value of n bits.	pubkey_nbits gives us the
	 * number of bits we have to use.  We then encode the session
	 * key in some way and we get it back in the big intger value
	 * FRAME.  Then we use FRAME, the public key PK->PKEY and the
	 * algorithm number PK->PUBKEY_ALGO and pass it to pubkey_encrypt
	 * which returns the encrypted value in the array ENC->DATA.
	 * This array has a size which depends on the used algorithm
	 * (e.g. 2 for Elgamal).  We don't need frame anymore because we
	 * have everything now in enc->data which is the passed to
	 * build_packet()
	 */
	frame = encode_session_key( dek, pubkey_nbits( pk->pubkey_algo,
							  pk->pkey ) );
	rc = pubkey_encrypt( pk->pubkey_algo, enc->data, frame, pk->pkey );
	mpi_free( frame );
	if( rc )
	    log_error("pubkey_encrypt failed: %s\n", g10_errstr(rc) );
	else {
	    if( opt.verbose ) {
		char *ustr = get_user_id_string_native (enc->keyid);
		log_info(_("%s/%s encrypted for: \"%s\"\n"),
		    pubkey_algo_to_string(enc->pubkey_algo),
		    cipher_algo_to_string(dek->algo), ustr );
		xfree(ustr);
	    }
	    /* and write it */
	    init_packet(&pkt);
	    pkt.pkttype = PKT_PUBKEY_ENC;
	    pkt.pkt.pubkey_enc = enc;
	    rc = build_packet( out, &pkt );
	    if( rc )
	       log_error("build_packet(pubkey_enc) failed: %s\n", g10_errstr(rc));
	}
	free_pubkey_enc(enc);
	if( rc )
	    return rc;
    }
    return 0;
}
/*
 * Register a resource (which currently may only be a keyring file).
 * The first keyring which is added by this function is
 * created if it does not exist.
 * Note: this function may be called before secure memory is
 * available.
 * Flag 1 == force
 * Flag 2 == mark resource as primary
 * Flag 4 == This is a default resources
 */
int
keydb_add_resource (const char *url, int flags, int secret)
{
    static int any_secret, any_public;
    const char *resname = url;
    char *filename = NULL;
    int force=(flags&1);
    int rc = 0;
    KeydbResourceType rt = KEYDB_RESOURCE_TYPE_NONE;
    void *token;

    /* Do we have an URL?
     *	gnupg-ring:filename  := this is a plain keyring
     *	filename := See what is is, but create as plain keyring.
     */
    if (strlen (resname) > 11) {
	if (!strncmp( resname, "gnupg-ring:", 11) ) {
	    rt = KEYDB_RESOURCE_TYPE_KEYRING;
	    resname += 11;
	}
#if !defined(HAVE_DRIVE_LETTERS) && !defined(__riscos__)
	else if (strchr (resname, ':')) {
	    log_error ("invalid key resource URL `%s'\n", url );
	    rc = G10ERR_GENERAL;
	    goto leave;
	}
#endif /* !HAVE_DRIVE_LETTERS && !__riscos__ */
    }

    if (*resname != DIRSEP_C ) { /* do tilde expansion etc */
	if (strchr(resname, DIRSEP_C) )
	    filename = make_filename (resname, NULL);
	else
	    filename = make_filename (opt.homedir, resname, NULL);
    }
    else
	filename = xstrdup (resname);

    if (!force)
	force = secret? !any_secret : !any_public;

    /* see whether we can determine the filetype */
    if (rt == KEYDB_RESOURCE_TYPE_NONE) {
	FILE *fp = fopen( filename, "rb" );

	if (fp) {
	    u32 magic;

	    if (fread( &magic, 4, 1, fp) == 1 ) {
		if (magic == 0x13579ace || magic == 0xce9a5713)
		    ; /* GDBM magic - no more support */
		else
		    rt = KEYDB_RESOURCE_TYPE_KEYRING;
	    }
	    else /* maybe empty: assume ring */
		rt = KEYDB_RESOURCE_TYPE_KEYRING;
	    fclose( fp );
	}
	else /* no file yet: create ring */
	    rt = KEYDB_RESOURCE_TYPE_KEYRING;
    }

    switch (rt) {
      case KEYDB_RESOURCE_TYPE_NONE:
	log_error ("unknown type of key resource `%s'\n", url );
	rc = G10ERR_GENERAL;
	goto leave;

      case KEYDB_RESOURCE_TYPE_KEYRING:
        rc = maybe_create_keyring (filename, force);
        if (rc)
          goto leave;

        if(keyring_register_filename (filename, secret, &token))
	  {
	    if (used_resources >= MAX_KEYDB_RESOURCES)
	      rc = G10ERR_RESOURCE_LIMIT;
	    else 
	      {
		if(flags&2)
		  primary_keyring=token;
		all_resources[used_resources].type = rt;
		all_resources[used_resources].u.kr = NULL; /* Not used here */
		all_resources[used_resources].token = token;
		all_resources[used_resources].secret = secret;
		used_resources++;
	      }
	  }
	else
	  {
	    /* This keyring was already registered, so ignore it.
	       However, we can still mark it as primary even if it was
	       already registered. */
	    if(flags&2)
	      primary_keyring=token;
	  }
	break;

      default:
	log_error ("resource type of `%s' not supported\n", url);
	rc = G10ERR_GENERAL;
	goto leave;
    }

    /* fixme: check directory permissions and print a warning */

  leave:
    if (rc)
      {
        /* Secret keyrings are not required in all cases.  To avoid
           having gpg return failure we use log_info here if the
           rewsource is a secret one and marked as default
           resource.  */
        if ((flags&4) && secret)
          log_info (_("keyblock resource `%s': %s\n"),
                    filename, g10_errstr(rc));
        else
          log_error (_("keyblock resource `%s': %s\n"),
                     filename, g10_errstr(rc));
      }
    else if (secret)
	any_secret = 1;
    else
	any_public = 1;
    xfree (filename);
    return rc;
}
/****************
 * Lookup a record via the hashtable tablewith key/keylen and return the
 * result in rec.  cmp() should return if the record is the desired one.
 * Returns -1 if not found, 0 if found or another errocode
 */
static int
lookup_hashtable( ulong table, const byte *key, size_t keylen,
		  int (*cmpfnc)(void*, const TRUSTREC *), void *cmpdata,
						TRUSTREC *rec )
{
    int rc;
    ulong hashrec, item;
    int msb;
    int level=0;

    hashrec = table;
  next_level:
    msb = key[level];
    hashrec += msb / ITEMS_PER_HTBL_RECORD;
    rc = tdbio_read_record( hashrec, rec, RECTYPE_HTBL );
    if( rc ) {
	log_error("lookup_hashtable failed: %s\n", g10_errstr(rc) );
	return rc;
    }

    item = rec->r.htbl.item[msb % ITEMS_PER_HTBL_RECORD];
    if( !item )
	return -1; /* not found */

    rc = tdbio_read_record( item, rec, 0 );
    if( rc ) {
	log_error( "hashtable read failed: %s\n", g10_errstr(rc) );
	return rc;
    }
    if( rec->rectype == RECTYPE_HTBL ) {
	hashrec = item;
	level++;
	if( level >= keylen ) {
	    log_error("hashtable has invalid indirections\n");
	    return G10ERR_TRUSTDB;
	}
	goto next_level;
    }
    else if( rec->rectype == RECTYPE_HLST ) {
	for(;;) {
	    int i;

	    for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
		if( rec->r.hlst.rnum[i] ) {
		    TRUSTREC tmp;

		    rc = tdbio_read_record( rec->r.hlst.rnum[i], &tmp, 0 );
		    if( rc ) {
			log_error( "lookup_hashtable: read item failed: %s\n",
							      g10_errstr(rc) );
			return rc;
		    }
		    if( (*cmpfnc)( cmpdata, &tmp ) ) {
			*rec = tmp;
			return 0;
		    }
		}
	    }
	    if( rec->r.hlst.next ) {
		rc = tdbio_read_record( rec->r.hlst.next, rec, RECTYPE_HLST );
		if( rc ) {
		    log_error( "lookup_hashtable: read hlst failed: %s\n",
							 g10_errstr(rc) );
		    return rc;
		}
	    }
	    else
		return -1; /* not found */
	}
    }


    if( (*cmpfnc)( cmpdata, rec ) )
	return 0; /* really found */

    return -1; /* no: not found */
}
/****************
 * create a new record and return its record number
 */
ulong
tdbio_new_recnum()
{
    off_t offset;
    ulong recnum;
    TRUSTREC vr, rec;
    int rc;

    /* look for unused records */
    rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
    if( rc )
	log_fatal( _("%s: error reading version record: %s\n"),
					     db_name, g10_errstr(rc) );
    if( vr.r.ver.firstfree ) {
	recnum = vr.r.ver.firstfree;
	rc = tdbio_read_record( recnum, &rec, RECTYPE_FREE );
	if( rc ) {
	    log_error( _("%s: error reading free record: %s\n"),
						  db_name,  g10_errstr(rc) );
	    return rc;
	}
	/* update dir record */
	vr.r.ver.firstfree = rec.r.free.next;
	rc = tdbio_write_record( &vr );
	if( rc ) {
	    log_error( _("%s: error writing dir record: %s\n"),
						     db_name, g10_errstr(rc) );
	    return rc;
	}
	/*zero out the new record */
	memset( &rec, 0, sizeof rec );
	rec.rectype = 0; /* unused record */
	rec.recnum = recnum;
	rc = tdbio_write_record( &rec );
	if( rc )
	    log_fatal(_("%s: failed to zero a record: %s\n"),
				       db_name, g10_errstr(rc));
    }
    else { /* not found, append a new record */
	offset = lseek( db_fd, 0, SEEK_END );
	if( offset == -1 )
	    log_fatal("trustdb: lseek to end failed: %s\n", strerror(errno) );
	recnum = offset / TRUST_RECORD_LEN;
	assert(recnum); /* this is will never be the first record */
	/* we must write a record, so that the next call to this function
	 * returns another recnum */
	memset( &rec, 0, sizeof rec );
	rec.rectype = 0; /* unused record */
	rec.recnum = recnum;
	rc = 0;
	if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
	    log_error(_("trustdb rec %lu: lseek failed: %s\n"),
						recnum, strerror(errno) );
	    rc = G10ERR_WRITE_FILE;
	}
	else {
	    int n = write( db_fd, &rec, TRUST_RECORD_LEN);
	    if( n != TRUST_RECORD_LEN ) {
		log_error(_("trustdb rec %lu: write failed (n=%d): %s\n"),
						 recnum, n, strerror(errno) );
		rc = G10ERR_WRITE_FILE;
	    }
	}

	if( rc )
	    log_fatal(_("%s: failed to append a record: %s\n"),
				    db_name,	g10_errstr(rc));
    }
    return recnum ;
}
int
tdbio_set_dbname( const char *new_dbname, int create )
{
    char *fname;
    static int initialized = 0;

    if( !initialized ) {
	atexit( cleanup );
	initialized = 1;
    }

    if(new_dbname==NULL)
      fname=make_filename(opt.homedir,"trustdb" EXTSEP_S "gpg", NULL);
    else if (*new_dbname != DIRSEP_C )
      {
	if (strchr(new_dbname, DIRSEP_C) )
	  fname = make_filename (new_dbname, NULL);
	else
	  fname = make_filename (opt.homedir, new_dbname, NULL);
      }
    else
      fname = xstrdup (new_dbname);

    if( access( fname, R_OK ) ) {
	if( errno != ENOENT ) {
	    log_error( _("can't access `%s': %s\n"), fname, strerror(errno) );
	    xfree(fname);
	    return G10ERR_TRUSTDB;
	}
	if( create ) {
	    FILE *fp;
	    TRUSTREC rec;
	    int rc;
	    char *p = strrchr( fname, DIRSEP_C );
	    mode_t oldmask;

	    assert(p);
	    *p = 0;
	    if( access( fname, F_OK ) ) {
		try_make_homedir( fname );
		log_fatal( _("%s: directory does not exist!\n"), fname );
	    }
	    *p = DIRSEP_C;

	    xfree(db_name);
	    db_name = fname;
#ifdef __riscos__
	    if( !lockhandle )
		lockhandle = create_dotlock( db_name );
	    if( !lockhandle )
		log_fatal( _("can't create lock for `%s'\n"), db_name );
            if( make_dotlock( lockhandle, -1 ) )
                log_fatal( _("can't lock `%s'\n"), db_name );
#endif /* __riscos__ */
	    oldmask=umask(077);
            if (is_secured_filename (fname)) {
                fp = NULL;
                errno = EPERM;
            }
            else
                fp =fopen( fname, "wb" );
	    umask(oldmask);
	    if( !fp )
		log_fatal( _("can't create `%s': %s\n"), fname, strerror(errno) );
	    fclose(fp);
	    db_fd = open( db_name, O_RDWR | MY_O_BINARY );
	    if( db_fd == -1 )
		log_fatal( _("can't open `%s': %s\n"), db_name, strerror(errno) );

#ifndef __riscos__
	    if( !lockhandle )
		lockhandle = create_dotlock( db_name );
	    if( !lockhandle )
		log_fatal( _("can't create lock for `%s'\n"), db_name );
#endif /* !__riscos__ */

            rc = create_version_record ();
	    if( rc )
		log_fatal( _("%s: failed to create version record: %s"),
						   fname, g10_errstr(rc));
	    /* and read again to check that we are okay */
	    if( tdbio_read_record( 0, &rec, RECTYPE_VER ) )
		log_fatal( _("%s: invalid trustdb created\n"), db_name );

	    if( !opt.quiet )
		log_info(_("%s: trustdb created\n"), db_name);

	    return 0;
	}
    }
    xfree(db_name);
    db_name = fname;
    return 0;
}