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