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