fe740964b742b55b9e2a490fbb42abd75113f742
[gnupg.git] / sm / call-agent.c
1 /* call-agent.c - divert operations to the agent
2  *      Copyright (C) 2001, 2002, 2003 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 <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <unistd.h> 
27 #include <time.h>
28 #include <assert.h>
29 #ifdef HAVE_LOCALE_H
30 #include <locale.h>
31 #endif
32
33 #include "gpgsm.h"
34 #include <gcrypt.h>
35 #include <assuan.h>
36 #include "i18n.h"
37 #include "keydb.h" /* fixme: Move this to import.c */
38 #include "../common/membuf.h"
39
40
41 static ASSUAN_CONTEXT agent_ctx = NULL;
42 static int force_pipe_server = 0;
43
44 struct cipher_parm_s {
45   ASSUAN_CONTEXT ctx;
46   const char *ciphertext;
47   size_t ciphertextlen;
48 };
49
50 struct genkey_parm_s {
51   ASSUAN_CONTEXT ctx;
52   const char *sexp;
53   size_t sexplen;
54 };
55
56 struct learn_parm_s {
57   int error;
58   ASSUAN_CONTEXT ctx;
59   membuf_t *data;
60 };
61
62
63 \f
64 /* Try to connect to the agent via socket or fork it off and work by
65    pipes.  Handle the server's initial greeting */
66 static int
67 start_agent (void)
68 {
69   int rc = 0;
70   char *infostr, *p;
71   ASSUAN_CONTEXT ctx;
72   char *dft_display = NULL;
73   char *dft_ttyname = NULL;
74   char *dft_ttytype = NULL;
75   char *old_lc = NULL;
76   char *dft_lc = NULL;
77
78   if (agent_ctx)
79     return 0; /* fixme: We need a context for each thread or serialize
80                  the access to the agent (which is suitable given that
81                  the agent is not MT */
82
83   infostr = force_pipe_server? NULL : getenv ("GPG_AGENT_INFO");
84   if (!infostr)
85     {
86       const char *pgmname;
87       const char *argv[3];
88       int no_close_list[3];
89       int i;
90
91       if (opt.verbose)
92         log_info (_("no running gpg-agent - starting one\n"));
93
94       if (fflush (NULL))
95         {
96           gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
97           log_error ("error flushing pending output: %s\n", strerror (errno));
98           return tmperr;
99         }
100
101       if (!opt.agent_program || !*opt.agent_program)
102         opt.agent_program = GNUPG_DEFAULT_AGENT;
103       if ( !(pgmname = strrchr (opt.agent_program, '/')))
104         pgmname = opt.agent_program;
105       else
106         pgmname++;
107
108       argv[0] = pgmname;
109       argv[1] = "--server";
110       argv[2] = NULL;
111
112       i=0;
113       if (log_get_fd () != -1)
114         no_close_list[i++] = log_get_fd ();
115       no_close_list[i++] = fileno (stderr);
116       no_close_list[i] = -1;
117
118       /* connect to the agent and perform initial handshaking */
119       rc = assuan_pipe_connect (&ctx, opt.agent_program, (char**)argv,
120                                 no_close_list);
121     }
122   else
123     {
124       int prot;
125       int pid;
126
127       infostr = xstrdup (infostr);
128       if ( !(p = strchr (infostr, ':')) || p == infostr)
129         {
130           log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
131           xfree (infostr);
132           force_pipe_server = 1;
133           return start_agent ();
134         }
135       *p++ = 0;
136       pid = atoi (p);
137       while (*p && *p != ':')
138         p++;
139       prot = *p? atoi (p+1) : 0;
140       if (prot != 1)
141         {
142           log_error (_("gpg-agent protocol version %d is not supported\n"),
143                      prot);
144           xfree (infostr);
145           force_pipe_server = 1;
146           return start_agent ();
147         }
148
149       rc = assuan_socket_connect (&ctx, infostr, pid);
150       xfree (infostr);
151       if (rc == ASSUAN_Connect_Failed)
152         {
153           log_error (_("can't connect to the agent - trying fall back\n"));
154           force_pipe_server = 1;
155           return start_agent ();
156         }
157     }
158
159   if (rc)
160     {
161       log_error ("can't connect to the agent: %s\n", assuan_strerror (rc));
162       return gpg_error (GPG_ERR_NO_AGENT);
163     }
164   agent_ctx = ctx;
165
166   if (DBG_ASSUAN)
167     log_debug ("connection to agent established\n");
168
169   rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
170   if (rc)
171     return map_assuan_err (rc);
172
173   dft_display = getenv ("DISPLAY");
174   if (opt.display || dft_display)
175     {
176       char *optstr;
177       if (asprintf (&optstr, "OPTION display=%s",
178                     opt.display ? opt.display : dft_display) < 0)
179         return OUT_OF_CORE (errno);
180       rc = assuan_transact (agent_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
181                             NULL);
182       free (optstr);
183       if (rc)
184         return map_assuan_err (rc);
185     }
186   if (!opt.ttyname)
187     {
188       dft_ttyname = getenv ("GPG_TTY");
189       if ((!dft_ttyname || !*dft_ttyname) && ttyname (0))
190         dft_ttyname = ttyname (0);
191     }
192   if (opt.ttyname || dft_ttyname)
193     {
194       char *optstr;
195       if (asprintf (&optstr, "OPTION ttyname=%s",
196                     opt.ttyname ? opt.ttyname : dft_ttyname) < 0)
197         return OUT_OF_CORE (errno);
198       rc = assuan_transact (agent_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
199                             NULL);
200       free (optstr);
201       if (rc)
202         return map_assuan_err (rc);
203     }
204   dft_ttytype = getenv ("TERM");
205   if (opt.ttytype || (dft_ttyname && dft_ttytype))
206     {
207       char *optstr;
208       if (asprintf (&optstr, "OPTION ttytype=%s",
209                     opt.ttyname ? opt.ttytype : dft_ttytype) < 0)
210         return OUT_OF_CORE (errno);
211       rc = assuan_transact (agent_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
212                             NULL);
213       free (optstr);
214       if (rc)
215         return map_assuan_err (rc);
216     }
217 #if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
218   old_lc = setlocale (LC_CTYPE, NULL);
219   if (old_lc)
220     {
221       old_lc = strdup (old_lc);
222       if (!old_lc)
223         return OUT_OF_CORE (errno);
224     }
225   dft_lc = setlocale (LC_CTYPE, "");
226 #endif
227   if (opt.lc_ctype || (dft_ttyname && dft_lc))
228     {
229       char *optstr;
230       if (asprintf (&optstr, "OPTION lc-ctype=%s",
231                     opt.lc_ctype ? opt.lc_ctype : dft_lc) < 0)
232         rc = OUT_OF_CORE (errno);
233       else
234         {
235           rc = assuan_transact (agent_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
236                                 NULL);
237           free (optstr);
238           if (rc)
239             rc = map_assuan_err (rc);
240         }
241     }
242 #if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
243   if (old_lc)
244     {
245       setlocale (LC_CTYPE, old_lc);
246       free (old_lc);
247     }
248 #endif
249   if (rc)
250     return rc;
251 #if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
252   old_lc = setlocale (LC_MESSAGES, NULL);
253   if (old_lc)
254     {
255       old_lc = strdup (old_lc);
256       if (!old_lc)
257         return OUT_OF_CORE (errno);
258     }
259   dft_lc = setlocale (LC_MESSAGES, "");
260 #endif
261   if (opt.lc_messages || (dft_ttyname && dft_lc))
262     {
263       char *optstr;
264       if (asprintf (&optstr, "OPTION lc-messages=%s",
265                     opt.lc_messages ? opt.lc_messages : dft_lc) < 0)
266         rc = OUT_OF_CORE (errno);
267       else
268         {
269           rc = assuan_transact (agent_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
270                                 NULL);
271           free (optstr);
272           if (rc)
273             rc = map_assuan_err (rc);
274         }
275     }
276 #if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
277   if (old_lc)
278     {
279       setlocale (LC_MESSAGES, old_lc);
280       free (old_lc);
281     }
282 #endif
283
284   return rc;
285 }
286
287
288 static AssuanError
289 membuf_data_cb (void *opaque, const void *buffer, size_t length)
290 {
291   membuf_t *data = opaque;
292
293   if (buffer)
294     put_membuf (data, buffer, length);
295   return 0;
296 }
297   
298
299
300 \f
301 /* Call the agent to do a sign operation using the key identified by
302    the hex string KEYGRIP. */
303 int
304 gpgsm_agent_pksign (const char *keygrip,
305                     unsigned char *digest, size_t digestlen, int digestalgo,
306                     char **r_buf, size_t *r_buflen )
307 {
308   int rc, i;
309   char *p, line[ASSUAN_LINELENGTH];
310   membuf_t data;
311   size_t len;
312
313   *r_buf = NULL;
314   rc = start_agent ();
315   if (rc)
316     return rc;
317
318   if (digestlen*2 + 50 > DIM(line))
319     return gpg_error (GPG_ERR_GENERAL);
320
321   rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
322   if (rc)
323     return map_assuan_err (rc);
324
325   snprintf (line, DIM(line)-1, "SIGKEY %s", keygrip);
326   line[DIM(line)-1] = 0;
327   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
328   if (rc)
329     return map_assuan_err (rc);
330
331   sprintf (line, "SETHASH %d ", digestalgo);
332   p = line + strlen (line);
333   for (i=0; i < digestlen ; i++, p += 2 )
334     sprintf (p, "%02X", digest[i]);
335   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
336   if (rc)
337     return map_assuan_err (rc);
338
339   init_membuf (&data, 1024);
340   rc = assuan_transact (agent_ctx, "PKSIGN",
341                         membuf_data_cb, &data, NULL, NULL, NULL, NULL);
342   if (rc)
343     {
344       xfree (get_membuf (&data, &len));
345       return map_assuan_err (rc);
346     }
347   *r_buf = get_membuf (&data, r_buflen);
348
349   if (!gcry_sexp_canon_len (*r_buf, *r_buflen, NULL, NULL))
350     {
351       xfree (*r_buf); *r_buf = NULL;
352       return gpg_error (GPG_ERR_INV_VALUE);
353     }
354
355   return *r_buf? 0 : OUT_OF_CORE (errno);
356 }
357
358
359
360 \f
361 /* Handle a CIPHERTEXT inquiry.  Note, we only send the data,
362    assuan_transact talkes care of flushing and writing the end */
363 static AssuanError
364 inq_ciphertext_cb (void *opaque, const char *keyword)
365 {
366   struct cipher_parm_s *parm = opaque; 
367   AssuanError rc;
368
369   assuan_begin_confidential (parm->ctx);
370   rc = assuan_send_data (parm->ctx, parm->ciphertext, parm->ciphertextlen);
371   assuan_end_confidential (parm->ctx);
372   return rc; 
373 }
374
375
376 /* Call the agent to do a decrypt operation using the key identified by
377    the hex string KEYGRIP. */
378 int
379 gpgsm_agent_pkdecrypt (const char *keygrip,
380                        ksba_const_sexp_t ciphertext, 
381                        char **r_buf, size_t *r_buflen )
382 {
383   int rc;
384   char line[ASSUAN_LINELENGTH];
385   membuf_t data;
386   struct cipher_parm_s cipher_parm;
387   size_t n, len;
388   char *buf, *endp;
389   size_t ciphertextlen;
390   
391   if (!keygrip || strlen(keygrip) != 40 || !ciphertext || !r_buf || !r_buflen)
392     return gpg_error (GPG_ERR_INV_VALUE);
393   *r_buf = NULL;
394
395   ciphertextlen = gcry_sexp_canon_len (ciphertext, 0, NULL, NULL);
396   if (!ciphertextlen)
397     return gpg_error (GPG_ERR_INV_VALUE);
398
399   rc = start_agent ();
400   if (rc)
401     return rc;
402
403   rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
404   if (rc)
405     return map_assuan_err (rc);
406
407   assert ( DIM(line) >= 50 );
408   snprintf (line, DIM(line)-1, "SETKEY %s", keygrip);
409   line[DIM(line)-1] = 0;
410   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
411   if (rc)
412     return map_assuan_err (rc);
413
414   init_membuf (&data, 1024);
415   cipher_parm.ctx = agent_ctx;
416   cipher_parm.ciphertext = ciphertext;
417   cipher_parm.ciphertextlen = ciphertextlen;
418   rc = assuan_transact (agent_ctx, "PKDECRYPT",
419                         membuf_data_cb, &data,
420                         inq_ciphertext_cb, &cipher_parm, NULL, NULL);
421   if (rc)
422     {
423       xfree (get_membuf (&data, &len));
424       return map_assuan_err (rc);
425     }
426
427   put_membuf (&data, "", 1); /* make sure it is 0 terminated */
428   buf = get_membuf (&data, &len);
429   if (!buf)
430     return gpg_error (GPG_ERR_ENOMEM);
431   /* FIXME: We would better a return a full S-exp and not just a part */
432   assert (len);
433   len--; /* remove the terminating 0 */
434   n = strtoul (buf, &endp, 10);
435   if (!n || *endp != ':')
436     return gpg_error (GPG_ERR_INV_SEXP);
437   endp++;
438   if (endp-buf+n > len)
439     return gpg_error (GPG_ERR_INV_SEXP); /* oops len does not
440                                             match internal len*/
441   memmove (buf, endp, n);
442   *r_buflen = n;
443   *r_buf = buf;
444   return 0;
445 }
446
447
448
449
450 \f
451 /* Handle a KEYPARMS inquiry.  Note, we only send the data,
452    assuan_transact takes care of flushing and writing the end */
453 static AssuanError
454 inq_genkey_parms (void *opaque, const char *keyword)
455 {
456   struct genkey_parm_s *parm = opaque; 
457   AssuanError rc;
458
459   rc = assuan_send_data (parm->ctx, parm->sexp, parm->sexplen);
460   return rc; 
461 }
462
463
464 \f
465 /* Call the agent to generate a newkey */
466 int
467 gpgsm_agent_genkey (ksba_const_sexp_t keyparms, ksba_sexp_t *r_pubkey)
468 {
469   int rc;
470   struct genkey_parm_s gk_parm;
471   membuf_t data;
472   size_t len;
473   char *buf;
474
475   *r_pubkey = NULL;
476   rc = start_agent ();
477   if (rc)
478     return rc;
479
480   rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
481   if (rc)
482     return map_assuan_err (rc);
483
484   init_membuf (&data, 1024);
485   gk_parm.ctx = agent_ctx;
486   gk_parm.sexp = keyparms;
487   gk_parm.sexplen = gcry_sexp_canon_len (keyparms, 0, NULL, NULL);
488   if (!gk_parm.sexplen)
489     return gpg_error (GPG_ERR_INV_VALUE);
490   rc = assuan_transact (agent_ctx, "GENKEY",
491                         membuf_data_cb, &data, 
492                         inq_genkey_parms, &gk_parm, NULL, NULL);
493   if (rc)
494     {
495       xfree (get_membuf (&data, &len));
496       return map_assuan_err (rc);
497     }
498   buf = get_membuf (&data, &len);
499   if (!buf)
500     return gpg_error (GPG_ERR_ENOMEM);
501   if (!gcry_sexp_canon_len (buf, len, NULL, NULL))
502     {
503       xfree (buf);
504       return gpg_error (GPG_ERR_INV_SEXP);
505     }
506   *r_pubkey = buf;
507   return 0;
508 }
509
510 \f
511 /* Ask the agent whether the certificate is in the list of trusted
512    keys */
513 int
514 gpgsm_agent_istrusted (ksba_cert_t cert)
515 {
516   int rc;
517   char *fpr;
518   char line[ASSUAN_LINELENGTH];
519
520   rc = start_agent ();
521   if (rc)
522     return rc;
523
524   fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
525   if (!fpr)
526     {
527       log_error ("error getting the fingerprint\n");
528       return gpg_error (GPG_ERR_GENERAL);
529     }
530
531   snprintf (line, DIM(line)-1, "ISTRUSTED %s", fpr);
532   line[DIM(line)-1] = 0;
533   xfree (fpr);
534
535   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
536   return map_assuan_err (rc);
537 }
538
539 /* Ask the agent to mark CERT as a trusted Root-CA one */
540 int
541 gpgsm_agent_marktrusted (ksba_cert_t cert)
542 {
543   int rc;
544   char *fpr, *dn;
545   char line[ASSUAN_LINELENGTH];
546
547   rc = start_agent ();
548   if (rc)
549     return rc;
550
551   fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
552   if (!fpr)
553     {
554       log_error ("error getting the fingerprint\n");
555       return gpg_error (GPG_ERR_GENERAL);
556     }
557
558   dn = ksba_cert_get_issuer (cert, 0);
559   if (!dn)
560     {
561       xfree (fpr);
562       return gpg_error (GPG_ERR_GENERAL);
563     }
564   snprintf (line, DIM(line)-1, "MARKTRUSTED %s S %s", fpr, dn);
565   line[DIM(line)-1] = 0;
566   ksba_free (dn);
567   xfree (fpr);
568
569   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
570   return map_assuan_err (rc);
571 }
572
573
574 \f
575 /* Ask the agent whether the a corresponding secret key is available
576    for the given keygrip */
577 int
578 gpgsm_agent_havekey (const char *hexkeygrip)
579 {
580   int rc;
581   char line[ASSUAN_LINELENGTH];
582
583   rc = start_agent ();
584   if (rc)
585     return rc;
586
587   if (!hexkeygrip || strlen (hexkeygrip) != 40)
588     return gpg_error (GPG_ERR_INV_VALUE);
589
590   snprintf (line, DIM(line)-1, "HAVEKEY %s", hexkeygrip);
591   line[DIM(line)-1] = 0;
592
593   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
594   return map_assuan_err (rc);
595 }
596
597 \f
598 static AssuanError
599 learn_cb (void *opaque, const void *buffer, size_t length)
600 {
601   struct learn_parm_s *parm = opaque;
602   size_t len;
603   char *buf;
604   ksba_cert_t cert;
605   int rc;
606
607   if (parm->error)
608     return 0;
609
610   if (buffer)
611     {
612       put_membuf (parm->data, buffer, length);
613       return 0;
614     }
615   /* END encountered - process what we have */
616   buf = get_membuf (parm->data, &len);
617   if (!buf)
618     {
619       parm->error = gpg_error (GPG_ERR_ENOMEM);
620       return 0;
621     }
622
623
624   /* FIXME: this should go into import.c */
625   rc = ksba_cert_new (&cert);
626   if (rc)
627     {
628       parm->error = rc;
629       return 0;
630     }
631   rc = ksba_cert_init_from_mem (cert, buf, len);
632   if (rc)
633     {
634       log_error ("failed to parse a certificate: %s\n", gpg_strerror (rc));
635       ksba_cert_release (cert);
636       parm->error = rc;
637       return 0;
638     }
639
640   rc = gpgsm_basic_cert_check (cert);
641   if (gpg_err_code (rc) == GPG_ERR_MISSING_CERT)
642     { /* For later use we store it in the ephemeral database. */
643       log_info ("issuer certificate missing - storing as ephemeral\n");
644       keydb_store_cert (cert, 1, NULL);
645     }
646   else if (rc)
647     log_error ("invalid certificate: %s\n", gpg_strerror (rc));
648   else
649     {
650       int existed;
651
652       if (!keydb_store_cert (cert, 0, &existed))
653         {
654           if (opt.verbose > 1 && existed)
655             log_info ("certificate already in DB\n");
656           else if (opt.verbose && !existed)
657             log_info ("certificate imported\n");
658         }
659     }
660
661   ksba_cert_release (cert);
662   init_membuf (parm->data, 4096);
663   return 0;
664 }
665   
666 /* Call the agent to learn about a smartcard */
667 int
668 gpgsm_agent_learn ()
669 {
670   int rc;
671   struct learn_parm_s learn_parm;
672   membuf_t data;
673   size_t len;
674
675   rc = start_agent ();
676   if (rc)
677     return rc;
678
679   init_membuf (&data, 4096);
680   learn_parm.error = 0;
681   learn_parm.ctx = agent_ctx;
682   learn_parm.data = &data;
683   rc = assuan_transact (agent_ctx, "LEARN --send",
684                         learn_cb, &learn_parm, 
685                         NULL, NULL, NULL, NULL);
686   xfree (get_membuf (&data, &len));
687   if (rc)
688     return map_assuan_err (rc);
689   return learn_parm.error;
690 }
691
692 \f
693 /* Ask the agent to change the passphrase of the key identified by HEXKEYGRIP. */
694 int
695 gpgsm_agent_passwd (const char *hexkeygrip)
696 {
697   int rc;
698   char line[ASSUAN_LINELENGTH];
699
700   rc = start_agent ();
701   if (rc)
702     return rc;
703
704   if (!hexkeygrip || strlen (hexkeygrip) != 40)
705     return gpg_error (GPG_ERR_INV_VALUE);
706
707   snprintf (line, DIM(line)-1, "PASSWD %s", hexkeygrip);
708   line[DIM(line)-1] = 0;
709
710   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
711   return map_assuan_err (rc);
712 }
713