mirror of
git://git.gnupg.org/gnupg.git
synced 2025-07-03 22:56:33 +02:00
Minor cleanups.
Implemented key helper kdns
This commit is contained in:
parent
ba63cfa79b
commit
86f35a55d0
17 changed files with 768 additions and 27 deletions
|
@ -1,3 +1,10 @@
|
|||
2008-04-07 Werner Koch <wk@g10code.com>
|
||||
|
||||
* gpgkeys_kdns.c: New.
|
||||
* Makefile.am: Support kdns.
|
||||
|
||||
* no-libgcrypt.c (gcry_strdup): Fix. It was not used.
|
||||
|
||||
2008-03-25 Werner Koch <wk@g10code.com>
|
||||
|
||||
* gpgkeys_ldap.c (build_attrs): Take care of char defaulting to
|
||||
|
|
|
@ -20,7 +20,8 @@
|
|||
# to gpg2keys_foo to allow for a non-conflicting installation of
|
||||
# gnupg1 and gnupg2. Having the same names for the helpers would
|
||||
# otherwise lead to trouble when to uninstall one of them.
|
||||
EXTRA_PROGRAMS = gpg2keys_ldap gpg2keys_hkp gpg2keys_finger gpg2keys_curl
|
||||
EXTRA_PROGRAMS = gpg2keys_ldap gpg2keys_hkp gpg2keys_finger gpg2keys_curl \
|
||||
gpg2keys_kdns
|
||||
EXTRA_SCRIPTS = gpg2keys_mailto
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/gl -I$(top_srcdir)/common -I$(top_srcdir)/intl
|
||||
|
@ -30,7 +31,7 @@ AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(GPG_ERROR_CFLAGS)
|
|||
include $(top_srcdir)/am/cmacros.am
|
||||
|
||||
libexec_PROGRAMS = $(GPGKEYS_LDAP) $(GPGKEYS_HKP) $(GPGKEYS_FINGER) \
|
||||
$(GPGKEYS_CURL)
|
||||
$(GPGKEYS_CURL) $(GPGKEYS_KDNS)
|
||||
libexec_SCRIPTS = $(GPGKEYS_MAILTO)
|
||||
noinst_SCRIPTS = gpg2keys_test
|
||||
|
||||
|
@ -47,6 +48,11 @@ gpg2keys_finger_CPPFLAGS = $(AM_CPPFLAGS)
|
|||
gpg2keys_finger_LDADD = $(common_libs) $(GPG_ERROR_LIBS) \
|
||||
$(NETLIBS) $(other_libs)
|
||||
|
||||
gpg2keys_kdns_SOURCES = gpgkeys_kdns.c ksutil.c ksutil.h no-libgcrypt.c
|
||||
gpg2keys_kdns_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
gpg2keys_kdns_LDADD = $(common_libs) $(GPG_ERROR_LIBS) \
|
||||
$(ADNSLIBS) $(NETLIBS) $(other_libs)
|
||||
|
||||
|
||||
gpg2keys_curl_SOURCES = gpgkeys_curl.c ksutil.c ksutil.h no-libgcrypt.c
|
||||
gpg2keys_hkp_SOURCES = gpgkeys_hkp.c ksutil.c ksutil.h no-libgcrypt.c
|
||||
|
|
435
keyserver/gpgkeys_kdns.c
Normal file
435
keyserver/gpgkeys_kdns.c
Normal file
|
@ -0,0 +1,435 @@
|
|||
/* gpgkeys_kdns.c - Fetch a key via the GnuPG specific KDNS scheme.
|
||||
* Copyright (C) 2008 g10 Code GmbH
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#ifdef HAVE_GETOPT_H
|
||||
# include <getopt.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#ifdef HAVE_ADNS_H
|
||||
# include <adns.h>
|
||||
#endif
|
||||
|
||||
#define INCLUDED_BY_MAIN_MODULE 1
|
||||
#include "util.h"
|
||||
#include "keyserver.h"
|
||||
#include "ksutil.h"
|
||||
|
||||
/* Our own name. */
|
||||
#define PGM "gpgkeys_kdns"
|
||||
|
||||
/* getopt(3) requires declarion of some global variables. */
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
|
||||
/* Convenience variables usually intialized withn std{in,out,err}. */
|
||||
static FILE *input, *output, *console;
|
||||
|
||||
/* Standard keyserver module options. */
|
||||
static struct ks_options *opt;
|
||||
|
||||
/* The flags we pass to adns_init: Do not allow any environment
|
||||
variables and for now enable debugging. */
|
||||
#define MY_ADNS_INITFLAGS (adns_if_noenv)
|
||||
|
||||
|
||||
/* ADNS has no support for CERT yes. */
|
||||
#define my_adns_r_cert 37
|
||||
|
||||
/* The root of the KDNS tree. */
|
||||
static const char *kdns_root;
|
||||
|
||||
/* The replacement string for the at sign. */
|
||||
static const char *kdns_at_repl;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Retrieve one key. ADDRESS should be an RFC-2822 addr-spec. */
|
||||
static int
|
||||
get_key (adns_state adns_ctx, char *address)
|
||||
{
|
||||
int ret = KEYSERVER_INTERNAL_ERROR;
|
||||
const char *domain;
|
||||
char *name = NULL;
|
||||
adns_answer *answer = NULL;
|
||||
const unsigned char *data;
|
||||
int datalen;
|
||||
struct b64state b64state;
|
||||
char *p;
|
||||
|
||||
domain = strrchr (address, '@');
|
||||
if (!domain || domain == address || !domain[1])
|
||||
{
|
||||
fprintf (console, PGM": invalid mail address `%s'\n", address);
|
||||
ret = KEYSERVER_GENERAL_ERROR;
|
||||
goto leave;
|
||||
}
|
||||
name = xtrymalloc (strlen (address) + strlen (kdns_at_repl)
|
||||
+ 1 + strlen (kdns_root) + 1);
|
||||
if (!name)
|
||||
goto leave;
|
||||
memcpy (name, address, domain - address);
|
||||
p = stpcpy (name + (domain-address), ".");
|
||||
if (*kdns_at_repl)
|
||||
p = stpcpy (stpcpy (p, kdns_at_repl), ".");
|
||||
p = stpcpy (p, domain+1);
|
||||
if (*kdns_root)
|
||||
strcpy (stpcpy (p, "."), kdns_root);
|
||||
|
||||
fprintf (output,"NAME %s BEGIN\n", address);
|
||||
if (opt->verbose > 2)
|
||||
fprintf(console, PGM": looking up `%s'\n", name);
|
||||
|
||||
|
||||
if ( adns_synchronous (adns_ctx, name, (adns_r_unknown | my_adns_r_cert),
|
||||
adns_qf_quoteok_query,
|
||||
&answer) )
|
||||
{
|
||||
fprintf (console, PGM": DNS query failed: %s\n", strerror (errno));
|
||||
ret = KEYSERVER_KEY_NOT_FOUND;
|
||||
goto leave;
|
||||
}
|
||||
if (answer->status != adns_s_ok)
|
||||
{
|
||||
fprintf (console, PGM": DNS query returned: %s (%s)\n",
|
||||
adns_strerror (answer->status),
|
||||
adns_errabbrev (answer->status));
|
||||
ret = KEYSERVER_KEY_NOT_FOUND;
|
||||
goto leave;
|
||||
}
|
||||
datalen = answer->rrs.byteblock->len;
|
||||
data = answer->rrs.byteblock->data;
|
||||
|
||||
if ( opt->debug > 1 )
|
||||
{
|
||||
int i;
|
||||
|
||||
fprintf (console, "got %d bytes of data:", datalen);
|
||||
for (i=0; i < datalen; i++)
|
||||
{
|
||||
if (!(i % 32))
|
||||
fprintf (console, "\n%08x ", i);
|
||||
fprintf (console, "%02x", data[i]);
|
||||
}
|
||||
putc ('\n', console);
|
||||
}
|
||||
if ( datalen < 5 )
|
||||
{
|
||||
fprintf (console, PGM": error: truncated CERT record\n");
|
||||
ret = KEYSERVER_KEY_NOT_FOUND;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
switch ( ((data[0]<<8)|data[1]) )
|
||||
{
|
||||
case 3: /* CERT type is PGP. */
|
||||
/* (key tag and algorithm fields are ignored for this CERT type). */
|
||||
data += 5;
|
||||
datalen -= 5;
|
||||
if ( datalen < 11 )
|
||||
{
|
||||
/* Gpg checks for a minium length of 11, thus we do the same. */
|
||||
fprintf (console, PGM": error: OpenPGP data to short\n");
|
||||
ret = KEYSERVER_KEY_NOT_FOUND;
|
||||
goto leave;
|
||||
}
|
||||
if (b64enc_start (&b64state, output, "PGP PUBLIC KEY BLOCK")
|
||||
|| b64enc_write (&b64state, data, datalen)
|
||||
|| b64enc_finish (&b64state))
|
||||
goto leave; /* Oops, base64 encoder failed. */
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf (console, PGM": CERT type %d ignored\n", (data[0] <<8|data[1]));
|
||||
ret = KEYSERVER_KEY_NOT_FOUND;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
ret = 0; /* All fine. */
|
||||
|
||||
leave:
|
||||
if (ret)
|
||||
fprintf (output, "\nNAME %s FAILED %d\n", address, ret);
|
||||
else
|
||||
fprintf (output, "\nNAME %s END\n", address);
|
||||
free (answer); /* (Right, this is free and not xfree.) */
|
||||
xfree (name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Print some help. */
|
||||
static void
|
||||
show_help (FILE *fp)
|
||||
{
|
||||
fputs (PGM" (GnuPG) " VERSION"\n\n", fp);
|
||||
fputs (" -h\thelp\n"
|
||||
" -V\tversion\n"
|
||||
" -o\toutput to this file\n"
|
||||
"\n", fp);
|
||||
fputs ("This keyserver helper accepts URLs of the form:\n"
|
||||
" kdns://[NAMESERVER]/[ROOT][?at=[STRING]]\n"
|
||||
"with\n"
|
||||
" NAMESERVER used for queries (default: system standard)\n"
|
||||
" ROOT a DNS name appended to the query (default: none)\n"
|
||||
" STRING A string to replace the '@' (default: \".\")\n"
|
||||
"\n", fp);
|
||||
fputs ("Example: A query for \"hacker@gnupg.org\" with\n"
|
||||
" kdns://10.0.0.1/example.net?at=_key?\n"
|
||||
"setup as --auto-key-lookup does a CERT record query\n"
|
||||
"with type PGP on the nameserver 10.0.0.1 for\n"
|
||||
" hacker._key_.gnupg.org.example.net\n"
|
||||
"\n", fp);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
int arg;
|
||||
int ret = KEYSERVER_INTERNAL_ERROR;
|
||||
char line[MAX_LINE];
|
||||
struct keylist *keylist = NULL;
|
||||
struct keylist **keylist_tail = &keylist;
|
||||
struct keylist *akey;
|
||||
int failed = 0;
|
||||
adns_state adns_ctx = NULL;
|
||||
adns_initflags my_adns_initflags = MY_ADNS_INITFLAGS;
|
||||
int tmprc;
|
||||
|
||||
/* The defaults for the KDNS name mangling. */
|
||||
kdns_root = "";
|
||||
kdns_at_repl = "";
|
||||
|
||||
console = stderr;
|
||||
|
||||
/* Kludge to implement standard GNU options. */
|
||||
if (argc > 1 && !strcmp (argv[1], "--version"))
|
||||
{
|
||||
fputs (PGM" (GnuPG) " VERSION"\n", stdout);
|
||||
return 0;
|
||||
}
|
||||
else if (argc > 1 && !strcmp (argv[1], "--help"))
|
||||
{
|
||||
show_help (stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ( (arg = getopt (argc, argv, "hVo:")) != -1 )
|
||||
{
|
||||
switch(arg)
|
||||
{
|
||||
case 'V':
|
||||
printf ("%d\n%s\n", KEYSERVER_PROTO_VERSION, VERSION);
|
||||
return KEYSERVER_OK;
|
||||
|
||||
case 'o':
|
||||
output = fopen (optarg,"w");
|
||||
if (!output)
|
||||
{
|
||||
fprintf (console, PGM": cannot open output file `%s': %s\n",
|
||||
optarg, strerror(errno) );
|
||||
return KEYSERVER_INTERNAL_ERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
default:
|
||||
show_help (console);
|
||||
return KEYSERVER_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc > optind)
|
||||
{
|
||||
input = fopen (argv[optind], "r");
|
||||
if (!input)
|
||||
{
|
||||
fprintf (console, PGM": cannot open input file `%s': %s\n",
|
||||
argv[optind], strerror(errno) );
|
||||
return KEYSERVER_INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (!input)
|
||||
input = stdin;
|
||||
|
||||
if (!output)
|
||||
output = stdout;
|
||||
|
||||
opt = init_ks_options();
|
||||
if(!opt)
|
||||
return KEYSERVER_NO_MEMORY;
|
||||
|
||||
/* Get the command and info block */
|
||||
while ( fgets(line,MAX_LINE,input) )
|
||||
{
|
||||
int err;
|
||||
|
||||
if(line[0]=='\n')
|
||||
break;
|
||||
|
||||
err = parse_ks_options (line, opt);
|
||||
if (err > 0)
|
||||
{
|
||||
ret = err;
|
||||
goto leave;
|
||||
}
|
||||
else if (!err)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (opt->timeout && register_timeout() == -1 )
|
||||
{
|
||||
fprintf (console, PGM": unable to register timeout handler\n");
|
||||
return KEYSERVER_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
fprintf (console, PGM": HOST=%s\n", opt->host? opt->host:"(none)");
|
||||
fprintf (console, PGM": PATH=%s\n", opt->path? opt->path:"(none)");
|
||||
if (opt->path && *opt->path == '/')
|
||||
{
|
||||
char *p, *pend;
|
||||
|
||||
kdns_root = opt->path+1;
|
||||
p = strchr (opt->path+1, '?');
|
||||
if (p)
|
||||
{
|
||||
*p++ = 0;
|
||||
do
|
||||
{
|
||||
pend = strchr (p, '&');
|
||||
if (pend)
|
||||
*pend++ = 0;
|
||||
if (!strncmp (p, "at=", 3))
|
||||
{
|
||||
/* Found. */
|
||||
kdns_at_repl = p+3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while ((p = pend));
|
||||
}
|
||||
}
|
||||
if (strchr (kdns_root, '/'))
|
||||
{
|
||||
fprintf (console, PGM": invalid character in KDNS root\n");
|
||||
return KEYSERVER_GENERAL_ERROR;
|
||||
}
|
||||
if (!strcmp (kdns_at_repl, "."))
|
||||
kdns_at_repl = "";
|
||||
fprintf (console, PGM": kdns_root=%s\n", kdns_root);
|
||||
fprintf (console, PGM": kdns_at=%s\n", kdns_at_repl);
|
||||
|
||||
|
||||
if (opt->debug)
|
||||
my_adns_initflags |= adns_if_debug;
|
||||
if (opt->host)
|
||||
{
|
||||
char cfgtext[200];
|
||||
|
||||
snprintf (cfgtext, sizeof cfgtext, "nameserver %s\n", opt->host);
|
||||
tmprc = adns_init_strcfg (&adns_ctx, my_adns_initflags, console,cfgtext);
|
||||
}
|
||||
else
|
||||
tmprc = adns_init (&adns_ctx, my_adns_initflags, console);
|
||||
if (tmprc)
|
||||
{
|
||||
fprintf (console, PGM": error initializing ADNS: %s\n",
|
||||
strerror (errno));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (opt->action == KS_GETNAME)
|
||||
{
|
||||
while ( fgets (line,MAX_LINE,input) )
|
||||
{
|
||||
if (line[0]=='\n' || !line[0] )
|
||||
break;
|
||||
line[strlen(line)-1] = 0; /* Trim the trailing LF. */
|
||||
|
||||
akey = xtrymalloc (sizeof *akey);
|
||||
if (!akey)
|
||||
{
|
||||
fprintf (console,
|
||||
PGM": out of memory while building key list\n");
|
||||
ret = KEYSERVER_NO_MEMORY;
|
||||
goto leave;
|
||||
}
|
||||
assert (sizeof (akey->str) > strlen(line));
|
||||
strcpy (akey->str, line);
|
||||
akey->next = NULL;
|
||||
*keylist_tail = akey;
|
||||
keylist_tail = &akey->next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (console,
|
||||
PGM": this keyserver type only supports "
|
||||
"key retrieval by name\n");
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Send the response */
|
||||
fprintf (output, "VERSION %d\n", KEYSERVER_PROTO_VERSION);
|
||||
fprintf (output, "PROGRAM %s\n\n", VERSION);
|
||||
|
||||
if (opt->verbose > 1)
|
||||
{
|
||||
if (opt->opaque)
|
||||
fprintf (console, "User:\t\t%s\n", opt->opaque);
|
||||
fprintf (console, "Command:\tGET\n");
|
||||
}
|
||||
|
||||
for (akey = keylist; akey; akey = akey->next)
|
||||
{
|
||||
set_timeout (opt->timeout);
|
||||
if ( get_key (adns_ctx, akey->str) )
|
||||
failed++;
|
||||
}
|
||||
if (!failed)
|
||||
ret = KEYSERVER_OK;
|
||||
|
||||
|
||||
leave:
|
||||
if (adns_ctx)
|
||||
adns_finish (adns_ctx);
|
||||
while (keylist)
|
||||
{
|
||||
akey = keylist->next;
|
||||
xfree (keylist);
|
||||
keylist = akey;
|
||||
}
|
||||
if (input != stdin)
|
||||
fclose (input);
|
||||
if (output != stdout)
|
||||
fclose (output);
|
||||
kdns_root = "";
|
||||
kdns_at_repl = ".";
|
||||
free_ks_options (opt);
|
||||
return ret;
|
||||
}
|
|
@ -49,7 +49,10 @@ gcry_xmalloc (size_t n)
|
|||
char *
|
||||
gcry_strdup (const char *string)
|
||||
{
|
||||
return malloc (strlen (string)+1);
|
||||
char *p = malloc (strlen (string)+1);
|
||||
if (p)
|
||||
strcpy (p, string);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue