2008-01-10 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / keyserver / ksutil.c
blob04e21b6a8e21688411a96af253e897885c23226a
1 /* ksutil.c - general keyserver utility functions
2 * Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
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.
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.
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/>.
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.
31 #include <config.h>
32 #include <signal.h>
33 #include <unistd.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <stdlib.h>
38 #ifdef HAVE_LIBCURL
39 #include <curl/curl.h>
40 #else
41 #include "curl-shim.h"
42 #endif
43 #include "keyserver.h"
44 #include "ksutil.h"
46 #ifdef HAVE_DOSISH_SYSTEM
48 unsigned int set_timeout(unsigned int seconds) {return 0;}
49 int register_timeout(void) {return 0;}
51 #else
53 static void
54 catch_alarm(int foo)
56 (void)foo;
57 _exit(KEYSERVER_TIMEOUT);
60 unsigned int
61 set_timeout(unsigned int seconds)
63 return alarm(seconds);
66 int
67 register_timeout(void)
69 #if defined(HAVE_SIGACTION) && defined(HAVE_STRUCT_SIGACTION)
70 struct sigaction act;
72 act.sa_handler=catch_alarm;
73 sigemptyset(&act.sa_mask);
74 act.sa_flags=0;
75 return sigaction(SIGALRM,&act,NULL);
76 #else
77 if(signal(SIGALRM,catch_alarm)==SIG_ERR)
78 return -1;
79 else
80 return 0;
81 #endif
84 #endif /* !HAVE_DOSISH_SYSTEM */
86 struct ks_options *
87 init_ks_options(void)
89 struct ks_options *opt;
91 opt=calloc(1,sizeof(struct ks_options));
93 if(opt)
95 opt->action=KS_UNKNOWN;
96 opt->flags.include_revoked=1;
97 opt->flags.include_subkeys=1;
98 opt->flags.check_cert=1;
99 opt->timeout=DEFAULT_KEYSERVER_TIMEOUT;
100 opt->path=strdup("/");
101 if(!opt->path)
103 free(opt);
104 opt=NULL;
108 return opt;
111 void
112 free_ks_options(struct ks_options *opt)
114 if(opt)
116 free(opt->host);
117 free(opt->port);
118 free(opt->scheme);
119 free(opt->auth);
120 free(opt->path);
121 free(opt->opaque);
122 free(opt->ca_cert_file);
123 free(opt);
127 /* Returns 0 if we "ate" the line. Returns >0, a KEYSERVER_ error
128 code if that error applies. Returns -1 if we did not match the
129 line at all. */
131 parse_ks_options(char *line,struct ks_options *opt)
133 int version;
134 char command[MAX_COMMAND+1];
135 char host[MAX_HOST+1];
136 char port[MAX_PORT+1];
137 char scheme[MAX_SCHEME+1];
138 char auth[MAX_AUTH+1];
139 char path[URLMAX_PATH+1];
140 char opaque[MAX_OPAQUE+1];
141 char option[MAX_OPTION+1];
143 if(line[0]=='#')
144 return 0;
146 if(sscanf(line,"COMMAND %" MKSTRING(MAX_COMMAND) "s\n",command)==1)
148 command[MAX_COMMAND]='\0';
150 if(strcasecmp(command,"get")==0)
151 opt->action=KS_GET;
152 else if(strcasecmp(command,"getname")==0)
153 opt->action=KS_GETNAME;
154 else if(strcasecmp(command,"send")==0)
155 opt->action=KS_SEND;
156 else if(strcasecmp(command,"search")==0)
157 opt->action=KS_SEARCH;
159 return 0;
162 if(sscanf(line,"HOST %" MKSTRING(MAX_HOST) "s\n",host)==1)
164 host[MAX_HOST]='\0';
165 free(opt->host);
166 opt->host=strdup(host);
167 if(!opt->host)
168 return KEYSERVER_NO_MEMORY;
169 return 0;
172 if(sscanf(line,"PORT %" MKSTRING(MAX_PORT) "s\n",port)==1)
174 port[MAX_PORT]='\0';
175 free(opt->port);
176 opt->port=strdup(port);
177 if(!opt->port)
178 return KEYSERVER_NO_MEMORY;
179 return 0;
182 if(sscanf(line,"SCHEME %" MKSTRING(MAX_SCHEME) "s\n",scheme)==1)
184 scheme[MAX_SCHEME]='\0';
185 free(opt->scheme);
186 opt->scheme=strdup(scheme);
187 if(!opt->scheme)
188 return KEYSERVER_NO_MEMORY;
189 return 0;
192 if(sscanf(line,"AUTH %" MKSTRING(MAX_AUTH) "s\n",auth)==1)
194 auth[MAX_AUTH]='\0';
195 free(opt->auth);
196 opt->auth=strdup(auth);
197 if(!opt->auth)
198 return KEYSERVER_NO_MEMORY;
199 return 0;
202 if(sscanf(line,"PATH %" MKSTRING(URLMAX_PATH) "s\n",path)==1)
204 path[URLMAX_PATH]='\0';
205 free(opt->path);
206 opt->path=strdup(path);
207 if(!opt->path)
208 return KEYSERVER_NO_MEMORY;
209 return 0;
212 if(sscanf(line,"OPAQUE %" MKSTRING(MAX_OPAQUE) "s\n",opaque)==1)
214 opaque[MAX_OPAQUE]='\0';
215 free(opt->opaque);
216 opt->opaque=strdup(opaque);
217 if(!opt->opaque)
218 return KEYSERVER_NO_MEMORY;
219 return 0;
222 if(sscanf(line,"VERSION %d\n",&version)==1)
224 if(version!=KEYSERVER_PROTO_VERSION)
225 return KEYSERVER_VERSION_ERROR;
227 return 0;
230 if(sscanf(line,"OPTION %" MKSTRING(MAX_OPTION) "[^\n]\n",option)==1)
232 int no=0;
233 char *start=&option[0];
235 option[MAX_OPTION]='\0';
237 if(strncasecmp(option,"no-",3)==0)
239 no=1;
240 start=&option[3];
243 if(strncasecmp(start,"verbose",7)==0)
245 if(no)
246 opt->verbose=0;
247 else if(start[7]=='=')
248 opt->verbose=atoi(&start[8]);
249 else
250 opt->verbose++;
252 else if(strcasecmp(start,"include-disabled")==0)
254 if(no)
255 opt->flags.include_disabled=0;
256 else
257 opt->flags.include_disabled=1;
259 else if(strcasecmp(start,"include-revoked")==0)
261 if(no)
262 opt->flags.include_revoked=0;
263 else
264 opt->flags.include_revoked=1;
266 else if(strcasecmp(start,"include-subkeys")==0)
268 if(no)
269 opt->flags.include_subkeys=0;
270 else
271 opt->flags.include_subkeys=1;
273 else if(strcasecmp(start,"check-cert")==0)
275 if(no)
276 opt->flags.check_cert=0;
277 else
278 opt->flags.check_cert=1;
280 else if(strncasecmp(start,"debug",5)==0)
282 if(no)
283 opt->debug=0;
284 else if(start[5]=='=')
285 opt->debug=atoi(&start[6]);
286 else if(start[5]=='\0')
287 opt->debug=1;
289 else if(strncasecmp(start,"timeout",7)==0)
291 if(no)
292 opt->timeout=0;
293 else if(start[7]=='=')
294 opt->timeout=atoi(&start[8]);
295 else if(start[7]=='\0')
296 opt->timeout=DEFAULT_KEYSERVER_TIMEOUT;
298 else if(strncasecmp(start,"ca-cert-file",12)==0)
300 if(no)
302 free(opt->ca_cert_file);
303 opt->ca_cert_file=NULL;
305 else if(start[12]=='=')
307 free(opt->ca_cert_file);
308 opt->ca_cert_file=strdup(&start[13]);
309 if(!opt->ca_cert_file)
310 return KEYSERVER_NO_MEMORY;
315 return -1;
318 const char *
319 ks_action_to_string(enum ks_action action)
321 switch(action)
323 case KS_UNKNOWN: return "UNKNOWN";
324 case KS_GET: return "GET";
325 case KS_GETNAME: return "GETNAME";
326 case KS_SEND: return "SEND";
327 case KS_SEARCH: return "SEARCH";
330 return "?";
333 /* Canonicalize CRLF to just LF by stripping CRs. This actually makes
334 sense, since on Unix-like machines LF is correct, and on win32-like
335 machines, our output buffer is opened in textmode and will
336 re-canonicalize line endings back to CRLF. Since we only need to
337 handle armored keys, we don't have to worry about odd cases like
338 CRCRCR and the like. */
340 void
341 print_nocr(FILE *stream,const char *str)
343 while(*str)
345 if(*str!='\r')
346 fputc(*str,stream);
347 str++;
351 enum ks_search_type
352 classify_ks_search(const char **search)
354 switch(**search)
356 case '*':
357 (*search)++;
358 return KS_SEARCH_SUBSTR;
359 case '=':
360 (*search)++;
361 return KS_SEARCH_EXACT;
362 case '<':
363 (*search)++;
364 return KS_SEARCH_MAIL;
365 case '@':
366 (*search)++;
367 return KS_SEARCH_MAILSUB;
368 case '0':
369 if((*search)[1]=='x')
371 if(strlen(*search)==10
372 && strspn(*search,"abcdefABCDEF1234567890x")==10)
374 (*search)+=2;
375 return KS_SEARCH_KEYID_SHORT;
377 else if(strlen(*search)==18
378 && strspn(*search,"abcdefABCDEF1234567890x")==18)
380 (*search)+=2;
381 return KS_SEARCH_KEYID_LONG;
384 /* fall through */
385 default:
386 return KS_SEARCH_SUBSTR;
391 curl_err_to_gpg_err(CURLcode error)
393 switch(error)
395 case CURLE_OK: return KEYSERVER_OK;
396 case CURLE_UNSUPPORTED_PROTOCOL: return KEYSERVER_SCHEME_NOT_FOUND;
397 case CURLE_COULDNT_CONNECT: return KEYSERVER_UNREACHABLE;
398 case CURLE_FTP_COULDNT_RETR_FILE: return KEYSERVER_KEY_NOT_FOUND;
399 default: return KEYSERVER_INTERNAL_ERROR;
403 #define B64 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
405 static void
406 curl_armor_writer(const unsigned char *buf,size_t size,void *cw_ctx)
408 struct curl_writer_ctx *ctx=cw_ctx;
409 size_t idx=0;
411 while(idx<size)
413 for(;ctx->armor_remaining<3 && idx<size;ctx->armor_remaining++,idx++)
414 ctx->armor_ctx[ctx->armor_remaining]=buf[idx];
416 if(ctx->armor_remaining==3)
418 /* Top 6 bytes of ctx->armor_ctx[0] */
419 fputc(B64[(ctx->armor_ctx[0]>>2)&0x3F],ctx->stream);
420 /* Bottom 2 bytes of ctx->armor_ctx[0] and top 4 bytes of
421 ctx->armor_ctx[1] */
422 fputc(B64[(((ctx->armor_ctx[0]<<4)&0x30)
423 |((ctx->armor_ctx[1]>>4)&0x0F))&0x3F],ctx->stream);
424 /* Bottom 4 bytes of ctx->armor_ctx[1] and top 2 bytes of
425 ctx->armor_ctx[2] */
426 fputc(B64[(((ctx->armor_ctx[1]<<2)&0x3C)
427 |((ctx->armor_ctx[2]>>6)&0x03))&0x3F],ctx->stream);
428 /* Bottom 6 bytes of ctx->armor_ctx[2] */
429 fputc(B64[(ctx->armor_ctx[2]&0x3F)],ctx->stream);
431 ctx->linelen+=4;
432 if(ctx->linelen>=70)
434 fputc('\n',ctx->stream);
435 ctx->linelen=0;
438 ctx->armor_remaining=0;
444 size_t
445 curl_writer(const void *ptr,size_t size,size_t nmemb,void *cw_ctx)
447 struct curl_writer_ctx *ctx=cw_ctx;
448 const char *buf=ptr;
449 size_t i;
451 if(!ctx->flags.initialized)
453 if(size*nmemb==0)
454 return 0;
456 /* The object we're fetching is in binary form */
457 if(*buf&0x80)
459 ctx->flags.armor=1;
460 fprintf(ctx->stream,BEGIN"\n\n");
462 else
463 ctx->marker=BEGIN;
465 ctx->flags.initialized=1;
468 if(ctx->flags.armor)
469 curl_armor_writer(ptr,size*nmemb,cw_ctx);
470 else
472 /* scan the incoming data for our marker */
473 for(i=0;!ctx->flags.done && i<(size*nmemb);i++)
475 if(buf[i]==ctx->marker[ctx->markeridx])
477 ctx->markeridx++;
478 if(ctx->marker[ctx->markeridx]=='\0')
480 if(ctx->flags.begun)
481 ctx->flags.done=1;
482 else
484 /* We've found the BEGIN marker, so now we're
485 looking for the END marker. */
486 ctx->flags.begun=1;
487 ctx->marker=END;
488 ctx->markeridx=0;
489 fprintf(ctx->stream,BEGIN);
490 continue;
494 else
495 ctx->markeridx=0;
497 if(ctx->flags.begun)
499 /* Canonicalize CRLF to just LF by stripping CRs. This
500 actually makes sense, since on Unix-like machines LF
501 is correct, and on win32-like machines, our output
502 buffer is opened in textmode and will re-canonicalize
503 line endings back to CRLF. Since this code is just
504 for handling armored keys, we don't have to worry
505 about odd cases like CRCRCR and the like. */
507 if(buf[i]!='\r')
508 fputc(buf[i],ctx->stream);
513 return size*nmemb;
516 void
517 curl_writer_finalize(struct curl_writer_ctx *ctx)
519 if(ctx->flags.armor)
521 if(ctx->armor_remaining==2)
523 /* Top 6 bytes of ctx->armorctx[0] */
524 fputc(B64[(ctx->armor_ctx[0]>>2)&0x3F],ctx->stream);
525 /* Bottom 2 bytes of ctx->armor_ctx[0] and top 4 bytes of
526 ctx->armor_ctx[1] */
527 fputc(B64[(((ctx->armor_ctx[0]<<4)&0x30)
528 |((ctx->armor_ctx[1]>>4)&0x0F))&0x3F],ctx->stream);
529 /* Bottom 4 bytes of ctx->armor_ctx[1] */
530 fputc(B64[((ctx->armor_ctx[1]<<2)&0x3C)],ctx->stream);
531 /* Pad */
532 fputc('=',ctx->stream);
534 else if(ctx->armor_remaining==1)
536 /* Top 6 bytes of ctx->armor_ctx[0] */
537 fputc(B64[(ctx->armor_ctx[0]>>2)&0x3F],ctx->stream);
538 /* Bottom 2 bytes of ctx->armor_ctx[0] */
539 fputc(B64[((ctx->armor_ctx[0]<<4)&0x30)],ctx->stream);
540 /* Pad */
541 fputc('=',ctx->stream);
542 /* Pad */
543 fputc('=',ctx->stream);
546 fprintf(ctx->stream,"\n"END);
547 ctx->flags.done=1;
553 ks_hextobyte (const char *s)
555 int c;
557 if ( *s >= '0' && *s <= '9' )
558 c = 16 * (*s - '0');
559 else if ( *s >= 'A' && *s <= 'F' )
560 c = 16 * (10 + *s - 'A');
561 else if ( *s >= 'a' && *s <= 'f' )
562 c = 16 * (10 + *s - 'a');
563 else
564 return -1;
565 s++;
566 if ( *s >= '0' && *s <= '9' )
567 c += *s - '0';
568 else if ( *s >= 'A' && *s <= 'F' )
569 c += 10 + *s - 'A';
570 else if ( *s >= 'a' && *s <= 'f' )
571 c += 10 + *s - 'a';
572 else
573 return -1;
574 return c;
578 /* Non localized version of toupper. */
579 int
580 ks_toupper (int c)
582 if (c >= 'a' && c <= 'z')
583 c &= ~0x20;
584 return c;
588 /* Non localized version of strcasecmp. */
590 ks_strcasecmp (const char *a, const char *b)
592 if (a == b)
593 return 0;
595 for (; *a && *b; a++, b++)
597 if (*a != *b && ks_toupper (*a) != ks_toupper (*b))
598 break;
600 return *a == *b? 0 : (ks_toupper (*a) - ks_toupper (*b));