* sign.c (get_default_signer): Use keydb_classify_name here.
[gnupg.git] / sm / server.c
1 /* server.c - Server mode and main entry point 
2  *      Copyright (C) 2001 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 2 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, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <unistd.h>
28
29 #include "gpgsm.h"
30 #include "../assuan/assuan.h"
31
32 #define set_error(e,t) assuan_set_error (ctx, ASSUAN_ ## e, (t))
33
34
35 /* The filepointer for status message used in non-server mode */
36 static FILE *statusfp;
37
38 /* Data used to assuciate an Assuan context with local server data */
39 struct server_local_s {
40   ASSUAN_CONTEXT assuan_ctx;
41   int message_fd;
42   CERTLIST recplist;
43 };
44
45 /* Map GNUPG_xxx error codes to Assuan status codes */
46 static int
47 rc_to_assuan_status (int rc)
48 {
49   switch (rc)
50     {
51     case 0: break;
52     case GNUPG_Bad_Certificate:   rc = ASSUAN_Bad_Certificate; break;
53     case GNUPG_Bad_Certificate_Path: rc = ASSUAN_Bad_Certificate_Path; break;
54     case GNUPG_Missing_Certificate: rc = ASSUAN_Missing_Certificate; break;
55     case GNUPG_No_Data:           rc = ASSUAN_No_Data_Available; break;
56     case GNUPG_Bad_Signature:     rc = ASSUAN_Bad_Signature; break;
57     case GNUPG_Not_Implemented:   rc = ASSUAN_Not_Implemented; break;
58     case GNUPG_No_Agent:          rc = ASSUAN_No_Agent; break;
59     case GNUPG_Agent_Error:       rc = ASSUAN_Agent_Error; break;
60     case GNUPG_No_Public_Key:     rc = ASSUAN_No_Public_Key; break;
61     case GNUPG_No_Secret_Key:     rc = ASSUAN_No_Secret_Key; break;
62     case GNUPG_Invalid_Data:      rc = ASSUAN_Invalid_Data; break;
63     case GNUPG_Invalid_Name:      rc = ASSUAN_Invalid_Name; break;
64
65     case GNUPG_Read_Error: 
66     case GNUPG_Write_Error:
67     case GNUPG_IO_Error: 
68       rc = ASSUAN_Server_IO_Error;
69       break;
70     case GNUPG_Out_Of_Core:    
71     case GNUPG_Resource_Limit: 
72       rc = ASSUAN_Server_Resource_Problem;
73       break;
74     case GNUPG_Bug: 
75     case GNUPG_Internal_Error:   
76       rc = ASSUAN_Server_Bug;
77       break;
78     default: 
79       rc = ASSUAN_Server_Fault;
80       break;
81     }
82   return rc;
83 }
84
85 static void
86 reset_notify (ASSUAN_CONTEXT ctx)
87 {
88   CTRL ctrl = assuan_get_pointer (ctx);
89
90   gpgsm_release_certlist (ctrl->server_local->recplist);
91   ctrl->server_local->recplist = NULL;
92 }
93
94
95 static void
96 input_notify (ASSUAN_CONTEXT ctx, const char *line)
97 {
98   CTRL ctrl = assuan_get_pointer (ctx);
99
100   ctrl->autodetect_encoding = 0;
101   ctrl->is_pem = 0;
102   ctrl->is_base64 = 0;
103   if (strstr (line, "--armor"))
104     ctrl->is_pem = 1;  
105   else if (strstr (line, "--base64"))
106     ctrl->is_base64 = 1; 
107   else if (strstr (line, "--binary"))
108     ;
109   else
110     ctrl->autodetect_encoding = 0;
111 }
112
113 static void
114 output_notify (ASSUAN_CONTEXT ctx, const char *line)
115 {
116   CTRL ctrl = assuan_get_pointer (ctx);
117
118   ctrl->create_pem = 0;
119   ctrl->create_base64 = 0;
120   if (strstr (line, "--armor"))
121     ctrl->create_pem = 1;  
122   else if (strstr (line, "--base64"))
123     ctrl->create_base64 = 1; /* just the raw output */
124 }
125
126
127
128 /*  RECIPIENT <userID>
129
130   Set the recipient for the encryption.  <userID> should be the
131   internal representation of the key; the server may accept any other
132   way of specification [we will support this].  If this is a valid and
133   trusted recipient the server does respond with OK, otherwise the
134   return is an ERR with the reason why the recipient can't be used,
135   the encryption will then not be done for this recipient.  IF the
136   policy is not to encrypt at all if not all recipients are valid, the
137   client has to take care of this.  All RECIPIENT commands are
138   cumulative until a RESET or an successful ENCRYPT command.  */
139 static int 
140 cmd_recipient (ASSUAN_CONTEXT ctx, char *line)
141 {
142   CTRL ctrl = assuan_get_pointer (ctx);
143   int rc;
144
145   rc = gpgsm_add_to_certlist (line, &ctrl->server_local->recplist);
146
147   return rc_to_assuan_status (rc);
148 }
149
150
151 /* ENCRYPT 
152
153   Do the actual encryption process. Takes the plaintext from the INPUT
154   command, writes to the ciphertext to the file descriptor set with
155   the OUTPUT command, take the recipients form all the recipients set
156   so far.  If this command fails the clients should try to delete all
157   output currently done or otherwise mark it as invalid.  GPGSM does
158   ensure that there won't be any security problem with leftover data
159   on the output in this case.
160
161   This command should in general not fail, as all necessary checks
162   have been done while setting the recipients.  The input and output
163   pipes are closed. */
164 static int 
165 cmd_encrypt (ASSUAN_CONTEXT ctx, char *line)
166 {
167   CTRL ctrl = assuan_get_pointer (ctx);
168   int inp_fd, out_fd;
169   FILE *out_fp;
170   int rc;
171
172   inp_fd = assuan_get_input_fd (ctx);
173   if (inp_fd == -1)
174     return set_error (No_Input, NULL);
175   out_fd = assuan_get_output_fd (ctx);
176   if (out_fd == -1)
177     return set_error (No_Output, NULL);
178
179   out_fp = fdopen ( dup(out_fd), "w");
180   if (!out_fp)
181     return set_error (General_Error, "fdopen() failed");
182   rc = gpgsm_encrypt (assuan_get_pointer (ctx),
183                       ctrl->server_local->recplist,
184                       inp_fd, out_fp);
185   fclose (out_fp);
186
187   if (!rc)
188     {
189       gpgsm_release_certlist (ctrl->server_local->recplist);
190       ctrl->server_local->recplist = NULL;
191     }
192   return rc_to_assuan_status (rc);
193 }
194
195 /* DECRYPT
196
197   This performs the decrypt operation after doing some check on the
198   internal state. (e.g. that only needed data has been set).  Because
199   it utilizes the GPG-Agent for the session key decryption, there is
200   no need to ask the client for a protecting passphrase - GpgAgent
201   does take care of this by requesting this from the user. */
202 static int 
203 cmd_decrypt (ASSUAN_CONTEXT ctx, char *line)
204 {
205   CTRL ctrl = assuan_get_pointer (ctx);
206   int inp_fd, out_fd;
207   FILE *out_fp;
208   int rc;
209
210   inp_fd = assuan_get_input_fd (ctx);
211   if (inp_fd == -1)
212     return set_error (No_Input, NULL);
213   out_fd = assuan_get_output_fd (ctx);
214   if (out_fd == -1)
215     return set_error (No_Output, NULL);
216
217   out_fp = fdopen ( dup(out_fd), "w");
218   if (!out_fp)
219     return set_error (General_Error, "fdopen() failed");
220   rc = gpgsm_decrypt (ctrl, inp_fd, out_fp); 
221   fclose (out_fp);
222
223   return rc_to_assuan_status (rc);
224 }
225
226
227 /* VERIFY
228
229   This does a verify operation on the message send to the input-FD.
230   The result is written out using status lines.  If an output FD was
231   given, the signed text will be written to that.
232   
233   If the signature is a detached one, the server will inquire about
234   the signed material and the client must provide it.
235   */
236 static int 
237 cmd_verify (ASSUAN_CONTEXT ctx, char *line)
238 {
239   int rc;
240   CTRL ctrl = assuan_get_pointer (ctx);
241   int fd = assuan_get_input_fd (ctx);
242
243   if (fd == -1)
244     return set_error (No_Input, NULL);
245
246   rc = gpgsm_verify (assuan_get_pointer (ctx), fd,
247                      ctrl->server_local->message_fd);
248
249   return rc_to_assuan_status (rc);
250 }
251
252
253 /* SIGN [--detached]
254
255   Sign the data set with the INPUT command and write it to the sink
256   set by OUTPUT.  With "--detached" specified, a detached signature is
257   created (surprise).  */
258 static int 
259 cmd_sign (ASSUAN_CONTEXT ctx, char *line)
260 {
261   int inp_fd, out_fd;
262   FILE *out_fp;
263   int detached;
264   int rc;
265
266   inp_fd = assuan_get_input_fd (ctx);
267   if (inp_fd == -1)
268     return set_error (No_Input, NULL);
269   out_fd = assuan_get_output_fd (ctx);
270   if (out_fd == -1)
271     return set_error (No_Output, NULL);
272
273   detached = !!strstr (line, "--detached");  /* fixme: this is ambiguous */
274
275   out_fp = fdopen ( dup(out_fd), "w");
276   if (!out_fp)
277     return set_error (General_Error, "fdopen() failed");
278   rc = gpgsm_sign (assuan_get_pointer (ctx), inp_fd, detached, out_fp);
279   fclose (out_fp);
280
281   return rc_to_assuan_status (rc);
282 }
283
284
285 /* IMPORT
286
287   Import the certificates read form the input-fd, return status
288   message for each imported one.  The import checks the validity of
289   the certificate but not of the path.  It is possible to import
290   expired certificates.  */
291 static int 
292 cmd_import (ASSUAN_CONTEXT ctx, char *line)
293 {
294   int rc;
295   int fd = assuan_get_input_fd (ctx);
296
297   if (fd == -1)
298     return set_error (No_Input, NULL);
299
300   rc = gpgsm_import (assuan_get_pointer (ctx), fd);
301
302   return rc_to_assuan_status (rc);
303 }
304
305 /* MESSAGE FD=<n>
306
307    Set the file descriptor to read a message which is used with
308    detached signatures */
309 static int 
310 cmd_message (ASSUAN_CONTEXT ctx, char *line)
311 {
312   char *endp;
313   int fd;
314   CTRL ctrl = assuan_get_pointer (ctx);
315
316   if (strncmp (line, "FD=", 3))
317     return set_error (Syntax_Error, "FD=<n> expected");
318   line += 3;
319   if (!digitp (*line))
320     return set_error (Syntax_Error, "number required");
321   fd = strtoul (line, &endp, 10);
322   if (*endp)
323     return set_error (Syntax_Error, "garbage found");
324   if (fd == -1)
325     return set_error (No_Input, NULL);
326
327   ctrl->server_local->message_fd = fd;
328   return 0;
329 }
330
331 static int 
332 cmd_listkeys (ASSUAN_CONTEXT ctx, char *line)
333 {
334   CTRL ctrl = assuan_get_pointer (ctx);
335
336   ctrl->with_colons = 1;
337   /* fixme: check that the returned data_fp is not NULL */
338   gpgsm_list_keys (assuan_get_pointer (ctx), NULL,
339                         assuan_get_data_fp (ctx));
340
341   return 0;
342 }
343
344
345
346
347 \f
348 /* Tell the assuan library about our commands */
349 static int
350 register_commands (ASSUAN_CONTEXT ctx)
351 {
352   static struct {
353     const char *name;
354     int cmd_id;
355     int (*handler)(ASSUAN_CONTEXT, char *line);
356   } table[] = {
357     { "RECIPIENT",  0,  cmd_recipient },
358     { "ENCRYPT",    0,  cmd_encrypt },
359     { "DECRYPT",    0,  cmd_decrypt },
360     { "VERIFY",     0,  cmd_verify },
361     { "SIGN",       0,  cmd_sign },
362     { "IMPORT",     0,  cmd_import },
363     { "",     ASSUAN_CMD_INPUT, NULL }, 
364     { "",     ASSUAN_CMD_OUTPUT, NULL }, 
365     { "MESSAGE",    0,  cmd_message },
366     { "LISTKEYS",   0,  cmd_listkeys },
367     { NULL }
368   };
369   int i, j, rc;
370
371   for (i=j=0; table[i].name; i++)
372     {
373       rc = assuan_register_command (ctx,
374                                     table[i].cmd_id? table[i].cmd_id
375                                                    : (ASSUAN_CMD_USER + j++),
376                                     table[i].name, table[i].handler);
377       if (rc)
378         return rc;
379     } 
380   return 0;
381 }
382
383 /* Startup the server */
384 void
385 gpgsm_server (void)
386 {
387   int rc;
388   int filedes[2];
389   ASSUAN_CONTEXT ctx;
390   struct server_control_s ctrl;
391
392   memset (&ctrl, 0, sizeof ctrl);
393
394   /* For now we use a simple pipe based server so that we can work
395      from scripts.  We will later add options to run as a daemon and
396      wait for requests on a Unix domain socket */
397   filedes[0] = 0;
398   filedes[1] = 1;
399   rc = assuan_init_pipe_server (&ctx, filedes);
400   if (rc)
401     {
402       log_error ("failed to initialize the server: %s\n",
403                  assuan_strerror(rc));
404       gpgsm_exit (2);
405     }
406   rc = register_commands (ctx);
407   if (rc)
408     {
409       log_error ("failed to the register commands with Assuan: %s\n",
410                  assuan_strerror(rc));
411       gpgsm_exit (2);
412     }
413   assuan_set_hello_line (ctx, "GNU Privacy Guard's S/M server ready");
414
415   assuan_register_reset_notify (ctx, reset_notify);
416   assuan_register_input_notify (ctx, input_notify);
417   assuan_register_output_notify (ctx, output_notify);
418
419   assuan_set_pointer (ctx, &ctrl);
420   ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
421   ctrl.server_local->assuan_ctx = ctx;
422   ctrl.server_local->message_fd = -1;
423
424   for (;;)
425     {
426       rc = assuan_accept (ctx);
427       if (rc == -1)
428         {
429           break;
430         }
431       else if (rc)
432         {
433           log_info ("Assuan accept problem: %s\n", assuan_strerror (rc));
434           break;
435         }
436       
437       rc = assuan_process (ctx);
438       if (rc)
439         {
440           log_info ("Assuan processing failed: %s\n", assuan_strerror (rc));
441           continue;
442         }
443     }
444
445   gpgsm_release_certlist (ctrl.server_local->recplist);
446   ctrl.server_local->recplist = NULL;
447
448   assuan_deinit_pipe_server (ctx);
449 }
450
451
452 static const char *
453 get_status_string ( int no ) 
454 {
455   const char *s;
456
457   switch (no)
458     {
459     case STATUS_ENTER  : s = "ENTER"; break;
460     case STATUS_LEAVE  : s = "LEAVE"; break;
461     case STATUS_ABORT  : s = "ABORT"; break;
462     case STATUS_GOODSIG: s = "GOODSIG"; break;
463     case STATUS_SIGEXPIRED: s = "SIGEXPIRED"; break;
464     case STATUS_KEYREVOKED: s = "KEYREVOKED"; break;
465     case STATUS_BADSIG : s = "BADSIG"; break;
466     case STATUS_ERRSIG : s = "ERRSIG"; break;
467     case STATUS_BADARMOR : s = "BADARMOR"; break;
468     case STATUS_RSA_OR_IDEA : s= "RSA_OR_IDEA"; break;
469     case STATUS_TRUST_UNDEFINED: s = "TRUST_UNDEFINED"; break;
470     case STATUS_TRUST_NEVER      : s = "TRUST_NEVER"; break;
471     case STATUS_TRUST_MARGINAL : s = "TRUST_MARGINAL"; break;
472     case STATUS_TRUST_FULLY      : s = "TRUST_FULLY"; break;
473     case STATUS_TRUST_ULTIMATE : s = "TRUST_ULTIMATE"; break;
474     case STATUS_GET_BOOL         : s = "GET_BOOL"; break;
475     case STATUS_GET_LINE         : s = "GET_LINE"; break;
476     case STATUS_GET_HIDDEN       : s = "GET_HIDDEN"; break;
477     case STATUS_GOT_IT   : s = "GOT_IT"; break;
478     case STATUS_SHM_INFO         : s = "SHM_INFO"; break;
479     case STATUS_SHM_GET  : s = "SHM_GET"; break;
480     case STATUS_SHM_GET_BOOL     : s = "SHM_GET_BOOL"; break;
481     case STATUS_SHM_GET_HIDDEN : s = "SHM_GET_HIDDEN"; break;
482     case STATUS_NEED_PASSPHRASE: s = "NEED_PASSPHRASE"; break;
483     case STATUS_VALIDSIG         : s = "VALIDSIG"; break;
484     case STATUS_SIG_ID   : s = "SIG_ID"; break;
485     case STATUS_ENC_TO   : s = "ENC_TO"; break;
486     case STATUS_NODATA   : s = "NODATA"; break;
487     case STATUS_BAD_PASSPHRASE : s = "BAD_PASSPHRASE"; break;
488     case STATUS_NO_PUBKEY        : s = "NO_PUBKEY"; break;
489     case STATUS_NO_SECKEY        : s = "NO_SECKEY"; break;
490     case STATUS_NEED_PASSPHRASE_SYM: s = "NEED_PASSPHRASE_SYM"; break;
491     case STATUS_DECRYPTION_FAILED: s = "DECRYPTION_FAILED"; break;
492     case STATUS_DECRYPTION_OKAY: s = "DECRYPTION_OKAY"; break;
493     case STATUS_MISSING_PASSPHRASE: s = "MISSING_PASSPHRASE"; break;
494     case STATUS_GOOD_PASSPHRASE : s = "GOOD_PASSPHRASE"; break;
495     case STATUS_GOODMDC  : s = "GOODMDC"; break;
496     case STATUS_BADMDC   : s = "BADMDC"; break;
497     case STATUS_ERRMDC   : s = "ERRMDC"; break;
498     case STATUS_IMPORTED         : s = "IMPORTED"; break;
499     case STATUS_IMPORT_RES       : s = "IMPORT_RES"; break;
500     case STATUS_FILE_START       : s = "FILE_START"; break;
501     case STATUS_FILE_DONE        : s = "FILE_DONE"; break;
502     case STATUS_FILE_ERROR       : s = "FILE_ERROR"; break;
503     case STATUS_BEGIN_DECRYPTION:s = "BEGIN_DECRYPTION"; break;
504     case STATUS_END_DECRYPTION : s = "END_DECRYPTION"; break;
505     case STATUS_BEGIN_ENCRYPTION:s = "BEGIN_ENCRYPTION"; break;
506     case STATUS_END_ENCRYPTION : s = "END_ENCRYPTION"; break;
507     case STATUS_DELETE_PROBLEM : s = "DELETE_PROBLEM"; break;
508     case STATUS_PROGRESS         : s = "PROGRESS"; break;
509     case STATUS_SIG_CREATED      : s = "SIG_CREATED"; break;
510     case STATUS_SESSION_KEY      : s = "SESSION_KEY"; break;
511     case STATUS_NOTATION_NAME  : s = "NOTATION_NAME" ; break;
512     case STATUS_NOTATION_DATA  : s = "NOTATION_DATA" ; break;
513     case STATUS_POLICY_URL     : s = "POLICY_URL" ; break;
514     case STATUS_BEGIN_STREAM   : s = "BEGIN_STREAM"; break;
515     case STATUS_END_STREAM     : s = "END_STREAM"; break;
516     case STATUS_KEY_CREATED    : s = "KEY_CREATED"; break;
517     case STATUS_UNEXPECTED     : s = "UNEXPECTED"; break;
518     case STATUS_INV_RECP       : s = "INV_RECP"; break;
519     case STATUS_NO_RECP        : s = "NO_RECP"; break;
520     case STATUS_ALREADY_SIGNED : s = "ALREADY_SIGNED"; break;
521     default: s = "?"; break;
522     }
523   return s;
524 }
525
526
527
528 void
529 gpgsm_status (CTRL ctrl, int no, const char *text)
530 {
531   if (ctrl->no_server)
532     {
533       if (ctrl->status_fd == -1)
534         return; /* no status wanted */
535       if (!statusfp)
536         {
537           if (ctrl->status_fd == 1)
538             statusfp = stdout;
539           else if (ctrl->status_fd == 2)
540             statusfp = stderr;
541           else
542             statusfp = fdopen (ctrl->status_fd, "w");
543       
544           if (!statusfp)
545             {
546               log_fatal ("can't open fd %d for status output: %s\n",
547                          ctrl->status_fd, strerror(errno));
548             }
549         }
550       
551       fputs ("[GNUPG:] ", statusfp);
552       fputs (get_status_string (no), statusfp);
553     
554       if (text)
555         {
556           putc ( ' ', statusfp );
557           for (; *text; text++) 
558             {
559               if (*text == '\n')
560                 fputs ( "\\n", statusfp );
561               else if (*text == '\r')
562                 fputs ( "\\r", statusfp );
563               else 
564                 putc ( *(const byte *)text,  statusfp );
565             }
566         }
567       putc ('\n', statusfp);
568       fflush (statusfp);
569     }
570   else 
571     {
572       ASSUAN_CONTEXT ctx = ctrl->server_local->assuan_ctx;
573
574       assuan_write_status (ctx, get_status_string (no), text);
575     }
576 }
577
578
579 #if 0
580 /*
581  * Write a status line with a buffer using %XX escapes.  If WRAP is >
582  * 0 wrap the line after this length.  If STRING is not NULL it will
583  * be prepended to the buffer, no escaping is done for string.
584  * A wrap of -1 forces spaces not to be encoded as %20.
585  */
586 void
587 write_status_text_and_buffer ( int no, const char *string,
588                                const char *buffer, size_t len, int wrap )
589 {
590     const char *s, *text;
591     int esc, first;
592     int lower_limit = ' ';
593     size_t n, count, dowrap;
594
595     if( !statusfp )
596         return;  /* not enabled */
597     
598     if (wrap == -1) {
599         lower_limit--;
600         wrap = 0;
601     }
602
603     text = get_status_string (no);
604     count = dowrap = first = 1;
605     do {
606         if (dowrap) {
607             fprintf (statusfp, "[GNUPG:] %s ", text );
608             count = dowrap = 0;
609             if (first && string) {
610                 fputs (string, statusfp);
611                 count += strlen (string);
612             }
613             first = 0;
614         }
615         for (esc=0, s=buffer, n=len; n && !esc; s++, n-- ) {
616             if ( *s == '%' || *(const byte*)s <= lower_limit 
617                            || *(const byte*)s == 127 ) 
618                 esc = 1;
619             if ( wrap && ++count > wrap ) {
620                 dowrap=1;
621                 break;
622             }
623         }
624         if (esc) {
625             s--; n++;
626         }
627         if (s != buffer) 
628             fwrite (buffer, s-buffer, 1, statusfp );
629         if ( esc ) {
630             fprintf (statusfp, "%%%02X", *(const byte*)s );
631             s++; n--;
632         }
633         buffer = s;
634         len = n;
635         if ( dowrap && len )
636             putc ( '\n', statusfp );
637     } while ( len );
638
639     putc ('\n',statusfp);
640     fflush (statusfp);
641 }
642 #endif
643
644
645
646
647
648
649