2006-12-21 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / keyserver / gpgkeys_finger.c
blob58082790f7dc3f2fe2a9fde07afb0a82f2fd8f6b
1 /* gpgkeys_finger.c - fetch a key via finger
2 * Copyright (C) 2004, 2005 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19 * USA.
22 #include <config.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #ifdef HAVE_GETOPT_H
29 #include <getopt.h>
30 #endif
32 #ifdef _WIN32
33 #include <windows.h>
34 #else
35 #include <unistd.h>
36 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <sys/time.h>
39 #include <time.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
42 #include <netdb.h>
43 #endif
45 #define INCLUDED_BY_MAIN_MODULE 1
46 #include "util.h"
47 #include "keyserver.h"
48 #include "ksutil.h"
49 #include "iobuf.h"
51 #ifdef _WIN32
52 #define sock_close(a) closesocket(a)
53 #else
54 #define sock_close(a) close(a)
55 #endif
57 extern char *optarg;
58 extern int optind;
60 static FILE *input,*output,*console;
61 static struct ks_options *opt;
63 #ifdef _WIN32
64 static void
65 deinit_sockets (void)
67 WSACleanup();
70 static void
71 init_sockets (void)
73 static int initialized;
74 static WSADATA wsdata;
76 if (initialized)
77 return;
79 if (WSAStartup (0x0101, &wsdata) )
81 fprintf (console, "error initializing socket library: ec=%d\n",
82 (int)WSAGetLastError () );
83 return;
85 if (wsdata.wVersion < 0x0001)
87 fprintf (console, "socket library version is %x.%x - but 1.1 needed\n",
88 LOBYTE(wsdata.wVersion), HIBYTE(wsdata.wVersion));
89 WSACleanup();
90 return;
92 atexit (deinit_sockets);
93 initialized = 1;
95 #endif /*_WIN32*/
98 /* Connect to SERVER at PORT and return a file descriptor or -1 on
99 error. */
100 static int
101 connect_server (const char *server, unsigned short port)
103 int sock = -1;
105 #ifdef _WIN32
106 struct hostent *hp;
107 struct sockaddr_in addr;
108 unsigned long l;
110 init_sockets ();
112 memset (&addr, 0, sizeof addr);
113 addr.sin_family = AF_INET;
114 addr.sin_port = htons (port);
116 /* Win32 gethostbyname doesn't handle IP addresses internally, so we
117 try inet_addr first on that platform only. */
118 if ((l = inet_addr (server)) != INADDR_NONE)
119 memcpy (&addr.sin_addr, &l, sizeof l);
120 else if ((hp = gethostbyname (server)))
122 if (hp->h_addrtype != AF_INET)
124 fprintf (console, "gpgkeys: unknown address family for `%s'\n",
125 server);
126 return -1;
128 if (hp->h_length != 4)
130 fprintf (console, "gpgkeys: illegal address length for `%s'\n",
131 server);
132 return -1;
134 memcpy (&addr.sin_addr, hp->h_addr, hp->h_length);
136 else
138 fprintf (console, "gpgkeys: host `%s' not found: ec=%d\n",
139 server, (int)WSAGetLastError ());
140 return -1;
143 sock = socket (AF_INET, SOCK_STREAM, 0);
144 if (sock == INVALID_SOCKET)
146 fprintf (console, "gpgkeys: error creating socket: ec=%d\n",
147 (int)WSAGetLastError ());
148 return -1;
151 if (connect (sock, (struct sockaddr *)&addr, sizeof addr))
153 fprintf (console, "gpgkeys: error connecting `%s': ec=%d\n",
154 server, (int)WSAGetLastError ());
155 sock_close (sock);
156 return -1;
159 #else
161 struct sockaddr_in addr;
162 struct hostent *host;
164 addr.sin_family = AF_INET;
165 addr.sin_port = htons (port);
166 host = gethostbyname ((char*)server);
167 if (!host)
169 fprintf (console, "gpgkeys: host `%s' not found: %s\n",
170 server, strerror (errno));
171 return -1;
174 addr.sin_addr = *(struct in_addr*)host->h_addr;
176 sock = socket (AF_INET, SOCK_STREAM, 0);
177 if (sock == -1)
179 fprintf (console, "gpgkeys: error creating socket: %s\n",
180 strerror (errno));
181 return -1;
184 if (connect (sock, (struct sockaddr *)&addr, sizeof addr) == -1)
186 fprintf (console, "gpgkeys: error connecting `%s': %s\n",
187 server, strerror (errno));
188 close (sock);
189 return -1;
191 #endif
193 return sock;
196 static int
197 write_server (int sock, const char *data, size_t length)
199 int nleft;
201 nleft = length;
202 while (nleft > 0)
204 int nwritten;
206 #ifdef _WIN32
207 nwritten = send (sock, data, nleft, 0);
208 if ( nwritten == SOCKET_ERROR )
210 fprintf (console, "gpgkeys: write failed: ec=%d\n",
211 (int)WSAGetLastError ());
212 return -1;
214 #else
215 nwritten = write (sock, data, nleft);
216 if (nwritten == -1)
218 if (errno == EINTR)
219 continue;
220 if (errno == EAGAIN)
222 struct timeval tv;
224 tv.tv_sec = 0;
225 tv.tv_usec = 50000;
226 select(0, NULL, NULL, NULL, &tv);
227 continue;
229 fprintf (console, "gpgkeys: write failed: %s\n", strerror(errno));
230 return -1;
232 #endif
233 nleft -=nwritten;
234 data += nwritten;
237 return 0;
241 /* Send the finger REQUEST to the server. Returns 0 and a file descriptor
242 in R_SOCK if the request was sucessful. */
243 static int
244 send_request (const char *request, int *r_sock)
246 char *server;
247 char *name;
248 int sock;
250 *r_sock = -1;
251 name = strdup (request);
252 if (!name)
254 fprintf(console,"gpgkeys: out of memory\n");
255 return KEYSERVER_NO_MEMORY;
258 server = strchr (name, '@');
259 if (!server)
261 fprintf (console, "gpgkeys: no name included in request\n");
262 free (name);
263 return KEYSERVER_GENERAL_ERROR;
265 *server++ = 0;
267 sock = connect_server (server, 79);
268 if (sock == -1)
270 free (name);
271 return KEYSERVER_UNREACHABLE;
274 if (write_server (sock, name, strlen (name))
275 || write_server (sock, "\r\n", 2))
277 free (name);
278 sock_close (sock);
279 return KEYSERVER_GENERAL_ERROR;
281 free (name);
282 *r_sock = sock;
283 return 0;
288 static int
289 get_key (char *getkey)
291 int rc;
292 int sock;
293 iobuf_t fp_read;
294 unsigned int maxlen, buflen, gotit=0;
295 byte *line = NULL;
297 if (strncmp (getkey,"0x",2)==0)
298 getkey+=2;
300 /* Frankly we don't know what keys the server will return; we
301 indicated the requested key anyway. */
302 fprintf(output,"KEY 0x%s BEGIN\n",getkey);
304 rc=send_request(opt->opaque,&sock);
305 if(rc)
307 fprintf(output,"KEY 0x%s FAILED %d\n",getkey, rc);
308 sock_close (sock);
309 return KEYSERVER_OK;
312 /* Hmmm, we use iobuf here only to cope with Windows socket
313 peculiarities (we can't used fdopen). */
314 fp_read = iobuf_sockopen (sock , "r");
315 if (!fp_read)
317 fprintf(output,"KEY 0x%s FAILED %d\n",getkey, KEYSERVER_INTERNAL_ERROR);
318 sock_close (sock);
319 return KEYSERVER_OK;
322 while ( iobuf_read_line ( fp_read, &line, &buflen, &maxlen))
324 maxlen=1024;
326 if(gotit)
328 print_nocr(output, (const char*)line);
329 if (!strncmp((char*)line,END,strlen(END)))
330 break;
332 else if(!strncmp((char*)line,BEGIN,strlen(BEGIN)))
334 print_nocr(output, (const char*)line);
335 gotit=1;
339 if(gotit)
340 fprintf (output,"KEY 0x%s END\n", getkey);
341 else
343 fprintf(console,"gpgkeys: no key data found for finger:%s\n",
344 opt->opaque);
345 fprintf(output,"KEY 0x%s FAILED %d\n",getkey,KEYSERVER_KEY_NOT_FOUND);
348 xfree(line);
349 iobuf_close (fp_read);
351 return KEYSERVER_OK;
355 static void
356 show_help (FILE *fp)
358 fprintf (fp,"-h\thelp\n");
359 fprintf (fp,"-V\tversion\n");
360 fprintf (fp,"-o\toutput to this file\n");
364 main(int argc,char *argv[])
366 int arg,ret=KEYSERVER_INTERNAL_ERROR;
367 char line[MAX_LINE];
368 char *thekey=NULL;
370 console=stderr;
372 /* Kludge to implement standard GNU options. */
373 if (argc > 1 && !strcmp (argv[1], "--version"))
375 fputs ("gpgkeys_finger (GnuPG) " VERSION"\n", stdout);
376 return 0;
378 else if (argc > 1 && !strcmp (argv[1], "--help"))
380 show_help (stdout);
381 return 0;
384 while((arg=getopt(argc,argv,"hVo:"))!=-1)
385 switch(arg)
387 default:
388 case 'h':
389 show_help (console);
390 return KEYSERVER_OK;
392 case 'V':
393 fprintf(stdout,"%d\n%s\n",KEYSERVER_PROTO_VERSION,VERSION);
394 return KEYSERVER_OK;
396 case 'o':
397 output=fopen(optarg,"w");
398 if(output==NULL)
400 fprintf(console,"gpgkeys: Cannot open output file `%s': %s\n",
401 optarg,strerror(errno));
402 return KEYSERVER_INTERNAL_ERROR;
405 break;
408 if(argc>optind)
410 input=fopen(argv[optind],"r");
411 if(input==NULL)
413 fprintf(console,"gpgkeys: Cannot open input file `%s': %s\n",
414 argv[optind],strerror(errno));
415 return KEYSERVER_INTERNAL_ERROR;
419 if(input==NULL)
420 input=stdin;
422 if(output==NULL)
423 output=stdout;
425 opt=init_ks_options();
426 if(!opt)
427 return KEYSERVER_NO_MEMORY;
429 /* Get the command and info block */
431 while(fgets(line,MAX_LINE,input)!=NULL)
433 int err;
435 if(line[0]=='\n')
436 break;
438 err=parse_ks_options(line,opt);
439 if(err>0)
441 ret=err;
442 goto fail;
444 else if(err==0)
445 continue;
448 if(opt->host)
450 fprintf(console,"gpgkeys: finger://relay/user syntax is not"
451 " supported. Use finger:user instead.\n");
452 ret=KEYSERVER_NOT_SUPPORTED;
453 goto fail;
456 if(opt->timeout && register_timeout()==-1)
458 fprintf(console,"gpgkeys: unable to register timeout handler\n");
459 return KEYSERVER_INTERNAL_ERROR;
462 /* If it's a GET or a SEARCH, the next thing to come in is the
463 keyids. If it's a SEND, then there are no keyids. */
465 if(opt->action==KS_GET)
467 /* Eat the rest of the file */
468 for(;;)
470 if(fgets(line,MAX_LINE,input)==NULL)
471 break;
472 else
474 if(line[0]=='\n' || line[0]=='\0')
475 break;
477 if(!thekey)
479 thekey=strdup(line);
480 if(!thekey)
482 fprintf(console,"gpgkeys: out of memory while "
483 "building key list\n");
484 ret=KEYSERVER_NO_MEMORY;
485 goto fail;
488 /* Trim the trailing \n */
489 thekey[strlen(line)-1]='\0';
494 else
496 fprintf(console,
497 "gpgkeys: this keyserver type only supports key retrieval\n");
498 goto fail;
501 if(!thekey || !opt->opaque)
503 fprintf(console,"gpgkeys: invalid keyserver instructions\n");
504 goto fail;
507 /* Send the response */
509 fprintf(output,"VERSION %d\n",KEYSERVER_PROTO_VERSION);
510 fprintf(output,"PROGRAM %s\n\n",VERSION);
512 if(opt->verbose>1)
514 fprintf(console,"User:\t\t%s\n",opt->opaque);
515 fprintf(console,"Command:\tGET\n");
518 set_timeout(opt->timeout);
520 ret=get_key(thekey);
522 fail:
524 free(thekey);
526 if(input!=stdin)
527 fclose(input);
529 if(output!=stdout)
530 fclose(output);
532 free_ks_options(opt);
534 return ret;