* gpgkeys_ftp.c (main, get_key): Use auth data as passed by gpg. Use
[gnupg.git] / keyserver / gpgkeys_ftp.c
1 /* gpgkeys_ftp.c - fetch a key via FTP
2  * Copyright (C) 2004 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 2 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, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <errno.h>
26 #include <unistd.h>
27 #ifdef HAVE_GETOPT_H
28 #include <getopt.h>
29 #endif
30 #include <curl/curl.h>
31 #include "keyserver.h"
32 #include "ksutil.h"
33
34 extern char *optarg;
35 extern int optind;
36
37 #define GET         0
38 #define MAX_LINE   80
39 #define MAX_PATH 1023
40 #define MAX_AUTH  127
41 #define MAX_HOST   79
42 #define MAX_PORT    9
43 #define MAX_URL (3+3+MAX_AUTH+1+MAX_HOST+1+1+MAX_PORT+1+1+MAX_PATH+1+50)
44
45 #define STRINGIFY(x) #x
46 #define MKSTRING(x) STRINGIFY(x)
47
48 static int verbose=0;
49 static char auth[MAX_AUTH+1],host[MAX_HOST+1]={'\0'},port[MAX_PORT+1]={'\0'},path[MAX_PATH+1]={'\0'};
50 static FILE *input=NULL,*output=NULL,*console=NULL;
51 static CURL *curl;
52 static char request[MAX_URL]={'\0'};
53
54 static int
55 get_key(char *getkey)
56 {
57   CURLcode res;
58   char errorbuffer[CURL_ERROR_SIZE];
59
60   if(strncmp(getkey,"0x",2)==0)
61     getkey+=2;
62
63   fprintf(output,"KEY 0x%s BEGIN\n",getkey);
64
65   sprintf(request,"ftp://%s%s%s%s%s%s%s",auth[0]?auth:"",auth[0]?"@":"",
66           host,port[0]?":":"",port[0]?port:"",path[0]?"":"/",path);
67
68   curl_easy_setopt(curl,CURLOPT_URL,request);
69   curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,fwrite);
70   curl_easy_setopt(curl,CURLOPT_FILE,output);
71   curl_easy_setopt(curl,CURLOPT_ERRORBUFFER,errorbuffer);
72
73   if(verbose>2)
74     {
75       curl_easy_setopt(curl,CURLOPT_STDERR,console);
76       curl_easy_setopt(curl,CURLOPT_VERBOSE,TRUE);
77     }
78
79   res=curl_easy_perform(curl);
80   if(res!=0)
81     {
82       fprintf(console,"gpgkeys: FTP fetch error %d: %s\n",res,errorbuffer);
83       fprintf(output,"KEY 0x%s FAILED %d\n",getkey,
84               (res==CURLE_FTP_COULDNT_RETR_FILE)?KEYSERVER_KEY_NOT_FOUND:
85               KEYSERVER_INTERNAL_ERROR);
86     }
87   else
88     fprintf(output,"KEY 0x%s END\n",getkey);
89
90   return KEYSERVER_OK;
91 }
92
93 static void 
94 show_help (FILE *fp)
95 {
96   fprintf (fp,"-h\thelp\n");
97   fprintf (fp,"-V\tversion\n");
98   fprintf (fp,"-o\toutput to this file\n");
99 }
100
101 int
102 main(int argc,char *argv[])
103 {
104   int arg,action=-1,ret=KEYSERVER_INTERNAL_ERROR;
105   char line[MAX_LINE];
106   char *thekey=NULL;
107   unsigned int timeout=DEFAULT_KEYSERVER_TIMEOUT;
108
109   console=stderr;
110
111   /* Kludge to implement standard GNU options.  */
112   if (argc > 1 && !strcmp (argv[1], "--version"))
113     {
114       fputs ("gpgkeys_ftp (GnuPG) " VERSION"\n", stdout);
115       return 0;
116     }
117   else if (argc > 1 && !strcmp (argv[1], "--help"))
118     {
119       show_help (stdout);
120       return 0;
121     }
122
123   while((arg=getopt(argc,argv,"hVo:"))!=-1)
124     switch(arg)
125       {
126       default:
127       case 'h':
128         show_help (console);
129         return KEYSERVER_OK;
130
131       case 'V':
132         fprintf(stdout,"%d\n%s\n",KEYSERVER_PROTO_VERSION,VERSION);
133         return KEYSERVER_OK;
134
135       case 'o':
136         output=fopen(optarg,"wb");
137         if(output==NULL)
138           {
139             fprintf(console,"gpgkeys: Cannot open output file `%s': %s\n",
140                     optarg,strerror(errno));
141             return KEYSERVER_INTERNAL_ERROR;
142           }
143
144         break;
145       }
146
147   if(argc>optind)
148     {
149       input=fopen(argv[optind],"r");
150       if(input==NULL)
151         {
152           fprintf(console,"gpgkeys: Cannot open input file `%s': %s\n",
153                   argv[optind],strerror(errno));
154           return KEYSERVER_INTERNAL_ERROR;
155         }
156     }
157
158   if(input==NULL)
159     input=stdin;
160
161   if(output==NULL)
162     output=stdout;
163
164   /* Get the command and info block */
165
166   while(fgets(line,MAX_LINE,input)!=NULL)
167     {
168       int version;
169       char commandstr[7];
170       char optionstr[256];
171       char hash;
172
173       if(line[0]=='\n')
174         break;
175
176       if(sscanf(line,"%c",&hash)==1 && hash=='#')
177         continue;
178
179       if(sscanf(line,"COMMAND %6s\n",commandstr)==1)
180         {
181           commandstr[6]='\0';
182
183           if(strcasecmp(commandstr,"get")==0)
184             action=GET;
185
186           continue;
187         }
188
189       if(sscanf(line,"AUTH %" MKSTRING(MAX_AUTH) "s\n",auth)==1)
190         {
191           host[MAX_AUTH]='\0';
192           continue;
193         }
194
195       if(sscanf(line,"HOST %" MKSTRING(MAX_HOST) "s\n",host)==1)
196         {
197           host[MAX_HOST]='\0';
198           continue;
199         }
200
201       if(sscanf(line,"PORT %" MKSTRING(MAX_PORT) "s\n",port)==1)
202         {
203           port[MAX_PORT]='\0';
204           continue;
205         }
206
207       if(sscanf(line,"PATH %" MKSTRING(MAX_PATH) "s\n",path)==1)
208         {
209           path[MAX_PATH]='\0';
210           continue;
211         }
212
213       if(sscanf(line,"VERSION %d\n",&version)==1)
214         {
215           if(version!=KEYSERVER_PROTO_VERSION)
216             {
217               ret=KEYSERVER_VERSION_ERROR;
218               goto fail;
219             }
220
221           continue;
222         }
223
224       if(sscanf(line,"OPTION %255s\n",optionstr)==1)
225         {
226           int no=0;
227           char *start=&optionstr[0];
228
229           optionstr[255]='\0';
230
231           if(strncasecmp(optionstr,"no-",3)==0)
232             {
233               no=1;
234               start=&optionstr[3];
235             }
236
237           if(strcasecmp(start,"verbose")==0)
238             {
239               if(no)
240                 verbose--;
241               else
242                 verbose++;
243             }
244           else if(strncasecmp(start,"timeout",7)==0)
245             {
246               if(no)
247                 timeout=0;
248               else
249                 timeout=atoi(&start[8]);
250             }
251
252           continue;
253         }
254     }
255
256   if(timeout && register_timeout()==-1)
257     {
258       fprintf(console,"gpgkeys: unable to register timeout handler\n");
259       return KEYSERVER_INTERNAL_ERROR;
260     }
261
262   curl_global_init(CURL_GLOBAL_DEFAULT);
263   curl=curl_easy_init();
264   if(!curl)
265     {
266       fprintf(console,"gpgkeys: unable to initialize curl\n");
267       ret=KEYSERVER_INTERNAL_ERROR;
268       goto fail;
269     }
270
271   /* If it's a GET or a SEARCH, the next thing to come in is the
272      keyids.  If it's a SEND, then there are no keyids. */
273
274   if(action==GET)
275     {
276       /* Eat the rest of the file */
277       for(;;)
278         {
279           if(fgets(line,MAX_LINE,input)==NULL)
280             break;
281           else
282             {
283               if(line[0]=='\n' || line[0]=='\0')
284                 break;
285
286               if(!thekey)
287                 {
288                   thekey=strdup(line);
289                   if(!thekey)
290                     {
291                       fprintf(console,"gpgkeys: out of memory while "
292                               "building key list\n");
293                       ret=KEYSERVER_NO_MEMORY;
294                       goto fail;
295                     }
296
297                   /* Trim the trailing \n */
298                   thekey[strlen(line)-1]='\0';
299                 }
300             }
301         }
302     }
303   else
304     {
305       fprintf(console,
306               "gpgkeys: this keyserver type only supports key retrieval\n");
307       goto fail;
308     }
309
310   if(!thekey || !host[0])
311     {
312       fprintf(console,"gpgkeys: invalid keyserver instructions\n");
313       goto fail;
314     }
315
316   /* Send the response */
317
318   fprintf(output,"VERSION %d\n",KEYSERVER_PROTO_VERSION);
319   fprintf(output,"PROGRAM %s\n\n",VERSION);
320
321   if(verbose>1)
322     {
323       fprintf(console,"Host:\t\t%s\n",host);
324       if(port[0])
325         fprintf(console,"Port:\t\t%s\n",port);
326       if(path[0])
327         fprintf(console,"Path:\t\t%s\n",path);
328       fprintf(console,"Command:\tGET\n");
329     }
330
331   set_timeout(timeout);
332
333   ret=get_key(thekey);
334
335   curl_easy_cleanup(curl);
336
337  fail:
338
339   free(thekey);
340
341   if(input!=stdin)
342     fclose(input);
343
344   if(output!=stdout)
345     fclose(output);
346
347   curl_global_cleanup();
348
349   return ret;
350 }