aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2014-08-14 15:14:21 +0000
committerWerner Koch <[email protected]>2014-08-14 15:15:50 +0000
commitc4b60cdae8dbf68206fd105fd09adeb61a9dafe4 (patch)
treee63d85f116ffdae27d76ff2bab4c32df9c323646
parentbuild: Yet another autogen.sh --find-version change. (diff)
downloadgnupg-c4b60cdae8dbf68206fd105fd09adeb61a9dafe4.tar.gz
gnupg-c4b60cdae8dbf68206fd105fd09adeb61a9dafe4.zip
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.
-rw-r--r--sm/gpgsm.c7
-rw-r--r--sm/gpgsm.h1
-rw-r--r--sm/keydb.c316
3 files changed, 223 insertions, 101 deletions
diff --git a/sm/gpgsm.c b/sm/gpgsm.c
index ded31986d..2faf203dd 100644
--- a/sm/gpgsm.c
+++ b/sm/gpgsm.c
@@ -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;
diff --git a/sm/gpgsm.h b/sm/gpgsm.h
index 83918cc9a..e8322b731 100644
--- a/sm/gpgsm.h
+++ b/sm/gpgsm.h
@@ -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. */
diff --git a/sm/keydb.c b/sm/keydb.c
index d9eb2e073..5a250b020 100644
--- a/sm/keydb.c
+++ b/sm/keydb.c
@@ -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;
-
- 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].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);
}
- *last_slash_in_filename = DIRSEP_C;
- }
-#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;
- }
-
- 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++;
- }
- }
+ used_resources++;
+ }
+ }
+ break;
- break;
default:
log_error ("resource type of '%s' not supported\n", url);
rc = gpg_error (GPG_ERR_NOT_SUPPORTED);