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