1 /* server.c -  The UI server part of GPA.
2    Copyright (C) 2007, 2008 g10 Code GmbH
3 
4    This file is part of GPA
5 
6    GPA is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10 
11    GPA is distributed in the hope that it will be useful, but WITHOUT
12    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
14    License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.  */
18 
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <assert.h>
26 #include <string.h>
27 #include <errno.h>
28 #ifndef HAVE_W32_SYSTEM
29 # include <sys/socket.h>
30 # include <sys/un.h>
31 #endif /*HAVE_W32_SYSTEM*/
32 
33 #include <gpgme.h>
34 #include <glib.h>
35 #include <assuan.h>
36 
37 #include "gpa.h"
38 #include "i18n.h"
39 #include "gpastreamencryptop.h"
40 #include "gpastreamsignop.h"
41 #include "gpastreamdecryptop.h"
42 #include "gpastreamverifyop.h"
43 #include "gpafileop.h"
44 #include "gpafileencryptop.h"
45 #include "gpafilesignop.h"
46 #include "gpafiledecryptop.h"
47 #include "gpafileverifyop.h"
48 #include "gpafileimportop.h"
49 
50 
51 #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
52 
53 /* The object used to keep track of the a connection's state.  */
54 struct conn_ctrl_s;
55 typedef struct conn_ctrl_s *conn_ctrl_t;
56 struct conn_ctrl_s
57 {
58   /* True if we are currently processing a command.  */
59   int in_command;
60 
61   /* NULL or continuation function for a command.  */
62   void (*cont_cmd) (assuan_context_t, gpg_error_t);
63 
64   /* Flag indicating that the client died while a continuation was
65      still registyered.  */
66   int client_died;
67 
68   /* This is a helper to detect that the unfinished error code actually
69      comes from our command handler.  */
70   int is_unfinished;
71 
72   /* An GPAOperation object.  */
73   GpaOperation *gpa_op;
74 
75   /* File descriptors used by the gpgme callbacks.  */
76   int input_fd;
77   int output_fd;
78 
79   /* File descriptor set with the MESSAGE command.  */
80   int message_fd;
81 
82   /* Flag indicating the the output shall be binary.  */
83   int output_binary;
84 
85   /* Channels used with the gpgme callbacks.  */
86   GIOChannel *input_channel;
87   GIOChannel *output_channel;
88   GIOChannel *message_channel;
89 
90   /* List of collected recipients.  */
91   GSList *recipients;
92 
93   /* Array of keys already prepared for RECIPIENTS.  */
94   gpgme_key_t *recipient_keys;
95 
96   /* The protocol as selected by the user.  */
97   gpgme_protocol_t selected_protocol;
98 
99   /* The current sender address (malloced) and a flag telleing whether
100      the sender ist just informational. */
101   gchar *sender;
102   int sender_just_info;
103   gpgme_protocol_t sender_protocol_hint;
104 
105   /* Session information:  A session number and a malloced title or NULL.  */
106   unsigned int session_number;
107   char *session_title;
108 
109   /* The list of all files to be processed.  */
110   GList *files;
111 };
112 
113 
114 /* The number of active connections.  */
115 static int connection_counter;
116 
117 /* A flag requesting a shutdown.  */
118 static gboolean shutdown_pending;
119 
120 
121 /* The nonce used by the server connection.  This nonce is required
122    under Windows to emulate Unix Domain Sockets.  This is managed by
123    libassuan but we need to store the nonce in the application.  Under
124    Unix this is just a stub.  */
125 static assuan_sock_nonce_t socket_nonce;
126 
127 
128 /* Forward declarations.  */
129 static void run_server_continuation (assuan_context_t ctx, gpg_error_t err);
130 
131 
132 
133 
134 
135 static int
not_finished(conn_ctrl_t ctrl)136 not_finished (conn_ctrl_t ctrl)
137 {
138   ctrl->is_unfinished = 1;
139   return gpg_error (GPG_ERR_UNFINISHED);
140 }
141 
142 
143 /* Test whether LINE contains thye option NAME.  An optional argument
144    of the option is ignored.  For example with NAME being "--protocol"
145    this function returns true for "--protocol" as well as for
146    "--protocol=foo".  The returned pointer points right behind the
147    option name, which may be an equal sign, Nul or a space.  If tehre
148    is no option NAME, false (i.e. NULL) is returned.
149 */
150 static const char *
has_option_name(const char * line,const char * name)151 has_option_name (const char *line, const char *name)
152 {
153   const char *s;
154   int n = strlen (name);
155 
156   s = strstr (line, name);
157   return (s && (s == line || spacep (s-1))
158           && (!s[n] || spacep (s+n) || s[n] == '=')) ? (s+n) : NULL;
159 }
160 
161 /* Check whether LINE contains the option NAME.  */
162 static int
has_option(const char * line,const char * name)163 has_option (const char *line, const char *name)
164 {
165   const char *s;
166   int n = strlen (name);
167 
168   s = strstr (line, name);
169   return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
170 }
171 
172 /* Skip over options. */
173 static char *
skip_options(char * line)174 skip_options (char *line)
175 {
176   while (spacep (line))
177     line++;
178   while ( *line == '-' && line[1] == '-' )
179     {
180       while (*line && !spacep (line))
181         line++;
182       while (spacep (line))
183         line++;
184     }
185   return line;
186 }
187 
188 /* Helper to be used as a GFunc for free. */
189 static void
free_func(void * p,void * dummy)190 free_func (void *p, void *dummy)
191 {
192   (void)dummy;
193   g_free (p);
194 }
195 
196 
197 static ssize_t
my_gpgme_read_cb(void * opaque,void * buffer,size_t size)198 my_gpgme_read_cb (void *opaque, void *buffer, size_t size)
199 {
200   conn_ctrl_t ctrl = opaque;
201   GIOStatus  status;
202   size_t nread;
203   int retval;
204 
205 /*   g_debug ("my_gpgme_read_cb: requesting %d bytes\n", (int)size); */
206   status = g_io_channel_read_chars (ctrl->input_channel, buffer, size,
207                                     &nread, NULL);
208   if (status == G_IO_STATUS_AGAIN
209       || (status == G_IO_STATUS_NORMAL && !nread))
210     {
211       errno = EAGAIN;
212       retval = -1;
213     }
214   else if (status == G_IO_STATUS_NORMAL)
215     retval = (int)nread;
216   else if (status == G_IO_STATUS_EOF)
217     retval = 0;
218   else
219     {
220       errno = EIO;
221       retval = -1;
222     }
223 /*   g_debug ("my_gpgme_read_cb: got status=%x, %d bytes, retval=%d\n",  */
224 /*            status, (int)size, retval); */
225 
226   return retval;
227 }
228 
229 
230 static ssize_t
my_gpgme_write_cb(void * opaque,const void * buffer,size_t size)231 my_gpgme_write_cb (void *opaque, const void *buffer, size_t size)
232 {
233   conn_ctrl_t ctrl = opaque;
234   GIOStatus  status;
235   size_t nwritten;
236   int retval;
237 
238   status = g_io_channel_write_chars (ctrl->output_channel, buffer, size,
239                                      &nwritten, NULL);
240   if (status == G_IO_STATUS_AGAIN)
241     {
242       errno = EAGAIN;
243       retval = -1;
244     }
245   else if (status == G_IO_STATUS_NORMAL)
246     retval = (int)nwritten;
247   else
248     {
249       errno = EIO;
250       retval = 1;
251     }
252 
253   return retval;
254 }
255 
256 
257 static struct gpgme_data_cbs my_gpgme_data_cbs =
258   {
259     my_gpgme_read_cb,
260     my_gpgme_write_cb,
261     NULL,
262     NULL
263   };
264 
265 
266 static ssize_t
my_gpgme_message_read_cb(void * opaque,void * buffer,size_t size)267 my_gpgme_message_read_cb (void *opaque, void *buffer, size_t size)
268 {
269   conn_ctrl_t ctrl = opaque;
270   GIOStatus  status;
271   size_t nread;
272   int retval;
273 
274   status = g_io_channel_read_chars (ctrl->message_channel, buffer, size,
275                                     &nread, NULL);
276   if (status == G_IO_STATUS_AGAIN
277       || (status == G_IO_STATUS_NORMAL && !nread))
278     {
279       errno = EAGAIN;
280       retval = -1;
281     }
282   else if (status == G_IO_STATUS_NORMAL)
283     retval = (int)nread;
284   else if (status == G_IO_STATUS_EOF)
285     retval = 0;
286   else
287     {
288       errno = EIO;
289       retval = -1;
290     }
291 
292   return retval;
293 }
294 
295 static struct gpgme_data_cbs my_gpgme_message_cbs =
296   {
297     my_gpgme_message_read_cb,
298     NULL,
299     NULL,
300     NULL
301   };
302 
303 
304 static ssize_t
my_devnull_write_cb(void * opaque,const void * buffer,size_t size)305 my_devnull_write_cb (void *opaque, const void *buffer, size_t size)
306 {
307   return size;
308 }
309 
310 
311 static struct gpgme_data_cbs my_devnull_data_cbs =
312   {
313     NULL,
314     my_devnull_write_cb,
315     NULL,
316     NULL
317   };
318 
319 
320 /* Release the recipients stored in the connection context. */
321 static void
release_recipients(conn_ctrl_t ctrl)322 release_recipients (conn_ctrl_t ctrl)
323 {
324   if (ctrl->recipients)
325     {
326       g_slist_foreach (ctrl->recipients, free_func, NULL);
327       g_slist_free (ctrl->recipients);
328       ctrl->recipients = NULL;
329     }
330 }
331 
332 
333 static void
free_file_item(gpa_file_item_t item)334 free_file_item (gpa_file_item_t item)
335 {
336   if (item->filename_in)
337     g_free (item->filename_in);
338   if (item->filename_out)
339     g_free (item->filename_out);
340 }
341 
342 
343 static void
release_files(conn_ctrl_t ctrl)344 release_files (conn_ctrl_t ctrl)
345 {
346   if (! ctrl->files)
347     return;
348 
349   g_list_foreach (ctrl->files, (GFunc) free_file_item, NULL);
350   g_list_free (ctrl->files);
351   ctrl->files = NULL;
352 }
353 
354 
355 static void
release_keys(gpgme_key_t * keys)356 release_keys (gpgme_key_t *keys)
357 {
358   if (keys)
359     {
360       int idx;
361 
362       for (idx=0; keys[idx]; idx++)
363         gpgme_key_unref (keys[idx]);
364       g_free (keys);
365     }
366 }
367 
368 
369 /* Reset already prepared keys.  */
370 static void
reset_prepared_keys(conn_ctrl_t ctrl)371 reset_prepared_keys (conn_ctrl_t ctrl)
372 {
373   release_keys (ctrl->recipient_keys);
374   ctrl->recipient_keys = NULL;
375   ctrl->selected_protocol = GPGME_PROTOCOL_UNKNOWN;
376 }
377 
378 
379 /* Helper to parse an protocol option.  */
380 static gpg_error_t
parse_protocol_option(assuan_context_t ctx,char * line,int mandatory,gpgme_protocol_t * r_protocol)381 parse_protocol_option (assuan_context_t ctx, char *line, int mandatory,
382                        gpgme_protocol_t *r_protocol)
383 {
384   *r_protocol = GPGME_PROTOCOL_UNKNOWN;
385   if (has_option (line, "--protocol=OpenPGP"))
386     *r_protocol = GPGME_PROTOCOL_OpenPGP;
387   else if (has_option (line, "--protocol=CMS"))
388     *r_protocol = GPGME_PROTOCOL_CMS;
389   else if (has_option_name (line, "--protocol"))
390     return set_error (GPG_ERR_ASS_PARAMETER, "invalid protocol");
391   else if (mandatory)
392     return set_error (GPG_ERR_ASS_PARAMETER, "no protocol specified");
393 
394   return 0;
395 }
396 
397 
398 static void
close_message_fd(conn_ctrl_t ctrl)399 close_message_fd (conn_ctrl_t ctrl)
400 {
401   if (ctrl->message_fd != -1)
402     {
403       close (ctrl->message_fd);
404       ctrl->message_fd = -1;
405     }
406 }
407 
408 
409 static void
finish_io_streams(assuan_context_t ctx,gpgme_data_t * r_input_data,gpgme_data_t * r_output_data,gpgme_data_t * r_message_data)410 finish_io_streams (assuan_context_t ctx,
411                    gpgme_data_t *r_input_data, gpgme_data_t *r_output_data,
412                    gpgme_data_t *r_message_data)
413 {
414   conn_ctrl_t ctrl = assuan_get_pointer (ctx);
415 
416   if (r_input_data)
417     gpgme_data_release (*r_input_data);
418   if (r_output_data)
419     gpgme_data_release (*r_output_data);
420   if (r_message_data)
421     gpgme_data_release (*r_message_data);
422   if (ctrl->input_channel)
423     {
424       g_io_channel_shutdown (ctrl->input_channel, 0, NULL);
425       ctrl->input_channel = NULL;
426     }
427   if (ctrl->output_channel)
428     {
429       g_io_channel_shutdown (ctrl->output_channel, 0, NULL);
430       ctrl->output_channel = NULL;
431     }
432   if (ctrl->message_channel)
433     {
434       g_io_channel_shutdown (ctrl->message_channel, 0, NULL);
435       ctrl->message_channel = NULL;
436     }
437 
438   close_message_fd (ctrl);
439   assuan_close_input_fd (ctx);
440   assuan_close_output_fd (ctx);
441   ctrl->input_fd = -1;
442   ctrl->output_fd = -1;
443 }
444 
445 
446 /* Translate the input and output file descriptors and return an error
447    if they are not set.  */
448 static gpg_error_t
translate_io_streams(assuan_context_t ctx)449 translate_io_streams (assuan_context_t ctx)
450 {
451   conn_ctrl_t ctrl = assuan_get_pointer (ctx);
452 
453   ctrl->input_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
454   if (ctrl->input_fd == -1)
455     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
456   ctrl->output_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
457   if (ctrl->output_fd == -1)
458     return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
459   return 0;
460 }
461 
462 
463 static gpg_error_t
prepare_io_streams(assuan_context_t ctx,gpgme_data_t * r_input_data,gpgme_data_t * r_output_data,gpgme_data_t * r_message_data)464 prepare_io_streams (assuan_context_t ctx,
465                     gpgme_data_t *r_input_data, gpgme_data_t *r_output_data,
466                     gpgme_data_t *r_message_data)
467 {
468   gpg_error_t err;
469   conn_ctrl_t ctrl = assuan_get_pointer (ctx);
470 
471   if (r_input_data)
472     *r_input_data = NULL;
473   if (r_output_data)
474     *r_output_data = NULL;
475   if (r_message_data)
476     *r_message_data = NULL;
477 
478   if (ctrl->input_fd != -1 && r_input_data)
479     {
480 #ifdef HAVE_W32_SYSTEM
481       ctrl->input_channel = g_io_channel_win32_new_fd (ctrl->input_fd);
482 #else
483       ctrl->input_channel = g_io_channel_unix_new (ctrl->input_fd);
484 #endif
485       if (!ctrl->input_channel)
486         {
487           /* g_debug ("error creating input channel"); */
488           err = gpg_error (GPG_ERR_EIO);
489           goto leave;
490         }
491       g_io_channel_set_encoding (ctrl->input_channel, NULL, NULL);
492       g_io_channel_set_buffered (ctrl->input_channel, FALSE);
493     }
494 
495   if (ctrl->output_fd != -1 && r_output_data)
496     {
497 #ifdef HAVE_W32_SYSTEM
498       ctrl->output_channel = g_io_channel_win32_new_fd (ctrl->output_fd);
499 #else
500       ctrl->output_channel = g_io_channel_unix_new (ctrl->output_fd);
501 #endif
502       if (!ctrl->output_channel)
503         {
504           g_debug ("error creating output channel");
505           err = gpg_error (GPG_ERR_EIO);
506           goto leave;
507         }
508       g_io_channel_set_encoding (ctrl->output_channel, NULL, NULL);
509       g_io_channel_set_buffered (ctrl->output_channel, FALSE);
510     }
511 
512   if (ctrl->message_fd != -1 && r_message_data)
513     {
514 #ifdef HAVE_W32_SYSTEM
515       ctrl->message_channel = g_io_channel_win32_new_fd (ctrl->message_fd);
516 #else
517       ctrl->message_channel = g_io_channel_unix_new (ctrl->message_fd);
518 #endif
519       if (!ctrl->message_channel)
520         {
521           g_debug ("error creating message channel");
522           err = gpg_error (GPG_ERR_EIO);
523           goto leave;
524         }
525       g_io_channel_set_encoding (ctrl->message_channel, NULL, NULL);
526       g_io_channel_set_buffered (ctrl->message_channel, FALSE);
527     }
528 
529   if (ctrl->input_channel)
530     {
531       err = gpgme_data_new_from_cbs (r_input_data, &my_gpgme_data_cbs, ctrl);
532       if (err)
533         goto leave;
534     }
535   if (ctrl->output_channel)
536     {
537       err = gpgme_data_new_from_cbs (r_output_data, &my_gpgme_data_cbs, ctrl);
538       if (err)
539         goto leave;
540       if (ctrl->output_binary)
541         gpgme_data_set_encoding (*r_output_data, GPGME_DATA_ENCODING_BINARY);
542     }
543   if (ctrl->message_channel)
544     {
545       err = gpgme_data_new_from_cbs (r_message_data,
546 				     &my_gpgme_message_cbs, ctrl);
547       if (err)
548         goto leave;
549     }
550 
551   err = 0;
552 
553  leave:
554   if (err)
555     finish_io_streams (ctx, r_input_data, r_output_data, r_message_data);
556   return err;
557 }
558 
559 
560 
561 static const char hlp_session[] =
562   "SESSION <number> [<string>]\n"
563   "\n"
564   "The NUMBER is an arbitrary value, a server may use to associate\n"
565   "simultaneous running sessions.  It is a 32 bit unsigned integer\n"
566   "with 0 as a special value indicating that no session association\n"
567   "shall be done.\n"
568   "\n"
569   "If STRING is given, the server may use this as the title of a\n"
570   "window or, in the case of an email operation, to extract the\n"
571   "sender's address. The string may contain spaces; thus no\n"
572   "plus-escaping is used.\n"
573   "\n"
574   "This command may be used at any time and overrides the effect of\n"
575   "the last command.  A RESET command undoes the effect of this\n"
576   "command.";
577 static gpg_error_t
cmd_session(assuan_context_t ctx,char * line)578 cmd_session (assuan_context_t ctx, char *line)
579 {
580   conn_ctrl_t ctrl = assuan_get_pointer (ctx);
581   char *endp;
582 
583   line = skip_options (line);
584 
585   ctrl->session_number = strtoul (line, &endp, 10);
586   for (line = endp; spacep (line); line++)
587     ;
588   xfree (ctrl->session_title);
589   ctrl->session_title = *line? xstrdup (line) : NULL;
590 
591   return assuan_process_done (ctx, 0);
592 }
593 
594 
595 
596 static const char hlp_recipient[] =
597   "RECIPIENT <recipient>\n"
598   "\n"
599   "Set the recipient for the encryption.  <recipient> is an RFC2822\n"
600   "recipient name.  This command may or may not check the recipient for\n"
601   "validity right away; if it does not (as here) all recipients are\n"
602   "checked at the time of the ENCRYPT command.  All RECIPIENT commands\n"
603   "are cumulative until a RESET or an successful ENCRYPT command.";
604 static gpg_error_t
cmd_recipient(assuan_context_t ctx,char * line)605 cmd_recipient (assuan_context_t ctx, char *line)
606 {
607   conn_ctrl_t ctrl = assuan_get_pointer (ctx);
608   gpg_error_t err = 0;
609 
610   reset_prepared_keys (ctrl);
611 
612   if (*line)
613     ctrl->recipients = g_slist_append (ctrl->recipients, xstrdup (line));
614 
615   return assuan_process_done (ctx, err);
616 }
617 
618 
619 
620 static const char hlp_message[] =
621   "MESSAGE FD[=<n>]\n"
622   "\n"
623   "Set the file descriptor to read a message of a detached signature to N.";
624 static gpg_error_t
cmd_message(assuan_context_t ctx,char * line)625 cmd_message (assuan_context_t ctx, char *line)
626 {
627   conn_ctrl_t ctrl = assuan_get_pointer (ctx);
628   gpg_error_t err;
629   assuan_fd_t sysfd;
630   int fd;
631 
632   err = assuan_command_parse_fd (ctx, line, &sysfd);
633   if (!err)
634     {
635       fd = translate_sys2libc_fd (sysfd, 0);
636       if (fd == -1)
637         err = set_error (GPG_ERR_ASS_NO_INPUT, NULL);
638       else
639         ctrl->message_fd = fd;
640     }
641   return assuan_process_done (ctx, err);
642 }
643 
644 
645 
646 
647 
648 /* Continuation for cmd_encrypt.  */
649 static void
cont_encrypt(assuan_context_t ctx,gpg_error_t err)650 cont_encrypt (assuan_context_t ctx, gpg_error_t err)
651 {
652   conn_ctrl_t ctrl = assuan_get_pointer (ctx);
653 
654   g_debug ("cont_encrypt called with ERR=%s <%s>",
655            gpg_strerror (err), gpg_strsource (err));
656 
657   finish_io_streams (ctx, NULL, NULL, NULL);
658   if (!err)
659     release_recipients (ctrl);
660   assuan_process_done (ctx, err);
661 }
662 
663 
664 static const char hlp_encrypt[] =
665   "ENCRYPT --protocol=OpenPGP|CMS\n"
666   "\n"
667   "Encrypt the data received on INPUT to OUTPUT.";
668 static gpg_error_t
cmd_encrypt(assuan_context_t ctx,char * line)669 cmd_encrypt (assuan_context_t ctx, char *line)
670 {
671   conn_ctrl_t ctrl = assuan_get_pointer (ctx);
672   gpg_error_t err;
673   gpgme_protocol_t protocol = 0;
674   GpaStreamEncryptOperation *op;
675   gpgme_data_t input_data = NULL;
676   gpgme_data_t output_data = NULL;
677 
678   err = parse_protocol_option (ctx, line, 1, &protocol);
679   if (err)
680     goto leave;
681 
682   if (protocol != ctrl->selected_protocol)
683     {
684       if (ctrl->selected_protocol != GPGME_PROTOCOL_UNKNOWN)
685         g_debug ("note: protocol does not match the one from PREP_ENCRYPT");
686       reset_prepared_keys (ctrl);
687     }
688 
689   line = skip_options (line);
690   if (*line)
691     {
692       err = set_error (GPG_ERR_ASS_SYNTAX, NULL);
693       goto leave;
694     }
695 
696   err = translate_io_streams (ctx);
697   if (err)
698     goto leave;
699   err = prepare_io_streams (ctx, &input_data, &output_data, NULL);
700   if (err)
701     goto leave;
702 
703   ctrl->cont_cmd = cont_encrypt;
704   op = gpa_stream_encrypt_operation_new (NULL, input_data, output_data,
705                                          ctrl->recipients,
706                                          ctrl->recipient_keys,
707                                          protocol, 0);
708   input_data = output_data = NULL;
709   g_signal_connect_swapped (G_OBJECT (op), "completed",
710 			    G_CALLBACK (run_server_continuation), ctx);
711   g_signal_connect (G_OBJECT (op), "completed",
712                     G_CALLBACK (g_object_unref), NULL);
713   g_signal_connect_swapped (G_OBJECT (op), "status",
714 			    G_CALLBACK (assuan_write_status), ctx);
715 
716   return not_finished (ctrl);
717 
718  leave:
719   finish_io_streams (ctx, &input_data, &output_data, NULL);
720   close_message_fd (ctrl);
721   assuan_close_input_fd (ctx);
722   assuan_close_output_fd (ctx);
723   ctrl->input_fd = -1;
724   ctrl->output_fd = -1;
725   return assuan_process_done (ctx, err);
726 }
727 
728 
729 
730 /* Continuation for cmd_prep_encrypt.  */
731 static void
cont_prep_encrypt(assuan_context_t ctx,gpg_error_t err)732 cont_prep_encrypt (assuan_context_t ctx, gpg_error_t err)
733 {
734   conn_ctrl_t ctrl = assuan_get_pointer (ctx);
735 
736   g_debug ("cont_prep_encrypt called with ERR=%s <%s>",
737            gpg_strerror (err), gpg_strsource (err));
738 
739   if (!err)
740     {
741       release_keys (ctrl->recipient_keys);
742       ctrl->recipient_keys = gpa_stream_encrypt_operation_get_keys
743         (GPA_STREAM_ENCRYPT_OPERATION (ctrl->gpa_op),
744          &ctrl->selected_protocol);
745 
746       if (ctrl->recipient_keys)
747         g_print ("received some keys\n");
748       else
749         g_print ("received no keys\n");
750     }
751 
752   if (ctrl->gpa_op)
753     {
754       g_object_unref (ctrl->gpa_op);
755       ctrl->gpa_op = NULL;
756     }
757   assuan_process_done (ctx, err);
758 }
759 
760 static const char hlp_prep_encrypt[] =
761   "PREP_ENCRYPT [--protocol=OpenPGP|CMS]\n"
762   "\n"
763   "Dummy encryption command used to check whether the given recipients\n"
764   "are all valid and to tell the client the preferred protocol.";
765 static gpg_error_t
cmd_prep_encrypt(assuan_context_t ctx,char * line)766 cmd_prep_encrypt (assuan_context_t ctx, char *line)
767 {
768   conn_ctrl_t ctrl = assuan_get_pointer (ctx);
769   gpg_error_t err;
770   gpgme_protocol_t protocol;
771   GpaStreamEncryptOperation *op;
772 
773   err = parse_protocol_option (ctx, line, 0, &protocol);
774   if (err)
775     goto leave;
776 
777   line = skip_options (line);
778   if (*line)
779     {
780       err = set_error (GPG_ERR_ASS_SYNTAX, NULL);
781       goto leave;
782     }
783 
784   reset_prepared_keys (ctrl);
785 
786   if (ctrl->gpa_op)
787     {
788       g_debug ("Oops: there is still an GPA_OP active\n");
789       g_object_unref (ctrl->gpa_op);
790       ctrl->gpa_op = NULL;
791     }
792   ctrl->cont_cmd = cont_prep_encrypt;
793   op = gpa_stream_encrypt_operation_new (NULL, NULL, NULL,
794                                          ctrl->recipients,
795                                          ctrl->recipient_keys,
796                                          protocol, 0);
797   /* Store that instance for later use but also install a signal
798      handler to unref it.  */
799   g_object_ref (op);
800   ctrl->gpa_op = GPA_OPERATION (op);
801   g_signal_connect_swapped (G_OBJECT (op), "completed",
802 			    G_CALLBACK (run_server_continuation), ctx);
803   g_signal_connect (G_OBJECT (op), "completed",
804                     G_CALLBACK (g_object_unref), NULL);
805   g_signal_connect_swapped (G_OBJECT (op), "status",
806 			    G_CALLBACK (assuan_write_status), ctx);
807 
808   return not_finished (ctrl);
809 
810  leave:
811   return assuan_process_done (ctx, err);
812 }
813 
814 
815 
816 static const char hlp_sender[] =
817   "SENDER <email>\n"
818   "\n"
819   "EMAIL is the plain ASCII encoded address (\"addr-spec\" as per\n"
820   "RFC-2822) enclosed in angle brackets.  The address set by this\n"
821   "command is valid until a successful \"SIGN\" command or until a\n"
822   "\"RESET\" command.  A second command overrides the effect of\n"
823   "the first one; if EMAIL is not given the server shall use the\n"
824   "default signing key.";
825 static gpg_error_t
cmd_sender(assuan_context_t ctx,char * line)826 cmd_sender (assuan_context_t ctx, char *line)
827 {
828   conn_ctrl_t ctrl = assuan_get_pointer (ctx);
829   gpg_error_t err;
830   gpgme_protocol_t protocol;
831 
832   err = parse_protocol_option (ctx, line, 0, &protocol);
833   if (err)
834     goto leave;
835 
836   ctrl->sender_just_info = has_option (line, "--info");
837 
838   line = skip_options (line);
839 
840   xfree (ctrl->sender);
841   ctrl->sender = NULL;
842   if (*line)
843     ctrl->sender = xstrdup (line);
844 
845   if (!err)
846     ctrl->sender_protocol_hint = protocol;
847 
848  leave:
849   return assuan_process_done (ctx, err);
850 }
851 
852 
853 
854 /* Continuation for cmd_sign.  */
855 static void
cont_sign(assuan_context_t ctx,gpg_error_t err)856 cont_sign (assuan_context_t ctx, gpg_error_t err)
857 {
858   conn_ctrl_t ctrl = assuan_get_pointer (ctx);
859 
860   g_debug ("cont_sign called with ERR=%s <%s>",
861            gpg_strerror (err), gpg_strsource (err));
862 
863   finish_io_streams (ctx, NULL, NULL, NULL);
864   if (!err)
865     {
866       xfree (ctrl->sender);
867       ctrl->sender = NULL;
868       ctrl->sender_protocol_hint = GPGME_PROTOCOL_UNKNOWN;
869     }
870   assuan_process_done (ctx, err);
871 }
872 
873 
874 static const char hlp_sign[] =
875   "SIGN --protocol=OpenPGP|CMS [--detached]\n"
876   "\n"
877   "Sign the data received on INPUT to OUTPUT.";
878 static gpg_error_t
cmd_sign(assuan_context_t ctx,char * line)879 cmd_sign (assuan_context_t ctx, char *line)
880 {
881   conn_ctrl_t ctrl = assuan_get_pointer (ctx);
882   gpg_error_t err;
883   gpgme_protocol_t protocol;
884   gboolean detached;
885   GpaStreamSignOperation *op;
886   gpgme_data_t input_data = NULL;
887   gpgme_data_t output_data = NULL;
888 
889   err = parse_protocol_option (ctx, line, 1, &protocol);
890   if (err)
891     goto leave;
892 
893   detached = has_option (line, "--detached");
894 
895   line = skip_options (line);
896   if (*line)
897     {
898       err = set_error (GPG_ERR_ASS_SYNTAX, NULL);
899       goto leave;
900     }
901 
902   err = translate_io_streams (ctx);
903   if (err)
904     goto leave;
905   err = prepare_io_streams (ctx, &input_data, &output_data, NULL);
906   if (err)
907     goto leave;
908 
909   ctrl->cont_cmd = cont_sign;
910   op = gpa_stream_sign_operation_new (NULL, input_data, output_data,
911                                       ctrl->sender, protocol, detached);
912   input_data = output_data = NULL;
913   g_signal_connect_swapped (G_OBJECT (op), "completed",
914 			    G_CALLBACK (run_server_continuation), ctx);
915   g_signal_connect (G_OBJECT (op), "completed",
916                     G_CALLBACK (g_object_unref), NULL);
917   g_signal_connect_swapped (G_OBJECT (op), "status",
918 			    G_CALLBACK (assuan_write_status), ctx);
919 
920   return not_finished (ctrl);
921 
922  leave:
923   finish_io_streams (ctx, &input_data, &output_data, NULL);
924   close_message_fd (ctrl);
925   assuan_close_input_fd (ctx);
926   assuan_close_output_fd (ctx);
927   ctrl->input_fd = -1;
928   ctrl->output_fd = -1;
929   return assuan_process_done (ctx, err);
930 }
931 
932 
933 
934 /* Continuation for cmd_decrypt.  */
935 static void
cont_decrypt(assuan_context_t ctx,gpg_error_t err)936 cont_decrypt (assuan_context_t ctx, gpg_error_t err)
937 {
938   g_debug ("cont_decrypt called with ERR=%s <%s>",
939            gpg_strerror (err), gpg_strsource (err));
940 
941   finish_io_streams (ctx, NULL, NULL, NULL);
942   assuan_process_done (ctx, err);
943 }
944 
945 
946 static const char hlp_decrypt[] =
947   "DECRYPT --protocol=OpenPGP|CMS [--no-verify]\n"
948   "\n"
949   "Decrypt a message given by the source set with the INPUT command\n"
950   "and write the plaintext to the sink set with the OUTPUT command.\n"
951   "\n"
952   "If the option --no-verify is given, the server should not try to\n"
953   "verify a signature, in case the input data is an OpenPGP combined\n"
954   "message.";
955 static gpg_error_t
cmd_decrypt(assuan_context_t ctx,char * line)956 cmd_decrypt (assuan_context_t ctx, char *line)
957 {
958   conn_ctrl_t ctrl = assuan_get_pointer (ctx);
959   gpg_error_t err;
960   gpgme_protocol_t protocol = 0;
961   int no_verify;
962   GpaStreamDecryptOperation *op;
963   gpgme_data_t input_data = NULL;
964   gpgme_data_t output_data = NULL;
965 
966   err = parse_protocol_option (ctx, line, 1, &protocol);
967   if (err)
968     goto leave;
969 
970   no_verify = has_option (line, "--no-verify");
971 
972   line = skip_options (line);
973   if (*line)
974     {
975       err = set_error (GPG_ERR_ASS_SYNTAX, NULL);
976       goto leave;
977     }
978 
979   err = translate_io_streams (ctx);
980   if (err)
981     goto leave;
982   err = prepare_io_streams (ctx, &input_data, &output_data, NULL);
983   if (err)
984     goto leave;
985 
986   ctrl->cont_cmd = cont_decrypt;
987 
988   op = gpa_stream_decrypt_operation_new (NULL, input_data, output_data,
989 					 no_verify, protocol,
990                                          ctrl->session_title);
991 
992   input_data = output_data = NULL;
993   g_signal_connect_swapped (G_OBJECT (op), "completed",
994 			    G_CALLBACK (run_server_continuation), ctx);
995   g_signal_connect (G_OBJECT (op), "completed",
996                     G_CALLBACK (g_object_unref), NULL);
997   g_signal_connect_swapped (G_OBJECT (op), "status",
998 			    G_CALLBACK (assuan_write_status), ctx);
999 
1000   return not_finished (ctrl);
1001 
1002  leave:
1003   finish_io_streams (ctx, &input_data, &output_data, NULL);
1004   close_message_fd (ctrl);
1005   assuan_close_input_fd (ctx);
1006   assuan_close_output_fd (ctx);
1007   ctrl->input_fd = -1;
1008   ctrl->output_fd = -1;
1009   return assuan_process_done (ctx, err);
1010 }
1011 
1012 
1013 
1014 
1015 /* Continuation for cmd_verify.  */
1016 static void
cont_verify(assuan_context_t ctx,gpg_error_t err)1017 cont_verify (assuan_context_t ctx, gpg_error_t err)
1018 {
1019   g_debug ("cont_verify called with ERR=%s <%s>",
1020            gpg_strerror (err), gpg_strsource (err));
1021 
1022   finish_io_streams (ctx, NULL, NULL, NULL);
1023   assuan_process_done (ctx, err);
1024 }
1025 
1026 
1027 static const char hlp_verify[] =
1028   "VERIFY --protocol=OpenPGP|CMS [--silent]\n"
1029   "\n"
1030   "Verify a message.  Depending on the combination of the\n"
1031   "sources/sinks set by the commands MESSAGE, INPUT and OUTPUT, the\n"
1032   "verification mode is selected like this:\n"
1033   "\n"
1034   "MESSAGE and INPUT\n"
1035   "  This indicates a detached signature.  Output data is not applicable.\n"
1036   "\n"
1037   "INPUT \n"
1038   "  This indicates an opaque signature.  As no output command has\n"
1039   "  been given, we are only required to check the signature.\n"
1040   "\n"
1041   "INPUT and OUTPUT\n"
1042   "  This indicates an opaque signature.  We write the signed data to\n"
1043   "  the file descriptor set by the OUTPUT command.  This data is even\n"
1044   "  written if the signature can't be verified.\n"
1045   "\n"
1046   "With the option --silent we won't display any dialog; this is for\n"
1047   "example used by the client to get the content of an opaque signed\n"
1048   "message.  This status message is always send before an OK response:\n"
1049   "\n"
1050   "   SIGSTATUS <flag> <displaystring>\n"
1051   "\n"
1052   "Defined FLAGS are:\n"
1053   "\n"
1054   "   none\n"
1055   "     The message has a signature but it could not not be verified\n"
1056   "     due to a missing key.\n"
1057   "\n"
1058   "   green\n"
1059   "     The signature is fully valid.\n"
1060   "\n"
1061   "   yellow\n"
1062   "     The signature is valid but additional information was shown\n"
1063   "     regarding the validity of the key.\n"
1064   "\n"
1065   "   red\n"
1066   "     The signature is not valid. \n"
1067   "\n"
1068   "The DISPLAYSTRING is a percent-and-plus-encoded string with a short\n"
1069   "human readable description of the status.";
1070 static gpg_error_t
cmd_verify(assuan_context_t ctx,char * line)1071 cmd_verify (assuan_context_t ctx, char *line)
1072 {
1073   conn_ctrl_t ctrl = assuan_get_pointer (ctx);
1074   gpg_error_t err;
1075   gpgme_protocol_t protocol = 0;
1076   int silent;
1077   GpaStreamVerifyOperation *op;
1078   gpgme_data_t input_data = NULL;
1079   gpgme_data_t output_data = NULL;
1080   gpgme_data_t message_data = NULL;
1081   enum { VERIFY_DETACH, VERIFY_OPAQUE, VERIFY_OPAQUE_WITH_OUTPUT } op_mode;
1082 
1083   err = parse_protocol_option (ctx, line, 1, &protocol);
1084   if (err)
1085     goto leave;
1086 
1087   silent = has_option (line, "--silent");
1088 
1089   line = skip_options (line);
1090   if (*line)
1091     {
1092       err = set_error (GPG_ERR_ASS_SYNTAX, NULL);
1093       goto leave;
1094     }
1095 
1096   /* Note: We can't use translate_io_streams because that returns an
1097      error if one is not opened but that is not an error here.  */
1098   ctrl->input_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
1099   ctrl->output_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
1100   if (ctrl->message_fd != -1 && ctrl->input_fd != -1
1101       && ctrl->output_fd == -1)
1102     op_mode = VERIFY_DETACH;
1103   else if (ctrl->message_fd == -1 && ctrl->input_fd != -1
1104            && ctrl->output_fd == -1)
1105     op_mode = VERIFY_OPAQUE;
1106   else if (ctrl->message_fd == -1 && ctrl->input_fd != -1
1107            && ctrl->output_fd != -1)
1108     op_mode = VERIFY_OPAQUE_WITH_OUTPUT;
1109   else
1110     {
1111       err = set_error (GPG_ERR_CONFLICT, "invalid verify mode");
1112       goto leave;
1113     }
1114 
1115   err = prepare_io_streams (ctx, &input_data, &output_data, &message_data);
1116   if (! err && op_mode == VERIFY_OPAQUE)
1117     err = gpgme_data_new_from_cbs (&output_data, &my_devnull_data_cbs, ctrl);
1118   if (err)
1119     goto leave;
1120 
1121   ctrl->cont_cmd = cont_verify;
1122 
1123   op = gpa_stream_verify_operation_new (NULL, input_data, message_data,
1124 					output_data, silent, protocol,
1125                                         ctrl->session_title);
1126 
1127   input_data = output_data = message_data = NULL;
1128   g_signal_connect_swapped (G_OBJECT (op), "completed",
1129 			    G_CALLBACK (run_server_continuation), ctx);
1130   g_signal_connect (G_OBJECT (op), "completed",
1131                     G_CALLBACK (g_object_unref), NULL);
1132   g_signal_connect_swapped (G_OBJECT (op), "status",
1133 			    G_CALLBACK (assuan_write_status), ctx);
1134 
1135   return not_finished (ctrl);
1136 
1137  leave:
1138   finish_io_streams (ctx, &input_data, &output_data, &message_data);
1139   close_message_fd (ctrl);
1140   assuan_close_input_fd (ctx);
1141   assuan_close_output_fd (ctx);
1142   ctrl->input_fd = -1;
1143   ctrl->output_fd = -1;
1144   return assuan_process_done (ctx, err);
1145 }
1146 
1147 
1148 
1149 static const char hlp_start_keymanager[] =
1150   "START_KEYMANAGER\n"
1151   "\n"
1152   "Pop up the key manager window.  The client expects that the key\n"
1153   "manager is brought into the foregound and that this command\n"
1154   "immediatley returns.";
1155 static gpg_error_t
cmd_start_keymanager(assuan_context_t ctx,char * line)1156 cmd_start_keymanager (assuan_context_t ctx, char *line)
1157 {
1158   gpa_open_key_manager (NULL, NULL);
1159 
1160   return assuan_process_done (ctx, 0);
1161 }
1162 
1163 static const char hlp_start_clipboard[] =
1164   "START_CLIPBOARD\n"
1165   "\n"
1166   "Pop up the clipboard window.  The client expects that the\n"
1167   "clipboard is brought into the foregound and that this command\n"
1168   "immediatley returns.";
1169 static gpg_error_t
cmd_start_clipboard(assuan_context_t ctx,char * line)1170 cmd_start_clipboard (assuan_context_t ctx, char *line)
1171 {
1172   gpa_open_clipboard (NULL, NULL);
1173 
1174   return assuan_process_done (ctx, 0);
1175 }
1176 
1177 static const char hlp_start_filemanager[] =
1178   "START_FILEMANAGER\n"
1179   "\n"
1180   "Pop up the file manager window.  The client expects that the file\n"
1181   "manager is brought into the foregound and that this command\n"
1182   "immediatley returns.";
1183 static gpg_error_t
cmd_start_filemanager(assuan_context_t ctx,char * line)1184 cmd_start_filemanager (assuan_context_t ctx, char *line)
1185 {
1186   gpa_open_filemanager (NULL, NULL);
1187 
1188   return assuan_process_done (ctx, 0);
1189 }
1190 
1191 
1192 #ifdef ENABLE_CARD_MANAGER
1193 static const char hlp_start_cardmanager[] =
1194   "START_CARDMANAGER\n"
1195   "\n"
1196   "Pop up the card manager window.  The client expects that the key\n"
1197   "manager is brought into the foregound and that this command\n"
1198   "immediatley returns.";
1199 static gpg_error_t
cmd_start_cardmanager(assuan_context_t ctx,char * line)1200 cmd_start_cardmanager (assuan_context_t ctx, char *line)
1201 {
1202   gpa_open_cardmanager (NULL, NULL);
1203 
1204   return assuan_process_done (ctx, 0);
1205 }
1206 #endif /*ENABLE_CARD_MANAGER*/
1207 
1208 static const char hlp_start_confdialog[] =
1209   "START_CONFDIALOG\n"
1210   "\n"
1211   "Pop up the configure dialog.  The client expects that the key\n"
1212   "manager is brought into the foregound and that this command\n"
1213   "immediatley returns.";
1214 static gpg_error_t
cmd_start_confdialog(assuan_context_t ctx,char * line)1215 cmd_start_confdialog (assuan_context_t ctx, char *line)
1216 {
1217   gpa_open_settings_dialog (NULL, NULL);
1218 
1219   return assuan_process_done (ctx, 0);
1220 }
1221 
1222 
1223 
1224 
1225 static const char hlp_getinfo[] =
1226   "GETINFO <what>\n"
1227   "\n"
1228   "Multipurpose function to return a variety of information.\n"
1229   "Supported values for WHAT are:\n"
1230   "\n"
1231   "  version     - Return the version of the program.\n"
1232   "  name        - Return the name of the program\n"
1233   "  pid         - Return the process id of the server.";
1234 static gpg_error_t
cmd_getinfo(assuan_context_t ctx,char * line)1235 cmd_getinfo (assuan_context_t ctx, char *line)
1236 {
1237   gpg_error_t err;
1238 
1239   if (!strcmp (line, "version"))
1240     {
1241       const char *s = PACKAGE_NAME " " PACKAGE_VERSION;
1242       err = assuan_send_data (ctx, s, strlen (s));
1243     }
1244   else if (!strcmp (line, "pid"))
1245     {
1246       char numbuf[50];
1247 
1248       snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
1249       err = assuan_send_data (ctx, numbuf, strlen (numbuf));
1250     }
1251   else if (!strcmp (line, "name"))
1252     {
1253       const char *s = PACKAGE_NAME;
1254       err = assuan_send_data (ctx, s, strlen (s));
1255     }
1256   else
1257     err = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
1258 
1259   return assuan_process_done (ctx, err);
1260 }
1261 
1262 
1263 static const char hlp_file[] =
1264   "FILE [--clear] <file>\n"
1265   "\n"
1266   "Add FILE to the list of files on which to operate.\n"
1267   "With --clear given, that list is first cleared.";
1268 static gpg_error_t
cmd_file(assuan_context_t ctx,char * line)1269 cmd_file (assuan_context_t ctx, char *line)
1270 {
1271   gpg_error_t err = 0;
1272   conn_ctrl_t ctrl = assuan_get_pointer (ctx);
1273   gboolean clear;
1274   gpa_file_item_t file_item;
1275   char *tail;
1276 
1277   clear = has_option (line, "--clear");
1278   line = skip_options (line);
1279 
1280   if (clear)
1281     release_files (ctrl);
1282 
1283   tail = line;
1284   while (*tail && ! spacep (tail))
1285     tail++;
1286   *tail = '\0';
1287   decode_percent_string (line);
1288 
1289   file_item = g_malloc0 (sizeof (*file_item));
1290   file_item->filename_in = g_strdup (line);
1291   ctrl->files = g_list_append (ctrl->files, file_item);
1292 
1293   return assuan_process_done (ctx, err);
1294 }
1295 
1296 
1297 /* Encrypt or sign files.  If neither ENCR nor SIGN is set, import
1298    files. */
1299 static gpg_error_t
impl_encrypt_sign_files(assuan_context_t ctx,int encr,int sign)1300 impl_encrypt_sign_files (assuan_context_t ctx, int encr, int sign)
1301 {
1302   gpg_error_t err = 0;
1303   conn_ctrl_t ctrl = assuan_get_pointer (ctx);
1304   GpaFileOperation *op;
1305 
1306   if (! ctrl->files)
1307     {
1308       err = set_error (GPG_ERR_ASS_SYNTAX, "no files specified");
1309       return assuan_process_done (ctx, err);
1310     }
1311 
1312   /* FIXME: Needs a root window.  Need to set "sign" default.  */
1313   if (encr && sign)
1314     op = (GpaFileOperation *)
1315       gpa_file_encrypt_sign_operation_new (NULL, ctrl->files, FALSE);
1316   else if (encr)
1317     op = (GpaFileOperation *)
1318       gpa_file_encrypt_operation_new (NULL, ctrl->files, FALSE);
1319   else if (sign)
1320     op = (GpaFileOperation *)
1321       gpa_file_sign_operation_new (NULL, ctrl->files, FALSE);
1322   else
1323     op = (GpaFileOperation *)
1324       gpa_file_import_operation_new (NULL, ctrl->files);
1325 
1326   /* Ownership of CTRL->files was passed to callee.  */
1327   ctrl->files = NULL;
1328   g_signal_connect (G_OBJECT (op), "completed",
1329 		    G_CALLBACK (g_object_unref), NULL);
1330 
1331   return assuan_process_done (ctx, err);
1332 }
1333 
1334 
1335 /* ENCRYPT_FILES --nohup  */
1336 static gpg_error_t
cmd_encrypt_files(assuan_context_t ctx,char * line)1337 cmd_encrypt_files (assuan_context_t ctx, char *line)
1338 {
1339   gpg_error_t err;
1340 
1341   if (! has_option (line, "--nohup"))
1342     {
1343       err = set_error (GPG_ERR_ASS_PARAMETER, "file ops require --nohup");
1344       return assuan_process_done (ctx, err);
1345     }
1346 
1347   line = skip_options (line);
1348   if (*line)
1349     {
1350       err = set_error (GPG_ERR_ASS_SYNTAX, NULL);
1351       return assuan_process_done (ctx, err);
1352     }
1353 
1354   return impl_encrypt_sign_files (ctx, 1, 0);
1355 }
1356 
1357 
1358 /* SIGN_FILES --nohup  */
1359 static gpg_error_t
cmd_sign_files(assuan_context_t ctx,char * line)1360 cmd_sign_files (assuan_context_t ctx, char *line)
1361 {
1362   gpg_error_t err;
1363 
1364   if (! has_option (line, "--nohup"))
1365     {
1366       err = set_error (GPG_ERR_ASS_PARAMETER, "file ops require --nohup");
1367       return assuan_process_done (ctx, err);
1368     }
1369 
1370   line = skip_options (line);
1371   if (*line)
1372     {
1373       err = set_error (GPG_ERR_ASS_SYNTAX, NULL);
1374       return assuan_process_done (ctx, err);
1375     }
1376 
1377   return impl_encrypt_sign_files (ctx, 0, 1);
1378 }
1379 
1380 
1381 /* ENCRYPT_SIGN_FILES --nohup  */
1382 static gpg_error_t
cmd_encrypt_sign_files(assuan_context_t ctx,char * line)1383 cmd_encrypt_sign_files (assuan_context_t ctx, char *line)
1384 {
1385   gpg_error_t err;
1386 
1387   if (! has_option (line, "--nohup"))
1388     {
1389       err = set_error (GPG_ERR_ASS_PARAMETER, "file ops require --nohup");
1390       return assuan_process_done (ctx, err);
1391     }
1392 
1393   line = skip_options (line);
1394   if (*line)
1395     {
1396       err = set_error (GPG_ERR_ASS_SYNTAX, NULL);
1397       return assuan_process_done (ctx, err);
1398     }
1399 
1400   return impl_encrypt_sign_files (ctx, 1, 1);
1401 }
1402 
1403 
1404 static gpg_error_t
impl_decrypt_verify_files(assuan_context_t ctx,int decrypt,int verify)1405 impl_decrypt_verify_files (assuan_context_t ctx, int decrypt, int verify)
1406 {
1407   gpg_error_t err = 0;
1408   conn_ctrl_t ctrl = assuan_get_pointer (ctx);
1409   GpaFileOperation *op;
1410 
1411   if (! ctrl->files)
1412     {
1413       err = set_error (GPG_ERR_ASS_SYNTAX, "no files specified");
1414       return assuan_process_done (ctx, err);
1415     }
1416 
1417   /* FIXME: Needs a root window.  Need to enable "verify".  */
1418   if (decrypt && verify)
1419     op = (GpaFileOperation *)
1420       gpa_file_decrypt_verify_operation_new (NULL, ctrl->files);
1421   else if (decrypt)
1422     op = (GpaFileOperation *)
1423       gpa_file_decrypt_operation_new (NULL, ctrl->files);
1424   else
1425     op = (GpaFileOperation *)
1426       gpa_file_verify_operation_new (NULL, ctrl->files);
1427 
1428   /* Ownership of CTRL->files was passed to callee.  */
1429   ctrl->files = NULL;
1430   g_signal_connect (G_OBJECT (op), "completed",
1431 		    G_CALLBACK (g_object_unref), NULL);
1432 
1433   return assuan_process_done (ctx, err);
1434 }
1435 
1436 
1437 /* DECRYPT_FILES --nohup  */
1438 static gpg_error_t
cmd_decrypt_files(assuan_context_t ctx,char * line)1439 cmd_decrypt_files (assuan_context_t ctx, char *line)
1440 {
1441   gpg_error_t err;
1442 
1443   if (! has_option (line, "--nohup"))
1444     {
1445       err = set_error (GPG_ERR_ASS_PARAMETER, "file ops require --nohup");
1446       return assuan_process_done (ctx, err);
1447     }
1448 
1449   line = skip_options (line);
1450   if (*line)
1451     {
1452       err = set_error (GPG_ERR_ASS_SYNTAX, NULL);
1453       return assuan_process_done (ctx, err);
1454     }
1455 
1456   return impl_decrypt_verify_files (ctx, 1, 0);
1457 }
1458 
1459 
1460 /* VERIFY_FILES --nohup  */
1461 static gpg_error_t
cmd_verify_files(assuan_context_t ctx,char * line)1462 cmd_verify_files (assuan_context_t ctx, char *line)
1463 {
1464   gpg_error_t err;
1465 
1466   if (! has_option (line, "--nohup"))
1467     {
1468       err = set_error (GPG_ERR_ASS_PARAMETER, "file ops require --nohup");
1469       return assuan_process_done (ctx, err);
1470     }
1471 
1472   line = skip_options (line);
1473   if (*line)
1474     {
1475       err = set_error (GPG_ERR_ASS_SYNTAX, NULL);
1476       return assuan_process_done (ctx, err);
1477     }
1478 
1479   return impl_decrypt_verify_files (ctx, 0, 1);
1480 }
1481 
1482 
1483 /* DECRYPT_VERIFY_FILES --nohup  */
1484 static gpg_error_t
cmd_decrypt_verify_files(assuan_context_t ctx,char * line)1485 cmd_decrypt_verify_files (assuan_context_t ctx, char *line)
1486 {
1487   gpg_error_t err;
1488 
1489   if (! has_option (line, "--nohup"))
1490     {
1491       err = set_error (GPG_ERR_ASS_PARAMETER, "file ops require --nohup");
1492       return assuan_process_done (ctx, err);
1493     }
1494 
1495   line = skip_options (line);
1496   if (*line)
1497     {
1498       err = set_error (GPG_ERR_ASS_SYNTAX, NULL);
1499       return assuan_process_done (ctx, err);
1500     }
1501 
1502   return impl_decrypt_verify_files (ctx, 1, 1);
1503 }
1504 
1505 
1506 /* IMPORT_FILES --nohup  */
1507 static gpg_error_t
cmd_import_files(assuan_context_t ctx,char * line)1508 cmd_import_files (assuan_context_t ctx, char *line)
1509 {
1510   gpg_error_t err;
1511 
1512   if (! has_option (line, "--nohup"))
1513     {
1514       err = set_error (GPG_ERR_ASS_PARAMETER, "file ops require --nohup");
1515       return assuan_process_done (ctx, err);
1516     }
1517 
1518   line = skip_options (line);
1519   if (*line)
1520     {
1521       err = set_error (GPG_ERR_ASS_SYNTAX, NULL);
1522       return assuan_process_done (ctx, err);
1523     }
1524 
1525   return impl_encrypt_sign_files (ctx, 0, 0);
1526 }
1527 
1528 
1529 
1530 /* CHECKSUM_CREATE_FILES --nohup  */
1531 static gpg_error_t
cmd_checksum_create_files(assuan_context_t ctx,char * line)1532 cmd_checksum_create_files (assuan_context_t ctx, char *line)
1533 {
1534   gpg_error_t err;
1535 
1536   if (! has_option (line, "--nohup"))
1537     {
1538       err = set_error (GPG_ERR_ASS_PARAMETER, "file ops require --nohup");
1539       return assuan_process_done (ctx, err);
1540     }
1541 
1542   line = skip_options (line);
1543   if (*line)
1544     {
1545       err = set_error (GPG_ERR_ASS_SYNTAX, NULL);
1546       return assuan_process_done (ctx, err);
1547     }
1548 
1549   err = set_error (GPG_ERR_NOT_IMPLEMENTED, "not implemented");
1550   return assuan_process_done (ctx, err);
1551 }
1552 
1553 
1554 /* CHECKSUM_VERIFY_FILES --nohup  */
1555 static gpg_error_t
cmd_checksum_verify_files(assuan_context_t ctx,char * line)1556 cmd_checksum_verify_files (assuan_context_t ctx, char *line)
1557 {
1558   gpg_error_t err;
1559 
1560   if (! has_option (line, "--nohup"))
1561     {
1562       err = set_error (GPG_ERR_ASS_PARAMETER, "file ops require --nohup");
1563       return assuan_process_done (ctx, err);
1564     }
1565 
1566   line = skip_options (line);
1567   if (*line)
1568     {
1569       err = set_error (GPG_ERR_ASS_SYNTAX, NULL);
1570       return assuan_process_done (ctx, err);
1571     }
1572 
1573   err = set_error (GPG_ERR_NOT_IMPLEMENTED, "not implemented");
1574   return assuan_process_done (ctx, err);
1575 }
1576 
1577 
1578 
1579 /* KILL_UISERVER  */
1580 static gpg_error_t
cmd_kill_uiserver(assuan_context_t ctx,char * line)1581 cmd_kill_uiserver (assuan_context_t ctx, char *line)
1582 {
1583   (void)line;
1584   shutdown_pending = TRUE;
1585   return assuan_process_done (ctx, 0);
1586 }
1587 
1588 
1589 
1590 static gpg_error_t
reset_notify(assuan_context_t ctx,char * line)1591 reset_notify (assuan_context_t ctx, char *line)
1592 {
1593   conn_ctrl_t ctrl = assuan_get_pointer (ctx);
1594 
1595   reset_prepared_keys (ctrl);
1596   release_recipients (ctrl);
1597   release_files (ctrl);
1598   xfree (ctrl->sender);
1599   ctrl->sender = NULL;
1600   ctrl->sender_protocol_hint = GPGME_PROTOCOL_UNKNOWN;
1601   finish_io_streams (ctx, NULL, NULL, NULL);
1602   close_message_fd (ctrl);
1603   assuan_close_input_fd (ctx);
1604   assuan_close_output_fd (ctx);
1605   ctrl->input_fd = -1;
1606   ctrl->output_fd = -1;
1607   ctrl->output_binary = 0;
1608   if (ctrl->gpa_op)
1609     {
1610       g_object_unref (ctrl->gpa_op);
1611       ctrl->gpa_op = NULL;
1612     }
1613   ctrl->session_number = 0;
1614   xfree (ctrl->session_title);
1615   ctrl->session_title = NULL;
1616   return 0;
1617 }
1618 
1619 
1620 static gpg_error_t
output_notify(assuan_context_t ctx,char * line)1621 output_notify (assuan_context_t ctx, char *line)
1622 {
1623   conn_ctrl_t ctrl = assuan_get_pointer (ctx);
1624 
1625   if (strstr (line, "--binary"))
1626     ctrl->output_binary = 1;
1627   else
1628     ctrl->output_binary = 0;
1629   /* Note: We also allow --armor and --base64 but because we don't
1630      check for errors we don't need to parse them.  */
1631   return 0;
1632 }
1633 
1634 
1635 
1636 /* Tell libassuan about our commands.   */
1637 static int
register_commands(assuan_context_t ctx)1638 register_commands (assuan_context_t ctx)
1639 {
1640   static struct {
1641     const char *name;
1642     assuan_handler_t handler;
1643     const char * const help;
1644   } table[] = {
1645     { "SESSION", cmd_session, hlp_session },
1646     { "RECIPIENT", cmd_recipient, hlp_recipient },
1647     { "INPUT", NULL },
1648     { "OUTPUT", NULL },
1649     { "MESSAGE", cmd_message, hlp_message },
1650     { "ENCRYPT", cmd_encrypt, hlp_encrypt },
1651     { "PREP_ENCRYPT", cmd_prep_encrypt, hlp_prep_encrypt },
1652     { "SENDER", cmd_sender, hlp_sender },
1653     { "SIGN", cmd_sign, hlp_sign },
1654     { "DECRYPT", cmd_decrypt, hlp_decrypt },
1655     { "VERIFY", cmd_verify, hlp_verify },
1656     { "START_KEYMANAGER", cmd_start_keymanager, hlp_start_keymanager },
1657     { "START_CLIPBOARD", cmd_start_clipboard, hlp_start_clipboard },
1658     { "START_FILEMANAGER", cmd_start_filemanager, hlp_start_filemanager },
1659 #ifdef ENABLE_CARD_MANAGER
1660     { "START_CARDMANAGER", cmd_start_cardmanager, hlp_start_cardmanager },
1661 #endif /*ENABLE_CARD_MANAGER*/
1662     { "START_CONFDIALOG", cmd_start_confdialog, hlp_start_confdialog },
1663     { "GETINFO", cmd_getinfo, hlp_getinfo },
1664     { "FILE", cmd_file, hlp_file },
1665     { "ENCRYPT_FILES", cmd_encrypt_files },
1666     { "SIGN_FILES", cmd_sign_files },
1667     { "ENCRYPT_SIGN_FILES", cmd_encrypt_sign_files },
1668     { "DECRYPT_FILES", cmd_decrypt_files },
1669     { "VERIFY_FILES", cmd_verify_files },
1670     { "DECRYPT_VERIFY_FILES", cmd_decrypt_verify_files },
1671     { "IMPORT_FILES", cmd_import_files },
1672     { "CHECKSUM_CREATE_FILES", cmd_checksum_create_files },
1673     { "CHECKSUM_VERIFY_FILES", cmd_checksum_verify_files },
1674     { "KILL_UISERVER", cmd_kill_uiserver },
1675     { NULL }
1676   };
1677   int i, rc;
1678 
1679   for (i=0; table[i].name; i++)
1680     {
1681       rc = assuan_register_command (ctx, table[i].name, table[i].handler,
1682 				    table[i].help);
1683       if (rc)
1684         return rc;
1685     }
1686 
1687   return 0;
1688 }
1689 
1690 
1691 /* Prepare for a new connection on descriptor FD.  */
1692 static assuan_context_t
connection_startup(assuan_fd_t fd)1693 connection_startup (assuan_fd_t fd)
1694 {
1695   gpg_error_t err;
1696   assuan_context_t ctx;
1697   conn_ctrl_t ctrl;
1698 
1699   /* Get an Assuan context for the already accepted file descriptor
1700      FD.  Allow descriptor passing.  */
1701   err = assuan_new (&ctx);
1702   if (err)
1703     {
1704       g_debug ("failed to initialize the new connection: %s",
1705                gpg_strerror (err));
1706       return NULL;
1707     }
1708 
1709   err = assuan_init_socket_server (ctx, fd, (ASSUAN_SOCKET_SERVER_FDPASSING
1710                                              | ASSUAN_SOCKET_SERVER_ACCEPTED));
1711   if (err)
1712     {
1713       g_debug ("failed to initialize the new connection: %s",
1714                gpg_strerror (err));
1715       return NULL;
1716     }
1717   err = register_commands (ctx);
1718   if (err)
1719     {
1720       g_debug ("failed to register commands with Assuan: %s",
1721                gpg_strerror (err));
1722       assuan_release (ctx);
1723       return NULL;
1724     }
1725 
1726   ctrl = g_malloc0 (sizeof *ctrl);
1727   assuan_set_pointer (ctx, ctrl);
1728   assuan_set_log_stream (ctx, stderr);
1729   assuan_register_reset_notify (ctx, reset_notify);
1730   assuan_register_output_notify (ctx, output_notify);
1731   ctrl->message_fd = -1;
1732 
1733   connection_counter++;
1734   return ctx;
1735 }
1736 
1737 
1738 /* Finish a connection.  This releases all resources and needs to be
1739    called becore the file descriptor is closed.  */
1740 static void
connection_finish(assuan_context_t ctx)1741 connection_finish (assuan_context_t ctx)
1742 {
1743   if (ctx)
1744     {
1745       conn_ctrl_t ctrl = assuan_get_pointer (ctx);
1746 
1747       reset_notify (ctx, NULL);
1748       assuan_release (ctx);
1749       g_free (ctrl);
1750       connection_counter--;
1751       if (!connection_counter && shutdown_pending)
1752         gtk_main_quit ();
1753     }
1754 }
1755 
1756 
1757 /* If the assuan context CTX has a registered continuation function,
1758    run it.  */
1759 static void
run_server_continuation(assuan_context_t ctx,gpg_error_t err)1760 run_server_continuation (assuan_context_t ctx, gpg_error_t err)
1761 {
1762   conn_ctrl_t ctrl = assuan_get_pointer (ctx);
1763   void (*cont_cmd) (assuan_context_t, gpg_error_t);
1764 
1765   if (!ctrl)
1766     {
1767       g_debug ("no context in gpa_run_server_continuation");
1768       return;
1769     }
1770   g_debug ("calling gpa_run_server_continuation (%s)", gpg_strerror (err));
1771   if (!ctrl->cont_cmd)
1772     {
1773       g_debug ("no continuation defined; using default");
1774       assuan_process_done (ctx, err);
1775     }
1776   else if (ctrl->client_died)
1777     {
1778       g_debug ("not running continuation as client has disconnected");
1779       connection_finish (ctx);
1780     }
1781   else
1782     {
1783       cont_cmd = ctrl->cont_cmd;
1784       ctrl->cont_cmd = NULL;
1785       cont_cmd (ctx, err);
1786     }
1787   g_debug ("leaving gpa_run_server_continuation");
1788 }
1789 
1790 
1791 /* This function is called by the main event loop if data can be read
1792    from the status channel.  */
1793 static gboolean
receive_cb(GIOChannel * channel,GIOCondition condition,void * data)1794 receive_cb (GIOChannel *channel, GIOCondition condition, void *data)
1795 {
1796   assuan_context_t ctx = data;
1797   conn_ctrl_t ctrl = assuan_get_pointer (ctx);
1798   gpg_error_t err;
1799 
1800   assert (ctrl);
1801   if (condition & G_IO_IN)
1802     {
1803       g_debug ("receive_cb");
1804       if (ctrl->cont_cmd)
1805         {
1806           g_debug ("  input received while waiting for continuation");
1807           g_usleep (2000000);
1808         }
1809       else if (ctrl->in_command)
1810         {
1811           g_debug ("  input received while still processing command");
1812           g_usleep (2000000);
1813         }
1814       else
1815         {
1816 	  int done = 0;
1817           ctrl->in_command++;
1818           err = assuan_process_next (ctx, &done);
1819           ctrl->in_command--;
1820 	  if (err)
1821 	    {
1822 	      g_debug ("assuan_process_next returned: %s <%s>",
1823 		       gpg_strerror (err), gpg_strsource (err));
1824 	    }
1825 	  else
1826 	    {
1827 	      g_debug ("assuan_process_next returned: %s",
1828 		       done ? "done" : "success");
1829 	    }
1830           if (gpg_err_code (err) == GPG_ERR_EAGAIN)
1831             ; /* Ignore.  */
1832           else if (!err && done)
1833             {
1834               if (ctrl->cont_cmd)
1835                 ctrl->client_died = 1; /* Need to delay the cleanup.  */
1836               else
1837                 connection_finish (ctx);
1838               return FALSE; /* Remove from the watch.  */
1839             }
1840           else if (gpg_err_code (err) == GPG_ERR_UNFINISHED)
1841             {
1842               if (!ctrl->is_unfinished)
1843                 {
1844                   /* It is quite possible that some other subsystem
1845                      returns that error code.  Tell the user about
1846                      this curiosity and finish the command.  */
1847                   g_debug ("note: Unfinished error code not emitted by us");
1848                   if (ctrl->cont_cmd)
1849                     g_debug ("OOPS: pending continuation!");
1850                   assuan_process_done (ctx, err);
1851                 }
1852             }
1853           else
1854             assuan_process_done (ctx, err);
1855         }
1856     }
1857   return TRUE;
1858 }
1859 
1860 
1861 /* This function is called by the main event loop if the listen fd is
1862    readable.  The function runs the accept and prepares the
1863    connection.  */
1864 static gboolean
accept_connection_cb(GIOChannel * listen_channel,GIOCondition condition,void * data)1865 accept_connection_cb (GIOChannel *listen_channel,
1866                       GIOCondition condition, void *data)
1867 {
1868   gpg_error_t err;
1869   int listen_fd, fd;
1870   struct sockaddr_un paddr;
1871   socklen_t plen = sizeof paddr;
1872   assuan_context_t ctx;
1873   GIOChannel *channel;
1874   unsigned int source_id;
1875 
1876   g_debug ("new connection request");
1877 #ifdef HAVE_W32_SYSTEM
1878   listen_fd = g_io_channel_win32_get_fd (listen_channel);
1879 #else
1880   listen_fd = g_io_channel_unix_get_fd (listen_channel);
1881 #endif
1882   fd = accept (listen_fd, (struct sockaddr *)&paddr, &plen);
1883   if (fd == -1)
1884     {
1885       g_debug ("error accepting connection: %s", strerror (errno));
1886       goto leave;
1887     }
1888   if (assuan_sock_check_nonce ((assuan_fd_t) fd, &socket_nonce))
1889     {
1890       g_debug ("new connection at fd %d refused", fd);
1891       goto leave;
1892     }
1893 
1894   g_debug ("new connection at fd %d", fd);
1895   ctx = connection_startup ((assuan_fd_t) fd);
1896   if (!ctx)
1897     goto leave;
1898 
1899 #ifdef HAVE_W32_SYSTEM
1900   channel = g_io_channel_win32_new_socket (fd);
1901 #else
1902   channel = g_io_channel_unix_new (fd);
1903 #endif
1904   if (!channel)
1905     {
1906       g_debug ("error creating a channel for fd %d\n", fd);
1907       goto leave;
1908     }
1909   g_io_channel_set_encoding (channel, NULL, NULL);
1910   g_io_channel_set_buffered (channel, FALSE);
1911 
1912   source_id = g_io_add_watch (channel, G_IO_IN, receive_cb, ctx);
1913   if (!source_id)
1914     {
1915       g_debug ("error creating watch for fd %d", fd);
1916       g_io_channel_shutdown (channel, 0, NULL);
1917       goto leave;
1918     }
1919   err = assuan_accept (ctx);
1920   if (err)
1921     {
1922       g_debug ("assuan accept failed: %s", gpg_strerror (err));
1923       g_io_channel_shutdown (channel, 0, NULL);
1924       goto leave;
1925     }
1926   g_debug ("connection at fd %d ready", fd);
1927   fd = -1;
1928 
1929  leave:
1930   if (fd != -1)
1931     assuan_sock_close ((assuan_fd_t) fd);
1932   return TRUE; /* Keep the listen_fd in the event loop.  */
1933 }
1934 
1935 
1936 
1937 /* Startup the server.  */
1938 void
gpa_start_server(void)1939 gpa_start_server (void)
1940 {
1941   char *socket_name;
1942   gpg_error_t err;
1943   int rc;
1944   assuan_fd_t fd;
1945   struct sockaddr_un serv_addr;
1946   socklen_t serv_addr_len = sizeof serv_addr;
1947   GIOChannel *channel;
1948   unsigned int source_id;
1949 
1950   assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
1951   err = assuan_sock_init ();
1952   if (err)
1953     {
1954       g_debug ("assuan_sock_init failed: %s <%s>",
1955                gpg_strerror (err), gpg_strsource (err));
1956       return;
1957     }
1958 
1959   socket_name = g_build_filename (gnupg_homedir, "S.uiserver", NULL);
1960   if (strlen (socket_name)+1 >= sizeof serv_addr.sun_path )
1961     {
1962       g_debug ("name of socket too long\n");
1963       g_free (socket_name);
1964       return;
1965     }
1966   g_debug ("using server socket `%s'", socket_name);
1967 
1968   fd = assuan_sock_new (AF_UNIX, SOCK_STREAM, 0);
1969   if (fd == ASSUAN_INVALID_FD)
1970     {
1971       g_debug ("can't create socket: %s\n", strerror(errno));
1972       g_free (socket_name);
1973       return;
1974     }
1975 
1976   memset (&serv_addr, 0, sizeof serv_addr);
1977   serv_addr.sun_family = AF_UNIX;
1978   strcpy (serv_addr.sun_path, socket_name);
1979   serv_addr_len = (offsetof (struct sockaddr_un, sun_path)
1980                    + strlen(serv_addr.sun_path) + 1);
1981 
1982   rc = assuan_sock_bind (fd, (struct sockaddr*) &serv_addr, serv_addr_len);
1983   if (rc == -1 && errno == EADDRINUSE)
1984     {
1985       remove (socket_name);
1986       rc = assuan_sock_bind (fd, (struct sockaddr*) &serv_addr, serv_addr_len);
1987     }
1988   if (rc != -1 && (rc=assuan_sock_get_nonce ((struct sockaddr*) &serv_addr,
1989                                              serv_addr_len, &socket_nonce)))
1990     g_debug ("error getting nonce for the socket");
1991   if (rc == -1)
1992     {
1993       g_debug ("error binding socket to `%s': %s\n",
1994                serv_addr.sun_path, strerror (errno) );
1995       assuan_sock_close (fd);
1996       g_free (socket_name);
1997       return;
1998     }
1999   g_free (socket_name);
2000   socket_name = NULL;
2001 
2002   if (listen ((int) fd, 5) == -1)
2003     {
2004       g_debug ("listen() failed: %s\n", strerror (errno));
2005       assuan_sock_close (fd);
2006       return;
2007     }
2008 #ifdef HAVE_W32_SYSTEM
2009   channel = g_io_channel_win32_new_socket ((int) fd);
2010 #else
2011   channel = g_io_channel_unix_new (fd);
2012 #endif
2013   if (!channel)
2014     {
2015       g_debug ("error creating a new listening channel\n");
2016       assuan_sock_close (fd);
2017       return;
2018     }
2019   g_io_channel_set_encoding (channel, NULL, NULL);
2020   g_io_channel_set_buffered (channel, FALSE);
2021 
2022   source_id = g_io_add_watch (channel, G_IO_IN, accept_connection_cb, NULL);
2023   if (!source_id)
2024     {
2025       g_debug ("error creating watch for listening channel\n");
2026       g_io_channel_shutdown (channel, 0, NULL);
2027       assuan_sock_close (fd);
2028       return;
2029     }
2030 
2031 }
2032 
2033 /* Set a flag to shutdown the server in a friendly way.  */
2034 void
gpa_stop_server(void)2035 gpa_stop_server (void)
2036 {
2037   shutdown_pending = TRUE;
2038   if (!connection_counter)
2039     gtk_main_quit ();
2040 }
2041 
2042 
2043 /* Helper for gpa_check-server.  */
2044 static gpg_error_t
check_name_cb(void * opaque,const void * buffer,size_t length)2045 check_name_cb (void *opaque, const void *buffer, size_t length)
2046 {
2047   int *result = opaque;
2048   const char *name = PACKAGE_NAME;
2049 
2050   if (length == strlen (name) && !strcmp (name, buffer))
2051     *result = 1;
2052 
2053   return 0;
2054 }
2055 
2056 
2057 /* Check whether an UI server is already running:
2058    0  = no
2059    1  = yes
2060    2  = yes - same program
2061  */
2062 int
gpa_check_server(void)2063 gpa_check_server (void)
2064 {
2065   gpg_error_t err;
2066   assuan_context_t ctx;
2067   int name_check = 0;
2068   int result;
2069 
2070   err = assuan_new (&ctx);
2071   if (!err)
2072     err = assuan_socket_connect (ctx,
2073                                  gpgme_get_dirinfo ("uiserver-socket"), 0, 0);
2074   if (err)
2075     {
2076       if (verbose || gpg_err_code (err) != GPG_ERR_ASS_CONNECT_FAILED)
2077         g_message ("error connecting an UI server: %s - %s",
2078                    gpg_strerror (err), "assuming not running");
2079       result = 0;
2080       goto leave;
2081     }
2082 
2083   err = assuan_transact (ctx, "GETINFO name",
2084                          check_name_cb, &name_check, NULL, NULL, NULL, NULL);
2085   if (err)
2086     {
2087       g_message ("requesting name of UI server failed: %s - %s",
2088                  gpg_strerror (err), "assuming not running");
2089       result = 1;
2090       goto leave;
2091     }
2092 
2093   if (name_check)
2094     {
2095       if (verbose)
2096         g_message ("an instance of this program is already running");
2097       result = 2;
2098     }
2099   else
2100     {
2101       g_message ("an different UI server is already running");
2102       result = 1;
2103     }
2104 
2105  leave:
2106   assuan_release (ctx);
2107   return result;
2108 }
2109 
2110 
2111 /* Send a command to the server.  */
2112 gpg_error_t
gpa_send_to_server(const char * cmd)2113 gpa_send_to_server (const char *cmd)
2114 {
2115   gpg_error_t err;
2116   assuan_context_t ctx;
2117 
2118   err = assuan_new (&ctx);
2119   if (!err)
2120     err = assuan_socket_connect (ctx,
2121                                  gpgme_get_dirinfo ("uiserver-socket"), 0, 0);
2122   if (err)
2123     {
2124       g_message ("error connecting the UI server: %s", gpg_strerror (err));
2125       goto leave;
2126     }
2127 
2128   err = assuan_transact (ctx, cmd, NULL, NULL, NULL, NULL, NULL, NULL);
2129   if (err)
2130     {
2131       g_message ("error sending '%s' to the UI server: %s",
2132                  cmd, gpg_strerror (err));
2133       goto leave;
2134     }
2135 
2136  leave:
2137   assuan_release (ctx);
2138   return err;
2139 }
2140