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,
36 #include <sys/types.h>
37 #include <sys/socket.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
45 #define INCLUDED_BY_MAIN_MODULE 1
47 #include "keyserver.h"
52 #define sock_close(a) closesocket(a)
54 #define sock_close(a) close(a)
60 static FILE *input
,*output
,*console
;
61 static struct ks_options
*opt
;
73 static int initialized
;
74 static WSADATA wsdata
;
79 if (WSAStartup (0x0101, &wsdata
) )
81 fprintf (console
, "error initializing socket library: ec=%d\n",
82 (int)WSAGetLastError () );
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
));
92 atexit (deinit_sockets
);
98 /* Connect to SERVER at PORT and return a file descriptor or -1 on
101 connect_server (const char *server
, unsigned short port
)
107 struct sockaddr_in addr
;
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",
128 if (hp
->h_length
!= 4)
130 fprintf (console
, "gpgkeys: illegal address length for `%s'\n",
134 memcpy (&addr
.sin_addr
, hp
->h_addr
, hp
->h_length
);
138 fprintf (console
, "gpgkeys: host `%s' not found: ec=%d\n",
139 server
, (int)WSAGetLastError ());
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 ());
151 if (connect (sock
, (struct sockaddr
*)&addr
, sizeof addr
))
153 fprintf (console
, "gpgkeys: error connecting `%s': ec=%d\n",
154 server
, (int)WSAGetLastError ());
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
);
169 fprintf (console
, "gpgkeys: host `%s' not found: %s\n",
170 server
, strerror (errno
));
174 addr
.sin_addr
= *(struct in_addr
*)host
->h_addr
;
176 sock
= socket (AF_INET
, SOCK_STREAM
, 0);
179 fprintf (console
, "gpgkeys: error creating socket: %s\n",
184 if (connect (sock
, (struct sockaddr
*)&addr
, sizeof addr
) == -1)
186 fprintf (console
, "gpgkeys: error connecting `%s': %s\n",
187 server
, strerror (errno
));
197 write_server (int sock
, const char *data
, size_t length
)
207 nwritten
= send (sock
, data
, nleft
, 0);
208 if ( nwritten
== SOCKET_ERROR
)
210 fprintf (console
, "gpgkeys: write failed: ec=%d\n",
211 (int)WSAGetLastError ());
215 nwritten
= write (sock
, data
, nleft
);
226 select(0, NULL
, NULL
, NULL
, &tv
);
229 fprintf (console
, "gpgkeys: write failed: %s\n", strerror(errno
));
241 /* Send the finger REQUEST to the server. Returns 0 and a file descriptor
242 in R_SOCK if the request was sucessful. */
244 send_request (const char *request
, int *r_sock
)
251 name
= strdup (request
);
254 fprintf(console
,"gpgkeys: out of memory\n");
255 return KEYSERVER_NO_MEMORY
;
258 server
= strchr (name
, '@');
261 fprintf (console
, "gpgkeys: no name included in request\n");
263 return KEYSERVER_GENERAL_ERROR
;
267 sock
= connect_server (server
, 79);
271 return KEYSERVER_UNREACHABLE
;
274 if (write_server (sock
, name
, strlen (name
))
275 || write_server (sock
, "\r\n", 2))
279 return KEYSERVER_GENERAL_ERROR
;
289 get_key (char *getkey
)
294 unsigned int maxlen
, buflen
, gotit
=0;
297 if (strncmp (getkey
,"0x",2)==0)
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
);
307 fprintf(output
,"KEY 0x%s FAILED %d\n",getkey
, rc
);
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");
317 fprintf(output
,"KEY 0x%s FAILED %d\n",getkey
, KEYSERVER_INTERNAL_ERROR
);
322 while ( iobuf_read_line ( fp_read
, &line
, &buflen
, &maxlen
))
328 print_nocr(output
, (const char*)line
);
329 if (!strncmp((char*)line
,END
,strlen(END
)))
332 else if(!strncmp((char*)line
,BEGIN
,strlen(BEGIN
)))
334 print_nocr(output
, (const char*)line
);
340 fprintf (output
,"KEY 0x%s END\n", getkey
);
343 fprintf(console
,"gpgkeys: no key data found for finger:%s\n",
345 fprintf(output
,"KEY 0x%s FAILED %d\n",getkey
,KEYSERVER_KEY_NOT_FOUND
);
349 iobuf_close (fp_read
);
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
;
372 /* Kludge to implement standard GNU options. */
373 if (argc
> 1 && !strcmp (argv
[1], "--version"))
375 fputs ("gpgkeys_finger (GnuPG) " VERSION
"\n", stdout
);
378 else if (argc
> 1 && !strcmp (argv
[1], "--help"))
384 while((arg
=getopt(argc
,argv
,"hVo:"))!=-1)
393 fprintf(stdout
,"%d\n%s\n",KEYSERVER_PROTO_VERSION
,VERSION
);
397 output
=fopen(optarg
,"w");
400 fprintf(console
,"gpgkeys: Cannot open output file `%s': %s\n",
401 optarg
,strerror(errno
));
402 return KEYSERVER_INTERNAL_ERROR
;
410 input
=fopen(argv
[optind
],"r");
413 fprintf(console
,"gpgkeys: Cannot open input file `%s': %s\n",
414 argv
[optind
],strerror(errno
));
415 return KEYSERVER_INTERNAL_ERROR
;
425 opt
=init_ks_options();
427 return KEYSERVER_NO_MEMORY
;
429 /* Get the command and info block */
431 while(fgets(line
,MAX_LINE
,input
)!=NULL
)
438 err
=parse_ks_options(line
,opt
);
450 fprintf(console
,"gpgkeys: finger://relay/user syntax is not"
451 " supported. Use finger:user instead.\n");
452 ret
=KEYSERVER_NOT_SUPPORTED
;
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 */
470 if(fgets(line
,MAX_LINE
,input
)==NULL
)
474 if(line
[0]=='\n' || line
[0]=='\0')
482 fprintf(console
,"gpgkeys: out of memory while "
483 "building key list\n");
484 ret
=KEYSERVER_NO_MEMORY
;
488 /* Trim the trailing \n */
489 thekey
[strlen(line
)-1]='\0';
497 "gpgkeys: this keyserver type only supports key retrieval\n");
501 if(!thekey
|| !opt
->opaque
)
503 fprintf(console
,"gpgkeys: invalid keyserver instructions\n");
507 /* Send the response */
509 fprintf(output
,"VERSION %d\n",KEYSERVER_PROTO_VERSION
);
510 fprintf(output
,"PROGRAM %s\n\n",VERSION
);
514 fprintf(console
,"User:\t\t%s\n",opt
->opaque
);
515 fprintf(console
,"Command:\tGET\n");
518 set_timeout(opt
->timeout
);
532 free_ks_options(opt
);