* gpgkeys_ldap.c (printquoted), curl-shim.c (curl_escape): Fix bad
[gnupg.git] / keyserver / ksutil.c
blob64912bb2d07a395200ce91c7a945b6058c34ec67
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 2 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, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19 * USA.
22 #include <config.h>
23 #include <signal.h>
24 #include <unistd.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
29 #ifdef HAVE_LIBCURL
30 #include <curl/curl.h>
31 #else
32 #include "curl-shim.h"
33 #endif
34 #include "keyserver.h"
35 #include "ksutil.h"
37 #ifdef HAVE_DOSISH_SYSTEM
39 unsigned int set_timeout(unsigned int seconds) {return 0;}
40 int register_timeout(void) {return 0;}
42 #else
44 static void
45 catch_alarm(int foo)
47 (void)foo;
48 _exit(KEYSERVER_TIMEOUT);
51 unsigned int
52 set_timeout(unsigned int seconds)
54 return alarm(seconds);
57 int
58 register_timeout(void)
60 #if defined(HAVE_SIGACTION) && defined(HAVE_STRUCT_SIGACTION)
61 struct sigaction act;
63 act.sa_handler=catch_alarm;
64 sigemptyset(&act.sa_mask);
65 act.sa_flags=0;
66 return sigaction(SIGALRM,&act,NULL);
67 #else
68 if(signal(SIGALRM,catch_alarm)==SIG_ERR)
69 return -1;
70 else
71 return 0;
72 #endif
75 #endif /* !HAVE_DOSISH_SYSTEM */
77 struct ks_options *
78 init_ks_options(void)
80 struct ks_options *opt;
82 opt=calloc(1,sizeof(struct ks_options));
84 if(opt)
86 opt->action=KS_UNKNOWN;
87 opt->flags.include_revoked=1;
88 opt->flags.include_subkeys=1;
89 opt->flags.check_cert=1;
90 opt->timeout=DEFAULT_KEYSERVER_TIMEOUT;
91 opt->path=strdup("/");
92 if(!opt->path)
94 free(opt);
95 opt=NULL;
99 return opt;
102 void
103 free_ks_options(struct ks_options *opt)
105 if(opt)
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);
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. */
122 parse_ks_options(char *line,struct ks_options *opt)
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];
134 if(line[0]=='#')
135 return 0;
137 if(sscanf(line,"COMMAND %" MKSTRING(MAX_COMMAND) "s\n",command)==1)
139 command[MAX_COMMAND]='\0';
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;
150 return 0;
153 if(sscanf(line,"HOST %" MKSTRING(MAX_HOST) "s\n",host)==1)
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;
163 if(sscanf(line,"PORT %" MKSTRING(MAX_PORT) "s\n",port)==1)
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;
173 if(sscanf(line,"SCHEME %" MKSTRING(MAX_SCHEME) "s\n",scheme)==1)
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;
183 if(sscanf(line,"AUTH %" MKSTRING(MAX_AUTH) "s\n",auth)==1)
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;
193 if(sscanf(line,"PATH %" MKSTRING(URLMAX_PATH) "s\n",path)==1)
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;
203 if(sscanf(line,"OPAQUE %" MKSTRING(MAX_OPAQUE) "s\n",opaque)==1)
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;
213 if(sscanf(line,"VERSION %d\n",&version)==1)
215 if(version!=KEYSERVER_PROTO_VERSION)
216 return KEYSERVER_VERSION_ERROR;
218 return 0;
221 if(sscanf(line,"OPTION %" MKSTRING(MAX_OPTION) "[^\n]\n",option)==1)
223 int no=0;
224 char *start=&option[0];
226 option[MAX_OPTION]='\0';
228 if(strncasecmp(option,"no-",3)==0)
230 no=1;
231 start=&option[3];
234 if(strncasecmp(start,"verbose",7)==0)
236 if(no)
237 opt->verbose=0;
238 else if(start[7]=='=')
239 opt->verbose=atoi(&start[8]);
240 else
241 opt->verbose++;
243 else if(strcasecmp(start,"include-disabled")==0)
245 if(no)
246 opt->flags.include_disabled=0;
247 else
248 opt->flags.include_disabled=1;
250 else if(strcasecmp(start,"include-revoked")==0)
252 if(no)
253 opt->flags.include_revoked=0;
254 else
255 opt->flags.include_revoked=1;
257 else if(strcasecmp(start,"include-subkeys")==0)
259 if(no)
260 opt->flags.include_subkeys=0;
261 else
262 opt->flags.include_subkeys=1;
264 else if(strcasecmp(start,"check-cert")==0)
266 if(no)
267 opt->flags.check_cert=0;
268 else
269 opt->flags.check_cert=1;
271 else if(strncasecmp(start,"debug",5)==0)
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;
280 else if(strncasecmp(start,"timeout",7)==0)
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;
289 else if(strncasecmp(start,"ca-cert-file",12)==0)
291 if(no)
293 free(opt->ca_cert_file);
294 opt->ca_cert_file=NULL;
296 else if(start[12]=='=')
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;
306 return -1;
309 const char *
310 ks_action_to_string(enum ks_action action)
312 switch(action)
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";
321 return "?";
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. */
331 void
332 print_nocr(FILE *stream,const char *str)
334 while(*str)
336 if(*str!='\r')
337 fputc(*str,stream);
338 str++;
342 enum ks_search_type
343 classify_ks_search(const char **search)
345 switch(**search)
347 case '*':
348 (*search)++;
349 return KS_SEARCH_SUBSTR;
350 case '=':
351 (*search)++;
352 return KS_SEARCH_EXACT;
353 case '<':
354 (*search)++;
355 return KS_SEARCH_MAIL;
356 case '@':
357 (*search)++;
358 return KS_SEARCH_MAILSUB;
359 case '0':
360 if((*search)[1]=='x')
362 if(strlen(*search)==10
363 && strspn(*search,"abcdefABCDEF1234567890x")==10)
365 (*search)+=2;
366 return KS_SEARCH_KEYID_SHORT;
368 else if(strlen(*search)==18
369 && strspn(*search,"abcdefABCDEF1234567890x")==18)
371 (*search)+=2;
372 return KS_SEARCH_KEYID_LONG;
375 /* fall through */
376 default:
377 return KS_SEARCH_SUBSTR;
382 curl_err_to_gpg_err(CURLcode error)
384 switch(error)
386 case CURLE_OK: return KEYSERVER_OK;
387 case CURLE_UNSUPPORTED_PROTOCOL: return KEYSERVER_SCHEME_NOT_FOUND;
388 case CURLE_COULDNT_CONNECT: return KEYSERVER_UNREACHABLE;
389 case CURLE_FTP_COULDNT_RETR_FILE: return KEYSERVER_KEY_NOT_FOUND;
390 default: return KEYSERVER_INTERNAL_ERROR;
394 #define B64 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
396 static void
397 curl_armor_writer(const unsigned char *buf,size_t size,void *cw_ctx)
399 struct curl_writer_ctx *ctx=cw_ctx;
400 size_t idx=0;
402 while(idx<size)
404 for(;ctx->armor_remaining<3 && idx<size;ctx->armor_remaining++,idx++)
405 ctx->armor_ctx[ctx->armor_remaining]=buf[idx];
407 if(ctx->armor_remaining==3)
409 /* Top 6 bytes of ctx->armor_ctx[0] */
410 fputc(B64[(ctx->armor_ctx[0]>>2)&0x3F],ctx->stream);
411 /* Bottom 2 bytes of ctx->armor_ctx[0] and top 4 bytes of
412 ctx->armor_ctx[1] */
413 fputc(B64[(((ctx->armor_ctx[0]<<4)&0x30)
414 |((ctx->armor_ctx[1]>>4)&0x0F))&0x3F],ctx->stream);
415 /* Bottom 4 bytes of ctx->armor_ctx[1] and top 2 bytes of
416 ctx->armor_ctx[2] */
417 fputc(B64[(((ctx->armor_ctx[1]<<2)&0x3C)
418 |((ctx->armor_ctx[2]>>6)&0x03))&0x3F],ctx->stream);
419 /* Bottom 6 bytes of ctx->armor_ctx[2] */
420 fputc(B64[(ctx->armor_ctx[2]&0x3F)],ctx->stream);
422 ctx->linelen+=4;
423 if(ctx->linelen>=70)
425 fputc('\n',ctx->stream);
426 ctx->linelen=0;
429 ctx->armor_remaining=0;
435 size_t
436 curl_writer(const void *ptr,size_t size,size_t nmemb,void *cw_ctx)
438 struct curl_writer_ctx *ctx=cw_ctx;
439 const char *buf=ptr;
440 size_t i;
442 if(!ctx->flags.initialized)
444 if(size*nmemb==0)
445 return 0;
447 /* The object we're fetching is in binary form */
448 if(*buf&0x80)
450 ctx->flags.armor=1;
451 fprintf(ctx->stream,BEGIN"\n\n");
453 else
454 ctx->marker=BEGIN;
456 ctx->flags.initialized=1;
459 if(ctx->flags.armor)
460 curl_armor_writer(ptr,size*nmemb,cw_ctx);
461 else
463 /* scan the incoming data for our marker */
464 for(i=0;!ctx->flags.done && i<(size*nmemb);i++)
466 if(buf[i]==ctx->marker[ctx->markeridx])
468 ctx->markeridx++;
469 if(ctx->marker[ctx->markeridx]=='\0')
471 if(ctx->flags.begun)
472 ctx->flags.done=1;
473 else
475 /* We've found the BEGIN marker, so now we're
476 looking for the END marker. */
477 ctx->flags.begun=1;
478 ctx->marker=END;
479 ctx->markeridx=0;
480 fprintf(ctx->stream,BEGIN);
481 continue;
485 else
486 ctx->markeridx=0;
488 if(ctx->flags.begun)
490 /* Canonicalize CRLF to just LF by stripping CRs. This
491 actually makes sense, since on Unix-like machines LF
492 is correct, and on win32-like machines, our output
493 buffer is opened in textmode and will re-canonicalize
494 line endings back to CRLF. Since this code is just
495 for handling armored keys, we don't have to worry
496 about odd cases like CRCRCR and the like. */
498 if(buf[i]!='\r')
499 fputc(buf[i],ctx->stream);
504 return size*nmemb;
507 void
508 curl_writer_finalize(struct curl_writer_ctx *ctx)
510 if(ctx->flags.armor)
512 if(ctx->armor_remaining==2)
514 /* Top 6 bytes of ctx->armorctx[0] */
515 fputc(B64[(ctx->armor_ctx[0]>>2)&0x3F],ctx->stream);
516 /* Bottom 2 bytes of ctx->armor_ctx[0] and top 4 bytes of
517 ctx->armor_ctx[1] */
518 fputc(B64[(((ctx->armor_ctx[0]<<4)&0x30)
519 |((ctx->armor_ctx[1]>>4)&0x0F))&0x3F],ctx->stream);
520 /* Bottom 4 bytes of ctx->armor_ctx[1] */
521 fputc(B64[((ctx->armor_ctx[1]<<2)&0x3C)],ctx->stream);
522 /* Pad */
523 fputc('=',ctx->stream);
525 else if(ctx->armor_remaining==1)
527 /* Top 6 bytes of ctx->armor_ctx[0] */
528 fputc(B64[(ctx->armor_ctx[0]>>2)&0x3F],ctx->stream);
529 /* Bottom 2 bytes of ctx->armor_ctx[0] */
530 fputc(B64[((ctx->armor_ctx[0]<<4)&0x30)],ctx->stream);
531 /* Pad */
532 fputc('=',ctx->stream);
533 /* Pad */
534 fputc('=',ctx->stream);
537 fprintf(ctx->stream,"\n"END);
538 ctx->flags.done=1;