* ksutil.h, ksutil.c (parse_ks_options): New keyserver-option
[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   _exit(KEYSERVER_TIMEOUT);
50 }
51
52 unsigned int
53 set_timeout(unsigned int seconds)
54 {
55   return alarm(seconds);
56 }
57
58 int
59 register_timeout(void)
60 {
61 #if defined(HAVE_SIGACTION) && defined(HAVE_STRUCT_SIGACTION)
62   struct sigaction act;
63
64   act.sa_handler=catch_alarm;
65   sigemptyset(&act.sa_mask);
66   act.sa_flags=0;
67   return sigaction(SIGALRM,&act,NULL);
68 #else 
69   if(signal(SIGALRM,catch_alarm)==SIG_ERR)
70     return -1;
71   else
72     return 0;
73 #endif
74 }
75
76 #endif /* !HAVE_DOSISH_SYSTEM */
77
78 struct ks_options *
79 init_ks_options(void)
80 {
81   struct ks_options *opt;
82
83   opt=calloc(1,sizeof(struct ks_options));
84
85   if(opt)
86     {
87       opt->action=KS_UNKNOWN;
88       opt->flags.check_cert=1;
89       opt->timeout=DEFAULT_KEYSERVER_TIMEOUT;
90       opt->path=strdup("/");
91       if(!opt->path)
92         {
93           free(opt);
94           opt=NULL;
95         }
96     }
97
98   return opt;
99 }
100
101 void
102 free_ks_options(struct ks_options *opt)
103 {
104   if(opt)
105     {
106       free(opt->host);
107       free(opt->port);
108       free(opt->scheme);
109       free(opt->auth);
110       free(opt->path);
111       free(opt->opaque);
112       free(opt->ca_cert_file);
113       free(opt);
114     }
115 }
116
117 /* Returns 0 if we "ate" the line.  Returns >0, a KEYSERVER_ error
118    code if that error applies.  Returns -1 if we did not match the
119    line at all. */
120 int
121 parse_ks_options(char *line,struct ks_options *opt)
122 {
123   int version;
124   char command[MAX_COMMAND+1];
125   char host[MAX_HOST+1];
126   char port[MAX_PORT+1];
127   char scheme[MAX_SCHEME+1];
128   char auth[MAX_AUTH+1];
129   char path[URLMAX_PATH+1];
130   char opaque[MAX_OPAQUE+1];
131   char option[MAX_OPTION+1];
132
133   if(line[0]=='#')
134     return 0;
135
136   if(sscanf(line,"COMMAND %" MKSTRING(MAX_COMMAND) "s\n",command)==1)
137     {
138       command[MAX_COMMAND]='\0';
139
140       if(strcasecmp(command,"get")==0)
141         opt->action=KS_GET;
142       else if(strcasecmp(command,"send")==0)
143         opt->action=KS_SEND;
144       else if(strcasecmp(command,"search")==0)
145         opt->action=KS_SEARCH;
146
147       return 0;
148     }
149
150   if(sscanf(line,"HOST %" MKSTRING(MAX_HOST) "s\n",host)==1)
151     {
152       host[MAX_HOST]='\0';
153       free(opt->host);
154       opt->host=strdup(host);
155       if(!opt->host)
156         return KEYSERVER_NO_MEMORY;
157       return 0;
158     }
159
160   if(sscanf(line,"PORT %" MKSTRING(MAX_PORT) "s\n",port)==1)
161     {
162       port[MAX_PORT]='\0';
163       free(opt->port);
164       opt->port=strdup(port);
165       if(!opt->port)
166         return KEYSERVER_NO_MEMORY;
167       return 0;
168     }
169
170   if(sscanf(line,"SCHEME %" MKSTRING(MAX_SCHEME) "s\n",scheme)==1)
171     {
172       scheme[MAX_SCHEME]='\0';
173       free(opt->scheme);
174       opt->scheme=strdup(scheme);
175       if(!opt->scheme)
176         return KEYSERVER_NO_MEMORY;
177       return 0;
178     }
179
180   if(sscanf(line,"AUTH %" MKSTRING(MAX_AUTH) "s\n",auth)==1)
181     {
182       auth[MAX_AUTH]='\0';
183       free(opt->auth);
184       opt->auth=strdup(auth);
185       if(!opt->auth)
186         return KEYSERVER_NO_MEMORY;
187       return 0;
188     }
189
190   if(sscanf(line,"PATH %" MKSTRING(URLMAX_PATH) "s\n",path)==1)
191     {
192       path[URLMAX_PATH]='\0';
193       free(opt->path);
194       opt->path=strdup(path);
195       if(!opt->path)
196         return KEYSERVER_NO_MEMORY;
197       return 0;
198     }
199
200   if(sscanf(line,"OPAQUE %" MKSTRING(MAX_OPAQUE) "s\n",opaque)==1)
201     {
202       opaque[MAX_OPAQUE]='\0';
203       free(opt->opaque);
204       opt->opaque=strdup(opaque);
205       if(!opt->opaque)
206         return KEYSERVER_NO_MEMORY;
207       return 0;
208     }
209
210   if(sscanf(line,"VERSION %d\n",&version)==1)
211     {
212       if(version!=KEYSERVER_PROTO_VERSION)
213         return KEYSERVER_VERSION_ERROR;
214
215       return 0;
216     }
217
218   if(sscanf(line,"OPTION %" MKSTRING(MAX_OPTION) "[^\n]\n",option)==1)
219     {
220       int no=0;
221       char *start=&option[0];
222
223       option[MAX_OPTION]='\0';
224
225       if(strncasecmp(option,"no-",3)==0)
226         {
227           no=1;
228           start=&option[3];
229         }
230
231       if(strncasecmp(start,"verbose",7)==0)
232         {
233           if(no)
234             opt->verbose=0;
235           else if(start[7]=='=')
236             opt->verbose=atoi(&start[8]);
237           else
238             opt->verbose++;
239         }
240       else if(strcasecmp(start,"include-disabled")==0)
241         {
242           if(no)
243             opt->flags.include_disabled=0;
244           else
245             opt->flags.include_disabled=1;
246         }
247       else if(strcasecmp(start,"include-revoked")==0)
248         {
249           if(no)
250             opt->flags.include_revoked=0;
251           else
252             opt->flags.include_revoked=1;
253         }
254       else if(strcasecmp(start,"include-subkeys")==0)
255         {
256           if(no)
257             opt->flags.include_subkeys=0;
258           else
259             opt->flags.include_subkeys=1;
260         }
261       else if(strcasecmp(start,"check-cert")==0)
262         {
263           if(no)
264             opt->flags.check_cert=0;
265           else
266             opt->flags.check_cert=1;
267         }
268       else if(strncasecmp(start,"debug",5)==0)
269         {
270           if(no)
271             opt->debug=0;
272           else if(start[5]=='=')
273             opt->debug=atoi(&start[6]);
274           else if(start[5]=='\0')
275             opt->debug=1;
276         }
277       else if(strncasecmp(start,"timeout",7)==0)
278         {
279           if(no)
280             opt->timeout=0;
281           else if(start[7]=='=')
282             opt->timeout=atoi(&start[8]);
283           else if(start[7]=='\0')
284             opt->timeout=DEFAULT_KEYSERVER_TIMEOUT;
285         }
286       else if(strncasecmp(start,"ca-cert-file",12)==0)
287         {
288           if(no)
289             {
290               free(opt->ca_cert_file);
291               opt->ca_cert_file=NULL;
292             }
293           else if(start[12]=='=')
294             {
295               free(opt->ca_cert_file);
296               opt->ca_cert_file=strdup(&start[13]);
297               if(!opt->ca_cert_file)
298                 return KEYSERVER_NO_MEMORY;
299             }
300         }
301       else if(strcasecmp(start,"exact-email")==0
302               || strcasecmp(start,"exact-mail")==0)
303         {
304           if(no)
305             opt->flags.exact_email=0;
306           else
307             opt->flags.exact_email=1;
308         }
309     }
310
311   return -1;
312 }
313
314 const char *
315 ks_action_to_string(enum ks_action action)
316 {
317   switch(action)
318     {
319     case KS_UNKNOWN: return "UNKNOWN";
320     case KS_GET:     return "GET";
321     case KS_SEND:    return "SEND";
322     case KS_SEARCH:  return "SEARCH";
323     }
324
325   return "?";
326 }
327
328 /* Canonicalize CRLF to just LF by stripping CRs.  This actually makes
329    sense, since on Unix-like machines LF is correct, and on win32-like
330    machines, our output buffer is opened in textmode and will
331    re-canonicalize line endings back to CRLF.  Since we only need to
332    handle armored keys, we don't have to worry about odd cases like
333    CRCRCR and the like. */
334
335 void
336 print_nocr(FILE *stream,const char *str)
337 {
338   while(*str)
339     {
340       if(*str!='\r')
341         fputc(*str,stream);
342       str++;
343     }
344 }
345
346 #if defined (HAVE_LIBCURL) || defined (FAKE_CURL)
347 int
348 curl_err_to_gpg_err(CURLcode error)
349 {
350   switch(error)
351     {
352     case CURLE_FTP_COULDNT_RETR_FILE: return KEYSERVER_KEY_NOT_FOUND;
353     case CURLE_UNSUPPORTED_PROTOCOL:  return KEYSERVER_SCHEME_NOT_FOUND;
354     default: return KEYSERVER_INTERNAL_ERROR;
355     }
356 }
357
358 size_t
359 curl_writer(const void *ptr,size_t size,size_t nmemb,void *cw_ctx)
360 {
361   struct curl_writer_ctx *ctx=cw_ctx;
362   const char *buf=ptr;
363   size_t i;
364
365   if(!ctx->initialized)
366     {
367       ctx->marker=BEGIN;
368       ctx->initialized=1;
369     }
370
371   /* scan the incoming data for our marker */
372   for(i=0;!ctx->done && i<(size*nmemb);i++)
373     {
374       if(buf[i]==ctx->marker[ctx->markeridx])
375         {
376           ctx->markeridx++;
377           if(ctx->marker[ctx->markeridx]=='\0')
378             {
379               if(ctx->begun)
380                 ctx->done=1;
381               else
382                 {
383                   /* We've found the BEGIN marker, so now we're looking
384                      for the END marker. */
385                   ctx->begun=1;
386                   ctx->marker=END;
387                   ctx->markeridx=0;
388                   fprintf(ctx->stream,BEGIN);
389                   continue;
390                 }
391             }
392         }
393       else
394         ctx->markeridx=0;
395
396       if(ctx->begun)
397         {
398           /* Canonicalize CRLF to just LF by stripping CRs.  This
399              actually makes sense, since on Unix-like machines LF is
400              correct, and on win32-like machines, our output buffer is
401              opened in textmode and will re-canonicalize line endings
402              back to CRLF.  Since we only need to handle armored keys,
403              we don't have to worry about odd cases like CRCRCR and
404              the like. */
405
406           if(buf[i]!='\r')
407             fputc(buf[i],ctx->stream);
408         }
409     }
410
411   return size*nmemb;
412 }
413 #endif