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:
Werner Koch 2014-08-14 17:14:21 +02:00
parent 21e5125e44
commit c4b60cdae8
3 changed files with 222 additions and 100 deletions

View File

@ -969,7 +969,10 @@ main ( int argc, char **argv)
default_config = 0;
}
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)
opt.homedir = pargs.r.ret_str;
else if (pargs.r_opt == aCallProtectTool)
@ -1270,7 +1273,7 @@ main ( int argc, char **argv)
goto next_pass;
}
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 oAgentProgram: opt.agent_program = pargs.r.ret_str; break;

View File

@ -59,6 +59,7 @@ struct
int answer_yes; /* assume yes on most questions */
int answer_no; /* assume no on most questions */
int dry_run; /* don't change any persistent data */
int no_homedir_creation;
const char *homedir; /* Configuration directory name */
const char *config_filename; /* Name of the used config file. */

View File

@ -1,5 +1,6 @@
/* keydb.c - key database dispatcher
* Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc.
* Copyright (C) 2014 g10 Code GmbH
*
* 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
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).
* 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
* if the function has created a a new keybox.
* if the function has created a new keybox.
*/
int
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;
char *filename = NULL;
int rc = 0;
FILE *fp;
KeydbResourceType rt = KEYDB_RESOURCE_TYPE_NONE;
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 */
if (rt == KEYDB_RESOURCE_TYPE_NONE)
{
FILE *fp2 = fopen( filename, "rb" );
FILE *fp = fopen( filename, "rb" );
if (fp2) {
u32 magic;
if (fp)
{
u32 magic;
/* FIXME: check for the keybox magic */
if (fread( &magic, 4, 1, fp2) == 1 )
{
if (magic == 0x13579ace || magic == 0xce9a5713)
; /* GDBM magic - no more support */
else
rt = KEYDB_RESOURCE_TYPE_KEYBOX;
}
else /* maybe empty: assume ring */
rt = KEYDB_RESOURCE_TYPE_KEYBOX;
fclose (fp2);
}
else /* no file yet: create ring */
/* FIXME: check for the keybox magic */
if (fread (&magic, 4, 1, fp) == 1 )
{
if (magic == 0x13579ace || magic == 0xce9a5713)
; /* GDBM magic - no more support */
else
rt = KEYDB_RESOURCE_TYPE_KEYBOX;
}
else /* maybe empty: assume keybox */
rt = KEYDB_RESOURCE_TYPE_KEYBOX;
fclose (fp);
}
else /* no file yet: create 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;
case KEYDB_RESOURCE_TYPE_KEYBOX:
fp = fopen (filename, "rb");
if (!fp && !force)
{
rc = gpg_error (gpg_err_code_from_errno (errno));
goto leave;
}
if (!fp)
{ /* no file */
#if 0 /* no autocreate of the homedirectory yet */
rc = maybe_create_keybox (filename, force, auto_created);
if (rc)
goto leave;
/* 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
{
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);
*last_slash_in_filename = 0;
if (access (filename, F_OK))
{ /* on the first time we try to create the default
homedir and in this case the process will be
terminated, so that on the next invocation can
read the options file in on startup */
try_make_homedir (filename);
rc = gpg_error (GPG_ERR_FILE_OPEN_ERROR);
*last_slash_in_filename = DIRSEP_C;
goto leave;
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);
}
*last_slash_in_filename = DIRSEP_C;
used_resources++;
}
#endif
fp = fopen (filename, "w");
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;
}
}
break;
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:
log_error ("resource type of '%s' not supported\n", url);
rc = gpg_error (GPG_ERR_NOT_SUPPORTED);