diff --git a/common/stringhelp.c b/common/stringhelp.c index e1ddf2cfb..7ce041d01 100644 --- a/common/stringhelp.c +++ b/common/stringhelp.c @@ -1035,6 +1035,26 @@ stpcpy(char *a,const char *b) } #endif +#ifndef HAVE_STRPBRK +/* Find the first occurrence in S of any character in ACCEPT. + Code taken from glibc-2.6/string/strpbrk.c (LGPLv2.1+) and modified. */ +char * +strpbrk (const char *s, const char *accept) +{ + while (*s != '\0') + { + const char *a = accept; + while (*a != '\0') + if (*a++ == *s) + return (char *) s; + ++s; + } + + return NULL; +} +#endif /*!HAVE_STRPBRK*/ + + #ifndef HAVE_STRSEP /* Code taken from glibc-2.2.1/sysdeps/generic/strsep.c. */ char * diff --git a/common/stringhelp.h b/common/stringhelp.h index 1ad380e79..1d3ee7237 100644 --- a/common/stringhelp.h +++ b/common/stringhelp.h @@ -99,6 +99,9 @@ int memicmp( const char *a, const char *b, size_t n ); #ifndef HAVE_STPCPY char *stpcpy(char *a,const char *b); #endif +#ifndef HAVE_STRPBRK +char *strpbrk (const char *s, const char *accept); +#endif #ifndef HAVE_STRSEP char *strsep (char **stringp, const char *delim); #endif diff --git a/common/sysutils.c b/common/sysutils.c index 858cb6500..397184583 100644 --- a/common/sysutils.c +++ b/common/sysutils.c @@ -1,7 +1,7 @@ /* sysutils.c - system helpers - * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, - * 2007, 2008 Free Software Foundation, Inc. - * Copyright (C) 2013 Werner Koch + * Copyright (C) 1991-2001, 2003-2004, + * 2006-2008 Free Software Foundation, Inc. + * Copyright (C) 2013-2014 Werner Koch * * This file is part of GnuPG. * @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -617,6 +618,90 @@ gnupg_mkdir (const char *name, const char *modestr) } +/* Our version of mkdtemp. The API is identical to POSIX.1-2008 + version. We do not use a system provided mkdtemp because we have a + good RNG instantly available and this way we don't have diverging + versions. */ +char * +gnupg_mkdtemp (char *tmpl) +{ + /* A lower bound on the number of temporary files to attempt to + generate. The maximum total number of temporary file names that + can exist for a given template is 62**6 (5*36**3 for Windows). + It should never be necessary to try all these combinations. + Instead if a reasonable number of names is tried (we define + reasonable as 62**3 or 5*36**3) fail to give the system + administrator the chance to remove the problems. */ +#ifdef HAVE_W32_SYSTEM + static const char letters[] = + "abcdefghijklmnopqrstuvwxyz0123456789"; +# define NUMBER_OF_LETTERS 36 +# define ATTEMPTS_MIN (5 * 36 * 36 * 36) +#else + static const char letters[] = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; +# define NUMBER_OF_LETTERS 62 +# define ATTEMPTS_MIN (62 * 62 * 62) +#endif + int len; + char *XXXXXX; + uint64_t value; + unsigned int count; + int save_errno = errno; + /* The number of times to attempt to generate a temporary file. To + conform to POSIX, this must be no smaller than TMP_MAX. */ +#if ATTEMPTS_MIN < TMP_MAX + unsigned int attempts = TMP_MAX; +#else + unsigned int attempts = ATTEMPTS_MIN; +#endif + + len = strlen (tmpl); + if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX")) + { + gpg_err_set_errno (EINVAL); + return NULL; + } + + /* This is where the Xs start. */ + XXXXXX = &tmpl[len - 6]; + + /* Get a random start value. */ + gcry_create_nonce (&value, sizeof value); + + /* Loop until a directory was created. */ + for (count = 0; count < attempts; value += 7777, ++count) + { + uint64_t v = value; + + /* Fill in the random bits. */ + XXXXXX[0] = letters[v % NUMBER_OF_LETTERS]; + v /= NUMBER_OF_LETTERS; + XXXXXX[1] = letters[v % NUMBER_OF_LETTERS]; + v /= NUMBER_OF_LETTERS; + XXXXXX[2] = letters[v % NUMBER_OF_LETTERS]; + v /= NUMBER_OF_LETTERS; + XXXXXX[3] = letters[v % NUMBER_OF_LETTERS]; + v /= NUMBER_OF_LETTERS; + XXXXXX[4] = letters[v % NUMBER_OF_LETTERS]; + v /= NUMBER_OF_LETTERS; + XXXXXX[5] = letters[v % NUMBER_OF_LETTERS]; + + if (!gnupg_mkdir (tmpl, "-rwx")) + { + gpg_err_set_errno (save_errno); + return tmpl; + } + if (errno != EEXIST) + return NULL; + } + + /* We got out of the loop because we ran out of combinations to try. */ + gpg_err_set_errno (EEXIST); + return NULL; +} + + int gnupg_setenv (const char *name, const char *value, int overwrite) { @@ -625,23 +710,72 @@ gnupg_setenv (const char *name, const char *value, int overwrite) (void)value; (void)overwrite; return 0; -#else +#elif defined(HAVE_W32_SYSTEM) + if (!overwrite) + { + char tmpbuf[10]; + if (GetEnvironmentVariable (name, tmpbuf, sizeof tmpbuf)) + return 0; /* Exists but overwrite was not requested. */ + } + if (!SetEnvironmentVariable (name, value)) + { + gpg_err_set_errno (EINVAL); /* (Might also be ENOMEM.) */ + return -1; + } + return 0; +#elif defined(HAVE_SETENV) return setenv (name, value, overwrite); +#else + char *buf; + + (void)overwrite; + if (!name || !value) + { + gpg_err_set_errno (EINVAL); + return -1; + } + buf = xtrymalloc (strlen (name) + 1 + strlen (value) + 1); + if (!buf) + return -1; + strcpy (stpcpy (stpcpy (buf, name), "="), value); +#if __GNUC__ +# warning no setenv - using putenv but leaking memory. +#endif + return putenv (buf); #endif } + int gnupg_unsetenv (const char *name) { #ifdef HAVE_W32CE_SYSTEM (void)name; return 0; -#else -# ifdef HAVE_UNSETENV +#elif defined(HAVE_W32_SYSTEM) + if (!SetEnvironmentVariable (name, NULL)) + { + gpg_err_set_errno (EINVAL); /* (Might also be ENOMEM.) */ + return -1; + } + return 0; +#elif defined(HAVE_UNSETENV) return unsetenv (name); -# else - return putenv (name); -# endif +#else + char *buf; + + if (!name) + { + gpg_err_set_errno (EINVAL); + return -1; + } + buf = xtrystrdup (name); + if (!buf) + return -1; +#if __GNUC__ +# warning no unsetenv - trying putenv but leaking memory. +#endif + return putenv (buf); #endif } diff --git a/common/sysutils.h b/common/sysutils.h index d139665ac..95276dea6 100644 --- a/common/sysutils.h +++ b/common/sysutils.h @@ -61,6 +61,7 @@ void gnupg_reopen_std (const char *pgmname); void gnupg_allow_set_foregound_window (pid_t pid); int gnupg_remove (const char *fname); int gnupg_mkdir (const char *name, const char *modestr); +char *gnupg_mkdtemp (char *template); int gnupg_setenv (const char *name, const char *value, int overwrite); int gnupg_unsetenv (const char *name); char *gnupg_getcwd (void); diff --git a/common/t-sysutils.c b/common/t-sysutils.c index d13bdfe41..68c3e418d 100644 --- a/common/t-sysutils.c +++ b/common/t-sysutils.c @@ -83,6 +83,7 @@ main (int argc, char **argv) verbose = 1; test_gnupg_tmpfile (); + /* Fixme: Add tests for setenv and unsetenv. */ return !!errcount; } diff --git a/configure.ac b/configure.ac index 203f29b81..f59c11772 100644 --- a/configure.ac +++ b/configure.ac @@ -577,7 +577,6 @@ AC_CHECK_TOOL(AR, ar, :) AC_PATH_PROG(PERL,"perl") AC_CHECK_TOOL(WINDRES, windres, :) AC_ISC_POSIX -gl_EARLY AC_SYS_LARGEFILE GNUPG_CHECK_USTAR @@ -1293,7 +1292,7 @@ AC_CHECK_HEADERS([signal.h]) AC_CHECK_FUNCS([memicmp stpcpy strsep strlwr strtoul memmove stricmp strtol \ memrchr isascii timegm getrusage setrlimit stat setlocale \ flockfile funlockfile fopencookie funopen getpwnam getpwuid \ - getenv inet_pton]) + getenv inet_pton strpbrk]) # end jnlib checks. diff --git a/g10/exec.c b/g10/exec.c index 5bcfc2e17..0194e9d90 100644 --- a/g10/exec.c +++ b/g10/exec.c @@ -49,6 +49,7 @@ #include "iobuf.h" #include "util.h" #include "membuf.h" +#include "sysutils.h" #include "exec.h" #ifdef NO_EXEC @@ -194,7 +195,7 @@ make_tempdir(struct exec_info *info) xfree(tmp); #endif - if(mkdtemp(info->tempdir)==NULL) + if (!gnupg_mkdtemp(info->tempdir)) log_error(_("can't create directory '%s': %s\n"), info->tempdir,strerror(errno)); else diff --git a/g13/be-encfs.c b/g13/be-encfs.c index 265b4c2bc..f59f4d947 100644 --- a/g13/be-encfs.c +++ b/g13/be-encfs.c @@ -30,6 +30,7 @@ #include "keyblob.h" #include "be-encfs.h" #include "runner.h" +#include "../common/sysutils.h" #include "../common/exechelp.h" @@ -415,7 +416,7 @@ be_encfs_create_container (ctrl_t ctrl, const char *fname, tupledesc_t tuples, err = gpg_error_from_syserror (); goto leave; } - if (!mkdtemp (mountpoint)) + if (!gnupg_mkdtemp (mountpoint)) { err = gpg_error_from_syserror (); log_error (_("can't create directory '%s': %s\n"), diff --git a/g13/mount.c b/g13/mount.c index 512e29d1a..fc640e0ee 100644 --- a/g13/mount.c +++ b/g13/mount.c @@ -33,6 +33,7 @@ #include "keyblob.h" #include "backend.h" #include "utils.h" +#include "../common/sysutils.h" #include "call-gpg.h" #include "mountinfo.h" #include "runner.h" @@ -260,7 +261,7 @@ g13_mount_container (ctrl_t ctrl, const char *filename, const char *mountpoint) mountpoint_buffer = xtrystrdup ("/tmp/g13-XXXXXX"); if (!mountpoint_buffer) return gpg_error_from_syserror (); - if (!mkdtemp (mountpoint_buffer)) + if (!gnupg_mkdtemp (mountpoint_buffer)) { err = gpg_error_from_syserror (); log_error (_("can't create directory '%s': %s\n"), diff --git a/tools/symcryptrun.c b/tools/symcryptrun.c index 48562b16b..4873d7690 100644 --- a/tools/symcryptrun.c +++ b/tools/symcryptrun.c @@ -90,6 +90,7 @@ #include "i18n.h" #include "../common/util.h" #include "../common/init.h" +#include "../common/sysutils.h" /* FIXME: Bah. For spwq_secure_free. */ #define SIMPLE_PWQUERY_IMPLEMENTATION 1 @@ -315,7 +316,7 @@ confucius_mktmpdir (void) name = xstrconcat (p, "gpg-XXXXXX", NULL); else name = xstrconcat (p, "/", "gpg-XXXXXX", NULL); - if (!name || !mkdtemp (name)) + if (!name || !gnupg_mkdtemp (name)) { log_error (_("can't create temporary directory '%s': %s\n"), name?name:"", strerror (errno));