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