Pth tweaks and improved estream.c
[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 enum ks_search_type
354 classify_ks_search(const char **search)
355 {
356   switch(**search)
357     {
358     case '*':
359       (*search)++;
360       return KS_SEARCH_SUBSTR;
361     case '=':
362       (*search)++;
363       return KS_SEARCH_EXACT;
364     case '<':
365       (*search)++;
366       return KS_SEARCH_MAIL;
367     case '@':
368       (*search)++;
369       return KS_SEARCH_MAILSUB;
370     case '0':
371       if((*search)[1]=='x')
372         {
373           if(strlen(*search)==10
374              && strspn(*search,"abcdefABCDEF1234567890x")==10)
375             {
376               (*search)+=2;
377               return KS_SEARCH_KEYID_SHORT;
378             }
379           else if(strlen(*search)==18
380                   && strspn(*search,"abcdefABCDEF1234567890x")==18)
381             {
382               (*search)+=2;
383               return KS_SEARCH_KEYID_LONG;
384             }
385         }
386       /* fall through */
387     default:
388       return KS_SEARCH_SUBSTR;
389     }
390 }
391
392 int
393 curl_err_to_gpg_err(CURLcode error)
394 {
395   switch(error)
396     {
397     case CURLE_OK:                    return KEYSERVER_OK;
398     case CURLE_UNSUPPORTED_PROTOCOL:  return KEYSERVER_SCHEME_NOT_FOUND;
399     case CURLE_COULDNT_CONNECT:       return KEYSERVER_UNREACHABLE;
400     case CURLE_FTP_COULDNT_RETR_FILE: return KEYSERVER_KEY_NOT_FOUND;
401     default: return KEYSERVER_INTERNAL_ERROR;
402     }
403 }
404
405 #define B64 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
406
407 static void
408 curl_armor_writer(const unsigned char *buf,size_t size,void *cw_ctx)
409 {
410   struct curl_writer_ctx *ctx=cw_ctx;
411   size_t idx=0;
412
413   while(idx<size)
414     {
415       for(;ctx->armor_remaining<3 && idx<size;ctx->armor_remaining++,idx++)
416         ctx->armor_ctx[ctx->armor_remaining]=buf[idx];
417
418       if(ctx->armor_remaining==3)
419         {
420           /* Top 6 bytes of ctx->armor_ctx[0] */
421           fputc(B64[(ctx->armor_ctx[0]>>2)&0x3F],ctx->stream);
422           /* Bottom 2 bytes of ctx->armor_ctx[0] and top 4 bytes of
423              ctx->armor_ctx[1] */
424           fputc(B64[(((ctx->armor_ctx[0]<<4)&0x30)
425                      |((ctx->armor_ctx[1]>>4)&0x0F))&0x3F],ctx->stream);
426           /* Bottom 4 bytes of ctx->armor_ctx[1] and top 2 bytes of
427              ctx->armor_ctx[2] */
428           fputc(B64[(((ctx->armor_ctx[1]<<2)&0x3C)
429                      |((ctx->armor_ctx[2]>>6)&0x03))&0x3F],ctx->stream);
430           /* Bottom 6 bytes of ctx->armor_ctx[2] */
431           fputc(B64[(ctx->armor_ctx[2]&0x3F)],ctx->stream);
432
433           ctx->linelen+=4;
434           if(ctx->linelen>=70)
435             {
436               fputc('\n',ctx->stream);
437               ctx->linelen=0;
438             }
439
440           ctx->armor_remaining=0;
441         }
442     }
443
444 }
445
446 size_t
447 curl_writer(const void *ptr,size_t size,size_t nmemb,void *cw_ctx)
448 {
449   struct curl_writer_ctx *ctx=cw_ctx;
450   const char *buf=ptr;
451   size_t i;
452
453   if(!ctx->flags.initialized)
454     {
455       if(size*nmemb==0)
456         return 0;
457
458       /* The object we're fetching is in binary form */
459       if(*buf&0x80)
460         {
461           ctx->flags.armor=1;
462           fprintf(ctx->stream,BEGIN"\n\n");
463         }
464       else
465         ctx->marker=BEGIN;
466
467       ctx->flags.initialized=1;
468     }
469
470   if(ctx->flags.armor)
471     curl_armor_writer(ptr,size*nmemb,cw_ctx);
472   else
473     {
474       /* scan the incoming data for our marker */
475       for(i=0;!ctx->flags.done && i<(size*nmemb);i++)
476         {
477           if(buf[i]==ctx->marker[ctx->markeridx])
478             {
479               ctx->markeridx++;
480               if(ctx->marker[ctx->markeridx]=='\0')
481                 {
482                   if(ctx->flags.begun)
483                     ctx->flags.done=1;
484                   else
485                     {
486                       /* We've found the BEGIN marker, so now we're
487                          looking for the END marker. */
488                       ctx->flags.begun=1;
489                       ctx->marker=END;
490                       ctx->markeridx=0;
491                       fprintf(ctx->stream,BEGIN);
492                       continue;
493                     }
494                 }
495             }
496           else
497             ctx->markeridx=0;
498
499           if(ctx->flags.begun)
500             {
501               /* Canonicalize CRLF to just LF by stripping CRs.  This
502                  actually makes sense, since on Unix-like machines LF
503                  is correct, and on win32-like machines, our output
504                  buffer is opened in textmode and will re-canonicalize
505                  line endings back to CRLF.  Since this code is just
506                  for handling armored keys, we don't have to worry
507                  about odd cases like CRCRCR and the like. */
508
509               if(buf[i]!='\r')
510                 fputc(buf[i],ctx->stream);
511             }
512         }
513     }
514
515   return size*nmemb;
516 }
517
518 void
519 curl_writer_finalize(struct curl_writer_ctx *ctx)
520 {
521   if(ctx->flags.armor)
522     {
523       if(ctx->armor_remaining==2)
524         {
525           /* Top 6 bytes of ctx->armorctx[0] */
526           fputc(B64[(ctx->armor_ctx[0]>>2)&0x3F],ctx->stream);
527           /* Bottom 2 bytes of ctx->armor_ctx[0] and top 4 bytes of
528              ctx->armor_ctx[1] */
529           fputc(B64[(((ctx->armor_ctx[0]<<4)&0x30)
530                      |((ctx->armor_ctx[1]>>4)&0x0F))&0x3F],ctx->stream);
531           /* Bottom 4 bytes of ctx->armor_ctx[1] */
532           fputc(B64[((ctx->armor_ctx[1]<<2)&0x3C)],ctx->stream);
533           /* Pad */
534           fputc('=',ctx->stream);
535         }
536       else if(ctx->armor_remaining==1)
537         {
538           /* Top 6 bytes of ctx->armor_ctx[0] */
539           fputc(B64[(ctx->armor_ctx[0]>>2)&0x3F],ctx->stream);
540           /* Bottom 2 bytes of ctx->armor_ctx[0] */
541           fputc(B64[((ctx->armor_ctx[0]<<4)&0x30)],ctx->stream);
542           /* Pad */
543           fputc('=',ctx->stream);
544           /* Pad */
545           fputc('=',ctx->stream);
546         }
547
548       fprintf(ctx->stream,"\n"END);
549       ctx->flags.done=1;
550     }
551 }
552
553
554 int
555 ks_hextobyte (const char *s)
556 {
557   int c;
558
559   if ( *s >= '0' && *s <= '9' )
560     c = 16 * (*s - '0');
561   else if ( *s >= 'A' && *s <= 'F' )
562     c = 16 * (10 + *s - 'A');
563   else if ( *s >= 'a' && *s <= 'f' )
564     c = 16 * (10 + *s - 'a');
565   else
566     return -1;
567   s++;
568   if ( *s >= '0' && *s <= '9' )
569     c += *s - '0';
570   else if ( *s >= 'A' && *s <= 'F' )
571     c += 10 + *s - 'A';
572   else if ( *s >= 'a' && *s <= 'f' )
573     c += 10 + *s - 'a';
574   else
575     return -1;
576   return c;
577 }
578
579
580 /* Non localized version of toupper.  */
581 int 
582 ks_toupper (int c)
583 {
584   if (c >= 'a' && c <= 'z')
585     c &= ~0x20;
586   return c;
587 }
588
589
590 /* Non localized version of strcasecmp.  */
591 int
592 ks_strcasecmp (const char *a, const char *b)
593 {
594   if (a == b)
595     return 0;
596
597   for (; *a && *b; a++, b++)
598     {
599       if (*a != *b && ks_toupper (*a) != ks_toupper (*b))
600         break;
601     }
602   return *a == *b? 0 : (ks_toupper (*a) - ks_toupper (*b));
603 }