e0abaa9c9837a4578ec43f8b5dcbf5deb2df4476
[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 3 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, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <ctype.h>
27 #include <assuan.h>
28 #include <unistd.h>
29 #include <assert.h>
30
31 #include "i18n.h"
32 #include "../common/util.h"
33 #include "../common/asshelp.h"
34 #include "../common/sysutils.h"
35 #include "../common/membuf.h"
36 #include "../common/ttyio.h"
37
38 #define CONTROL_D ('D' - 'A' + 1)
39 #define octdigitp(p) (*(p) >= '0' && *(p) <= '7')
40
41 /* Constants to identify the commands and options. */
42 enum cmd_and_opt_values
43   {
44     aNull = 0,
45     oQuiet      = 'q',
46     oVerbose    = 'v',
47     oRawSocket  = 'S',
48     oExec       = 'E',
49     oRun        = 'r',
50     oSubst      = 's',
51
52     oNoVerbose  = 500,
53     oHomedir,
54     oHex,
55     oDecode,
56     oNoExtConnect
57
58   };
59
60
61 /* The list of commands and options. */
62 static ARGPARSE_OPTS opts[] =
63   {
64     { 301, NULL, 0, N_("@\nOptions:\n ") },
65     
66     { oVerbose, "verbose",  0, N_("verbose") },
67     { oQuiet, "quiet",      0, N_("quiet") },
68     { oHex,   "hex",        0, N_("print data out hex encoded") },
69     { oDecode,"decode",     0, N_("decode received data lines") },
70     { oRawSocket, "raw-socket", 2, N_("|NAME|connect to Assuan socket NAME")},
71     { oExec, "exec", 0, N_("run the Assuan server given on the command line")},
72     { oNoExtConnect, "no-ext-connect",
73                             0, N_("do not use extended connect mode")},
74     { oRun,  "run", 2,         N_("|FILE|run commands from FILE on startup")},
75     { oSubst, "subst", 0,      N_("run /subst on startup")}, 
76     /* hidden options */
77     { oNoVerbose, "no-verbose",  0, "@"},
78     { oHomedir, "homedir", 2, "@" },   
79     {0}
80   };
81
82
83 /* We keep all global options in the structure OPT.  */
84 struct
85 {
86   int verbose;          /* Verbosity level.  */
87   int quiet;            /* Be extra quiet.  */
88   const char *homedir;  /* Configuration directory name */
89   int hex;              /* Print data lines in hex format. */
90   int decode;           /* Decode received data lines.  */
91   const char *raw_socket; /* Name of socket to connect in raw mode. */
92   int exec;             /* Run the pgm given on the command line. */
93   unsigned int connect_flags;    /* Flags used for connecting. */
94   int enable_varsubst;  /* Set if variable substitution is enabled.  */
95   int trim_leading_spaces;
96 } opt;
97
98
99
100 /* Definitions for /definq commands and a global linked list with all
101    the definitions. */
102 struct definq_s
103 {
104   struct definq_s *next;
105   char *name;     /* Name of inquiry or NULL for any name. */
106   int is_var;     /* True if FILE is a variable name. */
107   int is_prog;    /* True if FILE is a program to run. */
108   char file[1];   /* Name of file or program. */
109 };
110 typedef struct definq_s *definq_t;
111
112 static definq_t definq_list;
113 static definq_t *definq_list_tail = &definq_list;
114
115
116 /* Variable definitions and glovbal table.  */
117 struct variable_s
118 {
119   struct variable_s *next;
120   char *value;  /* Malloced value - always a string.  */
121   char name[1]; /* Name of the variable.  */
122 };
123 typedef struct variable_s *variable_t;
124
125 static variable_t variable_table;
126
127
128 /* To implement loops we store entire lines in a linked list.  */
129 struct loopline_s
130 {
131   struct loopline_s *next;
132   char line[1];
133 };
134 typedef struct loopline_s *loopline_t;
135
136
137 /* This is used to store the pid of the server.  */
138 static pid_t server_pid = (pid_t)(-1);
139
140
141 /* A list of open file descriptors. */
142 static struct
143 {
144   int inuse;
145 #ifdef HAVE_W32_SYSTEM
146   HANDLE handle;
147 #endif
148 } open_fd_table[256];
149
150
151 /*-- local prototypes --*/
152 static char *substitute_line_copy (const char *buffer);
153 static int read_and_print_response (assuan_context_t ctx, int *r_goterr);
154 static assuan_context_t start_agent (void);
155
156
157
158 \f
159 /* Print usage information and and provide strings for help. */
160 static const char *
161 my_strusage( int level )
162 {
163   const char *p;
164
165   switch (level)
166     {
167     case 11: p = "gpg-connect-agent (GnuPG)";
168       break;
169     case 13: p = VERSION; break;
170     case 17: p = PRINTABLE_OS_NAME; break;
171     case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
172       break;
173     case 1:
174     case 40: p = _("Usage: gpg-connect-agent [options] (-h for help)");
175       break;
176     case 41:
177       p = _("Syntax: gpg-connect-agent [options]\n"
178             "Connect to a running agent and send commands\n");
179       break;
180     case 31: p = "\nHome: "; break;
181     case 32: p = opt.homedir; break;
182     case 33: p = "\n"; break;
183
184     default: p = NULL; break;
185     }
186   return p;
187 }
188
189
190 static char *
191 gnu_getcwd (void)
192 {
193   char *buffer;
194   size_t size = 100;
195
196   for (;;)
197     {
198       buffer = xmalloc (size+1);
199       if (getcwd (buffer, size) == buffer)
200         return buffer;
201       xfree (buffer);
202       if (errno != ERANGE)
203         return NULL;
204       size *= 2;
205     }
206 }
207
208
209 /* Unescale STRING and returned the malloced result.  The surrounding
210    quotes must already be removed from STRING.  */
211 static char *
212 unescape_string (const char *string)
213 {
214   const unsigned char *s;
215   int esc;
216   size_t n;
217   char *buffer;
218   unsigned char *d;
219
220   n = 0;
221   for (s = (const unsigned char*)string, esc=0; *s; s++)
222     {
223       if (esc)
224         {
225           switch (*s)
226             {
227             case 'b':  
228             case 't':  
229             case 'v':  
230             case 'n':  
231             case 'f':  
232             case 'r':  
233             case '"':  
234             case '\'': 
235             case '\\': n++; break;
236             case 'x': 
237               if (s[1] && s[2] && hexdigitp (s+1) && hexdigitp (s+2))
238                 n++;
239               break;
240
241             default:
242               if (s[1] && s[2] 
243                   && octdigitp (s) && octdigitp (s+1) && octdigitp (s+2))
244                 n++;
245               break;
246             }
247           esc = 0;
248         }
249       else if (*s == '\\')
250         esc = 1;
251       else
252         n++;
253     } 
254
255   buffer = xmalloc (n+1);
256   d = (unsigned char*)buffer;
257   for (s = (const unsigned char*)string, esc=0; *s; s++)
258     {
259       if (esc)
260         {
261           switch (*s)
262             {
263             case 'b':  *d++ = '\b'; break;
264             case 't':  *d++ = '\t'; break;
265             case 'v':  *d++ = '\v'; break;
266             case 'n':  *d++ = '\n'; break;
267             case 'f':  *d++ = '\f'; break;
268             case 'r':  *d++ = '\r'; break;
269             case '"':  *d++ = '\"'; break;
270             case '\'': *d++ = '\''; break;
271             case '\\': *d++ = '\\'; break;
272             case 'x': 
273               if (s[1] && s[2] && hexdigitp (s+1) && hexdigitp (s+2))
274                 {
275                   s++;
276                   *d++ = xtoi_2 (s);
277                   s++;
278                 }
279               break;
280
281             default:
282               if (s[1] && s[2] 
283                   && octdigitp (s) && octdigitp (s+1) && octdigitp (s+2))
284                 {
285                   *d++ = (atoi_1 (s)*64) + (atoi_1 (s+1)*8) + atoi_1 (s+2);
286                   s += 2;
287                 }
288               break;
289             }
290           esc = 0;
291         }
292       else if (*s == '\\')
293         esc = 1;
294       else
295         *d++ = *s;
296     } 
297   *d = 0;
298   return buffer;
299 }
300
301
302 /* Do the percent unescaping and return a newly malloced string.
303    If WITH_PLUS is set '+' characters will be changed to space. */
304 static char *
305 unpercent_string (const char *string, int with_plus)
306 {
307   const unsigned char *s;
308   unsigned char *buffer, *p;
309   size_t n;
310
311   n = 0;
312   for (s=(const unsigned char *)string; *s; s++)
313     {
314       if (*s == '%' && s[1] && s[2])
315         { 
316           s++;
317           n++;
318           s++;
319         }
320       else if (with_plus && *s == '+')
321         n++;
322       else
323         n++;
324     }
325
326   buffer = xmalloc (n+1);
327   p = buffer;
328   for (s=(const unsigned char *)string; *s; s++)
329     {
330       if (*s == '%' && s[1] && s[2])
331         { 
332           s++;
333           *p++ = xtoi_2 (s);
334           s++;
335         }
336       else if (with_plus && *s == '+')
337         *p++ = ' ';
338       else
339         *p++ = *s;
340     }
341   *p = 0;
342   return (char*)buffer;
343 }
344
345
346
347
348 \f
349 static const char *
350 set_var (const char *name, const char *value)
351 {
352   variable_t var;
353
354   for (var = variable_table; var; var = var->next)
355     if (!strcmp (var->name, name))
356       break;
357   if (!var)
358     {
359       var = xmalloc (sizeof *var + strlen (name));
360       var->value = NULL;
361       strcpy (var->name, name);
362       var->next = variable_table;
363       variable_table = var;
364     }
365   xfree (var->value);
366   var->value = value? xstrdup (value) : NULL;
367   return var->value;
368 }    
369
370
371 static void
372 set_int_var (const char *name, int value)
373 {
374   char numbuf[35];
375
376   snprintf (numbuf, sizeof numbuf, "%d", value);
377   set_var (name, numbuf);
378 }
379
380
381 /* Return the value of a variable.  That value is valid until a
382    variable of the name is changed.  Return NULL if not found.  Note
383    that envvars are copied to our variable list at the first access
384    and not at oprogram start.  */
385 static const char *
386 get_var (const char *name)
387 {
388   variable_t var;
389   const char *s;
390
391   if (!*name)
392     return "";
393   for (var = variable_table; var; var = var->next)
394     if (!strcmp (var->name, name))
395       break;
396   if (!var && (s = getenv (name)))
397     return set_var (name, s);
398   if (!var || !var->value)
399     return NULL;
400   return var->value;
401 }
402
403
404 /* Perform some simple arithmentic operations.  Caller must release
405    the return value.  On error the return value is NULL.  */
406 static char *
407 arithmetic_op (int operator, const char *operands)
408 {
409   long result, value;
410   char numbuf[35];
411
412   while ( spacep (operands) )
413     operands++;
414   if (!*operands)
415     return NULL;
416   result = strtol (operands, NULL, 0);
417   while (*operands && !spacep (operands) )
418     operands++;
419   while (*operands)
420     {
421       while ( spacep (operands) )
422         operands++;
423       if (!*operands)
424         break;
425       value = strtol (operands, NULL, 0);
426       while (*operands && !spacep (operands) )
427         operands++;
428       switch (operator)
429         {
430         case '+': result += value; break;
431         case '-': result -= value; break;
432         case '*': result *= value; break;
433         case '/': 
434           if (!value)
435             return NULL;
436           result /= value;
437           break;
438         case '%': 
439           if (!value)
440             return NULL;
441           result %= value;
442           break;
443         default:
444           log_error ("unknown arithmetic operator `%c'\n", operator);
445           return NULL;
446         }
447     }
448   snprintf (numbuf, sizeof numbuf, "%ld", result);
449   return xstrdup (numbuf);
450 }
451
452
453
454 /* Extended version of get_var.  This returns a malloced string and
455    understand the fucntion syntax: "func args". 
456
457    Defined functions are
458    
459      get - Return a value described by the next argument:
460            cwd        - The current working directory.
461            homedir    - The gnupg homedir.
462            sysconfdir - GnuPG's system configuration directory.
463            bindir     - GnuPG's binary directory.
464            libdir     - GnuPG's library directory.
465            libexecdir - GnuPG's library directory for executable files.
466            datadir    - GnuPG's data directory.
467            serverpid  - The PID of the current server.
468
469      unescape ARGS
470            Remove C-style escapes from string.  Note that "\0" and
471            "\x00" terminate the string implictly.  Use "\x7d" to
472            represent the closing brace.  The args start right after
473            the first space after the function name.
474
475      unpercent ARGS
476      unpercent+ ARGS
477            Remove percent style ecaping from string.  Note that "%00
478            terminates the string implicitly.  Use "%7d" to represetn
479            the closing brace.  The args start right after the first
480            space after the function name.  "unpercent+" also maps '+'
481            to space.
482
483      percent ARGS
484      percent+ ARGS
485            Escape the args using the percent style.  Tabs, formfeeds,
486            linefeeds and carriage returns are also escaped.
487            "percent+" also maps spaces to plus characters.
488
489    Example: get_var_ext ("get sysconfdir") -> "/etc/gnupg"
490     
491   */
492 static char *
493 get_var_ext (const char *name)
494 {
495   static int recursion_count;
496   const char *s;
497   char *result;
498   char *p;
499   char *free_me = NULL;
500
501   if (recursion_count > 50)
502     {
503       log_error ("variables nested too deeply\n");
504       return NULL;
505     }
506
507   recursion_count++;
508   free_me = opt.enable_varsubst? substitute_line_copy (name) : NULL;
509   if (free_me)
510     name = free_me;
511   for (s=name; *s && !spacep (s); s++)
512     ;
513   if (!*s)
514     {
515       s = get_var (name);
516       result = s? xstrdup (s): NULL;
517     }
518   else if ( (s - name) == 3 && !strncmp (name, "get", 3))
519     {
520       while ( spacep (s) )
521         s++;
522       if (!strcmp (s, "cwd"))
523         {
524           result = gnu_getcwd ();
525           if (!result)
526             log_error ("getcwd failed: %s\n", strerror (errno));
527         }
528       else if (!strcmp (s, "homedir"))
529         result = make_filename (opt.homedir, NULL);
530       else if (!strcmp (s, "sysconfdir"))
531         result = xstrdup (gnupg_sysconfdir ());
532       else if (!strcmp (s, "bindir"))
533         result = xstrdup (gnupg_bindir ());
534       else if (!strcmp (s, "libdir"))
535         result = xstrdup (gnupg_libdir ());
536       else if (!strcmp (s, "libexecdir"))
537         result = xstrdup (gnupg_libexecdir ());
538       else if (!strcmp (s, "datadir"))
539         result = xstrdup (gnupg_datadir ());
540       else if (!strcmp (s, "serverpid"))
541         {
542           char numbuf[30];
543           snprintf (numbuf, sizeof numbuf, "%d", (int)server_pid);
544           result = xstrdup (numbuf);
545         }
546       else
547         {
548           log_error ("invalid argument `%s' for variable function `get'\n", s);
549           log_info  ("valid are: cwd, "
550                      "{home,bin,lib,libexec,data}dir, serverpid\n");
551           result = NULL;
552         }
553     }
554   else if ( (s - name) == 8 && !strncmp (name, "unescape", 8))
555     {
556       s++;
557       result = unescape_string (s);
558     }
559   else if ( (s - name) == 9 && !strncmp (name, "unpercent", 9))
560     {
561       s++;
562       result = unpercent_string (s, 0);
563     }
564   else if ( (s - name) == 10 && !strncmp (name, "unpercent+", 10))
565     {
566       s++;
567       result = unpercent_string (s, 1);
568     }
569   else if ( (s - name) == 7 && !strncmp (name, "percent", 7))
570     {
571       s++;
572       result = percent_escape (s, "\t\r\n\f\v");
573     }
574   else if ( (s - name) == 8 && !strncmp (name, "percent+", 8))
575     {
576       s++;
577       result = percent_escape (s, "\t\r\n\f\v");
578       for (p=result; *p; p++)
579         if (*p == ' ')
580           *p = '+';
581     }
582   else if ( (s - name) == 1 && strchr ("+-*/%", *name))
583     {
584       result = arithmetic_op (*name, s+1);
585     }
586   else
587     {
588       log_error ("unknown variable function `%.*s'\n", (int)(s-name), name);
589       result = NULL;
590     }
591     
592   xfree (free_me);
593   recursion_count--;
594   return result;
595 }
596
597
598 /* Substitute variables in LINE and return a new allocated buffer if
599    required.  The function might modify LINE if the expanded version
600    fits into it.  */
601 static char *
602 substitute_line (char *buffer)
603 {
604   char *line = buffer;
605   char *p, *pend;
606   const char *value;
607   size_t valuelen, n;
608   char *result = NULL;
609   char *freeme = NULL;
610
611   while (*line)
612     {
613       p = strchr (line, '$');
614       if (!p)
615         return result; /* No more variables.  */
616       
617       if (p[1] == '$') /* Escaped dollar sign. */
618         {
619           memmove (p, p+1, strlen (p+1)+1);
620           line = p + 1;
621           continue;
622         }
623       if (p[1] == '{')
624         {
625           int count = 0;
626
627           for (pend=p+2; *pend; pend++)
628             {
629               if (*pend == '{')
630                 count++;
631               else if (*pend == '}')
632                 {
633                   if (--count < 0)
634                     break;
635                 }
636             }
637           if (!*pend)
638             return result; /* Unclosed - don't substitute.  */
639         }
640       else
641         {
642           for (pend=p+1; *pend && !spacep (pend) && *pend != '$' ; pend++)
643             ;
644         }
645       if (p[1] == '{' && *pend == '}')
646         {
647           int save = *pend;
648           *pend = 0;
649           freeme = get_var_ext (p+2);
650           value = freeme;
651           *pend++ = save;
652         }
653       else if (*pend)
654         {
655           int save = *pend;
656           *pend = 0;
657           value = get_var (p+1);
658           *pend = save;
659         }
660       else
661         value = get_var (p+1);
662       if (!value)
663         value = "";
664       valuelen = strlen (value);
665       if (valuelen <= pend - p)
666         {
667           memcpy (p, value, valuelen);
668           p += valuelen;
669           n = pend - p;
670           if (n)
671             memmove (p, p+n, strlen (p+n)+1);
672           line = p;
673         }
674       else
675         {
676           char *src = result? result : buffer;
677           char *dst;
678
679           dst = xmalloc (strlen (src) + valuelen + 1);
680           n = p - src;
681           memcpy (dst, src, n);
682           memcpy (dst + n, value, valuelen);
683           n += valuelen;
684           strcpy (dst + n, pend);
685           line = dst + n;
686           xfree (result);
687           result = dst;
688         }
689       xfree (freeme);
690       freeme = NULL;
691     }
692   return result;
693 }
694
695 /* Same as substitute_line but do not modify BUFFER.  */
696 static char *
697 substitute_line_copy (const char *buffer)
698 {
699   char *result, *p;
700   
701   p = xstrdup (buffer?buffer:"");
702   result = substitute_line (p);
703   if (!result)
704     result = p;
705   else
706     xfree (p);
707   return result;
708 }
709
710
711 static void
712 assign_variable (char *line, int syslet)
713 {
714   char *name, *p, *tmp, *free_me, *buffer;
715
716   /* Get the  name. */
717   name = line;
718   for (p=name; *p && !spacep (p); p++)
719     ;
720   if (*p)
721     *p++ = 0;
722   while (spacep (p))
723     p++;
724
725   if (!*p)
726     set_var (name, NULL); /* Remove variable.  */ 
727   else if (syslet)
728     {
729       free_me = opt.enable_varsubst? substitute_line_copy (p) : NULL;
730       if (free_me)
731         p = free_me;
732       buffer = xmalloc (4 + strlen (p) + 1);
733       strcpy (stpcpy (buffer, "get "), p);
734       tmp = get_var_ext (buffer);
735       xfree (buffer);
736       set_var (name, tmp);
737       xfree (tmp);
738       xfree (free_me);
739     }
740   else 
741     {
742       tmp = opt.enable_varsubst? substitute_line_copy (p) : NULL;
743       if (tmp)
744         {
745           set_var (name, tmp);
746           xfree (tmp);
747         }
748       else
749         set_var (name, p);
750     }
751 }
752
753
754 static void
755 show_variables (void)
756 {
757   variable_t var;
758
759   for (var = variable_table; var; var = var->next)
760     if (var->value)
761       printf ("%-20s %s\n", var->name, var->value);
762 }
763
764
765 /* Store an inquire response pattern.  Note, that this function may
766    change the content of LINE.  We assume that leading white spaces
767    are already removed. */
768 static void
769 add_definq (char *line, int is_var, int is_prog)
770 {
771   definq_t d;
772   char *name, *p;
773
774   /* Get name. */
775   name = line;
776   for (p=name; *p && !spacep (p); p++)
777     ;
778   if (*p)
779     *p++ = 0;
780   while (spacep (p))
781     p++;
782
783   d = xmalloc (sizeof *d + strlen (p) );
784   strcpy (d->file, p);
785   d->is_var  = is_var;
786   d->is_prog = is_prog;
787   if ( !strcmp (name, "*"))
788     d->name = NULL;
789   else
790     d->name = xstrdup (name);
791
792   d->next = NULL;
793   *definq_list_tail = d;
794   definq_list_tail = &d->next;
795 }
796
797
798 /* Show all inquiry defintions. */
799 static void
800 show_definq (void)
801 {
802   definq_t d;
803
804   for (d=definq_list; d; d = d->next)
805     if (d->name)
806       printf ("%-20s %c %s\n", 
807               d->name, d->is_var? 'v' : d->is_prog? 'p':'f', d->file);
808   for (d=definq_list; d; d = d->next)
809     if (!d->name)
810       printf ("%-20s %c %s\n", "*", 
811               d->is_var? 'v': d->is_prog? 'p':'f', d->file);
812 }
813
814
815 /* Clear all inquiry definitions. */
816 static void
817 clear_definq (void)
818 {
819   while (definq_list)
820     { 
821       definq_t tmp = definq_list->next;
822       xfree (definq_list->name);
823       xfree (definq_list);
824       definq_list = tmp;
825     }
826   definq_list_tail = &definq_list;
827 }      
828
829
830 static void
831 do_sendfd (assuan_context_t ctx, char *line)
832 {
833   FILE *fp;
834   char *name, *mode, *p;
835   int rc, fd;
836
837   /* Get file name. */
838   name = line;
839   for (p=name; *p && !spacep (p); p++)
840     ;
841   if (*p)
842     *p++ = 0;
843   while (spacep (p))
844     p++;
845
846   /* Get mode.  */
847   mode = p;
848   if (!*mode)
849     mode = "r";
850   else
851     {
852       for (p=mode; *p && !spacep (p); p++)
853         ;
854       if (*p)
855         *p++ = 0;
856     }
857
858   /* Open and send. */
859   fp = fopen (name, mode);
860   if (!fp)
861     {
862       log_error ("can't open `%s' in \"%s\" mode: %s\n",
863                  name, mode, strerror (errno));
864       return;
865     }
866   fd = fileno (fp);
867
868   if (opt.verbose)
869     log_error ("file `%s' opened in \"%s\" mode, fd=%d\n",
870                name, mode, fd);
871
872   rc = assuan_sendfd (ctx, INT2FD (fd) );
873   if (rc)
874     log_error ("sending descriptor %d failed: %s\n", fd, gpg_strerror (rc));
875   fclose (fp);
876 }
877
878
879 static void
880 do_recvfd (assuan_context_t ctx, char *line)
881 {
882   log_info ("This command has not yet been implemented\n");
883 }
884
885
886 static void
887 do_open (char *line)
888 {
889   FILE *fp;
890   char *varname, *name, *mode, *p;
891   int fd;
892
893 #ifdef HAVE_W32_SYSTEM
894   if (server_pid == (pid_t)(-1))
895     {
896       log_error ("the pid of the server is unknown\n");
897       log_info ("use command \"/serverpid\" first\n");
898       return;
899     }
900 #endif
901
902   /* Get variable name. */
903   varname = line;
904   for (p=varname; *p && !spacep (p); p++)
905     ;
906   if (*p)
907     *p++ = 0;
908   while (spacep (p))
909     p++;
910
911   /* Get file name. */
912   name = p;
913   for (p=name; *p && !spacep (p); p++)
914     ;
915   if (*p)
916     *p++ = 0;
917   while (spacep (p))
918     p++;
919
920   /* Get mode.  */
921   mode = p;
922   if (!*mode)
923     mode = "r";
924   else
925     {
926       for (p=mode; *p && !spacep (p); p++)
927         ;
928       if (*p)
929         *p++ = 0;
930     }
931
932   /* Open and send. */
933   fp = fopen (name, mode);
934   if (!fp)
935     {
936       log_error ("can't open `%s' in \"%s\" mode: %s\n",
937                  name, mode, strerror (errno));
938       return;
939     }
940   fd = fileno (fp);
941   if (fd >= 0 && fd < DIM (open_fd_table))
942     {
943       open_fd_table[fd].inuse = 1;
944 #ifdef HAVE_W32_SYSTEM
945       {
946         HANDLE prochandle, handle, newhandle;
947
948         handle = (void*)_get_osfhandle (fd);
949      
950         prochandle = OpenProcess (PROCESS_DUP_HANDLE, FALSE, server_pid);
951         if (!prochandle)
952           {
953             log_error ("failed to open the server process\n");
954             close (fd);
955             return;
956           }
957
958         if (!DuplicateHandle (GetCurrentProcess(), handle,
959                               prochandle, &newhandle, 0,
960                               TRUE, DUPLICATE_SAME_ACCESS ))
961           {
962             log_error ("failed to duplicate the handle\n");
963             close (fd);
964             CloseHandle (prochandle);
965             return;
966           }
967         CloseHandle (prochandle);
968         open_fd_table[fd].handle = newhandle;
969       }
970       if (opt.verbose)
971         log_info ("file `%s' opened in \"%s\" mode, fd=%d  (libc=%d)\n",
972                    name, mode, (int)open_fd_table[fd].handle, fd);
973       set_int_var (varname, (int)open_fd_table[fd].handle);
974 #else  
975       if (opt.verbose)
976         log_info ("file `%s' opened in \"%s\" mode, fd=%d\n",
977                    name, mode, fd);
978       set_int_var (varname, fd);
979 #endif
980     }
981   else
982     {
983       log_error ("can't put fd %d into table\n", fd);
984       close (fd);
985     }
986 }
987
988
989 static void
990 do_close (char *line)
991 {
992   int fd = atoi (line);
993
994 #ifdef HAVE_W32_SYSTEM
995   int i;
996
997   for (i=0; i < DIM (open_fd_table); i++)
998     if ( open_fd_table[i].inuse && open_fd_table[i].handle == (void*)fd)
999       break;
1000   if (i < DIM (open_fd_table))
1001     fd = i;
1002   else
1003     {
1004       log_error ("given fd (system handle) has not been opened\n");
1005       return;
1006     }
1007 #endif
1008
1009   if (fd < 0 || fd >= DIM (open_fd_table))
1010     {
1011       log_error ("invalid fd\n");
1012       return;
1013     }
1014
1015   if (!open_fd_table[fd].inuse)
1016     {
1017       log_error ("given fd has not been opened\n");
1018       return;
1019     }
1020 #ifdef HAVE_W32_SYSTEM
1021   CloseHandle (open_fd_table[fd].handle); /* Close duped handle.  */
1022 #endif
1023   close (fd);
1024   open_fd_table[fd].inuse = 0;
1025 }
1026
1027
1028 static void
1029 do_showopen (void)
1030 {
1031   int i;
1032
1033   for (i=0; i < DIM (open_fd_table); i++)
1034     if (open_fd_table[i].inuse)
1035       {
1036 #ifdef HAVE_W32_SYSTEM
1037         printf ("%-15d (libc=%d)\n", (int)open_fd_table[i].handle, i);
1038 #else
1039         printf ("%-15d\n", i);
1040 #endif
1041       }
1042 }
1043
1044
1045
1046 static int
1047 getinfo_pid_cb (void *opaque, const void *buffer, size_t length)
1048 {
1049   membuf_t *mb = opaque;
1050   put_membuf (mb, buffer, length);
1051   return 0;
1052 }
1053
1054 /* Get the pid of the server and store it locally.  */
1055 static void
1056 do_serverpid (assuan_context_t ctx)
1057 {
1058   int rc;
1059   membuf_t mb;
1060   char *buffer;
1061   
1062   init_membuf (&mb, 100);
1063   rc = assuan_transact (ctx, "GETINFO pid", getinfo_pid_cb, &mb,
1064                         NULL, NULL, NULL, NULL);
1065   put_membuf (&mb, "", 1);
1066   buffer = get_membuf (&mb, NULL);
1067   if (rc || !buffer)
1068     log_error ("command \"%s\" failed: %s\n", 
1069                "GETINFO pid", gpg_strerror (rc));
1070   else
1071     {
1072       server_pid = (pid_t)strtoul (buffer, NULL, 10);
1073       if (opt.verbose)
1074         log_info ("server's PID is %lu\n", (unsigned long)server_pid);
1075     }
1076   xfree (buffer);
1077 }
1078
1079
1080 /* gpg-connect-agent's entry point. */
1081 int
1082 main (int argc, char **argv)
1083 {
1084   ARGPARSE_ARGS pargs;
1085   int no_more_options = 0;
1086   assuan_context_t ctx;
1087   char *line, *p;
1088   char *tmpline;
1089   size_t linesize;
1090   int rc;
1091   int cmderr;
1092   const char *opt_run = NULL;
1093   FILE *script_fp = NULL;
1094   int use_tty, keep_line;
1095   struct {
1096     int collecting;
1097     loopline_t head;
1098     loopline_t *tail;
1099     loopline_t current;
1100     unsigned int nestlevel; 
1101     char *condition;
1102   } loopstack[20];
1103   int        loopidx;
1104
1105   gnupg_rl_initialize ();
1106   set_strusage (my_strusage);
1107   log_set_prefix ("gpg-connect-agent", 1);
1108
1109   /* Make sure that our subsystems are ready.  */
1110   init_common_subsystems ();
1111
1112   assuan_set_assuan_err_source (0);
1113
1114   i18n_init();
1115
1116   opt.homedir = default_homedir ();
1117   opt.connect_flags = 1; /* Use extended connect mode.  */
1118
1119   /* Parse the command line. */
1120   pargs.argc  = &argc;
1121   pargs.argv  = &argv;
1122   pargs.flags =  1;  /* Do not remove the args.  */
1123   while (!no_more_options && optfile_parse (NULL, NULL, NULL, &pargs, opts))
1124     {
1125       switch (pargs.r_opt)
1126         {
1127         case oQuiet:     opt.quiet = 1; break;
1128         case oVerbose:   opt.verbose++; break;
1129         case oNoVerbose: opt.verbose = 0; break;
1130         case oHomedir:   opt.homedir = pargs.r.ret_str; break;
1131         case oHex:       opt.hex = 1; break;
1132         case oDecode:    opt.decode = 1; break;
1133         case oRawSocket: opt.raw_socket = pargs.r.ret_str; break;
1134         case oExec:      opt.exec = 1; break;
1135         case oNoExtConnect: opt.connect_flags &= ~(1); break;
1136         case oRun:       opt_run = pargs.r.ret_str; break;
1137         case oSubst: 
1138           opt.enable_varsubst = 1;
1139           opt.trim_leading_spaces = 1;
1140           break;
1141
1142         default: pargs.err = 2; break;
1143         }
1144     }
1145
1146   if (log_get_errorcount (0))
1147     exit (2);
1148
1149   use_tty = (isatty ( fileno (stdin)) && isatty (fileno (stdout)));
1150
1151   if (opt.exec)
1152     {
1153       if (!argc)
1154         {
1155           log_error (_("option \"%s\" requires a program "
1156                        "and optional arguments\n"), "--exec" );
1157           exit (1);
1158         }
1159     }
1160   else if (argc)
1161     usage (1);
1162
1163   if (opt.exec && opt.raw_socket)
1164     log_info (_("option \"%s\" ignored due to \"%s\"\n"),
1165               "--raw-socket", "--exec");
1166
1167   if (opt_run && !(script_fp = fopen (opt_run, "r")))
1168     {
1169       log_error ("cannot open run file `%s': %s\n",
1170                  opt_run, strerror (errno));
1171       exit (1);
1172     }
1173
1174
1175   if (opt.exec)
1176     {
1177       int no_close[3];
1178
1179       no_close[0] = fileno (stderr);
1180       no_close[1] = log_get_fd ();
1181       no_close[2] = -1;
1182       rc = assuan_pipe_connect_ext (&ctx, *argv, (const char **)argv,
1183                                     no_close, NULL, NULL,
1184                                     opt.connect_flags);
1185       if (rc)
1186         {
1187           log_error ("assuan_pipe_connect_ext failed: %s\n",
1188                      gpg_strerror (rc));
1189           exit (1);
1190         }
1191
1192       if (opt.verbose)
1193         log_info ("server `%s' started\n", *argv);
1194
1195     }
1196   else if (opt.raw_socket)
1197     {
1198       rc = assuan_socket_connect_ext (&ctx, opt.raw_socket, 0,
1199                                       opt.connect_flags);
1200       if (rc)
1201         {
1202           log_error ("can't connect to socket `%s': %s\n",
1203                      opt.raw_socket, gpg_strerror (rc));
1204           exit (1);
1205         }
1206
1207       if (opt.verbose)
1208         log_info ("connection to socket `%s' established\n", opt.raw_socket);
1209     }
1210   else
1211     ctx = start_agent ();
1212
1213   /* See whether there is a line pending from the server (in case
1214      assuan did not run the initial handshaking).  */
1215   if (assuan_pending_line (ctx))
1216     {
1217       rc = read_and_print_response (ctx, &cmderr);
1218       if (rc)
1219         log_info (_("receiving line failed: %s\n"), gpg_strerror (rc) );
1220     }
1221
1222  
1223   for (loopidx=0; loopidx < DIM (loopstack); loopidx++)
1224     loopstack[loopidx].collecting = 0;
1225   loopidx = -1;
1226   line = NULL;
1227   linesize = 0;
1228   keep_line = 1;
1229   for (;;)
1230     {
1231       int n;
1232       size_t maxlength = 2048;
1233
1234       assert (loopidx < (int)DIM (loopstack));
1235       if (loopidx >= 0 && loopstack[loopidx].current)
1236         {
1237           keep_line = 0;
1238           xfree (line);
1239           line = xstrdup (loopstack[loopidx].current->line);
1240           n = strlen (line);
1241           /* Never go beyond of the final /end.  */
1242           if (loopstack[loopidx].current->next)
1243             loopstack[loopidx].current = loopstack[loopidx].current->next;
1244           else if (!strncmp (line, "/end", 4) && (!line[4]||spacep(line+4)))
1245             ;
1246           else
1247             log_fatal ("/end command vanished\n");
1248         }
1249       else if (use_tty && !script_fp)
1250         {
1251           keep_line = 0;
1252           xfree (line);
1253           line = tty_get ("> ");
1254           n = strlen (line);
1255           if (n==1 && *line == CONTROL_D)
1256             n = 0;
1257           if (n >= maxlength)
1258             maxlength = 0;
1259         }
1260       else
1261         {
1262           if (!keep_line)
1263             {
1264               xfree (line);
1265               line = NULL;
1266               linesize = 0;
1267               keep_line = 1;
1268             }
1269           n = read_line (script_fp? script_fp:stdin, 
1270                          &line, &linesize, &maxlength);
1271         }
1272       if (n < 0)
1273         {
1274           log_error (_("error reading input: %s\n"), strerror (errno));
1275           if (script_fp)
1276             {
1277               fclose (script_fp);
1278               script_fp = NULL;
1279               log_error ("stopping script execution\n");
1280               continue;
1281             }
1282           exit (1);
1283         }
1284       if (!n)
1285         {
1286           /* EOF */
1287           if (script_fp)
1288             {
1289               fclose (script_fp);
1290               script_fp = NULL;
1291               if (opt.verbose)
1292                 log_info ("end of script\n");
1293               continue;
1294             }
1295           break; 
1296         }
1297       if (!maxlength)
1298         {
1299           log_error (_("line too long - skipped\n"));
1300           continue;
1301         }
1302       if (memchr (line, 0, n))
1303         log_info (_("line shortened due to embedded Nul character\n"));
1304       if (line[n-1] == '\n')
1305         line[n-1] = 0;
1306       
1307       if (opt.trim_leading_spaces)
1308         {
1309           const char *s = line;
1310           
1311           while (spacep (s))
1312             s++;
1313           if (s != line)
1314             {
1315               for (p=line; *s;)
1316                 *p++ = *s++;
1317               *p = 0;
1318               n = p - line;
1319             }
1320         }
1321
1322       if (loopidx+1 >= 0 && loopstack[loopidx+1].collecting)
1323         {
1324           loopline_t ll;
1325
1326           ll = xmalloc (sizeof *ll + strlen (line));
1327           ll->next = NULL;
1328           strcpy (ll->line, line);
1329           *loopstack[loopidx+1].tail = ll;
1330           loopstack[loopidx+1].tail = &ll->next;
1331
1332           if (!strncmp (line, "/end", 4) && (!line[4]||spacep(line+4)))
1333             loopstack[loopidx+1].nestlevel--;
1334           else if (!strncmp (line, "/while", 6) && (!line[6]||spacep(line+6)))
1335             loopstack[loopidx+1].nestlevel++;
1336           
1337           if (loopstack[loopidx+1].nestlevel)
1338             continue;
1339           /* We reached the corresponding /end.  */
1340           loopstack[loopidx+1].collecting = 0;
1341           loopidx++;
1342         }
1343
1344       if (*line == '/')
1345         {
1346           /* Handle control commands. */
1347           char *cmd = line+1;
1348
1349           for (p=cmd; *p && !spacep (p); p++)
1350             ;
1351           if (*p)
1352             *p++ = 0;
1353           while (spacep (p))
1354             p++;
1355           if (!strcmp (cmd, "let"))
1356             {
1357               assign_variable (p, 0);
1358             }
1359           else if (!strcmp (cmd, "slet"))
1360             {
1361               /* Deprecated - never used in a released version.  */
1362               assign_variable (p, 1);
1363             }
1364           else if (!strcmp (cmd, "showvar"))
1365             {
1366               show_variables ();
1367             }
1368           else if (!strcmp (cmd, "definq"))
1369             {
1370               tmpline = opt.enable_varsubst? substitute_line (p) : NULL;
1371               if (tmpline)
1372                 {
1373                   add_definq (tmpline, 1, 0);
1374                   xfree (tmpline);
1375                 }
1376               else
1377                 add_definq (p, 1, 0);
1378             }
1379           else if (!strcmp (cmd, "definqfile"))
1380             {
1381               tmpline = opt.enable_varsubst? substitute_line (p) : NULL;
1382               if (tmpline)
1383                 {
1384                   add_definq (tmpline, 0, 0);
1385                   xfree (tmpline);
1386                 }
1387               else
1388                 add_definq (p, 0, 0);
1389             }
1390           else if (!strcmp (cmd, "definqprog"))
1391             {
1392               tmpline = opt.enable_varsubst? substitute_line (p) : NULL;
1393               if (tmpline)
1394                 {
1395                   add_definq (tmpline, 0, 1);
1396                   xfree (tmpline);
1397                 }
1398               else
1399                 add_definq (p, 0, 1);
1400             }
1401           else if (!strcmp (cmd, "showdef"))
1402             {
1403               show_definq ();
1404             }
1405           else if (!strcmp (cmd, "cleardef"))
1406             {
1407               clear_definq ();
1408             }
1409           else if (!strcmp (cmd, "echo"))
1410             {
1411               tmpline = opt.enable_varsubst? substitute_line (p) : NULL;
1412               if (tmpline)
1413                 {
1414                   puts (tmpline);
1415                   xfree (tmpline);
1416                 }
1417               else
1418                 puts (p);
1419             }
1420           else if (!strcmp (cmd, "sendfd"))
1421             {
1422               tmpline = opt.enable_varsubst? substitute_line (p) : NULL;
1423               if (tmpline)
1424                 {
1425                   do_sendfd (ctx, tmpline);
1426                   xfree (tmpline);
1427                 }
1428               else
1429                 do_sendfd (ctx, p);
1430               continue;
1431             }
1432           else if (!strcmp (cmd, "recvfd"))
1433             {
1434               tmpline = opt.enable_varsubst? substitute_line (p) : NULL;
1435               if (tmpline)
1436                 {
1437                   do_recvfd (ctx, tmpline);
1438                   xfree (tmpline);
1439                 }
1440               else
1441                 do_recvfd (ctx, p);
1442               continue;
1443             }
1444           else if (!strcmp (cmd, "open"))
1445             {
1446               tmpline = opt.enable_varsubst? substitute_line (p) : NULL;
1447               if (tmpline)
1448                 {
1449                   do_open (tmpline);
1450                   xfree (tmpline);
1451                 }
1452               else
1453                 do_open (p);
1454             }
1455           else if (!strcmp (cmd, "close"))
1456             {
1457               tmpline = opt.enable_varsubst? substitute_line (p) : NULL;
1458               if (tmpline)
1459                 {
1460                   do_close (tmpline);
1461                   xfree (tmpline);
1462                 }
1463               else
1464                 do_close (p);
1465             }
1466           else if (!strcmp (cmd, "showopen"))
1467             {
1468               do_showopen ();
1469             }
1470           else if (!strcmp (cmd, "serverpid"))
1471             {
1472               do_serverpid (ctx);
1473             }
1474           else if (!strcmp (cmd, "hex"))
1475             opt.hex = 1;
1476           else if (!strcmp (cmd, "nohex"))
1477             opt.hex = 0;
1478           else if (!strcmp (cmd, "decode"))
1479             opt.decode = 1;
1480           else if (!strcmp (cmd, "nodecode"))
1481             opt.decode = 0;
1482           else if (!strcmp (cmd, "subst"))
1483             {
1484               opt.enable_varsubst = 1;
1485               opt.trim_leading_spaces = 1;
1486             }
1487           else if (!strcmp (cmd, "nosubst"))
1488             opt.enable_varsubst = 0;
1489           else if (!strcmp (cmd, "run"))
1490             {
1491               char *p2;
1492
1493               for (p2=p; *p2 && !spacep (p2); p2++)
1494                 ;
1495               if (*p2)
1496                 *p2++ = 0;
1497               while (spacep (p2))
1498                 p++;
1499               if (*p2)
1500                 {
1501                   log_error ("syntax error in run command\n");
1502                   if (script_fp)
1503                     {
1504                       fclose (script_fp);
1505                       script_fp = NULL;
1506                     }
1507                 }
1508               else if (script_fp)
1509                 {
1510                   log_error ("cannot nest run commands - stop\n");
1511                   fclose (script_fp);
1512                   script_fp = NULL;
1513                 }
1514               else if (!(script_fp = fopen (p, "r")))
1515                 {
1516                   log_error ("cannot open run file `%s': %s\n",
1517                              p, strerror (errno));
1518                 }
1519               else if (opt.verbose)
1520                 log_info ("running commands from `%s'\n", p);
1521             }
1522           else if (!strcmp (cmd, "while"))
1523             {
1524               if (loopidx+2 >= (int)DIM(loopstack))
1525                 {
1526                   log_error ("loops are nested too deep\n");
1527                   /* We should better die or break all loop in this
1528                      case as recovering from this error won't be
1529                      easy.  */
1530                 }
1531               else
1532                 {
1533                   loopstack[loopidx+1].head = NULL;
1534                   loopstack[loopidx+1].tail = &loopstack[loopidx+1].head;
1535                   loopstack[loopidx+1].current = NULL;
1536                   loopstack[loopidx+1].nestlevel = 1;
1537                   loopstack[loopidx+1].condition = xstrdup (p);
1538                   loopstack[loopidx+1].collecting = 1;
1539                 }
1540             }
1541           else if (!strcmp (cmd, "end"))
1542             {
1543               if (loopidx < 0)
1544                 log_error ("stray /end command encountered - ignored\n");
1545               else
1546                 {
1547                   char *tmpcond;
1548                   const char *value;
1549                   long condition;
1550
1551                   /* Evaluate the condition.  */
1552                   tmpcond = xstrdup (loopstack[loopidx].condition);
1553                   tmpline = substitute_line (tmpcond);
1554                   value = tmpline? tmpline : tmpcond;
1555                   condition = strtol (value, NULL, 0);
1556                   xfree (tmpline);
1557                   xfree (tmpcond);
1558
1559                   if (condition)
1560                     {
1561                       /* Run loop.  */
1562                       loopstack[loopidx].current = loopstack[loopidx].head;
1563                     }
1564                   else
1565                     {
1566                       /* Cleanup.  */
1567                       while (loopstack[loopidx].head)
1568                         {
1569                           loopline_t tmp = loopstack[loopidx].head->next;
1570                           xfree (loopstack[loopidx].head);
1571                           loopstack[loopidx].head = tmp;
1572                         }
1573                       loopstack[loopidx].tail = NULL;
1574                       loopstack[loopidx].current = NULL;
1575                       loopstack[loopidx].nestlevel = 0;
1576                       loopstack[loopidx].collecting = 0;
1577                       xfree (loopstack[loopidx].condition);
1578                       loopstack[loopidx].condition = NULL;
1579                       loopidx--;
1580                     }
1581                 }
1582             }
1583           else if (!strcmp (cmd, "bye"))
1584             {
1585               break;
1586             }
1587           else if (!strcmp (cmd, "sleep"))
1588             {
1589               gnupg_sleep (1);
1590             }
1591           else if (!strcmp (cmd, "help"))
1592             {
1593               puts (
1594 "Available commands:\n"
1595 "/echo ARGS             Echo ARGS.\n"
1596 "/let  NAME VALUE       Set variable NAME to VALUE.\n"
1597 "/showvar               Show all variables.\n"
1598 "/definq NAME VAR       Use content of VAR for inquiries with NAME.\n"
1599 "/definqfile NAME FILE  Use content of FILE for inquiries with NAME.\n"
1600 "/definqprog NAME PGM   Run PGM for inquiries with NAME.\n"
1601 "/showdef               Print all definitions.\n"
1602 "/cleardef              Delete all definitions.\n"
1603 "/sendfd FILE MODE      Open FILE and pass descriptor to server.\n"
1604 "/recvfd                Receive FD from server and print.\n"
1605 "/open VAR FILE MODE    Open FILE and assign the file descriptor to VAR.\n" 
1606 "/close FD              Close file with descriptor FD.\n"
1607 "/showopen              Show descriptors of all open files.\n"
1608 "/serverpid             Retrieve the pid of the server.\n"
1609 "/[no]hex               Enable hex dumping of received data lines.\n"
1610 "/[no]decode            Enable decoding of received data lines.\n"
1611 "/[no]subst             Enable varibale substitution.\n"
1612 "/run FILE              Run commands from FILE.\n"
1613 "/while VAR             Begin loop controlled by VAR.\n"
1614 "/end                   End loop.\n"
1615 "/bye                   Terminate gpg-connect-agent.\n"
1616 "/help                  Print this help.");
1617             }
1618           else
1619             log_error (_("unknown command `%s'\n"), cmd );
1620       
1621           continue;
1622         }
1623
1624       if (opt.verbose && script_fp)
1625         puts (line);
1626
1627       tmpline = opt.enable_varsubst? substitute_line (line) : NULL;
1628       if (tmpline)
1629         {
1630           rc = assuan_write_line (ctx, tmpline);
1631           xfree (tmpline);
1632         }
1633       else
1634         rc = assuan_write_line (ctx, line);
1635       if (rc)
1636         {
1637           log_info (_("sending line failed: %s\n"), gpg_strerror (rc) );
1638           break;
1639         }
1640       if (*line == '#' || !*line)
1641         continue; /* Don't expect a response for a comment line. */
1642
1643       rc = read_and_print_response (ctx, &cmderr);
1644       if (rc)
1645         log_info (_("receiving line failed: %s\n"), gpg_strerror (rc) );
1646       if ((rc || cmderr) && script_fp)
1647         {
1648           log_error ("stopping script execution\n");
1649           fclose (script_fp);
1650           script_fp = NULL;
1651         }
1652           
1653
1654       /* FIXME: If the last command was BYE or the server died for
1655          some other reason, we won't notice until we get the next
1656          input command.  Probing the connection with a non-blocking
1657          read could help to notice termination or other problems
1658          early.  */
1659     }
1660
1661   if (opt.verbose)
1662     log_info ("closing connection to agent\n");
1663   
1664   return 0; 
1665 }
1666
1667
1668 /* Handle an Inquire from the server.  Return False if it could not be
1669    handled; in this case the caller shll complete the operation.  LINE
1670    is the complete line as received from the server.  This function
1671    may change the content of LINE. */
1672 static int
1673 handle_inquire (assuan_context_t ctx, char *line)
1674 {
1675   const char *name;
1676   definq_t d;
1677   FILE *fp = NULL;
1678   char buffer[1024];
1679   int rc, n;
1680
1681   /* Skip the command and trailing spaces. */
1682   for (; *line && !spacep (line); line++)
1683     ;
1684   while (spacep (line))
1685     line++;
1686   /* Get the name. */
1687   name = line;
1688   for (; *line && !spacep (line); line++)
1689     ;
1690   if (*line)
1691     *line++ = 0;
1692
1693   /* Now match it against our list. he second loop is todetect the
1694      match all entry. **/
1695   for (d=definq_list; d; d = d->next)
1696     if (d->name && !strcmp (d->name, name))
1697         break;
1698   if (!d)
1699     for (d=definq_list; d; d = d->next)
1700       if (!d->name)
1701         break;
1702   if (!d)
1703     {
1704       if (opt.verbose)
1705         log_info ("no handler for inquiry `%s' found\n", name);
1706       return 0;
1707     }
1708
1709   if (d->is_var)
1710     {
1711       char *tmpvalue = get_var_ext (d->file);
1712       rc = assuan_send_data (ctx, tmpvalue, strlen (tmpvalue));
1713       xfree (tmpvalue);
1714       if (rc)
1715         log_error ("sending data back failed: %s\n", gpg_strerror (rc) );
1716     }
1717   else
1718     {
1719       if (d->is_prog)
1720         {
1721           fp = popen (d->file, "r");
1722           if (!fp)
1723             log_error ("error executing `%s': %s\n",
1724                        d->file, strerror (errno));
1725           else if (opt.verbose)
1726             log_error ("handling inquiry `%s' by running `%s'\n", 
1727                        name, d->file);
1728         }
1729       else
1730         {
1731           fp = fopen (d->file, "rb");
1732           if (!fp)
1733             log_error ("error opening `%s': %s\n", d->file, strerror (errno));
1734           else if (opt.verbose)
1735             log_error ("handling inquiry `%s' by returning content of `%s'\n",
1736                        name, d->file);
1737         }
1738       if (!fp)
1739         return 0;
1740
1741       while ( (n = fread (buffer, 1, sizeof buffer, fp)) )
1742         {
1743           rc = assuan_send_data (ctx, buffer, n);
1744           if (rc)
1745             {
1746               log_error ("sending data back failed: %s\n", gpg_strerror (rc) );
1747               break;
1748             }
1749         }
1750       if (ferror (fp))
1751         log_error ("error reading from `%s': %s\n", d->file, strerror (errno));
1752     }
1753
1754   rc = assuan_send_data (ctx, NULL, 0);
1755   if (rc)
1756     log_error ("sending data back failed: %s\n", gpg_strerror (rc) );
1757
1758   if (d->is_var)
1759     ;
1760   else if (d->is_prog)
1761     {
1762       if (pclose (fp))
1763         log_error ("error running `%s': %s\n", d->file, strerror (errno));
1764     }
1765   else
1766     fclose (fp);
1767   return 1;
1768 }
1769
1770
1771 /* Read all response lines from server and print them.  Returns 0 on
1772    success or an assuan error code.  Set R_GOTERR to true if the
1773    command did not returned OK.  */
1774 static int
1775 read_and_print_response (assuan_context_t ctx, int *r_goterr)
1776 {
1777   char *line;
1778   size_t linelen;
1779   assuan_error_t rc;
1780   int i, j;
1781   int need_lf = 0;
1782
1783   *r_goterr = 0;
1784   for (;;)
1785     {
1786       do 
1787         {
1788           rc = assuan_read_line (ctx, &line, &linelen);
1789           if (rc)
1790             return rc;
1791
1792           if (opt.verbose > 1 && *line == '#')
1793             {
1794               fwrite (line, linelen, 1, stdout);
1795               putchar ('\n');
1796             }
1797         }    
1798       while (*line == '#' || !linelen);
1799
1800       if (linelen >= 1
1801           && line[0] == 'D' && line[1] == ' ')
1802         {
1803           if (opt.hex)
1804             {
1805               for (i=2; i < linelen; )
1806                 {
1807                   int save_i = i;
1808
1809                   printf ("D[%04X] ", i-2);
1810                   for (j=0; j < 16 ; j++, i++)
1811                     {
1812                       if (j == 8)
1813                         putchar (' ');
1814                       if (i < linelen)
1815                         printf (" %02X", ((unsigned char*)line)[i]);
1816                       else
1817                         fputs ("   ", stdout);
1818                     }
1819                   fputs ("   ", stdout);
1820                   i= save_i;
1821                   for (j=0; j < 16; j++, i++)
1822                     {
1823                       unsigned int c = ((unsigned char*)line)[i];
1824                       if ( i >= linelen )
1825                         putchar (' ');
1826                       else if (isascii (c) && isprint (c) && !iscntrl (c))
1827                         putchar (c);
1828                       else
1829                         putchar ('.');
1830                     }
1831                   putchar ('\n');
1832                 }
1833             }
1834           else if (opt.decode)
1835             {
1836               const unsigned char *s;
1837               int need_d = 1;
1838               int c = 0;
1839
1840               for (j=2, s=(unsigned char*)line+2; j < linelen; j++, s++ )
1841                 {
1842                   if (need_d)
1843                     {
1844                       fputs ("D ", stdout);
1845                       need_d = 0;
1846                     }
1847                   if (*s == '%' && j+2 < linelen)
1848                     { 
1849                       s++; j++;
1850                       c = xtoi_2 ( s );
1851                       s++; j++;
1852                     }
1853                   else
1854                     c = *s;
1855                   if (c == '\n')
1856                     need_d = 1;
1857                   putchar (c);
1858                 }
1859               need_lf = (c != '\n');
1860             }
1861           else
1862             {
1863               fwrite (line, linelen, 1, stdout);
1864               putchar ('\n');
1865             }
1866         }
1867       else 
1868         {
1869           if (need_lf)
1870             {
1871               putchar ('\n');
1872               need_lf = 0;
1873             }
1874
1875           if (linelen >= 1
1876               && line[0] == 'S' 
1877               && (line[1] == '\0' || line[1] == ' '))
1878             {
1879               fwrite (line, linelen, 1, stdout);
1880               putchar ('\n');
1881             }  
1882           else if (linelen >= 2
1883                    && line[0] == 'O' && line[1] == 'K'
1884                    && (line[2] == '\0' || line[2] == ' '))
1885             {
1886               fwrite (line, linelen, 1, stdout);
1887               putchar ('\n');
1888               return 0;
1889             }
1890           else if (linelen >= 3
1891                    && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
1892                    && (line[3] == '\0' || line[3] == ' '))
1893             {
1894               fwrite (line, linelen, 1, stdout);
1895               putchar ('\n');
1896               *r_goterr = 1;
1897               return 0;
1898             }  
1899           else if (linelen >= 7
1900                    && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
1901                    && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
1902                    && line[6] == 'E' 
1903                    && (line[7] == '\0' || line[7] == ' '))
1904             {
1905               fwrite (line, linelen, 1, stdout);
1906               putchar ('\n');
1907               if (!handle_inquire (ctx, line))
1908                 assuan_write_line (ctx, "CANCEL");
1909             }
1910           else if (linelen >= 3
1911                    && line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
1912                    && (line[3] == '\0' || line[3] == ' '))
1913             {
1914               fwrite (line, linelen, 1, stdout);
1915               putchar ('\n');
1916               /* Received from server, thus more responses are expected.  */
1917             }
1918           else
1919             return gpg_error (GPG_ERR_ASS_INV_RESPONSE);
1920         }
1921     }
1922 }
1923
1924
1925
1926
1927 /* Connect to the agent and send the standard options.  */
1928 static assuan_context_t
1929 start_agent (void)
1930 {
1931   int rc = 0;
1932   char *infostr, *p;
1933   assuan_context_t ctx;
1934
1935   infostr = getenv ("GPG_AGENT_INFO");
1936   if (!infostr || !*infostr)
1937     {
1938       char *sockname;
1939
1940       /* Check whether we can connect at the standard socket.  */
1941       sockname = make_filename (opt.homedir, "S.gpg-agent", NULL);
1942       rc = assuan_socket_connect (&ctx, sockname, 0);
1943       xfree (sockname);
1944     }
1945   else
1946     {
1947       int prot;
1948       int pid;
1949
1950       infostr = xstrdup (infostr);
1951       if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
1952         {
1953           log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
1954           xfree (infostr);
1955           exit (1);
1956         }
1957       *p++ = 0;
1958       pid = atoi (p);
1959       while (*p && *p != PATHSEP_C)
1960         p++;
1961       prot = *p? atoi (p+1) : 0;
1962       if (prot != 1)
1963         {
1964           log_error (_("gpg-agent protocol version %d is not supported\n"),
1965                      prot);
1966           xfree (infostr);
1967           exit (1);
1968         }
1969
1970       rc = assuan_socket_connect (&ctx, infostr, pid);
1971       xfree (infostr);
1972     }
1973
1974   if (rc)
1975     {
1976       log_error ("can't connect to the agent: %s\n", gpg_strerror (rc));
1977       exit (1);
1978     }
1979
1980   if (opt.verbose)
1981     log_info ("connection to agent established\n");
1982
1983   rc = assuan_transact (ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
1984   if (rc)
1985     {
1986       log_error (_("error sending %s command: %s\n"), "RESET", 
1987                  gpg_strerror (rc));
1988       exit (1);
1989     }
1990
1991   rc = send_pinentry_environment (ctx, GPG_ERR_SOURCE_DEFAULT,
1992                                   NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1993   if (rc)
1994     {
1995       log_error (_("error sending standard options: %s\n"), gpg_strerror (rc));
1996       exit (1);
1997     }
1998
1999   return ctx;
2000 }