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