Add a way to get a listing of available CCID readers.
[gnupg.git] / tools / gpg-connect-agent.c
1 /* gpg-connect-agent.c - Tool to connect to the agent.
2  *      Copyright (C) 2005, 2007 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19  * USA.
20  */
21
22 #include <config.h>
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <ctype.h>
29 #include <assuan.h>
30
31 #include "i18n.h"
32 #include "../common/util.h"
33 #include "../common/asshelp.h"
34
35
36
37 /* Constants to identify the commands and options. */
38 enum cmd_and_opt_values
39   {
40     aNull = 0,
41     oQuiet      = 'q',
42     oVerbose    = 'v',
43     oRawSocket  = 'S',
44     oExec       = 'E',
45
46     oNoVerbose  = 500,
47     oHomedir,
48     oHex,
49     oDecode,
50     oNoExtConnect
51
52   };
53
54
55 /* The list of commands and options. */
56 static ARGPARSE_OPTS opts[] =
57   {
58     { 301, NULL, 0, N_("@\nOptions:\n ") },
59     
60     { oVerbose, "verbose",  0, N_("verbose") },
61     { oQuiet, "quiet",      0, N_("quiet") },
62     { oHex,   "hex",        0, N_("print data out hex encoded") },
63     { oDecode,"decode",     0, N_("decode received data lines") },
64     { oRawSocket, "raw-socket", 2, N_("|NAME|connect to Assuan socket NAME")},
65     { oExec, "exec", 0, N_("run the Assuan server given on the command line")},
66     { oNoExtConnect, "no-ext-connect",
67                             0, N_("do not use extended connect mode")},
68
69     /* hidden options */
70     { oNoVerbose, "no-verbose",  0, "@"},
71     { oHomedir, "homedir", 2, "@" },   
72     {0}
73   };
74
75
76 /* We keep all global options in the structure OPT.  */
77 struct
78 {
79   int verbose;          /* Verbosity level.  */
80   int quiet;            /* Be extra quiet.  */
81   const char *homedir;  /* Configuration directory name */
82   int hex;              /* Print data lines in hex format. */
83   int decode;           /* Decode received data lines.  */
84   const char *raw_socket; /* Name of socket to connect in raw mode. */
85   int exec;             /* Run the pgm given on the command line. */
86   unsigned int connect_flags;    /* Flags used for connecting. */
87 } opt;
88
89
90
91 /* Definitions for /definq commands and a global linked list with all
92    the definitions. */
93 struct definq_s
94 {
95   struct definq_s *next;
96   char *name;     /* Name of inquiry or NULL for any name. */
97   int is_prog;     /* True if this is a program to run. */
98   char file[1];   /* Name of file or program. */
99 };
100 typedef struct definq_s *definq_t;
101
102 static definq_t definq_list;
103 static definq_t *definq_list_tail = &definq_list;
104
105
106
107 /*-- local prototypes --*/
108 static int read_and_print_response (assuan_context_t ctx);
109 static assuan_context_t start_agent (void);
110
111
112
113 \f
114 /* Print usage information and and provide strings for help. */
115 static const char *
116 my_strusage( int level )
117 {
118   const char *p;
119
120   switch (level)
121     {
122     case 11: p = "gpg-connect-agent (GnuPG)";
123       break;
124     case 13: p = VERSION; break;
125     case 17: p = PRINTABLE_OS_NAME; break;
126     case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
127       break;
128     case 1:
129     case 40: p = _("Usage: gpg-connect-agent [options] (-h for help)");
130       break;
131     case 41:
132       p = _("Syntax: gpg-connect-agent [options]\n"
133             "Connect to a running agent and send commands\n");
134       break;
135     case 31: p = "\nHome: "; break;
136     case 32: p = opt.homedir; break;
137     case 33: p = "\n"; break;
138
139     default: p = NULL; break;
140     }
141   return p;
142 }
143
144
145 /* Initialize the gettext system. */
146 static void
147 i18n_init(void)
148 {
149 #ifdef USE_SIMPLE_GETTEXT
150   set_gettext_file (PACKAGE_GT);
151 #else
152 # ifdef ENABLE_NLS
153   setlocale (LC_ALL, "" );
154   bindtextdomain (PACKAGE_GT, LOCALEDIR);
155   textdomain (PACKAGE_GT);
156 # endif
157 #endif
158 }
159
160 /* Store an inquire response pattern.  Note, that this function may
161    change the content of LINE.  We assume that leading white spaces
162    are already removed. */
163 static void
164 add_definq (char *line, int is_prog)
165 {
166   definq_t d;
167   char *name, *p;
168
169   /* Get name. */
170   name = line;
171   for (p=name; *p && !spacep (p); p++)
172     ;
173   if (*p)
174     *p++ = 0;
175   while (spacep (p))
176     p++;
177
178   d = xmalloc (sizeof *d + strlen (p) );
179   strcpy (d->file, p);
180   d->is_prog = is_prog;
181   if ( !strcmp (name, "*"))
182     d->name = NULL;
183   else
184     d->name = xstrdup (name);
185
186   d->next = NULL;
187   *definq_list_tail = d;
188   definq_list_tail = &d->next;
189 }
190
191
192 /* Show all inquiry defintions. */
193 static void
194 show_definq (void)
195 {
196   definq_t d;
197
198   for (d=definq_list; d; d = d->next)
199     if (d->name)
200       printf ("%-20s %c %s\n", d->name, d->is_prog? 'p':'f', d->file);
201   for (d=definq_list; d; d = d->next)
202     if (!d->name)
203       printf ("%-20s %c %s\n", "*", d->is_prog? 'p':'f', d->file);
204 }
205
206
207 /* Clear all inquiry definitions. */
208 static void
209 clear_definq (void)
210 {
211   while (definq_list)
212     { 
213       definq_t tmp = definq_list->next;
214       xfree (definq_list->name);
215       xfree (definq_list);
216       definq_list = tmp;
217     }
218   definq_list_tail = &definq_list;
219 }      
220
221
222 static void
223 do_sendfd (assuan_context_t ctx, char *line)
224 {
225   FILE *fp;
226   char *name, *mode, *p;
227   int rc, fd;
228
229   /* Get file name. */
230   name = line;
231   for (p=name; *p && !spacep (p); p++)
232     ;
233   if (*p)
234     *p++ = 0;
235   while (spacep (p))
236     p++;
237
238   /* Get mode.  */
239   mode = p;
240   if (!*mode)
241     mode = "r";
242   else
243     {
244       for (p=mode; *p && !spacep (p); p++)
245         ;
246       if (*p)
247         *p++ = 0;
248     }
249
250   /* Open and send. */
251   fp = fopen (name, mode);
252   if (!fp)
253     {
254       log_error ("can't open `%s' in \"%s\" mode: %s\n",
255                  name, mode, strerror (errno));
256       return;
257     }
258   fd = fileno (fp);
259
260   if (opt.verbose)
261     log_error ("file `%s' opened in \"%s\" mode, fd=%d\n",
262                name, mode, fd);
263
264   rc = assuan_sendfd (ctx, fd);
265   if (rc)
266     log_error ("sednig  descriptor %d failed: %s\n", fd, gpg_strerror (rc));
267   fclose (fp);
268 }
269
270
271 static void
272 do_recvfd (assuan_context_t ctx, char *line)
273 {
274   log_info ("This command has not yet been implemented\n");
275 }
276
277
278
279 /* gpg-connect-agent's entry point. */
280 int
281 main (int argc, char **argv)
282 {
283   ARGPARSE_ARGS pargs;
284   int no_more_options = 0;
285   assuan_context_t ctx;
286   char *line, *p;
287   size_t linesize;
288   int rc;
289
290   set_strusage (my_strusage);
291   log_set_prefix ("gpg-connect-agent", 1);
292   assuan_set_assuan_err_source (0);
293
294   i18n_init();
295
296   opt.homedir = default_homedir ();
297   opt.connect_flags = 1; /* Use extended connect mode.  */
298
299   /* Parse the command line. */
300   pargs.argc  = &argc;
301   pargs.argv  = &argv;
302   pargs.flags =  1;  /* Do not remove the args.  */
303   while (!no_more_options && optfile_parse (NULL, NULL, NULL, &pargs, opts))
304     {
305       switch (pargs.r_opt)
306         {
307         case oQuiet:     opt.quiet = 1; break;
308         case oVerbose:   opt.verbose++; break;
309         case oNoVerbose: opt.verbose = 0; break;
310         case oHomedir:   opt.homedir = pargs.r.ret_str; break;
311         case oHex:       opt.hex = 1; break;
312         case oDecode:    opt.decode = 1; break;
313         case oRawSocket: opt.raw_socket = pargs.r.ret_str; break;
314         case oExec:      opt.exec = 1; break;
315         case oNoExtConnect: opt.connect_flags &= ~(1); break;
316
317         default: pargs.err = 2; break;
318         }
319     }
320
321   if (log_get_errorcount (0))
322     exit (2);
323
324   if (opt.exec)
325     {
326       if (!argc)
327         {
328           log_error (_("option \"%s\" requires a program "
329                        "and optional arguments\n"), "--exec" );
330           exit (1);
331         }
332     }
333   else if (argc)
334     usage (1);
335
336   if (opt.exec && opt.raw_socket)
337     log_info (_("option \"%s\" ignored due to \"%s\"\n"),
338               "--raw-socket", "--exec");
339
340   if (opt.exec)
341     {
342       int no_close[3];
343
344       no_close[0] = fileno (stderr);
345       no_close[1] = log_get_fd ();
346       no_close[2] = -1;
347       rc = assuan_pipe_connect_ext (&ctx, *argv, (const char **)argv,
348                                     no_close, NULL, NULL,
349                                     opt.connect_flags);
350       if (rc)
351         {
352           log_error ("assuan_pipe_connect_ext failed: %s\n",
353                      gpg_strerror (rc));
354           exit (1);
355         }
356
357       if (opt.verbose)
358         log_info ("server `%s' started\n", *argv);
359
360     }
361   else if (opt.raw_socket)
362     {
363       rc = assuan_socket_connect_ext (&ctx, opt.raw_socket, 0,
364                                       opt.connect_flags);
365       if (rc)
366         {
367           log_error ("can't connect to socket `%s': %s\n",
368                      opt.raw_socket, gpg_strerror (rc));
369           exit (1);
370         }
371
372       if (opt.verbose)
373         log_info ("connection to socket `%s' established\n", opt.raw_socket);
374     }
375   else
376     ctx = start_agent ();
377   line = NULL;
378   linesize = 0;
379   for (;;)
380     {
381       int n;
382       size_t maxlength;
383
384       maxlength = 2048;
385       n = read_line (stdin, &line, &linesize, &maxlength);
386       if (n < 0)
387         {
388           log_error (_("error reading input: %s\n"), strerror (errno));
389           exit (1);
390         }
391       if (!n)
392         break; /* EOF */
393       if (!maxlength)
394         {
395           log_error (_("line too long - skipped\n"));
396           continue;
397         }
398       if (memchr (line, 0, n))
399         log_info (_("line shortened due to embedded Nul character\n"));
400       if (line[n-1] == '\n')
401         line[n-1] = 0;
402       if (*line == '/')
403         {
404           /* Handle control commands. */
405           char *cmd = line+1;
406
407           for (p=cmd; *p && !spacep (p); p++)
408             ;
409           if (*p)
410             *p++ = 0;
411           while (spacep (p))
412             p++;
413           if (!strcmp (cmd, "definqfile"))
414             {
415               add_definq (p, 0);
416             }
417           else if (!strcmp (cmd, "definqprog"))
418             {
419               add_definq (p, 1);
420             }
421           else if (!strcmp (cmd, "showdef"))
422             {
423               show_definq ();
424             }
425           else if (!strcmp (cmd, "cleardef"))
426             {
427               clear_definq ();
428             }
429           else if (!strcmp (cmd, "echo"))
430             {
431               puts (p);
432             }
433           else if (!strcmp (cmd, "sendfd"))
434             {
435               do_sendfd (ctx, p);
436               continue;
437             }
438           else if (!strcmp (cmd, "recvfd"))
439             {
440               do_recvfd (ctx, p);
441               continue;
442             }
443           else if (!strcmp (cmd, "hex"))
444             opt.hex = 1;
445           else if (!strcmp (cmd, "nohex"))
446             opt.hex = 0;
447           else if (!strcmp (cmd, "decode"))
448             opt.decode = 1;
449           else if (!strcmp (cmd, "nodecode"))
450             opt.decode = 0;
451           else if (!strcmp (cmd, "help"))
452             {
453               puts (
454 "Available commands:\n"
455 "/echo ARGS             Echo ARGS.\n"
456 "/definqfile NAME FILE\n"
457 "    Use content of FILE for inquiries with NAME.\n"
458 "    NAME may be \"*\" to match any inquiry.\n"
459 "/definqprog NAME PGM\n"
460 "    Run PGM for inquiries matching NAME and pass the\n"
461 "    entire line to it as arguments.\n"
462 "/showdef               Print all definitions.\n"
463 "/cleardef              Delete all definitions.\n"
464 "/sendfd FILE MODE      Open FILE and pass descriptor to server.\n"
465 "/recvfd                Receive FD from server and print. \n"
466 "/[no]hex               Enable hex dumping of received data lines.\n"
467 "/[no]decode            Enable decoding of received data lines.\n"
468 "/help                  Print this help.");
469             }
470           else
471             log_error (_("unknown command `%s'\n"), cmd );
472       
473           continue;
474         }
475       
476       rc = assuan_write_line (ctx, line);
477       if (rc)
478         {
479           log_info (_("sending line failed: %s\n"), gpg_strerror (rc) );
480           continue;
481         }
482       if (*line == '#' || !*line)
483         continue; /* Don't expect a response for a comment line. */
484
485       rc = read_and_print_response (ctx);
486       if (rc)
487         log_info (_("receiving line failed: %s\n"), gpg_strerror (rc) );
488     }
489
490   if (opt.verbose)
491     log_info ("closing connection to agent\n");
492   
493   return 0; 
494 }
495
496
497 /* Handle an Inquire from the server.  Return False if it could not be
498    handled; in this case the caller shll complete the operation.  LINE
499    is the complete line as received from the server.  This function
500    may change the content of LINE. */
501 static int
502 handle_inquire (assuan_context_t ctx, char *line)
503 {
504   const char *name;
505   definq_t d;
506   FILE *fp;
507   char buffer[1024];
508   int rc, n;
509
510   /* Skip the command and trailing spaces. */
511   for (; *line && !spacep (line); line++)
512     ;
513   while (spacep (line))
514     line++;
515   /* Get the name. */
516   name = line;
517   for (; *line && !spacep (line); line++)
518     ;
519   if (*line)
520     *line++ = 0;
521
522   /* Now match it against our list. he second loop is todetect the
523      match all entry. **/
524   for (d=definq_list; d; d = d->next)
525     if (d->name && !strcmp (d->name, name))
526         break;
527   if (!d)
528     for (d=definq_list; d; d = d->next)
529       if (!d->name)
530         break;
531   if (!d)
532     {
533       if (opt.verbose)
534         log_info ("no handler for inquiry `%s' found\n", name);
535       return 0;
536     }
537
538   if (d->is_prog)
539     {
540       fp = popen (d->file, "r");
541       if (!fp)
542         log_error ("error executing `%s': %s\n", d->file, strerror (errno));
543       else if (opt.verbose)
544         log_error ("handling inquiry `%s' by running `%s'\n", name, d->file);
545     }
546   else
547     {
548       fp = fopen (d->file, "rb");
549       if (!fp)
550         log_error ("error opening `%s': %s\n", d->file, strerror (errno));
551       else if (opt.verbose)
552         log_error ("handling inquiry `%s' by returning content of `%s'\n",
553                    name, d->file);
554     }
555   if (!fp)
556     return 0;
557
558   while ( (n = fread (buffer, 1, sizeof buffer, fp)) )
559     {
560       rc = assuan_send_data (ctx, buffer, n);
561       if (rc)
562         {
563           log_error ("sending data back failed: %s\n", gpg_strerror (rc) );
564           break;
565         }
566     }
567   if (ferror (fp))
568     log_error ("error reading from `%s': %s\n", d->file, strerror (errno));
569
570   rc = assuan_send_data (ctx, NULL, 0);
571   if (rc)
572     log_error ("sending data back failed: %s\n", gpg_strerror (rc) );
573
574   if (d->is_prog)
575     {
576       if (pclose (fp))
577         log_error ("error running `%s': %s\n", d->file, strerror (errno));
578     }
579   else
580     fclose (fp);
581   return 1;
582 }
583
584
585 /* Read all response lines from server and print them.  Returns 0 on
586    success or an assuan error code. */
587 static int
588 read_and_print_response (assuan_context_t ctx)
589 {
590   char *line;
591   size_t linelen;
592   assuan_error_t rc;
593   int i, j;
594   int need_lf = 0;
595
596   for (;;)
597     {
598       do 
599         {
600           rc = assuan_read_line (ctx, &line, &linelen);
601           if (rc)
602             return rc;
603
604           if (opt.verbose > 1 && *line == '#')
605             {
606               fwrite (line, linelen, 1, stdout);
607               putchar ('\n');
608             }
609         }    
610       while (*line == '#' || !linelen);
611
612       if (linelen >= 1
613           && line[0] == 'D' && line[1] == ' ')
614         {
615           if (opt.hex)
616             {
617               for (i=2; i < linelen; )
618                 {
619                   int save_i = i;
620
621                   printf ("D[%04X] ", i-2);
622                   for (j=0; j < 16 ; j++, i++)
623                     {
624                       if (j == 8)
625                         putchar (' ');
626                       if (i < linelen)
627                         printf (" %02X", ((unsigned char*)line)[i]);
628                       else
629                         fputs ("   ", stdout);
630                     }
631                   fputs ("   ", stdout);
632                   i= save_i;
633                   for (j=0; j < 16; j++, i++)
634                     {
635                       unsigned int c = ((unsigned char*)line)[i];
636                       if ( i >= linelen )
637                         putchar (' ');
638                       else if (isascii (c) && isprint (c) && !iscntrl (c))
639                         putchar (c);
640                       else
641                         putchar ('.');
642                     }
643                   putchar ('\n');
644                 }
645             }
646           else if (opt.decode)
647             {
648               const unsigned char *s;
649               int need_d = 1;
650               int c = 0;
651
652               for (j=2, s=(unsigned char*)line+2; j < linelen; j++, s++ )
653                 {
654                   if (need_d)
655                     {
656                       fputs ("D ", stdout);
657                       need_d = 0;
658                     }
659                   if (*s == '%' && j+2 < linelen)
660                     { 
661                       s++; j++;
662                       c = xtoi_2 ( s );
663                       s++; j++;
664                     }
665                   else
666                     c = *s;
667                   if (c == '\n')
668                     need_d = 1;
669                   putchar (c);
670                 }
671               need_lf = (c != '\n');
672             }
673           else
674             {
675               fwrite (line, linelen, 1, stdout);
676               putchar ('\n');
677             }
678         }
679       else 
680         {
681           if (need_lf)
682             {
683               putchar ('\n');
684               need_lf = 0;
685             }
686
687           if (linelen >= 1
688               && line[0] == 'S' 
689               && (line[1] == '\0' || line[1] == ' '))
690             {
691               fwrite (line, linelen, 1, stdout);
692               putchar ('\n');
693             }  
694           else if (linelen >= 2
695                    && line[0] == 'O' && line[1] == 'K'
696                    && (line[2] == '\0' || line[2] == ' '))
697             {
698               fwrite (line, linelen, 1, stdout);
699               putchar ('\n');
700               return 0;
701             }
702           else if (linelen >= 3
703                    && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
704                    && (line[3] == '\0' || line[3] == ' '))
705             {
706               fwrite (line, linelen, 1, stdout);
707               putchar ('\n');
708               return 0;
709             }  
710           else if (linelen >= 7
711                    && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
712                    && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
713                    && line[6] == 'E' 
714                    && (line[7] == '\0' || line[7] == ' '))
715             {
716               fwrite (line, linelen, 1, stdout);
717               putchar ('\n');
718               if (!handle_inquire (ctx, line))
719                 assuan_write_line (ctx, "CANCEL");
720             }
721           else if (linelen >= 3
722                    && line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
723                    && (line[3] == '\0' || line[3] == ' '))
724             {
725               fwrite (line, linelen, 1, stdout);
726               putchar ('\n');
727               /* Received from server, thus more responses are expected.  */
728             }
729           else
730             return gpg_error (GPG_ERR_ASS_INV_RESPONSE);
731         }
732     }
733 }
734
735
736
737
738 /* Connect to the agent and send the standard options.  */
739 static assuan_context_t
740 start_agent (void)
741 {
742   int rc = 0;
743   char *infostr, *p;
744   assuan_context_t ctx;
745
746   infostr = getenv ("GPG_AGENT_INFO");
747   if (!infostr || !*infostr)
748     {
749       char *sockname;
750
751       /* Check whether we can connect at the standard socket.  */
752       sockname = make_filename (opt.homedir, "S.gpg-agent", NULL);
753       rc = assuan_socket_connect (&ctx, sockname, 0);
754       xfree (sockname);
755     }
756   else
757     {
758       int prot;
759       int pid;
760
761       infostr = xstrdup (infostr);
762       if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
763         {
764           log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
765           xfree (infostr);
766           exit (1);
767         }
768       *p++ = 0;
769       pid = atoi (p);
770       while (*p && *p != PATHSEP_C)
771         p++;
772       prot = *p? atoi (p+1) : 0;
773       if (prot != 1)
774         {
775           log_error (_("gpg-agent protocol version %d is not supported\n"),
776                      prot);
777           xfree (infostr);
778           exit (1);
779         }
780
781       rc = assuan_socket_connect (&ctx, infostr, pid);
782       xfree (infostr);
783     }
784
785   if (rc)
786     {
787       log_error ("can't connect to the agent: %s\n", gpg_strerror (rc));
788       exit (1);
789     }
790
791   if (opt.verbose)
792     log_info ("connection to agent established\n");
793
794   rc = assuan_transact (ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
795   if (rc)
796     {
797       log_error (_("error sending %s command: %s\n"), "RESET", 
798                  gpg_strerror (rc));
799       exit (1);
800     }
801
802   rc = send_pinentry_environment (ctx, GPG_ERR_SOURCE_DEFAULT,
803                                   NULL, NULL, NULL, NULL, NULL);
804   if (rc)
805     {
806       log_error (_("error sending standard options: %s\n"), gpg_strerror (rc));
807       exit (1);
808     }
809
810   return ctx;
811 }