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