summary refs log tree commit diff stats
path: root/libotr/libgpg-error-1.42/src/sysutils.c
diff options
context:
space:
mode:
Diffstat (limited to 'libotr/libgpg-error-1.42/src/sysutils.c')
-rw-r--r--libotr/libgpg-error-1.42/src/sysutils.c524
1 files changed, 524 insertions, 0 deletions
diff --git a/libotr/libgpg-error-1.42/src/sysutils.c b/libotr/libgpg-error-1.42/src/sysutils.c
new file mode 100644
index 0000000..8f70a66
--- /dev/null
+++ b/libotr/libgpg-error-1.42/src/sysutils.c
@@ -0,0 +1,524 @@
+/* sysutils.c - Platform specific helper functions
+ * Copyright (C) 2017 g10 Code GmbH
+ *
+ * This file is part of libgpg-error.
+ *
+ * libgpg-error is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * libgpg-error 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#ifdef HAVE_W32_SYSTEM
+# include <windows.h>
+#endif
+#ifdef HAVE_STAT
+# include <sys/stat.h>
+#endif
+#include <sys/types.h>
+#include <fcntl.h>
+#ifdef HAVE_PWD_H
+# include <pwd.h>
+#endif
+
+#include "gpgrt-int.h"
+
+
+#ifdef HAVE_W32_SYSTEM
+/* Return true if STRING has any 8 bit character.  */
+static int
+any8bitchar (const char *string)
+{
+  if (string)
+    for ( ; *string; string++)
+      if ((*string & 0x80))
+        return 1;
+  return 0;
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+
+/* Return true if FD is valid.  */
+int
+_gpgrt_fd_valid_p (int fd)
+{
+  int d = dup (fd);
+  if (d < 0)
+    return 0;
+  close (d);
+  return 1;
+}
+
+
+/* Our variant of getenv.  The returned string must be freed.  If the
+ * environment variable does not exists NULL is returned and ERRNO set
+ * to 0.  */
+char *
+_gpgrt_getenv (const char *name)
+{
+  if (!name || !*name || strchr (name, '='))
+    {
+      _gpg_err_set_errno (EINVAL);
+      return NULL;
+    }
+
+#ifdef HAVE_W32_SYSTEM
+  {
+    int len, size;
+    char *result;
+
+    len = GetEnvironmentVariable (name, NULL, 0);
+    if (!len && GetLastError () == ERROR_ENVVAR_NOT_FOUND)
+      {
+        _gpg_err_set_errno (0);
+        return NULL;
+      }
+  again:
+    size = len;
+    result = _gpgrt_malloc (size);
+    if (!result)
+      return NULL;
+    len = GetEnvironmentVariable (name, result, size);
+    if (len >= size)
+      {
+        /* Changed in the meantime - retry.  */
+        _gpgrt_free (result);
+        goto again;
+      }
+    if (!len && GetLastError () == ERROR_ENVVAR_NOT_FOUND)
+      {
+        /* Deleted in the meantime.  */
+        _gpgrt_free (result);
+        _gpg_err_set_errno (0);
+        return NULL;
+      }
+    if (!len)
+      {
+        /* Other error.  FIXME: We need mapping fucntion. */
+        _gpgrt_free (result);
+        _gpg_err_set_errno (EIO);
+        return NULL;
+      }
+
+    return result;
+  }
+#else /*!HAVE_W32_SYSTEM*/
+  {
+    const char *s = getenv (name);
+    if (!s)
+      {
+        _gpg_err_set_errno (0);
+        return NULL;
+      }
+    return _gpgrt_strdup (s);
+  }
+#endif /*!HAVE_W32_SYSTEM*/
+}
+
+
+/* Wrapper around setenv so that we can have the same function in
+ * Windows and Unix.  In contrast to the standard setenv passing a
+ * VALUE as NULL and setting OVERWRITE will remove the envvar.  */
+gpg_err_code_t
+_gpgrt_setenv (const char *name, const char *value, int overwrite)
+{
+  if (!name || !*name || strchr (name, '='))
+    return GPG_ERR_EINVAL;
+
+#ifdef HAVE_W32_SYSTEM
+  /* Windows maintains (at least) two sets of environment variables.
+   * One set can be accessed by GetEnvironmentVariable and
+   * SetEnvironmentVariable.  This set is inherited by the children.
+   * The other set is maintained in the C runtime, and is accessed
+   * using getenv and putenv.  We try to keep them in sync by
+   * modifying both sets.  Note that gpgrt_getenv ignores the libc
+   * values - however, too much existing code still uses getenv.  */
+  {
+    int exists;
+    char tmpbuf[10];
+    char *buf;
+
+    if (!value && overwrite)
+      {
+        if (!SetEnvironmentVariable (name, NULL))
+          return GPG_ERR_EINVAL;
+        if (getenv (name))
+          {
+            /* Ugly: Leaking memory.  */
+            buf = _gpgrt_strdup (name);
+            if (!buf)
+              return _gpg_err_code_from_syserror ();
+            if (putenv (buf))
+              return _gpg_err_code_from_syserror ();
+          }
+        return 0;
+      }
+
+    exists = GetEnvironmentVariable (name, tmpbuf, sizeof tmpbuf);
+    if ((! exists || overwrite) && !SetEnvironmentVariable (name, value))
+      return GPG_ERR_EINVAL; /* (Might also be ENOMEM.) */
+    if (overwrite || !getenv (name))
+      {
+        /* Ugly: Leaking memory.  */
+        buf = _gpgrt_strconcat (name, "=", value, NULL);
+        if (!buf)
+          return _gpg_err_code_from_syserror ();
+        if (putenv (buf))
+          return _gpg_err_code_from_syserror ();
+      }
+    return 0;
+  }
+
+#else /*!HAVE_W32_SYSTEM*/
+
+# ifdef HAVE_SETENV
+
+  {
+    if (!value && overwrite)
+      {
+        if (unsetenv (name))
+          return _gpg_err_code_from_syserror ();
+      }
+    else
+      {
+        if (setenv (name, value ? value : "", overwrite))
+          return _gpg_err_code_from_syserror ();
+      }
+
+    return 0;
+  }
+
+# else /*!HAVE_SETENV*/
+
+# if __GNUC__
+#   warning no setenv - using putenv but leaking memory.
+# endif
+  {
+    char *buf;
+
+    if (!value && overwrite)
+      {
+        if (getenv (name))
+          {
+            buf = _gpgrt_strdup (name);
+            if (!buf)
+              return _gpg_err_code_from_syserror ();
+            if (putenv (buf))
+              return -1;
+          }
+      }
+    else if (overwrite || !getenv (name))
+      {
+        buf = _gpgrt_strconcat (name, "=", value, NULL);
+        if (!buf)
+          return _gpg_err_code_from_syserror ();
+        if (putenv (buf))
+          return _gpg_err_code_from_syserror ();
+      }
+
+    return 0;
+  }
+# endif /*!HAVE_SETENV*/
+#endif /*!HAVE_W32_SYSTEM*/
+}
+
+
+#ifndef HAVE_W32_SYSTEM
+static mode_t
+modestr_to_mode (const char *modestr)
+{
+  mode_t mode = 0;
+
+  if (modestr && *modestr)
+    {
+      modestr++;
+      if (*modestr && *modestr++ == 'r')
+        mode |= S_IRUSR;
+      if (*modestr && *modestr++ == 'w')
+        mode |= S_IWUSR;
+      if (*modestr && *modestr++ == 'x')
+        mode |= S_IXUSR;
+      if (*modestr && *modestr++ == 'r')
+        mode |= S_IRGRP;
+      if (*modestr && *modestr++ == 'w')
+        mode |= S_IWGRP;
+      if (*modestr && *modestr++ == 'x')
+        mode |= S_IXGRP;
+      if (*modestr && *modestr++ == 'r')
+        mode |= S_IROTH;
+      if (*modestr && *modestr++ == 'w')
+        mode |= S_IWOTH;
+      if (*modestr && *modestr++ == 'x')
+        mode |= S_IXOTH;
+    }
+
+  return mode;
+}
+#endif
+
+
+/* A wrapper around mkdir which takes a string for the mode argument.
+ * This makes it easier to handle the mode argument which is not
+ * defined on all systems.  The format of the modestring is
+ *
+ *    "-rwxrwxrwx"
+ *
+ * '-' is a don't care or not set.  'r', 'w', 'x' are read allowed,
+ * write allowed, execution allowed with the first group for the user,
+ * the second for the group and the third for all others.  If the
+ * string is shorter than above the missing mode characters are meant
+ * to be not set.
+ *
+ * Note that in addition to returning an gpg-error error code ERRNO is
+ * also set by this function.
+ */
+gpg_err_code_t
+_gpgrt_mkdir (const char *name, const char *modestr)
+{
+#ifdef HAVE_W32_SYSTEM
+  wchar_t *wname;
+  gpg_err_code_t ec;
+  (void)modestr;
+
+  /* Note: Fixme: We should set appropriate permissions.  */
+  wname = _gpgrt_utf8_to_wchar (name);
+  if (!wname)
+    return _gpg_err_code_from_syserror ();
+  if (!CreateDirectoryW (wname, NULL))
+    {
+      _gpgrt_w32_set_errno (-1);
+      ec = _gpg_err_code_from_syserror ();
+    }
+  else
+    ec = 0;
+  _gpgrt_free_wchar (wname);
+  return ec;
+#elif MKDIR_TAKES_ONE_ARG
+  (void)modestr;
+  if (mkdir (name))
+    return _gpg_err_code_from_syserror ();
+  return 0;
+#else
+  if (mkdir (name, modestr_to_mode (modestr)))
+    return _gpg_err_code_from_syserror ();
+  return 0;
+#endif
+}
+
+
+/* A simple wrapper around chdir.  NAME is expected to be utf8
+ * encoded.
+ * Note that in addition to returning an gpg-error error code ERRNO is
+ * also set by this function.  */
+gpg_err_code_t
+_gpgrt_chdir (const char *name)
+{
+#ifdef HAVE_W32_SYSTEM
+  wchar_t *wname;
+  gpg_err_code_t ec;
+
+  wname = _gpgrt_utf8_to_wchar (name);
+  if (!wname)
+    return _gpg_err_code_from_syserror ();
+  if (!SetCurrentDirectoryW (wname))
+    {
+      _gpgrt_w32_set_errno (-1);
+      ec = _gpg_err_code_from_syserror ();
+    }
+  else
+    ec = 0;
+  _gpgrt_free_wchar (wname);
+  return ec;
+
+#else /*!HAVE_W32_SYSTEM*/
+  if (chdir (name))
+    return _gpg_err_code_from_syserror ();
+  return 0;
+#endif /*!HAVE_W32_SYSTEM*/
+}
+
+
+/* Return the current working directory as a malloced string.  Return
+ * NULL and sets ERRNO on error.  */
+char *
+_gpgrt_getcwd (void)
+{
+#ifdef HAVE_W32CE_SYSTEM
+
+  return xtrystrdup ("/");
+
+#elif defined(HAVE_W32_SYSTEM)
+  wchar_t wbuffer[MAX_PATH + sizeof(wchar_t)];
+  DWORD wlen;
+  char *buf, *p;
+
+  wlen = GetCurrentDirectoryW (MAX_PATH, wbuffer);
+  if (!wlen)
+    {
+      _gpgrt_w32_set_errno (-1);
+      return NULL;
+
+    }
+  else if (wlen > MAX_PATH)
+    {
+      _gpg_err_set_errno (ENAMETOOLONG);
+      return NULL;
+    }
+  buf = _gpgrt_wchar_to_utf8 (wbuffer, wlen);
+  if (buf)
+    {
+      for (p=buf; *p; p++)
+        if (*p == '\\')
+          *p = '/';
+    }
+  return buf;
+
+#else /*Unix*/
+  char *buffer;
+  size_t size = 100;
+
+  for (;;)
+    {
+      buffer = xtrymalloc (size+1);
+      if (!buffer)
+        return NULL;
+      if (getcwd (buffer, size) == buffer)
+        return buffer;
+      xfree (buffer);
+      if (errno != ERANGE)
+        return NULL;
+      size *= 2;
+    }
+#endif /*Unix*/
+}
+
+
+/* Wrapper around access to handle file name encoding under Windows.
+ * Returns 0 if FNAME can be accessed in MODE or an error code.  ERRNO
+ * is also set on error. */
+gpg_err_code_t
+_gpgrt_access (const char *fname, int mode)
+{
+  gpg_err_code_t ec;
+
+#ifdef HAVE_W32_SYSTEM
+  if (any8bitchar (fname))
+    {
+      wchar_t *wfname;
+
+      wfname = _gpgrt_utf8_to_wchar (fname);
+      if (!wfname)
+        ec = _gpg_err_code_from_syserror ();
+      else
+        {
+          ec = _waccess (wfname, mode)? _gpg_err_code_from_syserror () : 0;
+          _gpgrt_free_wchar (wfname);
+        }
+    }
+  else
+#endif /*HAVE_W32_SYSTEM*/
+    ec = access (fname, mode)? _gpg_err_code_from_syserror () : 0;
+
+  return ec;
+}
+
+
+
+/* Get the standard home directory for user NAME. If NAME is NULL the
+ * directory for the current user is returned.  Caller must release
+ * the returned string.  */
+char *
+_gpgrt_getpwdir (const char *name)
+{
+  char *result = NULL;
+#ifdef HAVE_PWD_H
+  struct passwd *pwd = NULL;
+
+  if (name)
+    {
+#ifdef HAVE_GETPWNAM
+      /* Fixme: We should use getpwnam_r if available.  */
+      pwd = getpwnam (name);
+#endif
+    }
+  else
+    {
+#ifdef HAVE_GETPWUID
+      /* Fixme: We should use getpwuid_r if available.  */
+      pwd = getpwuid (getuid());
+#endif
+    }
+  if (pwd)
+    {
+      result = _gpgrt_strdup (pwd->pw_dir);
+    }
+#else /*!HAVE_PWD_H*/
+  /* No support at all.  */
+  (void)name;
+#endif /*HAVE_PWD_H*/
+  return result;
+}
+
+
+/* Return a malloced copy of the current user's account name; this may
+ * return NULL on memory failure.  */
+char *
+_gpgrt_getusername (void)
+{
+  char *result = NULL;
+
+#ifdef HAVE_W32_SYSTEM
+  wchar_t wtmp[1];
+  wchar_t *wbuf;
+  DWORD wsize = 1;
+  char *buf;
+
+  GetUserNameW (wtmp, &wsize);
+  wbuf = _gpgrt_malloc (wsize * sizeof *wbuf);
+  if (!wbuf)
+    {
+      _gpgrt_w32_set_errno (-1);
+      return NULL;
+    }
+  if (!GetUserNameW (wbuf, &wsize))
+    {
+      _gpgrt_w32_set_errno (-1);
+      xfree (wbuf);
+      return NULL;
+    }
+  buf = _gpgrt_wchar_to_utf8 (wbuf, wsize);
+  xfree (wbuf);
+  return buf;
+
+#else /* !HAVE_W32_SYSTEM */
+
+# if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
+  struct passwd *pwd;
+
+  pwd = getpwuid (getuid());
+  if (pwd)
+    {
+      result = _gpgrt_strdup (pwd->pw_name);
+    }
+
+# endif /*HAVE_PWD_H*/
+
+#endif /* !HAVE_W32_SYSTEM */
+
+  return result;
+}