From a3dee2889106fcab112c1c96b32e04d8154875e7 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 11 Mar 2014 16:19:41 +0100 Subject: [PATCH] dirmngr: Add command option to mark hosts as dead or alive. * dirmngr/server.c (cmd_killdirmngr): Factor some code out to ... (check_owner_permission): here. (cmd_keyserver): Add options --dead and --alive. * dirmngr/ks-engine-hkp.c (host_in_pool_p): New. (ks_hkp_mark_host): New. -- Also removed the warning that the widnows part has not yet been done. AFAICS, the current mingw supports the all used socket functions. --- dirmngr/ks-engine-hkp.c | 88 +++++++++++++++++++++++++++++++++++++- dirmngr/ks-engine.h | 1 + dirmngr/server.c | 95 ++++++++++++++++++++++++++++++++--------- 3 files changed, 164 insertions(+), 20 deletions(-) diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c index 5d68cce3f..40759304d 100644 --- a/dirmngr/ks-engine-hkp.c +++ b/dirmngr/ks-engine-hkp.c @@ -18,7 +18,6 @@ * along with this program; if not, see . */ -#warning fixme Windows part not yet done #include #include @@ -153,6 +152,19 @@ sort_hostpool (const void *xa, const void *xb) } +/* Return true if the host with the hosttable index TBLIDX is in POOL. */ +static int +host_in_pool_p (int *pool, int tblidx) +{ + int i, pidx; + + for (i=0; (pidx = pool[i]) != -1; i++) + if (pidx == tblidx && hosttable[pidx]) + return 1; + return 0; +} + + /* Select a random host. Consult TABLE which indices into the global hosttable. Returns index into TABLE or -1 if no host could be selected. */ @@ -374,6 +386,80 @@ mark_host_dead (const char *name) } +/* Mark a host in the hosttable as dead or - if ALIVE is true - as + alive. If the host NAME does not exist a warning status message is + printed. */ +gpg_error_t +ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive) +{ + gpg_error_t err = 0; + hostinfo_t hi, hi2; + int idx, idx2, idx3, n; + + if (!name || !*name || !strcmp (name, "localhost")) + return 0; + + idx = find_hostinfo (name); + if (idx == -1) + return gpg_error (GPG_ERR_NOT_FOUND); + + hi = hosttable[idx]; + if (alive && hi->dead) + { + hi->dead = 0; + err = ks_printf_help (ctrl, "marking '%s' as alive", name); + } + else if (!alive && !hi->dead) + { + hi->dead = 1; + err = ks_printf_help (ctrl, "marking '%s' as dead", name); + } + + /* If the host is a pool mark all member hosts. */ + if (!err && hi->pool) + { + for (idx2=0; !err && (n=hi->pool[idx2]) != -1; idx2++) + { + assert (n >= 0 && n < hosttable_size); + + if (!alive) + { + /* Do not mark a host from a pool dead if it is also a + member in another pool. */ + for (idx3=0; idx3 < hosttable_size; idx3++) + { + if (hosttable[idx3] && hosttable[idx3] + && hosttable[idx3]->pool + && idx3 != idx + && host_in_pool_p (hosttable[idx3]->pool, n)) + break; + } + if (idx3 < hosttable_size) + continue; /* Host is also a member of another pool. */ + } + + hi2 = hosttable[n]; + if (!hi2) + ; + else if (alive && hi2->dead) + { + hi2->dead = 0; + err = ks_printf_help (ctrl, "marking '%s' as alive", + hi2->name); + } + else if (!alive && !hi2->dead) + { + hi2->dead = 1; + err = ks_printf_help (ctrl, "marking '%s' as dead", + hi2->name); + } + } + } + + return err; +} + + /* Debug function to print the entire hosttable. */ gpg_error_t ks_hkp_print_hosttable (ctrl_t ctrl) diff --git a/dirmngr/ks-engine.h b/dirmngr/ks-engine.h index 01a295ca9..a2faa751a 100644 --- a/dirmngr/ks-engine.h +++ b/dirmngr/ks-engine.h @@ -30,6 +30,7 @@ gpg_error_t ks_printf_help (ctrl_t ctrl, const char *format, /*-- ks-engine-hkp.c --*/ gpg_error_t ks_hkp_resolve (ctrl_t ctrl, parsed_uri_t uri); +gpg_error_t ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive); gpg_error_t ks_hkp_print_hosttable (ctrl_t ctrl); gpg_error_t ks_hkp_help (ctrl_t ctrl, parsed_uri_t uri); gpg_error_t ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, diff --git a/dirmngr/server.c b/dirmngr/server.c index d2682eaaa..fb619dfcc 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -298,6 +298,32 @@ skip_options (char *line) } +/* Return an error if the assuan context does not belong to teh owner + of the process or to root. On error FAILTEXT is set as Assuan + error string. */ +static gpg_error_t +check_owner_permission (assuan_context_t ctx, const char *failtext) +{ +#ifdef HAVE_W32_SYSTEM + /* Under Windows the dirmngr is always run under the control of the + user. */ + (void)ctx; + (void)failtext; +#else + gpg_err_code_t ec; + assuan_peercred_t cred; + + ec = gpg_err_code (assuan_get_peercred (ctx, &cred)); + if (!ec && cred->uid && cred->uid != getuid ()) + ec = GPG_ERR_EPERM; + if (ec) + return set_error (ec, failtext); +#endif + return 0; +} + + + /* Common code for get_cert_local and get_issuer_cert_local. */ static ksba_cert_t do_get_cert_local (ctrl_t ctrl, const char *name, const char *command) @@ -1392,10 +1418,16 @@ cmd_validate (assuan_context_t ctx, char *line) static const char hlp_keyserver[] = - "KEYSERVER [--clear|--help] []\n" + "KEYSERVER [] [|]\n" + "Options are:\n" + " --help\n" + " --clear Remove all configured keyservers\n" + " --resolve Resolve HKP host names and rotate\n" + " --hosttable Print table of known hosts and pools\n" + " --dead Mark as dead\n" + " --alive Mark as alive\n" "\n" "If called without arguments list all configured keyserver URLs.\n" - "If called with option \"--clear\" remove all configured keyservers\n" "If called with an URI add this as keyserver. Note that keyservers\n" "are configured on a per-session base. A default keyserver may already be\n" "present, thus the \"--clear\" option must be used to get full control.\n" @@ -1408,6 +1440,7 @@ cmd_keyserver (assuan_context_t ctx, char *line) ctrl_t ctrl = assuan_get_pointer (ctx); gpg_error_t err = 0; int clear_flag, add_flag, help_flag, host_flag, resolve_flag; + int dead_flag, alive_flag; uri_item_t item = NULL; /* gcc 4.4.5 is not able to detect that it is always initialized. */ @@ -1415,6 +1448,8 @@ cmd_keyserver (assuan_context_t ctx, char *line) help_flag = has_option (line, "--help"); resolve_flag = has_option (line, "--resolve"); host_flag = has_option (line, "--hosttable"); + dead_flag = has_option (line, "--dead"); + alive_flag = has_option (line, "--alive"); line = skip_options (line); add_flag = !!*line; @@ -1431,13 +1466,37 @@ cmd_keyserver (assuan_context_t ctx, char *line) goto leave; } + if (alive_flag && dead_flag) + { + err = set_error (GPG_ERR_ASS_PARAMETER, "no support for zombies"); + goto leave; + } + if (dead_flag) + { + err = check_owner_permission (ctx, "no permission to use --dead"); + if (err) + goto leave; + } + if (alive_flag || dead_flag) + { + if (!*line) + { + err = set_error (GPG_ERR_ASS_PARAMETER, "name of host missing"); + goto leave; + } + + err = ks_hkp_mark_host (ctrl, line, alive_flag); + if (err) + goto leave; + } + if (host_flag) { err = ks_hkp_print_hosttable (ctrl); if (err) goto leave; } - if (resolve_flag || host_flag) + if (resolve_flag || host_flag || alive_flag || dead_flag) goto leave; if (add_flag) @@ -1746,30 +1805,28 @@ static gpg_error_t cmd_killdirmngr (assuan_context_t ctx, char *line) { ctrl_t ctrl = assuan_get_pointer (ctx); + gpg_error_t err; (void)line; if (opt.system_daemon) { if (opt.system_service) - return set_error (GPG_ERR_NOT_SUPPORTED, - "can't do that whilst running as system service"); -#ifndef HAVE_W32_SYSTEM - { - gpg_err_code_t ec; - assuan_peercred_t cred; - - ec = gpg_err_code (assuan_get_peercred (ctx, &cred)); - if (!ec && cred->uid) - ec = GPG_ERR_EPERM; /* Only root may terminate. */ - if (ec) - return set_error (ec, "no permission to kill this process"); - } -#endif + err = set_error (GPG_ERR_NOT_SUPPORTED, + "can't do that whilst running as system service"); + else + err = check_owner_permission (ctx, + "no permission to kill this process"); } + else + err = 0; - ctrl->server_local->stopme = 1; - return gpg_error (GPG_ERR_EOF); + if (!err) + { + ctrl->server_local->stopme = 1; + err = gpg_error (GPG_ERR_EOF); + } + return err; }