Imported Upstream version 2.1.12
[platform/upstream/gpg2.git] / g10 / server.c
1 /* server.c - server mode for gpg
2  * Copyright (C) 2006, 2008  Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it 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  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public 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
20 #include <config.h>
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdarg.h>
26 #include <ctype.h>
27 #include <unistd.h>
28
29
30 #include "gpg.h"
31 #include <assuan.h>
32 #include "util.h"
33 #include "i18n.h"
34 #include "options.h"
35 #include "../common/server-help.h"
36 #include "../common/sysutils.h"
37 #include "status.h"
38
39
40 #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
41
42
43 /* Data used to associate an Assuan context with local server data.  */
44 struct server_local_s
45 {
46   /* Our current Assuan context. */
47   assuan_context_t assuan_ctx;
48   /* File descriptor as set by the MESSAGE command. */
49   gnupg_fd_t message_fd;
50
51   /* List of prepared recipients.  */
52   pk_list_t recplist;
53
54   /* Set if pinentry notifications should be passed back to the
55      client. */
56   int allow_pinentry_notify;
57 };
58
59
60 \f
61 /* Helper to close the message fd if it is open. */
62 static void
63 close_message_fd (ctrl_t ctrl)
64 {
65   if (ctrl->server_local->message_fd != GNUPG_INVALID_FD)
66     {
67       assuan_sock_close (ctrl->server_local->message_fd);
68       ctrl->server_local->message_fd = GNUPG_INVALID_FD;
69     }
70 }
71
72 \f
73 /* Called by libassuan for Assuan options.  See the Assuan manual for
74    details. */
75 static gpg_error_t
76 option_handler (assuan_context_t ctx, const char *key, const char *value)
77 {
78   ctrl_t ctrl = assuan_get_pointer (ctx);
79
80   (void)value;
81
82   /* Fixme: Implement the tty and locale args. */
83   if (!strcmp (key, "display"))
84     {
85     }
86   else if (!strcmp (key, "ttyname"))
87     {
88     }
89   else if (!strcmp (key, "ttytype"))
90     {
91     }
92   else if (!strcmp (key, "lc-ctype"))
93     {
94     }
95   else if (!strcmp (key, "lc-messages"))
96     {
97     }
98   else if (!strcmp (key, "xauthority"))
99     {
100     }
101   else if (!strcmp (key, "pinentry_user_data"))
102     {
103     }
104   else if (!strcmp (key, "list-mode"))
105     {
106       /* This is for now a dummy option. */
107     }
108   else if (!strcmp (key, "allow-pinentry-notify"))
109     {
110       ctrl->server_local->allow_pinentry_notify = 1;
111     }
112   else
113     return gpg_error (GPG_ERR_UNKNOWN_OPTION);
114
115   return 0;
116 }
117
118
119 /* Called by libassuan for RESET commands. */
120 static gpg_error_t
121 reset_notify (assuan_context_t ctx, char *line)
122 {
123   ctrl_t ctrl = assuan_get_pointer (ctx);
124
125   (void)line;
126
127   release_pk_list (ctrl->server_local->recplist);
128   ctrl->server_local->recplist = NULL;
129
130   close_message_fd (ctrl);
131   assuan_close_input_fd (ctx);
132   assuan_close_output_fd (ctx);
133   return 0;
134 }
135
136
137 /* Called by libassuan for INPUT commands. */
138 static gpg_error_t
139 input_notify (assuan_context_t ctx, char *line)
140 {
141 /*   ctrl_t ctrl = assuan_get_pointer (ctx); */
142
143   (void)ctx;
144
145   if (strstr (line, "--armor"))
146     ; /* FIXME */
147   else if (strstr (line, "--base64"))
148     ; /* FIXME */
149   else if (strstr (line, "--binary"))
150     ;
151   else
152     {
153       /* FIXME (autodetect encoding) */
154     }
155   return 0;
156 }
157
158
159 /* Called by libassuan for OUTPUT commands. */
160 static gpg_error_t
161 output_notify (assuan_context_t ctx, char *line)
162 {
163 /*   ctrl_t ctrl = assuan_get_pointer (ctx); */
164
165   (void)ctx;
166
167   if (strstr (line, "--armor"))
168     ; /* FIXME */
169   else if (strstr (line, "--base64"))
170     {
171       /* FIXME */
172     }
173   return 0;
174 }
175
176
177
178 \f
179 /*  RECIPIENT [--hidden] <userID>
180
181    Set the recipient for the encryption.  <userID> should be the
182    internal representation of the key; the server may accept any other
183    way of specification.  If this is a valid and trusted recipient the
184    server does respond with OK, otherwise the return is an ERR with
185    the reason why the recipient can't be used, the encryption will
186    then not be done for this recipient.  If the policy is not to
187    encrypt at all if not all recipients are valid, the client has to
188    take care of this.  All RECIPIENT commands are cumulative until a
189    RESET or an successful ENCRYPT command.  */
190 static gpg_error_t
191 cmd_recipient (assuan_context_t ctx, char *line)
192 {
193   ctrl_t ctrl = assuan_get_pointer (ctx);
194   gpg_error_t err;
195   int hidden;
196
197   hidden = has_option (line,"--hidden");
198   line = skip_options (line);
199
200   /* FIXME: Expand groups
201   if (opt.grouplist)
202     remusr = expand_group (rcpts);
203   else
204     remusr = rcpts;
205   */
206
207   err = find_and_check_key (ctrl, line, PUBKEY_USAGE_ENC, hidden,
208                             &ctrl->server_local->recplist);
209
210   if (err)
211     log_error ("command '%s' failed: %s\n", "RECIPIENT", gpg_strerror (err));
212   return err;
213 }
214
215
216 \f
217 /*  SIGNER <userID>
218
219    Set the signer's keys for the signature creation.  <userID> should
220    be the internal representation of the key; the server may accept
221    any other way of specification.  If this is a valid and usable
222    signing key the server does respond with OK, otherwise it returns
223    an ERR with the reason why the key can't be used, the signing will
224    then not be done for this key.  If the policy is not to sign at all
225    if not all signer keys are valid, the client has to take care of
226    this.  All SIGNER commands are cumulative until a RESET but they
227    are *not* reset by an SIGN command because it can be expected that
228    set of signers are used for more than one sign operation.
229
230    Note that this command returns an INV_RECP status which is a bit
231    strange, but they are very similar.  */
232 static gpg_error_t
233 cmd_signer (assuan_context_t ctx, char *line)
234 {
235   (void)ctx;
236   (void)line;
237   return gpg_error (GPG_ERR_NOT_SUPPORTED);
238 }
239
240
241 \f
242 /*  ENCRYPT
243
244    Do the actual encryption process.  Takes the plaintext from the
245    INPUT command, writes the ciphertext to the file descriptor set
246    with the OUTPUT command, take the recipients from all the
247    recipients set so far with RECIPIENTS.
248
249    If this command fails the clients should try to delete all output
250    currently done or otherwise mark it as invalid.  GPG does ensure
251    that there won't be any security problem with leftover data on the
252    output in this case.
253
254    In most cases this command won't fail because most necessary checks
255    have been done while setting the recipients.  However some checks
256    can only be done right here and thus error may occur anyway (for
257    example, no recipients at all).
258
259    The input, output and message pipes are closed after this
260    command.  */
261 static gpg_error_t
262 cmd_encrypt (assuan_context_t ctx, char *line)
263 {
264   ctrl_t ctrl = assuan_get_pointer (ctx);
265   gpg_error_t err;
266   int inp_fd, out_fd;
267
268   (void)line; /* LINE is not used.  */
269
270   if ( !ctrl->server_local->recplist )
271     {
272       write_status_text (STATUS_NO_RECP, "0");
273       err = gpg_error (GPG_ERR_NO_USER_ID);
274       goto leave;
275     }
276
277   inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
278   if (inp_fd == -1)
279     {
280       err = set_error (GPG_ERR_ASS_NO_INPUT, NULL);
281       goto leave;
282     }
283   out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
284   if (out_fd == -1)
285     {
286       err = set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
287       goto leave;
288     }
289
290
291   /* FIXME: GPGSM does this here: Add all encrypt-to marked recipients
292      from the default list. */
293
294   /* fixme: err = ctrl->audit? 0 : start_audit_session (ctrl);*/
295
296   err = encrypt_crypt (ctrl, inp_fd, NULL, NULL, 0,
297                        ctrl->server_local->recplist,
298                        out_fd);
299
300  leave:
301   /* Release the recipient list on success.  */
302   if (!err)
303     {
304       release_pk_list (ctrl->server_local->recplist);
305       ctrl->server_local->recplist = NULL;
306     }
307
308   /* Close and reset the fds. */
309   close_message_fd (ctrl);
310   assuan_close_input_fd (ctx);
311   assuan_close_output_fd (ctx);
312
313   if (err)
314     log_error ("command '%s' failed: %s\n", "ENCRYPT", gpg_strerror (err));
315   return err;
316 }
317
318
319 \f
320 /*  DECRYPT
321
322     This performs the decrypt operation.  */
323 static gpg_error_t
324 cmd_decrypt (assuan_context_t ctx, char *line)
325 {
326   ctrl_t ctrl = assuan_get_pointer (ctx);
327   gpg_error_t err;
328   int inp_fd, out_fd;
329
330   (void)line; /* LINE is not used.  */
331
332   inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
333   if (inp_fd == -1)
334     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
335   out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
336   if (out_fd == -1)
337     return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
338
339   glo_ctrl.lasterr = 0;
340   err = decrypt_message_fd (ctrl, inp_fd, out_fd);
341   if (!err)
342     err = glo_ctrl.lasterr;
343
344   /* Close and reset the fds. */
345   close_message_fd (ctrl);
346   assuan_close_input_fd (ctx);
347   assuan_close_output_fd (ctx);
348
349   if (err)
350     log_error ("command '%s' failed: %s\n", "DECRYPT", gpg_strerror (err));
351   return err;
352 }
353
354
355 \f
356 /*  VERIFY
357
358    This does a verify operation on the message send to the input-FD.
359    The result is written out using status lines.  If an output FD was
360    given, the signed text will be written to that.
361
362    If the signature is a detached one, the server will inquire about
363    the signed material and the client must provide it.
364  */
365 static gpg_error_t
366 cmd_verify (assuan_context_t ctx, char *line)
367 {
368   int rc;
369 #ifdef HAVE_W32_SYSTEM
370   (void)ctx;
371   (void)line;
372   rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
373 #else
374   ctrl_t ctrl = assuan_get_pointer (ctx);
375   gnupg_fd_t fd = assuan_get_input_fd (ctx);
376   gnupg_fd_t out_fd = assuan_get_output_fd (ctx);
377   estream_t out_fp = NULL;
378
379   /* FIXME: Revamp this code it is nearly to 3 years old and was only
380      intended as a quick test.  */
381
382   (void)line;
383
384   if (fd == GNUPG_INVALID_FD)
385     return gpg_error (GPG_ERR_ASS_NO_INPUT);
386
387   if (out_fd != GNUPG_INVALID_FD)
388     {
389       es_syshd_t syshd;
390
391 #ifdef HAVE_W32_SYSTEM
392       syshd.type = ES_SYSHD_HANDLE;
393       syshd.u.handle = out_fd;
394 #else
395       syshd.type = ES_SYSHD_FD;
396       syshd.u.fd = out_fd;
397 #endif
398       out_fp = es_sysopen_nc (&syshd, "w");
399       if (!out_fp)
400         return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
401     }
402
403   log_debug ("WARNING: The server mode is WORK "
404              "IN PROGRESS and not ready for use\n");
405
406   rc = gpg_verify (ctrl, fd, ctrl->server_local->message_fd, out_fp);
407
408   es_fclose (out_fp);
409   close_message_fd (ctrl);
410   assuan_close_input_fd (ctx);
411   assuan_close_output_fd (ctx);
412 #endif
413
414   if (rc)
415     log_error ("command '%s' failed: %s\n", "VERIFY", gpg_strerror (rc));
416   return rc;
417 }
418
419
420 \f
421 /*  SIGN [--detached]
422
423    Sign the data set with the INPUT command and write it to the sink
424    set by OUTPUT.  With "--detached" specified, a detached signature
425    is created.  */
426 static gpg_error_t
427 cmd_sign (assuan_context_t ctx, char *line)
428 {
429   (void)ctx;
430   (void)line;
431   return gpg_error (GPG_ERR_NOT_SUPPORTED);
432 }
433
434
435 \f
436 /*  IMPORT
437
438   Import keys as read from the input-fd, return status message for
439   each imported one.  The import checks the validity of the key.  */
440 static gpg_error_t
441 cmd_import (assuan_context_t ctx, char *line)
442 {
443   (void)ctx;
444   (void)line;
445   return gpg_error (GPG_ERR_NOT_SUPPORTED);
446 }
447
448
449 \f
450 /*  EXPORT [--data [--armor|--base64]] [--] pattern
451
452    Similar to the --export command line command, this command exports
453    public keys matching PATTERN.  The output is send to the output fd
454    unless the --data option has been used in which case the output
455    gets send inline using regular data lines.  The options "--armor"
456    and "--base" ospecify an output format if "--data" has been used.
457    Recall that in general the output format is set with the OUTPUT
458    command.
459  */
460 static gpg_error_t
461 cmd_export (assuan_context_t ctx, char *line)
462 {
463   (void)ctx;
464   (void)line;
465   return gpg_error (GPG_ERR_NOT_SUPPORTED);
466 }
467
468
469 \f
470 /*  DELKEYS
471
472     Fixme
473 */
474 static gpg_error_t
475 cmd_delkeys (assuan_context_t ctx, char *line)
476 {
477   (void)ctx;
478   (void)line;
479   return gpg_error (GPG_ERR_NOT_SUPPORTED);
480 }
481
482
483 \f
484 /*  MESSAGE FD[=<n>]
485
486    Set the file descriptor to read a message which is used with
487    detached signatures.  */
488 static gpg_error_t
489 cmd_message (assuan_context_t ctx, char *line)
490 {
491   int rc;
492   gnupg_fd_t fd;
493   ctrl_t ctrl = assuan_get_pointer (ctx);
494
495   rc = assuan_command_parse_fd (ctx, line, &fd);
496   if (rc)
497     return rc;
498   if (fd == GNUPG_INVALID_FD)
499     return gpg_error (GPG_ERR_ASS_NO_INPUT);
500   ctrl->server_local->message_fd = fd;
501   return 0;
502 }
503
504
505 \f
506 /* LISTKEYS [<patterns>]
507    LISTSECRETKEYS [<patterns>]
508
509    fixme
510 */
511 static gpg_error_t
512 do_listkeys (assuan_context_t ctx, char *line, int mode)
513 {
514   (void)ctx;
515   (void)line;
516   (void)mode;
517
518   return gpg_error (GPG_ERR_NOT_SUPPORTED);
519 }
520
521
522 static gpg_error_t
523 cmd_listkeys (assuan_context_t ctx, char *line)
524 {
525   return do_listkeys (ctx, line, 3);
526 }
527
528
529 static gpg_error_t
530 cmd_listsecretkeys (assuan_context_t ctx, char *line)
531 {
532   return do_listkeys (ctx, line, 2);
533 }
534
535
536 \f
537 /* GENKEY
538
539    Read the parameters in native format from the input fd and create a
540    new OpenPGP key.
541  */
542 static gpg_error_t
543 cmd_genkey (assuan_context_t ctx, char *line)
544 {
545   (void)ctx;
546   (void)line;
547   return gpg_error (GPG_ERR_NOT_SUPPORTED);
548 }
549
550
551 /* GETINFO <what>
552
553    Multipurpose function to return a variety of information.
554    Supported values for WHAT are:
555
556      version     - Return the version of the program.
557      pid         - Return the process id of the server.
558
559  */
560 static gpg_error_t
561 cmd_getinfo (assuan_context_t ctx, char *line)
562 {
563   int rc;
564
565   if (!strcmp (line, "version"))
566     {
567       const char *s = VERSION;
568       rc = assuan_send_data (ctx, s, strlen (s));
569     }
570   else if (!strcmp (line, "pid"))
571     {
572       char numbuf[50];
573
574       snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
575       rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
576     }
577   else
578     rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
579   return rc;
580 }
581
582 static const char hlp_passwd[] =
583   "PASSWD <userID>\n"
584   "\n"
585   "Change the passphrase of the secret key for USERID.";
586 static gpg_error_t
587 cmd_passwd (assuan_context_t ctx, char *line)
588 {
589   /* ctrl_t ctrl = assuan_get_pointer (ctx); */
590   gpg_error_t err;
591
592   (void)ctx;
593   (void)line;
594   /* line = skip_options (line); */
595
596   err = gpg_error (GPG_ERR_NOT_SUPPORTED);
597
598   return err;
599 }
600
601
602
603 \f
604 /* Helper to register our commands with libassuan. */
605 static int
606 register_commands (assuan_context_t ctx)
607 {
608   static struct
609   {
610     const char *name;
611     assuan_handler_t handler;
612     const char * const help;
613   } table[] = {
614     { "RECIPIENT",     cmd_recipient },
615     { "SIGNER",        cmd_signer    },
616     { "ENCRYPT",       cmd_encrypt   },
617     { "DECRYPT",       cmd_decrypt   },
618     { "VERIFY",        cmd_verify    },
619     { "SIGN",          cmd_sign      },
620     { "IMPORT",        cmd_import    },
621     { "EXPORT",        cmd_export    },
622     { "INPUT",         NULL          },
623     { "OUTPUT",        NULL          },
624     { "MESSAGE",       cmd_message   },
625     { "LISTKEYS",      cmd_listkeys  },
626     { "LISTSECRETKEYS",cmd_listsecretkeys },
627     { "GENKEY",        cmd_genkey    },
628     { "DELKEYS",       cmd_delkeys   },
629     { "GETINFO",       cmd_getinfo   },
630     { "PASSWD",        cmd_passwd,  hlp_passwd},
631     { NULL }
632   };
633   int i, rc;
634
635   for (i=0; table[i].name; i++)
636     {
637       rc = assuan_register_command (ctx, table[i].name,
638                                     table[i].handler, table[i].help);
639       if (rc)
640         return rc;
641     }
642   return 0;
643 }
644
645
646
647 \f
648 /* Startup the server.  CTRL must have been allocated by the caller
649    and set to the default values. */
650 int
651 gpg_server (ctrl_t ctrl)
652 {
653   int rc;
654 #ifndef HAVE_W32_SYSTEM
655   int filedes[2];
656 #endif
657   assuan_context_t ctx = NULL;
658   static const char hello[] = ("GNU Privacy Guard's OpenPGP server "
659                                VERSION " ready");
660
661   /* We use a pipe based server so that we can work from scripts.
662      assuan_init_pipe_server will automagically detect when we are
663      called with a socketpair and ignore FILEDES in this case.  */
664 #ifndef HAVE_W32_SYSTEM
665   filedes[0] = assuan_fdopen (0);
666   filedes[1] = assuan_fdopen (1);
667 #endif
668   rc = assuan_new (&ctx);
669   if (rc)
670     {
671       log_error ("failed to allocate the assuan context: %s\n",
672                  gpg_strerror (rc));
673       goto leave;
674     }
675
676 #ifdef HAVE_W32_SYSTEM
677   rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
678 #else
679   rc = assuan_init_pipe_server (ctx, filedes);
680 #endif
681   if (rc)
682     {
683       log_error ("failed to initialize the server: %s\n", gpg_strerror (rc));
684       goto leave;
685     }
686
687   rc = register_commands (ctx);
688   if (rc)
689     {
690       log_error ("failed to the register commands with Assuan: %s\n",
691                  gpg_strerror(rc));
692       goto leave;
693     }
694
695   assuan_set_pointer (ctx, ctrl);
696   if (opt.verbose || opt.debug)
697     {
698       char *tmp = NULL;
699
700       tmp = xtryasprintf ("Home: %s\n"
701                           "Config: %s\n"
702                           "%s",
703                           opt.homedir,
704                           "fixme: need config filename",
705                           hello);
706       if (tmp)
707         {
708           assuan_set_hello_line (ctx, tmp);
709           xfree (tmp);
710         }
711     }
712   else
713     assuan_set_hello_line (ctx, hello);
714   assuan_register_reset_notify (ctx, reset_notify);
715   assuan_register_input_notify (ctx, input_notify);
716   assuan_register_output_notify (ctx, output_notify);
717   assuan_register_option_handler (ctx, option_handler);
718
719   ctrl->server_local = xtrycalloc (1, sizeof *ctrl->server_local);
720   if (!ctrl->server_local)
721     {
722       rc = gpg_error_from_syserror ();
723       goto leave;
724     }
725   ctrl->server_local->assuan_ctx = ctx;
726   ctrl->server_local->message_fd = GNUPG_INVALID_FD;
727
728   for (;;)
729     {
730       rc = assuan_accept (ctx);
731       if (rc == -1)
732         {
733           rc = 0;
734           break;
735         }
736       else if (rc)
737         {
738           log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
739           break;
740         }
741
742       rc = assuan_process (ctx);
743       if (rc)
744         {
745           log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
746           continue;
747         }
748     }
749
750  leave:
751   if (ctrl->server_local)
752     {
753       release_pk_list (ctrl->server_local->recplist);
754
755       xfree (ctrl->server_local);
756       ctrl->server_local = NULL;
757     }
758   assuan_release (ctx);
759   return rc;
760 }
761
762
763 /* Helper to notify the client about Pinentry events.  Because that
764    might disturb some older clients, this is only done when enabled
765    via an option.  If it is not enabled we tell Windows to allow
766    setting the foreground window right here.  Returns an gpg error
767    code. */
768 gpg_error_t
769 gpg_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line)
770 {
771   if (!ctrl || !ctrl->server_local
772       || !ctrl->server_local->allow_pinentry_notify)
773     {
774       gnupg_allow_set_foregound_window ((pid_t)strtoul (line+17, NULL, 10));
775       /* Client might be interested in that event - send as status line.  */
776       if (!strncmp (line, "PINENTRY_LAUNCHED", 17)
777           && (line[17]==' '||!line[17]))
778         {
779           for (line += 17; *line && spacep (line); line++)
780             ;
781           write_status_text (STATUS_PINENTRY_LAUNCHED, line);
782         }
783       return 0;
784     }
785   return assuan_inquire (ctrl->server_local->assuan_ctx, line, NULL, NULL, 0);
786 }