1 /* assuan-pipe-connect.c - Establish a pipe connection (client)
2 * Copyright (C) 2001, 2002, 2003, 2005, 2006,
3 * 2007 Free Software Foundation, Inc.
5 * This file is part of Assuan.
7 * Assuan is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
12 * Assuan is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
32 #include <sys/types.h>
33 #ifndef HAVE_W32_SYSTEM
39 #include "assuan-defs.h"
41 /* Hacks for Slowaris. */
44 # define PF_LOCAL PF_UNIX
46 # define PF_LOCAL AF_UNIX
50 # define AF_LOCAL AF_UNIX
54 #ifdef _POSIX_OPEN_MAX
55 #define MAX_OPEN_FDS _POSIX_OPEN_MAX
57 #define MAX_OPEN_FDS 20
61 /* This should be called to make sure that SIGPIPE gets ignored. */
65 #ifndef _ASSUAN_NO_FIXED_SIGNALS
66 #ifndef HAVE_DOSISH_SYSTEM /* No SIGPIPE for these systems. */
67 static int fixed_signals
;
73 sigaction (SIGPIPE
, NULL
, &act
);
74 if (act
.sa_handler
== SIG_DFL
)
76 act
.sa_handler
= SIG_IGN
;
77 sigemptyset (&act
.sa_mask
);
79 sigaction (SIGPIPE
, &act
, NULL
);
82 /* FIXME: This is not MT safe */
84 #endif /*HAVE_DOSISH_SYSTEM*/
85 #endif /*!_ASSUAN_NO_FIXED_SIGNALS*/
89 #ifndef HAVE_W32_SYSTEM
91 writen (int fd
, const char *buffer
, size_t length
)
95 int nwritten
= write (fd
, buffer
, length
);
101 return -1; /* write error */
111 do_finish (assuan_context_t ctx
)
113 if (ctx
->inbound
.fd
!= ASSUAN_INVALID_FD
)
115 _assuan_close (ctx
->inbound
.fd
);
116 if (ctx
->inbound
.fd
== ctx
->outbound
.fd
)
117 ctx
->outbound
.fd
= ASSUAN_INVALID_FD
;
118 ctx
->inbound
.fd
= ASSUAN_INVALID_FD
;
120 if (ctx
->outbound
.fd
!= ASSUAN_INVALID_FD
)
122 _assuan_close (ctx
->outbound
.fd
);
123 ctx
->outbound
.fd
= ASSUAN_INVALID_FD
;
125 if (ctx
->pid
!= (pid_t
)(-1) && ctx
->pid
)
127 #ifndef HAVE_W32_SYSTEM
128 #ifndef _ASSUAN_USE_DOUBLE_FORK
129 if (!ctx
->flags
.no_waitpid
)
130 _assuan_waitpid (ctx
->pid
, NULL
, 0);
131 ctx
->pid
=(pid_t
)(-1);
133 #else /*!HAVE_W32_SYSTEM*/
134 CloseHandle ((HANDLE
) ctx
->pid
);
135 ctx
->pid
= (pid_t
) INVALID_HANDLE_VALUE
;
136 #endif /*HAVE_W32_SYSTEM*/
143 do_deinit (assuan_context_t ctx
)
149 /* Helper for pipe_connect. */
150 static assuan_error_t
151 initial_handshake (assuan_context_t
*ctx
)
156 err
= _assuan_read_from_server (*ctx
, &okay
, &off
);
158 _assuan_log_printf ("can't connect server: %s\n",
159 assuan_strerror (err
));
162 _assuan_log_printf ("can't connect server: `%s'\n",
163 (*ctx
)->inbound
.line
);
164 err
= _assuan_error (ASSUAN_Connect_Failed
);
169 assuan_disconnect (*ctx
);
176 #ifndef HAVE_W32_SYSTEM
177 #define pipe_connect pipe_connect_unix
178 /* Unix version of the pipe connection code. We use an extra macro to
179 make ChangeLog entries easier. */
180 static assuan_error_t
181 pipe_connect_unix (assuan_context_t
*ctx
,
182 const char *name
, const char *const argv
[],
184 void (*atfork
) (void *opaque
, int reserved
),
185 void *atforkvalue
, unsigned int flags
)
194 if (!ctx
|| !name
|| !argv
|| !argv
[0])
195 return _assuan_error (ASSUAN_Invalid_Value
);
199 sprintf (mypidstr
, "%lu", (unsigned long)getpid ());
202 return _assuan_error (ASSUAN_General_Error
);
208 return _assuan_error (ASSUAN_General_Error
);
211 err
= _assuan_new_context (ctx
);
220 (*ctx
)->pipe_mode
= 1;
221 (*ctx
)->inbound
.fd
= rp
[0]; /* Our inbound is read end of read pipe. */
222 (*ctx
)->outbound
.fd
= wp
[1]; /* Our outbound is write end of write pipe. */
223 (*ctx
)->deinit_handler
= do_deinit
;
224 (*ctx
)->finish_handler
= do_finish
;
226 /* FIXME: For GPGME we should better use _gpgme_io_spawn. The PID
227 stored here is actually soon useless. */
228 (*ctx
)->pid
= fork ();
235 _assuan_release_context (*ctx
);
236 return _assuan_error (ASSUAN_General_Error
);
239 if ((*ctx
)->pid
== 0)
241 #ifdef _ASSUAN_USE_DOUBLE_FORK
244 if ((pid
= fork ()) == 0)
252 atfork (atforkvalue
, 0);
254 /* Dup handles to stdin/stdout. */
255 if (rp
[1] != STDOUT_FILENO
)
257 if (dup2 (rp
[1], STDOUT_FILENO
) == -1)
259 _assuan_log_printf ("dup2 failed in child: %s\n",
264 if (wp
[0] != STDIN_FILENO
)
266 if (dup2 (wp
[0], STDIN_FILENO
) == -1)
268 _assuan_log_printf ("dup2 failed in child: %s\n",
274 /* Dup stderr to /dev/null unless it is in the list of FDs to be
275 passed to the child. */
279 for (; *fdp
!= -1 && *fdp
!= STDERR_FILENO
; fdp
++)
282 if (!fdp
|| *fdp
== -1)
284 int fd
= open ("/dev/null", O_WRONLY
);
287 _assuan_log_printf ("can't open `/dev/null': %s\n",
291 if (dup2 (fd
, STDERR_FILENO
) == -1)
293 _assuan_log_printf ("dup2(dev/null, 2) failed: %s\n",
300 /* Close all files which will not be duped and are not in the
302 n
= sysconf (_SC_OPEN_MAX
);
305 for (i
=0; i
< n
; i
++)
307 if ( i
== STDIN_FILENO
|| i
== STDOUT_FILENO
308 || i
== STDERR_FILENO
)
313 while (*fdp
!= -1 && *fdp
!= i
)
317 if (!(fdp
&& *fdp
!= -1))
322 /* We store our parents pid in the environment so that the
323 execed assuan server is able to read the actual pid of the
324 client. The server can't use getppid because it might have
325 been double forked before the assuan server has been
327 setenv ("_assuan_pipe_connect_pid", mypidstr
, 1);
329 /* Make sure that we never pass a connection fd variable
330 when using a simple pipe. */
331 unsetenv ("_assuan_connection_fd");
333 execv (name
, (char *const *) argv
);
334 /* oops - use the pipe to tell the parent about it */
335 snprintf (errbuf
, sizeof(errbuf
)-1,
336 "ERR %d can't exec `%s': %.50s\n",
337 _assuan_error (ASSUAN_Problem_Starting_Server
),
338 name
, strerror (errno
));
339 errbuf
[sizeof(errbuf
)-1] = 0;
340 writen (1, errbuf
, strlen (errbuf
));
343 #ifdef _ASSUAN_USE_DOUBLE_FORK
351 #ifdef _ASSUAN_USE_DOUBLE_FORK
352 _assuan_waitpid ((*ctx
)->pid
, NULL
, 0);
359 return initial_handshake (ctx
);
361 #endif /*!HAVE_W32_SYSTEM*/
364 #ifndef HAVE_W32_SYSTEM
365 /* This function is similar to pipe_connect but uses a socketpair and
366 sets the I/O up to use sendmsg/recvmsg. */
367 static assuan_error_t
368 socketpair_connect (assuan_context_t
*ctx
,
369 const char *name
, const char *const argv
[],
371 void (*atfork
) (void *opaque
, int reserved
),
379 || (name
&& (!argv
|| !argv
[0]))
381 return _assuan_error (ASSUAN_Invalid_Value
);
385 sprintf (mypidstr
, "%lu", (unsigned long)getpid ());
387 if ( socketpair (AF_LOCAL
, SOCK_STREAM
, 0, fds
) )
389 _assuan_log_printf ("socketpair failed: %s\n", strerror (errno
));
390 return _assuan_error (ASSUAN_General_Error
);
393 err
= _assuan_new_context (ctx
);
400 (*ctx
)->pipe_mode
= 1;
401 (*ctx
)->inbound
.fd
= fds
[0];
402 (*ctx
)->outbound
.fd
= fds
[0];
403 _assuan_init_uds_io (*ctx
);
404 (*ctx
)->deinit_handler
= _assuan_uds_deinit
;
405 (*ctx
)->finish_handler
= do_finish
;
407 (*ctx
)->pid
= fork ();
412 _assuan_release_context (*ctx
);
414 return _assuan_error (ASSUAN_General_Error
);
417 if ((*ctx
)->pid
== 0)
419 #ifdef _ASSUAN_USE_DOUBLE_FORK
422 if ((pid
= fork ()) == 0)
430 atfork (atforkvalue
, 0);
432 /* Connect stdin and stdout to /dev/null. */
433 fd
= open ("/dev/null", O_RDONLY
);
434 if (fd
== -1 || dup2 (fd
, STDIN_FILENO
) == -1)
436 _assuan_log_printf ("dup2(dev/null) failed: %s\n",
440 fd
= open ("/dev/null", O_WRONLY
);
441 if (fd
== -1 || dup2 (fd
, STDOUT_FILENO
) == -1)
443 _assuan_log_printf ("dup2(dev/null) failed: %s\n",
448 /* Dup stderr to /dev/null unless it is in the list of FDs to be
449 passed to the child. */
453 for (; *fdp
!= -1 && *fdp
!= STDERR_FILENO
; fdp
++)
456 if (!fdp
|| *fdp
== -1)
458 fd
= open ("/dev/null", O_WRONLY
);
459 if (fd
== -1 || dup2 (fd
, STDERR_FILENO
) == -1)
461 _assuan_log_printf ("dup2(dev/null) failed: %s\n",
468 /* Close all files which will not be duped, are not in the
469 fd_child_list and are not the connection fd. */
470 n
= sysconf (_SC_OPEN_MAX
);
473 for (i
=0; i
< n
; i
++)
475 if ( i
== STDIN_FILENO
|| i
== STDOUT_FILENO
476 || i
== STDERR_FILENO
|| i
== fds
[1])
481 while (*fdp
!= -1 && *fdp
!= i
)
485 if (!(fdp
&& *fdp
!= -1))
490 /* We store our parents pid in the environment so that the
491 execed assuan server is able to read the actual pid of the
492 client. The server can't use getppid becuase it might have
493 been double forked before the assuan server has been
495 setenv ("_assuan_pipe_connect_pid", mypidstr
, 1);
497 /* Now set the environment variable used to convey the
498 connection's file descriptor. */
499 sprintf (mypidstr
, "%d", fds
[1]);
500 if (setenv ("_assuan_connection_fd", mypidstr
, 1))
502 _assuan_log_printf ("setenv failed: %s\n", strerror (errno
));
508 /* No name and no args given, thus we don't do an exec
509 but continue the forked process. */
510 _assuan_release_context (*ctx
);
515 execv (name
, (char *const *) argv
);
516 /* oops - use the pipe to tell the parent about it */
517 snprintf (errbuf
, sizeof(errbuf
)-1,
518 "ERR %d can't exec `%s': %.50s\n",
519 _assuan_error (ASSUAN_Problem_Starting_Server
),
520 name
, strerror (errno
));
521 errbuf
[sizeof(errbuf
)-1] = 0;
522 writen (fds
[1], errbuf
, strlen (errbuf
));
525 #ifdef _ASSUAN_USE_DOUBLE_FORK
534 #ifdef _ASSUAN_USE_DOUBLE_FORK
535 _assuan_waitpid ((*ctx
)->pid
, NULL
, 0);
541 return initial_handshake (ctx
);
543 #endif /*!HAVE_W32_SYSTEM*/
547 #ifdef HAVE_W32_SYSTEM
548 /* Build a command line for use with W32's CreateProcess. On success
549 CMDLINE gets the address of a newly allocated string. */
551 build_w32_commandline (const char * const *argv
, char **cmdline
)
559 for (i
=0; (s
=argv
[i
]); i
++)
561 n
+= strlen (s
) + 1 + 2; /* (1 space, 2 quoting */
564 n
++; /* Need to double inner quotes. */
568 buf
= p
= xtrymalloc (n
);
572 for (i
=0; argv
[i
]; i
++)
576 if (!*argv
[i
]) /* Empty string. */
577 p
= stpcpy (p
, "\"\"");
578 else if (strpbrk (argv
[i
], " \t\n\v\f\""))
580 p
= stpcpy (p
, "\"");
581 for (s
=argv
[i
]; *s
; s
++)
591 p
= stpcpy (p
, argv
[i
]);
597 #endif /*HAVE_W32_SYSTEM*/
600 #ifdef HAVE_W32_SYSTEM
601 /* Create pipe where one end end is inheritable. */
603 create_inheritable_pipe (assuan_fd_t filedes
[2], int for_write
)
606 SECURITY_ATTRIBUTES sec_attr
;
608 memset (&sec_attr
, 0, sizeof sec_attr
);
609 sec_attr
.nLength
= sizeof sec_attr
;
610 sec_attr
.bInheritHandle
= FALSE
;
612 if (!CreatePipe (&r
, &w
, &sec_attr
, 0))
614 _assuan_log_printf ("CreatePipe failed: %s\n", w32_strerror (-1));
618 if (!DuplicateHandle (GetCurrentProcess(), for_write
? r
: w
,
619 GetCurrentProcess(), &h
, 0,
620 TRUE
, DUPLICATE_SAME_ACCESS
))
622 _assuan_log_printf ("DuplicateHandle failed: %s\n", w32_strerror (-1));
642 #endif /*HAVE_W32_SYSTEM*/
645 #ifdef HAVE_W32_SYSTEM
646 #define pipe_connect pipe_connect_w32
647 /* W32 version of the pipe connection code. */
648 static assuan_error_t
649 pipe_connect_w32 (assuan_context_t
*ctx
,
650 const char *name
, const char *const argv
[],
652 void (*atfork
) (void *opaque
, int reserved
),
653 void *atforkvalue
, unsigned int flags
)
660 SECURITY_ATTRIBUTES sec_attr
;
661 PROCESS_INFORMATION pi
=
663 NULL
, /* Returns process handle. */
664 0, /* Returns primary thread handle. */
665 0, /* Returns pid. */
670 HANDLE nullfd
= INVALID_HANDLE_VALUE
;
672 if (!ctx
|| !name
|| !argv
|| !argv
[0])
673 return _assuan_error (ASSUAN_Invalid_Value
);
677 sprintf (mypidstr
, "%lu", (unsigned long)getpid ());
679 /* Build the command line. */
680 if (build_w32_commandline (argv
, &cmdline
))
681 return _assuan_error (ASSUAN_Out_Of_Core
);
683 /* Create thew two pipes. */
684 if (create_inheritable_pipe (rp
, 0))
687 return _assuan_error (ASSUAN_General_Error
);
690 if (create_inheritable_pipe (wp
, 1))
695 return _assuan_error (ASSUAN_General_Error
);
699 err
= _assuan_new_context (ctx
);
707 return _assuan_error (ASSUAN_General_Error
);
710 (*ctx
)->pipe_mode
= 1;
711 (*ctx
)->inbound
.fd
= rp
[0]; /* Our inbound is read end of read pipe. */
712 (*ctx
)->outbound
.fd
= wp
[1]; /* Our outbound is write end of write pipe. */
713 (*ctx
)->deinit_handler
= do_deinit
;
714 (*ctx
)->finish_handler
= do_finish
;
717 /* fixme: Actually we should set the "_assuan_pipe_connect_pid" env
718 variable. However this requires us to write a full environment
719 handler, because the strings are expected in sorted order. The
720 suggestion given in the MS Reference Library, to save the old
721 value, changeit, create proces and restore it, is not thread
724 /* Start the process. */
725 memset (&sec_attr
, 0, sizeof sec_attr
);
726 sec_attr
.nLength
= sizeof sec_attr
;
727 sec_attr
.bInheritHandle
= FALSE
;
729 memset (&si
, 0, sizeof si
);
731 si
.dwFlags
= STARTF_USESTDHANDLES
;
732 si
.hStdInput
= wp
[0];
733 si
.hStdOutput
= rp
[1];
735 /* Dup stderr to /dev/null unless it is in the list of FDs to be
736 passed to the child. */
737 fd
= fileno (stderr
);
741 for (; *fdp
!= -1 && *fdp
!= fd
; fdp
++)
744 if (!fdp
|| *fdp
== -1)
746 nullfd
= CreateFile ("nul", GENERIC_WRITE
,
747 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
748 NULL
, OPEN_EXISTING
, 0, NULL
);
749 if (nullfd
== INVALID_HANDLE_VALUE
)
751 _assuan_log_printf ("can't open `nul': %s\n", w32_strerror (-1));
757 _assuan_release_context (*ctx
);
760 si
.hStdError
= nullfd
;
763 si
.hStdError
= (void*)_get_osfhandle (fd
);
766 /* Note: We inherit all handles flagged as inheritable. This seems
767 to be a security flaw but there seems to be no way of selecting
768 handles to inherit. */
769 /* _assuan_log_printf ("CreateProcess, path=`%s' cmdline=`%s'\n", */
770 /* name, cmdline); */
771 if (!CreateProcess (name
, /* Program to start. */
772 cmdline
, /* Command line arguments. */
773 &sec_attr
, /* Process security attributes. */
774 &sec_attr
, /* Thread security attributes. */
775 TRUE
, /* Inherit handles. */
776 (CREATE_DEFAULT_ERROR_MODE
777 | ((flags
& 128)? DETACHED_PROCESS
: 0)
778 | GetPriorityClass (GetCurrentProcess ())
779 | CREATE_SUSPENDED
), /* Creation flags. */
780 NULL
, /* Environment. */
781 NULL
, /* Use current drive/directory. */
782 &si
, /* Startup information. */
783 &pi
/* Returns process information. */
786 _assuan_log_printf ("CreateProcess failed: %s\n", w32_strerror (-1));
791 if (nullfd
!= INVALID_HANDLE_VALUE
)
792 CloseHandle (nullfd
);
794 _assuan_release_context (*ctx
);
795 return _assuan_error (ASSUAN_General_Error
);
799 if (nullfd
!= INVALID_HANDLE_VALUE
)
801 CloseHandle (nullfd
);
802 nullfd
= INVALID_HANDLE_VALUE
;
808 /* _assuan_log_printf ("CreateProcess ready: hProcess=%p hThread=%p" */
809 /* " dwProcessID=%d dwThreadId=%d\n", */
810 /* pi.hProcess, pi.hThread, */
811 /* (int) pi.dwProcessId, (int) pi.dwThreadId); */
813 ResumeThread (pi
.hThread
);
814 CloseHandle (pi
.hThread
);
815 (*ctx
)->pid
= (pid_t
) pi
.hProcess
;
817 return initial_handshake (ctx
);
819 #endif /*HAVE_W32_SYSTEM*/
822 /* Connect to a server over a pipe, creating the assuan context and
823 returning it in CTX. The server filename is NAME, the argument
824 vector in ARGV. FD_CHILD_LIST is a -1 terminated list of file
825 descriptors not to close in the child. */
827 assuan_pipe_connect (assuan_context_t
*ctx
, const char *name
,
828 const char *const argv
[], int *fd_child_list
)
830 return pipe_connect (ctx
, name
, argv
, fd_child_list
, NULL
, NULL
, 0);
836 assuan_pipe_connect2 (assuan_context_t
*ctx
,
837 const char *name
, const char *const argv
[],
839 void (*atfork
) (void *opaque
, int reserved
),
842 return pipe_connect (ctx
, name
, argv
, fd_child_list
, atfork
, atforkvalue
, 0);
846 /* Connect to a server over a full-duplex socket (i.e. created by
847 socketpair), creating the assuan context and returning it in CTX.
848 The server filename is NAME, the argument vector in ARGV.
849 FD_CHILD_LIST is a -1 terminated list of file descriptors not to
850 close in the child. ATFORK is called in the child right after the
851 fork; ATFORKVALUE is passed as the first argument and 0 is passed
852 as the second argument. The ATFORK function should only act if the
855 FLAGS is a bit vector and controls how the function acts:
856 Bit 0: If cleared a simple pipe based server is expected and the
857 function behaves similar to `assuan_pipe_connect'.
859 If set a server based on full-duplex pipes is expected. Such
860 pipes are usually created using the `socketpair' function.
861 It also enables features only available with such servers.
863 Bit 7: If set and there is a need to start ther server it will be
864 started as a background process. This flag is useful under
865 W32 systems, so that no new console is created and pops up a
866 console window when starting the server
869 If NAME as well as ARGV are NULL, no exec is done but the same
870 process is continued. However all file descriptors are closed and
871 some special environment variables are set. To let the caller
872 detect whether the child or the parent continues, the child returns
875 assuan_pipe_connect_ext (assuan_context_t
*ctx
,
876 const char *name
, const char *const argv
[],
878 void (*atfork
) (void *opaque
, int reserved
),
879 void *atforkvalue
, unsigned int flags
)
883 #ifdef HAVE_W32_SYSTEM
884 return _assuan_error (ASSUAN_Not_Implemented
);
886 return socketpair_connect (ctx
, name
, argv
, fd_child_list
,
887 atfork
, atforkvalue
);
891 return pipe_connect (ctx
, name
, argv
, fd_child_list
, atfork
, atforkvalue
,