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