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