23dbc8f07b64b4574733c8ecb49a72ac4629e84c
[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  * In addition, as a special exception, the Free Software Foundation
22  * gives permission to link the code of the keyserver helper tools:
23  * gpgkeys_ldap, gpgkeys_curl and gpgkeys_hkp with the OpenSSL
24  * project's "OpenSSL" library (or with modified versions of it that
25  * use the same license as the "OpenSSL" library), and distribute the
26  * linked executables.  You must obey the GNU General Public License
27  * in all respects for all of the code used other than "OpenSSL".  If
28  * you modify this file, you may extend this exception to your version
29  * of the file, but you are not obligated to do so.  If you do not
30  * wish to do so, delete this exception statement from your version.
31  */
32
33 #include <config.h>
34 #include <signal.h>
35 #include <unistd.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <stdlib.h>
39
40 #ifdef HAVE_LIBCURL
41 #include <curl/curl.h>
42 #else
43 #include "curl-shim.h"
44 #endif
45 #include "keyserver.h"
46 #include "ksutil.h"
47
48 #ifdef HAVE_DOSISH_SYSTEM
49
50 unsigned int set_timeout(unsigned int seconds) {return 0;}
51 int register_timeout(void) {return 0;}
52
53 #else
54
55 static void
56 catch_alarm(int foo)
57 {
58   (void)foo;
59   _exit(KEYSERVER_TIMEOUT);
60 }
61
62 unsigned int
63 set_timeout(unsigned int seconds)
64 {
65   return alarm(seconds);
66 }
67
68 int
69 register_timeout(void)
70 {
71 #if defined(HAVE_SIGACTION) && defined(HAVE_STRUCT_SIGACTION)
72   struct sigaction act;
73
74   act.sa_handler=catch_alarm;
75   sigemptyset(&act.sa_mask);
76   act.sa_flags=0;
77   return sigaction(SIGALRM,&act,NULL);
78 #else 
79   if(signal(SIGALRM,catch_alarm)==SIG_ERR)
80     return -1;
81   else
82     return 0;
83 #endif
84 }
85
86 #endif /* !HAVE_DOSISH_SYSTEM */
87
88 struct ks_options *
89 init_ks_options(void)
90 {
91   struct ks_options *opt;
92
93   opt=calloc(1,sizeof(struct ks_options));
94
95   if(opt)
96     {
97       opt->action=KS_UNKNOWN;
98       opt->flags.include_revoked=1;
99       opt->flags.include_subkeys=1;
100       opt->flags.check_cert=1;
101       opt->timeout=DEFAULT_KEYSERVER_TIMEOUT;
102       opt->path=strdup("/");
103       if(!opt->path)
104         {
105           free(opt);
106           opt=NULL;
107         }
108     }
109
110   return opt;
111 }
112
113 void
114 free_ks_options(struct ks_options *opt)
115 {
116   if(opt)
117     {
118       free(opt->host);
119       free(opt->port);
120       free(opt->scheme);
121       free(opt->auth);
122       free(opt->path);
123       free(opt->opaque);
124       free(opt->ca_cert_file);
125       free(opt);
126     }
127 }
128
129 /* Returns 0 if we "ate" the line.  Returns >0, a KEYSERVER_ error
130    code if that error applies.  Returns -1 if we did not match the
131    line at all. */
132 int
133 parse_ks_options(char *line,struct ks_options *opt)
134 {
135   int version;
136   char command[MAX_COMMAND+1];
137   char host[MAX_HOST+1];
138   char port[MAX_PORT+1];
139   char scheme[MAX_SCHEME+1];
140   char auth[MAX_AUTH+1];
141   char path[URLMAX_PATH+1];
142   char opaque[MAX_OPAQUE+1];
143   char option[MAX_OPTION+1];
144
145   if(line[0]=='#')
146     return 0;
147
148   if(sscanf(line,"COMMAND %" MKSTRING(MAX_COMMAND) "s\n",command)==1)
149     {
150       command[MAX_COMMAND]='\0';
151
152       if(strcasecmp(command,"get")==0)
153         opt->action=KS_GET;
154       else if(strcasecmp(command,"getname")==0)
155         opt->action=KS_GETNAME;
156       else if(strcasecmp(command,"send")==0)
157         opt->action=KS_SEND;
158       else if(strcasecmp(command,"search")==0)
159         opt->action=KS_SEARCH;
160
161       return 0;
162     }
163
164   if(sscanf(line,"HOST %" MKSTRING(MAX_HOST) "s\n",host)==1)
165     {
166       host[MAX_HOST]='\0';
167       free(opt->host);
168       opt->host=strdup(host);
169       if(!opt->host)
170         return KEYSERVER_NO_MEMORY;
171       return 0;
172     }
173
174   if(sscanf(line,"PORT %" MKSTRING(MAX_PORT) "s\n",port)==1)
175     {
176       port[MAX_PORT]='\0';
177       free(opt->port);
178       opt->port=strdup(port);
179       if(!opt->port)
180         return KEYSERVER_NO_MEMORY;
181       return 0;
182     }
183
184   if(sscanf(line,"SCHEME %" MKSTRING(MAX_SCHEME) "s\n",scheme)==1)
185     {
186       scheme[MAX_SCHEME]='\0';
187       free(opt->scheme);
188       opt->scheme=strdup(scheme);
189       if(!opt->scheme)
190         return KEYSERVER_NO_MEMORY;
191       return 0;
192     }
193
194   if(sscanf(line,"AUTH %" MKSTRING(MAX_AUTH) "s\n",auth)==1)
195     {
196       auth[MAX_AUTH]='\0';
197       free(opt->auth);
198       opt->auth=strdup(auth);
199       if(!opt->auth)
200         return KEYSERVER_NO_MEMORY;
201       return 0;
202     }
203
204   if(sscanf(line,"PATH %" MKSTRING(URLMAX_PATH) "s\n",path)==1)
205     {
206       path[URLMAX_PATH]='\0';
207       free(opt->path);
208       opt->path=strdup(path);
209       if(!opt->path)
210         return KEYSERVER_NO_MEMORY;
211       return 0;
212     }
213
214   if(sscanf(line,"OPAQUE %" MKSTRING(MAX_OPAQUE) "s\n",opaque)==1)
215     {
216       opaque[MAX_OPAQUE]='\0';
217       free(opt->opaque);
218       opt->opaque=strdup(opaque);
219       if(!opt->opaque)
220         return KEYSERVER_NO_MEMORY;
221       return 0;
222     }
223
224   if(sscanf(line,"VERSION %d\n",&version)==1)
225     {
226       if(version!=KEYSERVER_PROTO_VERSION)
227         return KEYSERVER_VERSION_ERROR;
228
229       return 0;
230     }
231
232   if(sscanf(line,"OPTION %" MKSTRING(MAX_OPTION) "[^\n]\n",option)==1)
233     {
234       int no=0;
235       char *start=&option[0];
236
237       option[MAX_OPTION]='\0';
238
239       if(strncasecmp(option,"no-",3)==0)
240         {
241           no=1;
242           start=&option[3];
243         }
244
245       if(strncasecmp(start,"verbose",7)==0)
246         {
247           if(no)
248             opt->verbose=0;
249           else if(start[7]=='=')
250             opt->verbose=atoi(&start[8]);
251           else
252             opt->verbose++;
253         }
254       else if(strcasecmp(start,"include-disabled")==0)
255         {
256           if(no)
257             opt->flags.include_disabled=0;
258           else
259             opt->flags.include_disabled=1;
260         }
261       else if(strcasecmp(start,"include-revoked")==0)
262         {
263           if(no)
264             opt->flags.include_revoked=0;
265           else
266             opt->flags.include_revoked=1;
267         }
268       else if(strcasecmp(start,"include-subkeys")==0)
269         {
270           if(no)
271             opt->flags.include_subkeys=0;
272           else
273             opt->flags.include_subkeys=1;
274         }
275       else if(strcasecmp(start,"check-cert")==0)
276         {
277           if(no)
278             opt->flags.check_cert=0;
279           else
280             opt->flags.check_cert=1;
281         }
282       else if(strncasecmp(start,"debug",5)==0)
283         {
284           if(no)
285             opt->debug=0;
286           else if(start[5]=='=')
287             opt->debug=atoi(&start[6]);
288           else if(start[5]=='\0')
289             opt->debug=1;
290         }
291       else if(strncasecmp(start,"timeout",7)==0)
292         {
293           if(no)
294             opt->timeout=0;
295           else if(start[7]=='=')
296             opt->timeout=atoi(&start[8]);
297           else if(start[7]=='\0')
298             opt->timeout=DEFAULT_KEYSERVER_TIMEOUT;
299         }
300       else if(strncasecmp(start,"ca-cert-file",12)==0)
301         {
302           if(no)
303             {
304               free(opt->ca_cert_file);
305               opt->ca_cert_file=NULL;
306             }
307           else if(start[12]=='=')
308             {
309               free(opt->ca_cert_file);
310               opt->ca_cert_file=strdup(&start[13]);
311               if(!opt->ca_cert_file)
312                 return KEYSERVER_NO_MEMORY;
313             }
314         }
315     }
316
317   return -1;
318 }
319
320 const char *
321 ks_action_to_string(enum ks_action action)
322 {
323   switch(action)
324     {
325     case KS_UNKNOWN: return "UNKNOWN";
326     case KS_GET:     return "GET";
327     case KS_GETNAME: return "GETNAME";
328     case KS_SEND:    return "SEND";
329     case KS_SEARCH:  return "SEARCH";
330     }
331
332   return "?";
333 }
334
335 /* Canonicalize CRLF to just LF by stripping CRs.  This actually makes
336    sense, since on Unix-like machines LF is correct, and on win32-like
337    machines, our output buffer is opened in textmode and will
338    re-canonicalize line endings back to CRLF.  Since we only need to
339    handle armored keys, we don't have to worry about odd cases like
340    CRCRCR and the like. */
341
342 void
343 print_nocr(FILE *stream,const char *str)
344 {
345   while(*str)
346     {
347       if(*str!='\r')
348         fputc(*str,stream);
349       str++;
350     }
351 }
352
353 #define HEX "abcdefABCDEF1234567890"
354
355 /* Return what sort of item is being searched for.  *search is
356    permuted to remove any special indicators of a search type. */
357 enum ks_search_type
358 classify_ks_search(const char **search)
359 {
360   switch(**search)
361     {
362     case '*':
363       (*search)++;
364       return KS_SEARCH_SUBSTR;
365     case '=':
366       (*search)++;
367       return KS_SEARCH_EXACT;
368     case '<':
369       (*search)++;
370       return KS_SEARCH_MAIL;
371     case '@':
372       (*search)++;
373       return KS_SEARCH_MAILSUB;
374     case '0':
375       if((*search)[1]=='x')
376         {
377           if(strlen(*search)==10 && strspn(*search,HEX"x")==10)
378             {
379               (*search)+=2;
380               return KS_SEARCH_KEYID_SHORT;
381             }
382           else if(strlen(*search)==18 && strspn(*search,HEX"x")==18)
383             {
384               (*search)+=2;
385               return KS_SEARCH_KEYID_LONG;
386             }
387         }
388       /* fall through */
389     default:
390       /* Try and recognize a key ID.  This isn't exact (it's possible
391          that a user ID string happens to be 8 or 16 digits of hex),
392          but it's extremely unlikely.  Plus the main GPG program does
393          this also, and consistency is good. */
394
395       if(strlen(*search)==8 && strspn(*search,HEX)==8)
396         return KS_SEARCH_KEYID_SHORT;
397       else if(strlen(*search)==16 && strspn(*search,HEX)==16)
398         return KS_SEARCH_KEYID_LONG;
399
400       /* Last resort */
401       return KS_SEARCH_SUBSTR;
402     }
403 }
404
405 int
406 curl_err_to_gpg_err(CURLcode error)
407 {
408   switch(error)
409     {
410     case CURLE_OK:                    return KEYSERVER_OK;
411     case CURLE_UNSUPPORTED_PROTOCOL:  return KEYSERVER_SCHEME_NOT_FOUND;
412     case CURLE_COULDNT_CONNECT:       return KEYSERVER_UNREACHABLE;
413     case CURLE_FTP_COULDNT_RETR_FILE: return KEYSERVER_KEY_NOT_FOUND;
414     default: return KEYSERVER_INTERNAL_ERROR;
415     }
416 }
417
418 #define B64 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
419
420 static void
421 curl_armor_writer(const unsigned char *buf,size_t size,void *cw_ctx)
422 {
423   struct curl_writer_ctx *ctx=cw_ctx;
424   size_t idx=0;
425
426   while(idx<size)
427     {
428       for(;ctx->armor_remaining<3 && idx<size;ctx->armor_remaining++,idx++)
429         ctx->armor_ctx[ctx->armor_remaining]=buf[idx];
430
431       if(ctx->armor_remaining==3)
432         {
433           /* Top 6 bytes of ctx->armor_ctx[0] */
434           fputc(B64[(ctx->armor_ctx[0]>>2)&0x3F],ctx->stream);
435           /* Bottom 2 bytes of ctx->armor_ctx[0] and top 4 bytes of
436              ctx->armor_ctx[1] */
437           fputc(B64[(((ctx->armor_ctx[0]<<4)&0x30)
438                      |((ctx->armor_ctx[1]>>4)&0x0F))&0x3F],ctx->stream);
439           /* Bottom 4 bytes of ctx->armor_ctx[1] and top 2 bytes of
440              ctx->armor_ctx[2] */
441           fputc(B64[(((ctx->armor_ctx[1]<<2)&0x3C)
442                      |((ctx->armor_ctx[2]>>6)&0x03))&0x3F],ctx->stream);
443           /* Bottom 6 bytes of ctx->armor_ctx[2] */
444           fputc(B64[(ctx->armor_ctx[2]&0x3F)],ctx->stream);
445
446           ctx->linelen+=4;
447           if(ctx->linelen>=70)
448             {
449               fputc('\n',ctx->stream);
450               ctx->linelen=0;
451             }
452
453           ctx->armor_remaining=0;
454         }
455     }
456
457 }
458
459 size_t
460 curl_writer(const void *ptr,size_t size,size_t nmemb,void *cw_ctx)
461 {
462   struct curl_writer_ctx *ctx=cw_ctx;
463   const char *buf=ptr;
464   size_t i;
465
466   if(!ctx->flags.initialized)
467     {
468       if(size*nmemb==0)
469         return 0;
470
471       /* The object we're fetching is in binary form */
472       if(*buf&0x80)
473         {
474           ctx->flags.armor=1;
475           fprintf(ctx->stream,BEGIN"\n\n");
476         }
477       else
478         ctx->marker=BEGIN;
479
480       ctx->flags.initialized=1;
481     }
482
483   if(ctx->flags.armor)
484     curl_armor_writer(ptr,size*nmemb,cw_ctx);
485   else
486     {
487       /* scan the incoming data for our marker */
488       for(i=0;!ctx->flags.done && i<(size*nmemb);i++)
489         {
490           if(buf[i]==ctx->marker[ctx->markeridx])
491             {
492               ctx->markeridx++;
493               if(ctx->marker[ctx->markeridx]=='\0')
494                 {
495                   if(ctx->flags.begun)
496                     ctx->flags.done=1;
497                   else
498                     {
499                       /* We've found the BEGIN marker, so now we're
500                          looking for the END marker. */
501                       ctx->flags.begun=1;
502                       ctx->marker=END;
503                       ctx->markeridx=0;
504                       fprintf(ctx->stream,BEGIN);
505                       continue;
506                     }
507                 }
508             }
509           else
510             ctx->markeridx=0;
511
512           if(ctx->flags.begun)
513             {
514               /* Canonicalize CRLF to just LF by stripping CRs.  This
515                  actually makes sense, since on Unix-like machines LF
516                  is correct, and on win32-like machines, our output
517                  buffer is opened in textmode and will re-canonicalize
518                  line endings back to CRLF.  Since this code is just
519                  for handling armored keys, we don't have to worry
520                  about odd cases like CRCRCR and the like. */
521
522               if(buf[i]!='\r')
523                 fputc(buf[i],ctx->stream);
524             }
525         }
526     }
527
528   return size*nmemb;
529 }
530
531 void
532 curl_writer_finalize(struct curl_writer_ctx *ctx)
533 {
534   if(ctx->flags.armor)
535     {
536       if(ctx->armor_remaining==2)
537         {
538           /* Top 6 bytes of ctx->armorctx[0] */
539           fputc(B64[(ctx->armor_ctx[0]>>2)&0x3F],ctx->stream);
540           /* Bottom 2 bytes of ctx->armor_ctx[0] and top 4 bytes of
541              ctx->armor_ctx[1] */
542           fputc(B64[(((ctx->armor_ctx[0]<<4)&0x30)
543                      |((ctx->armor_ctx[1]>>4)&0x0F))&0x3F],ctx->stream);
544           /* Bottom 4 bytes of ctx->armor_ctx[1] */
545           fputc(B64[((ctx->armor_ctx[1]<<2)&0x3C)],ctx->stream);
546           /* Pad */
547           fputc('=',ctx->stream);
548         }
549       else if(ctx->armor_remaining==1)
550         {
551           /* Top 6 bytes of ctx->armor_ctx[0] */
552           fputc(B64[(ctx->armor_ctx[0]>>2)&0x3F],ctx->stream);
553           /* Bottom 2 bytes of ctx->armor_ctx[0] */
554           fputc(B64[((ctx->armor_ctx[0]<<4)&0x30)],ctx->stream);
555           /* Pad */
556           fputc('=',ctx->stream);
557           /* Pad */
558           fputc('=',ctx->stream);
559         }
560
561       fprintf(ctx->stream,"\n"END);
562       ctx->flags.done=1;
563     }
564 }