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