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