Improved debug support: Assuan logging is now directed to the gpgme debug
[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   _assuan_log_printf ("created pipe: read=%p%s, write=%p%s\n",
645                       r, for_write? " (inherit)":"",
646                       w, for_write? "":" (inherit)");
647   filedes[0] = handle_to_fd (r);
648   filedes[1] = handle_to_fd (w);
649   return 0;
650 }
651 #endif /*HAVE_W32_SYSTEM*/
652
653
654 #ifdef HAVE_W32_SYSTEM
655 #define pipe_connect pipe_connect_w32
656 /* W32 version of the pipe connection code. */
657 static assuan_error_t
658 pipe_connect_w32 (assuan_context_t *ctx,
659                   const char *name, const char *const argv[],
660                   int *fd_child_list,
661                   void (*atfork) (void *opaque, int reserved),
662                   void *atforkvalue)
663 {
664   assuan_error_t err;
665   int rp[2];
666   int wp[2];
667   char mypidstr[50];
668   char *cmdline;
669   SECURITY_ATTRIBUTES sec_attr;
670   PROCESS_INFORMATION pi = 
671     {
672       NULL,      /* Returns process handle.  */
673       0,         /* Returns primary thread handle.  */
674       0,         /* Returns pid.  */
675       0          /* Returns tid.  */
676     };
677   STARTUPINFO si;
678   int fd, *fdp;
679   HANDLE nullfd = INVALID_HANDLE_VALUE;
680
681   if (!ctx || !name || !argv || !argv[0])
682     return _assuan_error (ASSUAN_Invalid_Value);
683
684   fix_signals ();
685
686   sprintf (mypidstr, "%lu", (unsigned long)getpid ());
687
688   /* Build the command line.  */
689   if (build_w32_commandline (argv, &cmdline))
690     return _assuan_error (ASSUAN_Out_Of_Core);
691
692   /* Create thew two pipes. */
693   if (create_inheritable_pipe (rp, 0))
694     {
695       xfree (cmdline);
696       return _assuan_error (ASSUAN_General_Error);
697     }
698   
699   if (create_inheritable_pipe (wp, 1))
700     {
701       CloseHandle (fd_to_handle (rp[0]));
702       CloseHandle (fd_to_handle (rp[1]));
703       xfree (cmdline);
704       return _assuan_error (ASSUAN_General_Error);
705     }
706
707   
708   err = _assuan_new_context (ctx);
709   if (err)
710     {
711       CloseHandle (fd_to_handle (rp[0]));
712       CloseHandle (fd_to_handle (rp[1]));
713       CloseHandle (fd_to_handle (wp[0]));
714       CloseHandle (fd_to_handle (wp[1]));
715       xfree (cmdline);
716       return _assuan_error (ASSUAN_General_Error);
717     }
718
719   (*ctx)->pipe_mode = 1;
720   (*ctx)->inbound.fd  = rp[0];  /* Our inbound is read end of read pipe. */
721   (*ctx)->outbound.fd = wp[1];  /* Our outbound is write end of write pipe. */
722   (*ctx)->deinit_handler = do_deinit;
723   (*ctx)->finish_handler = do_finish;
724
725
726   /* fixme: Actually we should set the "_assuan_pipe_connect_pid" env
727      variable.  However this requires us to write a full environment
728      handler, because the strings are expected in sorted order.  The
729      suggestion given in the MS Reference Library, to save the old
730      value, changeit, create proces and restore it, is not thread
731      safe.  */
732
733   /* Start the process.  */
734   memset (&sec_attr, 0, sizeof sec_attr );
735   sec_attr.nLength = sizeof sec_attr;
736   sec_attr.bInheritHandle = FALSE;
737   
738   memset (&si, 0, sizeof si);
739   si.cb = sizeof (si);
740   si.dwFlags = STARTF_USESTDHANDLES;
741   si.hStdInput  = fd_to_handle (wp[0]);
742   si.hStdOutput = fd_to_handle (rp[1]);
743
744   /* Dup stderr to /dev/null unless it is in the list of FDs to be
745      passed to the child. */
746   fd = fileno (stderr);
747   fdp = fd_child_list;
748   if (fdp)
749     {
750       for (; *fdp != -1 && *fdp != fd; fdp++)
751         ;
752     }
753   if (!fdp || *fdp == -1)
754     {
755       nullfd = CreateFile ("nul", GENERIC_WRITE,
756                            FILE_SHARE_READ | FILE_SHARE_WRITE,
757                            NULL, OPEN_EXISTING, 0, NULL);
758       _assuan_log_printf ("created nul device, hd=%p\n", nullfd);
759       if (nullfd == INVALID_HANDLE_VALUE)
760         {
761           _assuan_log_printf ("can't open `nul': %s\n", w32_strerror (-1));
762           CloseHandle (fd_to_handle (rp[0]));
763           CloseHandle (fd_to_handle (rp[1]));
764           CloseHandle (fd_to_handle (wp[0]));
765           CloseHandle (fd_to_handle (wp[1]));
766           xfree (cmdline);
767           _assuan_release_context (*ctx); 
768           return -1;
769         }
770       si.hStdError = nullfd;
771     }
772   else
773     si.hStdError = fd_to_handle (_get_osfhandle (fd));
774
775
776   /* Note: We inherit all handles flagged as inheritable.  This seems
777      to be a security flaw but there seems to be no way of selecting
778      handles to inherit. */
779   _assuan_log_printf ("CreateProcess, path=`%s' cmdline=`%s'\n",
780                       name, cmdline);
781   _assuan_log_printf ("        stdin=%p stdout=%p stderr=%p\n",
782                       si.hStdInput, si.hStdOutput, si.hStdError);
783   if (!CreateProcess (name,                 /* Program to start.  */
784                       cmdline,              /* Command line arguments.  */
785                       &sec_attr,            /* Process security attributes.  */
786                       &sec_attr,            /* Thread security attributes.  */
787                       TRUE,                 /* Inherit handles.  */
788                       (CREATE_DEFAULT_ERROR_MODE
789                        | DETACHED_PROCESS
790                        | GetPriorityClass (GetCurrentProcess ())
791                        | CREATE_SUSPENDED), /* Creation flags.  */
792                       NULL,                 /* Environment.  */
793                       NULL,                 /* Use current drive/directory.  */
794                       &si,                  /* Startup information. */
795                       &pi                   /* Returns process information.  */
796                       ))
797     {
798       _assuan_log_printf ("CreateProcess failed: %s\n", w32_strerror (-1));
799       CloseHandle (fd_to_handle (rp[0]));
800       CloseHandle (fd_to_handle (rp[1]));
801       CloseHandle (fd_to_handle (wp[0]));
802       CloseHandle (fd_to_handle (wp[1]));
803       if (nullfd != INVALID_HANDLE_VALUE)
804         CloseHandle (nullfd);
805       xfree (cmdline);
806       _assuan_release_context (*ctx); 
807       return _assuan_error (ASSUAN_General_Error);
808     }
809   xfree (cmdline);
810   cmdline = NULL;
811   if (nullfd != INVALID_HANDLE_VALUE)
812     {
813       CloseHandle (nullfd);
814       nullfd = INVALID_HANDLE_VALUE;
815     }
816
817   _assuan_log_printf ("closing handles %p and %p\n", 
818                       fd_to_handle (rp[1]), fd_to_handle (wp[0]) );
819   CloseHandle (fd_to_handle (rp[1]));
820   CloseHandle (fd_to_handle (wp[0]));
821
822   _assuan_log_printf ("CreateProcess ready: hProcess=%p hThread=%p"
823                       " dwProcessID=%d dwThreadId=%d\n",
824                       pi.hProcess, pi.hThread,
825                       (int) pi.dwProcessId, (int) pi.dwThreadId);
826
827   ResumeThread (pi.hThread);
828   CloseHandle (pi.hThread); 
829   (*ctx)->pid = 0;  /* We don't use the PID. */
830   CloseHandle (pi.hProcess); /* We don't need to wait for the process. */
831
832   return initial_handshake (ctx);
833 }
834 #endif /*HAVE_W32_SYSTEM*/
835
836 \f
837 /* Connect to a server over a pipe, creating the assuan context and
838    returning it in CTX.  The server filename is NAME, the argument
839    vector in ARGV.  FD_CHILD_LIST is a -1 terminated list of file
840    descriptors not to close in the child.  */
841 assuan_error_t
842 assuan_pipe_connect (assuan_context_t *ctx, const char *name,
843                      const char *const argv[], int *fd_child_list)
844 {
845   return pipe_connect (ctx, name, argv, fd_child_list, NULL, NULL);
846 }
847
848
849
850 assuan_error_t
851 assuan_pipe_connect2 (assuan_context_t *ctx,
852                       const char *name, const char *const argv[],
853                       int *fd_child_list,
854                       void (*atfork) (void *opaque, int reserved),
855                       void *atforkvalue)
856 {
857   return pipe_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue);
858 }
859
860
861 /* Connect to a server over a full-duplex socket (i.e. created by
862    socketpair), creating the assuan context and returning it in CTX.
863    The server filename is NAME, the argument vector in ARGV.
864    FD_CHILD_LIST is a -1 terminated list of file descriptors not to
865    close in the child.  ATFORK is called in the child right after the
866    fork; ATFORKVALUE is passed as the first argument and 0 is passed
867    as the second argument. The ATFORK function should only act if the
868    second value is 0.
869
870    For now FLAGS may either take the value 0 to behave like
871    assuan_pipe_connect2 or 1 to enable the described full-duplex
872    socket behaviour.
873
874    If NAME as well as ARGV are NULL, no exec is done but the same
875    process is continued.  However all file descriptors are closed and
876    some special environment variables are set. To let the caller
877    detect whether the child or the parent continues, the child returns
878    a CTX of NULL. */
879 assuan_error_t
880 assuan_pipe_connect_ext (assuan_context_t *ctx,
881                          const char *name, const char *const argv[],
882                          int *fd_child_list,
883                          void (*atfork) (void *opaque, int reserved),
884                          void *atforkvalue, unsigned int flags)
885 {
886   if ((flags & 1))
887     {
888 #ifdef HAVE_W32_SYSTEM
889       return _assuan_error (ASSUAN_Not_Implemented);
890 #else
891       return socketpair_connect (ctx, name, argv, fd_child_list,
892                                  atfork, atforkvalue);
893 #endif
894     }
895   else
896     return pipe_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue);
897 }
898