From 6f1c31fc6f4fa5e8f56b83b562ac1b732d79c282 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Mon, 10 Jun 2024 13:14:47 +0900 Subject: Cleanup for spawn use from libgpg-error. Signed-off-by: NIIBE Yutaka --- src/libassuan.def | 4 +- src/libassuan.vers | 4 +- src/system-posix.c | 256 ---------------------------------------------------- src/system-w32.c | 258 ----------------------------------------------------- src/system.c | 27 ------ 5 files changed, 4 insertions(+), 545 deletions(-) diff --git a/src/libassuan.def b/src/libassuan.def index 6f5452f..235d01b 100644 --- a/src/libassuan.def +++ b/src/libassuan.def @@ -91,7 +91,7 @@ EXPORTS __assuan_close @70 __assuan_pipe @71 __assuan_socketpair @72 - __assuan_spawn @73 +; __assuan_spawn @73 __assuan_usleep @74 assuan_fdopen @75 assuan_client_read_response @76 @@ -109,7 +109,7 @@ EXPORTS __assuan_write @88 __assuan_recvmsg @89 __assuan_sendmsg @90 - __assuan_waitpid @91 +; __assuan_waitpid @91 assuan_check_version @92 assuan_sock_set_sockaddr_un @93 assuan_sock_set_flag @94 diff --git a/src/libassuan.vers b/src/libassuan.vers index 209f43d..6839db2 100644 --- a/src/libassuan.vers +++ b/src/libassuan.vers @@ -113,7 +113,7 @@ LIBASSUAN_1.0 { __assuan_close; __assuan_pipe; __assuan_socketpair; - __assuan_spawn; +# __assuan_spawn; __assuan_usleep; __assuan_socket; __assuan_connect; @@ -121,7 +121,7 @@ LIBASSUAN_1.0 { __assuan_write; __assuan_recvmsg; __assuan_sendmsg; - __assuan_waitpid; +# __assuan_waitpid; local: *; diff --git a/src/system-posix.c b/src/system-posix.c index 3312523..780906d 100644 --- a/src/system-posix.c +++ b/src/system-posix.c @@ -152,262 +152,6 @@ __assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg, } - -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 */ -} - - -/* Return the maximum number of currently allowed open file - * descriptors. */ -static int -get_max_fds (void) -{ - int max_fds = -1; - -#ifdef HAVE_GETRLIMIT - struct rlimit rl; - - /* Under Linux we can figure out the highest used file descriptor by - * reading /proc/PID/fd. This is in the common cases much faster - * than for example doing 4096 close calls where almost all of them - * will fail. We use the same code in GnuPG and measured this: On a - * system with a limit of 4096 files and only 8 files open with the - * highest number being 10, we speedup close_all_fds from 125ms to - * 0.4ms including the readdir. - * - * Another option would be to close the file descriptors as returned - * from reading that directory - however then we need to snapshot - * that list before starting to close them. */ -#ifdef __linux__ - { - DIR *dir = NULL; - struct dirent *dir_entry; - const char *s; - int x; - - dir = opendir ("/proc/self/fd"); - if (dir) - { - while ((dir_entry = readdir (dir))) - { - s = dir_entry->d_name; - if ( *s < '0' || *s > '9') - continue; - x = atoi (s); - if (x > max_fds) - max_fds = x; - } - closedir (dir); - } - if (max_fds != -1) - return max_fds + 1; - } -#endif /* __linux__ */ - -# ifdef RLIMIT_NOFILE - if (!getrlimit (RLIMIT_NOFILE, &rl)) - max_fds = rl.rlim_max; -# endif - -# ifdef RLIMIT_OFILE - if (max_fds == -1 && !getrlimit (RLIMIT_OFILE, &rl)) - max_fds = rl.rlim_max; - -# endif -#endif /*HAVE_GETRLIMIT*/ - -#ifdef _SC_OPEN_MAX - if (max_fds == -1) - { - long int scres = sysconf (_SC_OPEN_MAX); - if (scres >= 0) - max_fds = scres; - } -#endif - -#ifdef _POSIX_OPEN_MAX - if (max_fds == -1) - max_fds = _POSIX_OPEN_MAX; -#endif - -#ifdef OPEN_MAX - if (max_fds == -1) - max_fds = OPEN_MAX; -#endif - - if (max_fds == -1) - max_fds = 256; /* Arbitrary limit. */ - - /* AIX returns INT32_MAX instead of a proper value. We assume that - this is always an error and use a more reasonable limit. */ -#ifdef INT32_MAX - if (max_fds == INT32_MAX) - max_fds = 256; -#endif - - return max_fds; -} - - -int -__assuan_spawn (assuan_context_t ctx, assuan_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 = get_max_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; -} - - - -/* FIXME: Add some sort of waitpid function that covers GPGME and - gpg-agent's use of assuan. */ -assuan_pid_t -__assuan_waitpid (assuan_context_t ctx, assuan_pid_t pid, int nowait, - int *status, int options) -{ - if (nowait) - return 0; - - /* 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. */ - return waitpid (pid, status, options ? WNOHANG : 0); -} - - int __assuan_socketpair (assuan_context_t ctx, int namespace, int style, diff --git a/src/system-w32.c b/src/system-w32.c index 1d06cd6..9248edf 100644 --- a/src/system-w32.c +++ b/src/system-w32.c @@ -63,33 +63,6 @@ __assuan_usleep (assuan_context_t ctx, unsigned int usec) } - -/* Three simple wrappers, only used because thes function are named in - the def file. */ -HANDLE -_assuan_w32ce_prepare_pipe (int *r_rvid, int write_end) -{ - (void)r_rvid; - (void)write_end; - return INVALID_HANDLE_VALUE; -} - -HANDLE -_assuan_w32ce_finish_pipe (int rvid, int write_end) -{ - (void)rvid; - (void)write_end; - return INVALID_HANDLE_VALUE; -} - -DWORD -_assuan_w32ce_create_pipe (HANDLE *read_hd, HANDLE *write_hd, - LPSECURITY_ATTRIBUTES sec_attr, DWORD size) -{ - return CreatePipe (read_hd, write_hd, sec_attr, size); -} - - /* Create a pipe with one inheritable end. Default implementation. */ int @@ -399,237 +372,6 @@ __assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg, gpg_err_set_errno (ENOSYS); return -1; } - - - - -/* 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, assuan_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. */ - }; - STARTUPINFOW si; - assuan_fd_t fd; - assuan_fd_t *fdp; - char *cmdline; - wchar_t *wcmdline = NULL; - wchar_t *wname = NULL; - HANDLE nullfd = INVALID_HANDLE_VALUE; - int rc; - - /* 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, change it, create process 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; - - /* 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. A fix for this would be to use a helper - process like we have in gpgme. - Take care: CreateProcessW may modify wpgmname */ - /* _assuan_log_printf ("CreateProcess, path=`%s' cmdline=`%s'\n", */ - /* name, cmdline); */ - if (name && !(wname = _assuan_utf8_to_wchar (name))) - rc = 0; - else if (!(wcmdline = _assuan_utf8_to_wchar (cmdline))) - rc = 0; - else - rc = CreateProcessW (wname, /* Program to start. */ - wcmdline, /* 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) - | GetPriorityClass (GetCurrentProcess ()) - | CREATE_SUSPENDED), /* Creation flags. */ - NULL, /* Environment. */ - NULL, /* Use current drive/directory. */ - &si, /* Startup information. */ - &pi /* Returns process information. */ - ); - if (!rc) - { - TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_w32", ctx, - "CreateProcess failed%s: %s", _assuan_w32_strerror (ctx, -1)); - free (wname); - free (wcmdline); - _assuan_free (ctx, cmdline); - if (nullfd != INVALID_HANDLE_VALUE) - CloseHandle (nullfd); - - gpg_err_set_errno (EIO); - return -1; - } - - free (wname); - free (wcmdline); - _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 = (assuan_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; -} - - - - -/* FIXME: Add some sort of waitpid function that covers GPGME and - gpg-agent's use of assuan. */ -assuan_pid_t -__assuan_waitpid (assuan_context_t ctx, assuan_pid_t pid, int nowait, - int *status, int options) -{ - int code; - DWORD exit_code; - - (void)ctx; - - if (nowait) - return 0; - - code = WaitForSingleObject ((HANDLE)pid, options? 0: INFINITE); - - if (code == WAIT_OBJECT_0) - { - if (status) - { - GetExitCodeProcess ((HANDLE)pid, &exit_code); - *status = (int)exit_code; - } - CloseHandle ((HANDLE)pid); - return pid; - } - else if (code == WAIT_TIMEOUT) - return 0; - else - return -1; -} - - int __assuan_socketpair (assuan_context_t ctx, int namespace, int style, diff --git a/src/system.c b/src/system.c index d687b1b..0862681 100644 --- a/src/system.c +++ b/src/system.c @@ -376,33 +376,6 @@ _assuan_spawn (assuan_context_t ctx, const char *name, const char **argv, return TRACE_SYSERR (res); } - - - -/* FIXME: Add some sort of waitpid function that covers GPGME and - gpg-agent's use of assuan. */ -assuan_pid_t -_assuan_waitpid (assuan_context_t ctx, assuan_pid_t pid, int action, - int *status, int options) -{ -#if DEBUG_SYSIO - assuan_pid_t res; - TRACE_BEG4 (ctx, ASSUAN_LOG_SYSIO, "_assuan_waitpid", ctx, - "pid=%i, action=%i, status=%p, options=%i", - pid, action, status, options); - _assuan_pre_syscall (); - res = __assuan_waitpid (ctx, pid, action, status, options); - _assuan_post_syscall (); -#else - assuan_pid_t res; - _assuan_pre_syscall (); - res = __assuan_waitpid (ctx, pid, action, status, options); - _assuan_post_syscall (); - return res; -#endif -} - - int _assuan_socketpair (assuan_context_t ctx, int namespace, int style, -- cgit v1.2.3