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