diff --git a/g10/ChangeLog b/g10/ChangeLog index 2f1204475..d874c8385 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,11 @@ +2004-08-11 Werner Koch + + * gpgv.c (destroy_dotlock): New stub. + + * keydb.c (keydb_add_resource): Factored keyring creation out to .. + (maybe_create_keyring): .. new. Make sure that we do the checks + in a locked state. Problem reported by Stefan Haller. + 2004-08-09 Werner Koch * Makefile.am (LDADD): Replaced INTLLIBS by LIBINTL. diff --git a/g10/gpgv.c b/g10/gpgv.c index 31034f1fe..6337d7242 100644 --- a/g10/gpgv.c +++ b/g10/gpgv.c @@ -390,6 +390,7 @@ int tty_no_terminal(int onoff) {return 0;} /* We do not do any locking, so use these stubs here */ void disable_dotlock(void) {} DOTLOCK create_dotlock( const char *file_to_lock ) { return NULL; } +void destroy_dotlock (DOTLOCK h) { }; int make_dotlock( DOTLOCK h, long timeout ) { return 0;} int release_dotlock( DOTLOCK h ) {return 0;} void remove_lockfiles(void) {} diff --git a/g10/keydb.c b/g10/keydb.c index b85d83649..96c37b4d9 100644 --- a/g10/keydb.c +++ b/g10/keydb.c @@ -1,5 +1,5 @@ /* keydb.c - key database dispatcher - * Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -69,6 +69,111 @@ static int lock_all (KEYDB_HANDLE hd); static void unlock_all (KEYDB_HANDLE hd); +/* Handle the creation of a keyring if it does not yet exist. Take + into acount that other processes might have the keyring alread + locked. This lock check does not work if the directory itself is + not yet available. */ +static int +maybe_create_keyring (char *filename, int force) +{ + DOTLOCK lockhd; + IOBUF iobuf; + int rc; + mode_t oldmask; + char *last_slash_in_filename; + + /* 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 G10ERR_OPEN_FILE; + + /* To avoid races with other instances of gpg trying to create or + update the keyring (it is removed during an update for a short + time), we do the next stuff in a locked state. */ + lockhd = create_dotlock (filename); + 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 G10ERR_OPEN_FILE; + else + return G10ERR_GENERAL; + } + + if ( make_dotlock (lockhd, -1) ) + { + /* This is something bad. Probably a stale lockfile. */ + log_info ("can't lock `%s'\n", filename ); + rc = G10ERR_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. */ + + 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 check again. */ + static int tried; + + if (!tried) + { + tried = 1; + try_make_homedir (filename); + } + if (access (filename, F_OK)) + { + rc = G10ERR_OPEN_FILE; + *last_slash_in_filename = DIRSEP_C; + goto leave; + } + } + *last_slash_in_filename = DIRSEP_C; + + oldmask = umask (077); + iobuf = iobuf_create (filename); + umask (oldmask); + if (!iobuf) + { + log_error ( _("error creating keyring `%s': %s\n"), + filename, strerror(errno)); + rc = G10ERR_OPEN_FILE; + goto leave; + } + + if (!opt.quiet) + log_info (_("keyring `%s' created\n"), filename); + + iobuf_close (iobuf); + /* Must invalidate that ugly cache */ + iobuf_ioctl (NULL, 2, 0, filename); + rc = 0; + + leave: + release_dotlock (lockhd); + destroy_dotlock (lockhd); + return rc; +} + + /* * Register a resource (which currently may only be a keyring file). * The first keyring which is added by this function is @@ -81,7 +186,6 @@ keydb_add_resource (const char *url, int force, int secret) { static int any_secret, any_public; const char *resname = url; - IOBUF iobuf = NULL; char *filename = NULL; int rc = 0; KeydbResourceType rt = KEYDB_RESOURCE_TYPE_NONE; @@ -145,56 +249,9 @@ keydb_add_resource (const char *url, int force, int secret) goto leave; case KEYDB_RESOURCE_TYPE_KEYRING: - if (access(filename, F_OK)) - { /* file does not exist */ - mode_t oldmask; - char *last_slash_in_filename; - - if (!force) - { - rc = G10ERR_OPEN_FILE; - goto leave; - } - - 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 check again. */ - static int tried; - - if (!tried) - { - tried = 1; - try_make_homedir (filename); - } - if (access (filename, F_OK)) - { - rc = G10ERR_OPEN_FILE; - *last_slash_in_filename = DIRSEP_C; - goto leave; - } - } - *last_slash_in_filename = DIRSEP_C; - - oldmask=umask(077); - iobuf = iobuf_create (filename); - umask(oldmask); - if (!iobuf) - { - log_error ( _("error creating keyring `%s': %s\n"), - filename, strerror(errno)); - rc = G10ERR_OPEN_FILE; - goto leave; - } - - if (!opt.quiet) - log_info (_("keyring `%s' created\n"), filename); - iobuf_close (iobuf); - iobuf = NULL; - /* must invalidate that ugly cache */ - iobuf_ioctl (NULL, 2, 0, (char*)filename); - } /* end file creation */ + rc = maybe_create_keyring (filename, force); + if (rc) + goto leave; token = keyring_register_filename (filename, secret); if (!token) diff --git a/include/util.h b/include/util.h index bbbef0472..8156a7ed7 100644 --- a/include/util.h +++ b/include/util.h @@ -144,6 +144,7 @@ typedef struct dotlock_handle *DOTLOCK; void disable_dotlock(void); DOTLOCK create_dotlock( const char *file_to_lock ); +void destroy_dotlock ( DOTLOCK h ); int make_dotlock( DOTLOCK h, long timeout ); int release_dotlock( DOTLOCK h ); void remove_lockfiles (void); diff --git a/util/ChangeLog b/util/ChangeLog index adfd49191..d151326d1 100644 --- a/util/ChangeLog +++ b/util/ChangeLog @@ -1,3 +1,8 @@ +2004-08-11 Werner Koch + + * dotlock.c (destroy_dotlock): New. + (remove_lockfiles): Implement in terms of destroy_dotlock. + 2004-08-09 Werner Koch * Makefile.am (http-test): Replaced INTLLIBS by LIBINTL. @@ -1105,7 +1110,7 @@ Fri Feb 13 15:14:13 1998 Werner Koch (wk@isil.d.shuttle.de) - Copyright 1998,1999,2000,2001,2002,2003 Free Software Foundation, Inc. + Copyright 1998,1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. This file is free software; as a special exception the author gives unlimited permission to copy and/or distribute it, with or without diff --git a/util/dotlock.c b/util/dotlock.c index f4ab37327..f28b0e409 100644 --- a/util/dotlock.c +++ b/util/dotlock.c @@ -1,5 +1,5 @@ /* dotlock.c - dotfile locking - * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001, 2004 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -197,6 +197,28 @@ create_dotlock( const char *file_to_lock ) return h; } + +void +destroy_dotlock ( DOTLOCK h ) +{ +#if !defined (HAVE_DOSISH_SYSTEM) + if ( h ) + { + if (!h->disable) + { + if (h->locked) + unlink (h->lockname); + unlink (h->tname); + m_free (h->tname); + m_free (h->lockname); + } + m_free(h); + } +#endif +} + + + static int maybe_deadlock( DOTLOCK h ) { @@ -407,14 +429,7 @@ remove_lockfiles() while( h ) { h2 = h->next; - if( !h->disable ) { - if( h->locked ) - unlink( h->lockname ); - unlink(h->tname); - m_free(h->tname); - m_free(h->lockname); - } - m_free(h); + destroy_dotlock (h); h = h2; } #endif