mirror of
git://git.gnupg.org/gnupg.git
synced 2025-04-12 22:11:29 +02:00
sm: Create homedir and lock empty keybox creation.
* sm/gpgsm.h (opt): Add field "no_homedir_creation". * sm/gpgsm.c (main): Set it if --no-options is used. * sm/keydb.c (try_make_homedir): New. Similar to the one from g10/openfile.c. (maybe_create_keybox): New. Similar to the one from g10/keydb.c. (keydb_add_resource): Replace some code by maybe_create_keybox.
This commit is contained in:
parent
21e5125e44
commit
c4b60cdae8
@ -969,7 +969,10 @@ main ( int argc, char **argv)
|
|||||||
default_config = 0;
|
default_config = 0;
|
||||||
}
|
}
|
||||||
else if (pargs.r_opt == oNoOptions)
|
else if (pargs.r_opt == oNoOptions)
|
||||||
default_config = 0; /* --no-options */
|
{
|
||||||
|
default_config = 0; /* --no-options */
|
||||||
|
opt.no_homedir_creation = 1;
|
||||||
|
}
|
||||||
else if (pargs.r_opt == oHomedir)
|
else if (pargs.r_opt == oHomedir)
|
||||||
opt.homedir = pargs.r.ret_str;
|
opt.homedir = pargs.r.ret_str;
|
||||||
else if (pargs.r_opt == aCallProtectTool)
|
else if (pargs.r_opt == aCallProtectTool)
|
||||||
@ -1270,7 +1273,7 @@ main ( int argc, char **argv)
|
|||||||
goto next_pass;
|
goto next_pass;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case oNoOptions: break; /* no-options */
|
case oNoOptions: opt.no_homedir_creation = 1; break; /* no-options */
|
||||||
case oHomedir: opt.homedir = pargs.r.ret_str; break;
|
case oHomedir: opt.homedir = pargs.r.ret_str; break;
|
||||||
case oAgentProgram: opt.agent_program = pargs.r.ret_str; break;
|
case oAgentProgram: opt.agent_program = pargs.r.ret_str; break;
|
||||||
|
|
||||||
|
@ -59,6 +59,7 @@ struct
|
|||||||
int answer_yes; /* assume yes on most questions */
|
int answer_yes; /* assume yes on most questions */
|
||||||
int answer_no; /* assume no on most questions */
|
int answer_no; /* assume no on most questions */
|
||||||
int dry_run; /* don't change any persistent data */
|
int dry_run; /* don't change any persistent data */
|
||||||
|
int no_homedir_creation;
|
||||||
|
|
||||||
const char *homedir; /* Configuration directory name */
|
const char *homedir; /* Configuration directory name */
|
||||||
const char *config_filename; /* Name of the used config file. */
|
const char *config_filename; /* Name of the used config file. */
|
||||||
|
314
sm/keydb.c
314
sm/keydb.c
@ -1,5 +1,6 @@
|
|||||||
/* keydb.c - key database dispatcher
|
/* keydb.c - key database dispatcher
|
||||||
* Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc.
|
* Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc.
|
||||||
|
* Copyright (C) 2014 g10 Code GmbH
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -68,11 +69,173 @@ static int lock_all (KEYDB_HANDLE hd);
|
|||||||
static void unlock_all (KEYDB_HANDLE hd);
|
static void unlock_all (KEYDB_HANDLE hd);
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
try_make_homedir (const char *fname)
|
||||||
|
{
|
||||||
|
const char *defhome = standard_homedir ();
|
||||||
|
|
||||||
|
/* Create the directory only if the supplied directory name is the
|
||||||
|
same as the default one. This way we avoid to create arbitrary
|
||||||
|
directories when a non-default home directory is used. To cope
|
||||||
|
with HOME, we do compare only the suffix if we see that the
|
||||||
|
default homedir does start with a tilde. */
|
||||||
|
if ( opt.dry_run || opt.no_homedir_creation )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
( !compare_filenames (fname, defhome) )
|
||||||
|
#else
|
||||||
|
( *defhome == '~'
|
||||||
|
&& (strlen(fname) >= strlen (defhome+1)
|
||||||
|
&& !strcmp(fname+strlen(fname)-strlen(defhome+1), defhome+1 ) ))
|
||||||
|
|| (*defhome != '~' && !compare_filenames( fname, defhome ) )
|
||||||
|
#endif
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (gnupg_mkdir (fname, "-rwx"))
|
||||||
|
log_info (_("can't create directory '%s': %s\n"),
|
||||||
|
fname, strerror(errno) );
|
||||||
|
else if (!opt.quiet )
|
||||||
|
log_info (_("directory '%s' created\n"), fname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Handle the creation of a keybox if it does not yet exist. Take
|
||||||
|
into acount that other processes might have the keybox already
|
||||||
|
locked. This lock check does not work if the directory itself is
|
||||||
|
not yet available. If R_CREATED is not NULL it will be set to true
|
||||||
|
if the function created a new keybox. */
|
||||||
|
static int
|
||||||
|
maybe_create_keybox (char *filename, int force, int *r_created)
|
||||||
|
{
|
||||||
|
dotlock_t lockhd = NULL;
|
||||||
|
FILE *fp;
|
||||||
|
int rc;
|
||||||
|
mode_t oldmask;
|
||||||
|
char *last_slash_in_filename;
|
||||||
|
int save_slash;
|
||||||
|
|
||||||
|
if (r_created)
|
||||||
|
*r_created = 0;
|
||||||
|
|
||||||
|
/* A quick test whether the filename already exists. */
|
||||||
|
if (!access (filename, F_OK))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* If we don't want to create a new file at all, there is no need to
|
||||||
|
go any further - bail out right here. */
|
||||||
|
if (!force)
|
||||||
|
return gpg_error (GPG_ERR_ENOENT);
|
||||||
|
|
||||||
|
/* First of all we try to create the home directory. Note, that we
|
||||||
|
don't do any locking here because any sane application of gpg
|
||||||
|
would create the home directory by itself and not rely on gpg's
|
||||||
|
tricky auto-creation which is anyway only done for some home
|
||||||
|
directory name patterns. */
|
||||||
|
last_slash_in_filename = strrchr (filename, DIRSEP_C);
|
||||||
|
#if HAVE_W32_SYSTEM
|
||||||
|
{
|
||||||
|
/* Windows may either have a slash or a backslash. Take care of it. */
|
||||||
|
char *p = strrchr (filename, '/');
|
||||||
|
if (!last_slash_in_filename || p > last_slash_in_filename)
|
||||||
|
last_slash_in_filename = p;
|
||||||
|
}
|
||||||
|
#endif /*HAVE_W32_SYSTEM*/
|
||||||
|
if (!last_slash_in_filename)
|
||||||
|
return gpg_error (GPG_ERR_ENOENT); /* No slash at all - should
|
||||||
|
not happen though. */
|
||||||
|
save_slash = *last_slash_in_filename;
|
||||||
|
*last_slash_in_filename = 0;
|
||||||
|
if (access(filename, F_OK))
|
||||||
|
{
|
||||||
|
static int tried;
|
||||||
|
|
||||||
|
if (!tried)
|
||||||
|
{
|
||||||
|
tried = 1;
|
||||||
|
try_make_homedir (filename);
|
||||||
|
}
|
||||||
|
if (access (filename, F_OK))
|
||||||
|
{
|
||||||
|
rc = gpg_error_from_syserror ();
|
||||||
|
*last_slash_in_filename = save_slash;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*last_slash_in_filename = save_slash;
|
||||||
|
|
||||||
|
/* To avoid races with other instances of gpg trying to create or
|
||||||
|
update the keybox (it is removed during an update for a short
|
||||||
|
time), we do the next stuff in a locked state. */
|
||||||
|
lockhd = dotlock_create (filename, 0);
|
||||||
|
if (!lockhd)
|
||||||
|
{
|
||||||
|
/* A reason for this to fail is that the directory is not
|
||||||
|
writable. However, this whole locking stuff does not make
|
||||||
|
sense if this is the case. An empty non-writable directory
|
||||||
|
with no keyring is not really useful at all. */
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("can't allocate lock for '%s'\n", filename );
|
||||||
|
|
||||||
|
if (!force)
|
||||||
|
return gpg_error (GPG_ERR_ENOENT);
|
||||||
|
else
|
||||||
|
return gpg_error (GPG_ERR_GENERAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( dotlock_take (lockhd, -1) )
|
||||||
|
{
|
||||||
|
/* This is something bad. Probably a stale lockfile. */
|
||||||
|
log_info ("can't lock '%s'\n", filename);
|
||||||
|
rc = gpg_error (GPG_ERR_GENERAL);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now the real test while we are locked. */
|
||||||
|
if (!access(filename, F_OK))
|
||||||
|
{
|
||||||
|
rc = 0; /* Okay, we may access the file now. */
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The file does not yet exist, create it now. */
|
||||||
|
oldmask = umask (077);
|
||||||
|
fp = fopen (filename, "w");
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
rc = gpg_error_from_syserror ();
|
||||||
|
umask (oldmask);
|
||||||
|
log_error (_("error creating keybox '%s': %s\n"),
|
||||||
|
filename, gpg_strerror (rc));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
umask (oldmask);
|
||||||
|
|
||||||
|
if (!opt.quiet)
|
||||||
|
log_info (_("keybox '%s' created\n"), filename);
|
||||||
|
if (r_created)
|
||||||
|
*r_created = 1;
|
||||||
|
|
||||||
|
fclose (fp);
|
||||||
|
rc = 0;
|
||||||
|
|
||||||
|
leave:
|
||||||
|
if (lockhd)
|
||||||
|
{
|
||||||
|
dotlock_release (lockhd);
|
||||||
|
dotlock_destroy (lockhd);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register a resource (which currently may only be a keybox file).
|
* Register a resource (which currently may only be a keybox file).
|
||||||
* The first keybox which is added by this function is created if it
|
* The first keybox which is added by this function is created if it
|
||||||
* does not exist. If AUTO_CREATED is not NULL it will be set to true
|
* does not exist. If AUTO_CREATED is not NULL it will be set to true
|
||||||
* if the function has created a a new keybox.
|
* if the function has created a new keybox.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
keydb_add_resource (const char *url, int force, int secret, int *auto_created)
|
keydb_add_resource (const char *url, int force, int secret, int *auto_created)
|
||||||
@ -81,7 +244,6 @@ keydb_add_resource (const char *url, int force, int secret, int *auto_created)
|
|||||||
const char *resname = url;
|
const char *resname = url;
|
||||||
char *filename = NULL;
|
char *filename = NULL;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
FILE *fp;
|
|
||||||
KeydbResourceType rt = KEYDB_RESOURCE_TYPE_NONE;
|
KeydbResourceType rt = KEYDB_RESOURCE_TYPE_NONE;
|
||||||
|
|
||||||
if (auto_created)
|
if (auto_created)
|
||||||
@ -124,24 +286,25 @@ keydb_add_resource (const char *url, int force, int secret, int *auto_created)
|
|||||||
/* see whether we can determine the filetype */
|
/* see whether we can determine the filetype */
|
||||||
if (rt == KEYDB_RESOURCE_TYPE_NONE)
|
if (rt == KEYDB_RESOURCE_TYPE_NONE)
|
||||||
{
|
{
|
||||||
FILE *fp2 = fopen( filename, "rb" );
|
FILE *fp = fopen( filename, "rb" );
|
||||||
|
|
||||||
if (fp2) {
|
if (fp)
|
||||||
u32 magic;
|
{
|
||||||
|
u32 magic;
|
||||||
|
|
||||||
/* FIXME: check for the keybox magic */
|
/* FIXME: check for the keybox magic */
|
||||||
if (fread( &magic, 4, 1, fp2) == 1 )
|
if (fread (&magic, 4, 1, fp) == 1 )
|
||||||
{
|
{
|
||||||
if (magic == 0x13579ace || magic == 0xce9a5713)
|
if (magic == 0x13579ace || magic == 0xce9a5713)
|
||||||
; /* GDBM magic - no more support */
|
; /* GDBM magic - no more support */
|
||||||
else
|
else
|
||||||
rt = KEYDB_RESOURCE_TYPE_KEYBOX;
|
rt = KEYDB_RESOURCE_TYPE_KEYBOX;
|
||||||
}
|
}
|
||||||
else /* maybe empty: assume ring */
|
else /* maybe empty: assume keybox */
|
||||||
rt = KEYDB_RESOURCE_TYPE_KEYBOX;
|
rt = KEYDB_RESOURCE_TYPE_KEYBOX;
|
||||||
fclose (fp2);
|
fclose (fp);
|
||||||
}
|
}
|
||||||
else /* no file yet: create ring */
|
else /* no file yet: create keybox */
|
||||||
rt = KEYDB_RESOURCE_TYPE_KEYBOX;
|
rt = KEYDB_RESOURCE_TYPE_KEYBOX;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,91 +316,46 @@ keydb_add_resource (const char *url, int force, int secret, int *auto_created)
|
|||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
case KEYDB_RESOURCE_TYPE_KEYBOX:
|
||||||
fp = fopen (filename, "rb");
|
rc = maybe_create_keybox (filename, force, auto_created);
|
||||||
if (!fp && !force)
|
if (rc)
|
||||||
{
|
goto leave;
|
||||||
rc = gpg_error (gpg_err_code_from_errno (errno));
|
/* Now register the file */
|
||||||
goto leave;
|
{
|
||||||
}
|
void *token = keybox_register_file (filename, secret);
|
||||||
|
if (!token)
|
||||||
if (!fp)
|
; /* already registered - ignore it */
|
||||||
{ /* no file */
|
else if (used_resources >= MAX_KEYDB_RESOURCES)
|
||||||
#if 0 /* no autocreate of the homedirectory yet */
|
rc = gpg_error (GPG_ERR_RESOURCE_LIMIT);
|
||||||
|
else
|
||||||
{
|
{
|
||||||
char *last_slash_in_filename;
|
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;
|
||||||
|
|
||||||
last_slash_in_filename = strrchr (filename, DIRSEP_C);
|
all_resources[used_resources].lockhandle
|
||||||
*last_slash_in_filename = 0;
|
= dotlock_create (filename, 0);
|
||||||
if (access (filename, F_OK))
|
if (!all_resources[used_resources].lockhandle)
|
||||||
{ /* on the first time we try to create the default
|
log_fatal ( _("can't create lock for '%s'\n"), filename);
|
||||||
homedir and in this case the process will be
|
|
||||||
terminated, so that on the next invocation can
|
/* Do a compress run if needed and the file is not locked. */
|
||||||
read the options file in on startup */
|
if (!dotlock_take (all_resources[used_resources].lockhandle, 0))
|
||||||
try_make_homedir (filename);
|
{
|
||||||
rc = gpg_error (GPG_ERR_FILE_OPEN_ERROR);
|
KEYBOX_HANDLE kbxhd = keybox_new (token, secret);
|
||||||
*last_slash_in_filename = DIRSEP_C;
|
|
||||||
goto leave;
|
if (kbxhd)
|
||||||
|
{
|
||||||
|
keybox_compress (kbxhd);
|
||||||
|
keybox_release (kbxhd);
|
||||||
|
}
|
||||||
|
dotlock_release (all_resources[used_resources].lockhandle);
|
||||||
}
|
}
|
||||||
*last_slash_in_filename = DIRSEP_C;
|
|
||||||
|
used_resources++;
|
||||||
}
|
}
|
||||||
#endif
|
}
|
||||||
fp = fopen (filename, "w");
|
break;
|
||||||
if (!fp)
|
|
||||||
{
|
|
||||||
rc = gpg_error (gpg_err_code_from_errno (errno));
|
|
||||||
log_error (_("error creating keybox '%s': %s\n"),
|
|
||||||
filename, strerror(errno));
|
|
||||||
if (errno == ENOENT)
|
|
||||||
log_info (_("you may want to start the gpg-agent first\n"));
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!opt.quiet)
|
|
||||||
log_info (_("keybox '%s' created\n"), filename);
|
|
||||||
if (auto_created)
|
|
||||||
*auto_created = 1;
|
|
||||||
}
|
|
||||||
fclose (fp);
|
|
||||||
fp = NULL;
|
|
||||||
/* now register the file */
|
|
||||||
{
|
|
||||||
|
|
||||||
void *token = keybox_register_file (filename, secret);
|
|
||||||
if (!token)
|
|
||||||
; /* already registered - ignore it */
|
|
||||||
else if (used_resources >= MAX_KEYDB_RESOURCES)
|
|
||||||
rc = gpg_error (GPG_ERR_RESOURCE_LIMIT);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
|
|
||||||
all_resources[used_resources].lockhandle
|
|
||||||
= dotlock_create (filename, 0);
|
|
||||||
if (!all_resources[used_resources].lockhandle)
|
|
||||||
log_fatal ( _("can't create lock for '%s'\n"), filename);
|
|
||||||
|
|
||||||
/* Do a compress run if needed and the file is not locked. */
|
|
||||||
if (!dotlock_take (all_resources[used_resources].lockhandle, 0))
|
|
||||||
{
|
|
||||||
KEYBOX_HANDLE kbxhd = keybox_new (token, secret);
|
|
||||||
|
|
||||||
if (kbxhd)
|
|
||||||
{
|
|
||||||
keybox_compress (kbxhd);
|
|
||||||
keybox_release (kbxhd);
|
|
||||||
}
|
|
||||||
dotlock_release (all_resources[used_resources].lockhandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
used_resources++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
log_error ("resource type of '%s' not supported\n", url);
|
log_error ("resource type of '%s' not supported\n", url);
|
||||||
rc = gpg_error (GPG_ERR_NOT_SUPPORTED);
|
rc = gpg_error (GPG_ERR_NOT_SUPPORTED);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user