1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-04-11 22:01:08 +02:00

gpg: Auto-migrate existing secring.gpg.

* g10/migrate.c: New.
* g10/import.c (import_old_secring): New.
(import_one): Add arg silent.
(transfer_secret_keys): Add arg batch.
(import_secret_one): Add args batch and for_migration.
* g10/gpg.c (main): Call migration function.
This commit is contained in:
Werner Koch 2014-06-05 11:19:59 +02:00
parent 09a2d4ec74
commit 4f0625889b
7 changed files with 274 additions and 62 deletions

29
README
View File

@ -85,21 +85,10 @@ MIGRATION FROM 1.4 or 2.0 to 2.1
The major change in 2.1 is gpg-agent taking care of the OpenPGP secret The major change in 2.1 is gpg-agent taking care of the OpenPGP secret
keys (those managed by GPG). The former file "secring.gpg" will not keys (those managed by GPG). The former file "secring.gpg" will not
be used anymore. Newly generated keys are stored in the agent's key be used anymore. Newly generated keys are stored in the agent's key
store directory "~/.gnupg/private-keys-v1.d/". store directory "~/.gnupg/private-keys-v1.d/". The first time gpg
needs a secret key it checks whether a "secring.gpg" exists and
To migrate your existing keys you need to run the command copies them to the new store. The old secring.gpg is kept for use by
older versions of gpg.
gpg2 --batch --import ~/.gnupg/secring.gpg
Secret keys already imported are skipped by this command. It is
advisable to keep the secring.gpg for use with older versions of GPG.
The use of "--batch" with "--import" is highly recommended. If you do
not use "--batch" the agent would ask for the passphrase of each key.
In this case you may use the Cancel button of the Pinentry to skip
importing this key. If you want to stop the enite import process and
you use a decent version of Pinentry, you should close the Pinentry
window instead of hitting the Cancel button.
Note that gpg-agent now uses a fixed socket by default. All tools Note that gpg-agent now uses a fixed socket by default. All tools
will start the gpg-agent as needed. In general there is no more need will start the gpg-agent as needed. In general there is no more need
@ -111,11 +100,11 @@ of the card related sub-commands of --edit-key are not yet fully
supported. However, signing and decryption with a smartcard does supported. However, signing and decryption with a smartcard does
work. work.
The Dirmngr is now part of GnuPG proper. Thus there is no more need The Dirmngr is now part of GnuPG proper and also used to access
to install the separate dirmngr package. The directroy layout of OpenPGP keyservers. The directroy layout of Dirmngr changed to make
Dirmngr changed to make use of the GnuPG directories; for example you use of the GnuPG directories. Dirmngr is started by gpg or gpgsm as
use /etc/gnupg/trusted-certs and /var/lib/gnupg/extra-certs. Dirmngr needed needed. There is no more need to install a separate dirmngr
needs to be started as a system daemon. package.

View File

@ -3042,18 +3042,33 @@ files; They all live in in the current home directory (@pxref{option
@table @file @table @file
@item ~/.gnupg/secring.gpg
The secret keyring. You should backup this file.
@item ~/.gnupg/secring.gpg.lock
The lock file for the secret keyring.
@item ~/.gnupg/pubring.gpg @item ~/.gnupg/pubring.gpg
The public keyring. You should backup this file. The public keyring. You should backup this file.
@item ~/.gnupg/pubring.gpg.lock @item ~/.gnupg/pubring.gpg.lock
The lock file for the public keyring. The lock file for the public keyring.
@ifset gpgtwoone
@item ~/.gnupg/pubring.kbx
The public keyring using a different format. This file is sharred
with @command{gpgsm}. You should backup this file.
@item ~/.gnupg/pubring.kbx.lock
The lock file for @file{pubring.kbx}.
@end ifset
@item ~/.gnupg/secring.gpg
@ifclear gpgtwoone
The secret keyring. You should backup this file.
@end ifclear
@ifset gpgtwoone
A secret keyring as used by GnuPG versions before 2.1. It is not
used by GnuPG 2.1 and later.
@item ~/.gnupg/.gpg-v21-migrated
File indicating that a migration to GnuPG 2.1 has taken place.
@end ifset
@item ~/.gnupg/trustdb.gpg @item ~/.gnupg/trustdb.gpg
The trust database. There is no need to backup this file; it is better The trust database. There is no need to backup this file; it is better
to backup the ownertrust values (@pxref{option --export-ownertrust}). to backup the ownertrust values (@pxref{option --export-ownertrust}).
@ -3064,6 +3079,9 @@ files; They all live in in the current home directory (@pxref{option
@item ~/.gnupg/random_seed @item ~/.gnupg/random_seed
A file used to preserve the state of the internal random pool. A file used to preserve the state of the internal random pool.
@item ~/.gnupg/secring.gpg.lock
The lock file for the secret keyring.
@item /usr[/local]/share/gnupg/options.skel @item /usr[/local]/share/gnupg/options.skel
The skeleton options file. The skeleton options file.

View File

@ -110,6 +110,7 @@ gpg2_SOURCES = gpg.c \
dearmor.c \ dearmor.c \
import.c \ import.c \
export.c \ export.c \
migrate.c \
delkey.c \ delkey.c \
keygen.c \ keygen.c \
helptext.c \ helptext.c \

View File

@ -3594,6 +3594,43 @@ main (int argc, char **argv)
break; break;
} }
/* Check for certain command whether we need to migrate a
secring.gpg to the gpg-agent. */
switch (cmd)
{
case aListSecretKeys:
case aSign:
case aSignEncr:
case aSignEncrSym:
case aSignSym:
case aClearsign:
case aDecrypt:
case aSignKey:
case aLSignKey:
case aEditKey:
case aPasswd:
case aDeleteSecretKeys:
case aDeleteSecretAndPublicKeys:
case aKeygen:
case aImport:
case aExportSecret:
case aExportSecretSub:
case aGenRevoke:
case aDesigRevoke:
case aCardEdit:
case aChangePIN:
migrate_secring (ctrl);
break;
case aListKeys:
if (opt.with_secret)
migrate_secring (ctrl);
break;
default:
break;
}
/* The command dispatcher. */
switch( cmd ) switch( cmd )
{ {
case aServer: case aServer:

View File

@ -1,6 +1,7 @@
/* import.c - import a key into our key storage. /* import.c - import a key into our key storage.
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
* 2007, 2010, 2011 Free Software Foundation, Inc. * 2007, 2010, 2011 Free Software Foundation, Inc.
* Copyright (C) 2014 Werner Koch
* *
* This file is part of GnuPG. * This file is part of GnuPG.
* *
@ -68,9 +69,10 @@ static void revocation_present (ctrl_t ctrl, kbnode_t keyblock);
static int import_one (ctrl_t ctrl, static int import_one (ctrl_t ctrl,
const char *fname, KBNODE keyblock,struct stats_s *stats, const char *fname, KBNODE keyblock,struct stats_s *stats,
unsigned char **fpr,size_t *fpr_len, unsigned char **fpr,size_t *fpr_len,
unsigned int options,int from_sk); unsigned int options,int from_sk, int silent);
static int import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock, static int import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
struct stats_s *stats, unsigned int options); struct stats_s *stats, int batch,
unsigned int options, int for_migration);
static int import_revoke_cert( const char *fname, KBNODE node, static int import_revoke_cert( const char *fname, KBNODE node,
struct stats_s *stats); struct stats_s *stats);
static int chk_self_sigs( const char *fname, KBNODE keyblock, static int chk_self_sigs( const char *fname, KBNODE keyblock,
@ -227,6 +229,7 @@ import_keys_internal (ctrl_t ctrl, iobuf_t inp, char **fnames, int nnames,
return rc; return rc;
} }
void void
import_keys (ctrl_t ctrl, char **fnames, int nnames, import_keys (ctrl_t ctrl, char **fnames, int nnames,
void *stats_handle, unsigned int options ) void *stats_handle, unsigned int options )
@ -293,9 +296,10 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct stats_s *stats,
while( !(rc = read_block( inp, &pending_pkt, &keyblock) )) { while( !(rc = read_block( inp, &pending_pkt, &keyblock) )) {
if( keyblock->pkt->pkttype == PKT_PUBLIC_KEY ) if( keyblock->pkt->pkttype == PKT_PUBLIC_KEY )
rc = import_one (ctrl, fname, keyblock, rc = import_one (ctrl, fname, keyblock,
stats, fpr, fpr_len, options, 0); stats, fpr, fpr_len, options, 0, 0);
else if( keyblock->pkt->pkttype == PKT_SECRET_KEY ) else if( keyblock->pkt->pkttype == PKT_SECRET_KEY )
rc = import_secret_one (ctrl, fname, keyblock, stats, options); rc = import_secret_one (ctrl, fname, keyblock, stats,
opt.batch, options, 0);
else if( keyblock->pkt->pkttype == PKT_SIGNATURE else if( keyblock->pkt->pkttype == PKT_SIGNATURE
&& keyblock->pkt->pkt.signature->sig_class == 0x20 ) && keyblock->pkt->pkt.signature->sig_class == 0x20 )
rc = import_revoke_cert( fname, keyblock, stats ); rc = import_revoke_cert( fname, keyblock, stats );
@ -320,6 +324,57 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct stats_s *stats,
} }
/* Helper to migrate secring.gpg to GnuPG 2.1. */
gpg_error_t
import_old_secring (ctrl_t ctrl, const char *fname)
{
gpg_error_t err;
iobuf_t inp;
PACKET *pending_pkt = NULL;
kbnode_t keyblock = NULL; /* Need to initialize because gcc can't
grasp the return semantics of
read_block. */
struct stats_s *stats;
inp = iobuf_open (fname);
if (inp && is_secured_file (iobuf_get_fd (inp)))
{
iobuf_close (inp);
inp = NULL;
gpg_err_set_errno (EPERM);
}
if (!inp)
{
err = gpg_error_from_syserror ();
log_error (_("can't open '%s': %s\n"), fname, gpg_strerror (err));
return err;
}
getkey_disable_caches();
stats = import_new_stats_handle ();
while (!(err = read_block (inp, &pending_pkt, &keyblock)))
{
if (keyblock->pkt->pkttype == PKT_SECRET_KEY)
err = import_secret_one (ctrl, fname, keyblock, stats, 1, 0, 1);
release_kbnode (keyblock);
if (err)
break;
}
import_release_stats_handle (stats);
if (err == -1)
err = 0;
else if (err && gpg_err_code (err) != G10ERR_INV_KEYRING)
log_error (_("error reading '%s': %s\n"), fname, gpg_strerror (err));
else if (err)
log_error ("import from '%s' failed: %s\n", fname, gpg_strerror (err));
iobuf_close (inp);
iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname);
return err;
}
void void
import_print_stats (void *hd) import_print_stats (void *hd)
{ {
@ -771,16 +826,17 @@ check_prefs (ctrl_t ctrl, kbnode_t keyblock)
} }
/**************** /****************
* Try to import one keyblock. Return an error only in serious cases, but * Try to import one keyblock. Return an error only in serious cases,
* never for an invalid keyblock. It uses log_error to increase the * but never for an invalid keyblock. It uses log_error to increase
* internal errorcount, so that invalid input can be detected by programs * the internal errorcount, so that invalid input can be detected by
* which called gpg. * programs which called gpg. If SILENT is no messages are printed -
* even most error messages are suppressed.
*/ */
static int static int
import_one (ctrl_t ctrl, import_one (ctrl_t ctrl,
const char *fname, KBNODE keyblock, struct stats_s *stats, const char *fname, KBNODE keyblock, struct stats_s *stats,
unsigned char **fpr,size_t *fpr_len,unsigned int options, unsigned char **fpr,size_t *fpr_len,unsigned int options,
int from_sk ) int from_sk, int silent)
{ {
PKT_public_key *pk; PKT_public_key *pk;
PKT_public_key *pk_orig; PKT_public_key *pk_orig;
@ -804,7 +860,7 @@ import_one (ctrl_t ctrl,
keyid_from_pk( pk, keyid ); keyid_from_pk( pk, keyid );
uidnode = find_next_kbnode( keyblock, PKT_USER_ID ); uidnode = find_next_kbnode( keyblock, PKT_USER_ID );
if( opt.verbose && !opt.interactive ) if (opt.verbose && !opt.interactive && !silent)
{ {
log_info( "pub %s/%s %s ", log_info( "pub %s/%s %s ",
pubkey_string (pk, pkstrbuf, sizeof pkstrbuf), pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
@ -819,11 +875,12 @@ import_one (ctrl_t ctrl,
if( !uidnode ) if( !uidnode )
{ {
log_error( _("key %s: no user ID\n"), keystr_from_pk(pk)); if (!silent)
log_error( _("key %s: no user ID\n"), keystr_from_pk(pk));
return 0; return 0;
} }
if (opt.interactive) { if (opt.interactive && !silent) {
if(is_status_enabled()) if(is_status_enabled())
print_import_check (pk, uidnode->pkt->pkt.user_id); print_import_check (pk, uidnode->pkt->pkt.user_id);
merge_keys_and_selfsig (keyblock); merge_keys_and_selfsig (keyblock);
@ -856,7 +913,7 @@ import_one (ctrl_t ctrl,
return rc== -1? 0:rc; return rc== -1? 0:rc;
/* If we allow such a thing, mark unsigned uids as valid */ /* If we allow such a thing, mark unsigned uids as valid */
if( opt.allow_non_selfsigned_uid ) if( opt.allow_non_selfsigned_uid)
for( node=keyblock; node; node = node->next ) for( node=keyblock; node; node = node->next )
if( node->pkt->pkttype == PKT_USER_ID && !(node->flag & 1) ) if( node->pkt->pkttype == PKT_USER_ID && !(node->flag & 1) )
{ {
@ -869,9 +926,11 @@ import_one (ctrl_t ctrl,
} }
if( !delete_inv_parts( fname, keyblock, keyid, options ) ) { if( !delete_inv_parts( fname, keyblock, keyid, options ) ) {
log_error( _("key %s: no valid user IDs\n"), keystr_from_pk(pk)); if (!silent) {
if( !opt.quiet ) log_error( _("key %s: no valid user IDs\n"), keystr_from_pk(pk));
log_info(_("this may be caused by a missing self-signature\n")); if( !opt.quiet )
log_info(_("this may be caused by a missing self-signature\n"));
}
stats->no_user_id++; stats->no_user_id++;
return 0; return 0;
} }
@ -881,12 +940,13 @@ import_one (ctrl_t ctrl,
rc = get_pubkey_fast ( pk_orig, keyid ); rc = get_pubkey_fast ( pk_orig, keyid );
if( rc && rc != G10ERR_NO_PUBKEY && rc != G10ERR_UNU_PUBKEY ) if( rc && rc != G10ERR_NO_PUBKEY && rc != G10ERR_UNU_PUBKEY )
{ {
log_error( _("key %s: public key not found: %s\n"), if (!silent)
keystr(keyid), g10_errstr(rc)); log_error (_("key %s: public key not found: %s\n"),
keystr(keyid), g10_errstr(rc));
} }
else if ( rc && (opt.import_options&IMPORT_MERGE_ONLY) ) else if ( rc && (opt.import_options&IMPORT_MERGE_ONLY) )
{ {
if( opt.verbose ) if( opt.verbose && !silent )
log_info( _("key %s: new key - skipped\n"), keystr(keyid)); log_info( _("key %s: new key - skipped\n"), keystr(keyid));
rc = 0; rc = 0;
stats->skipped_new_keys++; stats->skipped_new_keys++;
@ -896,7 +956,7 @@ import_one (ctrl_t ctrl,
rc = keydb_locate_writable (hd, NULL); rc = keydb_locate_writable (hd, NULL);
if (rc) { if (rc) {
log_error (_("no writable keyring found: %s\n"), g10_errstr (rc)); log_error (_("no writable keyring found: %s\n"), g10_errstr (rc));
keydb_release (hd); keydb_release (hd);
return G10ERR_GENERAL; return G10ERR_GENERAL;
} }
@ -921,7 +981,7 @@ import_one (ctrl_t ctrl,
keydb_release (hd); keydb_release (hd);
/* we are ready */ /* we are ready */
if( !opt.quiet ) if( !opt.quiet && !silent)
{ {
char *p=get_user_id_native (keyid); char *p=get_user_id_native (keyid);
log_info( _("key %s: public key \"%s\" imported\n"), log_info( _("key %s: public key \"%s\" imported\n"),
@ -948,7 +1008,8 @@ import_one (ctrl_t ctrl,
* weird is going on */ * weird is going on */
if( cmp_public_keys( pk_orig, pk ) ) if( cmp_public_keys( pk_orig, pk ) )
{ {
log_error( _("key %s: doesn't match our copy\n"),keystr(keyid)); if (!silent)
log_error( _("key %s: doesn't match our copy\n"),keystr(keyid));
goto leave; goto leave;
} }
@ -1011,7 +1072,7 @@ import_one (ctrl_t ctrl,
revalidation_mark (); revalidation_mark ();
/* we are ready */ /* we are ready */
if( !opt.quiet ) if( !opt.quiet && !silent)
{ {
char *p=get_user_id_native(keyid); char *p=get_user_id_native(keyid);
if( n_uids == 1 ) if( n_uids == 1 )
@ -1053,7 +1114,7 @@ import_one (ctrl_t ctrl,
stats->n_sigs_cleaned +=n_sigs_cleaned; stats->n_sigs_cleaned +=n_sigs_cleaned;
stats->n_uids_cleaned +=n_uids_cleaned; stats->n_uids_cleaned +=n_uids_cleaned;
if (is_status_enabled ()) if (is_status_enabled () && !silent)
print_import_ok (pk, ((n_uids?2:0)|(n_sigs?4:0)|(n_subk?8:0))); print_import_ok (pk, ((n_uids?2:0)|(n_sigs?4:0)|(n_subk?8:0)));
} }
else else
@ -1062,7 +1123,7 @@ import_one (ctrl_t ctrl,
if (is_status_enabled ()) if (is_status_enabled ())
print_import_ok (pk, 0); print_import_ok (pk, 0);
if( !opt.quiet ) if( !opt.quiet && !silent)
{ {
char *p=get_user_id_native(keyid); char *p=get_user_id_native(keyid);
log_info( _("key %s: \"%s\" not changed\n"),keystr(keyid),p); log_info( _("key %s: \"%s\" not changed\n"),keystr(keyid),p);
@ -1129,9 +1190,12 @@ import_one (ctrl_t ctrl,
/* Transfer all the secret keys in SEC_KEYBLOCK to the gpg-agent. The /* Transfer all the secret keys in SEC_KEYBLOCK to the gpg-agent. The
function prints diagnostics and returns an error code. */ function prints diagnostics and returns an error code. If BATCH is
true the secret keys are stored by gpg-agent in the transfer format
(i.e. no re-protection and aksing for passphrases). */
static gpg_error_t static gpg_error_t
transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock) transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock,
int batch)
{ {
gpg_error_t err = 0; gpg_error_t err = 0;
void *kek = NULL; void *kek = NULL;
@ -1358,7 +1422,7 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
{ {
char *desc = gpg_format_keydesc (pk, FORMAT_KEYDESC_IMPORT, 1); char *desc = gpg_format_keydesc (pk, FORMAT_KEYDESC_IMPORT, 1);
err = agent_import_key (ctrl, desc, &cache_nonce, err = agent_import_key (ctrl, desc, &cache_nonce,
wrappedkey, wrappedkeylen, opt.batch); wrappedkey, wrappedkeylen, batch);
xfree (desc); xfree (desc);
} }
if (!err) if (!err)
@ -1454,7 +1518,8 @@ sec_to_pub_keyblock (kbnode_t sec_keyblock)
*/ */
static int static int
import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock, import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
struct stats_s *stats, unsigned int options) struct stats_s *stats, int batch, unsigned int options,
int for_migration)
{ {
PKT_public_key *pk; PKT_public_key *pk;
struct seckey_info *ski; struct seckey_info *ski;
@ -1475,7 +1540,7 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
keyid_from_pk (pk, keyid); keyid_from_pk (pk, keyid);
uidnode = find_next_kbnode (keyblock, PKT_USER_ID); uidnode = find_next_kbnode (keyblock, PKT_USER_ID);
if (opt.verbose) if (opt.verbose && !for_migration)
{ {
log_info ("sec %s/%s %s ", log_info ("sec %s/%s %s ",
pubkey_string (pk, pkstrbuf, sizeof pkstrbuf), pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
@ -1489,13 +1554,15 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
if ((options & IMPORT_NO_SECKEY)) if ((options & IMPORT_NO_SECKEY))
{ {
log_error (_("importing secret keys not allowed\n")); if (!for_migration)
log_error (_("importing secret keys not allowed\n"));
return 0; return 0;
} }
if (!uidnode) if (!uidnode)
{ {
log_error( _("key %s: no user ID\n"), keystr_from_pk (pk)); if (!for_migration)
log_error( _("key %s: no user ID\n"), keystr_from_pk (pk));
return 0; return 0;
} }
@ -1511,8 +1578,9 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
cipher algorithm (only checks the primary key, though). */ cipher algorithm (only checks the primary key, though). */
if (ski->algo > 110) if (ski->algo > 110)
{ {
log_error (_("key %s: secret key with invalid cipher %d" if (!for_migration)
" - skipped\n"), keystr_from_pk (pk), ski->algo); log_error (_("key %s: secret key with invalid cipher %d"
" - skipped\n"), keystr_from_pk (pk), ski->algo);
return 0; return 0;
} }
@ -1542,7 +1610,7 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
public key block, and below we will output another one for public key block, and below we will output another one for
the secret keys. FIXME? */ the secret keys. FIXME? */
import_one (ctrl, fname, pub_keyblock, stats, import_one (ctrl, fname, pub_keyblock, stats,
NULL, NULL, options, 1); NULL, NULL, options, 1, for_migration);
/* Fixme: We should check for an invalid keyblock and /* Fixme: We should check for an invalid keyblock and
cancel the secret key import in this case. */ cancel the secret key import in this case. */
@ -1564,7 +1632,7 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
else else
{ {
nr_prev = stats->secret_imported; nr_prev = stats->secret_imported;
if (!transfer_secret_keys (ctrl, stats, keyblock)) if (!transfer_secret_keys (ctrl, stats, keyblock, batch))
{ {
int status = 16; int status = 16;
if (!opt.quiet) if (!opt.quiet)

View File

@ -290,6 +290,7 @@ int import_keys_stream (ctrl_t ctrl, iobuf_t inp, void *stats_hd,
int import_keys_es_stream (ctrl_t ctrl, estream_t fp, void *stats_handle, int import_keys_es_stream (ctrl_t ctrl, estream_t fp, void *stats_handle,
unsigned char **fpr, size_t *fpr_len, unsigned char **fpr, size_t *fpr_len,
unsigned int options); unsigned int options);
gpg_error_t import_old_secring (ctrl_t ctrl, const char *fname);
void *import_new_stats_handle (void); void *import_new_stats_handle (void);
void import_release_stats_handle (void *p); void import_release_stats_handle (void *p);
void import_print_stats (void *hd); void import_print_stats (void *hd);
@ -379,4 +380,8 @@ int card_store_subkey (KBNODE node, int use);
#define S2K_DECODE_COUNT(_val) ((16ul + ((_val) & 15)) << (((_val) >> 4) + 6)) #define S2K_DECODE_COUNT(_val) ((16ul + ((_val) & 15)) << (((_val) >> 4) + 6))
/*-- migrate.c --*/
void migrate_secring (ctrl_t ctrl);
#endif /*G10_MAIN_H*/ #endif /*G10_MAIN_H*/

94
g10/migrate.c Normal file
View File

@ -0,0 +1,94 @@
/* migrate.c - Migrate from earlier GnupG versions.
* Copyright (C) 2014 Werner Koch
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "gpg.h"
#include "options.h"
#include "keydb.h"
#include "util.h"
#include "main.h"
#ifdef HAVE_DOSISH_SYSTEM
# define V21_MIGRATION_FNAME "gpg-v21-migrated"
#else
# define V21_MIGRATION_FNAME ".gpg-v21-migrated"
#endif
/* Check whether a default secring.gpg from GnuPG < 2.1 exists and
import it if not yet done. */
void
migrate_secring (ctrl_t ctrl)
{
dotlock_t lockhd = NULL;
char *secring = NULL;
char *flagfile = NULL;
secring = make_filename (opt.homedir, "secring" EXTSEP_S "gpg", NULL);
if (access (secring, F_OK))
goto leave; /* Does not exist or is not readable. */
flagfile = make_filename (opt.homedir, V21_MIGRATION_FNAME, NULL);
if (!access (flagfile, F_OK))
goto leave; /* Does exist - fine. */
log_info ("starting migration from earlier GnuPG versions\n");
lockhd = dotlock_create (flagfile, 0);
if (!lockhd)
{
log_error ("can't allocate lock for '%s': %s\n",
flagfile, gpg_strerror (gpg_error_from_syserror ()));
goto leave;
}
if (dotlock_take (lockhd, -1))
{
log_error ("can't lock '%s': %s\n",
flagfile, gpg_strerror (gpg_error_from_syserror ()));
dotlock_destroy (lockhd);
lockhd = NULL;
goto leave;
}
log_info ("porting secret keys from '%s' to gpg-agent\n", secring);
if (!import_old_secring (ctrl, secring))
{
FILE *fp = fopen (flagfile, "w");
if (!fp || fclose (fp))
log_error ("error creating flag file '%s': %s\n",
flagfile, gpg_strerror (gpg_error_from_syserror ()));
else
log_info ("migration succeeded\n");
}
leave:
if (lockhd)
{
dotlock_release (lockhd);
dotlock_destroy (lockhd);
}
xfree (flagfile);
xfree (secring);
}