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