Translation fix
[gnupg.git] / keyserver / gpgkeys_kdns.c
blob5979b0668e4c866b3a51a815f1aac1cf888237be
1 /* gpgkeys_kdns.c - Fetch a key via the GnuPG specific KDNS scheme.
2 * Copyright (C) 2008 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
6 * GnuPG is free software; you can redistribute it and/or modify it
7 * 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/>.
20 #include <config.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #ifdef HAVE_GETOPT_H
27 # include <getopt.h>
28 #endif
29 #include <assert.h>
30 #ifdef HAVE_ADNS_H
31 # include <adns.h>
32 # ifndef HAVE_ADNS_FREE
33 # define adns_free free
34 # endif
35 #endif
37 #define INCLUDED_BY_MAIN_MODULE 1
38 #include "util.h"
39 #include "keyserver.h"
40 #include "ksutil.h"
42 /* Our own name. */
43 #define PGM "gpgkeys_kdns"
45 /* getopt(3) requires declarion of some global variables. */
46 extern char *optarg;
47 extern int optind;
49 /* Convenience variables usually intialized withn std{in,out,err}. */
50 static FILE *input, *output, *console;
52 /* Standard keyserver module options. */
53 static struct ks_options *opt;
55 /* The flags we pass to adns_init: Do not allow any environment
56 variables and for now enable debugging. */
57 #define MY_ADNS_INITFLAGS (adns_if_noenv)
60 /* ADNS has no support for CERT yes. */
61 #define my_adns_r_cert 37
63 /* The root of the KDNS tree. */
64 static const char *kdns_root;
66 /* The replacement string for the at sign. */
67 static const char *kdns_at_repl;
69 /* Flag indicating that a TCP conenction should be used. */
70 static int kdns_usevc;
74 /* Retrieve one key. ADDRESS should be an RFC-2822 addr-spec. */
75 static int
76 get_key (adns_state adns_ctx, char *address)
78 int ret = KEYSERVER_INTERNAL_ERROR;
79 const char *domain;
80 char *name = NULL;
81 adns_answer *answer = NULL;
82 const unsigned char *data;
83 int datalen;
84 struct b64state b64state;
85 char *p;
87 domain = strrchr (address, '@');
88 if (!domain || domain == address || !domain[1])
90 fprintf (console, PGM": invalid mail address `%s'\n", address);
91 ret = KEYSERVER_GENERAL_ERROR;
92 goto leave;
94 name = xtrymalloc (strlen (address) + strlen (kdns_at_repl)
95 + 1 + strlen (kdns_root) + 1);
96 if (!name)
97 goto leave;
98 memcpy (name, address, domain - address);
99 p = stpcpy (name + (domain-address), ".");
100 if (*kdns_at_repl)
101 p = stpcpy (stpcpy (p, kdns_at_repl), ".");
102 p = stpcpy (p, domain+1);
103 if (*kdns_root)
104 strcpy (stpcpy (p, "."), kdns_root);
106 fprintf (output,"NAME %s BEGIN\n", address);
107 if (opt->verbose > 2)
108 fprintf(console, PGM": looking up `%s'\n", name);
110 if ( adns_synchronous (adns_ctx, name, (adns_r_unknown | my_adns_r_cert),
111 adns_qf_quoteok_query|(kdns_usevc?adns_qf_usevc:0),
112 &answer) )
114 fprintf (console, PGM": DNS query failed: %s\n", strerror (errno));
115 ret = KEYSERVER_KEY_NOT_FOUND;
116 goto leave;
118 if (answer->status != adns_s_ok)
120 fprintf (console, PGM": DNS query returned: %s (%s)\n",
121 adns_strerror (answer->status),
122 adns_errabbrev (answer->status));
123 ret = KEYSERVER_KEY_NOT_FOUND;
124 goto leave;
126 datalen = answer->rrs.byteblock->len;
127 data = answer->rrs.byteblock->data;
129 if ( opt->debug > 1 )
131 int i;
133 fprintf (console, "got %d bytes of data:", datalen);
134 for (i=0; i < datalen; i++)
136 if (!(i % 32))
137 fprintf (console, "\n%08x ", i);
138 fprintf (console, "%02x", data[i]);
140 putc ('\n', console);
142 if ( datalen < 5 )
144 fprintf (console, PGM": error: truncated CERT record\n");
145 ret = KEYSERVER_KEY_NOT_FOUND;
146 goto leave;
149 switch ( ((data[0]<<8)|data[1]) )
151 case 3: /* CERT type is PGP. */
152 /* (key tag and algorithm fields are ignored for this CERT type). */
153 data += 5;
154 datalen -= 5;
155 if ( datalen < 11 )
157 /* Gpg checks for a minium length of 11, thus we do the same. */
158 fprintf (console, PGM": error: OpenPGP data to short\n");
159 ret = KEYSERVER_KEY_NOT_FOUND;
160 goto leave;
162 if (b64enc_start (&b64state, output, "PGP PUBLIC KEY BLOCK")
163 || b64enc_write (&b64state, data, datalen)
164 || b64enc_finish (&b64state))
165 goto leave; /* Oops, base64 encoder failed. */
166 break;
168 default:
169 fprintf (console, PGM": CERT type %d ignored\n", (data[0] <<8|data[1]));
170 ret = KEYSERVER_KEY_NOT_FOUND;
171 goto leave;
174 ret = 0; /* All fine. */
176 leave:
177 if (ret)
178 fprintf (output, "\nNAME %s FAILED %d\n", address, ret);
179 else
180 fprintf (output, "\nNAME %s END\n", address);
181 adns_free (answer);
182 xfree (name);
183 return ret;
187 /* Print some help. */
188 static void
189 show_help (FILE *fp)
191 fputs (PGM" (GnuPG) " VERSION"\n\n", fp);
192 fputs (" -h\thelp\n"
193 " -V\tversion\n"
194 " -o\toutput to this file\n"
195 "\n", fp);
196 fputs ("This keyserver helper accepts URLs of the form:\n"
197 " kdns://[NAMESERVER]/[ROOT][?at=STRING]\n"
198 "with\n"
199 " NAMESERVER used for queries (default: system standard)\n"
200 " ROOT a DNS name appended to the query (default: none)\n"
201 " STRING a string to replace the '@' (default: \".\")\n"
202 "If a long answer is expected add the parameter \"usevc=1\".\n"
203 "\n", fp);
204 fputs ("Example: A query for \"hacker@gnupg.org\" with\n"
205 " kdns://10.0.0.1/example.net?at=_key&usevc=1\n"
206 "setup as --auto-key-lookup does a CERT record query\n"
207 "with type PGP on the nameserver 10.0.0.1 for\n"
208 " hacker._key_.gnupg.org.example.net\n"
209 "\n", fp);
214 main (int argc, char *argv[])
216 int arg;
217 int ret = KEYSERVER_INTERNAL_ERROR;
218 char line[MAX_LINE];
219 struct keylist *keylist = NULL;
220 struct keylist **keylist_tail = &keylist;
221 struct keylist *akey;
222 int failed = 0;
223 adns_state adns_ctx = NULL;
224 adns_initflags my_adns_initflags = MY_ADNS_INITFLAGS;
225 int tmprc;
227 /* The defaults for the KDNS name mangling. */
228 kdns_root = "";
229 kdns_at_repl = "";
231 console = stderr;
233 /* Kludge to implement standard GNU options. */
234 if (argc > 1 && !strcmp (argv[1], "--version"))
236 fputs (PGM" (GnuPG) " VERSION"\n", stdout);
237 return 0;
239 else if (argc > 1 && !strcmp (argv[1], "--help"))
241 show_help (stdout);
242 return 0;
245 while ( (arg = getopt (argc, argv, "hVo:")) != -1 )
247 switch(arg)
249 case 'V':
250 printf ("%d\n%s\n", KEYSERVER_PROTO_VERSION, VERSION);
251 return KEYSERVER_OK;
253 case 'o':
254 output = fopen (optarg,"w");
255 if (!output)
257 fprintf (console, PGM": cannot open output file `%s': %s\n",
258 optarg, strerror(errno) );
259 return KEYSERVER_INTERNAL_ERROR;
261 break;
263 case 'h':
264 default:
265 show_help (console);
266 return KEYSERVER_OK;
270 if (argc > optind)
272 input = fopen (argv[optind], "r");
273 if (!input)
275 fprintf (console, PGM": cannot open input file `%s': %s\n",
276 argv[optind], strerror(errno) );
277 return KEYSERVER_INTERNAL_ERROR;
281 if (!input)
282 input = stdin;
284 if (!output)
285 output = stdout;
287 opt = init_ks_options();
288 if(!opt)
289 return KEYSERVER_NO_MEMORY;
291 /* Get the command and info block */
292 while ( fgets(line,MAX_LINE,input) )
294 int err;
296 if(line[0]=='\n')
297 break;
299 err = parse_ks_options (line, opt);
300 if (err > 0)
302 ret = err;
303 goto leave;
305 else if (!err)
306 continue;
309 if (opt->timeout && register_timeout() == -1 )
311 fprintf (console, PGM": unable to register timeout handler\n");
312 return KEYSERVER_INTERNAL_ERROR;
315 if (opt->verbose)
317 fprintf (console, PGM": HOST=%s\n", opt->host? opt->host:"(none)");
318 fprintf (console, PGM": PATH=%s\n", opt->path? opt->path:"(none)");
320 if (opt->path && *opt->path == '/')
322 char *p, *pend;
324 kdns_root = opt->path+1;
325 p = strchr (opt->path+1, '?');
326 if (p)
328 *p++ = 0;
331 pend = strchr (p, '&');
332 if (pend)
333 *pend++ = 0;
334 if (!strncmp (p, "at=", 3))
335 kdns_at_repl = p+3;
336 else if (!strncmp (p, "usevc=", 6))
337 kdns_usevc = !!atoi (p+6);
339 while ((p = pend));
342 if (strchr (kdns_root, '/'))
344 fprintf (console, PGM": invalid character in KDNS root\n");
345 return KEYSERVER_GENERAL_ERROR;
347 if (!strcmp (kdns_at_repl, "."))
348 kdns_at_repl = "";
350 if (opt->verbose)
352 fprintf (console, PGM": kdns_root=%s\n", kdns_root);
353 fprintf (console, PGM": kdns_at=%s\n", kdns_at_repl);
354 fprintf (console, PGM": kdns_usevc=%d\n", kdns_usevc);
357 if (opt->debug)
358 my_adns_initflags |= adns_if_debug;
359 if (opt->host)
361 char cfgtext[200];
363 snprintf (cfgtext, sizeof cfgtext, "nameserver %s\n", opt->host);
364 tmprc = adns_init_strcfg (&adns_ctx, my_adns_initflags, console,cfgtext);
366 else
367 tmprc = adns_init (&adns_ctx, my_adns_initflags, console);
368 if (tmprc)
370 fprintf (console, PGM": error initializing ADNS: %s\n",
371 strerror (errno));
372 goto leave;
375 if (opt->action == KS_GETNAME)
377 while ( fgets (line,MAX_LINE,input) )
379 if (line[0]=='\n' || !line[0] )
380 break;
381 line[strlen(line)-1] = 0; /* Trim the trailing LF. */
383 akey = xtrymalloc (sizeof *akey);
384 if (!akey)
386 fprintf (console,
387 PGM": out of memory while building key list\n");
388 ret = KEYSERVER_NO_MEMORY;
389 goto leave;
391 assert (sizeof (akey->str) > strlen(line));
392 strcpy (akey->str, line);
393 akey->next = NULL;
394 *keylist_tail = akey;
395 keylist_tail = &akey->next;
398 else
400 fprintf (console,
401 PGM": this keyserver type only supports "
402 "key retrieval by name\n");
403 goto leave;
406 /* Send the response */
407 fprintf (output, "VERSION %d\n", KEYSERVER_PROTO_VERSION);
408 fprintf (output, "PROGRAM %s\n\n", VERSION);
410 if (opt->verbose > 1)
412 if (opt->opaque)
413 fprintf (console, "User:\t\t%s\n", opt->opaque);
414 fprintf (console, "Command:\tGET\n");
417 for (akey = keylist; akey; akey = akey->next)
419 set_timeout (opt->timeout);
420 if ( get_key (adns_ctx, akey->str) )
421 failed++;
423 if (!failed)
424 ret = KEYSERVER_OK;
427 leave:
428 if (adns_ctx)
429 adns_finish (adns_ctx);
430 while (keylist)
432 akey = keylist->next;
433 xfree (keylist);
434 keylist = akey;
436 if (input != stdin)
437 fclose (input);
438 if (output != stdout)
439 fclose (output);
440 kdns_root = "";
441 kdns_at_repl = ".";
442 free_ks_options (opt);
443 return ret;