* gpgkeys_ldap.c (printquoted), curl-shim.c (curl_escape): Fix bad
[gnupg.git] / keyserver / gpgkeys_finger.c
blob4124ebc72f3ed439239d5e9cfba7ac4f985a68dc
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"
50 #ifdef _WIN32
51 #define sock_close(a) closesocket(a)
52 #else
53 #define sock_close(a) close(a)
54 #endif
56 extern char *optarg;
57 extern int optind;
59 static FILE *input,*output,*console;
60 static struct ks_options *opt;
62 #ifdef _WIN32
63 static void
64 deinit_sockets (void)
66 WSACleanup();
69 static void
70 init_sockets (void)
72 static int initialized;
73 static WSADATA wsdata;
75 if (initialized)
76 return;
78 if (WSAStartup (0x0101, &wsdata) )
80 fprintf (console, "error initializing socket library: ec=%d\n",
81 (int)WSAGetLastError () );
82 return;
84 if (wsdata.wVersion < 0x0001)
86 fprintf (console, "socket library version is %x.%x - but 1.1 needed\n",
87 LOBYTE(wsdata.wVersion), HIBYTE(wsdata.wVersion));
88 WSACleanup();
89 return;
91 atexit (deinit_sockets);
92 initialized = 1;
94 #endif /*_WIN32*/
97 /* Connect to SERVER at PORT and return a file descriptor or -1 on
98 error. */
99 static int
100 connect_server (const char *server, unsigned short port)
102 int sock = -1;
104 #ifdef _WIN32
105 struct hostent *hp;
106 struct sockaddr_in addr;
107 unsigned long l;
109 init_sockets ();
111 memset (&addr, 0, sizeof addr);
112 addr.sin_family = AF_INET;
113 addr.sin_port = htons (port);
115 /* Win32 gethostbyname doesn't handle IP addresses internally, so we
116 try inet_addr first on that platform only. */
117 if ((l = inet_addr (server)) != INADDR_NONE)
118 memcpy (&addr.sin_addr, &l, sizeof l);
119 else if ((hp = gethostbyname (server)))
121 if (hp->h_addrtype != AF_INET)
123 fprintf (console, "gpgkeys: unknown address family for `%s'\n",
124 server);
125 return -1;
127 if (hp->h_length != 4)
129 fprintf (console, "gpgkeys: illegal address length for `%s'\n",
130 server);
131 return -1;
133 memcpy (&addr.sin_addr, hp->h_addr, hp->h_length);
135 else
137 fprintf (console, "gpgkeys: host `%s' not found: ec=%d\n",
138 server, (int)WSAGetLastError ());
139 return -1;
142 sock = socket (AF_INET, SOCK_STREAM, 0);
143 if (sock == INVALID_SOCKET)
145 fprintf (console, "gpgkeys: error creating socket: ec=%d\n",
146 (int)WSAGetLastError ());
147 return -1;
150 if (connect (sock, (struct sockaddr *)&addr, sizeof addr))
152 fprintf (console, "gpgkeys: error connecting `%s': ec=%d\n",
153 server, (int)WSAGetLastError ());
154 sock_close (sock);
155 return -1;
158 #else
160 struct sockaddr_in addr;
161 struct hostent *host;
163 addr.sin_family = AF_INET;
164 addr.sin_port = htons (port);
165 host = gethostbyname ((char*)server);
166 if (!host)
168 fprintf (console, "gpgkeys: host `%s' not found: %s\n",
169 server, strerror (errno));
170 return -1;
173 addr.sin_addr = *(struct in_addr*)host->h_addr;
175 sock = socket (AF_INET, SOCK_STREAM, 0);
176 if (sock == -1)
178 fprintf (console, "gpgkeys: error creating socket: %s\n",
179 strerror (errno));
180 return -1;
183 if (connect (sock, (struct sockaddr *)&addr, sizeof addr) == -1)
185 fprintf (console, "gpgkeys: error connecting `%s': %s\n",
186 server, strerror (errno));
187 close (sock);
188 return -1;
190 #endif
192 return sock;
195 static int
196 write_server (int sock, const char *data, size_t length)
198 int nleft;
200 nleft = length;
201 while (nleft > 0)
203 int nwritten;
205 #ifdef _WIN32
206 nwritten = send (sock, data, nleft, 0);
207 if ( nwritten == SOCKET_ERROR )
209 fprintf (console, "gpgkeys: write failed: ec=%d\n",
210 (int)WSAGetLastError ());
211 return -1;
213 #else
214 nwritten = write (sock, data, nleft);
215 if (nwritten == -1)
217 if (errno == EINTR)
218 continue;
219 if (errno == EAGAIN)
221 struct timeval tv;
223 tv.tv_sec = 0;
224 tv.tv_usec = 50000;
225 select(0, NULL, NULL, NULL, &tv);
226 continue;
228 fprintf (console, "gpgkeys: write failed: %s\n", strerror(errno));
229 return -1;
231 #endif
232 nleft -=nwritten;
233 data += nwritten;
236 return 0;
240 /* Send the finger REQUEST to the server. Returns 0 and a file descriptor
241 in R_SOCK if the request was sucessful. */
242 static int
243 send_request (const char *request, int *r_sock)
245 char *server;
246 char *name;
247 int sock;
249 *r_sock = -1;
250 name = strdup (request);
251 if (!name)
253 fprintf(console,"gpgkeys: out of memory\n");
254 return KEYSERVER_NO_MEMORY;
257 server = strchr (name, '@');
258 if (!server)
260 fprintf (console, "gpgkeys: no name included in request\n");
261 free (name);
262 return KEYSERVER_GENERAL_ERROR;
264 *server++ = 0;
266 sock = connect_server (server, 79);
267 if (sock == -1)
269 free (name);
270 return KEYSERVER_UNREACHABLE;
273 if (write_server (sock, name, strlen (name))
274 || write_server (sock, "\r\n", 2))
276 free (name);
277 sock_close (sock);
278 return KEYSERVER_GENERAL_ERROR;
280 free (name);
281 *r_sock = sock;
282 return 0;
287 static int
288 get_key (char *getkey)
290 int rc;
291 int sock;
292 IOBUF fp_read;
293 unsigned int maxlen, buflen, gotit=0;
294 byte *line = NULL;
296 if (strncmp (getkey,"0x",2)==0)
297 getkey+=2;
299 /* Frankly we don't know what keys the server will return; we
300 indicated the requested key anyway. */
301 fprintf(output,"KEY 0x%s BEGIN\n",getkey);
303 rc=send_request(opt->opaque,&sock);
304 if(rc)
306 fprintf(output,"KEY 0x%s FAILED %d\n",getkey, rc);
307 sock_close (sock);
308 return KEYSERVER_OK;
311 /* Hmmm, we use iobuf here only to cope with Windows socket
312 peculiarities (we can't used fdopen). */
313 fp_read = iobuf_sockopen (sock , "r");
314 if (!fp_read)
316 fprintf(output,"KEY 0x%s FAILED %d\n",getkey, KEYSERVER_INTERNAL_ERROR);
317 sock_close (sock);
318 return KEYSERVER_OK;
321 while ( iobuf_read_line ( fp_read, &line, &buflen, &maxlen))
323 maxlen=1024;
325 if(gotit)
327 print_nocr(output,line);
328 if (!strncmp(line,END,strlen(END)))
329 break;
331 else if(!strncmp(line,BEGIN,strlen(BEGIN)))
333 print_nocr(output,line);
334 gotit=1;
338 if(gotit)
339 fprintf (output,"KEY 0x%s END\n", getkey);
340 else
342 fprintf(console,"gpgkeys: no key data found for finger:%s\n",
343 opt->opaque);
344 fprintf(output,"KEY 0x%s FAILED %d\n",getkey,KEYSERVER_KEY_NOT_FOUND);
347 xfree(line);
348 iobuf_close (fp_read);
350 return KEYSERVER_OK;
354 static void
355 show_help (FILE *fp)
357 fprintf (fp,"-h\thelp\n");
358 fprintf (fp,"-V\tversion\n");
359 fprintf (fp,"-o\toutput to this file\n");
363 main(int argc,char *argv[])
365 int arg,ret=KEYSERVER_INTERNAL_ERROR;
366 char line[MAX_LINE];
367 char *thekey=NULL;
369 console=stderr;
371 /* Kludge to implement standard GNU options. */
372 if (argc > 1 && !strcmp (argv[1], "--version"))
374 fputs ("gpgkeys_finger (GnuPG) " VERSION"\n", stdout);
375 return 0;
377 else if (argc > 1 && !strcmp (argv[1], "--help"))
379 show_help (stdout);
380 return 0;
383 while((arg=getopt(argc,argv,"hVo:"))!=-1)
384 switch(arg)
386 default:
387 case 'h':
388 show_help (console);
389 return KEYSERVER_OK;
391 case 'V':
392 fprintf(stdout,"%d\n%s\n",KEYSERVER_PROTO_VERSION,VERSION);
393 return KEYSERVER_OK;
395 case 'o':
396 output=fopen(optarg,"w");
397 if(output==NULL)
399 fprintf(console,"gpgkeys: Cannot open output file `%s': %s\n",
400 optarg,strerror(errno));
401 return KEYSERVER_INTERNAL_ERROR;
404 break;
407 if(argc>optind)
409 input=fopen(argv[optind],"r");
410 if(input==NULL)
412 fprintf(console,"gpgkeys: Cannot open input file `%s': %s\n",
413 argv[optind],strerror(errno));
414 return KEYSERVER_INTERNAL_ERROR;
418 if(input==NULL)
419 input=stdin;
421 if(output==NULL)
422 output=stdout;
424 opt=init_ks_options();
425 if(!opt)
426 return KEYSERVER_NO_MEMORY;
428 /* Get the command and info block */
430 while(fgets(line,MAX_LINE,input)!=NULL)
432 int err;
434 if(line[0]=='\n')
435 break;
437 err=parse_ks_options(line,opt);
438 if(err>0)
440 ret=err;
441 goto fail;
443 else if(err==0)
444 continue;
447 if(opt->host)
449 fprintf(console,"gpgkeys: finger://relay/user syntax is not"
450 " supported. Use finger:user instead.\n");
451 ret=KEYSERVER_NOT_SUPPORTED;
452 goto fail;
455 if(opt->timeout && register_timeout()==-1)
457 fprintf(console,"gpgkeys: unable to register timeout handler\n");
458 return KEYSERVER_INTERNAL_ERROR;
461 /* If it's a GET or a SEARCH, the next thing to come in is the
462 keyids. If it's a SEND, then there are no keyids. */
464 if(opt->action==KS_GET)
466 /* Eat the rest of the file */
467 for(;;)
469 if(fgets(line,MAX_LINE,input)==NULL)
470 break;
471 else
473 if(line[0]=='\n' || line[0]=='\0')
474 break;
476 if(!thekey)
478 thekey=strdup(line);
479 if(!thekey)
481 fprintf(console,"gpgkeys: out of memory while "
482 "building key list\n");
483 ret=KEYSERVER_NO_MEMORY;
484 goto fail;
487 /* Trim the trailing \n */
488 thekey[strlen(line)-1]='\0';
493 else
495 fprintf(console,
496 "gpgkeys: this keyserver type only supports key retrieval\n");
497 goto fail;
500 if(!thekey || !opt->opaque)
502 fprintf(console,"gpgkeys: invalid keyserver instructions\n");
503 goto fail;
506 /* Send the response */
508 fprintf(output,"VERSION %d\n",KEYSERVER_PROTO_VERSION);
509 fprintf(output,"PROGRAM %s\n\n",VERSION);
511 if(opt->verbose>1)
513 fprintf(console,"User:\t\t%s\n",opt->opaque);
514 fprintf(console,"Command:\tGET\n");
517 set_timeout(opt->timeout);
519 ret=get_key(thekey);
521 fail:
523 free(thekey);
525 if(input!=stdin)
526 fclose(input);
528 if(output!=stdout)
529 fclose(output);
531 free_ks_options(opt);
533 return ret;