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