* ksutil.c (curl_err_to_gpg_err): Add CURLE_OK and CURLE_COULDNT_CONNECT.
[gnupg.git] / keyserver / ksutil.c
1 /* ksutil.c - general keyserver utility functions
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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19  * USA.
20  */
21
22 #include <config.h>
23 #include <signal.h>
24 #include <unistd.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28
29 #ifdef HAVE_LIBCURL
30 #include <curl/curl.h>
31 #else
32 #ifdef FAKE_CURL
33 #include "curl-shim.h"
34 #endif
35 #endif
36 #include "keyserver.h"
37 #include "ksutil.h"
38
39 #ifdef HAVE_DOSISH_SYSTEM
40
41 unsigned int set_timeout(unsigned int seconds) {return 0;}
42 int register_timeout(void) {return 0;}
43
44 #else
45
46 static void
47 catch_alarm(int foo)
48 {
49   (void)foo;
50   _exit(KEYSERVER_TIMEOUT);
51 }
52
53 unsigned int
54 set_timeout(unsigned int seconds)
55 {
56   return alarm(seconds);
57 }
58
59 int
60 register_timeout(void)
61 {
62 #if defined(HAVE_SIGACTION) && defined(HAVE_STRUCT_SIGACTION)
63   struct sigaction act;
64
65   act.sa_handler=catch_alarm;
66   sigemptyset(&act.sa_mask);
67   act.sa_flags=0;
68   return sigaction(SIGALRM,&act,NULL);
69 #else 
70   if(signal(SIGALRM,catch_alarm)==SIG_ERR)
71     return -1;
72   else
73     return 0;
74 #endif
75 }
76
77 #endif /* !HAVE_DOSISH_SYSTEM */
78
79 struct ks_options *
80 init_ks_options(void)
81 {
82   struct ks_options *opt;
83
84   opt=calloc(1,sizeof(struct ks_options));
85
86   if(opt)
87     {
88       opt->action=KS_UNKNOWN;
89       opt->flags.check_cert=1;
90       opt->timeout=DEFAULT_KEYSERVER_TIMEOUT;
91       opt->path=strdup("/");
92       if(!opt->path)
93         {
94           free(opt);
95           opt=NULL;
96         }
97     }
98
99   return opt;
100 }
101
102 void
103 free_ks_options(struct ks_options *opt)
104 {
105   if(opt)
106     {
107       free(opt->host);
108       free(opt->port);
109       free(opt->scheme);
110       free(opt->auth);
111       free(opt->path);
112       free(opt->opaque);
113       free(opt->ca_cert_file);
114       free(opt);
115     }
116 }
117
118 /* Returns 0 if we "ate" the line.  Returns >0, a KEYSERVER_ error
119    code if that error applies.  Returns -1 if we did not match the
120    line at all. */
121 int
122 parse_ks_options(char *line,struct ks_options *opt)
123 {
124   int version;
125   char command[MAX_COMMAND+1];
126   char host[MAX_HOST+1];
127   char port[MAX_PORT+1];
128   char scheme[MAX_SCHEME+1];
129   char auth[MAX_AUTH+1];
130   char path[URLMAX_PATH+1];
131   char opaque[MAX_OPAQUE+1];
132   char option[MAX_OPTION+1];
133
134   if(line[0]=='#')
135     return 0;
136
137   if(sscanf(line,"COMMAND %" MKSTRING(MAX_COMMAND) "s\n",command)==1)
138     {
139       command[MAX_COMMAND]='\0';
140
141       if(strcasecmp(command,"get")==0)
142         opt->action=KS_GET;
143       else if(strcasecmp(command,"send")==0)
144         opt->action=KS_SEND;
145       else if(strcasecmp(command,"search")==0)
146         opt->action=KS_SEARCH;
147
148       return 0;
149     }
150
151   if(sscanf(line,"HOST %" MKSTRING(MAX_HOST) "s\n",host)==1)
152     {
153       host[MAX_HOST]='\0';
154       free(opt->host);
155       opt->host=strdup(host);
156       if(!opt->host)
157         return KEYSERVER_NO_MEMORY;
158       return 0;
159     }
160
161   if(sscanf(line,"PORT %" MKSTRING(MAX_PORT) "s\n",port)==1)
162     {
163       port[MAX_PORT]='\0';
164       free(opt->port);
165       opt->port=strdup(port);
166       if(!opt->port)
167         return KEYSERVER_NO_MEMORY;
168       return 0;
169     }
170
171   if(sscanf(line,"SCHEME %" MKSTRING(MAX_SCHEME) "s\n",scheme)==1)
172     {
173       scheme[MAX_SCHEME]='\0';
174       free(opt->scheme);
175       opt->scheme=strdup(scheme);
176       if(!opt->scheme)
177         return KEYSERVER_NO_MEMORY;
178       return 0;
179     }
180
181   if(sscanf(line,"AUTH %" MKSTRING(MAX_AUTH) "s\n",auth)==1)
182     {
183       auth[MAX_AUTH]='\0';
184       free(opt->auth);
185       opt->auth=strdup(auth);
186       if(!opt->auth)
187         return KEYSERVER_NO_MEMORY;
188       return 0;
189     }
190
191   if(sscanf(line,"PATH %" MKSTRING(URLMAX_PATH) "s\n",path)==1)
192     {
193       path[URLMAX_PATH]='\0';
194       free(opt->path);
195       opt->path=strdup(path);
196       if(!opt->path)
197         return KEYSERVER_NO_MEMORY;
198       return 0;
199     }
200
201   if(sscanf(line,"OPAQUE %" MKSTRING(MAX_OPAQUE) "s\n",opaque)==1)
202     {
203       opaque[MAX_OPAQUE]='\0';
204       free(opt->opaque);
205       opt->opaque=strdup(opaque);
206       if(!opt->opaque)
207         return KEYSERVER_NO_MEMORY;
208       return 0;
209     }
210
211   if(sscanf(line,"VERSION %d\n",&version)==1)
212     {
213       if(version!=KEYSERVER_PROTO_VERSION)
214         return KEYSERVER_VERSION_ERROR;
215
216       return 0;
217     }
218
219   if(sscanf(line,"OPTION %" MKSTRING(MAX_OPTION) "[^\n]\n",option)==1)
220     {
221       int no=0;
222       char *start=&option[0];
223
224       option[MAX_OPTION]='\0';
225
226       if(strncasecmp(option,"no-",3)==0)
227         {
228           no=1;
229           start=&option[3];
230         }
231
232       if(strncasecmp(start,"verbose",7)==0)
233         {
234           if(no)
235             opt->verbose=0;
236           else if(start[7]=='=')
237             opt->verbose=atoi(&start[8]);
238           else
239             opt->verbose++;
240         }
241       else if(strcasecmp(start,"include-disabled")==0)
242         {
243           if(no)
244             opt->flags.include_disabled=0;
245           else
246             opt->flags.include_disabled=1;
247         }
248       else if(strcasecmp(start,"include-revoked")==0)
249         {
250           if(no)
251             opt->flags.include_revoked=0;
252           else
253             opt->flags.include_revoked=1;
254         }
255       else if(strcasecmp(start,"include-subkeys")==0)
256         {
257           if(no)
258             opt->flags.include_subkeys=0;
259           else
260             opt->flags.include_subkeys=1;
261         }
262       else if(strcasecmp(start,"check-cert")==0)
263         {
264           if(no)
265             opt->flags.check_cert=0;
266           else
267             opt->flags.check_cert=1;
268         }
269       else if(strncasecmp(start,"debug",5)==0)
270         {
271           if(no)
272             opt->debug=0;
273           else if(start[5]=='=')
274             opt->debug=atoi(&start[6]);
275           else if(start[5]=='\0')
276             opt->debug=1;
277         }
278       else if(strncasecmp(start,"timeout",7)==0)
279         {
280           if(no)
281             opt->timeout=0;
282           else if(start[7]=='=')
283             opt->timeout=atoi(&start[8]);
284           else if(start[7]=='\0')
285             opt->timeout=DEFAULT_KEYSERVER_TIMEOUT;
286         }
287       else if(strncasecmp(start,"ca-cert-file",12)==0)
288         {
289           if(no)
290             {
291               free(opt->ca_cert_file);
292               opt->ca_cert_file=NULL;
293             }
294           else if(start[12]=='=')
295             {
296               free(opt->ca_cert_file);
297               opt->ca_cert_file=strdup(&start[13]);
298               if(!opt->ca_cert_file)
299                 return KEYSERVER_NO_MEMORY;
300             }
301         }
302     }
303
304   return -1;
305 }
306
307 const char *
308 ks_action_to_string(enum ks_action action)
309 {
310   switch(action)
311     {
312     case KS_UNKNOWN: return "UNKNOWN";
313     case KS_GET:     return "GET";
314     case KS_SEND:    return "SEND";
315     case KS_SEARCH:  return "SEARCH";
316     }
317
318   return "?";
319 }
320
321 /* Canonicalize CRLF to just LF by stripping CRs.  This actually makes
322    sense, since on Unix-like machines LF is correct, and on win32-like
323    machines, our output buffer is opened in textmode and will
324    re-canonicalize line endings back to CRLF.  Since we only need to
325    handle armored keys, we don't have to worry about odd cases like
326    CRCRCR and the like. */
327
328 void
329 print_nocr(FILE *stream,const char *str)
330 {
331   while(*str)
332     {
333       if(*str!='\r')
334         fputc(*str,stream);
335       str++;
336     }
337 }
338
339 enum ks_search_type
340 classify_ks_search(const char **search)
341 {
342   switch(**search)
343     {
344     default:
345       return KS_SEARCH_SUBSTR;
346     case '*':
347       (*search)++;
348       return KS_SEARCH_SUBSTR;
349     case '=':
350       (*search)++;
351       return KS_SEARCH_EXACT;
352     case '<':
353       return KS_SEARCH_MAIL;
354     case '@':
355       (*search)++;
356       return KS_SEARCH_MAILSUB;
357     }
358 }
359
360 #if defined (HAVE_LIBCURL) || defined (FAKE_CURL)
361 int
362 curl_err_to_gpg_err(CURLcode error)
363 {
364   switch(error)
365     {
366     case CURLE_OK:                    return KEYSERVER_OK;
367     case CURLE_UNSUPPORTED_PROTOCOL:  return KEYSERVER_SCHEME_NOT_FOUND;
368     case CURLE_COULDNT_CONNECT:       return KEYSERVER_UNREACHABLE;
369     case CURLE_FTP_COULDNT_RETR_FILE: return KEYSERVER_KEY_NOT_FOUND;
370     default: return KEYSERVER_INTERNAL_ERROR;
371     }
372 }
373
374 size_t
375 curl_writer(const void *ptr,size_t size,size_t nmemb,void *cw_ctx)
376 {
377   struct curl_writer_ctx *ctx=cw_ctx;
378   const char *buf=ptr;
379   size_t i;
380
381   if(!ctx->initialized)
382     {
383       ctx->marker=BEGIN;
384       ctx->initialized=1;
385     }
386
387   /* scan the incoming data for our marker */
388   for(i=0;!ctx->done && i<(size*nmemb);i++)
389     {
390       if(buf[i]==ctx->marker[ctx->markeridx])
391         {
392           ctx->markeridx++;
393           if(ctx->marker[ctx->markeridx]=='\0')
394             {
395               if(ctx->begun)
396                 ctx->done=1;
397               else
398                 {
399                   /* We've found the BEGIN marker, so now we're looking
400                      for the END marker. */
401                   ctx->begun=1;
402                   ctx->marker=END;
403                   ctx->markeridx=0;
404                   fprintf(ctx->stream,BEGIN);
405                   continue;
406                 }
407             }
408         }
409       else
410         ctx->markeridx=0;
411
412       if(ctx->begun)
413         {
414           /* Canonicalize CRLF to just LF by stripping CRs.  This
415              actually makes sense, since on Unix-like machines LF is
416              correct, and on win32-like machines, our output buffer is
417              opened in textmode and will re-canonicalize line endings
418              back to CRLF.  Since we only need to handle armored keys,
419              we don't have to worry about odd cases like CRCRCR and
420              the like. */
421
422           if(buf[i]!='\r')
423             fputc(buf[i],ctx->stream);
424         }
425     }
426
427   return size*nmemb;
428 }
429 #endif