* gpgkeys_hkp.c (get_key), gpgkeys_http.c (get_key): Fix missing
[gnupg.git] / keyserver / gpgkeys_finger.c
1 /* gpgkeys_finger.c - fetch a key via finger
2  * Copyright (C) 2004, 2005 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 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <errno.h>
26 #include <unistd.h>
27 #ifdef HAVE_GETOPT_H
28 #include <getopt.h>
29 #endif
30
31 #ifdef _WIN32
32 #include <windows.h>
33 #else
34 #include <unistd.h>
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <sys/time.h>
38 #include <time.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41 #include <netdb.h>
42 #endif
43
44 #define INCLUDED_BY_MAIN_MODULE 1
45 #include "util.h"
46 #include "keyserver.h"
47 #include "ksutil.h"
48
49 #ifdef _WIN32
50 #define sock_close(a)  closesocket(a)
51 #else
52 #define sock_close(a)  close(a)
53 #endif
54
55 extern char *optarg;
56 extern int optind;
57
58 static int verbose=0;
59 static char path[MAX_OPAQUE+1];
60 static FILE *input, *output, *console;
61
62 #ifdef _WIN32
63 static void
64 deinit_sockets (void)
65 {
66   WSACleanup();
67 }
68
69 static void
70 init_sockets (void)
71 {
72   static int initialized;
73   static WSADATA wsdata;
74
75   if (initialized)
76     return;
77
78   if (WSAStartup (0x0101, &wsdata) )
79     {
80       fprintf (console, "error initializing socket library: ec=%d\n", 
81                (int)WSAGetLastError () );
82       return;
83     }
84   if (wsdata.wVersion < 0x0001)
85     {
86       fprintf (console, "socket library version is %x.%x - but 1.1 needed\n",
87                LOBYTE(wsdata.wVersion), HIBYTE(wsdata.wVersion));
88       WSACleanup();
89       return;
90     }
91   atexit  (deinit_sockets);
92   initialized = 1;
93 }
94 #endif /*_WIN32*/
95
96
97 /* Connect to SERVER at PORT and return a file descriptor or -1 on
98    error. */
99 static int
100 connect_server (const char *server, unsigned short port)
101 {
102   int sock = -1;
103
104 #ifdef _WIN32
105   struct hostent *hp;
106   struct sockaddr_in addr;
107   unsigned long l;
108
109   init_sockets ();
110
111   memset (&addr, 0, sizeof addr);
112   addr.sin_family = AF_INET;
113   addr.sin_port = htons (port);
114
115   /* Win32 gethostbyname doesn't handle IP addresses internally, so we
116      try inet_addr first on that platform only. */
117   if ((l = inet_addr (server)) != INADDR_NONE) 
118     memcpy (&addr.sin_addr, &l, sizeof l);
119   else if ((hp = gethostbyname (server))) 
120     {
121       if (hp->h_addrtype != AF_INET)
122         {
123           fprintf (console, "gpgkeys: unknown address family for `%s'\n",
124                    server);
125           return -1;
126         }
127       if (hp->h_length != 4)
128         {
129           fprintf (console, "gpgkeys: illegal address length for `%s'\n",
130                    server);
131           return -1;
132         }
133       memcpy (&addr.sin_addr, hp->h_addr, hp->h_length);
134     }
135   else
136     {
137       fprintf (console, "gpgkeys: host `%s' not found: ec=%d\n",
138                server, (int)WSAGetLastError ());
139       return -1;
140     }
141
142   sock = socket (AF_INET, SOCK_STREAM, 0);
143   if (sock == INVALID_SOCKET)
144     {
145       fprintf (console, "gpgkeys: error creating socket: ec=%d\n", 
146                (int)WSAGetLastError ());
147       return -1;
148     }
149
150   if (connect (sock, (struct sockaddr *)&addr, sizeof addr))
151     {
152       fprintf (console, "gpgkeys: error connecting `%s': ec=%d\n", 
153                server, (int)WSAGetLastError ());
154       sock_close (sock);
155       return -1;
156     }
157
158 #else
159
160   struct sockaddr_in addr;
161   struct hostent *host;
162
163   addr.sin_family = AF_INET;
164   addr.sin_port = htons (port);
165   host = gethostbyname ((char*)server);
166   if (!host)
167     {
168       fprintf (console, "gpgkeys: host `%s' not found: %s\n",
169                server, strerror (errno));
170       return -1;
171     }
172   
173   addr.sin_addr = *(struct in_addr*)host->h_addr;
174
175   sock = socket (AF_INET, SOCK_STREAM, 0);
176   if (sock == -1)
177     {
178       fprintf (console, "gpgkeys: error creating socket: %s\n", 
179                strerror (errno));
180       return -1;
181     }
182   
183   if (connect (sock, (struct sockaddr *)&addr, sizeof addr) == -1)
184     {
185       fprintf (console, "gpgkeys: error connecting `%s': %s\n", 
186                server, strerror (errno));
187       close (sock);
188       return -1;
189     }
190 #endif
191     
192   return sock;
193 }
194
195 static int
196 write_server (int sock, const char *data, size_t length)
197 {
198   int nleft;
199
200   nleft = length;
201   while (nleft > 0) 
202     {
203       int nwritten;
204       
205 #ifdef _WIN32  
206       nwritten = send (sock, data, nleft, 0);
207       if ( nwritten == SOCKET_ERROR )
208         {
209           fprintf (console, "gpgkeys: write failed: ec=%d\n",
210                    (int)WSAGetLastError ());
211           return -1;
212         }
213 #else
214       nwritten = write (sock, data, nleft);
215       if (nwritten == -1)
216         {
217           if (errno == EINTR)
218             continue;
219           if (errno == EAGAIN)
220             {
221               struct timeval tv;
222               
223               tv.tv_sec =  0;
224               tv.tv_usec = 50000;
225               select(0, NULL, NULL, NULL, &tv);
226               continue;
227             }
228           fprintf (console, "gpgkeys: write failed: %s\n", strerror(errno));
229           return -1;
230         }
231 #endif
232       nleft -=nwritten;
233       data += nwritten;
234     }
235   
236   return 0;
237 }
238
239
240 /* Send the finger REQUEST to the server.  Returns 0 and a file descriptor
241    in R_SOCK if the request was sucessful. */
242 static int
243 send_request (const char *request, int *r_sock)
244 {
245   char *server;
246   char *name;
247   int sock;
248
249   *r_sock = -1;
250   name = strdup (request);
251   if (!name)
252     {
253       fprintf(console,"gpgkeys: out of memory\n");
254       return KEYSERVER_NO_MEMORY;
255     }
256
257   server = strchr (name, '@');
258   if (!server)
259     {
260       fprintf (console, "gpgkeys: no name included in request\n");
261       free (name);
262       return KEYSERVER_GENERAL_ERROR;
263     }
264   *server++ = 0;
265   
266   sock = connect_server (server, 79);
267   if (sock == -1)
268     {
269       free (name);
270       return KEYSERVER_UNREACHABLE;
271     }
272
273   if (write_server (sock, name, strlen (name))
274       || write_server (sock, "\r\n", 2))
275     {
276       free (name);
277       sock_close (sock);
278       return KEYSERVER_GENERAL_ERROR;
279     }
280   free (name);
281   *r_sock = sock;
282   return 0;
283 }
284
285
286
287 static int
288 get_key (char *getkey)
289 {
290   int rc;
291   int sock;
292   IOBUF fp_read;
293   unsigned int maxlen, buflen, gotit=0;
294   byte *line = NULL;
295
296   if (strncmp (getkey,"0x",2)==0)
297     getkey+=2;
298
299   /* Frankly we don't know what keys the server will return; we
300      indicated the requested key anyway. */
301   fprintf(output,"KEY 0x%s BEGIN\n",getkey);
302
303   rc = send_request (path, &sock);
304   if(rc)
305     {
306       fprintf(output,"KEY 0x%s FAILED %d\n",getkey, rc);
307       sock_close (sock);
308       return KEYSERVER_OK;
309     }
310   
311   /* Hmmm, we use iobuf here only to cope with Windows socket
312      peculiarities (we can't used fdopen).  */
313   fp_read = iobuf_sockopen (sock , "r");
314   if (!fp_read)
315     {
316       fprintf(output,"KEY 0x%s FAILED %d\n",getkey, KEYSERVER_INTERNAL_ERROR);
317       sock_close (sock);
318       return KEYSERVER_OK;
319     }
320
321   while ( iobuf_read_line ( fp_read, &line, &buflen, &maxlen))
322     {
323       maxlen=1024;
324       
325       if(gotit)
326         {
327           fputs (line, output);
328           if (!strncmp(line,END,strlen(END)))
329             break;
330         }
331       else if(!strncmp(line,BEGIN,strlen(BEGIN)))
332         {
333           fputs (line,output);
334           gotit=1;
335         }
336     }
337   
338   if(gotit)
339     fprintf (output,"KEY 0x%s END\n", getkey);
340   else
341     {
342       fprintf (console,"gpgkeys: key %s not found on keyserver\n",getkey);
343       fprintf (output,"KEY 0x%s FAILED %d\n",
344                getkey,KEYSERVER_KEY_NOT_FOUND);
345     }
346
347   m_free(line);
348   iobuf_close (fp_read);
349
350   return KEYSERVER_OK;
351 }
352
353
354 static void 
355 show_help (FILE *fp)
356 {
357   fprintf (fp,"-h\thelp\n");
358   fprintf (fp,"-V\tversion\n");
359   fprintf (fp,"-o\toutput to this file\n");
360 }
361
362 int
363 main(int argc,char *argv[])
364 {
365   int arg,action=-1,ret=KEYSERVER_INTERNAL_ERROR;
366   char line[MAX_LINE];
367   char *thekey=NULL;
368   unsigned int timeout=DEFAULT_KEYSERVER_TIMEOUT;
369
370   console=stderr;
371
372   /* Kludge to implement standard GNU options.  */
373   if (argc > 1 && !strcmp (argv[1], "--version"))
374     {
375       fputs ("gpgkeys_ldap (GnuPG) " VERSION"\n", stdout);
376       return 0;
377     }
378   else if (argc > 1 && !strcmp (argv[1], "--help"))
379     {
380       show_help (stdout);
381       return 0;
382     }
383
384   while((arg=getopt(argc,argv,"hVo:"))!=-1)
385     switch(arg)
386       {
387       default:
388       case 'h':
389         show_help (console);
390         return KEYSERVER_OK;
391
392       case 'V':
393         fprintf(stdout,"%d\n%s\n",KEYSERVER_PROTO_VERSION,VERSION);
394         return KEYSERVER_OK;
395
396       case 'o':
397         output=fopen(optarg,"w");
398         if(output==NULL)
399           {
400             fprintf(console,"gpgkeys: Cannot open output file `%s': %s\n",
401                     optarg,strerror(errno));
402             return KEYSERVER_INTERNAL_ERROR;
403           }
404
405         break;
406       }
407
408   if(argc>optind)
409     {
410       input=fopen(argv[optind],"r");
411       if(input==NULL)
412         {
413           fprintf(console,"gpgkeys: Cannot open input file `%s': %s\n",
414                   argv[optind],strerror(errno));
415           return KEYSERVER_INTERNAL_ERROR;
416         }
417     }
418
419   if(input==NULL)
420     input=stdin;
421
422   if(output==NULL)
423     output=stdout;
424
425   /* Get the command and info block */
426
427   while(fgets(line,MAX_LINE,input)!=NULL)
428     {
429       int version;
430       char command[MAX_COMMAND+1];
431       char option[MAX_OPTION+1];
432       char hash;
433
434       if(line[0]=='\n')
435         break;
436
437       if(sscanf(line,"%c",&hash)==1 && hash=='#')
438         continue;
439
440       if(sscanf(line,"COMMAND %" MKSTRING(MAX_COMMAND) "s\n",command)==1)
441         {
442           command[MAX_COMMAND]='\0';
443
444           if(strcasecmp(command,"get")==0)
445             action=GET;
446
447           continue;
448         }
449
450       if(strncmp(line,"HOST ",5)==0)
451         {
452           fprintf(console,"gpgkeys: finger://relay/user syntax is not"
453                   " supported.  Use finger:user instead.\n");
454           ret=KEYSERVER_NOT_SUPPORTED;
455           goto fail;
456         }
457
458       if(sscanf(line,"OPAQUE %" MKSTRING(MAX_OPAQUE) "s\n",path)==1)
459         {
460           path[MAX_OPAQUE]='\0';
461           continue;
462         }
463
464       if(sscanf(line,"VERSION %d\n",&version)==1)
465         {
466           if(version!=KEYSERVER_PROTO_VERSION)
467             {
468               ret=KEYSERVER_VERSION_ERROR;
469               goto fail;
470             }
471
472           continue;
473         }
474
475       if(sscanf(line,"OPTION %" MKSTRING(MAX_OPTION) "s\n",option)==1)
476         {
477           int no=0;
478           char *start=&option[0];
479
480           option[MAX_OPTION]='\0';
481
482           if(strncasecmp(option,"no-",3)==0)
483             {
484               no=1;
485               start=&option[3];
486             }
487
488           if(strcasecmp(start,"verbose")==0)
489             {
490               if(no)
491                 verbose--;
492               else
493                 verbose++;
494             }
495           else if(strncasecmp(start,"timeout",7)==0)
496             {
497               if(no)
498                 timeout=0;
499               else if(start[7]=='=')
500                 timeout=atoi(&start[8]);
501               else if(start[7]=='\0')
502                 timeout=DEFAULT_KEYSERVER_TIMEOUT;
503             }
504
505           continue;
506         }
507     }
508
509   if(timeout && register_timeout()==-1)
510     {
511       fprintf(console,"gpgkeys: unable to register timeout handler\n");
512       return KEYSERVER_INTERNAL_ERROR;
513     }
514
515   /* If it's a GET or a SEARCH, the next thing to come in is the
516      keyids.  If it's a SEND, then there are no keyids. */
517
518   if(action==GET)
519     {
520       /* Eat the rest of the file */
521       for(;;)
522         {
523           if(fgets(line,MAX_LINE,input)==NULL)
524             break;
525           else
526             {
527               if(line[0]=='\n' || line[0]=='\0')
528                 break;
529
530               if(!thekey)
531                 {
532                   thekey=strdup(line);
533                   if(!thekey)
534                     {
535                       fprintf(console,"gpgkeys: out of memory while "
536                               "building key list\n");
537                       ret=KEYSERVER_NO_MEMORY;
538                       goto fail;
539                     }
540
541                   /* Trim the trailing \n */
542                   thekey[strlen(line)-1]='\0';
543                 }
544             }
545         }
546     }
547   else
548     {
549       fprintf(console,
550               "gpgkeys: this keyserver type only supports key retrieval\n");
551       goto fail;
552     }
553
554   if(!thekey || !*path)
555     {
556       fprintf(console,"gpgkeys: invalid keyserver instructions\n");
557       goto fail;
558     }
559
560   /* Send the response */
561
562   fprintf(output,"VERSION %d\n",KEYSERVER_PROTO_VERSION);
563   fprintf(output,"PROGRAM %s\n\n",VERSION);
564
565   if (verbose>1)
566     {
567       if(path[0])
568         fprintf(console,"Path:\t\t%s\n",path);
569       fprintf(console,"Command:\tGET\n");
570     }
571
572   set_timeout(timeout);
573
574   ret = get_key(thekey);
575
576  fail:
577
578   free(thekey);
579
580   if(input!=stdin)
581     fclose(input);
582
583   if(output!=stdout)
584     fclose(output);
585
586   return ret;
587 }