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