Added new directory common to enable sharing of some code and error
[gnupg.git] / agent / gpg-agent.c
1 /* gpg-agent.c  -  The GnuPG Agent
2  *      Copyright (C) 2000, 2001 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 /*
22  * How to use the client mode:
23  *  printf '\0\0\0\002AAAAAAAAAAAAAAAAAAAAAPlease enter the passphrase for\n 
24  *          key 0x12345678\nJoe Hacker <joe@hackworld.foo>\n' 
25  *     | ./gpg-agent --client | od
26  * Or use a builtin command to shut the agent down.
27  *   ./gpg-agent --shutdown | od
28  *
29  */
30
31 #include <config.h>
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <stddef.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <assert.h>
39 #include <time.h>
40 #include <fcntl.h>
41 #include <unistd.h>
42 #include <signal.h>
43
44 #include <gcrypt.h>
45
46 #include "util.h"
47 #include "../assuan/assuan.h" /* malloc hooks */
48 #include "i18n.h"
49
50
51 enum cmd_and_opt_values 
52 { aNull = 0,
53   oCsh            = 'c',
54   oQuiet          = 'q',
55   oSh             = 's',
56   oVerbose        = 'v',
57   
58   oNoVerbose = 500,
59   oOptions,
60   oDebug,
61   oDebugAll,
62   oNoGreeting,
63   oNoOptions,
64   oHomedir,
65   oNoDetach,
66   oNoGrab,
67   oClient,
68   oShutdown,
69   oFlush,
70   oLogFile,
71   oServer,
72 aTest };
73
74
75 static ARGPARSE_OPTS opts[] = {
76   
77   { 301, NULL, 0, N_("@Options:\n ") },
78
79   /* FIXME: add option --server */
80   { oServer,   "server",     0, N_("run in server mode") },
81   { oVerbose, "verbose",   0, N_("verbose") },
82   { oQuiet,     "quiet",     0, N_("be somewhat more quiet") },
83   { oSh,        "sh",        0, N_("sh-style command output") },
84   { oCsh,       "csh",       0, N_("csh-style command output") },
85   { oOptions, "options"  , 2, N_("read options from file")},
86   { oDebug,     "debug"     ,4|16, N_("set debugging flags")},
87   { oDebugAll, "debug-all" ,0, N_("enable full debugging")},
88   { oNoDetach, "no-detach" ,0, N_("do not detach from the console")},
89   { oNoGrab, "no-grab"     ,0, N_("do not grab keyboard and mouse")},
90   { oClient, "client"      ,0, N_("run in client mode for testing")},
91   { oLogFile, "log-file"   ,2, N_("use a log file for the server")},
92   { oShutdown, "shutdown"  ,0, N_("shutdown the agent")},
93   { oFlush   , "flush"     ,0, N_("flush the cache")},
94   {0}
95 };
96
97
98 static struct {
99   const char *homedir;
100   int client;
101   int verbose;
102   int quiet;
103   unsigned int debug;
104   int nodetach;
105   int grab;
106   const char *logfile;
107   int csh_style;
108 } opt;
109
110 typedef struct {
111     int used;
112     char fpr[20];
113     char *pw;
114     size_t pwlen;
115     size_t totlen;
116 } CACHE_SLOT;
117
118 #define MAX_CACHE_ENTRIES 10
119 #define MAX_CACHE_AGE  1000 /* should fit into an integer */
120 static volatile int caught_fatal_sig = 0;
121 static volatile int shut_me_down = 0;
122 static CACHE_SLOT the_cache[MAX_CACHE_ENTRIES];
123 static char *socket_name = NULL;
124
125 #define buftou32( p )  ((*(byte*)(p) << 24) | (*((byte*)(p)+1)<< 16) | \
126                        (*((byte*)(p)+2) << 8) | (*((byte*)(p)+3)))
127 #define u32tobuf( p, a ) do {                                   \
128                             ((byte*)p)[0] = (byte)((a) >> 24);  \
129                             ((byte*)p)[1] = (byte)((a) >> 16);  \
130                             ((byte*)p)[2] = (byte)((a) >>  8);  \
131                             ((byte*)p)[3] = (byte)((a)      );  \
132                         } while(0)
133
134
135 static int start_listening ( const char *name );
136 static int writen ( int fd, const void *buf, size_t nbytes );
137 static int readn ( int fd, void *buf, size_t buflen, size_t *ret_nread );
138
139 static void process_request ( int fd );
140
141
142 static const char *
143 my_strusage( int level )
144 {
145     const char *p;
146     switch( level ) {
147       case 11: p = "gpg-agent (GnuPG)";
148         break;
149       case 13: p = VERSION; break;
150       case 17: p = PRINTABLE_OS_NAME; break;
151       case 19: p =
152             _("Please report bugs to <bug-gnupg@gnu.org>.\n");
153         break;
154       case 1:
155       case 40:  p =
156             _("Usage: gpg-agent [options] (-h for help)");
157         break;
158       case 41:  p =
159             _("Syntax: gpg-agent [options] [command [args]]\n"
160               "Secret key management for GnuPG\n");
161         break;
162
163       default:  p = NULL;
164     }
165     return p;
166 }
167
168
169
170 static void
171 i18n_init (void)
172 {
173   #ifdef USE_SIMPLE_GETTEXT
174     set_gettext_file( PACKAGE );
175   #else
176   #ifdef ENABLE_NLS
177     /* gtk_set_locale (); HMMM: We have not yet called gtk_init */
178     bindtextdomain( PACKAGE, GNUPG_LOCALEDIR );
179     textdomain( PACKAGE );
180   #endif
181   #endif
182 }
183
184 static void
185 cleanup (void)
186 {
187   if (socket_name)
188     {
189       char *p = socket_name;
190       socket_name = NULL;
191       remove ( p );
192       gcry_free (p);
193     }
194 }
195
196 static RETSIGTYPE
197 cleanup_sh (int sig)
198 {
199   if (caught_fatal_sig)
200     raise (sig);
201   caught_fatal_sig = 1;
202   shut_me_down = 1;
203
204   /* gcry_control( GCRYCTL_TERM_SECMEM );*/
205   cleanup ();
206
207 #ifndef HAVE_DOSISH_SYSTEM
208   {     /* reset action to default action and raise signal again */
209     struct sigaction nact;
210     nact.sa_handler = SIG_DFL;
211     sigemptyset( &nact.sa_mask );
212     nact.sa_flags = 0;
213     sigaction( sig, &nact, NULL);
214   }
215 #endif
216   raise( sig );
217 }
218
219 int
220 main (int argc, char **argv )
221 {
222   ARGPARSE_ARGS pargs;
223   int orig_argc;
224   char **orig_argv;
225   FILE *configfp = NULL;
226   char *configname = NULL;
227   const char *shell;
228   unsigned configlineno;
229   int parse_debug = 0;
230   int default_config =1;
231   int greeting = 0;
232   int nogreeting = 0;
233   int server_mode = 0;
234   int do_shutdown = 0;
235   int do_flush = 0;
236
237   set_strusage( my_strusage );
238   /*   log_set_name ("gpg-agent"); */
239   srand (time (NULL)); /* the about dialog uses rand() */
240   i18n_init ();
241
242   /* check that the libraries are suitable.  Do it here because
243      the option parsing may need services of the library */
244   if (!gcry_check_version ( "1.1.4" ) )
245     {
246       log_fatal( _("libgcrypt is too old (need %s, have %s)\n"),
247                  VERSION, gcry_check_version (NULL) );
248     }
249
250   assuan_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);
251
252
253   shell = getenv("SHELL");
254   if (shell && strlen(shell) >= 3 && !strcmp(shell+strlen(shell)-3, "csh") )
255     opt.csh_style = 1;
256   
257   opt.homedir = getenv("GNUPGHOME");
258   if (!opt.homedir || !*opt.homedir)
259     {
260 #ifdef HAVE_DRIVE_LETTERS
261       opt.homedir = "c:/gnupg-test";
262 #else
263       opt.homedir = "~/.gnupg-test";
264 #endif
265     }
266   opt.grab = 1;
267
268   /* check whether we have a config file on the commandline */
269   orig_argc = argc;
270   orig_argv = argv;
271   pargs.argc = &argc;
272   pargs.argv = &argv;
273   pargs.flags= 1|(1<<6);  /* do not remove the args, ignore version */
274   while (arg_parse( &pargs, opts))
275     {
276       if (pargs.r_opt == oDebug || pargs.r_opt == oDebugAll)
277         parse_debug++;
278       else if (pargs.r_opt == oOptions)
279         { /* yes there is one, so we do not try the default one, but
280              read the option file when it is encountered at the
281              commandline */
282           default_config = 0;
283         }
284         else if (pargs.r_opt == oNoOptions)
285           default_config = 0; /* --no-options */
286         else if (pargs.r_opt == oHomedir)
287           opt.homedir = pargs.r.ret_str;
288     }
289
290   if (default_config)
291     configname = make_filename (opt.homedir, "gpg-agent.conf", NULL );
292   
293   argc = orig_argc;
294   argv = orig_argv;
295   pargs.argc = &argc;
296   pargs.argv = &argv;
297   pargs.flags=  1;  /* do not remove the args */
298  next_pass:
299   if (configname)
300     {
301       configlineno = 0;
302       configfp = fopen (configname, "r");
303       if (!configfp)
304         {
305           if (default_config)
306             {
307               if( parse_debug )
308                 log_info (_("NOTE: no default option file `%s'\n"),
309                           configname );
310             }
311           else
312             {
313               log_error (_("option file `%s': %s\n"),
314                          configname, strerror(errno) );
315               exit(2);
316             }
317           xfree (configname); 
318           configname = NULL;
319         }
320       if (parse_debug && configname )
321         log_info (_("reading options from `%s'\n"), configname );
322       default_config = 0;
323     }
324
325   while (optfile_parse( configfp, configname, &configlineno, &pargs, opts) )
326     {
327       switch (pargs.r_opt)
328         {
329         case oQuiet: opt.quiet = 1; break;
330         case oVerbose: opt.verbose++; break;
331
332         case oDebug: opt.debug |= pargs.r.ret_ulong; break;
333         case oDebugAll: opt.debug = ~0; break;
334
335         case oOptions:
336           /* config files may not be nested (silently ignore them) */
337           if (!configfp)
338             {
339                 xfree(configname);
340                 configname = xstrdup(pargs.r.ret_str);
341                 goto next_pass;
342             }
343           break;
344         case oNoGreeting: nogreeting = 1; break;
345         case oNoVerbose: opt.verbose = 0; break;
346         case oNoOptions: break; /* no-options */
347         case oHomedir: opt.homedir = pargs.r.ret_str; break;
348         case oNoDetach: opt.nodetach = 1; break;
349         case oNoGrab: opt.grab = 0; break;
350         case oClient: opt.client = 1; break;
351         case oShutdown: opt.client = 1; do_shutdown = 1; break;
352         case oFlush: opt.client = 1; do_flush = 1; break;
353         case oLogFile: opt.logfile = pargs.r.ret_str; break;
354         case oCsh: opt.csh_style = 1; break;
355         case oSh: opt.csh_style = 0; break;
356         case oServer: server_mode = 1; break;
357
358         default : pargs.err = configfp? 1:2; break;
359         }
360     }
361   if (configfp)
362     {
363       fclose( configfp );
364       configfp = NULL;
365       xfree(configname);
366       configname = NULL;
367       goto next_pass;
368     }
369   xfree (configname);
370   configname = NULL;
371   if (log_get_errorcount(0))
372     exit(2);
373   if (nogreeting )
374     greeting = 0;
375
376   if (greeting)
377     {
378       fprintf (stderr, "%s %s; %s\n",
379                  strusage(11), strusage(13), strusage(14) );
380       fprintf (stderr, "%s\n", strusage(15) );
381     }
382 #ifdef IS_DEVELOPMENT_VERSION
383   log_info ("NOTE: this is a development version!\n");
384 #endif
385
386   socket_name =  make_filename (opt.homedir, "S.gpg-agent", NULL );
387   if (strchr ( socket_name, ':') )
388     {
389       log_error ("colons are not allowed in the socket name\n");
390       exit (1);
391     }
392    
393   if (opt.client)
394     { /* a client for testing this agent */
395 #if 0 /* FIXME: We are going to use assuan here */
396       int fd;
397       struct sockaddr_un client_addr;
398       size_t len;
399       char buffer[1000];
400       int nread;
401
402       if ( strlen (socket_name)+1 >= sizeof client_addr.sun_path ) {
403         log_error ("name of socket to long\n");
404         exit (1);
405       }
406
407       if( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1 )
408         log_fatal("can't create socket: %s\n", strerror(errno) );
409
410       memset( &client_addr, 0, sizeof client_addr );
411       client_addr.sun_family = AF_UNIX;
412       strcpy( client_addr.sun_path, socket_name );
413       len = offsetof (struct sockaddr_un, sun_path)
414         + strlen(client_addr.sun_path) + 1;
415
416       if( connect( fd, (struct sockaddr*)&client_addr, len ) == -1 ) {
417         log_error ( "connect() failed: %s\n", strerror (errno) );
418         exit (1);
419       }
420
421       if ( do_shutdown ) {
422         u32tobuf (buffer+4, GPGA_PROT_SHUTDOWN );
423         nread = 4;
424       }
425       else if ( do_flush ) {
426         u32tobuf (buffer+4, GPGA_PROT_FLUSH );
427         nread = 4;
428       }
429       else {
430         nread =  fread ( buffer+4, 1, DIM(buffer)-4, stdin );
431             
432         if ( opt.verbose )
433           log_info ( "%d bytes read from stdin\n", nread );
434       }
435       u32tobuf (buffer, nread );
436       writen ( fd, "GPGA\0\0\0\x01", 8 );
437       writen ( fd, buffer, nread + 4 );
438       /* now read the response */
439       readn ( fd, buffer, DIM(buffer), &nread );
440       if ( opt.verbose )
441         log_info ( "%d bytes got from agent\n", nread );
442
443       fwrite ( buffer, 1, nread, stdout );
444       close (fd );
445 #endif
446     }
447   else
448     { /* regular server mode */
449       int listen_fd;
450       pid_t child;
451       int i;
452         
453       listen_fd = start_listening (socket_name);
454       if (listen_fd == -1)
455         {
456           cleanup ();
457           exit (1);
458         }
459
460
461       fflush (NULL);
462       child = fork ();
463       if (child == -1) 
464         {
465           log_fatal ("fork failed: %s\n", strerror (errno) );
466           cleanup ();
467           exit (1);
468         }
469       else if ( child ) 
470         { /* parent */
471           char *infostr;
472           
473           close (listen_fd );
474           
475           /* create the info string */
476           infostr = xmalloc ( 20 + strlen(socket_name) + 30 + 2 );
477           sprintf ( infostr, "GPG_AGENT_INFO=%s:%lu",
478                     socket_name, (ulong)child );
479           if ( argc ) 
480             { /* run the program given on the commandline */
481               if (putenv (infostr))
482                 {
483                   log_error ("failed to set environment: %s\n",
484                              strerror (errno) );
485                   kill (child, SIGTERM );
486                   cleanup ();
487                   exit (1);
488                 }
489               execvp (argv[0], argv);
490               log_error ("failed to run the command: %s\n",
491                          strerror (errno));    
492               kill (child, SIGTERM);
493               cleanup ();
494               exit (1);
495             }
496           /* print the environment string, so that the caller can use
497              eval to set it */
498           if (opt.csh_style)
499             {
500               *strchr (infostr, '=') = ' ';
501               printf ( "setenv %s\n", infostr);
502             }
503           else
504             {
505               printf ( "%s; export GPG_AGENT_INFO;\n", infostr);
506             }
507           exit (0); 
508         } /* end parent */
509
510       if ( (opt.debug & 1) )
511         sleep( 20 ); /* give us some time to attach gdb to the child */
512
513       if (opt.logfile)
514         {
515           /* FIXME:log_set_logfile (opt.logfile, -1);*/
516         }
517        
518       if ( atexit( cleanup ) )
519         {
520           log_error ("atexit failed\n");
521           cleanup ();
522           exit (1);
523         }
524
525       if ( !opt.nodetach )
526         {
527           for (i=0 ; i <= 2; i++ ) 
528             {
529               if ( log_get_fd () != i)
530                 close ( i );
531             }
532             
533           if (setsid() == -1)
534             {
535               log_error ("setsid() failed: %s\n", strerror(errno) );
536               cleanup ();
537               exit (1);
538             }
539         }
540
541       {
542         struct sigaction oact, nact;
543         
544         nact.sa_handler = cleanup_sh;
545         sigemptyset ( &nact.sa_mask );
546         nact.sa_flags = 0;
547         
548         sigaction ( SIGHUP, NULL, &oact );
549         if ( oact.sa_handler != SIG_IGN )
550           sigaction( SIGHUP, &nact, NULL);
551         sigaction( SIGTERM, NULL, &oact );
552         if ( oact.sa_handler != SIG_IGN )
553           sigaction( SIGTERM, &nact, NULL);
554         nact.sa_handler = SIG_IGN;
555         sigaction( SIGPIPE, &nact, NULL );
556         sigaction( SIGINT, &nact, NULL );
557       }
558
559       if ( chdir("/") )
560         {
561           log_error ("chdir to / failed: %s\n", strerror (errno) );
562           exit (1);
563         }
564
565       /* for now there is no need for concurrent requests because we
566          are asking for passphrases which might pop up a window to get
567          the users respond.  In future the agent may provide other
568          services which won't need a user interaction */
569 #if 0
570       while (!shut_me_down)
571         {
572           struct sockaddr_un clnt_addr;
573           size_t len = sizeof clnt_addr;
574           int fd;
575           /* FIXME: convert to assuan */     
576           fd = accept ( listen_fd, (struct sockaddr*)&clnt_addr, &len );
577           if ( fd == -1 )
578             log_error ( "accept() failed: %s\n", strerror (errno));
579           else
580             {
581               process_request ( fd );
582               close (fd );
583             }
584         }
585 #endif
586       close (listen_fd);
587     }
588   
589   return 0;
590 }
591
592
593 static int
594 start_listening (const char *name)
595 {
596 #if 0
597   int len;
598   int fd;
599   struct sockaddr_un serv_addr;
600   
601   if (opt.verbose)
602     log_info ("using socket `%s'\n", socket_name );
603
604   if (strlen (socket_name)+1 >= sizeof serv_addr.sun_path ) 
605     {
606       log_error ("name of socket to long\n");
607       return -1;
608     }
609
610   if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1 )
611     log_fatal("can't create socket: %s\n", strerror(errno) );
612
613   memset( &serv_addr, 0, sizeof serv_addr );
614   serv_addr.sun_family = AF_UNIX;
615   strcpy( serv_addr.sun_path, socket_name );
616   len = (offsetof (struct sockaddr_un, sun_path)
617          + strlen(serv_addr.sun_path) + 1);
618   
619   remove (socket_name); errno = 0;
620   if (bind( fd, (struct sockaddr*)&serv_addr, len ) == -1 )
621     {
622       log_error ( "error binding address `%s': %m\n", serv_addr.sun_path );
623       close (fd );
624       return -1;
625     }
626   
627   if (listen (fd, 5 ) == -1)
628     {
629       log_error ( "listen() failed: %s\n", strerror (errno) );
630       close ( fd );
631       return -1;
632     }
633 #endif
634   return -1;
635 }
636
637 /* Look for the passprase as given by the 20 bytes DATA and return it's
638   slot number.  If this passphrase is not in the cache, return -1 */
639 static int
640 open_cached_passphrase ( const char *fpr )
641 {
642   int i;
643   
644   for (i=0; i < MAX_CACHE_ENTRIES; i++ ) 
645     {
646       if (the_cache[i].used && !memcmp (the_cache[i].fpr, fpr, 20))
647         {
648           if ( the_cache[i].used < MAX_CACHE_AGE )
649             the_cache[i].used++;
650           return i;
651         }
652     }
653   
654   return -1;
655 }
656
657 /* Get pointers to the cached passphrase and return the real length
658    PWLEN as well as the somewhat larger BLOCKLEN */
659 static const char * 
660 read_cached_passphrase (int slot, size_t *pwlen, size_t *blocklen)
661 {
662   assert (slot >=0 && slot < MAX_CACHE_ENTRIES);
663   *pwlen    = the_cache[slot].pwlen;
664   *blocklen = the_cache[slot].totlen;
665   return the_cache[slot].pw;
666 }
667
668 static const void
669 clear_cached_passphrase ( int slot )
670 {
671   assert ( slot >=0 && slot < MAX_CACHE_ENTRIES );
672   xfree (the_cache[slot].pw ); 
673   the_cache[slot].pw = NULL; 
674   the_cache[slot].used = 0;
675 }
676
677 static void
678 close_cached_passphrase ( int slot )
679 {
680   /* not yet needed */
681 }
682
683
684 static void
685 set_cached_passphrase ( const char *fpr, const char *pw )
686 {
687   int i, min_used = MAX_CACHE_AGE, slot = -1;
688     
689   for (i=0; i < 20 && !fpr[i]; i++ )
690     ;
691   if (i== 20)
692     return; /* never cache an all empty fingerprint */
693
694   /* first see whether we have already cached this one */
695   for (i=0; i < MAX_CACHE_ENTRIES; i++ ) 
696     {
697       if ( the_cache[i].used && !memcmp (the_cache[i].fpr, fpr, 20) )
698         {
699           slot = i;
700           break;
701         }
702     }
703
704   if (slot == -1)
705     { /* Find an unused one or reuse one */
706       for (i=0; i < MAX_CACHE_ENTRIES; i++ )
707         {
708           if ( !the_cache[i].used ) {
709             slot = i;
710             break;
711           }
712           if ( the_cache[i].used < min_used )
713             {
714               min_used = the_cache[i].used;
715               slot = i;
716             }
717         }
718       assert ( slot != -1 );
719     }
720   xfree (the_cache[slot].pw);
721   /* fixme: Allocate to fixed sizes */
722   the_cache[slot].used = 1;
723   memcpy (the_cache[slot].fpr, fpr, 20 );
724   the_cache[slot].pw = gcry_xstrdup ( pw );
725   the_cache[slot].pwlen = strlen ( pw );
726   the_cache[slot].totlen = strlen ( pw );
727 }
728
729
730
731 static int
732 passphrase_dialog ( const byte *fpr, const char *user_string )
733 {
734   /* FIXME: call the PIN-ENtry */
735
736   return 0;
737 }
738
739
740
741 static int
742 writen ( int fd, const void *buf, size_t nbytes )
743 {
744   size_t nleft = nbytes;
745   ssize_t nwritten;
746   
747   while (nleft > 0)
748     {
749       nwritten = write( fd, buf, nleft );
750       if ( nwritten < 0 )
751         {
752           log_error ( "writen() failed: %s\n", strerror (errno) );
753           return -1;
754         }
755       nleft -= nwritten;
756       buf = (const char*)buf + nwritten;
757     }
758   return 0;
759 }
760
761
762 static int
763 readn ( int fd, void *buf, size_t buflen, size_t *ret_nread )
764 {
765   size_t nleft = buflen;
766   int nread;
767   char *p;
768   
769   p = buf;
770   while (nleft > 0 )
771     {
772       nread = read ( fd, buf, nleft );
773       if ( nread < 0 )
774         {
775           log_error ( "read() error: %s\n", strerror (errno) );
776           return -1;
777         }
778       else if (!nread )
779         break; /* EOF */
780         nleft -= nread;
781         buf = (char*)buf + nread;
782     }
783   if (ret_nread )
784     *ret_nread = buflen - nleft;
785   return 0;
786 }
787
788
789
790
791 static void
792 reply_error ( int fd, int x )
793 {
794   /*FIXME:*/
795 }
796
797 static void
798 reply ( int fd, int x, const char *data, size_t datalen )
799 {
800   /*FIXME:*/
801 }
802
803 static void
804 req_get_version ( int fd, const char *data, size_t datalen )
805 {
806   /*FIXME:*/
807 }
808
809 static void
810 req_get_passphrase ( int fd, const char *data, size_t datalen )
811 {
812 #if 0
813   int slot;
814   const char *pw;
815   size_t pwlen, blocklen;
816
817   if (datalen < 20)
818     {
819       reply_error ( fd, GPGA_PROT_INVALID_DATA );
820       return;
821     }
822
823   slot = open_cached_passphrase ( data );
824   if ( slot == -1 )
825     {
826       int rc;
827       char *string;
828       
829       if ( datalen > 20 ) 
830         {
831           string = xmalloc ( datalen - 20 + 1 );
832           memcpy (string, data+20, datalen-20 );
833           string[datalen-20] = 0;
834         }
835       else
836         {
837           string = xstrdup ("[fingerprint]");
838         }
839       rc = passphrase_dialog ( data, string ); 
840       xfree (string);
841       if (rc) 
842         {
843           reply_error ( fd, rc );
844           return;
845         }
846       slot = open_cached_passphrase ( data );
847       if (slot < 0)
848         BUG ();
849     }
850     
851   pw = read_cached_passphrase ( slot, &pwlen, &blocklen );
852   if (!pw || blocklen < pwlen)
853     BUG ();
854 #if 0 /* FIXME: */
855     /* we do a hardcoded reply here to avoid copying of the passphrase
856      * from the cache to a temporary buffer */
857   {
858     byte buf[20]; 
859     
860     u32tobuf ( buf+0, (8+blocklen) );
861     u32tobuf ( buf+4, GPGA_PROT_GOT_PASSPHRASE );
862     u32tobuf ( buf+8, pwlen );
863     writen ( fd, buf, 12 );
864     writen ( fd, pw, blocklen );
865   }
866 #endif
867   close_cached_passphrase ( slot );
868 #endif
869 }
870
871 static void
872 req_clear_passphrase ( int fd, const char *data, size_t datalen )
873 {
874 #if 0
875   int slot;
876   
877   if ( datalen < 20 )
878     {
879       reply_error ( fd, GPGA_PROT_INVALID_DATA );
880       return;
881     }
882
883   slot = open_cached_passphrase ( data );
884   if ( slot == -1 ) 
885     {
886       reply_error ( fd, GPGA_PROT_NO_PASSPHRASE );
887       return;
888     }
889          
890   clear_cached_passphrase ( slot );
891   close_cached_passphrase ( slot );
892   reply_error (fd, GPGA_PROT_OKAY );
893 #endif
894 }
895
896 static void
897 req_shutdown ( int fd, const char *data, size_t datalen )
898 {
899   shut_me_down = 1;
900 /*    reply ( fd, GPGA_PROT_OKAY, "", 0 ); */
901 }
902
903
904 static void
905 req_flush ( int fd, const char *data, size_t datalen )
906 {
907   int i;
908   
909   /* FIXME: when using multiple connections we need to cope with locking */
910   for (i=0; i < MAX_CACHE_ENTRIES; i++ )
911     {
912       if ( the_cache[i].used ) {
913         xfree ( the_cache[i].pw );
914         the_cache[i].pw = NULL;
915         the_cache[i].used = 0;
916       }
917     }
918 /*    reply ( fd, GPGA_PROT_OKAY, "", 0 ); */
919 }
920
921
922 static void
923 process_request ( int fd )
924 {
925 #if 0
926   byte buf[3000]; /* Below is a hardcoded max. length check */
927   byte *data;
928   size_t n, nread;    
929   
930     /* Check the magic and the protocol number */
931   if ( readn ( fd, buf, 12, &nread ) )
932     goto read_failure;
933   if ( nread != 12 || memcmp ( buf, "GPGA\0\0\0\x01", 8 ) ) {
934     reply_error ( fd, GPGA_PROT_PROTOCOL_ERROR );
935     return;
936   }
937   n = buftou32 ( buf + 8 ); /* length of following packet */
938   if ( n < 4 || n > 2048 ) {
939     reply_error ( fd, GPGA_PROT_INVALID_DATA );
940     return;
941   }
942   /* read the request packet */
943   if ( readn ( fd, buf, n, &nread ) )
944     goto read_failure;
945   if ( nread != n ) {
946     reply_error ( fd, GPGA_PROT_PROTOCOL_ERROR );
947     return;
948   }
949   /* dispatch the request */
950   n -= 4;
951   data = buf+4;
952   switch ( buftou32 ( buf ) ) {
953   case GPGA_PROT_GET_VERSION: 
954     req_get_version ( fd, data, n );
955     break;
956   case GPGA_PROT_GET_PASSPHRASE:
957     req_get_passphrase (fd, data, n);
958     break;
959   case GPGA_PROT_CLEAR_PASSPHRASE:
960     req_clear_passphrase (fd, data, n ); 
961     break;
962   case GPGA_PROT_SHUTDOWN:
963     req_shutdown (fd, data, n );
964     break;
965   case GPGA_PROT_FLUSH:
966     req_flush (fd, data, n );
967     break;
968
969   default:
970     reply_error ( fd, GPGA_PROT_INVALID_REQUEST );
971     break;
972   }      
973     
974   return;
975
976  read_failure:
977   /* it does not make sense to respond in this case */
978   log_error ( "read failure: %s\n", strerror(errno));
979   return;
980 #endif
981 }
982
983
984