2009-09-23 Marcus Brinkmann <marcus@g10code.de>
[gnupg.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/sysutils.h"
36
37
38 #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
39
40
41 /* Data used to associate an Assuan context with local server data.  */
42 struct server_local_s 
43 {
44   /* Our current Assuan context. */
45   assuan_context_t assuan_ctx;  
46   /* File descriptor as set by the MESSAGE command. */
47   gnupg_fd_t message_fd;               
48 };
49
50
51 \f
52 /* Helper to close the message fd if it is open. */
53 static void 
54 close_message_fd (ctrl_t ctrl)
55 {
56   if (ctrl->server_local->message_fd != GNUPG_INVALID_FD)
57     {
58       assuan_sock_close (ctrl->server_local->message_fd);
59       ctrl->server_local->message_fd = GNUPG_INVALID_FD;
60     } 
61 }
62
63
64 \f
65 /* Called by libassuan for Assuan options.  See the Assuan manual for
66    details. */
67 static gpg_error_t
68 option_handler (assuan_context_t ctx, const char *key, const char *value)
69 {
70 /*   ctrl_t ctrl = assuan_get_pointer (ctx); */
71
72   (void)ctx;
73   (void)value;
74
75   /* Fixme: Implement the tty and locale args. */
76   if (!strcmp (key, "display"))
77     {
78     }
79   else if (!strcmp (key, "ttyname"))
80     {
81     }
82   else if (!strcmp (key, "ttytype"))
83     {
84     }
85   else if (!strcmp (key, "lc-ctype"))
86     {
87     }
88   else if (!strcmp (key, "lc-messages"))
89     {
90     }
91   else if (!strcmp (key, "xauthority"))
92     {
93     }
94   else if (!strcmp (key, "pinentry_user_data"))
95     {
96     }
97   else if (!strcmp (key, "list-mode"))
98     {
99       /* This is for now a dummy option. */
100     }
101   else
102     return gpg_error (GPG_ERR_UNKNOWN_OPTION);
103
104   return 0;
105 }
106
107
108 /* Called by libassuan for RESET commands. */
109 static gpg_error_t
110 reset_notify (assuan_context_t ctx, char *line)
111 {
112   ctrl_t ctrl = assuan_get_pointer (ctx);
113
114   (void)line;
115
116   close_message_fd (ctrl);
117   assuan_close_input_fd (ctx);
118   assuan_close_output_fd (ctx);
119   return 0;
120 }
121
122
123 /* Called by libassuan for INPUT commands. */
124 static gpg_error_t
125 input_notify (assuan_context_t ctx, char *line)
126 {
127 /*   ctrl_t ctrl = assuan_get_pointer (ctx); */
128
129   (void)ctx;
130
131   if (strstr (line, "--armor"))
132     ; /* FIXME */
133   else if (strstr (line, "--base64"))
134     ; /* FIXME */
135   else if (strstr (line, "--binary"))
136     ;
137   else
138     {
139       /* FIXME (autodetect encoding) */
140     }
141   return 0;
142 }
143
144
145 /* Called by libassuan for OUTPUT commands. */
146 static gpg_error_t
147 output_notify (assuan_context_t ctx, char *line)
148 {
149 /*   ctrl_t ctrl = assuan_get_pointer (ctx); */
150   
151   (void)ctx;
152
153   if (strstr (line, "--armor"))
154     ; /* FIXME */
155   else if (strstr (line, "--base64"))
156     {
157       /* FIXME */
158     }
159   return 0;
160 }
161
162
163
164 \f
165 /*  RECIPIENT <userID>
166
167    Set the recipient for the encryption.  <userID> should be the
168    internal representation of the key; the server may accept any other
169    way of specification.  If this is a valid and trusted recipient the
170    server does respond with OK, otherwise the return is an ERR with
171    the reason why the recipient can't be used, the encryption will
172    then not be done for this recipient.  If the policy is not to
173    encrypt at all if not all recipients are valid, the client has to
174    take care of this.  All RECIPIENT commands are cumulative until a
175    RESET or an successful ENCRYPT command.  */
176 static gpg_error_t
177 cmd_recipient (assuan_context_t ctx, char *line)
178 {
179   (void)ctx;
180   (void)line;
181   return gpg_error (GPG_ERR_NOT_SUPPORTED);
182 }
183
184
185 \f
186 /*  SIGNER <userID>
187
188    Set the signer's keys for the signature creation.  <userID> should
189    be the internal representation of the key; the server may accept
190    any other way of specification.  If this is a valid and usable
191    signing key the server does respond with OK, otherwise it returns
192    an ERR with the reason why the key can't be used, the signing will
193    then not be done for this key.  If the policy is not to sign at all
194    if not all signer keys are valid, the client has to take care of
195    this.  All SIGNER commands are cumulative until a RESET but they
196    are *not* reset by an SIGN command becuase it can be expected that
197    set of signers are used for more than one sign operation.
198
199    Note that this command returns an INV_RECP status which is a bit
200    strange, but they are very similar.  */
201 static gpg_error_t
202 cmd_signer (assuan_context_t ctx, char *line)
203 {
204   (void)ctx;
205   (void)line;
206   return gpg_error (GPG_ERR_NOT_SUPPORTED);
207 }
208
209
210 \f
211 /*  ENCRYPT 
212
213    Do the actual encryption process.  Takes the plaintext from the
214    INPUT command, writes to the ciphertext to the file descriptor set
215    with the OUTPUT command, take the recipients form all the
216    recipients set so far.  If this command fails the clients should
217    try to delete all output currently done or otherwise mark it as
218    invalid.  GPG does ensure that there won't be any security problem
219    with leftover data on the output in this case.
220
221    This command should in general not fail, as all necessary checks
222    have been done while setting the recipients.  The input and output
223    pipes are closed.  */
224 static gpg_error_t
225 cmd_encrypt (assuan_context_t ctx, char *line)
226 {
227   (void)ctx;
228   (void)line;
229   return gpg_error (GPG_ERR_NOT_SUPPORTED);
230 }
231
232
233 \f
234 /*  DECRYPT
235
236    This performs the decrypt operation after doing some checks on the
237    internal state (e.g. that only needed data has been set).   */
238 static gpg_error_t
239 cmd_decrypt (assuan_context_t ctx, char *line)
240 {
241   (void)ctx;
242   (void)line;
243   return gpg_error (GPG_ERR_NOT_SUPPORTED);
244 }
245
246
247 \f
248 /*  VERIFY
249
250    This does a verify operation on the message send to the input-FD.
251    The result is written out using status lines.  If an output FD was
252    given, the signed text will be written to that.
253   
254    If the signature is a detached one, the server will inquire about
255    the signed material and the client must provide it.
256  */
257 static gpg_error_t
258 cmd_verify (assuan_context_t ctx, char *line)
259 {
260   int rc;
261   ctrl_t ctrl = assuan_get_pointer (ctx);
262   gnupg_fd_t fd = assuan_get_input_fd (ctx);
263   gnupg_fd_t out_fd = assuan_get_output_fd (ctx);
264   FILE *out_fp = NULL;
265
266   (void)line;
267
268   if (fd == GNUPG_INVALID_FD)
269     return gpg_error (GPG_ERR_ASS_NO_INPUT);
270
271   if (out_fd != GNUPG_INVALID_FD)
272     {
273       out_fp = fdopen ( dup (FD2INT (out_fd)), "w");
274       if (!out_fp)
275         return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
276     }
277
278   log_debug ("WARNING: The server mode work "
279              "in progress and not ready for use\n");
280
281   /* Need to dup it because it might get closed and libassuan won't
282      know about it then. */
283   rc = gpg_verify (ctrl,
284                    dup ( FD2INT (fd)), 
285                    dup ( FD2INT (ctrl->server_local->message_fd)),
286                    out_fp);
287
288   if (out_fp)
289     fclose (out_fp);
290   close_message_fd (ctrl);
291   assuan_close_input_fd (ctx);
292   assuan_close_output_fd (ctx);
293
294   return rc;
295 }
296
297
298 \f
299 /*  SIGN [--detached]
300
301    Sign the data set with the INPUT command and write it to the sink
302    set by OUTPUT.  With "--detached" specified, a detached signature
303    is created.  */
304 static gpg_error_t
305 cmd_sign (assuan_context_t ctx, char *line)
306 {
307   (void)ctx;
308   (void)line;
309   return gpg_error (GPG_ERR_NOT_SUPPORTED);
310 }
311
312
313 \f
314 /*  IMPORT
315
316   Import keys as read from the input-fd, return status message for
317   each imported one.  The import checks the validity of the key.  */
318 static gpg_error_t
319 cmd_import (assuan_context_t ctx, char *line)
320 {
321   (void)ctx;
322   (void)line;
323   return gpg_error (GPG_ERR_NOT_SUPPORTED);
324 }
325
326
327 \f
328 /*  EXPORT [--data [--armor|--base64]] [--] pattern
329
330    Similar to the --export command line command, this command exports
331    public keys matching PATTERN.  The output is send to the output fd
332    unless the --data option has been used in which case the output
333    gets send inline using regular data lines.  The options "--armor"
334    and "--base" ospecify an output format if "--data" has been used.
335    Recall that in general the output format is set with the OUTPUT
336    command.
337  */
338 static gpg_error_t
339 cmd_export (assuan_context_t ctx, char *line)
340 {
341   (void)ctx;
342   (void)line;
343   return gpg_error (GPG_ERR_NOT_SUPPORTED);
344 }
345
346
347 \f
348 /*  DELKEYS
349
350     Fixme
351 */
352 static gpg_error_t
353 cmd_delkeys (assuan_context_t ctx, char *line)
354 {
355   (void)ctx;
356   (void)line;
357   return gpg_error (GPG_ERR_NOT_SUPPORTED);
358 }
359
360
361 \f
362 /*  MESSAGE FD[=<n>]
363
364    Set the file descriptor to read a message which is used with
365    detached signatures.  */
366 static gpg_error_t
367 cmd_message (assuan_context_t ctx, char *line)
368 {
369   int rc;
370   gnupg_fd_t fd;
371   ctrl_t ctrl = assuan_get_pointer (ctx);
372
373   rc = assuan_command_parse_fd (ctx, line, &fd);
374   if (rc)
375     return rc;
376   if (fd == GNUPG_INVALID_FD)
377     return gpg_error (GPG_ERR_ASS_NO_INPUT);
378   ctrl->server_local->message_fd = fd;
379   return 0;
380 }
381
382
383 \f
384 /* LISTKEYS [<patterns>]
385    LISTSECRETKEYS [<patterns>]
386
387    fixme
388 */
389 static gpg_error_t
390 do_listkeys (assuan_context_t ctx, char *line, int mode)
391 {
392   (void)ctx;
393   (void)line;
394   (void)mode;
395
396   return gpg_error (GPG_ERR_NOT_SUPPORTED);
397 }
398
399
400 static gpg_error_t
401 cmd_listkeys (assuan_context_t ctx, char *line)
402 {
403   return do_listkeys (ctx, line, 3);
404 }
405
406
407 static gpg_error_t
408 cmd_listsecretkeys (assuan_context_t ctx, char *line)
409 {
410   return do_listkeys (ctx, line, 2);
411 }
412
413
414 \f
415 /* GENKEY
416
417    Read the parameters in native format from the input fd and create a
418    new OpenPGP key.
419  */
420 static gpg_error_t
421 cmd_genkey (assuan_context_t ctx, char *line)
422 {
423   (void)ctx;
424   (void)line;
425   return gpg_error (GPG_ERR_NOT_SUPPORTED);
426 }
427
428
429 /* GETINFO <what>
430
431    Multipurpose function to return a variety of information.
432    Supported values for WHAT are:
433
434      version     - Return the version of the program.
435      pid         - Return the process id of the server.
436
437  */
438 static gpg_error_t
439 cmd_getinfo (assuan_context_t ctx, char *line)
440 {
441   int rc;
442
443   if (!strcmp (line, "version"))
444     {
445       const char *s = VERSION;
446       rc = assuan_send_data (ctx, s, strlen (s));
447     }
448   else if (!strcmp (line, "pid"))
449     {
450       char numbuf[50];
451
452       snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
453       rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
454     }
455   else
456     rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
457   return rc;
458 }
459
460
461 \f
462 /* Helper to register our commands with libassuan. */
463 static int
464 register_commands (assuan_context_t ctx)
465 {
466   static struct 
467   {
468     const char *name;
469     assuan_handler_t handler;
470   } table[] = {
471     { "RECIPIENT",     cmd_recipient },
472     { "SIGNER",        cmd_signer    },
473     { "ENCRYPT",       cmd_encrypt   },
474     { "DECRYPT",       cmd_decrypt   },
475     { "VERIFY",        cmd_verify    },
476     { "SIGN",          cmd_sign      },
477     { "IMPORT",        cmd_import    },
478     { "EXPORT",        cmd_export    },
479     { "INPUT",         NULL          }, 
480     { "OUTPUT",        NULL          }, 
481     { "MESSAGE",       cmd_message   },
482     { "LISTKEYS",      cmd_listkeys  },
483     { "LISTSECRETKEYS",cmd_listsecretkeys },
484     { "GENKEY",        cmd_genkey    },
485     { "DELKEYS",       cmd_delkeys   },
486     { "GETINFO",       cmd_getinfo   },
487     { NULL }
488   };
489   int i, rc;
490
491   for (i=0; table[i].name; i++)
492     {
493       rc = assuan_register_command (ctx, table[i].name, table[i].handler, NULL);
494       if (rc)
495         return rc;
496     } 
497   return 0;
498 }
499
500
501
502 \f
503 /* Startup the server.  CTRL must have been allocated by the caller
504    and set to the default values. */
505 int
506 gpg_server (ctrl_t ctrl)
507 {
508   int rc;
509   int filedes[2];
510   assuan_context_t ctx = NULL;
511   static const char hello[] = ("GNU Privacy Guard's OpenPGP server "
512                                VERSION " ready");
513
514   /* We use a pipe based server so that we can work from scripts.
515      assuan_init_pipe_server will automagically detect when we are
516      called with a socketpair and ignore FILEDES in this case.  */
517   filedes[0] = assuan_fdopen (0);
518   filedes[1] = assuan_fdopen (1);
519   rc = assuan_new (&ctx);
520   if (rc)
521     {
522       log_error ("failed to allocate the assuan context: %s\n",
523                  gpg_strerror (rc));
524       goto leave;
525     }
526   
527   rc = assuan_init_pipe_server (ctx, filedes);
528   if (rc)
529     {
530       log_error ("failed to initialize the server: %s\n", gpg_strerror (rc));
531       goto leave;
532     }
533
534   rc = register_commands (ctx);
535   if (rc)
536     {
537       log_error ("failed to the register commands with Assuan: %s\n",
538                  gpg_strerror(rc));
539       goto leave;
540     }
541
542   assuan_set_pointer (ctx, ctrl);
543   if (opt.verbose || opt.debug)
544     {
545       char *tmp = NULL;
546       const char *s1 = getenv ("GPG_AGENT_INFO");
547
548       if (asprintf (&tmp,
549                     "Home: %s\n"
550                     "Config: %s\n"
551                     "AgentInfo: %s\n"
552                     "%s",
553                     opt.homedir,
554                     "fixme: need config filename",
555                     s1?s1:"[not set]",
556                     hello) > 0)
557         {
558           assuan_set_hello_line (ctx, tmp);
559           free (tmp);
560         }
561     }
562   else
563     assuan_set_hello_line (ctx, hello);
564   assuan_register_reset_notify (ctx, reset_notify);
565   assuan_register_input_notify (ctx, input_notify);
566   assuan_register_output_notify (ctx, output_notify);
567   assuan_register_option_handler (ctx, option_handler);
568
569   ctrl->server_local = xtrycalloc (1, sizeof *ctrl->server_local);
570   if (!ctrl->server_local)
571     {
572       rc = gpg_error_from_syserror ();
573       goto leave;
574     }
575   ctrl->server_local->assuan_ctx = ctx;
576   ctrl->server_local->message_fd = GNUPG_INVALID_FD;
577
578   if (DBG_ASSUAN)
579     assuan_set_log_stream (ctx, log_get_stream ());
580
581   for (;;)
582     {
583       rc = assuan_accept (ctx);
584       if (rc == -1)
585         {
586           rc = 0;
587           break;
588         }
589       else if (rc)
590         {
591           log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
592           break;
593         }
594       
595       rc = assuan_process (ctx);
596       if (rc)
597         {
598           log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
599           continue;
600         }
601     }
602
603  leave:
604   xfree (ctrl->server_local);
605   ctrl->server_local = NULL;
606   assuan_release (ctx);
607   return rc;
608 }
609