* gpg-agent.c (main): Disable core dumps.
[gnupg.git] / agent / command.c
1 /* command.c - gpg-agent command handler
2  *      Copyright (C) 2001, 2002 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 /* FIXME: we should not use the default assuan buffering but setup
22    some buffering in secure mempory to protect session keys etc. */
23
24 #include <config.h>
25 #include <errno.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <unistd.h>
31
32 #include "agent.h"
33 #include "../assuan/assuan.h"
34
35 /* maximum allowed size of the inquired ciphertext */
36 #define MAXLEN_CIPHERTEXT 4096
37 /* maximum allowed size of the key parameters */
38 #define MAXLEN_KEYPARAM 1024
39
40 #define set_error(e,t) assuan_set_error (ctx, ASSUAN_ ## e, (t))
41
42
43 #if MAX_DIGEST_LEN < 20
44 #error MAX_DIGEST_LEN shorter than keygrip
45 #endif
46
47 /* Data used to associate an Assuan context with local server data */
48 struct server_local_s {
49   ASSUAN_CONTEXT assuan_ctx;
50   int message_fd;
51 };
52
53
54
55
56 \f
57 static void
58 reset_notify (ASSUAN_CONTEXT ctx)
59 {
60   CTRL ctrl = assuan_get_pointer (ctx);
61
62   memset (ctrl->keygrip, 0, 20);
63   ctrl->have_keygrip = 0;
64   ctrl->digest.valuelen = 0;
65 }
66
67 /* ISTRUSTED <hexstring_with_fingerprint>
68
69    Return OK when we have an entry with this fingerprint in our
70    trustlist */
71 static int
72 cmd_istrusted (ASSUAN_CONTEXT ctx, char *line)
73 {
74   int rc, n, i;
75   char *p;
76   char fpr[41];
77
78   /* parse the fingerprint value */
79   for (p=line,n=0; hexdigitp (p); p++, n++)
80     ;
81   if (*p || !(n == 40 || n == 32))
82     return set_error (Parameter_Error, "invalid fingerprint");
83   i = 0;
84   if (n==32)
85     {
86       strcpy (fpr, "00000000");
87       i += 8;
88     }
89   for (p=line; i < 40; p++, i++)
90     fpr[i] = *p >= 'a'? (*p & 0xdf): *p;
91   fpr[i] = 0;
92   rc = agent_istrusted (fpr);
93   if (!rc)
94     return 0;
95   else if (rc == -1)
96     return ASSUAN_Not_Trusted;
97   else
98     return map_to_assuan_status (rc);
99 }
100
101 /* LISTTRUSTED 
102
103    List all entries from the trustlist */
104 static int
105 cmd_listtrusted (ASSUAN_CONTEXT ctx, char *line)
106 {
107   return map_to_assuan_status (agent_listtrusted (ctx));
108 }
109
110
111 /* MARKTRUSTED <hexstring_with_fingerprint> <flag>
112
113    Store a new key in into the trustlist*/
114 static int
115 cmd_marktrusted (ASSUAN_CONTEXT ctx, char *line)
116 {
117   return ASSUAN_Not_Implemented;
118 }
119
120
121
122 \f
123 /* SIGKEY <hexstring_with_keygrip>
124    SETKEY <hexstring_with_keygrip>
125   
126    Set the  key used for a sign or decrypt operation */
127 static int
128 cmd_sigkey (ASSUAN_CONTEXT ctx, char *line)
129 {
130   int n;
131   char *p;
132   CTRL ctrl = assuan_get_pointer (ctx);
133   unsigned char *buf;
134
135   /* parse the hash value */
136   for (p=line,n=0; hexdigitp (p); p++, n++)
137     ;
138   if (*p)
139     return set_error (Parameter_Error, "invalid hexstring");
140   if ((n&1))
141     return set_error (Parameter_Error, "odd number of digits");
142   n /= 2;
143   if (n != 20)
144     return set_error (Parameter_Error, "invalid length of keygrip");
145
146   buf = ctrl->keygrip;
147   for (p=line, n=0; n < 20; p += 2, n++)
148     buf[n] = xtoi_2 (p);
149   ctrl->have_keygrip = 1;
150   return 0;
151 }
152
153 /* SETHASH <algonumber> <hexstring> 
154
155   The client can use this command to tell the server about the data
156   (which usually is a hash) to be signed. */
157 static int
158 cmd_sethash (ASSUAN_CONTEXT ctx, char *line)
159 {
160   int n;
161   char *p;
162   CTRL ctrl = assuan_get_pointer (ctx);
163   unsigned char *buf;
164   char *endp;
165   int algo;
166
167   /* parse the algo number and check it */
168   algo = (int)strtoul (line, &endp, 10);
169   for (line = endp; *line == ' ' || *line == '\t'; line++)
170     ;
171   if (!algo || gcry_md_test_algo (algo))
172     return set_error (Unsupported_Algorithm, NULL);
173   ctrl->digest.algo = algo;
174
175   /* parse the hash value */
176   for (p=line,n=0; hexdigitp (p); p++, n++)
177     ;
178   if (*p)
179     return set_error (Parameter_Error, "invalid hexstring");
180   if ((n&1))
181     return set_error (Parameter_Error, "odd number of digits");
182   n /= 2;
183   if (n != 16 && n != 20 && n != 24 && n != 32)
184     return set_error (Parameter_Error, "unsupported length of hash");
185   if (n > MAX_DIGEST_LEN)
186     return set_error (Parameter_Error, "hash value to long");
187
188   buf = ctrl->digest.value;
189   ctrl->digest.valuelen = n;
190   for (p=line, n=0; n < ctrl->digest.valuelen; p += 2, n++)
191     buf[n] = xtoi_2 (p);
192   for (; n < ctrl->digest.valuelen; n++)
193     buf[n] = 0;
194   return 0;
195 }
196
197
198 /* PKSIGN <options>
199
200    Perform the actual sign operation. Neither input nor output are
201    sensitive to eavesdropping */
202 static int
203 cmd_pksign (ASSUAN_CONTEXT ctx, char *line)
204 {
205   int rc;
206   CTRL ctrl = assuan_get_pointer (ctx);
207
208   rc = agent_pksign (ctrl, assuan_get_data_fp (ctx));
209   return map_to_assuan_status (rc);
210 }
211
212 /* PKDECRYPT <options>
213
214    Perform the actual decrypt operation.  Input is not 
215    sensitive to eavesdropping */
216 static int
217 cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line)
218 {
219   int rc;
220   CTRL ctrl = assuan_get_pointer (ctx);
221   char *value;
222   size_t valuelen;
223
224   /* First inquire the data to decrypt */
225   rc = assuan_inquire (ctx, "CIPHERTEXT",
226                        &value, &valuelen, MAXLEN_CIPHERTEXT);
227   if (rc)
228     return rc;
229
230   rc = agent_pkdecrypt (ctrl, value, valuelen, assuan_get_data_fp (ctx));
231   xfree (value);
232   return map_to_assuan_status (rc);
233 }
234
235
236 /* GENKEY
237
238    Generate a new key, store the secret part and return the public
239    part.  Here is an example transaction:
240
241    C: GENKEY
242    S: INQUIRE KEYPARM
243    C: D (genkey (rsa (nbits  1024)))
244    C: END
245    S: D (public-key
246    S: D   (rsa (n 326487324683264) (e 10001)))
247    S  OK key created
248 */
249
250 static int
251 cmd_genkey (ASSUAN_CONTEXT ctx, char *line)
252 {
253   CTRL ctrl = assuan_get_pointer (ctx);
254   int rc;
255   char *value;
256   size_t valuelen;
257
258   /* First inquire the parameters */
259   rc = assuan_inquire (ctx, "KEYPARAM", &value, &valuelen, MAXLEN_KEYPARAM);
260   if (rc)
261     return rc;
262
263   rc = agent_genkey (ctrl, value, valuelen, assuan_get_data_fp (ctx));
264   xfree (value);
265   return map_to_assuan_status (rc);
266 }
267
268
269 /* GET_PASSPHRASE <cache_id> [<error_message> <prompt> <description>]
270
271    This function is usually used to ask for a passphrase to be used
272    for conventional encryption, but may also be used by programs which
273    need specal handling of passphrases.  This command uses a syntax
274    which helps clients to use the agent with minimum effort.  The
275    agent either returns with an error or with a OK followed by the hex
276    encoded passphrase.  Note that the length of the strings is
277    implicitly limited by the maximum length of a command.
278 */
279
280 static int
281 cmd_get_passphrase (ASSUAN_CONTEXT ctx, char *line)
282 {
283   int rc;
284   const char *pw;
285   char *response;
286   char *cacheid = NULL, *desc = NULL, *prompt = NULL, *errtext = NULL;
287   char *p;
288
289   /* parse the stuff */
290   for (p=line; *p == ' '; p++)
291     ;
292   cacheid = p;
293   p = strchr (cacheid, ' ');
294   if (p)
295     {
296       *p++ = 0;
297       while (*p == ' ')
298         p++;
299       errtext = p;
300       p = strchr (errtext, ' ');
301       if (p)
302         {
303           *p++ = 0;
304           while (*p == ' ')
305             p++;
306           prompt = p;
307           p = strchr (prompt, ' ');
308           if (p)
309             {
310               *p++ = 0;
311               while (*p == ' ')
312                 p++;
313               desc = p;
314               p = strchr (desc, ' ');
315               if (p)
316                 *p = 0; /* ignore garbage */
317             }
318         }
319     }
320   if (!cacheid || !*cacheid || strlen (cacheid) > 50)
321     return set_error (Parameter_Error, "invalid length of cacheID");
322   if (!desc)
323     return set_error (Parameter_Error, "no description given");
324
325   if (!strcmp (cacheid, "X"))
326     cacheid = NULL;
327   if (!strcmp (errtext, "X"))
328     errtext = NULL;
329   if (!strcmp (prompt, "X"))
330     prompt = NULL;
331   if (!strcmp (desc, "X"))
332     desc = NULL;
333
334   /* Note: we store the hexified versions in the cache. */
335   pw = cacheid ? agent_get_cache (cacheid) : NULL;
336   if (pw)
337     {
338       assuan_begin_confidential (ctx);
339       rc = assuan_set_okay_line (ctx, pw);
340     }
341   else
342     {
343       rc = agent_get_passphrase (&response, desc, prompt, errtext);
344       if (!rc)
345         {
346           if (cacheid)
347             agent_put_cache (cacheid, response, 0);
348           assuan_begin_confidential (ctx);
349           rc = assuan_set_okay_line (ctx, response);
350           xfree (response);
351         }
352     }
353
354   return map_to_assuan_status (rc);
355 }
356
357
358 /* CLEAR_PASSPHRASE <cache_id>
359
360    may be used to invalidate the cache entry for a passphrase.  The
361    function returns with OK even when there is no cached passphrase.
362 */
363
364 static int
365 cmd_clear_passphrase (ASSUAN_CONTEXT ctx, char *line)
366 {
367   char *cacheid = NULL;
368   char *p;
369
370   /* parse the stuff */
371   for (p=line; *p == ' '; p++)
372     ;
373   cacheid = p;
374   p = strchr (cacheid, ' ');
375   if (p)
376     *p = 0; /* ignore garbage */
377   if (!cacheid || !*cacheid || strlen (cacheid) > 50)
378     return set_error (Parameter_Error, "invalid length of cacheID");
379
380   agent_put_cache (cacheid, NULL, 0);
381   return 0;
382 }
383
384
385 \f
386 /* Tell the assuan library about our commands */
387 static int
388 register_commands (ASSUAN_CONTEXT ctx)
389 {
390   static struct {
391     const char *name;
392     int cmd_id;
393     int (*handler)(ASSUAN_CONTEXT, char *line);
394   } table[] = {
395     { "ISTRUSTED",  0,  cmd_istrusted },
396     { "SIGKEY",     0,  cmd_sigkey },
397     { "SETKEY",     0,  cmd_sigkey },
398     { "SETHASH",    0,  cmd_sethash },
399     { "PKSIGN",     0,  cmd_pksign },
400     { "PKDECRYPT",  0,  cmd_pkdecrypt },
401     { "GENKEY",     0,  cmd_genkey },
402     { "GET_PASSPHRASE",0, cmd_get_passphrase },
403     { "CLEAR_PASSPHRASE",0, cmd_clear_passphrase },
404     { "LISTTRUSTED",  0,  cmd_listtrusted },
405     { "MARKTRUSTED",  0,  cmd_marktrusted },
406     { "",     ASSUAN_CMD_INPUT, NULL }, 
407     { "",     ASSUAN_CMD_OUTPUT, NULL }, 
408     { NULL }
409   };
410   int i, j, rc;
411
412   for (i=j=0; table[i].name; i++)
413     {
414       rc = assuan_register_command (ctx,
415                                     table[i].cmd_id? table[i].cmd_id
416                                                    : (ASSUAN_CMD_USER + j++),
417                                     table[i].name, table[i].handler);
418       if (rc)
419         return rc;
420     } 
421   assuan_register_reset_notify (ctx, reset_notify);
422   return 0;
423 }
424
425
426 /* Startup the server.  If LISTEN_FD is given as -1, this is simple
427    piper server, otherwise it is a regular server */
428 void
429 start_command_handler (int listen_fd)
430 {
431   int rc;
432   ASSUAN_CONTEXT ctx;
433   struct server_control_s ctrl;
434
435   memset (&ctrl, 0, sizeof ctrl);
436
437   
438   if (listen_fd == -1)
439     {
440       int filedes[2];
441
442       filedes[0] = 0;
443       filedes[1] = 1;
444       rc = assuan_init_pipe_server (&ctx, filedes);
445     }
446   else
447     {
448       rc = assuan_init_socket_server (&ctx, listen_fd);
449     }
450   if (rc)
451     {
452       log_error ("failed to initialize the server: %s\n",
453                  assuan_strerror(rc));
454       agent_exit (2);
455     }
456   rc = register_commands (ctx);
457   if (rc)
458     {
459       log_error ("failed to register commands with Assuan: %s\n",
460                  assuan_strerror(rc));
461       agent_exit (2);
462     }
463
464   assuan_set_pointer (ctx, &ctrl);
465   ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
466   ctrl.server_local->assuan_ctx = ctx;
467   ctrl.server_local->message_fd = -1;
468
469   if (DBG_ASSUAN)
470     assuan_set_log_stream (ctx, log_get_stream ());
471
472   for (;;)
473     {
474       rc = assuan_accept (ctx);
475       if (rc == -1)
476         {
477           break;
478         }
479       else if (rc)
480         {
481           log_info ("Assuan accept problem: %s\n", assuan_strerror (rc));
482           break;
483         }
484       
485       rc = assuan_process (ctx);
486       if (rc)
487         {
488           log_info ("Assuan processing failed: %s\n", assuan_strerror (rc));
489           continue;
490         }
491     }
492
493
494   assuan_deinit_server (ctx);
495 }
496
497
498