aboutsummaryrefslogtreecommitdiffstats
path: root/common/sysutils.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/sysutils.c')
-rw-r--r--common/sysutils.c182
1 files changed, 175 insertions, 7 deletions
diff --git a/common/sysutils.c b/common/sysutils.c
index 90627b7c8..6c7d616b9 100644
--- a/common/sysutils.c
+++ b/common/sysutils.c
@@ -559,17 +559,15 @@ translate_sys2libc_fd (gnupg_fd_t fd, int for_write)
}
/* This is the same as translate_sys2libc_fd but takes an integer
- which is assumed to be such an system handle. On WindowsCE the
- passed FD is a rendezvous ID and the function finishes the pipe
- creation. */
+ which is assumed to be such an system handle. */
int
translate_sys2libc_fd_int (int fd, int for_write)
{
#ifdef HAVE_W32_SYSTEM
if (fd <= 2)
- return fd; /* Do not do this for error, stdin, stdout, stderr. */
+ return fd; /* Do not do this for stdin, stdout, and stderr. */
- return translate_sys2libc_fd ((void*)fd, for_write);
+ return translate_sys2libc_fd ((void*)(intptr_t)fd, for_write);
#else
(void)for_write;
return fd;
@@ -577,6 +575,70 @@ translate_sys2libc_fd_int (int fd, int for_write)
}
+/*
+ * Parse the string representation of a file reference (file handle on
+ * Windows or file descriptor on POSIX) in FDSTR. The string
+ * representation may be either of folllowing:
+
+ * (1) 0, 1, or 2 which means stdin, stdout, and stderr, respectively.
+ * (2) Integer representation (by %d of printf).
+ * (3) Hex representation which starts as "0x".
+ *
+ * Then, fill R_SYSHD, according to the value of a file reference.
+ *
+ */
+gpg_error_t
+gnupg_parse_fdstr (const char *fdstr, es_syshd_t *r_syshd)
+{
+ int fd = -1;
+#ifdef HAVE_W32_SYSTEM
+ gnupg_fd_t hd;
+ char *endptr;
+ int base;
+
+ if (!strcmp (fdstr, "0"))
+ fd = 0;
+ else if (!strcmp (fdstr, "1"))
+ fd = 1;
+ else if (!strcmp (fdstr, "2"))
+ fd = 2;
+
+ if (fd >= 0)
+ {
+ r_syshd->type = ES_SYSHD_FD;
+ r_syshd->u.fd = fd;
+ return 0;
+ }
+
+ if (!strncmp (fdstr, "0x", 2))
+ {
+ base = 16;
+ fdstr += 2;
+ }
+ else
+ base = 10;
+
+ gpg_err_set_errno (0);
+#ifdef _WIN64
+ hd = (gnupg_fd_t)strtoll (fdstr, &endptr, base);
+#else
+ hd = (gnupg_fd_t)strtol (fdstr, &endptr, base);
+#endif
+ if (errno != 0 || endptr == fdstr || *endptr != '\0')
+ return gpg_error (GPG_ERR_INV_ARG);
+
+ r_syshd->type = ES_SYSHD_HANDLE;
+ r_syshd->u.handle = hd;
+ return 0;
+#else
+ fd = atoi (fdstr);
+ r_syshd->type = ES_SYSHD_FD;
+ r_syshd->u.fd = fd;
+ return 0;
+#endif
+}
+
+
/* Check whether FNAME has the form "-&nnnn", where N is a non-zero
* number. Returns this number or -1 if it is not the case. If the
* caller wants to use the file descriptor for writing FOR_WRITE shall
@@ -594,13 +656,74 @@ check_special_filename (const char *fname, int for_write, int notranslate)
for (i=0; digitp (fname+i); i++ )
;
if (!fname[i])
- return notranslate? atoi (fname)
- /**/ : translate_sys2libc_fd_int (atoi (fname), for_write);
+ {
+ if (notranslate)
+ return atoi (fname);
+ else
+ {
+ es_syshd_t syshd;
+
+ if (gnupg_parse_fdstr (fname, &syshd))
+ return -1;
+
+#ifdef HAVE_W32_SYSTEM
+ if (syshd.type == ES_SYSHD_FD)
+ return syshd.u.fd;
+ else
+ return translate_sys2libc_fd ((gnupg_fd_t)syshd.u.handle, for_write);
+#else
+ (void)for_write;
+ return syshd.u.fd;
+#endif
+ }
+ }
}
return -1;
}
+/* Check whether FNAME has the form "-&nnnn", where N is a number
+ * representing a file. Returns GNUPG_INVALID_FD if it is not the
+ * case. Returns a file descriptor on POSIX, a system handle on
+ * Windows. */
+gnupg_fd_t
+gnupg_check_special_filename (const char *fname)
+{
+ if (allow_special_filenames
+ && fname && *fname == '-' && fname[1] == '&')
+ {
+ int i;
+
+ fname += 2;
+ for (i=0; digitp (fname+i); i++ )
+ ;
+ if (!fname[i])
+ {
+ es_syshd_t syshd;
+
+ if (gnupg_parse_fdstr (fname, &syshd))
+ return GNUPG_INVALID_FD;
+
+#ifdef HAVE_W32_SYSTEM
+ if (syshd.type == ES_SYSHD_FD)
+ {
+ if (syshd.u.fd == 0)
+ return GetStdHandle (STD_INPUT_HANDLE);
+ else if (syshd.u.fd == 1)
+ return GetStdHandle (STD_OUTPUT_HANDLE);
+ else if (syshd.u.fd == 2)
+ return GetStdHandle (STD_ERROR_HANDLE);
+ }
+ else
+ return syshd.u.handle;
+#else
+ return syshd.u.fd;
+#endif
+ }
+ }
+ return GNUPG_INVALID_FD;
+}
+
/* Replacement for tmpfile(). This is required because the tmpfile
function of Windows' runtime library is broken, insecure, ignores
TMPDIR and so on. In addition we create a file with an inheritable
@@ -1158,6 +1281,19 @@ gnupg_setenv (const char *name, const char *value, int overwrite)
return setenv (name, value, overwrite);
#else /*!HAVE_SETENV*/
if (! getenv (name) || overwrite)
+#if defined(HAVE_W32_SYSTEM) && defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
+ {
+ int e = _putenv_s (name, value);
+
+ if (e)
+ {
+ gpg_err_set_errno (e);
+ return -1;
+ }
+ else
+ return 0;
+ }
+#else
{
char *buf;
@@ -1175,6 +1311,7 @@ gnupg_setenv (const char *name, const char *value, int overwrite)
# endif
return putenv (buf);
}
+#endif /*!HAVE_W32_SYSTEM*/
return 0;
#endif /*!HAVE_SETENV*/
}
@@ -1199,6 +1336,18 @@ gnupg_unsetenv (const char *name)
#ifdef HAVE_UNSETENV
return unsetenv (name);
+#elif defined(HAVE_W32_SYSTEM) && defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
+ {
+ int e = _putenv_s (name, "");
+
+ if (e)
+ {
+ gpg_err_set_errno (e);
+ return -1;
+ }
+ else
+ return 0;
+ }
#else /*!HAVE_UNSETENV*/
{
char *buf;
@@ -1829,3 +1978,22 @@ gnupg_fd_valid (int fd)
close (d);
return 1;
}
+
+
+/* Open a stream from FD (a file descriptor on POSIX, a system
+ handle on Windows), non-closed. */
+estream_t
+open_stream_nc (gnupg_fd_t fd, const char *mode)
+{
+ es_syshd_t syshd;
+
+#ifdef HAVE_W32_SYSTEM
+ syshd.type = ES_SYSHD_HANDLE;
+ syshd.u.handle = fd;
+#else
+ syshd.type = ES_SYSHD_FD;
+ syshd.u.fd = fd;
+#endif
+
+ return es_sysopen_nc (&syshd, mode);
+}