8e7abeae8ac6a2dfe2e5ab4f11f936d72b744814
[gpgme.git] / gpgme / w32-glib-io.c
1 /* w32-glib-io.c - W32 Glib I/O functions
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2004, 2005 g10 Code GmbH
4
5    This file is part of GPGME.
6  
7    GPGME 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    GPGME 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, write to the Free Software
19    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20    02111-1307, USA.  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <errno.h>
30 #include <signal.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <sys/time.h>
34 #include <sys/types.h>
35 #include <windows.h>
36 #include <io.h>
37
38 #include "util.h"
39 #include "priv-io.h"
40 #include "sema.h"
41 #include "debug.h"
42
43 #include <glib.h>
44
45 \f
46 /* This file is an ugly hack to get GPGME working with glib on Windows
47    targets.  On Windows, you can not select() on file descriptors.
48    The only way to check if there is something to read is to read
49    something.  This means that GPGME can not let glib check for data
50    without letting glib also handle the data on Windows targets.
51
52    The ugly consequence is that we need to work on GIOChannels in
53    GPGME, creating a glib dependency.  Also, we need to export an
54    interface for the application to get at GPGME's GIOChannel.  There
55    is no good way to abstract all this with callbacks, because the
56    whole thing is also interconnected with the creation of pipes and
57    child processes.
58
59    The following rules apply only to this I/O backend:
60
61    * All "file descriptors" that GPGME gives to the application are
62    not system file descriptors, but some internal number maintained by
63    GPGME.  I call them "Something like a file descriptor" (SLAFD).
64    It's an ugly name for an ugly thing.
65
66    * The application can use this "file descriptor" for exactly one
67    thing: To call gpgme_get_giochannel on it.  This returns the
68    GIOChannel that the application can actually use.  The channel can
69    then be integrated in the event loop.
70
71    * ALL operations must use the user defined event loop.  GPGME can
72    not anymore provide its own event loop.  This is mostly a sanity
73    requirement: Although we have in theory all information we need to
74    make the GPGME W32 code for select still work, it would be a big
75    complication and require changes throughout GPGME.
76
77    Eventually, we probably have to bite the bullet and make some
78    really nice callback interfaces to let the user control all this at
79    a per-context level.  */
80
81 \f
82 /* Something like a file descriptor.  We can not use "real" file
83    descriptors, because for some reason we can't create them from
84    osfhandles to be inherited.  Argh!  */
85 static struct
86 {
87   /* This is non-null if the entry is used.  */
88   HANDLE osfhandle;
89
90   /* This is non-null if there is a GIOChannel for this handle.  Only
91      for our end of the pipe.  */
92   GIOChannel *channel;
93 } slafd_table[256];
94
95 #define MAX_SLAFD ((int) DIM (slafd_table))
96
97 static int
98 create_slafd (HANDLE handle, int create_channel)
99 {
100   int slafd;
101
102   for (slafd = 0; slafd < MAX_SLAFD; slafd++)
103     if (slafd_table[slafd].osfhandle == NULL)
104       break;
105
106   if (slafd == MAX_SLAFD)
107     return -1;
108
109   if (create_channel)
110     {
111       /* FIXME: Do we need to specify the direction, too?  */
112       //      int fd = _open_osfhandle ((long) handle, 0);
113       //      DEBUG2("opened handle %p to %i\n", handle, fd);
114       slafd_table[slafd].channel = g_io_channel_unix_new ((int)handle);
115       if (!slafd_table[slafd].channel)
116         {
117           errno = EIO;  /* XXX */
118           return -1;
119         }
120     }
121   else
122     slafd_table[slafd].channel = NULL;
123   
124   slafd_table[slafd].osfhandle = handle;
125   return slafd;
126 }
127
128
129 static GIOChannel *
130 find_channel (int fd)
131 {
132   if (fd < 0 || fd >= MAX_SLAFD)
133     return NULL;
134
135   return slafd_table[fd].channel;
136 }
137
138
139 static HANDLE
140 find_handle (int fd)
141 {
142   if (fd < 0 || fd >= MAX_SLAFD)
143     return NULL;
144
145   return slafd_table[fd].osfhandle;
146 }
147
148
149 /* Look up the giochannel for "file descriptor" FD.  */
150 GIOChannel *
151 gpgme_get_giochannel (int fd)
152 {
153   return find_channel (fd);
154 }
155
156 \f
157 void
158 _gpgme_io_subsystem_init (void)
159 {
160 }
161
162 \f
163 static struct
164 {
165   void (*handler) (int,void*);
166   void *value;
167 } notify_table[MAX_SLAFD];
168
169 int
170 _gpgme_io_read (int fd, void *buffer, size_t count)
171 {
172   int saved_errno = 0;
173   gsize nread;
174   GIOChannel *chan;
175   GIOStatus status;
176
177   DEBUG2 ("fd %d: about to read %d bytes\n", fd, (int) count);
178
179   chan = find_channel (fd);
180   if (!chan)
181     {
182       DEBUG1 ("fd %d: no channel registered\n", fd);
183       errno = EINVAL;
184       return -1;
185     }
186   DEBUG2 ("fd %d: channel %p\n", fd, chan);
187
188   {
189     GError *err = NULL;
190     status = g_io_channel_read_chars (chan, (gchar *) buffer,
191                                       count, &nread, &err);
192     if (err)
193       {
194         DEBUG3 ("fd %d: status %i, err %s\n", fd, status, err->message);
195         g_error_free (err);
196       }
197   }
198
199   if (status == G_IO_STATUS_EOF)
200     nread = 0;
201   else if (status != G_IO_STATUS_NORMAL)
202     {
203       DEBUG2 ("fd %d: status %d\n", fd, status);
204       nread = -1;
205       saved_errno = EIO;
206     }
207
208   DEBUG2 ("fd %d: got %d bytes\n", fd, nread);
209   if (nread > 0)
210     _gpgme_debug (2, "fd %d: got `%.*s'\n", fd, nread, buffer);
211
212   errno = saved_errno;
213   return nread;
214 }
215
216
217 int
218 _gpgme_io_write (int fd, const void *buffer, size_t count)
219 {
220   int saved_errno = 0;
221   gsize nwritten;
222   GIOChannel *chan;
223   GIOStatus status;
224
225   DEBUG2 ("fd %d: about to write %d bytes\n", fd, (int) count);
226   _gpgme_debug (2, "fd %d: write `%.*s'\n", fd, (int) count, buffer);
227
228   chan = find_channel (fd);
229   if (!chan)
230     {
231       DEBUG1 ("fd %d: no channel registered\n", fd);
232       errno = EINVAL;
233       return -1;
234     }
235
236   status = g_io_channel_write_chars (chan, (gchar *) buffer, count,
237                                      &nwritten, NULL);
238   if (status != G_IO_STATUS_NORMAL)
239     {
240       nwritten = -1;
241       saved_errno = EIO;
242     }
243   DEBUG2 ("fd %d:          wrote %d bytes\n", fd, (int) nwritten);
244   errno = saved_errno;
245   return nwritten;
246 }
247
248
249 int
250 _gpgme_io_pipe ( int filedes[2], int inherit_idx )
251 {
252     HANDLE r, w;
253     SECURITY_ATTRIBUTES sec_attr;
254
255     memset (&sec_attr, 0, sizeof sec_attr );
256     sec_attr.nLength = sizeof sec_attr;
257     sec_attr.bInheritHandle = FALSE;
258
259     DEBUG1("INHERIT: %i\n", inherit_idx);
260     
261 #define PIPEBUF_SIZE  4096
262     if (!CreatePipe ( &r, &w, &sec_attr, PIPEBUF_SIZE))
263         return -1;
264     /* Make one end inheritable. */
265     if ( inherit_idx == 0 ) {
266         HANDLE h;
267         if (!DuplicateHandle( GetCurrentProcess(), r,
268                               GetCurrentProcess(), &h, 0,
269                               TRUE, DUPLICATE_SAME_ACCESS ) ) {
270             DEBUG1 ("DuplicateHandle failed: ec=%d\n", (int)GetLastError());
271             CloseHandle (r);
272             CloseHandle (w);
273             return -1;
274         }
275         CloseHandle (r);
276         r = h;
277     }
278     else if ( inherit_idx == 1 ) {
279         HANDLE h;
280         if (!DuplicateHandle( GetCurrentProcess(), w,
281                               GetCurrentProcess(), &h, 0,
282                               TRUE, DUPLICATE_SAME_ACCESS ) ) {
283             DEBUG1 ("DuplicateHandle failed: ec=%d\n", (int)GetLastError());
284             CloseHandle (r);
285             CloseHandle (w);
286             return -1;
287         }
288         CloseHandle (w);
289         w = h;
290     }
291     filedes[0] = create_slafd (r, inherit_idx == 1);
292     if (filedes[0] == -1)
293       {
294         DEBUG1 ("create_slafd failed: ec=%d\n", errno);
295         CloseHandle (r);
296         CloseHandle (w);
297         return -1;
298       }
299
300     filedes[1] = create_slafd (w, inherit_idx == 0);
301     if (filedes[1] == -1)
302       {
303         DEBUG1 ("create_slafd failed: ec=%d\n", errno);
304         _gpgme_io_close (filedes[0]);
305         CloseHandle (r);
306         CloseHandle (w);
307         return -1;
308       }
309
310     DEBUG5 ("CreatePipe %p %p %d %d inherit=%d\n", r, w,
311                    filedes[0], filedes[1], inherit_idx );
312     return 0;
313 }
314
315
316 int
317 _gpgme_io_close (int fd)
318 {
319   GIOChannel *chan;
320
321   if (fd < 0 || fd >= MAX_SLAFD)
322     {
323       errno = EBADF;
324       return -1;
325     }
326
327   /* First call the notify handler.  */
328   DEBUG1 ("closing fd %d", fd);
329   if (notify_table[fd].handler)
330     {
331       notify_table[fd].handler (fd, notify_table[fd].value);
332       notify_table[fd].handler = NULL;
333       notify_table[fd].value = NULL;
334     }
335
336   /* Then do the close.  */    
337   chan = slafd_table[fd].channel;
338   if (chan)
339     {
340       g_io_channel_shutdown (chan, 1, NULL);
341       g_io_channel_unref (chan);
342     }
343   
344   if (!CloseHandle (slafd_table[fd].osfhandle))
345     { 
346       DEBUG2 ("CloseHandle for fd %d failed: ec=%d\n",
347               fd, (int)GetLastError ());
348     }
349
350   slafd_table[fd].osfhandle = NULL;
351
352   return 0;
353 }
354
355
356 int
357 _gpgme_io_set_close_notify (int fd, void (*handler)(int, void*), void *value)
358 {
359   assert (fd != -1);
360
361   if (fd < 0 || fd >= (int) DIM (notify_table))
362     return -1;
363   DEBUG1 ("set notification for fd %d", fd);
364   notify_table[fd].handler = handler;
365   notify_table[fd].value = value;
366   return 0;
367 }
368
369
370 int
371 _gpgme_io_set_nonblocking (int fd)
372 {
373   GIOChannel *chan;
374   GIOStatus status;
375
376   chan = find_channel (fd);
377   if (!chan)
378     {
379       errno = EIO;
380       return -1;
381     }
382
383   status = g_io_channel_set_flags (chan,
384                                    g_io_channel_get_flags (chan) |
385                                    G_IO_FLAG_NONBLOCK, NULL);
386   if (status != G_IO_STATUS_NORMAL)
387     {
388       errno = EIO;
389       return -1;
390     }
391
392   return 0;
393 }
394
395
396 static char *
397 build_commandline ( char **argv )
398 {
399   int i, n = 0;
400   char *buf, *p;
401   
402   /* FIXME: we have to quote some things because under Windows the
403    * program parses the commandline and does some unquoting.  For now
404    * we only do very basic quoting to the first argument because this
405    * one often contains a space (e.g. C:\\Program Files\GNU\GnuPG\gpg.exe) 
406    * and we would produce an invalid line in that case.  */
407   for (i=0; argv[i]; i++)
408     n += strlen (argv[i]) + 2 + 1; /* 2 extra bytes for possible quoting */
409   buf = p = malloc (n);
410   if ( !buf )
411     return NULL;
412   *buf = 0;
413   if ( argv[0] )
414     {
415       if (strpbrk (argv[0], " \t"))
416         p = stpcpy (stpcpy (stpcpy (p, "\""), argv[0]), "\"");
417       else
418         p = stpcpy (p, argv[0]);
419       for (i = 1; argv[i]; i++)
420         {
421           if (!*argv[i])
422             p = stpcpy (p, " \"\"");
423           else
424             p = stpcpy (stpcpy (p, " "), argv[i]);
425         }
426     }
427   
428   return buf;
429 }
430
431
432 int
433 _gpgme_io_spawn ( const char *path, char **argv,
434                   struct spawn_fd_item_s *fd_child_list,
435                   struct spawn_fd_item_s *fd_parent_list )
436 {
437     SECURITY_ATTRIBUTES sec_attr;
438     PROCESS_INFORMATION pi = {
439         NULL,      /* returns process handle */
440         0,         /* returns primary thread handle */
441         0,         /* returns pid */
442         0         /* returns tid */
443     };
444     STARTUPINFO si;
445     char *envblock = NULL;
446     int cr_flags = CREATE_DEFAULT_ERROR_MODE
447                  | GetPriorityClass (GetCurrentProcess ());
448     int i;
449     char *arg_string;
450     int duped_stdin = 0;
451     int duped_stderr = 0;
452     HANDLE hnul = INVALID_HANDLE_VALUE;
453     /* FIXME.  */
454     int debug_me = 0;
455
456     memset (&sec_attr, 0, sizeof sec_attr );
457     sec_attr.nLength = sizeof sec_attr;
458     sec_attr.bInheritHandle = FALSE;
459
460     arg_string = build_commandline ( argv );
461     if (!arg_string )
462         return -1; 
463
464     memset (&si, 0, sizeof si);
465     si.cb = sizeof (si);
466     si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
467     si.wShowWindow = debug_me? SW_SHOW : SW_HIDE;
468     si.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
469     si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
470     si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
471
472     for (i=0; fd_child_list[i].fd != -1; i++ ) {
473         if (fd_child_list[i].dup_to == 0 ) {
474             si.hStdInput = find_handle (fd_child_list[i].fd);
475             DEBUG2 ("using %d (%p) for stdin", fd_child_list[i].fd,
476                     find_handle (fd_child_list[i].fd));
477             duped_stdin=1;
478         }
479         else if (fd_child_list[i].dup_to == 1 ) {
480             si.hStdOutput = find_handle (fd_child_list[i].fd);
481             DEBUG2 ("using %d (%p) for stdout", fd_child_list[i].fd,
482                     find_handle (fd_child_list[i].fd));
483         }
484         else if (fd_child_list[i].dup_to == 2 ) {
485             si.hStdError = find_handle (fd_child_list[i].fd);
486             DEBUG1 ("using %d for stderr", fd_child_list[i].fd );
487             duped_stderr = 1;
488         }
489     }
490
491     if( !duped_stdin || !duped_stderr ) {
492         SECURITY_ATTRIBUTES sa;
493
494         memset (&sa, 0, sizeof sa );
495         sa.nLength = sizeof sa;
496         sa.bInheritHandle = TRUE;
497         hnul = CreateFile ( "nul",
498                             GENERIC_READ|GENERIC_WRITE,
499                             FILE_SHARE_READ|FILE_SHARE_WRITE,
500                             &sa,
501                             OPEN_EXISTING,
502                             FILE_ATTRIBUTE_NORMAL,
503                             NULL );
504         if ( hnul == INVALID_HANDLE_VALUE ) {
505             DEBUG1 ("can't open `nul': ec=%d\n", (int)GetLastError ());
506             free (arg_string);
507             return -1;
508         }
509         /* Make sure that the process has a connected stdin */
510         if ( !duped_stdin ) {
511             si.hStdInput = hnul;
512             DEBUG1 ("using %d for dummy stdin", (int)hnul );
513         }
514         /* We normally don't want all the normal output */
515         if ( !duped_stderr ) {
516             si.hStdError = hnul;
517             DEBUG1 ("using %d for dummy stderr", (int)hnul );
518         }
519     }
520
521     DEBUG2 ("CreateProcess, path=`%s' args=`%s'", path, arg_string);
522     cr_flags |= CREATE_SUSPENDED; 
523     if ( !CreateProcessA (path,
524                           arg_string,
525                           &sec_attr,     /* process security attributes */
526                           &sec_attr,     /* thread security attributes */
527                           TRUE,          /* inherit handles */
528                           cr_flags,      /* creation flags */
529                           envblock,      /* environment */
530                           NULL,          /* use current drive/directory */
531                           &si,           /* startup information */
532                           &pi            /* returns process information */
533         ) ) {
534         DEBUG1 ("CreateProcess failed: ec=%d\n", (int) GetLastError ());
535         free (arg_string);
536         return -1;
537     }
538
539     /* Close the /dev/nul handle if used. */
540     if (hnul != INVALID_HANDLE_VALUE ) {
541         if ( !CloseHandle ( hnul ) )
542             DEBUG1 ("CloseHandle(hnul) failed: ec=%d\n", (int)GetLastError());
543     }
544
545     /* Close the other ends of the pipes. */
546     for (i = 0; fd_parent_list[i].fd != -1; i++)
547       _gpgme_io_close (fd_parent_list[i].fd);
548
549     DEBUG4 ("CreateProcess ready\n"
550             "-   hProcess=%p  hThread=%p\n"
551             "-   dwProcessID=%d dwThreadId=%d\n",
552             pi.hProcess, pi.hThread, 
553             (int) pi.dwProcessId, (int) pi.dwThreadId);
554
555     if ( ResumeThread ( pi.hThread ) < 0 ) {
556         DEBUG1 ("ResumeThread failed: ec=%d\n", (int)GetLastError ());
557     }
558
559     if ( !CloseHandle (pi.hThread) ) { 
560         DEBUG1 ("CloseHandle of thread failed: ec=%d\n",
561                  (int)GetLastError ());
562     }
563
564     return 0;
565 }
566
567
568 /*
569  * Select on the list of fds.
570  * Returns: -1 = error
571  *           0 = timeout or nothing to select
572  *          >0 = number of signaled fds
573  */
574 int
575 _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
576 {
577   assert (!"ARGH!  The user of this library MUST define io callbacks!");
578   errno = EINVAL;
579   return -1;
580 }