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