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