LCOV - code coverage report
Current view: top level - dirmngr - ks-action.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 152 0.0 %
Date: 2015-11-05 17:10:59 Functions: 0 8 0.0 %

          Line data    Source code
       1             : /* ks-action.c - OpenPGP keyserver actions
       2             :  * Copyright (C) 2011 Free Software Foundation, Inc.
       3             :  * Copyright (C) 2011, 2014 Werner Koch
       4             :  * Copyright (C) 2015 g10 Code GmbH
       5             :  *
       6             :  * This file is part of GnuPG.
       7             :  *
       8             :  * GnuPG is free software; you can redistribute it and/or modify
       9             :  * it under the terms of the GNU General Public License as published by
      10             :  * the Free Software Foundation; either version 3 of the License, or
      11             :  * (at your option) any later version.
      12             :  *
      13             :  * GnuPG is distributed in the hope that it will be useful,
      14             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :  * GNU General Public License for more details.
      17             :  *
      18             :  * You should have received a copy of the GNU General Public License
      19             :  * along with this program; if not, see <http://www.gnu.org/licenses/>.
      20             :  */
      21             : 
      22             : #include <config.h>
      23             : 
      24             : #include <stdio.h>
      25             : #include <stdlib.h>
      26             : #include <string.h>
      27             : #include <assert.h>
      28             : 
      29             : #include "dirmngr.h"
      30             : #include "misc.h"
      31             : #include "ks-engine.h"
      32             : #include "ks-action.h"
      33             : #if USE_LDAP
      34             : # include "ldap-parse-uri.h"
      35             : #endif
      36             : 
      37             : /* Called by the engine's help functions to print the actual help.  */
      38             : gpg_error_t
      39           0 : ks_print_help (ctrl_t ctrl, const char *text)
      40             : {
      41           0 :   return dirmngr_status_help (ctrl, text);
      42             : }
      43             : 
      44             : 
      45             : /* Called by the engine's help functions to print the actual help.  */
      46             : gpg_error_t
      47           0 : ks_printf_help (ctrl_t ctrl, const char *format, ...)
      48             : {
      49             :   va_list arg_ptr;
      50             :   gpg_error_t err;
      51             :   char *buf;
      52             : 
      53           0 :   va_start (arg_ptr, format);
      54           0 :   buf = es_vbsprintf (format, arg_ptr);
      55           0 :   err = buf? 0 : gpg_error_from_syserror ();
      56           0 :   va_end (arg_ptr);
      57           0 :   if (!err)
      58           0 :     err = dirmngr_status_help (ctrl, buf);
      59           0 :   es_free (buf);
      60           0 :   return err;
      61             : }
      62             : 
      63             : 
      64             : /* Run the help command for the engine responsible for URI.  */
      65             : gpg_error_t
      66           0 : ks_action_help (ctrl_t ctrl, const char *url)
      67             : {
      68             :   gpg_error_t err;
      69             :   parsed_uri_t parsed_uri;  /* The broken down URI.  */
      70             : 
      71           0 :   if (!url || !*url)
      72             :     {
      73           0 :       ks_print_help (ctrl, "Known schemata:\n");
      74           0 :       parsed_uri = NULL;
      75             :     }
      76             :   else
      77             :     {
      78             : #if USE_LDAP
      79           0 :       if (ldap_uri_p (url))
      80           0 :         err = ldap_parse_uri (&parsed_uri, url);
      81             :       else
      82             : #endif
      83             :         {
      84           0 :           err = http_parse_uri (&parsed_uri, url, 1);
      85             :         }
      86             : 
      87           0 :       if (err)
      88           0 :         return err;
      89             :     }
      90             : 
      91             :   /* Call all engines to give them a chance to print a help sting.  */
      92           0 :   err = ks_hkp_help (ctrl, parsed_uri);
      93           0 :   if (!err)
      94           0 :     err = ks_http_help (ctrl, parsed_uri);
      95           0 :   if (!err)
      96           0 :     err = ks_finger_help (ctrl, parsed_uri);
      97           0 :   if (!err)
      98           0 :     err = ks_kdns_help (ctrl, parsed_uri);
      99             : #if USE_LDAP
     100           0 :   if (!err)
     101           0 :     err = ks_ldap_help (ctrl, parsed_uri);
     102             : #endif
     103             : 
     104           0 :   if (!parsed_uri)
     105           0 :     ks_print_help (ctrl,
     106             :                    "(Use an URL for engine specific help.)");
     107             :   else
     108           0 :     http_release_parsed_uri (parsed_uri);
     109           0 :   return err;
     110             : }
     111             : 
     112             : 
     113             : /* Resolve all host names.  This is useful for looking at the status
     114             :    of configured keyservers.  */
     115             : gpg_error_t
     116           0 : ks_action_resolve (ctrl_t ctrl, uri_item_t keyservers)
     117             : {
     118           0 :   gpg_error_t err = 0;
     119           0 :   int any_server = 0;
     120             :   uri_item_t uri;
     121             : 
     122           0 :   for (uri = keyservers; !err && uri; uri = uri->next)
     123             :     {
     124           0 :       if (uri->parsed_uri->is_http)
     125             :         {
     126           0 :           any_server = 1;
     127           0 :           err = ks_hkp_resolve (ctrl, uri->parsed_uri);
     128           0 :           if (err)
     129           0 :             break;
     130             :         }
     131             :     }
     132             : 
     133           0 :   if (!any_server)
     134           0 :     err = gpg_error (GPG_ERR_NO_KEYSERVER);
     135           0 :   return err;
     136             : }
     137             : 
     138             : 
     139             : /* Search all configured keyservers for keys matching PATTERNS and
     140             :    write the result to the provided output stream.  */
     141             : gpg_error_t
     142           0 : ks_action_search (ctrl_t ctrl, uri_item_t keyservers,
     143             :                   strlist_t patterns, estream_t outfp)
     144             : {
     145           0 :   gpg_error_t err = 0;
     146           0 :   int any_server = 0;
     147             :   uri_item_t uri;
     148             :   estream_t infp;
     149             : 
     150           0 :   if (!patterns)
     151           0 :     return gpg_error (GPG_ERR_NO_USER_ID);
     152             : 
     153             :   /* FIXME: We only take care of the first pattern.  To fully support
     154             :      multiple patterns we might either want to run several queries in
     155             :      parallel and merge them.  We also need to decide what to do with
     156             :      errors - it might not be the best idea to ignore an error from
     157             :      one server and silently continue with another server.  For now we
     158             :      stop at the first error. */
     159           0 :   for (uri = keyservers; !err && uri; uri = uri->next)
     160             :     {
     161           0 :       int is_http = uri->parsed_uri->is_http;
     162           0 :       int is_ldap = 0;
     163             : #if USE_LDAP
     164           0 :       is_ldap = (strcmp (uri->parsed_uri->scheme, "ldap") == 0
     165           0 :                  || strcmp (uri->parsed_uri->scheme, "ldaps") == 0
     166           0 :                  || strcmp (uri->parsed_uri->scheme, "ldapi") == 0);
     167             : #endif
     168           0 :       if (is_http || is_ldap)
     169             :         {
     170           0 :           any_server = 1;
     171             : #if USE_LDAP
     172           0 :           if (is_ldap)
     173           0 :             err = ks_ldap_search (ctrl, uri->parsed_uri, patterns->d, &infp);
     174             :           else
     175             : #endif
     176             :             {
     177           0 :               err = ks_hkp_search (ctrl, uri->parsed_uri, patterns->d, &infp);
     178             :             }
     179             : 
     180           0 :           if (!err)
     181             :             {
     182           0 :               err = copy_stream (infp, outfp);
     183           0 :               es_fclose (infp);
     184           0 :               break;
     185             :             }
     186             :         }
     187             :     }
     188             : 
     189           0 :   if (!any_server)
     190           0 :     err = gpg_error (GPG_ERR_NO_KEYSERVER);
     191           0 :   return err;
     192             : }
     193             : 
     194             : 
     195             : /* Get the requested keys (matching PATTERNS) using all configured
     196             :    keyservers and write the result to the provided output stream.  */
     197             : gpg_error_t
     198           0 : ks_action_get (ctrl_t ctrl, uri_item_t keyservers,
     199             :                strlist_t patterns, estream_t outfp)
     200             : {
     201           0 :   gpg_error_t err = 0;
     202           0 :   gpg_error_t first_err = 0;
     203           0 :   int any_server = 0;
     204           0 :   int any_data = 0;
     205             :   strlist_t sl;
     206             :   uri_item_t uri;
     207             :   estream_t infp;
     208             : 
     209           0 :   if (!patterns)
     210           0 :     return gpg_error (GPG_ERR_NO_USER_ID);
     211             : 
     212             :   /* FIXME: We only take care of the first keyserver.  To fully
     213             :      support multiple keyservers we need to track the result for each
     214             :      pattern and use the next keyserver if one key was not found.  The
     215             :      keyservers might not all be fully synced thus it is not clear
     216             :      whether the first keyserver has the freshest copy of the key.
     217             :      Need to think about a better strategy.  */
     218           0 :   for (uri = keyservers; !err && uri; uri = uri->next)
     219             :     {
     220           0 :       int is_http = uri->parsed_uri->is_http;
     221           0 :       int is_ldap = 0;
     222             : 
     223             : #if USE_LDAP
     224           0 :       is_ldap = (strcmp (uri->parsed_uri->scheme, "ldap") == 0
     225           0 :                  || strcmp (uri->parsed_uri->scheme, "ldaps") == 0
     226           0 :                  || strcmp (uri->parsed_uri->scheme, "ldapi") == 0);
     227             : #endif
     228             : 
     229           0 :       if (is_http || is_ldap)
     230             :         {
     231           0 :           any_server = 1;
     232           0 :           for (sl = patterns; !err && sl; sl = sl->next)
     233             :             {
     234             : #if USE_LDAP
     235           0 :               if (is_ldap)
     236           0 :                 err = ks_ldap_get (ctrl, uri->parsed_uri, sl->d, &infp);
     237             :               else
     238             : #endif
     239             :                 {
     240           0 :                   err = ks_hkp_get (ctrl, uri->parsed_uri, sl->d, &infp);
     241             :                 }
     242             : 
     243           0 :               if (err)
     244             :                 {
     245             :                   /* It is possible that a server does not carry a
     246             :                      key, thus we only save the error and continue
     247             :                      with the next pattern.  FIXME: It is an open
     248             :                      question how to return such an error condition to
     249             :                      the caller.  */
     250           0 :                   first_err = err;
     251           0 :                   err = 0;
     252             :                 }
     253             :               else
     254             :                 {
     255           0 :                   err = copy_stream (infp, outfp);
     256             :                   /* Reading from the keyserver should never fail, thus
     257             :                      return this error.  */
     258           0 :                   if (!err)
     259           0 :                     any_data = 1;
     260           0 :                   es_fclose (infp);
     261           0 :                   infp = NULL;
     262             :                 }
     263             :             }
     264             :         }
     265           0 :       if (any_data)
     266           0 :         break; /* Stop loop after a keyserver returned something.  */
     267             :     }
     268             : 
     269           0 :   if (!any_server)
     270           0 :     err = gpg_error (GPG_ERR_NO_KEYSERVER);
     271           0 :   else if (!err && first_err && !any_data)
     272           0 :     err = first_err;
     273           0 :   return err;
     274             : }
     275             : 
     276             : 
     277             : /* Retrieve keys from URL and write the result to the provided output
     278             :    stream OUTFP.  */
     279             : gpg_error_t
     280           0 : ks_action_fetch (ctrl_t ctrl, const char *url, estream_t outfp)
     281             : {
     282           0 :   gpg_error_t err = 0;
     283             :   estream_t infp;
     284             :   parsed_uri_t parsed_uri;  /* The broken down URI.  */
     285             : 
     286           0 :   if (!url)
     287           0 :     return gpg_error (GPG_ERR_INV_URI);
     288             : 
     289           0 :   err = http_parse_uri (&parsed_uri, url, 1);
     290           0 :   if (err)
     291           0 :     return err;
     292             : 
     293           0 :   if (parsed_uri->is_http)
     294             :     {
     295           0 :       err = ks_http_fetch (ctrl, url, &infp);
     296           0 :       if (!err)
     297             :         {
     298           0 :           err = copy_stream (infp, outfp);
     299           0 :           es_fclose (infp);
     300             :         }
     301             :     }
     302           0 :   else if (!parsed_uri->opaque)
     303             :     {
     304           0 :       err = gpg_error (GPG_ERR_INV_URI);
     305             :     }
     306           0 :   else if (!strcmp (parsed_uri->scheme, "finger"))
     307             :     {
     308           0 :       err = ks_finger_fetch (ctrl, parsed_uri, &infp);
     309           0 :       if (!err)
     310             :         {
     311           0 :           err = copy_stream (infp, outfp);
     312           0 :           es_fclose (infp);
     313             :         }
     314             :     }
     315           0 :   else if (!strcmp (parsed_uri->scheme, "kdns"))
     316             :     {
     317           0 :       err = ks_kdns_fetch (ctrl, parsed_uri, &infp);
     318           0 :       if (!err)
     319             :         {
     320           0 :           err = copy_stream (infp, outfp);
     321           0 :           es_fclose (infp);
     322             :         }
     323             :     }
     324             :   else
     325           0 :     err = gpg_error (GPG_ERR_INV_URI);
     326             : 
     327           0 :   http_release_parsed_uri (parsed_uri);
     328           0 :   return err;
     329             : }
     330             : 
     331             : 
     332             : 
     333             : /* Send an OpenPGP key to all keyservers.  The key in {DATA,DATALEN}
     334             :    is expected to be in OpenPGP binary transport format.  The metadata
     335             :    in {INFO,INFOLEN} is in colon-separated format (concretely, it is
     336             :    the output of 'for x in keys sigs; do gpg --list-$x --with-colons
     337             :    KEYID; done'.  This function may modify DATA and INFO.  If this is
     338             :    a problem, then the caller should create a copy.  */
     339             : gpg_error_t
     340           0 : ks_action_put (ctrl_t ctrl, uri_item_t keyservers,
     341             :                void *data, size_t datalen,
     342             :                void *info, size_t infolen)
     343             : {
     344           0 :   gpg_error_t err = 0;
     345           0 :   gpg_error_t first_err = 0;
     346           0 :   int any_server = 0;
     347             :   uri_item_t uri;
     348             : 
     349             :   (void) info;
     350             :   (void) infolen;
     351             : 
     352           0 :   for (uri = keyservers; !err && uri; uri = uri->next)
     353             :     {
     354           0 :       int is_http = uri->parsed_uri->is_http;
     355           0 :       int is_ldap = 0;
     356             : 
     357             : #if USE_LDAP
     358           0 :       is_ldap = (strcmp (uri->parsed_uri->scheme, "ldap") == 0
     359           0 :                 || strcmp (uri->parsed_uri->scheme, "ldaps") == 0
     360           0 :                 || strcmp (uri->parsed_uri->scheme, "ldapi") == 0);
     361             : #endif
     362             : 
     363           0 :       if (is_http || is_ldap)
     364             :         {
     365           0 :           any_server = 1;
     366             : #if USE_LDAP
     367           0 :           if (is_ldap)
     368           0 :             err = ks_ldap_put (ctrl, uri->parsed_uri, data, datalen,
     369             :                                info, infolen);
     370             :           else
     371             : #endif
     372             :             {
     373           0 :               err = ks_hkp_put (ctrl, uri->parsed_uri, data, datalen);
     374             :             }
     375           0 :           if (err)
     376             :             {
     377           0 :               first_err = err;
     378           0 :               err = 0;
     379             :             }
     380             :         }
     381             :     }
     382             : 
     383           0 :   if (!any_server)
     384           0 :     err = gpg_error (GPG_ERR_NO_KEYSERVER);
     385           0 :   else if (!err && first_err)
     386           0 :     err = first_err;
     387           0 :   return err;
     388             : }

Generated by: LCOV version 1.11