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/>.
32 # ifndef HAVE_ADNS_FREE
33 # define adns_free free
37 #define INCLUDED_BY_MAIN_MODULE 1
39 #include "keyserver.h"
43 #define PGM "gpgkeys_kdns"
45 /* getopt(3) requires declarion of some global variables. */
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. */
76 get_key (adns_state adns_ctx
, char *address
)
78 int ret
= KEYSERVER_INTERNAL_ERROR
;
81 adns_answer
*answer
= NULL
;
82 const unsigned char *data
;
84 struct b64state b64state
;
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
;
94 name
= xtrymalloc (strlen (address
) + strlen (kdns_at_repl
)
95 + 1 + strlen (kdns_root
) + 1);
98 memcpy (name
, address
, domain
- address
);
99 p
= stpcpy (name
+ (domain
-address
), ".");
101 p
= stpcpy (stpcpy (p
, kdns_at_repl
), ".");
102 p
= stpcpy (p
, domain
+1);
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),
114 fprintf (console
, PGM
": DNS query failed: %s\n", strerror (errno
));
115 ret
= KEYSERVER_KEY_NOT_FOUND
;
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
;
126 datalen
= answer
->rrs
.byteblock
->len
;
127 data
= answer
->rrs
.byteblock
->data
;
129 if ( opt
->debug
> 1 )
133 fprintf (console
, "got %d bytes of data:", datalen
);
134 for (i
=0; i
< datalen
; i
++)
137 fprintf (console
, "\n%08x ", i
);
138 fprintf (console
, "%02x", data
[i
]);
140 putc ('\n', console
);
144 fprintf (console
, PGM
": error: truncated CERT record\n");
145 ret
= KEYSERVER_KEY_NOT_FOUND
;
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). */
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
;
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. */
169 fprintf (console
, PGM
": CERT type %d ignored\n", (data
[0] <<8|data
[1]));
170 ret
= KEYSERVER_KEY_NOT_FOUND
;
174 ret
= 0; /* All fine. */
178 fprintf (output
, "\nNAME %s FAILED %d\n", address
, ret
);
180 fprintf (output
, "\nNAME %s END\n", address
);
187 /* Print some help. */
191 fputs (PGM
" (GnuPG) " VERSION
"\n\n", fp
);
194 " -o\toutput to this file\n"
196 fputs ("This keyserver helper accepts URLs of the form:\n"
197 " kdns://[NAMESERVER]/[ROOT][?at=STRING]\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"
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"
214 main (int argc
, char *argv
[])
217 int ret
= KEYSERVER_INTERNAL_ERROR
;
219 struct keylist
*keylist
= NULL
;
220 struct keylist
**keylist_tail
= &keylist
;
221 struct keylist
*akey
;
223 adns_state adns_ctx
= NULL
;
224 adns_initflags my_adns_initflags
= MY_ADNS_INITFLAGS
;
227 /* The defaults for the KDNS name mangling. */
233 /* Kludge to implement standard GNU options. */
234 if (argc
> 1 && !strcmp (argv
[1], "--version"))
236 fputs (PGM
" (GnuPG) " VERSION
"\n", stdout
);
239 else if (argc
> 1 && !strcmp (argv
[1], "--help"))
245 while ( (arg
= getopt (argc
, argv
, "hVo:")) != -1 )
250 printf ("%d\n%s\n", KEYSERVER_PROTO_VERSION
, VERSION
);
254 output
= fopen (optarg
,"w");
257 fprintf (console
, PGM
": cannot open output file `%s': %s\n",
258 optarg
, strerror(errno
) );
259 return KEYSERVER_INTERNAL_ERROR
;
272 input
= fopen (argv
[optind
], "r");
275 fprintf (console
, PGM
": cannot open input file `%s': %s\n",
276 argv
[optind
], strerror(errno
) );
277 return KEYSERVER_INTERNAL_ERROR
;
287 opt
= init_ks_options();
289 return KEYSERVER_NO_MEMORY
;
291 /* Get the command and info block */
292 while ( fgets(line
,MAX_LINE
,input
) )
299 err
= parse_ks_options (line
, opt
);
309 if (opt
->timeout
&& register_timeout() == -1 )
311 fprintf (console
, PGM
": unable to register timeout handler\n");
312 return KEYSERVER_INTERNAL_ERROR
;
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
== '/')
324 kdns_root
= opt
->path
+1;
325 p
= strchr (opt
->path
+1, '?');
331 pend
= strchr (p
, '&');
334 if (!strncmp (p
, "at=", 3))
336 else if (!strncmp (p
, "usevc=", 6))
337 kdns_usevc
= !!atoi (p
+6);
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
, "."))
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
);
358 my_adns_initflags
|= adns_if_debug
;
363 snprintf (cfgtext
, sizeof cfgtext
, "nameserver %s\n", opt
->host
);
364 tmprc
= adns_init_strcfg (&adns_ctx
, my_adns_initflags
, console
,cfgtext
);
367 tmprc
= adns_init (&adns_ctx
, my_adns_initflags
, console
);
370 fprintf (console
, PGM
": error initializing ADNS: %s\n",
375 if (opt
->action
== KS_GETNAME
)
377 while ( fgets (line
,MAX_LINE
,input
) )
379 if (line
[0]=='\n' || !line
[0] )
381 line
[strlen(line
)-1] = 0; /* Trim the trailing LF. */
383 akey
= xtrymalloc (sizeof *akey
);
387 PGM
": out of memory while building key list\n");
388 ret
= KEYSERVER_NO_MEMORY
;
391 assert (sizeof (akey
->str
) > strlen(line
));
392 strcpy (akey
->str
, line
);
394 *keylist_tail
= akey
;
395 keylist_tail
= &akey
->next
;
401 PGM
": this keyserver type only supports "
402 "key retrieval by name\n");
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)
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
) )
429 adns_finish (adns_ctx
);
432 akey
= keylist
->next
;
438 if (output
!= stdout
)
442 free_ks_options (opt
);