LCOV - code coverage report
Current view: top level - dirmngr - ks-action.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 161 0.0 %
Date: 2016-11-29 15:00:56 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 <https://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           0 :   int any_results = 0;
     148             :   uri_item_t uri;
     149             :   estream_t infp;
     150             : 
     151           0 :   if (!patterns)
     152           0 :     return gpg_error (GPG_ERR_NO_USER_ID);
     153             : 
     154             :   /* FIXME: We only take care of the first pattern.  To fully support
     155             :      multiple patterns we might either want to run several queries in
     156             :      parallel and merge them.  We also need to decide what to do with
     157             :      errors - it might not be the best idea to ignore an error from
     158             :      one server and silently continue with another server.  For now we
     159             :      stop at the first error, unless the server responds with '404 Not
     160             :      Found', in which case we try the next server.  */
     161           0 :   for (uri = keyservers; !err && uri; uri = uri->next)
     162             :     {
     163           0 :       int is_http = uri->parsed_uri->is_http;
     164           0 :       int is_ldap = 0;
     165           0 :       unsigned int http_status = 0;
     166             : #if USE_LDAP
     167           0 :       is_ldap = (strcmp (uri->parsed_uri->scheme, "ldap") == 0
     168           0 :                  || strcmp (uri->parsed_uri->scheme, "ldaps") == 0
     169           0 :                  || strcmp (uri->parsed_uri->scheme, "ldapi") == 0);
     170             : #endif
     171           0 :       if (is_http || is_ldap)
     172             :         {
     173           0 :           any_server = 1;
     174             : #if USE_LDAP
     175           0 :           if (is_ldap)
     176           0 :             err = ks_ldap_search (ctrl, uri->parsed_uri, patterns->d, &infp);
     177             :           else
     178             : #endif
     179             :             {
     180           0 :               err = ks_hkp_search (ctrl, uri->parsed_uri, patterns->d,
     181             :                                    &infp, &http_status);
     182             :             }
     183             : 
     184           0 :           if (err == gpg_error (GPG_ERR_NO_DATA)
     185           0 :               && http_status == 404 /* not found */)
     186             :             {
     187             :               /* No record found.  Clear error and try next server.  */
     188           0 :               err = 0;
     189           0 :               continue;
     190             :             }
     191             : 
     192           0 :           if (!err)
     193             :             {
     194           0 :               err = copy_stream (infp, outfp);
     195           0 :               es_fclose (infp);
     196           0 :               any_results = 1;
     197           0 :               break;
     198             :             }
     199             :         }
     200             :     }
     201             : 
     202           0 :   if (!any_server)
     203           0 :     err = gpg_error (GPG_ERR_NO_KEYSERVER);
     204           0 :   else if (err == 0 && !any_results)
     205           0 :     err = gpg_error (GPG_ERR_NO_DATA);
     206           0 :   return err;
     207             : }
     208             : 
     209             : 
     210             : /* Get the requested keys (matching PATTERNS) using all configured
     211             :    keyservers and write the result to the provided output stream.  */
     212             : gpg_error_t
     213           0 : ks_action_get (ctrl_t ctrl, uri_item_t keyservers,
     214             :                strlist_t patterns, estream_t outfp)
     215             : {
     216           0 :   gpg_error_t err = 0;
     217           0 :   gpg_error_t first_err = 0;
     218           0 :   int any_server = 0;
     219           0 :   int any_data = 0;
     220             :   strlist_t sl;
     221             :   uri_item_t uri;
     222             :   estream_t infp;
     223             : 
     224           0 :   if (!patterns)
     225           0 :     return gpg_error (GPG_ERR_NO_USER_ID);
     226             : 
     227             :   /* FIXME: We only take care of the first keyserver.  To fully
     228             :      support multiple keyservers we need to track the result for each
     229             :      pattern and use the next keyserver if one key was not found.  The
     230             :      keyservers might not all be fully synced thus it is not clear
     231             :      whether the first keyserver has the freshest copy of the key.
     232             :      Need to think about a better strategy.  */
     233           0 :   for (uri = keyservers; !err && uri; uri = uri->next)
     234             :     {
     235           0 :       int is_http = uri->parsed_uri->is_http;
     236           0 :       int is_ldap = 0;
     237             : 
     238             : #if USE_LDAP
     239           0 :       is_ldap = (strcmp (uri->parsed_uri->scheme, "ldap") == 0
     240           0 :                  || strcmp (uri->parsed_uri->scheme, "ldaps") == 0
     241           0 :                  || strcmp (uri->parsed_uri->scheme, "ldapi") == 0);
     242             : #endif
     243             : 
     244           0 :       if (is_http || is_ldap)
     245             :         {
     246           0 :           any_server = 1;
     247           0 :           for (sl = patterns; !err && sl; sl = sl->next)
     248             :             {
     249             : #if USE_LDAP
     250           0 :               if (is_ldap)
     251           0 :                 err = ks_ldap_get (ctrl, uri->parsed_uri, sl->d, &infp);
     252             :               else
     253             : #endif
     254             :                 {
     255           0 :                   err = ks_hkp_get (ctrl, uri->parsed_uri, sl->d, &infp);
     256             :                 }
     257             : 
     258           0 :               if (err)
     259             :                 {
     260             :                   /* It is possible that a server does not carry a
     261             :                      key, thus we only save the error and continue
     262             :                      with the next pattern.  FIXME: It is an open
     263             :                      question how to return such an error condition to
     264             :                      the caller.  */
     265           0 :                   first_err = err;
     266           0 :                   err = 0;
     267             :                 }
     268             :               else
     269             :                 {
     270           0 :                   err = copy_stream (infp, outfp);
     271             :                   /* Reading from the keyserver should never fail, thus
     272             :                      return this error.  */
     273           0 :                   if (!err)
     274           0 :                     any_data = 1;
     275           0 :                   es_fclose (infp);
     276           0 :                   infp = NULL;
     277             :                 }
     278             :             }
     279             :         }
     280           0 :       if (any_data)
     281           0 :         break; /* Stop loop after a keyserver returned something.  */
     282             :     }
     283             : 
     284           0 :   if (!any_server)
     285           0 :     err = gpg_error (GPG_ERR_NO_KEYSERVER);
     286           0 :   else if (!err && first_err && !any_data)
     287           0 :     err = first_err;
     288           0 :   return err;
     289             : }
     290             : 
     291             : 
     292             : /* Retrieve keys from URL and write the result to the provided output
     293             :    stream OUTFP.  */
     294             : gpg_error_t
     295           0 : ks_action_fetch (ctrl_t ctrl, const char *url, estream_t outfp)
     296             : {
     297           0 :   gpg_error_t err = 0;
     298             :   estream_t infp;
     299             :   parsed_uri_t parsed_uri;  /* The broken down URI.  */
     300             : 
     301           0 :   if (!url)
     302           0 :     return gpg_error (GPG_ERR_INV_URI);
     303             : 
     304           0 :   err = http_parse_uri (&parsed_uri, url, 1);
     305           0 :   if (err)
     306           0 :     return err;
     307             : 
     308           0 :   if (parsed_uri->is_http)
     309             :     {
     310           0 :       err = ks_http_fetch (ctrl, url, &infp);
     311           0 :       if (!err)
     312             :         {
     313           0 :           err = copy_stream (infp, outfp);
     314           0 :           es_fclose (infp);
     315             :         }
     316             :     }
     317           0 :   else if (!parsed_uri->opaque)
     318             :     {
     319           0 :       err = gpg_error (GPG_ERR_INV_URI);
     320             :     }
     321           0 :   else if (!strcmp (parsed_uri->scheme, "finger"))
     322             :     {
     323           0 :       err = ks_finger_fetch (ctrl, parsed_uri, &infp);
     324           0 :       if (!err)
     325             :         {
     326           0 :           err = copy_stream (infp, outfp);
     327           0 :           es_fclose (infp);
     328             :         }
     329             :     }
     330           0 :   else if (!strcmp (parsed_uri->scheme, "kdns"))
     331             :     {
     332           0 :       err = ks_kdns_fetch (ctrl, parsed_uri, &infp);
     333           0 :       if (!err)
     334             :         {
     335           0 :           err = copy_stream (infp, outfp);
     336           0 :           es_fclose (infp);
     337             :         }
     338             :     }
     339             :   else
     340           0 :     err = gpg_error (GPG_ERR_INV_URI);
     341             : 
     342           0 :   http_release_parsed_uri (parsed_uri);
     343           0 :   return err;
     344             : }
     345             : 
     346             : 
     347             : 
     348             : /* Send an OpenPGP key to all keyservers.  The key in {DATA,DATALEN}
     349             :    is expected to be in OpenPGP binary transport format.  The metadata
     350             :    in {INFO,INFOLEN} is in colon-separated format (concretely, it is
     351             :    the output of 'for x in keys sigs; do gpg --list-$x --with-colons
     352             :    KEYID; done'.  This function may modify DATA and INFO.  If this is
     353             :    a problem, then the caller should create a copy.  */
     354             : gpg_error_t
     355           0 : ks_action_put (ctrl_t ctrl, uri_item_t keyservers,
     356             :                void *data, size_t datalen,
     357             :                void *info, size_t infolen)
     358             : {
     359           0 :   gpg_error_t err = 0;
     360           0 :   gpg_error_t first_err = 0;
     361           0 :   int any_server = 0;
     362             :   uri_item_t uri;
     363             : 
     364             :   (void) info;
     365             :   (void) infolen;
     366             : 
     367           0 :   for (uri = keyservers; !err && uri; uri = uri->next)
     368             :     {
     369           0 :       int is_http = uri->parsed_uri->is_http;
     370           0 :       int is_ldap = 0;
     371             : 
     372             : #if USE_LDAP
     373           0 :       is_ldap = (strcmp (uri->parsed_uri->scheme, "ldap") == 0
     374           0 :                 || strcmp (uri->parsed_uri->scheme, "ldaps") == 0
     375           0 :                 || strcmp (uri->parsed_uri->scheme, "ldapi") == 0);
     376             : #endif
     377             : 
     378           0 :       if (is_http || is_ldap)
     379             :         {
     380           0 :           any_server = 1;
     381             : #if USE_LDAP
     382           0 :           if (is_ldap)
     383           0 :             err = ks_ldap_put (ctrl, uri->parsed_uri, data, datalen,
     384             :                                info, infolen);
     385             :           else
     386             : #endif
     387             :             {
     388           0 :               err = ks_hkp_put (ctrl, uri->parsed_uri, data, datalen);
     389             :             }
     390           0 :           if (err)
     391             :             {
     392           0 :               first_err = err;
     393           0 :               err = 0;
     394             :             }
     395             :         }
     396             :     }
     397             : 
     398           0 :   if (!any_server)
     399           0 :     err = gpg_error (GPG_ERR_NO_KEYSERVER);
     400           0 :   else if (!err && first_err)
     401           0 :     err = first_err;
     402           0 :   return err;
     403             : }

Generated by: LCOV version 1.11