2007-07-04 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / assuan / assuan-pipe-connect.c
1 /* assuan-pipe-connect.c - Establish a pipe connection (client) 
2  * Copyright (C) 2001, 2002, 2003, 2005, 2006 Free Software Foundation, Inc.
3  *
4  * This file is part of Assuan.
5  *
6  * Assuan is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * Assuan is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19  * USA. 
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <signal.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <sys/types.h>
34 #ifndef HAVE_W32_SYSTEM
35 #include <sys/wait.h>
36 #else
37 #include <windows.h>
38 #endif
39
40 #include "assuan-defs.h"
41
42 /* Hacks for Slowaris.  */
43 #ifndef PF_LOCAL
44 # ifdef PF_UNIX
45 #  define PF_LOCAL PF_UNIX
46 # else
47 #  define PF_LOCAL AF_UNIX
48 # endif
49 #endif
50 #ifndef AF_LOCAL
51 # define AF_LOCAL AF_UNIX
52 #endif
53
54
55 #ifdef _POSIX_OPEN_MAX
56 #define MAX_OPEN_FDS _POSIX_OPEN_MAX
57 #else
58 #define MAX_OPEN_FDS 20
59 #endif
60
61 #ifdef HAVE_W32_SYSTEM
62 /* We assume that a HANDLE can be represented by an int which should
63    be true for all i386 systems (HANDLE is defined as void *) and
64    these are the only systems for which Windows is available.  Further
65    we assume that -1 denotes an invalid handle.  */
66 #define fd_to_handle(a)  ((HANDLE)(a))
67 #define handle_to_fd(a)  ((int)(a))
68 #define pid_to_handle(a) ((HANDLE)(a))
69 #define handle_to_pid(a) ((int)(a))
70 #endif /*HAVE_W32_SYSTEM*/
71
72
73 /* This should be called to make sure that SIGPIPE gets ignored.  */
74 static void
75 fix_signals (void)
76 {
77 #ifndef _ASSUAN_NO_FIXED_SIGNALS
78 #ifndef HAVE_DOSISH_SYSTEM  /* No SIGPIPE for these systems.  */
79   static int fixed_signals;
80
81   if (!fixed_signals)
82     { 
83       struct sigaction act;
84         
85       sigaction (SIGPIPE, NULL, &act);
86       if (act.sa_handler == SIG_DFL)
87         {
88           act.sa_handler = SIG_IGN;
89           sigemptyset (&act.sa_mask);
90           act.sa_flags = 0;
91           sigaction (SIGPIPE, &act, NULL);
92         }
93       fixed_signals = 1;
94       /* FIXME: This is not MT safe */
95     }
96 #endif /*HAVE_DOSISH_SYSTEM*/
97 #endif /*!_ASSUAN_NO_FIXED_SIGNALS*/
98 }
99
100
101 #ifndef HAVE_W32_SYSTEM
102 static int
103 writen (int fd, const char *buffer, size_t length)
104 {
105   while (length)
106     {
107       int nwritten = write (fd, buffer, length);
108       
109       if (nwritten < 0)
110         {
111           if (errno == EINTR)
112             continue;
113           return -1; /* write error */
114         }
115       length -= nwritten;
116       buffer += nwritten;
117     }
118   return 0;  /* okay */
119 }
120 #endif
121
122 static int
123 do_finish (assuan_context_t ctx)
124 {
125   if (ctx->inbound.fd != -1)
126     {
127       _assuan_close (ctx->inbound.fd);
128       if (ctx->inbound.fd == ctx->outbound.fd)
129         ctx->outbound.fd = -1;
130       ctx->inbound.fd = -1;
131     }
132   if (ctx->outbound.fd != -1)
133     {
134       _assuan_close (ctx->outbound.fd);
135       ctx->outbound.fd = -1;
136     }
137   if (ctx->pid != -1 && ctx->pid)
138     {
139 #ifndef HAVE_W32_SYSTEM
140 #ifndef _ASSUAN_USE_DOUBLE_FORK
141       if (!ctx->flags.no_waitpid)
142         _assuan_waitpid (ctx->pid, NULL, 0); 
143       ctx->pid = -1;
144 #endif
145 #endif /*!HAVE_W32_SYSTEM*/
146     }
147   return 0;
148 }
149
150 static void
151 do_deinit (assuan_context_t ctx)
152 {
153   do_finish (ctx);
154 }
155
156
157 /* Helper for pipe_connect. */
158 static assuan_error_t
159 initial_handshake (assuan_context_t *ctx)
160 {
161   int okay, off;
162   assuan_error_t err;
163   
164   err = _assuan_read_from_server (*ctx, &okay, &off);
165   if (err)
166     _assuan_log_printf ("can't connect server: %s\n",
167                         assuan_strerror (err));
168   else if (okay != 1)
169     {
170       _assuan_log_printf ("can't connect server: `%s'\n",
171                           (*ctx)->inbound.line);
172       err = _assuan_error (ASSUAN_Connect_Failed);
173     }
174
175   if (err)
176     {
177       assuan_disconnect (*ctx);
178       *ctx = NULL;
179     }
180   return err;
181 }
182
183
184 #ifndef HAVE_W32_SYSTEM
185 #define pipe_connect pipe_connect_unix
186 /* Unix version of the pipe connection code.  We use an extra macro to
187    make ChangeLog entries easier. */
188 static assuan_error_t
189 pipe_connect_unix (assuan_context_t *ctx,
190                    const char *name, const char *const argv[],
191                    int *fd_child_list,
192                    void (*atfork) (void *opaque, int reserved),
193                    void *atforkvalue)
194 {
195   assuan_error_t err;
196   int rp[2];
197   int wp[2];
198   char mypidstr[50];
199
200   if (!ctx || !name || !argv || !argv[0])
201     return _assuan_error (ASSUAN_Invalid_Value);
202
203   fix_signals ();
204
205   sprintf (mypidstr, "%lu", (unsigned long)getpid ());
206
207   if (pipe (rp) < 0)
208     return _assuan_error (ASSUAN_General_Error);
209   
210   if (pipe (wp) < 0)
211     {
212       close (rp[0]);
213       close (rp[1]);
214       return _assuan_error (ASSUAN_General_Error);
215     }
216
217   err = _assuan_new_context (ctx);
218   if (err)
219     {
220       close (rp[0]);
221       close (rp[1]);
222       close (wp[0]);
223       close (wp[1]);
224       return err;
225     }
226   (*ctx)->pipe_mode = 1;
227   (*ctx)->inbound.fd  = rp[0];  /* Our inbound is read end of read pipe. */
228   (*ctx)->outbound.fd = wp[1];  /* Our outbound is write end of write pipe. */
229   (*ctx)->deinit_handler = do_deinit;
230   (*ctx)->finish_handler = do_finish;
231
232   /* FIXME: For GPGME we should better use _gpgme_io_spawn.  The PID
233      stored here is actually soon useless.  */
234   (*ctx)->pid = fork ();
235   if ((*ctx)->pid < 0)
236     {
237       close (rp[0]);
238       close (rp[1]);
239       close (wp[0]);
240       close (wp[1]);
241       _assuan_release_context (*ctx); 
242       return _assuan_error (ASSUAN_General_Error);
243     }
244
245   if ((*ctx)->pid == 0)
246     {
247 #ifdef _ASSUAN_USE_DOUBLE_FORK      
248       pid_t pid;
249
250       if ((pid = fork ()) == 0)
251 #endif
252         {
253           int i, n;
254           char errbuf[512];
255           int *fdp;
256           
257           if (atfork)
258             atfork (atforkvalue, 0);
259
260           /* Dup handles to stdin/stdout. */
261           if (rp[1] != STDOUT_FILENO)
262             {
263               if (dup2 (rp[1], STDOUT_FILENO) == -1)
264                 {
265                   _assuan_log_printf ("dup2 failed in child: %s\n",
266                                       strerror (errno));
267                   _exit (4);
268                 }
269             }
270           if (wp[0] != STDIN_FILENO)
271             {
272               if (dup2 (wp[0], STDIN_FILENO) == -1)
273                 {
274                   _assuan_log_printf ("dup2 failed in child: %s\n",
275                                       strerror (errno));
276                   _exit (4);
277                 }
278             }
279
280           /* Dup stderr to /dev/null unless it is in the list of FDs to be
281              passed to the child. */
282           fdp = fd_child_list;
283           if (fdp)
284             {
285               for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++)
286                 ;
287             }
288           if (!fdp || *fdp == -1)
289             {
290               int fd = open ("/dev/null", O_WRONLY);
291               if (fd == -1)
292                 {
293                   _assuan_log_printf ("can't open `/dev/null': %s\n",
294                                       strerror (errno));
295                   _exit (4);
296                 }
297               if (dup2 (fd, STDERR_FILENO) == -1)
298                 {
299                   _assuan_log_printf ("dup2(dev/null, 2) failed: %s\n",
300                                       strerror (errno));
301                   _exit (4);
302                 }
303             }
304
305
306           /* Close all files which will not be duped and are not in the
307              fd_child_list. */
308           n = sysconf (_SC_OPEN_MAX);
309           if (n < 0)
310             n = MAX_OPEN_FDS;
311           for (i=0; i < n; i++)
312             {
313               if ( i == STDIN_FILENO || i == STDOUT_FILENO
314                    || i == STDERR_FILENO)
315                 continue;
316               fdp = fd_child_list;
317               if (fdp)
318                 {
319                   while (*fdp != -1 && *fdp != i)
320                     fdp++;
321                 }
322
323               if (!(fdp && *fdp != -1))
324                 close(i);
325             }
326           errno = 0;
327
328           /* We store our parents pid in the environment so that the
329              execed assuan server is able to read the actual pid of the
330              client.  The server can't use getppid because it might have
331              been double forked before the assuan server has been
332              initialized. */
333           setenv ("_assuan_pipe_connect_pid", mypidstr, 1);
334
335           /* Make sure that we never pass a connection fd variable
336              when using a simple pipe.  */
337           unsetenv ("_assuan_connection_fd");
338
339           execv (name, (char *const *) argv); 
340           /* oops - use the pipe to tell the parent about it */
341           snprintf (errbuf, sizeof(errbuf)-1,
342                     "ERR %d can't exec `%s': %.50s\n",
343                     _assuan_error (ASSUAN_Problem_Starting_Server),
344                     name, strerror (errno));
345           errbuf[sizeof(errbuf)-1] = 0;
346           writen (1, errbuf, strlen (errbuf));
347           _exit (4);
348         }
349 #ifdef _ASSUAN_USE_DOUBLE_FORK
350       if (pid == -1)
351         _exit (1);
352       else
353         _exit (0);
354 #endif
355     }
356
357 #ifdef _ASSUAN_USE_DOUBLE_FORK
358   _assuan_waitpid ((*ctx)->pid, NULL, 0);
359   (*ctx)->pid = -1;
360 #endif
361
362   close (rp[1]);
363   close (wp[0]);
364
365   return initial_handshake (ctx);
366 }
367 #endif /*!HAVE_W32_SYSTEM*/
368
369
370 #ifndef HAVE_W32_SYSTEM
371 /* This function is similar to pipe_connect but uses a socketpair and
372    sets the I/O up to use sendmsg/recvmsg. */
373 static assuan_error_t
374 socketpair_connect (assuan_context_t *ctx,
375                     const char *name, const char *const argv[],
376                     int *fd_child_list,
377                     void (*atfork) (void *opaque, int reserved),
378                     void *atforkvalue)
379 {
380   assuan_error_t err;
381   int fds[2];
382   char mypidstr[50];
383
384   if (!ctx
385       || (name && (!argv || !argv[0]))
386       || (!name && argv))
387     return _assuan_error (ASSUAN_Invalid_Value);
388
389   fix_signals ();
390
391   sprintf (mypidstr, "%lu", (unsigned long)getpid ());
392
393   if ( socketpair (AF_LOCAL, SOCK_STREAM, 0, fds) )
394     {
395       _assuan_log_printf ("socketpair failed: %s\n", strerror (errno));
396       return _assuan_error (ASSUAN_General_Error);
397     }
398   
399   err = _assuan_new_context (ctx);
400   if (err)
401     {
402       close (fds[0]);
403       close (fds[1]);
404       return err;
405     }
406   (*ctx)->pipe_mode = 1;
407   (*ctx)->inbound.fd  = fds[0]; 
408   (*ctx)->outbound.fd = fds[0]; 
409   _assuan_init_uds_io (*ctx);
410   (*ctx)->deinit_handler = _assuan_uds_deinit;
411   (*ctx)->finish_handler = do_finish;
412
413   (*ctx)->pid = fork ();
414   if ((*ctx)->pid < 0)
415     {
416       close (fds[0]);
417       close (fds[1]);
418       _assuan_release_context (*ctx); 
419       *ctx = NULL;
420       return _assuan_error (ASSUAN_General_Error);
421     }
422
423   if ((*ctx)->pid == 0)
424     {
425 #ifdef _ASSUAN_USE_DOUBLE_FORK      
426       pid_t pid;
427
428       if ((pid = fork ()) == 0)
429 #endif
430         {
431           int fd, i, n;
432           char errbuf[512];
433           int *fdp;
434           
435           if (atfork)
436             atfork (atforkvalue, 0);
437
438           /* Connect stdin and stdout to /dev/null. */
439           fd = open ("/dev/null", O_RDONLY);
440           if (fd == -1 || dup2 (fd, STDIN_FILENO) == -1)
441             {
442               _assuan_log_printf ("dup2(dev/null) failed: %s\n",
443                                   strerror (errno));
444               _exit (4);
445             }
446           fd = open ("/dev/null", O_WRONLY);
447           if (fd == -1 || dup2 (fd, STDOUT_FILENO) == -1)
448             {
449               _assuan_log_printf ("dup2(dev/null) failed: %s\n",
450                                   strerror (errno));
451               _exit (4);
452             }
453
454           /* Dup stderr to /dev/null unless it is in the list of FDs to be
455              passed to the child. */
456           fdp = fd_child_list;
457           if (fdp)
458             {
459               for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++)
460                 ;
461             }
462           if (!fdp || *fdp == -1)
463             {
464               fd = open ("/dev/null", O_WRONLY);
465               if (fd == -1 || dup2 (fd, STDERR_FILENO) == -1)
466                 {
467                   _assuan_log_printf ("dup2(dev/null) failed: %s\n",
468                                       strerror (errno));
469                   _exit (4);
470                 }
471             }
472
473
474           /* Close all files which will not be duped, are not in the
475              fd_child_list and are not the connection fd. */
476           n = sysconf (_SC_OPEN_MAX);
477           if (n < 0)
478             n = MAX_OPEN_FDS;
479           for (i=0; i < n; i++)
480             {
481               if ( i == STDIN_FILENO || i == STDOUT_FILENO
482                    || i == STDERR_FILENO || i == fds[1])
483                 continue;
484               fdp = fd_child_list;
485               if (fdp)
486                 {
487                   while (*fdp != -1 && *fdp != i)
488                     fdp++;
489                 }
490
491               if (!(fdp && *fdp != -1))
492                 close(i);
493             }
494           errno = 0;
495
496           /* We store our parents pid in the environment so that the
497              execed assuan server is able to read the actual pid of the
498              client.  The server can't use getppid becuase it might have
499              been double forked before the assuan server has been
500              initialized. */
501           setenv ("_assuan_pipe_connect_pid", mypidstr, 1);
502
503           /* Now set the environment variable used to convey the
504              connection's file descriptor. */
505           sprintf (mypidstr, "%d", fds[1]);
506           if (setenv ("_assuan_connection_fd", mypidstr, 1))
507             {
508               _assuan_log_printf ("setenv failed: %s\n", strerror (errno));
509               _exit (4);
510             }
511
512           if (!name && !argv)
513             {
514               /* No name and no args given, thus we don't do an exec
515                  but continue the forked process.  */
516               _assuan_release_context (*ctx);
517               *ctx = NULL;
518               return 0;
519             }
520
521           execv (name, (char *const *) argv); 
522           /* oops - use the pipe to tell the parent about it */
523           snprintf (errbuf, sizeof(errbuf)-1,
524                     "ERR %d can't exec `%s': %.50s\n",
525                     _assuan_error (ASSUAN_Problem_Starting_Server),
526                     name, strerror (errno));
527           errbuf[sizeof(errbuf)-1] = 0;
528           writen (fds[1], errbuf, strlen (errbuf));
529           _exit (4);
530         }
531 #ifdef _ASSUAN_USE_DOUBLE_FORK
532       if (pid == -1)
533         _exit (1);
534       else
535         _exit (0);
536 #endif
537     }
538
539
540 #ifdef _ASSUAN_USE_DOUBLE_FORK
541   _assuan_waitpid ((*ctx)->pid, NULL, 0);
542   (*ctx)->pid = -1;
543 #endif
544
545   close (fds[1]);
546   
547   return initial_handshake (ctx);
548 }
549 #endif /*!HAVE_W32_SYSTEM*/
550
551
552
553 #ifdef HAVE_W32_SYSTEM
554 /* Build a command line for use with W32's CreateProcess.  On success
555    CMDLINE gets the address of a newly allocated string.  */
556 static int
557 build_w32_commandline (const char * const *argv, char **cmdline)
558 {
559   int i, n;
560   const char *s;
561   char *buf, *p;
562
563   *cmdline = NULL;
564   n = 0;
565   for (i=0; (s=argv[i]); i++)
566     {
567       n += strlen (s) + 1 + 2;  /* (1 space, 2 quoting */
568       for (; *s; s++)
569         if (*s == '\"')
570           n++;  /* Need to double inner quotes.  */
571     }
572   n++;
573
574   buf = p = xtrymalloc (n);
575   if (!buf)
576     return -1;
577
578   for (i=0; argv[i]; i++) 
579     {
580       if (i)
581         p = stpcpy (p, " ");
582       if (!*argv[i]) /* Empty string. */
583         p = stpcpy (p, "\"\"");
584       else if (strpbrk (argv[i], " \t\n\v\f\""))
585         {
586           p = stpcpy (p, "\"");
587           for (s=argv[i]; *s; s++)
588             {
589               *p++ = *s;
590               if (*s == '\"')
591                 *p++ = *s;
592             }
593           *p++ = '\"';
594           *p = 0;
595         }
596       else
597         p = stpcpy (p, argv[i]);
598     }
599
600   *cmdline= buf;
601   return 0;
602 }
603 #endif /*HAVE_W32_SYSTEM*/
604
605
606 #ifdef HAVE_W32_SYSTEM
607 /* Create pipe where one end end is inheritable.  */
608 static int
609 create_inheritable_pipe (int filedes[2], int for_write)
610 {
611   HANDLE r, w, h;
612   SECURITY_ATTRIBUTES sec_attr;
613
614   memset (&sec_attr, 0, sizeof sec_attr );
615   sec_attr.nLength = sizeof sec_attr;
616   sec_attr.bInheritHandle = FALSE;
617     
618   if (!CreatePipe (&r, &w, &sec_attr, 0))
619     {
620       _assuan_log_printf ("CreatePipe failed: %s\n", w32_strerror (-1));
621       return -1;
622     }
623
624   if (!DuplicateHandle (GetCurrentProcess(), for_write? r : w,
625                         GetCurrentProcess(), &h, 0,
626                         TRUE, DUPLICATE_SAME_ACCESS ))
627     {
628       _assuan_log_printf ("DuplicateHandle failed: %s\n", w32_strerror (-1));
629       CloseHandle (r);
630       CloseHandle (w);
631       return -1;
632     }
633   if (for_write)
634     {
635       CloseHandle (r);
636       r = h;
637     }
638   else
639     {
640       CloseHandle (w);
641       w = h;
642     }
643
644   filedes[0] = handle_to_fd (r);
645   filedes[1] = handle_to_fd (w);
646   return 0;
647 }
648 #endif /*HAVE_W32_SYSTEM*/
649
650
651 #ifdef HAVE_W32_SYSTEM
652 #define pipe_connect pipe_connect_w32
653 /* W32 version of the pipe connection code. */
654 static assuan_error_t
655 pipe_connect_w32 (assuan_context_t *ctx,
656                   const char *name, const char *const argv[],
657                   int *fd_child_list,
658                   void (*atfork) (void *opaque, int reserved),
659                   void *atforkvalue)
660 {
661   assuan_error_t err;
662   int rp[2];
663   int wp[2];
664   char mypidstr[50];
665   char *cmdline;
666   SECURITY_ATTRIBUTES sec_attr;
667   PROCESS_INFORMATION pi = 
668     {
669       NULL,      /* Returns process handle.  */
670       0,         /* Returns primary thread handle.  */
671       0,         /* Returns pid.  */
672       0          /* Returns tid.  */
673     };
674   STARTUPINFO si;
675   int fd, *fdp;
676   HANDLE nullfd = INVALID_HANDLE_VALUE;
677
678   if (!ctx || !name || !argv || !argv[0])
679     return _assuan_error (ASSUAN_Invalid_Value);
680
681   fix_signals ();
682
683   sprintf (mypidstr, "%lu", (unsigned long)getpid ());
684
685   /* Build the command line.  */
686   if (build_w32_commandline (argv, &cmdline))
687     return _assuan_error (ASSUAN_Out_Of_Core);
688
689   /* Create thew two pipes. */
690   if (create_inheritable_pipe (rp, 0))
691     {
692       xfree (cmdline);
693       return _assuan_error (ASSUAN_General_Error);
694     }
695   
696   if (create_inheritable_pipe (wp, 1))
697     {
698       CloseHandle (fd_to_handle (rp[0]));
699       CloseHandle (fd_to_handle (rp[1]));
700       xfree (cmdline);
701       return _assuan_error (ASSUAN_General_Error);
702     }
703
704   
705   err = _assuan_new_context (ctx);
706   if (err)
707     {
708       CloseHandle (fd_to_handle (rp[0]));
709       CloseHandle (fd_to_handle (rp[1]));
710       CloseHandle (fd_to_handle (wp[0]));
711       CloseHandle (fd_to_handle (wp[1]));
712       xfree (cmdline);
713       return _assuan_error (ASSUAN_General_Error);
714     }
715
716   (*ctx)->pipe_mode = 1;
717   (*ctx)->inbound.fd  = rp[0];  /* Our inbound is read end of read pipe. */
718   (*ctx)->outbound.fd = wp[1];  /* Our outbound is write end of write pipe. */
719   (*ctx)->deinit_handler = do_deinit;
720   (*ctx)->finish_handler = do_finish;
721
722
723   /* fixme: Actually we should set the "_assuan_pipe_connect_pid" env
724      variable.  However this requires us to write a full environment
725      handler, because the strings are expected in sorted order.  The
726      suggestion given in the MS Reference Library, to save the old
727      value, changeit, create proces and restore it, is not thread
728      safe.  */
729
730   /* Start the process.  */
731   memset (&sec_attr, 0, sizeof sec_attr );
732   sec_attr.nLength = sizeof sec_attr;
733   sec_attr.bInheritHandle = FALSE;
734   
735   memset (&si, 0, sizeof si);
736   si.cb = sizeof (si);
737   si.dwFlags = STARTF_USESTDHANDLES;
738   si.hStdInput  = fd_to_handle (wp[0]);
739   si.hStdOutput = fd_to_handle (rp[1]);
740
741   /* Dup stderr to /dev/null unless it is in the list of FDs to be
742      passed to the child. */
743   fd = fileno (stderr);
744   fdp = fd_child_list;
745   if (fdp)
746     {
747       for (; *fdp != -1 && *fdp != fd; fdp++)
748         ;
749     }
750   if (!fdp || *fdp == -1)
751     {
752       nullfd = CreateFile ("nul", GENERIC_WRITE,
753                            FILE_SHARE_READ | FILE_SHARE_WRITE,
754                            NULL, OPEN_EXISTING, 0, NULL);
755       if (nullfd == INVALID_HANDLE_VALUE)
756         {
757           _assuan_log_printf ("can't open `nul': %s\n", w32_strerror (-1));
758           CloseHandle (fd_to_handle (rp[0]));
759           CloseHandle (fd_to_handle (rp[1]));
760           CloseHandle (fd_to_handle (wp[0]));
761           CloseHandle (fd_to_handle (wp[1]));
762           xfree (cmdline);
763           _assuan_release_context (*ctx); 
764           return -1;
765         }
766       si.hStdError = nullfd;
767     }
768   else
769     si.hStdError = fd_to_handle (_get_osfhandle (fd));
770
771
772   /* Note: We inherit all handles flagged as inheritable.  This seems
773      to be a security flaw but there seems to be no way of selecting
774      handles to inherit. */
775   /*   _assuan_log_printf ("CreateProcess, path=`%s' cmdline=`%s'\n", */
776   /*                       name, cmdline); */
777   if (!CreateProcess (name,                 /* Program to start.  */
778                       cmdline,              /* Command line arguments.  */
779                       &sec_attr,            /* Process security attributes.  */
780                       &sec_attr,            /* Thread security attributes.  */
781                       TRUE,                 /* Inherit handles.  */
782                       (CREATE_DEFAULT_ERROR_MODE
783                        | GetPriorityClass (GetCurrentProcess ())
784                        | CREATE_SUSPENDED), /* Creation flags.  */
785                       NULL,                 /* Environment.  */
786                       NULL,                 /* Use current drive/directory.  */
787                       &si,                  /* Startup information. */
788                       &pi                   /* Returns process information.  */
789                       ))
790     {
791       _assuan_log_printf ("CreateProcess failed: %s\n", w32_strerror (-1));
792       CloseHandle (fd_to_handle (rp[0]));
793       CloseHandle (fd_to_handle (rp[1]));
794       CloseHandle (fd_to_handle (wp[0]));
795       CloseHandle (fd_to_handle (wp[1]));
796       if (nullfd != INVALID_HANDLE_VALUE)
797         CloseHandle (nullfd);
798       xfree (cmdline);
799       _assuan_release_context (*ctx); 
800       return _assuan_error (ASSUAN_General_Error);
801     }
802   xfree (cmdline);
803   cmdline = NULL;
804   if (nullfd != INVALID_HANDLE_VALUE)
805     {
806       CloseHandle (nullfd);
807       nullfd = INVALID_HANDLE_VALUE;
808     }
809
810   CloseHandle (fd_to_handle (rp[1]));
811   CloseHandle (fd_to_handle (wp[0]));
812
813   /*   _assuan_log_printf ("CreateProcess ready: hProcess=%p hThread=%p" */
814   /*                       " dwProcessID=%d dwThreadId=%d\n", */
815   /*                       pi.hProcess, pi.hThread, */
816   /*                       (int) pi.dwProcessId, (int) pi.dwThreadId); */
817
818   ResumeThread (pi.hThread);
819   CloseHandle (pi.hThread); 
820   (*ctx)->pid = 0;  /* We don't use the PID. */
821   CloseHandle (pi.hProcess); /* We don't need to wait for the process. */
822
823   return initial_handshake (ctx);
824 }
825 #endif /*HAVE_W32_SYSTEM*/
826
827 \f
828 /* Connect to a server over a pipe, creating the assuan context and
829    returning it in CTX.  The server filename is NAME, the argument
830    vector in ARGV.  FD_CHILD_LIST is a -1 terminated list of file
831    descriptors not to close in the child.  */
832 assuan_error_t
833 assuan_pipe_connect (assuan_context_t *ctx, const char *name,
834                      const char *const argv[], int *fd_child_list)
835 {
836   return pipe_connect (ctx, name, argv, fd_child_list, NULL, NULL);
837 }
838
839
840
841 assuan_error_t
842 assuan_pipe_connect2 (assuan_context_t *ctx,
843                       const char *name, const char *const argv[],
844                       int *fd_child_list,
845                       void (*atfork) (void *opaque, int reserved),
846                       void *atforkvalue)
847 {
848   return pipe_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue);
849 }
850
851
852 /* Connect to a server over a full-duplex socket (i.e. created by
853    socketpair), creating the assuan context and returning it in CTX.
854    The server filename is NAME, the argument vector in ARGV.
855    FD_CHILD_LIST is a -1 terminated list of file descriptors not to
856    close in the child.  ATFORK is called in the child right after the
857    fork; ATFORKVALUE is passed as the first argument and 0 is passed
858    as the second argument. The ATFORK function should only act if the
859    second value is 0.
860
861    For now FLAGS may either take the value 0 to behave like
862    assuan_pipe_connect2 or 1 to enable the described full-duplex
863    socket behaviour.
864
865    If NAME as well as ARGV are NULL, no exec is done but the same
866    process is continued.  However all file descriptors are closed and
867    some special environment variables are set. To let the caller
868    detect whether the child or the parent continues, the child returns
869    a CTX of NULL. */
870 assuan_error_t
871 assuan_pipe_connect_ext (assuan_context_t *ctx,
872                          const char *name, const char *const argv[],
873                          int *fd_child_list,
874                          void (*atfork) (void *opaque, int reserved),
875                          void *atforkvalue, unsigned int flags)
876 {
877   if ((flags & 1))
878     {
879 #ifdef HAVE_W32_SYSTEM
880       return _assuan_error (ASSUAN_Not_Implemented);
881 #else
882       return socketpair_connect (ctx, name, argv, fd_child_list,
883                                  atfork, atforkvalue);
884 #endif
885     }
886   else
887     return pipe_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue);
888 }
889