aboutsummaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/compliance.c13
-rw-r--r--common/compliance.h1
-rw-r--r--common/dotlock.c322
-rw-r--r--common/dotlock.h23
-rw-r--r--common/homedir.c192
-rw-r--r--common/name-value.c61
-rw-r--r--common/name-value.h7
-rw-r--r--common/openpgpdefs.h3
-rw-r--r--common/t-dotlock.c36
9 files changed, 538 insertions, 120 deletions
diff --git a/common/compliance.c b/common/compliance.c
index 59d94038d..04978ed1b 100644
--- a/common/compliance.c
+++ b/common/compliance.c
@@ -256,6 +256,13 @@ gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
if (! initialized)
return 1;
+ /* Map the the generic ECC algo to ECDSA if requested. */
+ if ((algo_flags & PK_ALGO_FLAG_ECC18)
+ && algo == GCRY_PK_ECC
+ && (use == PK_USE_VERIFICATION
+ || use == PK_USE_SIGNING))
+ algo = GCRY_PK_ECDSA;
+
switch (compliance)
{
case CO_DE_VS:
@@ -280,7 +287,6 @@ gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
default:
log_assert (!"reached");
}
- (void)algo_flags;
break;
case PUBKEY_ALGO_DSA:
@@ -301,7 +307,7 @@ gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
result = (use == PK_USE_DECRYPTION);
break;
- case PUBKEY_ALGO_ECDH:
+ case PUBKEY_ALGO_ECDH: /* Same value as GCRY_PK_ECC, i.e. 18 */
case GCRY_PK_ECDH:
if (use == PK_USE_DECRYPTION)
result = 1;
@@ -549,6 +555,9 @@ gnupg_rng_is_compliant (enum gnupg_compliance_mode compliance)
int *result;
int res;
+ /* #warning debug code ahead */
+ /* return 1; */
+
result = get_compliance_cache (compliance, 1);
if (result && *result != -1)
diff --git a/common/compliance.h b/common/compliance.h
index ead11472c..111fdc74b 100644
--- a/common/compliance.h
+++ b/common/compliance.h
@@ -50,6 +50,7 @@ enum pk_use_case
/* Flags to distinguish public key algorithm variants. */
#define PK_ALGO_FLAG_RSAPSS 1 /* Use rsaPSS padding. */
+#define PK_ALGO_FLAG_ECC18 256 /* GCRY_PK_ECC is used in a generic way. */
int gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
diff --git a/common/dotlock.c b/common/dotlock.c
index 74186b776..fe6d7fe71 100644
--- a/common/dotlock.c
+++ b/common/dotlock.c
@@ -291,6 +291,7 @@
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/utsname.h>
+# include <dirent.h>
#endif
#include <sys/types.h>
#include <sys/time.h>
@@ -393,9 +394,18 @@ struct dotlock_handle
unsigned int locked:1; /* Lock status. */
unsigned int disable:1; /* If true, locking is disabled. */
unsigned int use_o_excl:1; /* Use open (O_EXCL) for locking. */
+ unsigned int by_parent:1; /* Parent does the locking. */
+ unsigned int no_write:1; /* No write to the lockfile. */
int extra_fd; /* A place for the caller to store an FD. */
+ /* An optional info callback - see dotlock_set_info_cb. */
+ int (*info_cb)(dotlock_t, void *,
+ enum dotlock_reasons reason,
+ const char *,...);
+ void *info_cb_value;
+
+
#ifdef HAVE_DOSISH_SYSTEM
HANDLE lockhd; /* The W32 handle of the lock file. */
#else /*!HAVE_DOSISH_SYSTEM */
@@ -545,8 +555,15 @@ read_lockfile (dotlock_t h, int *same_node, int *r_fd)
if ( (fd = open (h->lockname, O_RDONLY)) == -1 )
{
int e = errno;
- my_info_2 ("error opening lockfile '%s': %s\n",
- h->lockname, strerror(errno) );
+ if (errno != ENOENT)
+ {
+ my_info_2 ("error opening lockfile '%s': %s\n",
+ h->lockname, strerror(errno) );
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
+ "error opening lockfile '%s': %s\n",
+ h->lockname, strerror (errno) );
+ }
if (buffer != buffer_space)
xfree (buffer);
my_set_errno (e); /* Need to return ERRNO here. */
@@ -564,6 +581,10 @@ read_lockfile (dotlock_t h, int *same_node, int *r_fd)
{
int e = errno;
my_info_1 ("error reading lockfile '%s'\n", h->lockname );
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
+ "error reading lockfile '%s': %s\n",
+ h->lockname, strerror (errno) );
close (fd);
if (buffer != buffer_space)
xfree (buffer);
@@ -583,6 +604,9 @@ read_lockfile (dotlock_t h, int *same_node, int *r_fd)
if (nread < 11)
{
my_info_1 ("invalid size of lockfile '%s'\n", h->lockname);
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_INV_FILE,
+ "invalid size of lockfile '%s'\n", h->lockname);
if (buffer != buffer_space)
xfree (buffer);
my_set_errno (EINVAL);
@@ -594,6 +618,9 @@ read_lockfile (dotlock_t h, int *same_node, int *r_fd)
|| !pid )
{
my_error_2 ("invalid pid %d in lockfile '%s'\n", pid, h->lockname);
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_INV_FILE,
+ "invalid pid %d in lockfile '%s'\n", pid, h->lockname);
if (buffer != buffer_space)
xfree (buffer);
my_set_errno (EINVAL);
@@ -655,6 +682,80 @@ use_hardlinks_p (const char *tname)
#ifdef HAVE_POSIX_SYSTEM
+static int
+dotlock_get_process_id (dotlock_t h)
+{
+ return h->by_parent? (int)getppid(): (int)getpid();
+}
+
+static int
+dotlock_detect_tname (dotlock_t h)
+{
+ struct stat sb;
+ DIR *dir;
+ char *dirname;
+ char *basename;
+ struct dirent *d;
+ int r;
+
+ if (stat (h->lockname, &sb))
+ return -1;
+
+ basename = make_basename (h->lockname, NULL);
+ dirname = make_dirname (h->lockname);
+
+ dir = opendir (dirname);
+ if (dir == NULL)
+ {
+ xfree (basename);
+ xfree (dirname);
+ return -1;
+ }
+
+ while ((d = readdir (dir)))
+ if (sb.st_ino == d->d_ino && strcmp (d->d_name, basename))
+ break;
+
+ if (d)
+ {
+ int len = strlen (h->tname);
+ int dlen = strlen (d->d_name);
+ const char *tname_path;
+
+ if (dlen > len)
+ {
+ xfree (basename);
+ xfree (dirname);
+ return -1;
+ }
+
+ strcpy (stpcpy (stpcpy (h->tname, dirname), DIRSEP_S), d->d_name);
+ h->use_o_excl = 0;
+ tname_path = strchr (h->tname + strlen (dirname) + 2, '.');
+ if (!tname_path)
+ {
+ xfree (basename);
+ xfree (dirname);
+ return -1;
+ }
+ h->nodename_off = tname_path - h->tname + 1;
+ }
+ else
+ h->use_o_excl = 1;
+
+ r = closedir (dir);
+ if (r)
+ {
+ xfree (basename);
+ xfree (dirname);
+ return r;
+ }
+
+ xfree (basename);
+ xfree (dirname);
+ return 0;
+}
+
/* Locking core for Unix. It used a temporary file and the link
system call to make locking an atomic operation. */
static dotlock_t
@@ -667,8 +768,10 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
int dirpartlen;
struct utsname utsbuf;
size_t tnamelen;
+ int pid;
- snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid() );
+ pid = dotlock_get_process_id (h);
+ snprintf (pidstr, sizeof pidstr, "%10d\n", pid);
/* Create a temporary file. */
if ( uname ( &utsbuf ) )
@@ -702,10 +805,17 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
}
h->nodename_len = strlen (nodename);
+ if (h->no_write)
+ {
+ memset (h->tname, '_', tnamelen);
+ h->tname[tnamelen] = 0;
+ goto skip_write;
+ }
+
snprintf (h->tname, tnamelen, "%.*s/.#lk%p.", dirpartlen, dirpart, h );
h->nodename_off = strlen (h->tname);
snprintf (h->tname+h->nodename_off, tnamelen - h->nodename_off,
- "%s.%d", nodename, (int)getpid ());
+ "%s.%d", nodename, pid);
do
{
@@ -722,6 +832,10 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
UNLOCK_all_lockfiles ();
my_error_2 (_("failed to create temporary file '%s': %s\n"),
h->tname, strerror (errno));
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_WAITING,
+ _("failed to create temporary file '%s': %s\n"),
+ h->tname, strerror (errno));
xfree (h->tname);
xfree (h);
my_set_errno (saveerrno);
@@ -755,11 +869,16 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
int saveerrno = errno;
my_error_2 ("can't check whether hardlinks are supported for '%s': %s\n"
, h->tname, strerror (saveerrno));
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_CONFIG_TEST,
+ "can't check whether hardlinks are supported for '%s': %s\n"
+ , h->tname, strerror (saveerrno));
my_set_errno (saveerrno);
}
goto write_failed;
}
+ skip_write:
h->lockname = xtrymalloc (strlen (file_to_lock) + 6 );
if (!h->lockname)
{
@@ -775,6 +894,20 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
strcpy (stpcpy (h->lockname, file_to_lock), EXTSEP_S "lock");
UNLOCK_all_lockfiles ();
+ if (h->no_write)
+ {
+ if (dotlock_detect_tname (h) < 0)
+ {
+ xfree (h->lockname);
+ xfree (h->tname);
+ xfree (h);
+ my_set_errno (EACCES);
+ return NULL;
+ }
+
+ h->locked = 1;
+ }
+
return h;
write_failed:
@@ -783,6 +916,11 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
all_lockfiles = h->next;
UNLOCK_all_lockfiles ();
my_error_2 (_("error writing to '%s': %s\n"), h->tname, strerror (errno));
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
+ _("error writing to '%s': %s\n"),
+ h->tname, strerror (errno));
+
if ( fd != -1 )
close (fd);
unlink (h->tname);
@@ -849,6 +987,10 @@ dotlock_create_w32 (dotlock_t h, const char *file_to_lock)
all_lockfiles = h->next;
UNLOCK_all_lockfiles ();
my_error_2 (_("can't create '%s': %s\n"), h->lockname, w32_strerror (-1));
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
+ _("can't create '%s': %s\n"),
+ h->lockname, w32_strerror (-1));
xfree (h->lockname);
xfree (h);
my_set_errno (saveerrno);
@@ -873,7 +1015,15 @@ dotlock_create_w32 (dotlock_t h, const char *file_to_lock)
POSIX systems a temporary file ".#lk.<hostname>.pid[.threadid] is
used.
- FLAGS must be 0.
+ FLAGS may include DOTLOCK_PREPARE_CREATE bit, which only allocates
+ the handle and requires a further call to dotlock_finish_create.
+ This can be used to set a callback between these calls.
+
+ FLAGS may include DOTLOCK_LOCK_BY_PARENT bit, when it's the parent
+ process controlling the lock. This is used by dotlock util.
+
+ FLAGS may include DOTLOCK_LOCKED bit, when it should not create the
+ lockfile, but to unlock. This is used by dotlock util.
The function returns an new handle which needs to be released using
destroy_dotlock but gets also released at the termination of the
@@ -885,8 +1035,13 @@ dotlock_create (const char *file_to_lock, unsigned int flags)
{
static int initialized;
dotlock_t h;
+#ifndef HAVE_DOSISH_SYSTEM
+ int by_parent = 0;
+ int no_write = 0;
+#endif
- if ( !initialized )
+ if ( !(flags & DOTLOCK_LOCK_BY_PARENT)
+ && !initialized )
{
atexit (dotlock_remove_lockfiles);
initialized = 1;
@@ -895,7 +1050,15 @@ dotlock_create (const char *file_to_lock, unsigned int flags)
if ( !file_to_lock )
return NULL; /* Only initialization was requested. */
- if (flags)
+#ifndef HAVE_DOSISH_SYSTEM
+ if ((flags & DOTLOCK_LOCK_BY_PARENT) || (flags & DOTLOCK_LOCKED))
+ {
+ by_parent = !!(flags & DOTLOCK_LOCK_BY_PARENT);
+ no_write = !!(flags & DOTLOCK_LOCKED);
+ flags &= ~(DOTLOCK_LOCK_BY_PARENT | DOTLOCK_LOCKED);
+ }
+#endif
+ if ((flags & ~DOTLOCK_PREPARE_CREATE))
{
my_set_errno (EINVAL);
return NULL;
@@ -905,6 +1068,10 @@ dotlock_create (const char *file_to_lock, unsigned int flags)
if (!h)
return NULL;
h->extra_fd = -1;
+#ifndef HAVE_DOSISH_SYSTEM
+ h->by_parent = by_parent;
+ h->no_write = no_write;
+#endif
if (never_lock)
{
@@ -916,6 +1083,24 @@ dotlock_create (const char *file_to_lock, unsigned int flags)
return h;
}
+ if ((flags & DOTLOCK_PREPARE_CREATE))
+ return h;
+ else
+ return dotlock_finish_create (h, file_to_lock);
+}
+
+
+/* This function may be used along with dotlock_create (file_name,
+ * DOTLOCK_PREPARE_CREATE) to finish the creation call. The given
+ * filename shall be the same as passed to dotlock_create. On success
+ * the same handle H is returned, on error NULL is returned and H is
+ * released. */
+dotlock_t
+dotlock_finish_create (dotlock_t h, const char *file_to_lock)
+{
+ if (!h || !file_to_lock)
+ return NULL;
+
#ifdef HAVE_DOSISH_SYSTEM
return dotlock_create_w32 (h, file_to_lock);
#else /*!HAVE_DOSISH_SYSTEM */
@@ -942,6 +1127,24 @@ dotlock_get_fd (dotlock_t h)
}
+/* Set a callback function for info diagnostics. The callback
+ * function CB is called with the handle, the opaque value OPAQUE, a
+ * reason code, and a format string with its arguments. The callback
+ * shall return 0 to continue operation or true in which case the
+ * current function will be terminated with an error. */
+void
+dotlock_set_info_cb (dotlock_t h,
+ int (*cb)(dotlock_t, void *,
+ enum dotlock_reasons reason,
+ const char *,...),
+ void *opaque)
+{
+ h->info_cb = cb;
+ h->info_cb_value = opaque;
+}
+
+
+
#ifdef HAVE_POSIX_SYSTEM
/* Unix specific code of destroy_dotlock. */
@@ -952,7 +1155,6 @@ dotlock_destroy_unix (dotlock_t h)
unlink (h->lockname);
if (h->tname && !h->use_o_excl)
unlink (h->tname);
- xfree (h->tname);
}
#endif /*HAVE_POSIX_SYSTEM*/
@@ -998,15 +1200,28 @@ dotlock_destroy (dotlock_t h)
UNLOCK_all_lockfiles ();
/* Then destroy the lock. */
- if (!h->disable)
+ if (!h->disable
+ && (!h->by_parent || h->no_write))
{
+ /* NOTE: under the condition of (by_parent && !no_write),
+ it doesn't come here. So, the lock file remains. */
#ifdef HAVE_DOSISH_SYSTEM
dotlock_destroy_w32 (h);
#else /* !HAVE_DOSISH_SYSTEM */
dotlock_destroy_unix (h);
#endif /* HAVE_DOSISH_SYSTEM */
- xfree (h->lockname);
}
+
+#ifdef HAVE_POSIX_SYSTEM
+ /* When DOTLOCK_LOCK_BY_PARENT and lock fails,
+ the temporary file created should be removed. */
+ if (h->by_parent && !h->no_write && !h->locked)
+ if (h->tname && !h->use_o_excl)
+ unlink (h->tname);
+
+ xfree (h->tname);
+#endif
+ xfree (h->lockname);
xfree(h);
}
@@ -1061,6 +1276,7 @@ static int
dotlock_take_unix (dotlock_t h, long timeout)
{
int wtime = 0;
+ int timedout = 0;
int sumtime = 0;
int pid;
int lastpid = -1;
@@ -1089,6 +1305,10 @@ dotlock_take_unix (dotlock_t h, long timeout)
saveerrno = errno;
my_error_2 ("lock not made: open(O_EXCL) of '%s' failed: %s\n",
h->lockname, strerror (saveerrno));
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
+ "lock not made: open(O_EXCL) of '%s' failed: %s\n",
+ h->lockname, strerror (saveerrno));
my_set_errno (saveerrno);
return -1;
}
@@ -1096,7 +1316,8 @@ dotlock_take_unix (dotlock_t h, long timeout)
{
char pidstr[16];
- snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid());
+ snprintf (pidstr, sizeof pidstr, "%10d\n",
+ dotlock_get_process_id (h));
if (write (fd, pidstr, 11 ) == 11
&& write (fd, h->tname + h->nodename_off,h->nodename_len)
== h->nodename_len
@@ -1110,6 +1331,10 @@ dotlock_take_unix (dotlock_t h, long timeout)
saveerrno = errno;
my_error_2 ("lock not made: writing to '%s' failed: %s\n",
h->lockname, strerror (errno));
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
+ "lock not made: writing to '%s' failed: %s\n",
+ h->lockname, strerror (errno));
close (fd);
unlink (h->lockname);
my_set_errno (saveerrno);
@@ -1128,6 +1353,10 @@ dotlock_take_unix (dotlock_t h, long timeout)
saveerrno = errno;
my_error_1 ("lock not made: Oops: stat of tmp file failed: %s\n",
strerror (errno));
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
+ "lock not made: Oops: stat of tmp file failed: %s\n",
+ strerror (errno));
/* In theory this might be a severe error: It is possible
that link succeeded but stat failed due to changed
permissions. We can't do anything about it, though. */
@@ -1149,16 +1378,19 @@ dotlock_take_unix (dotlock_t h, long timeout)
{
saveerrno = errno;
my_info_0 ("cannot read lockfile\n");
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
+ "cannot read lockfile\n");
my_set_errno (saveerrno);
return -1;
}
my_info_0 ("lockfile disappeared\n");
goto again;
}
- else if ( (pid == getpid() && same_node)
+ else if ( (pid == dotlock_get_process_id (h) && same_node && !h->by_parent)
|| (same_node && kill (pid, 0) && errno == ESRCH) )
- /* Stale lockfile is detected. */
{
+ /* Stale lockfile is detected. */
struct stat sb;
/* Check if it's unlocked during examining the lockfile. */
@@ -1201,6 +1433,9 @@ dotlock_take_unix (dotlock_t h, long timeout)
unlink (h->lockname);
my_info_1 (_("removing stale lockfile (created by %d)\n"), pid);
close (fd);
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_STALE_REMOVED,
+ _("removing stale lockfile (created by %d)\n"), pid);
goto again;
}
@@ -1218,6 +1453,8 @@ dotlock_take_unix (dotlock_t h, long timeout)
wtime = 0; /* Reset because owner chnaged. */
wtimereal = next_wait_interval (&wtime, &timeout);
+ if (!timeout)
+ timedout = 1; /* remember. */
sumtime += wtimereal;
if (sumtime >= 1500)
@@ -1225,6 +1462,15 @@ dotlock_take_unix (dotlock_t h, long timeout)
sumtime = 0;
my_info_3 (_("waiting for lock (held by %d%s) %s...\n"),
pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):"");
+ if (h->info_cb
+ && h->info_cb (h, h->info_cb_value, DOTLOCK_WAITING,
+ _("waiting for lock (held by %d%s) %s...\n"),
+ pid, maybe_dead,
+ maybe_deadlock(h)? _("(deadlock?) "):""))
+ {
+ my_set_errno (ECANCELED);
+ return -1;
+ }
}
tv.tv_sec = wtimereal / 1000;
@@ -1233,7 +1479,7 @@ dotlock_take_unix (dotlock_t h, long timeout)
goto again;
}
- my_set_errno (EACCES);
+ my_set_errno (timedout? ETIMEDOUT : EACCES);
return -1;
}
#endif /*HAVE_POSIX_SYSTEM*/
@@ -1246,6 +1492,7 @@ static int
dotlock_take_w32 (dotlock_t h, long timeout)
{
int wtime = 0;
+ int timedout = 0;
int w32err;
OVERLAPPED ovl;
@@ -1264,7 +1511,11 @@ dotlock_take_w32 (dotlock_t h, long timeout)
{
my_error_2 (_("lock '%s' not made: %s\n"),
h->lockname, w32_strerror (w32err));
- my_set_errno (map_w32_to_errno (w32err));
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
+ _("lock '%s' not made: %s\n"),
+ h->lockname, w32_strerror (w32err));
+ _set_errno (map_w32_to_errno (w32err));
return -1;
}
@@ -1273,15 +1524,26 @@ dotlock_take_w32 (dotlock_t h, long timeout)
int wtimereal;
wtimereal = next_wait_interval (&wtime, &timeout);
+ if (!timeout)
+ timedout = 1; /* remember. */
if (wtime >= 800)
- my_info_1 (_("waiting for lock %s...\n"), h->lockname);
+ {
+ my_info_1 (_("waiting for lock %s...\n"), h->lockname);
+ if (h->info_cb
+ && h->info_cb (h, h->info_cb_value, DOTLOCK_WAITING,
+ _("waiting for lock %s...\n"), h->lockname))
+ {
+ my_set_errno (ECANCELED);
+ return -1;
+ }
+ }
Sleep (wtimereal);
goto again;
}
- my_set_errno (EACCES);
+ my_set_errno (timedout? ETIMEDOUT : EACCES);
return -1;
}
#endif /*HAVE_DOSISH_SYSTEM*/
@@ -1328,12 +1590,18 @@ dotlock_release_unix (dotlock_t h)
{
saveerrno = errno;
my_error_0 ("release_dotlock: lockfile error\n");
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
+ "release_dotlock: lockfile error\n");
my_set_errno (saveerrno);
return -1;
}
- if ( pid != getpid() || !same_node )
+ if ( pid != dotlock_get_process_id (h) || !same_node )
{
my_error_1 ("release_dotlock: not our lock (pid=%d)\n", pid);
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_CONFLICT,
+ "release_dotlock: not our lock (pid=%d)\n", pid);
my_set_errno (EACCES);
return -1;
}
@@ -1343,6 +1611,10 @@ dotlock_release_unix (dotlock_t h)
saveerrno = errno;
my_error_1 ("release_dotlock: error removing lockfile '%s'\n",
h->lockname);
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
+ "release_dotlock: error removing lockfile '%s'\n",
+ h->lockname);
my_set_errno (saveerrno);
return -1;
}
@@ -1363,10 +1635,15 @@ dotlock_release_w32 (dotlock_t h)
memset (&ovl, 0, sizeof ovl);
if (!UnlockFileEx (h->lockhd, 0, 1, 0, &ovl))
{
- int saveerrno = map_w32_to_errno (GetLastError ());
+ int ec = (int)GetLastError ();
+
my_error_2 ("release_dotlock: error removing lockfile '%s': %s\n",
- h->lockname, w32_strerror (-1));
- my_set_errno (saveerrno);
+ h->lockname, w32_strerror (ec));
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
+ "release_dotlock: error removing lockfile '%s': %s\n",
+ h->lockname, w32_strerror (ec));
+ my_set_errno (map_w32_to_errno (ec));
return -1;
}
@@ -1397,6 +1674,9 @@ dotlock_release (dotlock_t h)
if ( !h->locked )
{
my_debug_1 ("Oops, '%s' is not locked\n", h->lockname);
+ if (h->info_cb)
+ h->info_cb (h, h->info_cb_value, DOTLOCK_NOT_LOCKED,
+ "Oops, '%s' is not locked\n", h->lockname);
return 0;
}
diff --git a/common/dotlock.h b/common/dotlock.h
index 03131bb0c..0f52d4037 100644
--- a/common/dotlock.h
+++ b/common/dotlock.h
@@ -97,12 +97,35 @@ extern "C"
struct dotlock_handle;
typedef struct dotlock_handle *dotlock_t;
+enum dotlock_reasons
+ {
+ DOTLOCK_CONFIG_TEST, /* Can't check system - function terminates. */
+ DOTLOCK_FILE_ERROR, /* General file error - function terminates. */
+ DOTLOCK_INV_FILE, /* Invalid file - function terminates. */
+ DOTLOCK_CONFLICT, /* Something is wrong - function terminates. */
+ DOTLOCK_NOT_LOCKED, /* Not locked - No action required. */
+ DOTLOCK_STALE_REMOVED, /* Stale lock file was removed - retrying. */
+ DOTLOCK_WAITING /* Waiting for the lock - may be terminated. */
+ };
+
+/* Flags for dotlock_create. */
+#define DOTLOCK_PREPARE_CREATE (1U << 5) /* Require dotlock_finish_create. */
+#define DOTLOCK_LOCK_BY_PARENT (1U << 6) /* Used by dotlock util. */
+#define DOTLOCK_LOCKED (1U << 7) /* Used by dotlock util. */
+
void dotlock_disable (void);
dotlock_t dotlock_create (const char *file_to_lock, unsigned int flags);
+dotlock_t dotlock_finish_create (dotlock_t h, const char *file_to_lock);
void dotlock_set_fd (dotlock_t h, int fd);
int dotlock_get_fd (dotlock_t h);
+void dotlock_set_info_cb (dotlock_t h,
+ int (*cb)(dotlock_t, void *,
+ enum dotlock_reasons reason,
+ const char *,...),
+ void *opaque);
void dotlock_destroy (dotlock_t h);
int dotlock_take (dotlock_t h, long timeout);
+int dotlock_is_locked (dotlock_t h);
int dotlock_release (dotlock_t h);
void dotlock_remove_lockfiles (void);
diff --git a/common/homedir.c b/common/homedir.c
index 286685feb..2b99c9bdc 100644
--- a/common/homedir.c
+++ b/common/homedir.c
@@ -77,6 +77,14 @@
#endif
+/* Mode flags for unix_rootdir. */
+enum wantdir_values {
+ WANTDIR_ROOT = 0,
+ WANTDIR_SYSCONF,
+ WANTDIR_SOCKET
+};
+
+
/* The GnuPG homedir. This is only accessed by the functions
* gnupg_homedir and gnupg_set_homedir. Malloced. */
static char *the_gnupg_homedir;
@@ -491,11 +499,12 @@ w32_rootdir (void)
* file system. If WANT_SYSCONFDIR is true the optional sysconfdir
* entry is returned. */
static const char *
-unix_rootdir (int want_sysconfdir)
+unix_rootdir (enum wantdir_values wantdir)
{
static int checked;
static char *dir; /* for the rootdir */
static char *sdir; /* for the sysconfdir */
+ static char *s2dir; /* for the socketdir */
if (!checked)
{
@@ -510,8 +519,10 @@ unix_rootdir (int want_sysconfdir)
estream_t fp;
char *rootdir;
char *sysconfdir;
+ char *socketdir;
const char *name;
int ignoreall = 0;
+ int okay;
for (;;)
{
@@ -602,45 +613,44 @@ unix_rootdir (int want_sysconfdir)
linelen = 0;
rootdir = NULL;
sysconfdir = NULL;
+ socketdir = NULL;
while ((length = es_read_line (fp, &line, &linelen, NULL)) > 0)
{
+ static const char *names[] =
+ {
+ "rootdir",
+ "sysconfdir",
+ "socketdir",
+ ".enable"
+ };
+ int i;
+ size_t n;
+
/* Strip NL and CR, if present. */
while (length > 0
&& (line[length - 1] == '\n' || line[length - 1] == '\r'))
line[--length] = 0;
trim_spaces (line);
- if (!strncmp (line, "rootdir=", 8))
- {
- name = "rootdir";
- p = line + 8;
- }
- else if (!strncmp (line, "rootdir =", 9)) /* (What a kludge) */
- {
- name = "rootdir";
- p = line + 9;
- }
- else if (!strncmp (line, "sysconfdir=", 11))
+ /* Find the stamement. */
+ name = NULL;
+ for (i=0; i < DIM (names); i++)
{
- name = "sysconfdir";
- p = line + 11;
- }
- else if (!strncmp (line, "sysconfdir =", 12)) /* (What a kludge) */
- {
- name = "sysconfdir";
- p = line + 12;
- }
- else if (!strncmp (line, ".enable=", 8))
- {
- name = ".enable";
- p = line + 8;
- }
- else if (!strncmp (line, ".enable =", 9))
- {
- name = ".enable";
- p = line + 9;
+ n = strlen (names[i]);
+ if (!strncmp (line, names[i], n))
+ {
+ while (line[n] == ' ' || line[n] == '\t')
+ n++;
+ if (line[n] == '=')
+ {
+ name = names[i];
+ p = line + n + 1;
+ break;
+ }
+ }
}
- else
- continue;
+ if (!name)
+ continue; /* Statement not known. */
+
trim_spaces (p);
p = substitute_envvars (p);
if (!p)
@@ -665,6 +675,11 @@ unix_rootdir (int want_sysconfdir)
xfree (sysconfdir);
sysconfdir = p;
}
+ else if (!strcmp (name, "socketdir"))
+ {
+ xfree (socketdir);
+ socketdir = p;
+ }
else
{
xfree (rootdir);
@@ -680,6 +695,7 @@ unix_rootdir (int want_sysconfdir)
xfree (line);
xfree (rootdir);
xfree (sysconfdir);
+ xfree (socketdir);
checked = 1;
return NULL;
}
@@ -687,29 +703,26 @@ unix_rootdir (int want_sysconfdir)
xfree (buffer);
xfree (line);
+ okay = 0;
if (ignoreall)
- {
- xfree (rootdir);
- xfree (sysconfdir);
- sdir = dir = NULL;
- }
+ ;
else if (!rootdir || !*rootdir || *rootdir != '/')
{
log_info ("invalid rootdir '%s' specified in gpgconf.ctl\n", rootdir);
- xfree (rootdir);
- xfree (sysconfdir);
- dir = NULL;
}
else if (sysconfdir && (!*sysconfdir || *sysconfdir != '/'))
{
log_info ("invalid sysconfdir '%s' specified in gpgconf.ctl\n",
sysconfdir);
- xfree (rootdir);
- xfree (sysconfdir);
- dir = NULL;
+ }
+ else if (socketdir && (!*socketdir || *socketdir != '/'))
+ {
+ log_info ("invalid socketdir '%s' specified in gpgconf.ctl\n",
+ socketdir);
}
else
{
+ okay = 1;
while (*rootdir && rootdir[strlen (rootdir)-1] == '/')
rootdir[strlen (rootdir)-1] = 0;
dir = rootdir;
@@ -723,11 +736,34 @@ unix_rootdir (int want_sysconfdir)
gpgrt_annotate_leaked_object (sdir);
/* log_info ("want sysconfdir '%s'\n", sdir); */
}
+ if (socketdir)
+ {
+ while (*socketdir && socketdir[strlen (socketdir)-1] == '/')
+ socketdir[strlen (socketdir)-1] = 0;
+ s2dir = socketdir;
+ gpgrt_annotate_leaked_object (s2dir);
+ /* log_info ("want socketdir '%s'\n", s2dir); */
+ }
+ }
+
+ if (!okay)
+ {
+ xfree (rootdir);
+ xfree (sysconfdir);
+ xfree (socketdir);
+ dir = sdir = s2dir = NULL;
}
checked = 1;
}
- return want_sysconfdir? sdir : dir;
+ switch (wantdir)
+ {
+ case WANTDIR_ROOT: return dir;
+ case WANTDIR_SYSCONF: return sdir;
+ case WANTDIR_SOCKET: return s2dir;
+ }
+
+ return NULL; /* Not reached. */
}
#endif /* Unix */
@@ -1038,7 +1074,8 @@ _gnupg_socketdir_internal (int skip_checks, unsigned *r_info)
};
int i;
struct stat sb;
- char prefix[19 + 1 + 20 + 6 + 1];
+ char prefixbuffer[19 + 1 + 20 + 6 + 1];
+ const char *prefix;
const char *s;
char *name = NULL;
@@ -1053,35 +1090,42 @@ _gnupg_socketdir_internal (int skip_checks, unsigned *r_info)
* as a background process with no (desktop) user logged in. Thus
* we better don't do that. */
- /* Check whether we have a /run/[gnupg/]user dir. */
- for (i=0; bases[i]; i++)
- {
- snprintf (prefix, sizeof prefix, "%s/user/%u",
- bases[i], (unsigned int)getuid ());
- if (!stat (prefix, &sb) && S_ISDIR(sb.st_mode))
- break;
- }
- if (!bases[i])
+ prefix = unix_rootdir (WANTDIR_SOCKET);
+ if (!prefix)
{
- *r_info |= 2; /* No /run/user directory. */
- goto leave;
- }
+ /* gpgconf.ctl does not specify a directory. Check whether we
+ * have the usual /run/[gnupg/]user dir. */
+ for (i=0; bases[i]; i++)
+ {
+ snprintf (prefixbuffer, sizeof prefixbuffer, "%s/user/%u",
+ bases[i], (unsigned int)getuid ());
+ prefix = prefixbuffer;
+ if (!stat (prefix, &sb) && S_ISDIR(sb.st_mode))
+ break;
+ }
+ if (!bases[i])
+ {
+ *r_info |= 2; /* No /run/user directory. */
+ goto leave;
+ }
- if (sb.st_uid != getuid ())
- {
- *r_info |= 4; /* Not owned by the user. */
- if (!skip_checks)
- goto leave;
- }
+ if (sb.st_uid != getuid ())
+ {
+ *r_info |= 4; /* Not owned by the user. */
+ if (!skip_checks)
+ goto leave;
+ }
- if (strlen (prefix) + 7 >= sizeof prefix)
- {
- *r_info |= 1; /* Ooops: Buffer too short to append "/gnupg". */
- goto leave;
+ if (strlen (prefix) + 7 >= sizeof prefixbuffer)
+ {
+ *r_info |= 1; /* Ooops: Buffer too short to append "/gnupg". */
+ goto leave;
+ }
+ strcat (prefixbuffer, "/gnupg");
}
- strcat (prefix, "/gnupg");
- /* Check whether the gnupg sub directory has proper permissions. */
+ /* Check whether the gnupg sub directory (or the specified diretory)
+ * has proper permissions. */
if (stat (prefix, &sb))
{
if (errno != ENOENT)
@@ -1241,7 +1285,7 @@ gnupg_sysconfdir (void)
}
return name;
#else /*!HAVE_W32_SYSTEM*/
- const char *dir = unix_rootdir (1);
+ const char *dir = unix_rootdir (WANTDIR_SYSCONF);
if (dir)
return dir;
else
@@ -1270,7 +1314,7 @@ gnupg_bindir (void)
else
return rdir;
#else /*!HAVE_W32_SYSTEM*/
- rdir = unix_rootdir (0);
+ rdir = unix_rootdir (WANTDIR_ROOT);
if (rdir)
{
if (!name)
@@ -1297,7 +1341,7 @@ gnupg_libexecdir (void)
static char *name;
const char *rdir;
- rdir = unix_rootdir (0);
+ rdir = unix_rootdir (WANTDIR_ROOT);
if (rdir)
{
if (!name)
@@ -1327,7 +1371,7 @@ gnupg_libdir (void)
#else /*!HAVE_W32_SYSTEM*/
const char *rdir;
- rdir = unix_rootdir (0);
+ rdir = unix_rootdir (WANTDIR_ROOT);
if (rdir)
{
if (!name)
@@ -1358,7 +1402,7 @@ gnupg_datadir (void)
#else /*!HAVE_W32_SYSTEM*/
const char *rdir;
- rdir = unix_rootdir (0);
+ rdir = unix_rootdir (WANTDIR_ROOT);
if (rdir)
{
if (!name)
@@ -1390,7 +1434,7 @@ gnupg_localedir (void)
#else /*!HAVE_W32_SYSTEM*/
const char *rdir;
- rdir = unix_rootdir (0);
+ rdir = unix_rootdir (WANTDIR_ROOT);
if (rdir)
{
if (!name)
diff --git a/common/name-value.c b/common/name-value.c
index 0dffc63b4..ea6a84f56 100644
--- a/common/name-value.c
+++ b/common/name-value.c
@@ -48,6 +48,7 @@ struct name_value_container
struct name_value_entry *first;
struct name_value_entry *last;
unsigned int private_key_mode:1;
+ unsigned int modified:1;
};
@@ -87,11 +88,15 @@ my_error (gpg_err_code_t ec)
/* Allocation and deallocation. */
-/* Allocate a private key container structure. */
+/* Allocate a name value container structure. */
nvc_t
nvc_new (void)
{
- return xtrycalloc (1, sizeof (struct name_value_container));
+ nvc_t nvc;
+ nvc = xtrycalloc (1, sizeof (struct name_value_container));
+ if (nvc)
+ nvc->modified = 1;
+ return nvc;
}
@@ -142,6 +147,24 @@ nvc_release (nvc_t pk)
xfree (pk);
}
+
+/* Return the modified-flag of the container and clear it if CLEAR is
+ * set. That flag is set for a new container and set with each
+ * update. */
+int
+nvc_modified (nvc_t pk, int clear)
+{
+ int modified;
+
+ if (!pk)
+ return 0;
+ modified = pk->modified;
+ if (clear)
+ pk->modified = 0;
+ return modified;
+}
+
+
/* Dealing with names and values. */
@@ -427,6 +450,8 @@ _nvc_add (nvc_t pk, char *name, char *value, strlist_t raw_value,
else
pk->first = pk->last = e;
+ pk->modified = 1;
+
leave:
if (err)
{
@@ -476,36 +501,29 @@ nvc_set (nvc_t pk, const char *name, const char *value)
e = nvc_lookup (pk, name);
if (e)
- {
- char *v;
-
- v = xtrystrdup (value);
- if (v == NULL)
- return my_error_from_syserror ();
-
- free_strlist_wipe (e->raw_value);
- e->raw_value = NULL;
- if (e->value)
- wipememory (e->value, strlen (e->value));
- xfree (e->value);
- e->value = v;
-
- return 0;
- }
+ return nve_set (pk, e, value);
else
return nvc_add (pk, name, value);
}
-/* Update entry E to VALUE. */
+/* Update entry E to VALUE. PK is optional; if given its modified
+ * flag will be updated. */
gpg_error_t
-nve_set (nve_t e, const char *value)
+nve_set (nvc_t pk, nve_t e, const char *value)
{
char *v;
if (!e)
return GPG_ERR_INV_ARG;
+ if (e->value && value && !strcmp (e->value, value))
+ {
+ /* Setting same value - ignore this call and don't set the
+ * modified flag (if PK is given). */
+ return 0;
+ }
+
v = xtrystrdup (value? value:"");
if (!v)
return my_error_from_syserror ();
@@ -516,6 +534,8 @@ nve_set (nve_t e, const char *value)
wipememory (e->value, strlen (e->value));
xfree (e->value);
e->value = v;
+ if (pk)
+ pk->modified = 1;
return 0;
}
@@ -536,6 +556,7 @@ nvc_delete (nvc_t pk, nve_t entry)
pk->last = entry->prev;
nve_release (entry, pk->private_key_mode);
+ pk->modified = 1;
}
diff --git a/common/name-value.h b/common/name-value.h
index b3fc2f63c..dfded6678 100644
--- a/common/name-value.h
+++ b/common/name-value.h
@@ -50,6 +50,9 @@ nvc_t nvc_new_private_key (void);
/* Release a name value container structure. */
void nvc_release (nvc_t pk);
+/* Return the modified flag and optionally clear it. */
+int nvc_modified (nvc_t pk, int clear);
+
/* Get the name. */
char *nve_name (nve_t pke);
@@ -92,8 +95,8 @@ gpg_error_t nvc_add (nvc_t pk, const char *name, const char *value);
first entry is updated. */
gpg_error_t nvc_set (nvc_t pk, const char *name, const char *value);
-/* Update entry E to VALUE. */
-gpg_error_t nve_set (nve_t e, const char *value);
+/* Update entry E to VALUE. PK is optional. */
+gpg_error_t nve_set (nvc_t pk, nve_t e, const char *value);
/* Delete the given entry from PK. */
void nvc_delete (nvc_t pk, nve_t pke);
diff --git a/common/openpgpdefs.h b/common/openpgpdefs.h
index c97995568..d8672ac47 100644
--- a/common/openpgpdefs.h
+++ b/common/openpgpdefs.h
@@ -122,6 +122,9 @@ typedef enum
SIGSUBPKT_ATTST_SIGS = 37, /* Attested Certifications. */
SIGSUBPKT_KEY_BLOCK = 38, /* Entire key used. */
+ SIGSUBPKT_META_HASH = 40, /* Literal Data Meta Hash. */
+ SIGSUBPKT_TRUST_ALIAS = 41, /* Trust Alias. */
+
SIGSUBPKT_FLAG_CRITICAL = 128
}
sigsubpkttype_t;
diff --git a/common/t-dotlock.c b/common/t-dotlock.c
index 994ef1be3..87e62bb33 100644
--- a/common/t-dotlock.c
+++ b/common/t-dotlock.c
@@ -52,6 +52,7 @@
#ifdef HAVE_W32_SYSTEM
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
+
const char *
w32_strerror (int ec)
{
@@ -174,6 +175,11 @@ strconcat (const char *s1, ...)
#define PGM "t-dotlock"
+static int opt_silent;
+
+
+
+
#ifndef HAVE_W32_SYSTEM
static volatile int ctrl_c_pending_flag;
static void
@@ -217,6 +223,9 @@ inf (const char *format, ...)
{
va_list arg_ptr;
+ if (opt_silent)
+ return;
+
va_start (arg_ptr, format);
fprintf (stderr, PGM "[%lu]: ", (unsigned long)getpid ());
vfprintf (stderr, format, arg_ptr);
@@ -225,15 +234,35 @@ inf (const char *format, ...)
}
+static int
+lock_info_cb (dotlock_t h, void *opaque, enum dotlock_reasons reason,
+ const char *format, ...)
+{
+ va_list arg_ptr;
+
+ va_start (arg_ptr, format);
+ fprintf (stderr, PGM "[%lu]: info_cb: reason %d, ",
+ (unsigned long)getpid (), (int)reason);
+ vfprintf (stderr, format, arg_ptr);
+ va_end (arg_ptr);
+ return 0;
+}
+
+
static void
lock_and_unlock (const char *fname)
{
dotlock_t h;
unsigned long usec;
- h = dotlock_create (fname, 0);
+ h = dotlock_create (fname, DOTLOCK_PREPARE_CREATE);
if (!h)
die ("error creating lock file for '%s': %s", fname, strerror (errno));
+ dotlock_set_info_cb (h, lock_info_cb, NULL);
+ h = dotlock_finish_create (h, fname);
+ if (!h)
+ die ("error finishing lock file creation for '%s': %s",
+ fname, strerror (errno));
inf ("lock created");
do
@@ -270,6 +299,11 @@ main (int argc, char **argv)
ctrl_c_pending_flag = 1;
argc--;
}
+ if (argc > 1 && !strcmp (argv[1], "--silent"))
+ {
+ opt_silent = 1;
+ argc--;
+ }
if (argc > 1)
fname = argv[argc-1];