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