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