Remove use of gnulib (part 2)
[gnupg.git] / common / sysutils.c
index 648e70f..3971845 100644 (file)
@@ -1,15 +1,26 @@
 /* sysutils.c -  system helpers
- * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004,
- *               2007, 2008  Free Software Foundation, Inc.
+ * Copyright (C) 1991-2001, 2003-2004,
+ *               2006-2008  Free Software Foundation, Inc.
+ * Copyright (C) 2013-2014 Werner Koch
  *
  * This file is part of GnuPG.
  *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
  *
- * GnuPG is distributed in the hope that it will be useful,
+ *   - the GNU Lesser General Public License as published by the Free
+ *     Software Foundation; either version 3 of the License, or (at
+ *     your option) any later version.
+ *
+ * or
+ *
+ *   - the GNU General Public License as published by the Free
+ *     Software Foundation; either version 2 of the License, or (at
+ *     your option) any later version.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
 
 #include <config.h>
 
-#ifdef WITHOUT_GNU_PTH /* Give the Makefile a chance to build without Pth.  */
-# undef HAVE_PTH
-# undef USE_GNU_PTH
+#ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth.  */
+# undef HAVE_NPTH
+# undef USE_NPTH
 #endif
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdint.h>
 #include <string.h>
 #include <unistd.h>
 #include <errno.h>
 # include <sys/resource.h>
 #endif
 #ifdef HAVE_W32_SYSTEM
-# define WINVER 0x0500  /* Required for AllowSetForegroundWindow.  */
+# if WINVER < 0x0500
+#   define WINVER 0x0500  /* Required for AllowSetForegroundWindow.  */
+# endif
+# ifdef HAVE_WINSOCK2_H
+#  include <winsock2.h>
+# endif
 # include <windows.h>
 #endif
-#ifdef HAVE_PTH
-# include <pth.h>
+#ifdef HAVE_NPTH
+# include <npth.h>
 #endif
 #include <fcntl.h>
 
 #include <assuan.h>
 
-#include "setenv.h"   /* Gnulib replacement.  */
-
 #include "util.h"
 #include "i18n.h"
 
@@ -259,18 +274,8 @@ check_permissions(const char *path,int extension,int checkonly)
 void
 gnupg_sleep (unsigned int seconds)
 {
-#ifdef HAVE_PTH
-  /* With Pth we force a regular sleep for seconds == 0 so that also
-     the process will give up its timeslot.  */
-  if (!seconds)
-    {
-# ifdef HAVE_W32_SYSTEM
-      Sleep (0);
-# else
-      sleep (0);
-# endif
-    }
-  pth_sleep (seconds);
+#ifdef USE_NPTH
+  npth_sleep (seconds);
 #else
   /* Fixme:  make sure that a sleep won't wake up to early.  */
 # ifdef HAVE_W32_SYSTEM
@@ -613,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)
 {
@@ -621,26 +710,105 @@ 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
+}
+
+
+/* Return the current working directory as a malloced string.  Return
+   NULL and sets ERRNo on error.  */
+char *
+gnupg_getcwd (void)
+{
+  char *buffer;
+  size_t size = 100;
+
+  for (;;)
+    {
+      buffer = xtrymalloc (size+1);
+      if (!buffer)
+        return NULL;
+#ifdef HAVE_W32CE_SYSTEM
+      strcpy (buffer, "/");  /* Always "/".  */
+      return buffer;
+#else
+      if (getcwd (buffer, size) == buffer)
+        return buffer;
+      xfree (buffer);
+      if (errno != ERANGE)
+        return NULL;
+      size *= 2;
+#endif
+    }
 }
 
+
+\f
 #ifdef HAVE_W32CE_SYSTEM
 /* There is a isatty function declaration in cegcc but it does not
    make sense, thus we redefine it.  */
@@ -678,3 +846,59 @@ _gnupg_getenv (const char *name)
 }
 
 #endif /*HAVE_W32CE_SYSTEM*/
+
+
+#ifdef HAVE_W32_SYSTEM
+/* Return the user's security identifier from the current process.  */
+PSID
+w32_get_user_sid (void)
+{
+  int okay = 0;
+  HANDLE proc = NULL;
+  HANDLE token = NULL;
+  TOKEN_USER *user = NULL;
+  PSID sid = NULL;
+  DWORD tokenlen, sidlen;
+
+  proc = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
+  if (!proc)
+    goto leave;
+
+  if (!OpenProcessToken (proc, TOKEN_QUERY, &token))
+    goto leave;
+
+  if (!GetTokenInformation (token, TokenUser, NULL, 0, &tokenlen)
+      && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+    goto leave;
+
+  user = xtrymalloc (tokenlen);
+  if (!user)
+    goto leave;
+
+  if (!GetTokenInformation (token, TokenUser, user, tokenlen, &tokenlen))
+    goto leave;
+  if (!IsValidSid (user->User.Sid))
+    goto leave;
+  sidlen = GetLengthSid (user->User.Sid);
+  sid = xtrymalloc (sidlen);
+  if (!sid)
+    goto leave;
+  if (!CopySid (sidlen, sid, user->User.Sid))
+    goto leave;
+  okay = 1;
+
+ leave:
+  xfree (user);
+  if (token)
+    CloseHandle (token);
+  if (proc)
+    CloseHandle (proc);
+
+  if (!okay)
+    {
+      xfree (sid);
+      sid = NULL;
+    }
+  return sid;
+}
+#endif /*HAVE_W32_SYSTEM*/