diff options
Diffstat (limited to 'src/system.c')
-rw-r--r-- | src/system.c | 660 |
1 files changed, 10 insertions, 650 deletions
diff --git a/src/system.c b/src/system.c index fa942f7..22d7a0b 100644 --- a/src/system.c +++ b/src/system.c @@ -28,11 +28,6 @@ #include <sys/types.h> #include <time.h> #include <fcntl.h> -#ifdef HAVE_W32_SYSTEM -# include <windows.h> -#else -# include <sys/wait.h> -#endif #include "assuan-defs.h" #include "debug.h" @@ -45,30 +40,7 @@ #define DEBUG_SYSIO 0 - -assuan_fd_t -assuan_fdopen (int fd) -{ -#ifdef HAVE_W32_SYSTEM -#ifdef HAVE_W32CE_SYSTEM - assuan_fd_t ifd = (assuan_fd_t)fd; -#else - assuan_fd_t ifd = (assuan_fd_t) _get_osfhandle (fd); -#endif - assuan_fd_t ofd; - if (! DuplicateHandle(GetCurrentProcess(), ifd, - GetCurrentProcess(), &ofd, 0, - TRUE, DUPLICATE_SAME_ACCESS)) - { - gpg_err_set_errno (EIO); - return ASSUAN_INVALID_FD; - } - return ofd; -#else - return dup (fd); -#endif -} /* Manage memory specific to a context. */ @@ -154,40 +126,8 @@ _assuan_system_hooks_copy (assuan_system_hooks_t dst, ; } - -/* Sleep for the given number of microseconds. Default - implementation. */ -void -__assuan_usleep (assuan_context_t ctx, unsigned int usec) -{ - if (! usec) - return; - -#ifdef HAVE_NANOSLEEP - { - struct timespec req; - struct timespec rem; - - req.tv_sec = 0; - req.tv_nsec = usec * 1000; - - while (nanosleep (&req, &rem) < 0 && errno == EINTR) - req = rem; - } -#elif defined(HAVE_W32_SYSTEM) - Sleep (usec / 1000); -#else - { - struct timeval tv; - - tv.tv_sec = usec / 1000000; - tv.tv_usec = usec % 1000000; - select (0, NULL, NULL, NULL, &tv); - } -#endif -} - + /* Sleep for the given number of microseconds. */ void _assuan_usleep (assuan_context_t ctx, unsigned int usec) @@ -198,61 +138,8 @@ _assuan_usleep (assuan_context_t ctx, unsigned int usec) (ctx->system.usleep) (ctx, usec); } - -/* Create a pipe with one inheritable end. Default implementation. */ -int -__assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx) -{ -#ifdef HAVE_W32_SYSTEM - HANDLE rh; - HANDLE wh; - HANDLE th; - SECURITY_ATTRIBUTES sec_attr; - - memset (&sec_attr, 0, sizeof (sec_attr)); - sec_attr.nLength = sizeof (sec_attr); - sec_attr.bInheritHandle = FALSE; - - if (!CreatePipe (&rh, &wh, &sec_attr, 0)) - { - TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_pipe", ctx, - "CreatePipe failed: %s", _assuan_w32_strerror (ctx, -1)); - gpg_err_set_errno (EIO); - return -1; - } - - if (! DuplicateHandle (GetCurrentProcess(), (inherit_idx == 0) ? rh : wh, - GetCurrentProcess(), &th, 0, - TRUE, DUPLICATE_SAME_ACCESS )) - { - TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_pipe", ctx, - "DuplicateHandle failed: %s", _assuan_w32_strerror (ctx, -1)); - CloseHandle (rh); - CloseHandle (wh); - gpg_err_set_errno (EIO); - return -1; - } - if (inherit_idx == 0) - { - CloseHandle (rh); - rh = th; - } - else - { - CloseHandle (wh); - wh = th; - } - - fd[0] = rh; - fd[1] = wh; - - return 0; -#else - return pipe (fd); -#endif -} - + /* Create a pipe with one inheritable end. */ int _assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx) @@ -269,30 +156,8 @@ _assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx) return TRACE_SUC2 ("read=0x%x, write=0x%x", fd[0], fd[1]); } - -/* Close the given file descriptor, created with _assuan_pipe or one - of the socket functions. Default implementation. */ -int -__assuan_close (assuan_context_t ctx, assuan_fd_t fd) -{ -#ifdef HAVE_W32_SYSTEM - int rc = closesocket (HANDLE2SOCKET(fd)); - if (rc) - gpg_err_set_errno ( _assuan_sock_wsa2errno (WSAGetLastError ()) ); - if (rc && WSAGetLastError () == WSAENOTSOCK) - { - rc = CloseHandle (fd); - if (rc) - /* FIXME. */ - gpg_err_set_errno (EIO); - } - return rc; -#else - return close (fd); -#endif -} - + /* Close the given file descriptor, created with _assuan_pipe or one of the socket functions. */ int @@ -304,64 +169,8 @@ _assuan_close (assuan_context_t ctx, assuan_fd_t fd) return (ctx->system.close) (ctx, fd); } - -static ssize_t -__assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size) -{ -#ifdef HAVE_W32_SYSTEM - /* Due to the peculiarities of the W32 API we can't use read for a - network socket and thus we try to use recv first and fallback to - read if recv detects that it is not a network socket. */ - int res; - - res = recv (HANDLE2SOCKET (fd), buffer, size, 0); - if (res == -1) - { - switch (WSAGetLastError ()) - { - case WSAENOTSOCK: - { - DWORD nread = 0; - - res = ReadFile (fd, buffer, size, &nread, NULL); - if (! res) - { - switch (GetLastError ()) - { - case ERROR_BROKEN_PIPE: - gpg_err_set_errno (EPIPE); - break; - - default: - gpg_err_set_errno (EIO); - } - res = -1; - } - else - res = (int) nread; - } - break; - - case WSAEWOULDBLOCK: - gpg_err_set_errno (EAGAIN); - break; - - case ERROR_BROKEN_PIPE: - gpg_err_set_errno (EPIPE); - break; - - default: - gpg_err_set_errno (EIO); - break; - } - } - return res; -#else /*!HAVE_W32_SYSTEM*/ - return read (fd, buffer, size); -#endif /*!HAVE_W32_SYSTEM*/ -} - + ssize_t _assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size) { @@ -376,48 +185,8 @@ _assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size) #endif } - -static ssize_t -__assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer, - size_t size) -{ -#ifdef HAVE_W32_SYSTEM - /* Due to the peculiarities of the W32 API we can't use write for a - network socket and thus we try to use send first and fallback to - write if send detects that it is not a network socket. */ - int res; - - res = send (HANDLE2SOCKET (fd), buffer, size, 0); - if (res == -1 && WSAGetLastError () == WSAENOTSOCK) - { - DWORD nwrite; - - res = WriteFile (fd, buffer, size, &nwrite, NULL); - if (! res) - { - switch (GetLastError ()) - { - case ERROR_BROKEN_PIPE: - case ERROR_NO_DATA: - gpg_err_set_errno (EPIPE); - break; - - default: - gpg_err_set_errno (EIO); - break; - } - res = -1; - } - else - res = (int) nwrite; - } - return res; -#else /*!HAVE_W32_SYSTEM*/ - return write (fd, buffer, size); -#endif /*!HAVE_W32_SYSTEM*/ -} - + ssize_t _assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer, size_t size) @@ -433,25 +202,8 @@ _assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer, #endif } - -static int -__assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg, - int flags) -{ -#ifdef HAVE_W32_SYSTEM - gpg_err_set_errno (ENOSYS); - return -1; -#else - int ret; - do - ret = recvmsg (fd, msg, flags); - while (ret == -1 && errno == EINTR); - - return ret; -#endif -} - + int _assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg, int flags) @@ -485,25 +237,8 @@ _assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg, #endif } - -static int -__assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg, - int flags) -{ -#ifdef HAVE_W32_SYSTEM - gpg_err_set_errno (ENOSYS); - return -1; -#else - int ret; - do - ret = sendmsg (fd, msg, flags); - while (ret == -1 && errno == EINTR); - - return ret; -#endif -} - + int _assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg, int flags) @@ -536,340 +271,8 @@ _assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg, #endif } - -#ifdef HAVE_W32_SYSTEM -/* Build a command line for use with W32's CreateProcess. On success - CMDLINE gets the address of a newly allocated string. */ -static int -build_w32_commandline (assuan_context_t ctx, const char * const *argv, - char **cmdline) -{ - int i, n; - const char *s; - char *buf, *p; - - *cmdline = NULL; - n = 0; - for (i=0; (s = argv[i]); i++) - { - n += strlen (s) + 1 + 2; /* (1 space, 2 quoting */ - for (; *s; s++) - if (*s == '\"') - n++; /* Need to double inner quotes. */ - } - n++; - - buf = p = _assuan_malloc (ctx, n); - if (! buf) - return -1; - - for (i = 0; argv[i]; i++) - { - if (i) - p = stpcpy (p, " "); - if (! *argv[i]) /* Empty string. */ - p = stpcpy (p, "\"\""); - else if (strpbrk (argv[i], " \t\n\v\f\"")) - { - p = stpcpy (p, "\""); - for (s = argv[i]; *s; s++) - { - *p++ = *s; - if (*s == '\"') - *p++ = *s; - } - *p++ = '\"'; - *p = 0; - } - else - p = stpcpy (p, argv[i]); - } - - *cmdline= buf; - return 0; -} - - -int -__assuan_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name, - const char **argv, - assuan_fd_t fd_in, assuan_fd_t fd_out, - assuan_fd_t *fd_child_list, - void (*atfork) (void *opaque, int reserved), - void *atforkvalue, unsigned int flags) -{ - SECURITY_ATTRIBUTES sec_attr; - PROCESS_INFORMATION pi = - { - NULL, /* Returns process handle. */ - 0, /* Returns primary thread handle. */ - 0, /* Returns pid. */ - 0 /* Returns tid. */ - }; - STARTUPINFO si; - assuan_fd_t fd; - assuan_fd_t *fdp; - char *cmdline; - HANDLE nullfd = INVALID_HANDLE_VALUE; - - /* fixme: Actually we should set the "_assuan_pipe_connect_pid" env - variable. However this requires us to write a full environment - handler, because the strings are expected in sorted order. The - suggestion given in the MS Reference Library, to save the old - value, changeit, create proces and restore it, is not thread - safe. */ - - /* Build the command line. */ - if (build_w32_commandline (ctx, argv, &cmdline)) - return -1; - - /* Start the process. */ - memset (&sec_attr, 0, sizeof sec_attr); - sec_attr.nLength = sizeof sec_attr; - sec_attr.bInheritHandle = FALSE; - - memset (&si, 0, sizeof si); - si.cb = sizeof (si); - si.dwFlags = STARTF_USESTDHANDLES; - /* FIXME: Dup to nul if ASSUAN_INVALID_FD. */ - si.hStdInput = fd_in; - si.hStdOutput = fd_out; - - /* Dup stderr to /dev/null unless it is in the list of FDs to be - passed to the child. */ - fd = assuan_fd_from_posix_fd (fileno (stderr)); - fdp = fd_child_list; - if (fdp) - { - for (; *fdp != ASSUAN_INVALID_FD && *fdp != fd; fdp++) - ; - } - if (!fdp || *fdp == ASSUAN_INVALID_FD) - { - nullfd = CreateFileW (L"nul", GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, 0, NULL); - if (nullfd == INVALID_HANDLE_VALUE) - { - TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx, - "can't open `nul': %s", _assuan_w32_strerror (ctx, -1)); - _assuan_free (ctx, cmdline); - gpg_err_set_errno (EIO); - return -1; - } - si.hStdError = nullfd; - } - else - si.hStdError = fd; - -#ifdef HAVE_W32CE_SYSTEM -# define DETACHED_PROCESS (0) -#endif - /* Note: We inherit all handles flagged as inheritable. This seems - to be a security flaw but there seems to be no way of selecting - handles to inherit. */ - /* _assuan_log_printf ("CreateProcess, path=`%s' cmdline=`%s'\n", */ - /* name, cmdline); */ - if (!CreateProcess (name, /* Program to start. */ - cmdline, /* Command line arguments. */ - &sec_attr, /* Process security attributes. */ - &sec_attr, /* Thread security attributes. */ - TRUE, /* Inherit handles. */ - (CREATE_DEFAULT_ERROR_MODE - | ((flags & 128)? DETACHED_PROCESS : 0) -#ifndef HAVE_W32CE_SYSTEM - | GetPriorityClass (GetCurrentProcess ()) -#endif - | CREATE_SUSPENDED), /* Creation flags. */ - NULL, /* Environment. */ - NULL, /* Use current drive/directory. */ - &si, /* Startup information. */ - &pi /* Returns process information. */ - )) - { - TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_w32", ctx, - "CreateProcess failed: %s", _assuan_w32_strerror (ctx, -1)); - _assuan_free (ctx, cmdline); - if (nullfd != INVALID_HANDLE_VALUE) - CloseHandle (nullfd); - - gpg_err_set_errno (EIO); - return -1; - } - - _assuan_free (ctx, cmdline); - if (nullfd != INVALID_HANDLE_VALUE) - CloseHandle (nullfd); - - ResumeThread (pi.hThread); - CloseHandle (pi.hThread); - - /* _assuan_log_printf ("CreateProcess ready: hProcess=%p hThread=%p" */ - /* " dwProcessID=%d dwThreadId=%d\n", */ - /* pi.hProcess, pi.hThread, */ - /* (int) pi.dwProcessId, (int) pi.dwThreadId); */ - - *r_pid = (pid_t) pi.hProcess; - - /* No need to modify peer process, as we don't change the handle - names. However this also means we are not safe, as we inherit - too many handles. Should use approach similar to gpgme and glib - using a helper process. */ - - return 0; -} - -#else - -static int -writen (int fd, const char *buffer, size_t length) -{ - while (length) - { - int nwritten = write (fd, buffer, length); - - if (nwritten < 0) - { - if (errno == EINTR) - continue; - return -1; /* write error */ - } - length -= nwritten; - buffer += nwritten; - } - return 0; /* okay */ -} - - -int -__assuan_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name, - const char **argv, - assuan_fd_t fd_in, assuan_fd_t fd_out, - assuan_fd_t *fd_child_list, - void (*atfork) (void *opaque, int reserved), - void *atforkvalue, unsigned int flags) -{ - int pid; - - pid = fork (); - if (pid < 0) - return -1; - - if (pid == 0) - { - /* Child process (server side). */ - int i; - int n; - char errbuf[512]; - int *fdp; - int fdnul; - - if (atfork) - atfork (atforkvalue, 0); - - fdnul = open ("/dev/null", O_WRONLY); - if (fdnul == -1) - { - TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx, - "can't open `/dev/null': %s", strerror (errno)); - _exit (4); - } - - /* Dup handles to stdin/stdout. */ - if (fd_out != STDOUT_FILENO) - { - if (dup2 (fd_out == ASSUAN_INVALID_FD ? fdnul : fd_out, - STDOUT_FILENO) == -1) - { - TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx, - "dup2 failed in child: %s", strerror (errno)); - _exit (4); - } - } - - if (fd_in != STDIN_FILENO) - { - if (dup2 (fd_in == ASSUAN_INVALID_FD ? fdnul : fd_in, - STDIN_FILENO) == -1) - { - TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx, - "dup2 failed in child: %s", strerror (errno)); - _exit (4); - } - } - - /* Dup stderr to /dev/null unless it is in the list of FDs to be - passed to the child. */ - fdp = fd_child_list; - if (fdp) - { - for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++) - ; - } - if (!fdp || *fdp == -1) - { - if (dup2 (fdnul, STDERR_FILENO) == -1) - { - TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_unix", ctx, - "dup2(dev/null, 2) failed: %s", strerror (errno)); - _exit (4); - } - } - close (fdnul); - - /* Close all files which will not be duped and are not in the - fd_child_list. */ - n = sysconf (_SC_OPEN_MAX); - if (n < 0) - n = MAX_OPEN_FDS; - for (i = 0; i < n; i++) - { - if (i == STDIN_FILENO || i == STDOUT_FILENO || i == STDERR_FILENO) - continue; - fdp = fd_child_list; - if (fdp) - { - while (*fdp != -1 && *fdp != i) - fdp++; - } - - if (!(fdp && *fdp != -1)) - close (i); - } - gpg_err_set_errno (0); - - if (! name) - { - /* No name and no args given, thus we don't do an exec - but continue the forked process. */ - *argv = "server"; - - /* FIXME: Cleanup. */ - return 0; - } - - execv (name, (char *const *) argv); - - /* oops - use the pipe to tell the parent about it */ - snprintf (errbuf, sizeof(errbuf)-1, - "ERR %d can't exec `%s': %.50s\n", - _assuan_error (ctx, GPG_ERR_ASS_SERVER_START), - name, strerror (errno)); - errbuf[sizeof(errbuf)-1] = 0; - writen (1, errbuf, strlen (errbuf)); - _exit (4); - } - - if (! name) - *argv = "client"; - - *r_pid = pid; - - return 0; -} -#endif /* ! HAVE_W32_SYSTEM */ - + /* Create a new process from NAME and ARGV. Provide FD_IN and FD_OUT as stdin and stdout. Inherit the ASSUAN_INVALID_FD-terminated FD_CHILD_LIST as given (no remapping), which must be inheritable. @@ -924,26 +327,10 @@ _assuan_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name, return TRACE_SYSERR (res); } + /* FIXME: Add some sort of waitpid function that covers GPGME and gpg-agent's use of assuan. */ -static pid_t -__assuan_waitpid (assuan_context_t ctx, pid_t pid, int nowait, - int *status, int options) -{ -#ifndef HAVE_W32_SYSTEM - /* We can't just release the PID, a waitpid is mandatory. But - NOWAIT in POSIX systems just means the caller already did the - waitpid for this child. */ - if (! nowait) - return waitpid (pid, NULL, 0); -#else /* ! HAVE_W32_SYSTEM */ - CloseHandle ((HANDLE) pid); -#endif /* HAVE_W32_SYSTEM */ - return 0; -} - - pid_t _assuan_waitpid (assuan_context_t ctx, pid_t pid, int action, int *status, int options) @@ -960,19 +347,8 @@ _assuan_waitpid (assuan_context_t ctx, pid_t pid, int action, #endif } - -int -__assuan_socketpair (assuan_context_t ctx, int namespace, int style, - int protocol, assuan_fd_t filedes[2]) -{ -#if HAVE_W32_SYSTEM - gpg_err_set_errno (ENOSYS); - return -1; -#else - return socketpair (namespace, style, protocol, filedes); -#endif -} + int _assuan_socketpair (assuan_context_t ctx, int namespace, int style, int protocol, assuan_fd_t filedes[2]) @@ -989,19 +365,3 @@ _assuan_socketpair (assuan_context_t ctx, int namespace, int style, return TRACE_SYSERR (res); } - -/* The default system hooks for assuan contexts. */ -struct assuan_system_hooks _assuan_system_hooks = - { - ASSUAN_SYSTEM_HOOKS_VERSION, - __assuan_usleep, - __assuan_pipe, - __assuan_close, - __assuan_read, - __assuan_write, - __assuan_recvmsg, - __assuan_sendmsg, - __assuan_spawn, - __assuan_waitpid, - __assuan_socketpair - }; |