aboutsummaryrefslogtreecommitdiffstats
path: root/keyserver/ksutil.c
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2006-06-30 13:19:49 +0000
committerWerner Koch <[email protected]>2006-06-30 13:19:49 +0000
commit640d5a8c53289f396ae018a4c36e2e8894261329 (patch)
treef2aecb490c84becc776ae45f32b027672a69ed19 /keyserver/ksutil.c
parentA couple of fixes. gpg2's key generation does now work. (diff)
downloadgnupg-640d5a8c53289f396ae018a4c36e2e8894261329.tar.gz
gnupg-640d5a8c53289f396ae018a4c36e2e8894261329.zip
Added keyserver directory from trunk
Diffstat (limited to '')
-rw-r--r--keyserver/ksutil.c540
1 files changed, 540 insertions, 0 deletions
diff --git a/keyserver/ksutil.c b/keyserver/ksutil.c
new file mode 100644
index 000000000..64912bb2d
--- /dev/null
+++ b/keyserver/ksutil.c
@@ -0,0 +1,540 @@
+/* ksutil.c - general keyserver utility functions
+ * Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#include <config.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef HAVE_LIBCURL
+#include <curl/curl.h>
+#else
+#include "curl-shim.h"
+#endif
+#include "keyserver.h"
+#include "ksutil.h"
+
+#ifdef HAVE_DOSISH_SYSTEM
+
+unsigned int set_timeout(unsigned int seconds) {return 0;}
+int register_timeout(void) {return 0;}
+
+#else
+
+static void
+catch_alarm(int foo)
+{
+ (void)foo;
+ _exit(KEYSERVER_TIMEOUT);
+}
+
+unsigned int
+set_timeout(unsigned int seconds)
+{
+ return alarm(seconds);
+}
+
+int
+register_timeout(void)
+{
+#if defined(HAVE_SIGACTION) && defined(HAVE_STRUCT_SIGACTION)
+ struct sigaction act;
+
+ act.sa_handler=catch_alarm;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags=0;
+ return sigaction(SIGALRM,&act,NULL);
+#else
+ if(signal(SIGALRM,catch_alarm)==SIG_ERR)
+ return -1;
+ else
+ return 0;
+#endif
+}
+
+#endif /* !HAVE_DOSISH_SYSTEM */
+
+struct ks_options *
+init_ks_options(void)
+{
+ struct ks_options *opt;
+
+ opt=calloc(1,sizeof(struct ks_options));
+
+ if(opt)
+ {
+ opt->action=KS_UNKNOWN;
+ opt->flags.include_revoked=1;
+ opt->flags.include_subkeys=1;
+ opt->flags.check_cert=1;
+ opt->timeout=DEFAULT_KEYSERVER_TIMEOUT;
+ opt->path=strdup("/");
+ if(!opt->path)
+ {
+ free(opt);
+ opt=NULL;
+ }
+ }
+
+ return opt;
+}
+
+void
+free_ks_options(struct ks_options *opt)
+{
+ if(opt)
+ {
+ free(opt->host);
+ free(opt->port);
+ free(opt->scheme);
+ free(opt->auth);
+ free(opt->path);
+ free(opt->opaque);
+ free(opt->ca_cert_file);
+ free(opt);
+ }
+}
+
+/* Returns 0 if we "ate" the line. Returns >0, a KEYSERVER_ error
+ code if that error applies. Returns -1 if we did not match the
+ line at all. */
+int
+parse_ks_options(char *line,struct ks_options *opt)
+{
+ int version;
+ char command[MAX_COMMAND+1];
+ char host[MAX_HOST+1];
+ char port[MAX_PORT+1];
+ char scheme[MAX_SCHEME+1];
+ char auth[MAX_AUTH+1];
+ char path[URLMAX_PATH+1];
+ char opaque[MAX_OPAQUE+1];
+ char option[MAX_OPTION+1];
+
+ if(line[0]=='#')
+ return 0;
+
+ if(sscanf(line,"COMMAND %" MKSTRING(MAX_COMMAND) "s\n",command)==1)
+ {
+ command[MAX_COMMAND]='\0';
+
+ if(strcasecmp(command,"get")==0)
+ opt->action=KS_GET;
+ else if(strcasecmp(command,"getname")==0)
+ opt->action=KS_GETNAME;
+ else if(strcasecmp(command,"send")==0)
+ opt->action=KS_SEND;
+ else if(strcasecmp(command,"search")==0)
+ opt->action=KS_SEARCH;
+
+ return 0;
+ }
+
+ if(sscanf(line,"HOST %" MKSTRING(MAX_HOST) "s\n",host)==1)
+ {
+ host[MAX_HOST]='\0';
+ free(opt->host);
+ opt->host=strdup(host);
+ if(!opt->host)
+ return KEYSERVER_NO_MEMORY;
+ return 0;
+ }
+
+ if(sscanf(line,"PORT %" MKSTRING(MAX_PORT) "s\n",port)==1)
+ {
+ port[MAX_PORT]='\0';
+ free(opt->port);
+ opt->port=strdup(port);
+ if(!opt->port)
+ return KEYSERVER_NO_MEMORY;
+ return 0;
+ }
+
+ if(sscanf(line,"SCHEME %" MKSTRING(MAX_SCHEME) "s\n",scheme)==1)
+ {
+ scheme[MAX_SCHEME]='\0';
+ free(opt->scheme);
+ opt->scheme=strdup(scheme);
+ if(!opt->scheme)
+ return KEYSERVER_NO_MEMORY;
+ return 0;
+ }
+
+ if(sscanf(line,"AUTH %" MKSTRING(MAX_AUTH) "s\n",auth)==1)
+ {
+ auth[MAX_AUTH]='\0';
+ free(opt->auth);
+ opt->auth=strdup(auth);
+ if(!opt->auth)
+ return KEYSERVER_NO_MEMORY;
+ return 0;
+ }
+
+ if(sscanf(line,"PATH %" MKSTRING(URLMAX_PATH) "s\n",path)==1)
+ {
+ path[URLMAX_PATH]='\0';
+ free(opt->path);
+ opt->path=strdup(path);
+ if(!opt->path)
+ return KEYSERVER_NO_MEMORY;
+ return 0;
+ }
+
+ if(sscanf(line,"OPAQUE %" MKSTRING(MAX_OPAQUE) "s\n",opaque)==1)
+ {
+ opaque[MAX_OPAQUE]='\0';
+ free(opt->opaque);
+ opt->opaque=strdup(opaque);
+ if(!opt->opaque)
+ return KEYSERVER_NO_MEMORY;
+ return 0;
+ }
+
+ if(sscanf(line,"VERSION %d\n",&version)==1)
+ {
+ if(version!=KEYSERVER_PROTO_VERSION)
+ return KEYSERVER_VERSION_ERROR;
+
+ return 0;
+ }
+
+ if(sscanf(line,"OPTION %" MKSTRING(MAX_OPTION) "[^\n]\n",option)==1)
+ {
+ int no=0;
+ char *start=&option[0];
+
+ option[MAX_OPTION]='\0';
+
+ if(strncasecmp(option,"no-",3)==0)
+ {
+ no=1;
+ start=&option[3];
+ }
+
+ if(strncasecmp(start,"verbose",7)==0)
+ {
+ if(no)
+ opt->verbose=0;
+ else if(start[7]=='=')
+ opt->verbose=atoi(&start[8]);
+ else
+ opt->verbose++;
+ }
+ else if(strcasecmp(start,"include-disabled")==0)
+ {
+ if(no)
+ opt->flags.include_disabled=0;
+ else
+ opt->flags.include_disabled=1;
+ }
+ else if(strcasecmp(start,"include-revoked")==0)
+ {
+ if(no)
+ opt->flags.include_revoked=0;
+ else
+ opt->flags.include_revoked=1;
+ }
+ else if(strcasecmp(start,"include-subkeys")==0)
+ {
+ if(no)
+ opt->flags.include_subkeys=0;
+ else
+ opt->flags.include_subkeys=1;
+ }
+ else if(strcasecmp(start,"check-cert")==0)
+ {
+ if(no)
+ opt->flags.check_cert=0;
+ else
+ opt->flags.check_cert=1;
+ }
+ else if(strncasecmp(start,"debug",5)==0)
+ {
+ if(no)
+ opt->debug=0;
+ else if(start[5]=='=')
+ opt->debug=atoi(&start[6]);
+ else if(start[5]=='\0')
+ opt->debug=1;
+ }
+ else if(strncasecmp(start,"timeout",7)==0)
+ {
+ if(no)
+ opt->timeout=0;
+ else if(start[7]=='=')
+ opt->timeout=atoi(&start[8]);
+ else if(start[7]=='\0')
+ opt->timeout=DEFAULT_KEYSERVER_TIMEOUT;
+ }
+ else if(strncasecmp(start,"ca-cert-file",12)==0)
+ {
+ if(no)
+ {
+ free(opt->ca_cert_file);
+ opt->ca_cert_file=NULL;
+ }
+ else if(start[12]=='=')
+ {
+ free(opt->ca_cert_file);
+ opt->ca_cert_file=strdup(&start[13]);
+ if(!opt->ca_cert_file)
+ return KEYSERVER_NO_MEMORY;
+ }
+ }
+ }
+
+ return -1;
+}
+
+const char *
+ks_action_to_string(enum ks_action action)
+{
+ switch(action)
+ {
+ case KS_UNKNOWN: return "UNKNOWN";
+ case KS_GET: return "GET";
+ case KS_GETNAME: return "GETNAME";
+ case KS_SEND: return "SEND";
+ case KS_SEARCH: return "SEARCH";
+ }
+
+ return "?";
+}
+
+/* Canonicalize CRLF to just LF by stripping CRs. This actually makes
+ sense, since on Unix-like machines LF is correct, and on win32-like
+ machines, our output buffer is opened in textmode and will
+ re-canonicalize line endings back to CRLF. Since we only need to
+ handle armored keys, we don't have to worry about odd cases like
+ CRCRCR and the like. */
+
+void
+print_nocr(FILE *stream,const char *str)
+{
+ while(*str)
+ {
+ if(*str!='\r')
+ fputc(*str,stream);
+ str++;
+ }
+}
+
+enum ks_search_type
+classify_ks_search(const char **search)
+{
+ switch(**search)
+ {
+ case '*':
+ (*search)++;
+ return KS_SEARCH_SUBSTR;
+ case '=':
+ (*search)++;
+ return KS_SEARCH_EXACT;
+ case '<':
+ (*search)++;
+ return KS_SEARCH_MAIL;
+ case '@':
+ (*search)++;
+ return KS_SEARCH_MAILSUB;
+ case '0':
+ if((*search)[1]=='x')
+ {
+ if(strlen(*search)==10
+ && strspn(*search,"abcdefABCDEF1234567890x")==10)
+ {
+ (*search)+=2;
+ return KS_SEARCH_KEYID_SHORT;
+ }
+ else if(strlen(*search)==18
+ && strspn(*search,"abcdefABCDEF1234567890x")==18)
+ {
+ (*search)+=2;
+ return KS_SEARCH_KEYID_LONG;
+ }
+ }
+ /* fall through */
+ default:
+ return KS_SEARCH_SUBSTR;
+ }
+}
+
+int
+curl_err_to_gpg_err(CURLcode error)
+{
+ switch(error)
+ {
+ case CURLE_OK: return KEYSERVER_OK;
+ case CURLE_UNSUPPORTED_PROTOCOL: return KEYSERVER_SCHEME_NOT_FOUND;
+ case CURLE_COULDNT_CONNECT: return KEYSERVER_UNREACHABLE;
+ case CURLE_FTP_COULDNT_RETR_FILE: return KEYSERVER_KEY_NOT_FOUND;
+ default: return KEYSERVER_INTERNAL_ERROR;
+ }
+}
+
+#define B64 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
+
+static void
+curl_armor_writer(const unsigned char *buf,size_t size,void *cw_ctx)
+{
+ struct curl_writer_ctx *ctx=cw_ctx;
+ size_t idx=0;
+
+ while(idx<size)
+ {
+ for(;ctx->armor_remaining<3 && idx<size;ctx->armor_remaining++,idx++)
+ ctx->armor_ctx[ctx->armor_remaining]=buf[idx];
+
+ if(ctx->armor_remaining==3)
+ {
+ /* Top 6 bytes of ctx->armor_ctx[0] */
+ fputc(B64[(ctx->armor_ctx[0]>>2)&0x3F],ctx->stream);
+ /* Bottom 2 bytes of ctx->armor_ctx[0] and top 4 bytes of
+ ctx->armor_ctx[1] */
+ fputc(B64[(((ctx->armor_ctx[0]<<4)&0x30)
+ |((ctx->armor_ctx[1]>>4)&0x0F))&0x3F],ctx->stream);
+ /* Bottom 4 bytes of ctx->armor_ctx[1] and top 2 bytes of
+ ctx->armor_ctx[2] */
+ fputc(B64[(((ctx->armor_ctx[1]<<2)&0x3C)
+ |((ctx->armor_ctx[2]>>6)&0x03))&0x3F],ctx->stream);
+ /* Bottom 6 bytes of ctx->armor_ctx[2] */
+ fputc(B64[(ctx->armor_ctx[2]&0x3F)],ctx->stream);
+
+ ctx->linelen+=4;
+ if(ctx->linelen>=70)
+ {
+ fputc('\n',ctx->stream);
+ ctx->linelen=0;
+ }
+
+ ctx->armor_remaining=0;
+ }
+ }
+
+}
+
+size_t
+curl_writer(const void *ptr,size_t size,size_t nmemb,void *cw_ctx)
+{
+ struct curl_writer_ctx *ctx=cw_ctx;
+ const char *buf=ptr;
+ size_t i;
+
+ if(!ctx->flags.initialized)
+ {
+ if(size*nmemb==0)
+ return 0;
+
+ /* The object we're fetching is in binary form */
+ if(*buf&0x80)
+ {
+ ctx->flags.armor=1;
+ fprintf(ctx->stream,BEGIN"\n\n");
+ }
+ else
+ ctx->marker=BEGIN;
+
+ ctx->flags.initialized=1;
+ }
+
+ if(ctx->flags.armor)
+ curl_armor_writer(ptr,size*nmemb,cw_ctx);
+ else
+ {
+ /* scan the incoming data for our marker */
+ for(i=0;!ctx->flags.done && i<(size*nmemb);i++)
+ {
+ if(buf[i]==ctx->marker[ctx->markeridx])
+ {
+ ctx->markeridx++;
+ if(ctx->marker[ctx->markeridx]=='\0')
+ {
+ if(ctx->flags.begun)
+ ctx->flags.done=1;
+ else
+ {
+ /* We've found the BEGIN marker, so now we're
+ looking for the END marker. */
+ ctx->flags.begun=1;
+ ctx->marker=END;
+ ctx->markeridx=0;
+ fprintf(ctx->stream,BEGIN);
+ continue;
+ }
+ }
+ }
+ else
+ ctx->markeridx=0;
+
+ if(ctx->flags.begun)
+ {
+ /* Canonicalize CRLF to just LF by stripping CRs. This
+ actually makes sense, since on Unix-like machines LF
+ is correct, and on win32-like machines, our output
+ buffer is opened in textmode and will re-canonicalize
+ line endings back to CRLF. Since this code is just
+ for handling armored keys, we don't have to worry
+ about odd cases like CRCRCR and the like. */
+
+ if(buf[i]!='\r')
+ fputc(buf[i],ctx->stream);
+ }
+ }
+ }
+
+ return size*nmemb;
+}
+
+void
+curl_writer_finalize(struct curl_writer_ctx *ctx)
+{
+ if(ctx->flags.armor)
+ {
+ if(ctx->armor_remaining==2)
+ {
+ /* Top 6 bytes of ctx->armorctx[0] */
+ fputc(B64[(ctx->armor_ctx[0]>>2)&0x3F],ctx->stream);
+ /* Bottom 2 bytes of ctx->armor_ctx[0] and top 4 bytes of
+ ctx->armor_ctx[1] */
+ fputc(B64[(((ctx->armor_ctx[0]<<4)&0x30)
+ |((ctx->armor_ctx[1]>>4)&0x0F))&0x3F],ctx->stream);
+ /* Bottom 4 bytes of ctx->armor_ctx[1] */
+ fputc(B64[((ctx->armor_ctx[1]<<2)&0x3C)],ctx->stream);
+ /* Pad */
+ fputc('=',ctx->stream);
+ }
+ else if(ctx->armor_remaining==1)
+ {
+ /* Top 6 bytes of ctx->armor_ctx[0] */
+ fputc(B64[(ctx->armor_ctx[0]>>2)&0x3F],ctx->stream);
+ /* Bottom 2 bytes of ctx->armor_ctx[0] */
+ fputc(B64[((ctx->armor_ctx[0]<<4)&0x30)],ctx->stream);
+ /* Pad */
+ fputc('=',ctx->stream);
+ /* Pad */
+ fputc('=',ctx->stream);
+ }
+
+ fprintf(ctx->stream,"\n"END);
+ ctx->flags.done=1;
+ }
+}