Chnages to supporta pinnetry notification
[gpgme.git] / gpgme / w32-qt-io.cpp
1 /* w32-qt-io.c - W32 Glib I/O functions
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2004, 2005, 2007 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 "kdpipeiodevice.h"
39
40 extern "C"
41 {
42 #include "util.h"
43 #include "priv-io.h"
44 #include "sema.h"
45 #include "debug.h"
46 }
47
48 #ifndef O_BINARY
49 #ifdef _O_BINARY
50 #define O_BINARY        _O_BINARY
51 #else
52 #define O_BINARY        0
53 #endif
54 #endif
55
56 using _gpgme_::KDPipeIODevice;
57
58 \f
59 /* This file is an ugly hack to get GPGME working with Qt on Windows
60    targets.  On Windows, you can not select() on file descriptors.
61 \f
62    The only way to check if there is something to read is to read
63    something.  This means that GPGME can not let Qt check for data
64    without letting Qt also handle the data on Windows targets.
65
66    The ugly consequence is that we need to work on QIODevices in
67    GPGME, creating a Qt dependency.  Also, we need to export an
68    interface for the application to get at GPGME's QIODevices.  There
69    is no good way to abstract all this with callbacks, because the
70    whole thing is also interconnected with the creation of pipes and
71    child processes.
72
73    The following rule applies only to this I/O backend:
74
75    * ALL operations must use the user defined event loop.  GPGME can
76    not anymore provide its own event loop.  This is mostly a sanity
77    requirement: Although we have in theory all information we need to
78    make the GPGME W32 code for select still work, it would be a big
79    complication and require changes throughout GPGME.
80
81    Eventually, we probably have to bite the bullet and make some
82    really nice callback interfaces to let the user control all this at
83    a per-context level.  */
84
85 #define MAX_SLAFD 1024
86
87 struct DeviceEntry {
88   DeviceEntry() : iodev( 0 ), refCount( 1 ), blocking( true ) {}
89     KDPipeIODevice* iodev;
90     bool blocking;
91     mutable int refCount;
92     void ref() const { ++refCount; }
93     int unref() const { assert( refCount > 0 ); return --refCount; }
94 };
95
96 DeviceEntry* iodevice_table[MAX_SLAFD];
97
98
99 static KDPipeIODevice *
100 find_channel (int fd, int create)
101 {
102   assert( fd < MAX_SLAFD );
103   if (fd < 0 || fd >= MAX_SLAFD)
104     return NULL;
105
106   if (create && !iodevice_table[fd])
107   {
108     DeviceEntry* entry = new DeviceEntry;
109     entry->iodev = new KDPipeIODevice
110       (fd, QIODevice::ReadWrite|QIODevice::Unbuffered);
111     iodevice_table[fd] = entry; 
112   }
113   return iodevice_table[fd] ? iodevice_table[fd]->iodev : 0;
114 }
115
116 /* Write the printable version of FD to the buffer BUF of length
117    BUFLEN.  The printable version is the representation on the command
118    line that the child process expects.  */
119 int
120 _gpgme_io_fd2str (char *buf, int buflen, int fd)
121 {
122   return snprintf (buf, buflen, "%d", (long)_get_osfhandle( fd ) );
123 }
124
125 \f
126 void
127 _gpgme_io_subsystem_init (void)
128 {
129 }
130
131 \f
132 static struct
133 {
134   _gpgme_close_notify_handler_t handler;
135   void *value;
136 } notify_table[MAX_SLAFD];
137
138
139 int
140 _gpgme_io_read (int fd, void *buffer, size_t count)
141 {
142   int saved_errno = 0;
143   qint64 nread;
144   KDPipeIODevice *chan;
145   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
146               "buffer=%p, count=%u", buffer, count);
147
148   chan = find_channel (fd, 0);
149   if (!chan)
150     {
151       TRACE_LOG ("no channel registered");
152       errno = EINVAL;
153       return TRACE_SYSRES (-1);
154     }
155   TRACE_LOG1 ("channel %p", chan);
156   if ( iodevice_table[fd] && !iodevice_table[fd]->blocking && chan->readWouldBlock() ) {
157       errno = EAGAIN;
158       return TRACE_SYSRES( -1 );
159   }
160  
161   nread = chan->read ((char *) buffer, count);
162   if (nread < 0)
163     {
164       TRACE_LOG1 ("err %s", qPrintable (chan->errorString ()));
165       saved_errno = EIO;
166       nread = -1;
167     }
168
169   TRACE_LOGBUF ((char *) buffer, nread);
170
171   errno = saved_errno;
172   return TRACE_SYSRES (nread);
173 }
174
175
176 int
177 _gpgme_io_write (int fd, const void *buffer, size_t count)
178 {
179   qint64 nwritten;
180   KDPipeIODevice *chan;
181   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
182               "buffer=%p, count=%u", buffer, count);
183   TRACE_LOGBUF ((char *) buffer, count);
184
185   chan = find_channel (fd, 0);
186   if (!chan)
187     {
188       TRACE_LOG ("fd %d: no channel registered");
189       errno = EINVAL;
190       return -1;
191     }
192
193   if ( iodevice_table[fd] && !iodevice_table[fd]->blocking && chan->writeWouldBlock() )
194   {
195       errno = EAGAIN;
196       return TRACE_SYSRES( -1 );
197   }
198   nwritten = chan->write ((char *) buffer, count);
199
200   if (nwritten < 0)
201     {
202       nwritten = -1;
203       errno = EIO;
204       return TRACE_SYSRES(-1);
205     }
206   errno = 0;
207   return TRACE_SYSRES (nwritten);
208 }
209
210
211 int
212 _gpgme_io_pipe (int filedes[2], int inherit_idx)
213 {
214   KDPipeIODevice *chan;
215   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes,
216               "inherit_idx=%i (GPGME uses it for %s)",
217               inherit_idx, inherit_idx ? "reading" : "writing");
218
219 #define PIPEBUF_SIZE  4096
220   if (_pipe (filedes, PIPEBUF_SIZE, O_NOINHERIT | O_BINARY) == -1)
221     return TRACE_SYSRES (-1);
222
223   /* Make one end inheritable. */
224   if (inherit_idx == 0)
225     {
226       int new_read;
227
228       new_read = _dup (filedes[0]);
229       _close (filedes[0]);
230       filedes[0] = new_read;
231
232       if (new_read < 0)
233         {
234           _close (filedes[1]);
235           return TRACE_SYSRES (-1);
236         }
237     }
238   else if (inherit_idx == 1)
239     {
240       int new_write;
241
242       new_write = _dup (filedes[1]);
243       _close (filedes[1]);
244       filedes[1] = new_write;
245
246       if (new_write < 0)
247         {
248           _close (filedes[0]);
249           return TRACE_SYSRES (-1);
250         }
251     }
252
253   /* Now we have a pipe with the right end inheritable.  The other end
254      should have a giochannel.  */
255
256   chan = find_channel (filedes[1 - inherit_idx], 1);
257
258   if (!chan)
259     {
260       int saved_errno = errno;
261       _close (filedes[0]);
262       _close (filedes[1]);
263       errno = saved_errno;
264       return TRACE_SYSRES (-1);
265     }
266
267   return TRACE_SUC5 ("read=0x%x/%p, write=0x%x/%p, channel=%p",
268           filedes[0], (HANDLE) _get_osfhandle (filedes[0]),
269           filedes[1], (HANDLE) _get_osfhandle (filedes[1]),
270           chan);
271 }
272
273 int
274 _gpgme_io_close (int fd)
275 {
276   KDPipeIODevice *chan;
277   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
278
279   if (fd < 0 || fd >= MAX_SLAFD)
280     {
281       errno = EBADF;
282       return TRACE_SYSRES (-1);
283     }
284
285   /* First call the notify handler.  */
286   if (notify_table[fd].handler)
287     {
288       notify_table[fd].handler (fd, notify_table[fd].value);
289       notify_table[fd].handler = NULL;
290       notify_table[fd].value = NULL;
291     }
292
293   /* Then do the close.  */    
294   
295   DeviceEntry* const entry = iodevice_table[fd];
296   if ( entry ) {
297       if ( entry->unref() == 0 ) {
298           entry->iodev->close();
299           delete entry->iodev;
300           delete entry;
301           iodevice_table[fd] = 0;
302       }
303   } else {
304       _close( fd );
305   }
306
307   
308
309   return 0;
310 }
311
312
313 int
314 _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
315                             void *value)
316 {
317   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
318               "close_handler=%p/%p", handler, value);
319
320   assert (fd != -1);
321
322   if (fd < 0 || fd >= (int) DIM (notify_table))
323     {
324       errno = EINVAL;
325       return TRACE_SYSRES (-1);
326     }
327   notify_table[fd].handler = handler;
328   notify_table[fd].value = value;
329   return TRACE_SYSRES (0);
330 }
331
332
333 int
334 _gpgme_io_set_nonblocking (int fd)
335 {
336   DeviceEntry* const entry = iodevice_table[fd];
337   assert( entry );
338   entry->blocking = false; 
339   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
340   return TRACE_SYSRES (0);
341 }
342
343
344 static char *
345 build_commandline (char **argv)
346 {
347   int i;
348   int n = 0;
349   char *buf;
350   char *p;
351   
352   /* We have to quote some things because under Windows the program
353      parses the commandline and does some unquoting.  We enclose the
354      whole argument in double-quotes, and escape literal double-quotes
355      as well as backslashes with a backslash.  We end up with a
356      trailing space at the end of the line, but that is harmless.  */
357   for (i = 0; argv[i]; i++)
358     {
359       p = argv[i];
360       /* The leading double-quote.  */
361       n++;
362       while (*p)
363       {
364           /* An extra one for each literal that must be escaped.  */
365           if (*p == '\\' || *p == '"')
366             n++;
367           n++;
368           p++;
369         }
370       /* The trailing double-quote and the delimiter.  */
371       n += 2;
372     }
373   /* And a trailing zero.  */
374   n++;
375
376   buf = p = (char *) malloc (n);
377   if (!buf)
378     return NULL;
379   for (i = 0; argv[i]; i++)
380     {
381       char *argvp = argv[i];
382
383       *(p++) = '"';
384       while (*argvp)
385         {
386           if (*argvp == '\\' || *argvp == '"')
387             *(p++) = '\\';
388           *(p++) = *(argvp++);
389         }
390       *(p++) = '"';
391       *(p++) = ' ';
392     }
393   *(p++) = 0;
394
395   return buf;
396 }
397
398
399 int
400 _gpgme_io_spawn (const char *path, char **argv,
401                  struct spawn_fd_item_s *fd_child_list,
402                  struct spawn_fd_item_s *fd_parent_list, pid_t *r_pid)
403 {
404   SECURITY_ATTRIBUTES sec_attr;
405   PROCESS_INFORMATION pi =
406     {
407       NULL,      /* returns process handle */
408       0,         /* returns primary thread handle */
409       0,         /* returns pid */
410       0         /* returns tid */
411     };
412   STARTUPINFO si;
413   char *envblock = NULL;
414   int cr_flags = CREATE_DEFAULT_ERROR_MODE
415     | GetPriorityClass (GetCurrentProcess ());
416   int i;
417   char *arg_string;
418   int duped_stdin = 0;
419   int duped_stderr = 0;
420   HANDLE hnul = INVALID_HANDLE_VALUE;
421   /* FIXME.  */
422   int debug_me = 0;
423   TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
424               "path=%s", path);
425   i = 0;
426   while (argv[i])
427     {
428       TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
429       i++;
430     }
431   
432   memset (&sec_attr, 0, sizeof sec_attr);
433   sec_attr.nLength = sizeof sec_attr;
434   sec_attr.bInheritHandle = FALSE;
435   
436   arg_string = build_commandline (argv);
437   if (!arg_string)
438     return TRACE_SYSRES (-1);
439   
440   memset (&si, 0, sizeof si);
441   si.cb = sizeof (si);
442   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
443   si.wShowWindow = debug_me? SW_SHOW : SW_HIDE;
444   si.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
445   si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
446   si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
447   
448   for (i = 0; fd_child_list[i].fd != -1; i++)
449     {
450       if (fd_child_list[i].dup_to == 0)
451         {
452           si.hStdInput = (HANDLE) _get_osfhandle (fd_child_list[i].fd);
453           TRACE_LOG2 ("using 0x%x/%p for stdin", fd_child_list[i].fd,
454                       _get_osfhandle (fd_child_list[i].fd));
455           duped_stdin = 1;
456         }
457       else if (fd_child_list[i].dup_to == 1)
458         {
459           si.hStdOutput = (HANDLE) _get_osfhandle (fd_child_list[i].fd);
460           TRACE_LOG2 ("using 0x%x/%p for stdout", fd_child_list[i].fd,
461                       _get_osfhandle (fd_child_list[i].fd));
462         }
463       else if (fd_child_list[i].dup_to == 2)
464         {
465           si.hStdError = (HANDLE) _get_osfhandle (fd_child_list[i].fd);
466           TRACE_LOG2 ("using 0x%x/%p for stderr", fd_child_list[i].fd,
467                       _get_osfhandle (fd_child_list[i].fd));
468           duped_stderr = 1;
469         }
470     }
471   
472   if (!duped_stdin || !duped_stderr)
473     {
474       SECURITY_ATTRIBUTES sa;
475       
476       memset (&sa, 0, sizeof sa);
477       sa.nLength = sizeof sa;
478       sa.bInheritHandle = TRUE;
479       hnul = CreateFile ("nul",
480                          GENERIC_READ|GENERIC_WRITE,
481                          FILE_SHARE_READ|FILE_SHARE_WRITE,
482                          &sa,
483                          OPEN_EXISTING,
484                          FILE_ATTRIBUTE_NORMAL,
485                          NULL);
486       if (hnul == INVALID_HANDLE_VALUE)
487         {
488           TRACE_LOG1 ("CreateFile (\"nul\") failed: ec=%d",
489                       (int) GetLastError ());
490           free (arg_string);
491           /* FIXME: Should translate the error code.  */
492           errno = EIO;
493           return TRACE_SYSRES (-1);
494         }
495       /* Make sure that the process has a connected stdin.  */
496       if (!duped_stdin)
497         {
498           si.hStdInput = hnul;
499           TRACE_LOG1 ("using 0x%x for dummy stdin", (int) hnul);
500         }
501       /* We normally don't want all the normal output.  */
502       if (!duped_stderr)
503         {
504           si.hStdError = hnul;
505           TRACE_LOG1 ("using %d for dummy stderr", (int)hnul);
506         }
507     }
508   
509   cr_flags |= CREATE_SUSPENDED;
510   cr_flags |= DETACHED_PROCESS;
511   if (!CreateProcessA (path,
512                        arg_string,
513                        &sec_attr,     /* process security attributes */
514                        &sec_attr,     /* thread security attributes */
515                        TRUE,          /* inherit handles */
516                        cr_flags,      /* creation flags */
517                        envblock,      /* environment */
518                        NULL,          /* use current drive/directory */
519                        &si,           /* startup information */
520                        &pi))          /* returns process information */
521     {
522       TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ());
523       free (arg_string);
524       /* FIXME: Should translate the error code.  */
525       errno = EIO;
526       return TRACE_SYSRES (-1);
527     }
528   
529   /* Close the /dev/nul handle if used.  */
530   if (hnul != INVALID_HANDLE_VALUE)
531     {
532       if (!CloseHandle (hnul))
533         TRACE_LOG1 ("CloseHandle (hnul) failed: ec=%d (ignored)",
534                     (int) GetLastError ());
535     }
536   
537   /* Close the other ends of the pipes.  */
538   for (i = 0; fd_parent_list[i].fd != -1; i++)
539     _gpgme_io_close (fd_parent_list[i].fd);
540
541   
542   TRACE_LOG4 ("CreateProcess ready: hProcess=%p, hThread=%p, "
543               "dwProcessID=%d, dwThreadId=%d",
544               pi.hProcess, pi.hThread, 
545               (int) pi.dwProcessId, (int) pi.dwThreadId);
546   if (r_pid)
547     *r_pid = (pid_t)pi.dwProcessId;
548   
549   if (ResumeThread (pi.hThread) < 0)
550     TRACE_LOG1 ("ResumeThread failed: ec=%d", (int) GetLastError ());
551   
552   if (!CloseHandle (pi.hThread))
553     TRACE_LOG1 ("CloseHandle of thread failed: ec=%d",
554                 (int) GetLastError ());
555
556   TRACE_SUC1 ("process=%p", pi.hProcess);
557
558   /* We don't need to wait for the process. */
559   CloseHandle (pi.hProcess);
560
561   return TRACE_SYSRES (0);
562 }
563
564
565 /* Select on the list of fds.  Returns: -1 = error, 0 = timeout or
566    nothing to select, > 0 = number of signaled fds.  */
567 int
568 _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
569 {
570   /* Use a 1s timeout.  */
571
572   void *dbg_help = NULL;
573   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
574               "nfds=%u, nonblock=%u", nfds, nonblock);
575
576   /* We only implement the special case of nonblock == true.  */
577   assert (nonblock);
578
579   int count = 0;
580
581   TRACE_SEQ (dbg_help, "select on [ ");
582   for (int i = 0; i < nfds; i++)
583     {
584       if (fds[i].fd == -1)
585         {
586           fds[i].signaled = 0;
587         }
588       else if (fds[i].for_read )
589       {
590           const KDPipeIODevice * const chan = find_channel (fds[i].fd, 0);
591           assert (chan);   
592           fds[i].signaled = chan->readWouldBlock() ? 0 : 1;
593           TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
594           if ( fds[i].signaled ) 
595               count++;
596         }
597       else if (fds[i].for_write)
598         {
599           const KDPipeIODevice * const chan = find_channel (fds[i].fd, 0);
600           assert (chan);
601           fds[i].signaled = chan->writeWouldBlock() ? 0 : 1;
602           TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
603           if ( fds[i].signaled ) 
604               count++;
605         }
606     }
607   TRACE_END (dbg_help, "]"); 
608
609   return TRACE_SYSRES (count);
610 }
611
612
613 /* Look up the qiodevice for file descriptor FD.  */
614 extern "C"
615 void *
616 gpgme_get_fdptr (int fd)
617 {
618   return find_channel (fd, 0);
619 }
620
621
622 /* Obsolete compatibility interface.  */
623 extern "C"
624 void *
625 gpgme_get_giochannel (int fd)
626 {
627   return NULL;
628 }
629
630
631 int
632 _gpgme_io_dup (int fd)
633 {
634     assert( iodevice_table[fd] );
635     iodevice_table[fd]->ref();
636     return fd;
637 }
638