Added keyserver directory from trunk
[gnupg.git] / keyserver / ksutil.c
1 /* ksutil.c - general keyserver utility functions
2  * Copyright (C) 2004, 2005, 2006 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 #include "curl-shim.h"
33 #endif
34 #include "keyserver.h"
35 #include "ksutil.h"
36
37 #ifdef HAVE_DOSISH_SYSTEM
38
39 unsigned int set_timeout(unsigned int seconds) {return 0;}
40 int register_timeout(void) {return 0;}
41
42 #else
43
44 static void
45 catch_alarm(int foo)
46 {
47   (void)foo;
48   _exit(KEYSERVER_TIMEOUT);
49 }
50
51 unsigned int
52 set_timeout(unsigned int seconds)
53 {
54   return alarm(seconds);
55 }
56
57 int
58 register_timeout(void)
59 {
60 #if defined(HAVE_SIGACTION) && defined(HAVE_STRUCT_SIGACTION)
61   struct sigaction act;
62
63   act.sa_handler=catch_alarm;
64   sigemptyset(&act.sa_mask);
65   act.sa_flags=0;
66   return sigaction(SIGALRM,&act,NULL);
67 #else 
68   if(signal(SIGALRM,catch_alarm)==SIG_ERR)
69     return -1;
70   else
71     return 0;
72 #endif
73 }
74
75 #endif /* !HAVE_DOSISH_SYSTEM */
76
77 struct ks_options *
78 init_ks_options(void)
79 {
80   struct ks_options *opt;
81
82   opt=calloc(1,sizeof(struct ks_options));
83
84   if(opt)
85     {
86       opt->action=KS_UNKNOWN;
87       opt->flags.include_revoked=1;
88       opt->flags.include_subkeys=1;
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,"getname")==0)
144         opt->action=KS_GETNAME;
145       else if(strcasecmp(command,"send")==0)
146         opt->action=KS_SEND;
147       else if(strcasecmp(command,"search")==0)
148         opt->action=KS_SEARCH;
149
150       return 0;
151     }
152
153   if(sscanf(line,"HOST %" MKSTRING(MAX_HOST) "s\n",host)==1)
154     {
155       host[MAX_HOST]='\0';
156       free(opt->host);
157       opt->host=strdup(host);
158       if(!opt->host)
159         return KEYSERVER_NO_MEMORY;
160       return 0;
161     }
162
163   if(sscanf(line,"PORT %" MKSTRING(MAX_PORT) "s\n",port)==1)
164     {
165       port[MAX_PORT]='\0';
166       free(opt->port);
167       opt->port=strdup(port);
168       if(!opt->port)
169         return KEYSERVER_NO_MEMORY;
170       return 0;
171     }
172
173   if(sscanf(line,"SCHEME %" MKSTRING(MAX_SCHEME) "s\n",scheme)==1)
174     {
175       scheme[MAX_SCHEME]='\0';
176       free(opt->scheme);
177       opt->scheme=strdup(scheme);
178       if(!opt->scheme)
179         return KEYSERVER_NO_MEMORY;
180       return 0;
181     }
182
183   if(sscanf(line,"AUTH %" MKSTRING(MAX_AUTH) "s\n",auth)==1)
184     {
185       auth[MAX_AUTH]='\0';
186       free(opt->auth);
187       opt->auth=strdup(auth);
188       if(!opt->auth)
189         return KEYSERVER_NO_MEMORY;
190       return 0;
191     }
192
193   if(sscanf(line,"PATH %" MKSTRING(URLMAX_PATH) "s\n",path)==1)
194     {
195       path[URLMAX_PATH]='\0';
196       free(opt->path);
197       opt->path=strdup(path);
198       if(!opt->path)
199         return KEYSERVER_NO_MEMORY;
200       return 0;
201     }
202
203   if(sscanf(line,"OPAQUE %" MKSTRING(MAX_OPAQUE) "s\n",opaque)==1)
204     {
205       opaque[MAX_OPAQUE]='\0';
206       free(opt->opaque);
207       opt->opaque=strdup(opaque);
208       if(!opt->opaque)
209         return KEYSERVER_NO_MEMORY;
210       return 0;
211     }
212
213   if(sscanf(line,"VERSION %d\n",&version)==1)
214     {
215       if(version!=KEYSERVER_PROTO_VERSION)
216         return KEYSERVER_VERSION_ERROR;
217
218       return 0;
219     }
220
221   if(sscanf(line,"OPTION %" MKSTRING(MAX_OPTION) "[^\n]\n",option)==1)
222     {
223       int no=0;
224       char *start=&option[0];
225
226       option[MAX_OPTION]='\0';
227
228       if(strncasecmp(option,"no-",3)==0)
229         {
230           no=1;
231           start=&option[3];
232         }
233
234       if(strncasecmp(start,"verbose",7)==0)
235         {
236           if(no)
237             opt->verbose=0;
238           else if(start[7]=='=')
239             opt->verbose=atoi(&start[8]);
240           else
241             opt->verbose++;
242         }
243       else if(strcasecmp(start,"include-disabled")==0)
244         {
245           if(no)
246             opt->flags.include_disabled=0;
247           else
248             opt->flags.include_disabled=1;
249         }
250       else if(strcasecmp(start,"include-revoked")==0)
251         {
252           if(no)
253             opt->flags.include_revoked=0;
254           else
255             opt->flags.include_revoked=1;
256         }
257       else if(strcasecmp(start,"include-subkeys")==0)
258         {
259           if(no)
260             opt->flags.include_subkeys=0;
261           else
262             opt->flags.include_subkeys=1;
263         }
264       else if(strcasecmp(start,"check-cert")==0)
265         {
266           if(no)
267             opt->flags.check_cert=0;
268           else
269             opt->flags.check_cert=1;
270         }
271       else if(strncasecmp(start,"debug",5)==0)
272         {
273           if(no)
274             opt->debug=0;
275           else if(start[5]=='=')
276             opt->debug=atoi(&start[6]);
277           else if(start[5]=='\0')
278             opt->debug=1;
279         }
280       else if(strncasecmp(start,"timeout",7)==0)
281         {
282           if(no)
283             opt->timeout=0;
284           else if(start[7]=='=')
285             opt->timeout=atoi(&start[8]);
286           else if(start[7]=='\0')
287             opt->timeout=DEFAULT_KEYSERVER_TIMEOUT;
288         }
289       else if(strncasecmp(start,"ca-cert-file",12)==0)
290         {
291           if(no)
292             {
293               free(opt->ca_cert_file);
294               opt->ca_cert_file=NULL;
295             }
296           else if(start[12]=='=')
297             {
298               free(opt->ca_cert_file);
299               opt->ca_cert_file=strdup(&start[13]);
300               if(!opt->ca_cert_file)
301                 return KEYSERVER_NO_MEMORY;
302             }
303         }
304     }
305
306   return -1;
307 }
308
309 const char *
310 ks_action_to_string(enum ks_action action)
311 {
312   switch(action)
313     {
314     case KS_UNKNOWN: return "UNKNOWN";
315     case KS_GET:     return "GET";
316     case KS_GETNAME: return "GETNAME";
317     case KS_SEND:    return "SEND";
318     case KS_SEARCH:  return "SEARCH";
319     }
320
321   return "?";
322 }
323
324 /* Canonicalize CRLF to just LF by stripping CRs.  This actually makes
325    sense, since on Unix-like machines LF is correct, and on win32-like
326    machines, our output buffer is opened in textmode and will
327    re-canonicalize line endings back to CRLF.  Since we only need to
328    handle armored keys, we don't have to worry about odd cases like
329    CRCRCR and the like. */
330
331 void
332 print_nocr(FILE *stream,const char *str)
333 {
334   while(*str)
335     {
336       if(*str!='\r')
337         fputc(*str,stream);
338       str++;
339     }
340 }
341
342 enum ks_search_type
343 classify_ks_search(const char **search)
344 {
345   switch(**search)
346     {
347     case '*':
348       (*search)++;
349       return KS_SEARCH_SUBSTR;
350     case '=':
351       (*search)++;
352       return KS_SEARCH_EXACT;
353     case '<':
354       (*search)++;
355       return KS_SEARCH_MAIL;
356     case '@':
357       (*search)++;
358       return KS_SEARCH_MAILSUB;
359     case '0':
360       if((*search)[1]=='x')
361         {
362           if(strlen(*search)==10
363              && strspn(*search,"abcdefABCDEF1234567890x")==10)
364             {
365               (*search)+=2;
366               return KS_SEARCH_KEYID_SHORT;
367             }
368           else if(strlen(*search)==18
369                   && strspn(*search,"abcdefABCDEF1234567890x")==18)
370             {
371               (*search)+=2;
372               return KS_SEARCH_KEYID_LONG;
373             }
374         }
375       /* fall through */
376     default:
377       return KS_SEARCH_SUBSTR;
378     }
379 }
380
381 int
382 curl_err_to_gpg_err(CURLcode error)
383 {
384   switch(error)
385     {
386     case CURLE_OK:                    return KEYSERVER_OK;
387     case CURLE_UNSUPPORTED_PROTOCOL:  return KEYSERVER_SCHEME_NOT_FOUND;
388     case CURLE_COULDNT_CONNECT:       return KEYSERVER_UNREACHABLE;
389     case CURLE_FTP_COULDNT_RETR_FILE: return KEYSERVER_KEY_NOT_FOUND;
390     default: return KEYSERVER_INTERNAL_ERROR;
391     }
392 }
393
394 #define B64 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
395
396 static void
397 curl_armor_writer(const unsigned char *buf,size_t size,void *cw_ctx)
398 {
399   struct curl_writer_ctx *ctx=cw_ctx;
400   size_t idx=0;
401
402   while(idx<size)
403     {
404       for(;ctx->armor_remaining<3 && idx<size;ctx->armor_remaining++,idx++)
405         ctx->armor_ctx[ctx->armor_remaining]=buf[idx];
406
407       if(ctx->armor_remaining==3)
408         {
409           /* Top 6 bytes of ctx->armor_ctx[0] */
410           fputc(B64[(ctx->armor_ctx[0]>>2)&0x3F],ctx->stream);
411           /* Bottom 2 bytes of ctx->armor_ctx[0] and top 4 bytes of
412              ctx->armor_ctx[1] */
413           fputc(B64[(((ctx->armor_ctx[0]<<4)&0x30)
414                      |((ctx->armor_ctx[1]>>4)&0x0F))&0x3F],ctx->stream);
415           /* Bottom 4 bytes of ctx->armor_ctx[1] and top 2 bytes of
416              ctx->armor_ctx[2] */
417           fputc(B64[(((ctx->armor_ctx[1]<<2)&0x3C)
418                      |((ctx->armor_ctx[2]>>6)&0x03))&0x3F],ctx->stream);
419           /* Bottom 6 bytes of ctx->armor_ctx[2] */
420           fputc(B64[(ctx->armor_ctx[2]&0x3F)],ctx->stream);
421
422           ctx->linelen+=4;
423           if(ctx->linelen>=70)
424             {
425               fputc('\n',ctx->stream);
426               ctx->linelen=0;
427             }
428
429           ctx->armor_remaining=0;
430         }
431     }
432
433 }
434
435 size_t
436 curl_writer(const void *ptr,size_t size,size_t nmemb,void *cw_ctx)
437 {
438   struct curl_writer_ctx *ctx=cw_ctx;
439   const char *buf=ptr;
440   size_t i;
441
442   if(!ctx->flags.initialized)
443     {
444       if(size*nmemb==0)
445         return 0;
446
447       /* The object we're fetching is in binary form */
448       if(*buf&0x80)
449         {
450           ctx->flags.armor=1;
451           fprintf(ctx->stream,BEGIN"\n\n");
452         }
453       else
454         ctx->marker=BEGIN;
455
456       ctx->flags.initialized=1;
457     }
458
459   if(ctx->flags.armor)
460     curl_armor_writer(ptr,size*nmemb,cw_ctx);
461   else
462     {
463       /* scan the incoming data for our marker */
464       for(i=0;!ctx->flags.done && i<(size*nmemb);i++)
465         {
466           if(buf[i]==ctx->marker[ctx->markeridx])
467             {
468               ctx->markeridx++;
469               if(ctx->marker[ctx->markeridx]=='\0')
470                 {
471                   if(ctx->flags.begun)
472                     ctx->flags.done=1;
473                   else
474                     {
475                       /* We've found the BEGIN marker, so now we're
476                          looking for the END marker. */
477                       ctx->flags.begun=1;
478                       ctx->marker=END;
479                       ctx->markeridx=0;
480                       fprintf(ctx->stream,BEGIN);
481                       continue;
482                     }
483                 }
484             }
485           else
486             ctx->markeridx=0;
487
488           if(ctx->flags.begun)
489             {
490               /* Canonicalize CRLF to just LF by stripping CRs.  This
491                  actually makes sense, since on Unix-like machines LF
492                  is correct, and on win32-like machines, our output
493                  buffer is opened in textmode and will re-canonicalize
494                  line endings back to CRLF.  Since this code is just
495                  for handling armored keys, we don't have to worry
496                  about odd cases like CRCRCR and the like. */
497
498               if(buf[i]!='\r')
499                 fputc(buf[i],ctx->stream);
500             }
501         }
502     }
503
504   return size*nmemb;
505 }
506
507 void
508 curl_writer_finalize(struct curl_writer_ctx *ctx)
509 {
510   if(ctx->flags.armor)
511     {
512       if(ctx->armor_remaining==2)
513         {
514           /* Top 6 bytes of ctx->armorctx[0] */
515           fputc(B64[(ctx->armor_ctx[0]>>2)&0x3F],ctx->stream);
516           /* Bottom 2 bytes of ctx->armor_ctx[0] and top 4 bytes of
517              ctx->armor_ctx[1] */
518           fputc(B64[(((ctx->armor_ctx[0]<<4)&0x30)
519                      |((ctx->armor_ctx[1]>>4)&0x0F))&0x3F],ctx->stream);
520           /* Bottom 4 bytes of ctx->armor_ctx[1] */
521           fputc(B64[((ctx->armor_ctx[1]<<2)&0x3C)],ctx->stream);
522           /* Pad */
523           fputc('=',ctx->stream);
524         }
525       else if(ctx->armor_remaining==1)
526         {
527           /* Top 6 bytes of ctx->armor_ctx[0] */
528           fputc(B64[(ctx->armor_ctx[0]>>2)&0x3F],ctx->stream);
529           /* Bottom 2 bytes of ctx->armor_ctx[0] */
530           fputc(B64[((ctx->armor_ctx[0]<<4)&0x30)],ctx->stream);
531           /* Pad */
532           fputc('=',ctx->stream);
533           /* Pad */
534           fputc('=',ctx->stream);
535         }
536
537       fprintf(ctx->stream,"\n"END);
538       ctx->flags.done=1;
539     }
540 }