LCOV - code coverage report
Current view: top level - mnt/wasteland/wcohen/systemtap_write/systemtap - csclient.cxx (source / functions) Hit Total Coverage
Test: stap.info Lines: 1054 1605 65.7 %
Date: 2013-03-08 Functions: 77 84 91.7 %
Branches: 1225 3550 34.5 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  Compile server client functions
       3                 :            :  Copyright (C) 2010-2013 Red Hat Inc.
       4                 :            : 
       5                 :            :  This file is part of systemtap, and is free software.  You can
       6                 :            :  redistribute it and/or modify it under the terms of the GNU General
       7                 :            :  Public License (GPL); either version 2, or (at your option) any
       8                 :            :  later version.
       9                 :            : */
      10                 :            : 
      11                 :            : // Completely disable the client if NSS is not available.
      12                 :            : #include "config.h"
      13                 :            : #if HAVE_NSS
      14                 :            : #include "session.h"
      15                 :            : #include "cscommon.h"
      16                 :            : #include "csclient.h"
      17                 :            : #include "util.h"
      18                 :            : #include "stap-probe.h"
      19                 :            : 
      20                 :            : #include <sys/times.h>
      21                 :            : #include <vector>
      22                 :            : #include <fstream>
      23                 :            : #include <sstream>
      24                 :            : #include <cassert>
      25                 :            : #include <cstdlib>
      26                 :            : #include <cstdio>
      27                 :            : #include <algorithm>
      28                 :            : 
      29                 :            : extern "C" {
      30                 :            : #include <unistd.h>
      31                 :            : #include <linux/limits.h>
      32                 :            : #include <sys/time.h>
      33                 :            : #include <glob.h>
      34                 :            : #include <limits.h>
      35                 :            : #include <sys/socket.h>
      36                 :            : #include <sys/stat.h>
      37                 :            : #include <net/if.h>
      38                 :            : #include <netdb.h>
      39                 :            : #include <arpa/inet.h>
      40                 :            : #include <pwd.h>
      41                 :            : }
      42                 :            : 
      43                 :            : #if HAVE_AVAHI
      44                 :            : extern "C" {
      45                 :            : #include <avahi-client/client.h>
      46                 :            : #include <avahi-client/lookup.h>
      47                 :            : 
      48                 :            : #include <avahi-common/simple-watch.h>
      49                 :            : #include <avahi-common/malloc.h>
      50                 :            : #include <avahi-common/error.h>
      51                 :            : #include <avahi-common/timeval.h>
      52                 :            : }
      53                 :            : #endif // HAVE_AVAHI
      54                 :            : 
      55                 :            : extern "C" {
      56                 :            : #include <ssl.h>
      57                 :            : #include <nspr.h>
      58                 :            : #include <nss.h>
      59                 :            : #include <certdb.h>
      60                 :            : #include <pk11pub.h>
      61                 :            : #include <prerror.h>
      62                 :            : #include <secerr.h>
      63                 :            : #include <sslerr.h>
      64                 :            : }
      65                 :            : 
      66                 :            : #include "nsscommon.h"
      67                 :            : 
      68                 :            : using namespace std;
      69                 :            : 
      70                 :            : #define STAP_CSC_01 _("WARNING: The domain name, %s, does not match the DNS name(s) on the server certificate:\n")
      71                 :            : #define STAP_CSC_02 _("could not find input file %s\n")
      72                 :            : #define STAP_CSC_03 _("could not open input file %s\n")
      73                 :            : #define STAP_CSC_04 _("Unable to open output file %s\n")
      74                 :            : #define STAP_CSC_05 _("could not write to %s\n")
      75                 :            : 
      76                 :            : static PRIPv6Addr &copyAddress (PRIPv6Addr &PRin6, const in6_addr &in6);
      77                 :            : static PRNetAddr &copyNetAddr (PRNetAddr &x, const PRNetAddr &y);
      78                 :            : bool operator!= (const PRNetAddr &x, const PRNetAddr &y);
      79                 :            : bool operator== (const PRNetAddr &x, const PRNetAddr &y);
      80                 :            : 
      81                 :            : extern "C"
      82                 :            : void
      83                 :          0 : nsscommon_error (const char *msg, int logit __attribute ((unused)))
      84                 :            : {
      85                 :          0 :   clog << msg << endl << flush;
      86                 :          0 : }
      87                 :            : 
      88                 :            : // Information about compile servers.
      89 [ +  - ][ +  - ]:       3436 : struct compile_server_info
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
      90                 :            : {
      91                 :        332 :   compile_server_info ()
      92 [ +  - ][ +  - ]:        332 :   {
                 [ +  - ]
      93                 :        332 :     memset (& address, 0, sizeof (address));
      94                 :        332 :   }
      95                 :            : 
      96                 :            :   string host_name;
      97                 :            :   PRNetAddr address;
      98                 :            :   string version;
      99                 :            :   string sysinfo;
     100                 :            :   string certinfo;
     101                 :            : 
     102                 :       1788 :   bool empty () const
     103                 :            :   {
     104 [ +  + ][ +  - ]:       1788 :     return this->host_name.empty () && ! this->hasAddress ();
     105                 :            :   }
     106                 :       4849 :   bool hasAddress () const
     107                 :            :   {
     108                 :       4849 :     return this->address.raw.family != 0;
     109                 :            :   }
     110                 :       2721 :   unsigned short port () const
     111                 :            :   {
     112         [ +  + ]:       2721 :     if (this->address.raw.family == PR_AF_INET)
     113                 :       2574 :       return ntohs (this->address.inet.port);
     114         [ -  + ]:        147 :     if (this->address.raw.family == PR_AF_INET6)
     115                 :          0 :       return ntohs (this->address.ipv6.port);
     116                 :       2721 :     return 0;
     117                 :            :   }
     118                 :         12 :   unsigned short setPort (unsigned short port)
     119                 :            :   {
     120         [ +  - ]:         12 :     if (this->address.raw.family == PR_AF_INET)
     121                 :         12 :       return this->address.inet.port = htons (port);
     122         [ #  # ]:          0 :     if (this->address.raw.family == PR_AF_INET6)
     123                 :          0 :       return this->address.ipv6.port = htons (port);
     124                 :         12 :     return 0;
     125                 :            :   }
     126                 :            : 
     127                 :       1696 :   bool operator== (const compile_server_info &that) const
     128                 :            :   {
     129                 :            :     // If both ip addressed are not set, then the host names must match, otherwise
     130                 :            :     // the addresses must match.
     131 [ +  + ][ +  + ]:       1696 :     if (! this->hasAddress() || ! that.hasAddress())
                 [ +  + ]
     132                 :            :       {
     133         [ +  + ]:        539 :         if (this->host_name != that.host_name)
     134                 :        492 :           return false;
     135                 :            :       }
     136         [ +  + ]:       1157 :     else if (this->address != that.address)
     137                 :        723 :       return false;
     138                 :            : 
     139                 :            :     // Compare the other fields only if they have both been set.
     140         [ +  + ]:        911 :     if (this->port() != 0 && that.port() != 0 &&
           [ +  +  +  + ]
                 [ +  + ]
     141                 :        430 :         this->port() != that.port())
     142                 :         96 :       return false;
     143         [ +  + ]:        719 :     if (! this->version.empty () && ! that.version.empty () &&
           [ +  +  -  + ]
                 [ -  + ]
     144                 :        334 :         this->version != that.version)
     145                 :          0 :       return false;
     146         [ +  + ]:        719 :     if (! this->sysinfo.empty () && ! that.sysinfo.empty () &&
           [ +  +  -  + ]
                 [ -  + ]
     147                 :        334 :         this->sysinfo != that.sysinfo)
     148                 :          0 :       return false;
     149         [ +  + ]:        766 :     if (! this->certinfo.empty () && ! that.certinfo.empty () &&
           [ +  +  -  + ]
                 [ -  + ]
     150                 :        381 :         this->certinfo != that.certinfo)
     151                 :          0 :       return false;
     152                 :            : 
     153                 :       1696 :     return true; // They are equal
     154                 :            :   }
     155                 :            : 
     156                 :            :   // Used to sort servers by preference for order of contact. The preferred server is
     157                 :            :   // "less" than the other one.
     158                 :         80 :   bool operator< (const compile_server_info &that) const
     159                 :            :   {
     160                 :            :     // Prefer servers with a later (higher) version number.
     161 [ +  - ][ +  - ]:         80 :     cs_protocol_version this_version (this->version.c_str ());
     162 [ +  - ][ +  - ]:         80 :     cs_protocol_version that_version (that.version.c_str ());
     163 [ +  - ][ +  - ]:         80 :     return that_version < this_version;
                 [ +  - ]
     164                 :            :   }
     165                 :            : };
     166                 :            : 
     167                 :            : ostream &operator<< (ostream &s, const compile_server_info &i);
     168                 :            : ostream &operator<< (ostream &s, const vector<compile_server_info> &v);
     169                 :            : 
     170                 :            : static void
     171                 :         51 : preferred_order (vector<compile_server_info> &servers)
     172                 :            : {
     173                 :            :   // Sort the given list of servers into the preferred order for contacting.
     174                 :            :   // Don't bother if there are less than 2 servers in the list.
     175         [ +  + ]:         51 :   if (servers.size () < 2)
     176                 :         51 :     return;
     177                 :            : 
     178                 :            :   // Sort the list using compile_server_info::operator<
     179                 :         34 :   sort (servers.begin (), servers.end ());
     180                 :            : }
     181                 :            : 
     182 [ +  - ][ +  - ]:         53 : struct compile_server_cache
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     183                 :            : {
     184                 :            :   vector<compile_server_info> default_servers;
     185                 :            :   vector<compile_server_info> specified_servers;
     186                 :            :   vector<compile_server_info> trusted_servers;
     187                 :            :   vector<compile_server_info> signing_servers;
     188                 :            :   vector<compile_server_info> online_servers;
     189                 :            :   vector<compile_server_info> all_servers;
     190                 :            :   map<string,vector<compile_server_info> > resolved_servers;
     191                 :            : };
     192                 :            : 
     193                 :            : // For filtering queries.
     194                 :            : enum compile_server_properties {
     195                 :            :   compile_server_all        = 0x1,
     196                 :            :   compile_server_trusted    = 0x2,
     197                 :            :   compile_server_online     = 0x4,
     198                 :            :   compile_server_compatible = 0x8,
     199                 :            :   compile_server_signer     = 0x10,
     200                 :            :   compile_server_specified  = 0x20
     201                 :            : };
     202                 :            : 
     203                 :            : // Static functions.
     204                 :            : static compile_server_cache* cscache(systemtap_session& s);
     205                 :            : static void query_server_status (systemtap_session &s, const string &status_string);
     206                 :            : 
     207                 :            : static void get_server_info (systemtap_session &s, int pmask, vector<compile_server_info> &servers);
     208                 :            : static void get_all_server_info (systemtap_session &s, vector<compile_server_info> &servers);
     209                 :            : static void get_default_server_info (systemtap_session &s, vector<compile_server_info> &servers);
     210                 :            : static void get_specified_server_info (systemtap_session &s, vector<compile_server_info> &servers, bool no_default = false);
     211                 :            : static void get_or_keep_online_server_info (systemtap_session &s, vector<compile_server_info> &servers, bool keep);
     212                 :            : static void get_or_keep_trusted_server_info (systemtap_session &s, vector<compile_server_info> &servers, bool keep);
     213                 :            : static void get_or_keep_signing_server_info (systemtap_session &s, vector<compile_server_info> &servers, bool keep);
     214                 :            : static void get_or_keep_compatible_server_info (systemtap_session &s, vector<compile_server_info> &servers, bool keep);
     215                 :            : static void keep_common_server_info (const compile_server_info &info_to_keep, vector<compile_server_info> &filtered_info);
     216                 :            : static void keep_common_server_info (const vector<compile_server_info> &info_to_keep, vector<compile_server_info> &filtered_info);
     217                 :            : static void keep_server_info_with_cert_and_port (systemtap_session &s, const compile_server_info &server, vector<compile_server_info> &servers);
     218                 :            : 
     219                 :            : static void add_server_info (const compile_server_info &info, vector<compile_server_info>& list);
     220                 :            : static void add_server_info (const vector<compile_server_info> &source, vector<compile_server_info> &target);
     221                 :            : static void merge_server_info (const compile_server_info &source, compile_server_info &target);
     222                 :            : #if 0 // not used right now
     223                 :            : static void merge_server_info (const compile_server_info &source, vector<compile_server_info> &target);
     224                 :            : static void merge_server_info (const vector<compile_server_info> &source, vector <compile_server_info> &target);
     225                 :            : #endif
     226                 :            : static void resolve_host (systemtap_session& s, compile_server_info &server, vector<compile_server_info> &servers);
     227                 :            : 
     228                 :            : /* Exit error codes */
     229                 :            : #define SUCCESS                   0
     230                 :            : #define GENERAL_ERROR             1
     231                 :            : #define CA_CERT_INVALID_ERROR     2
     232                 :            : #define SERVER_CERT_EXPIRED_ERROR 3
     233                 :            : 
     234                 :            : // -----------------------------------------------------
     235                 :            : // NSS related code used by the compile server client
     236                 :            : // -----------------------------------------------------
     237                 :            : static void add_server_trust (systemtap_session &s, const string &cert_db_path, const vector<compile_server_info> &server_list);
     238                 :            : static void revoke_server_trust (systemtap_session &s, const string &cert_db_path, const vector<compile_server_info> &server_list);
     239                 :            : static void get_server_info_from_db (systemtap_session &s, vector<compile_server_info> &servers, const string &cert_db_path);
     240                 :            : 
     241                 :         92 : static string global_client_cert_db_path () {
     242         [ +  - ]:         92 :   return SYSCONFDIR "/systemtap/ssl/client";
     243                 :            : }
     244                 :            : 
     245                 :            : static string
     246                 :         94 : private_ssl_cert_db_path ()
     247                 :            : {
     248                 :         94 :   return local_client_cert_db_path ();
     249                 :            : }
     250                 :            : 
     251                 :            : static string
     252                 :         92 : global_ssl_cert_db_path ()
     253                 :            : {
     254                 :         92 :   return global_client_cert_db_path ();
     255                 :            : }
     256                 :            : 
     257                 :            : static string
     258                 :         27 : signing_cert_db_path ()
     259                 :            : {
     260         [ +  - ]:         27 :   return SYSCONFDIR "/systemtap/staprun";
     261                 :            : }
     262                 :            : 
     263                 :            : /* Connection state.  */
     264                 :            : typedef struct connectionState_t
     265                 :            : {
     266                 :            :   const char *hostName;
     267                 :            :   PRNetAddr   addr;
     268                 :            :   const char *infileName;
     269                 :            :   const char *outfileName;
     270                 :            :   const char *trustNewServerMode;
     271                 :            : } connectionState_t;
     272                 :            : 
     273                 :            : #if 0 /* No client authorization */
     274                 :            : static char *
     275                 :            : myPasswd(PK11SlotInfo *info, PRBool retry, void *arg)
     276                 :            : {
     277                 :            :   char * passwd = NULL;
     278                 :            : 
     279                 :            :   if ( (!retry) && arg )
     280                 :            :     passwd = PORT_Strdup((char *)arg);
     281                 :            : 
     282                 :            :   return passwd;
     283                 :            : }
     284                 :            : #endif
     285                 :            : 
     286                 :            : /* Add the server's certificate to our database of trusted servers.  */
     287                 :            : static SECStatus
     288                 :          1 : trustNewServer (CERTCertificate *serverCert)
     289                 :            : {
     290                 :            :   SECStatus secStatus;
     291                 :          1 :   CERTCertTrust *trust = NULL;
     292                 :          1 :   PK11SlotInfo *slot = NULL;
     293                 :            : 
     294                 :            :   /* Import the certificate.  */
     295                 :          1 :   slot = PK11_GetInternalKeySlot();
     296                 :          1 :   const char *nickname = server_cert_nickname ();
     297                 :          1 :   secStatus = PK11_ImportCert(slot, serverCert, CK_INVALID_HANDLE, nickname, PR_FALSE);
     298         [ -  + ]:          1 :   if (secStatus != SECSuccess)
     299                 :          0 :     goto done;
     300                 :            :   
     301                 :            :   /* Make it a trusted peer.  */
     302                 :          1 :   trust = (CERTCertTrust *)PORT_ZAlloc(sizeof(CERTCertTrust));
     303         [ -  + ]:          1 :   if (! trust)
     304                 :            :     {
     305                 :          0 :       secStatus = SECFailure;
     306                 :          0 :       goto done;
     307                 :            :     }
     308                 :            : 
     309                 :          1 :   secStatus = CERT_DecodeTrustString(trust, "P,P,P");
     310         [ -  + ]:          1 :   if (secStatus != SECSuccess)
     311                 :          0 :     goto done;
     312                 :            : 
     313                 :          1 :   secStatus = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), serverCert, trust);
     314                 :            : 
     315                 :            : done:
     316         [ +  - ]:          1 :   if (slot)
     317                 :          1 :     PK11_FreeSlot (slot);
     318         [ +  - ]:          1 :   if (trust)
     319                 :          1 :     PORT_Free(trust);
     320                 :          1 :   return secStatus;
     321                 :            : }
     322                 :            : 
     323                 :            : /* Called when the server certificate verification fails. This gives us
     324                 :            :    the chance to trust the server anyway and add the certificate to the
     325                 :            :    local database.  */
     326                 :            : static SECStatus
     327                 :          1 : badCertHandler(void *arg, PRFileDesc *sslSocket)
     328                 :            : {
     329                 :            :   SECStatus secStatus;
     330                 :            :   PRErrorCode errorNumber;
     331                 :          1 :   CERTCertificate *serverCert = NULL;
     332                 :            :   SECItem subAltName;
     333                 :          1 :   PRArenaPool *tmpArena = NULL;
     334                 :            :   CERTGeneralName *nameList, *current;
     335                 :          1 :   char *expected = NULL;
     336                 :          1 :   const connectionState_t *connectionState = (connectionState_t *)arg;
     337                 :            : 
     338         [ +  - ]:          1 :   errorNumber = PR_GetError ();
     339      [ -  +  - ]:          1 :   switch (errorNumber)
     340                 :            :     {
     341                 :            :     case SSL_ERROR_BAD_CERT_DOMAIN:
     342                 :            :       /* Since we administer our own client-side databases of trustworthy
     343                 :            :          certificates, we don't need the domain name(s) on the certificate to
     344                 :            :          match. If the cert is in our database, then we can trust it.
     345                 :            :          Issue a warning and accept the certificate.  */
     346         [ #  # ]:          0 :       expected = SSL_RevealURL (sslSocket);
     347         [ #  # ]:          0 :       fprintf (stderr, STAP_CSC_01, expected);
     348                 :            : 
     349                 :            :       /* List the DNS names from the server cert as part of the warning.
     350                 :            :          First, find the alt-name extension on the certificate.  */
     351                 :          0 :       subAltName.data = NULL;
     352         [ #  # ]:          0 :       serverCert = SSL_PeerCertificate (sslSocket);
     353                 :            :       secStatus = CERT_FindCertExtension (serverCert,
     354                 :            :                                           SEC_OID_X509_SUBJECT_ALT_NAME,
     355         [ #  # ]:          0 :                                           & subAltName);
     356 [ #  # ][ #  # ]:          0 :       if (secStatus != SECSuccess || ! subAltName.data)
     357                 :            :         {
     358         [ #  # ]:          0 :           fprintf (stderr, _("Unable to find alt name extension on the server certificate\n"));
     359                 :          0 :           secStatus = SECSuccess; /* Not a fatal error */
     360                 :          0 :           break;
     361                 :            :         }
     362                 :            : 
     363                 :            :       // Now, decode the extension.
     364         [ #  # ]:          0 :       tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
     365         [ #  # ]:          0 :       if (! tmpArena) 
     366                 :            :         {
     367         [ #  # ]:          0 :           fprintf (stderr, _("Out of memory\n"));
     368         [ #  # ]:          0 :           SECITEM_FreeItem(& subAltName, PR_FALSE);
     369                 :          0 :           secStatus = SECSuccess; /* Not a fatal error here */
     370                 :          0 :           break;
     371                 :            :         }
     372         [ #  # ]:          0 :       nameList = CERT_DecodeAltNameExtension (tmpArena, & subAltName);
     373         [ #  # ]:          0 :       SECITEM_FreeItem(& subAltName, PR_FALSE);
     374         [ #  # ]:          0 :       if (! nameList)
     375                 :            :         {
     376         [ #  # ]:          0 :           fprintf (stderr, _("Unable to decode alt name extension on server certificate\n"));
     377                 :          0 :           secStatus = SECSuccess; /* Not a fatal error */
     378                 :          0 :           break;
     379                 :            :         }
     380                 :            : 
     381                 :            :       /* List the DNS names from the server cert as part of the warning.
     382                 :            :          The names are in a circular list.  */
     383                 :          0 :       current = nameList;
     384         [ #  # ]:          0 :       do
     385                 :            :         {
     386                 :            :           /* Make sure this is a DNS name.  */
     387         [ #  # ]:          0 :           if (current->type == certDNSName)
     388                 :            :             {
     389                 :            :               fprintf (stderr, "  %.*s\n",
     390         [ #  # ]:          0 :                        (int)current->name.other.len, current->name.other.data);
     391                 :            :             }
     392         [ #  # ]:          0 :           current = CERT_GetNextGeneralName (current);
     393                 :            :         }
     394                 :            :       while (current != nameList);
     395                 :            : 
     396                 :            :       /* Accept the certificate */
     397                 :          0 :       secStatus = SECSuccess;
     398                 :          0 :       break;
     399                 :            : 
     400                 :            :     case SEC_ERROR_CA_CERT_INVALID:
     401                 :            :       /* The server's certificate is not trusted. Should we trust it? */
     402                 :          1 :       secStatus = SECFailure; /* Do not trust by default. */
     403         [ -  + ]:          1 :       if (! connectionState->trustNewServerMode)
     404                 :          0 :         break;
     405                 :            : 
     406                 :            :       /* Trust it for this session only?  */
     407         [ -  + ]:          1 :       if (strcmp (connectionState->trustNewServerMode, "session") == 0)
     408                 :            :         {
     409                 :          0 :           secStatus = SECSuccess;
     410                 :          0 :           break;
     411                 :            :         }
     412                 :            : 
     413                 :            :       /* Trust it permanently?  */
     414         [ +  - ]:          1 :       if (strcmp (connectionState->trustNewServerMode, "permanent") == 0)
     415                 :            :         {
     416                 :            :           /* The user wants to trust this server. Get the server's certificate so
     417                 :            :              and add it to our database.  */
     418         [ +  - ]:          1 :           serverCert = SSL_PeerCertificate (sslSocket);
     419         [ +  - ]:          1 :           if (serverCert != NULL)
     420                 :            :             {
     421         [ +  - ]:          1 :               secStatus = trustNewServer (serverCert);
     422                 :            :             }
     423                 :            :         }
     424                 :          1 :       break;
     425                 :            :     default:
     426                 :          0 :       secStatus = SECFailure; /* Do not trust this server */
     427                 :          0 :       break;
     428                 :            :     }
     429                 :            : 
     430         [ -  + ]:          1 :   if (expected)
     431         [ #  # ]:          0 :     PORT_Free (expected);
     432         [ -  + ]:          1 :   if (tmpArena)
     433         [ #  # ]:          0 :     PORT_FreeArena (tmpArena, PR_FALSE);
     434                 :            : 
     435         [ +  - ]:          1 :   if (serverCert != NULL)
     436                 :            :     {
     437         [ +  - ]:          1 :       CERT_DestroyCertificate (serverCert);
     438                 :            :     }
     439                 :            : 
     440                 :          1 :   return secStatus;
     441                 :            : }
     442                 :            : 
     443                 :            : static PRFileDesc *
     444                 :         36 : setupSSLSocket (connectionState_t *connectionState)
     445                 :            : {
     446                 :            :   PRFileDesc         *tcpSocket;
     447                 :            :   PRFileDesc         *sslSocket;
     448                 :            :   PRSocketOptionData    socketOption;
     449                 :            :   PRStatus            prStatus;
     450                 :            :   SECStatus           secStatus;
     451                 :            : 
     452         [ +  - ]:         36 :   tcpSocket = PR_OpenTCPSocket(connectionState->addr.raw.family);
     453         [ -  + ]:         36 :   if (tcpSocket == NULL)
     454                 :          0 :     goto loser;
     455                 :            : 
     456                 :            :   /* Make the socket blocking. */
     457                 :         36 :   socketOption.option = PR_SockOpt_Nonblocking;
     458                 :         36 :   socketOption.value.non_blocking = PR_FALSE;
     459                 :            : 
     460         [ +  - ]:         36 :   prStatus = PR_SetSocketOption(tcpSocket, &socketOption);
     461         [ -  + ]:         36 :   if (prStatus != PR_SUCCESS)
     462                 :          0 :     goto loser;
     463                 :            : 
     464                 :            :   /* Import the socket into the SSL layer. */
     465         [ +  - ]:         36 :   sslSocket = SSL_ImportFD(NULL, tcpSocket);
     466         [ -  + ]:         36 :   if (!sslSocket)
     467                 :          0 :     goto loser;
     468                 :            : 
     469                 :            :   /* Set configuration options. */
     470         [ +  - ]:         36 :   secStatus = SSL_OptionSet(sslSocket, SSL_SECURITY, PR_TRUE);
     471         [ -  + ]:         36 :   if (secStatus != SECSuccess)
     472                 :          0 :     goto loser;
     473                 :            : 
     474         [ +  - ]:         36 :   secStatus = SSL_OptionSet(sslSocket, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE);
     475         [ -  + ]:         36 :   if (secStatus != SECSuccess)
     476                 :          0 :     goto loser;
     477                 :            : 
     478                 :            :   /* Set SSL callback routines. */
     479                 :            : #if 0 /* no client authentication */
     480                 :            :   secStatus = SSL_GetClientAuthDataHook(sslSocket,
     481                 :            :                                         (SSLGetClientAuthData)myGetClientAuthData,
     482                 :            :                                         (void *)certNickname);
     483                 :            :   if (secStatus != SECSuccess)
     484                 :            :     goto loser;
     485                 :            : #endif
     486                 :            : #if 0 /* Use the default */
     487                 :            :   secStatus = SSL_AuthCertificateHook(sslSocket,
     488                 :            :                                       (SSLAuthCertificate)myAuthCertificate,
     489                 :            :                                       (void *)CERT_GetDefaultCertDB());
     490                 :            :   if (secStatus != SECSuccess)
     491                 :            :     goto loser;
     492                 :            : #endif
     493                 :            : 
     494                 :            :   secStatus = SSL_BadCertHook(sslSocket, (SSLBadCertHandler)badCertHandler,
     495         [ +  - ]:         36 :                               connectionState);
     496         [ -  + ]:         36 :   if (secStatus != SECSuccess)
     497                 :          0 :     goto loser;
     498                 :            : 
     499                 :            : #if 0 /* No handshake callback */
     500                 :            :   secStatus = SSL_HandshakeCallback(sslSocket, myHandshakeCallback, NULL);
     501                 :            :   if (secStatus != SECSuccess)
     502                 :            :     goto loser;
     503                 :            : #endif
     504                 :            : 
     505                 :         36 :   return sslSocket;
     506                 :            : 
     507                 :            :  loser:
     508         [ #  # ]:          0 :   if (tcpSocket)
     509         [ #  # ]:          0 :     PR_Close(tcpSocket);
     510                 :         36 :   return NULL;
     511                 :            : }
     512                 :            : 
     513                 :            : 
     514                 :            : static SECStatus
     515                 :         36 : handle_connection (PRFileDesc *sslSocket, connectionState_t *connectionState)
     516                 :            : {
     517                 :            :   PRInt32     numBytes;
     518                 :            :   char       *readBuffer;
     519                 :            :   PRFileInfo  info;
     520                 :            :   PRFileDesc *local_file_fd;
     521                 :            :   PRStatus    prStatus;
     522                 :         36 :   SECStatus   secStatus = SECSuccess;
     523                 :            : 
     524                 :            : #define READ_BUFFER_SIZE (60 * 1024)
     525                 :            : 
     526                 :            :   /* If we don't have both the input and output file names, then we're
     527                 :            :      contacting this server only in order to establish trust. In this case send
     528                 :            :      0 as the file size and exit. */
     529 [ +  + ][ -  + ]:         36 :   if (! connectionState->infileName || ! connectionState->outfileName)
     530                 :            :     {
     531                 :          1 :       numBytes = htonl ((PRInt32)0);
     532         [ +  - ]:          1 :       numBytes = PR_Write (sslSocket, & numBytes, sizeof (numBytes));
     533         [ -  + ]:          1 :       if (numBytes < 0)
     534                 :          0 :         return SECFailure;
     535                 :          1 :       return SECSuccess;
     536                 :            :     }
     537                 :            : 
     538                 :            :   /* read and send the data. */
     539                 :            :   /* Try to open the local file named.  
     540                 :            :    * If successful, then write it to the server
     541                 :            :    */
     542         [ +  - ]:         35 :   prStatus = PR_GetFileInfo(connectionState->infileName, &info);
     543 [ +  - ][ +  - ]:         35 :   if (prStatus != PR_SUCCESS ||
                 [ -  + ]
     544                 :            :       info.type != PR_FILE_FILE ||
     545                 :            :       info.size < 0)
     546                 :            :     {
     547                 :          0 :       fprintf (stderr, STAP_CSC_02,
     548         [ #  # ]:          0 :                connectionState->infileName);
     549                 :          0 :       return SECFailure;
     550                 :            :     }
     551                 :            : 
     552         [ +  - ]:         35 :   local_file_fd = PR_Open(connectionState->infileName, PR_RDONLY, 0);
     553         [ -  + ]:         35 :   if (local_file_fd == NULL)
     554                 :            :     {
     555         [ #  # ]:          0 :       fprintf (stderr, STAP_CSC_03, connectionState->infileName);
     556                 :          0 :       return SECFailure;
     557                 :            :     }
     558                 :            : 
     559                 :            :   /* Send the file size first, so the server knows when it has the entire file. */
     560                 :         35 :   numBytes = htonl ((PRInt32)info.size);
     561         [ +  - ]:         35 :   numBytes = PR_Write(sslSocket, & numBytes, sizeof (numBytes));
     562         [ -  + ]:         35 :   if (numBytes < 0)
     563                 :            :     {
     564         [ #  # ]:          0 :       PR_Close(local_file_fd);
     565                 :          0 :       return SECFailure;
     566                 :            :     }
     567                 :            : 
     568                 :            :   /* Transmit the local file across the socket.  */
     569                 :            :   numBytes = PR_TransmitFile(sslSocket, local_file_fd, 
     570                 :            :                              NULL, 0,
     571                 :            :                              PR_TRANSMITFILE_KEEP_OPEN,
     572         [ +  - ]:         35 :                              PR_INTERVAL_NO_TIMEOUT);
     573         [ -  + ]:         35 :   if (numBytes < 0)
     574                 :            :     {
     575         [ #  # ]:          0 :       PR_Close(local_file_fd);
     576                 :          0 :       return SECFailure;
     577                 :            :     }
     578                 :            : 
     579         [ +  - ]:         35 :   PR_Close(local_file_fd);
     580                 :            : 
     581                 :            :   /* read until EOF */
     582         [ +  - ]:         35 :   readBuffer = (char *)PORT_Alloc(READ_BUFFER_SIZE);
     583         [ -  + ]:         35 :   if (! readBuffer) {
     584         [ #  # ]:          0 :     fprintf (stderr, _("Out of memory\n"));
     585                 :          0 :     return SECFailure;
     586                 :            :   }
     587                 :            : 
     588                 :            :   local_file_fd = PR_Open(connectionState->outfileName, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
     589         [ +  - ]:         35 :                           PR_IRUSR | PR_IWUSR | PR_IRGRP | PR_IWGRP | PR_IROTH);
     590         [ -  + ]:         35 :   if (local_file_fd == NULL)
     591                 :            :     {
     592         [ #  # ]:          0 :       fprintf (stderr, STAP_CSC_04, connectionState->outfileName);
     593                 :          0 :       return SECFailure;
     594                 :            :     }
     595                 :         35 :   while (PR_TRUE)
     596                 :            :     {
     597         [ +  - ]:         70 :       numBytes = PR_Read(sslSocket, readBuffer, READ_BUFFER_SIZE);
     598         [ +  + ]:         70 :       if (numBytes == 0)
     599                 :         35 :         break;  /* EOF */
     600                 :            : 
     601         [ -  + ]:         35 :       if (numBytes < 0)
     602                 :            :         {
     603                 :          0 :           secStatus = SECFailure;
     604                 :          0 :           break;
     605                 :            :         }
     606                 :            : 
     607                 :            :       /* Write to output file */
     608         [ +  - ]:         35 :       numBytes = PR_Write(local_file_fd, readBuffer, numBytes);
     609         [ -  + ]:         35 :       if (numBytes < 0)
     610                 :            :         {
     611         [ #  # ]:          0 :           fprintf (stderr, STAP_CSC_05, connectionState->outfileName);
     612                 :          0 :           secStatus = SECFailure;
     613                 :          0 :           break;
     614                 :            :         }
     615                 :            :     }
     616                 :            : 
     617         [ +  - ]:         35 :   PR_Free(readBuffer);
     618         [ +  - ]:         35 :   PR_Close(local_file_fd);
     619                 :            : 
     620                 :            :   /* Caller closes the socket. */
     621                 :         36 :   return secStatus;
     622                 :            : }
     623                 :            : 
     624                 :            : /* make the connection.
     625                 :            : */
     626                 :            : static SECStatus
     627                 :         36 : do_connect (connectionState_t *connectionState)
     628                 :            : {
     629                 :            :   PRFileDesc *sslSocket;
     630                 :            :   PRStatus    prStatus;
     631                 :            :   SECStatus   secStatus;
     632                 :            : 
     633                 :         36 :   secStatus = SECSuccess;
     634                 :            : 
     635                 :            :   /* Set up SSL secure socket. */
     636                 :         36 :   sslSocket = setupSSLSocket (connectionState);
     637         [ -  + ]:         36 :   if (sslSocket == NULL)
     638                 :          0 :     return SECFailure;
     639                 :            : 
     640                 :            : #if 0 /* no client authentication */
     641                 :            :   secStatus = SSL_SetPKCS11PinArg(sslSocket, password);
     642                 :            :   if (secStatus != SECSuccess)
     643                 :            :     goto done;
     644                 :            : #endif
     645                 :            : 
     646                 :         36 :   secStatus = SSL_SetURL(sslSocket, connectionState->hostName);
     647         [ -  + ]:         36 :   if (secStatus != SECSuccess)
     648                 :          0 :     goto done;
     649                 :            : 
     650                 :         36 :   prStatus = PR_Connect(sslSocket, & connectionState->addr, PR_INTERVAL_NO_TIMEOUT);
     651         [ -  + ]:         36 :   if (prStatus != PR_SUCCESS)
     652                 :            :     {
     653                 :          0 :       secStatus = SECFailure;
     654                 :          0 :       goto done;
     655                 :            :     }
     656                 :            : 
     657                 :            :   /* Established SSL connection, ready to send data. */
     658                 :         36 :   secStatus = SSL_ResetHandshake(sslSocket, /* asServer */ PR_FALSE);
     659         [ -  + ]:         36 :   if (secStatus != SECSuccess)
     660                 :          0 :     goto done;
     661                 :            : 
     662                 :            :   /* This is normally done automatically on the first I/O operation,
     663                 :            :      but doing it here catches any authentication problems early.  */
     664                 :         36 :   secStatus = SSL_ForceHandshake(sslSocket);
     665         [ -  + ]:         36 :   if (secStatus != SECSuccess)
     666                 :          0 :     goto done;
     667                 :            : 
     668                 :            :   // Connect to the server and make the request.
     669                 :         36 :   secStatus = handle_connection(sslSocket, connectionState);
     670                 :            : 
     671                 :            :  done:
     672                 :         36 :   prStatus = PR_Close(sslSocket);
     673                 :         36 :   return secStatus;
     674                 :            : }
     675                 :            : 
     676                 :            : static bool
     677                 :          0 : isIPv6LinkLocal (const PRNetAddr &address)
     678                 :            : {
     679                 :            :   // Link-local addresses are members of the address block fe80::
     680 [ #  # ][ #  # ]:          0 :   if (address.raw.family == PR_AF_INET6 &&
                 [ #  # ]
     681                 :          0 :       address.ipv6.ip.pr_s6_addr[0] == 0xfe && address.ipv6.ip.pr_s6_addr[1] == 0x80)
     682                 :          0 :     return true;
     683                 :          0 :   return false;
     684                 :            : }
     685                 :            : 
     686                 :            : int
     687                 :         36 : client_connect (const compile_server_info &server,
     688                 :            :                 const char* infileName, const char* outfileName,
     689                 :            :                 const char* trustNewServer)
     690                 :            : {
     691                 :            :   SECStatus   secStatus;
     692                 :            :   PRErrorCode errorNumber;
     693                 :            :   int         attempt;
     694                 :         36 :   int         errCode = GENERAL_ERROR;
     695                 :            :   struct connectionState_t connectionState;
     696                 :            : 
     697                 :            :   // Set up a connection state for use by NSS error callbacks.
     698                 :         36 :   memset (& connectionState, 0, sizeof (connectionState));
     699         [ +  - ]:         36 :   connectionState.hostName = server.host_name.c_str ();
     700                 :         36 :   connectionState.addr = server.address;
     701                 :         36 :   connectionState.infileName = infileName;
     702                 :         36 :   connectionState.outfileName = outfileName;
     703                 :         36 :   connectionState.trustNewServerMode = trustNewServer;
     704                 :            : 
     705                 :            :   /* Some errors (see below) represent a situation in which trying again
     706                 :            :      should succeed. However, don't try forever.  */
     707         [ +  - ]:         36 :   for (attempt = 0; attempt < 5; ++attempt)
     708                 :            :     {
     709         [ +  - ]:         36 :       secStatus = do_connect (& connectionState);
     710         [ +  - ]:         36 :       if (secStatus == SECSuccess)
     711                 :         36 :         return SUCCESS;
     712                 :            : 
     713         [ #  # ]:          0 :       errorNumber = PR_GetError ();
     714   [ #  #  #  # ]:          0 :       switch (errorNumber)
     715                 :            :         {
     716                 :            :         case PR_CONNECT_RESET_ERROR:
     717                 :            :           /* Server was not ready. */
     718         [ #  # ]:          0 :           sleep (1);
     719                 :          0 :           break; /* Try again */
     720                 :            :         case SEC_ERROR_EXPIRED_CERTIFICATE:
     721                 :            :           /* The server's certificate has expired. It should
     722                 :            :              generate a new certificate. Return now and we'll try again. */
     723                 :          0 :           errCode = SERVER_CERT_EXPIRED_ERROR;
     724                 :          0 :           return errCode;
     725                 :            :         case SEC_ERROR_CA_CERT_INVALID:
     726                 :            :           /* The server's certificate is not trusted. The exit code must
     727                 :            :              reflect this.  */
     728                 :          0 :           errCode = CA_CERT_INVALID_ERROR;
     729                 :          0 :           return errCode;
     730                 :            :         default:
     731                 :            :           /* This error is fatal.  */
     732                 :          0 :           return errCode;
     733                 :            :         }
     734                 :            :     }
     735                 :            : 
     736                 :         36 :   return errCode;
     737                 :            : }
     738                 :            : 
     739                 :            : int
     740                 :         39 : compile_server_client::passes_0_4 ()
     741                 :            : {
     742                 :         39 :   PROBE1(stap, client__start, &s);
     743                 :            : 
     744                 :            :   // arguments parsed; get down to business
     745         [ -  + ]:         39 :   if (s.verbose)
     746 [ #  # ][ #  # ]:          0 :     clog << _("Using a compile server.") << endl;
     747                 :            : 
     748                 :            :   struct tms tms_before;
     749                 :         39 :   times (& tms_before);
     750                 :            :   struct timeval tv_before;
     751                 :         39 :   gettimeofday (&tv_before, NULL);
     752                 :            : 
     753                 :            :   // Create the request package.
     754         [ +  - ]:         39 :   int rc = initialize ();
     755         [ +  - ]:         39 :   assert_no_interrupts();
     756         [ -  + ]:         39 :   if (rc != 0) goto done;
     757         [ +  - ]:         39 :   rc = create_request ();
     758         [ +  + ]:         39 :   assert_no_interrupts();
     759         [ +  + ]:         36 :   if (rc != 0) goto done;
     760         [ +  - ]:         35 :   rc = package_request ();
     761         [ +  - ]:         35 :   assert_no_interrupts();
     762         [ -  + ]:         35 :   if (rc != 0) goto done;
     763                 :            : 
     764                 :            :   // Submit it to the server.
     765         [ +  - ]:         35 :   rc = find_and_connect_to_server ();
     766         [ +  - ]:         35 :   assert_no_interrupts();
     767         [ -  + ]:         35 :   if (rc != 0) goto done;
     768                 :            : 
     769                 :            :   // Unpack and process the response.
     770         [ +  - ]:         35 :   rc = unpack_response ();
     771         [ +  - ]:         35 :   assert_no_interrupts();
     772         [ -  + ]:         35 :   if (rc != 0) goto done;
     773         [ +  - ]:         35 :   rc = process_response ();
     774                 :            : 
     775 [ +  + ][ -  + ]:         35 :   if (rc == 0 && s.last_pass == 4)
     776                 :            :     {
     777 [ #  # ][ #  # ]:          0 :       cout << s.module_name + ".ko";
                 [ #  # ]
     778         [ #  # ]:          0 :       cout << endl;
     779                 :            :     }
     780                 :            : 
     781                 :            :  done:
     782                 :            :   struct tms tms_after;
     783                 :         36 :   times (& tms_after);
     784                 :         36 :   unsigned _sc_clk_tck = sysconf (_SC_CLK_TCK);
     785                 :            :   struct timeval tv_after;
     786                 :         36 :   gettimeofday (&tv_after, NULL);
     787                 :            : 
     788                 :            : #define TIMESPRINT "in " << \
     789                 :            :            (tms_after.tms_cutime + tms_after.tms_utime \
     790                 :            :             - tms_before.tms_cutime - tms_before.tms_utime) * 1000 / (_sc_clk_tck) << "usr/" \
     791                 :            :         << (tms_after.tms_cstime + tms_after.tms_stime \
     792                 :            :             - tms_before.tms_cstime - tms_before.tms_stime) * 1000 / (_sc_clk_tck) << "sys/" \
     793                 :            :         << ((tv_after.tv_sec - tv_before.tv_sec) * 1000 + \
     794                 :            :             ((long)tv_after.tv_usec - (long)tv_before.tv_usec) / 1000) << "real ms."
     795                 :            : 
     796                 :            :   // syntax errors, if any, are already printed
     797         [ -  + ]:         36 :   if (s.verbose)
     798                 :            :     {
     799         [ #  # ]:          0 :       string ws = s.winning_server;
     800 [ #  # ][ #  # ]:          0 :       if (ws == "") ws = "?";
                 [ #  # ]
     801 [ #  # ][ #  # ]:          0 :       clog << _("Passes: via server ") << ws << " "
                 [ #  # ]
     802 [ #  # ][ #  # ]:          0 :            << getmemusage()
                 [ #  # ]
     803 [ #  # ][ #  # ]:          0 :            << TIMESPRINT
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     804 [ #  # ][ #  # ]:          0 :            << endl;
     805                 :            :     }
     806         [ +  + ]:         36 :   if (rc)
     807                 :            :     {
     808 [ +  - ][ +  - ]:         30 :       clog << _("Passes: via server failed.  Try again with another '-v' option.") << endl;
     809                 :            :     }
     810                 :            : 
     811         [ +  + ]:         36 :   if (rc == 0)
     812                 :            :     {
     813                 :            :       // Save the module, if necessary.
     814         [ -  + ]:          6 :       if (s.last_pass == 4)
     815                 :          0 :         s.save_module = true;
     816                 :            : 
     817                 :            :       // Copy module to the current directory.
     818 [ -  + ][ #  # ]:          6 :       if (s.save_module && ! pending_interrupts)
     819                 :            :         {
     820 [ #  # ][ #  # ]:          0 :           string module_src_path = s.tmpdir + "/" + s.module_name + ".ko";
         [ #  # ][ #  # ]
                 [ #  # ]
     821         [ #  # ]:          0 :           string module_dest_path = s.module_name + ".ko";
     822         [ #  # ]:          0 :           copy_file (module_src_path, module_dest_path, s.verbose >= 3);
     823                 :            :           // Also copy the module signature, it it exists.
     824         [ #  # ]:          0 :           module_src_path += ".sgn";
     825 [ #  # ][ #  # ]:          0 :           if (file_exists (module_src_path))
     826                 :            :             {
     827         [ #  # ]:          0 :               module_dest_path += ".sgn";
     828         [ #  # ]:          0 :               copy_file(module_src_path, module_dest_path, s.verbose >= 3);
     829 [ #  # ][ #  # ]:          3 :             }
     830                 :            :         }
     831                 :            :     }
     832                 :            : 
     833                 :         36 :   PROBE1(stap, client__end, &s);
     834                 :            : 
     835                 :         36 :   return rc;
     836                 :            : }
     837                 :            : 
     838                 :            : // Initialize a client/server session.
     839                 :            : int
     840                 :         39 : compile_server_client::initialize ()
     841                 :            : {
     842                 :         39 :   int rc = 0;
     843                 :            : 
     844                 :            :   // Initialize session state
     845                 :         39 :   argc = 0;
     846                 :            : 
     847                 :            :   // Private location for server certificates.
     848         [ +  - ]:         39 :   private_ssl_dbs.push_back (private_ssl_cert_db_path ());
     849                 :            : 
     850                 :            :   // Additional public location.
     851         [ +  - ]:         39 :   public_ssl_dbs.push_back (global_ssl_cert_db_path ());
     852                 :            : 
     853                 :            :   // Create a temporary directory to package things in.
     854         [ +  - ]:         39 :   client_tmpdir = s.tmpdir + "/client";
     855                 :         39 :   rc = create_dir (client_tmpdir.c_str ());
     856         [ -  + ]:         39 :   if (rc != 0)
     857                 :            :     {
     858                 :          0 :       const char* e = strerror (errno);
     859                 :          0 :       clog << _("ERROR: cannot create temporary directory (\"")
     860                 :          0 :            << client_tmpdir << "\"): " << e
     861                 :          0 :            << endl;
     862                 :            :     }
     863                 :            : 
     864                 :         39 :   return rc;
     865                 :            : }
     866                 :            : 
     867                 :            : // Create the request package.
     868                 :            : int
     869                 :         39 : compile_server_client::create_request ()
     870                 :            : {
     871                 :            :   // Add the current protocol version.
     872 [ +  - ][ +  - ]:         39 :   int rc = write_to_file (client_tmpdir + "/version", CURRENT_CS_PROTOCOL_VERSION);
                 [ +  - ]
     873         [ -  + ]:         39 :   if (rc != 0)
     874                 :          0 :     return rc;
     875                 :            : 
     876                 :            :   // Add the script file or script option
     877 [ +  - ][ +  + ]:         39 :   if (s.script_file != "")
     878                 :            :     {
     879 [ +  - ][ -  + ]:         11 :       if (s.script_file == "-")
     880                 :            :         {
     881                 :            :           // Copy the script from stdin
     882         [ #  # ]:          0 :           string packaged_script_dir = client_tmpdir + "/script";
     883 [ #  # ][ #  # ]:          0 :           rc = create_dir (packaged_script_dir.c_str ());
     884         [ #  # ]:          0 :           if (rc != 0)
     885                 :            :             {
     886                 :          0 :               const char* e = strerror (errno);
     887         [ #  # ]:          0 :               clog << _("ERROR: cannot create temporary directory ")
     888 [ #  # ][ #  # ]:          0 :                    << packaged_script_dir << ": " << e
                 [ #  # ]
     889         [ #  # ]:          0 :                    << endl;
     890                 :          0 :               return rc;
     891                 :            :             }
     892 [ #  # ][ #  # ]:          0 :           rc = ! copy_file("/dev/stdin", packaged_script_dir + "/-");
         [ #  # ][ #  # ]
                 [ #  # ]
     893         [ #  # ]:          0 :           if (rc != 0)
     894                 :          0 :             return rc;
     895                 :            : 
     896                 :            :           // Name the script in the packaged arguments.
     897 [ #  # ][ #  # ]:          0 :           rc = add_package_arg ("script/-");
                 [ #  # ]
     898         [ #  # ]:          0 :           if (rc != 0)
     899 [ #  # ][ #  # ]:          0 :             return rc;
     900                 :            :         }
     901                 :            :       else
     902                 :            :         {
     903                 :            :           // Add the script to our package. This will also name the script
     904                 :            :           // in the packaged arguments.
     905 [ +  - ][ +  - ]:         11 :           rc = include_file_or_directory ("script", s.script_file);
                 [ +  - ]
     906         [ -  + ]:         11 :           if (rc != 0)
     907                 :          0 :             return rc;
     908                 :            :         }
     909                 :            :     }
     910                 :            : 
     911                 :            :   // Add -I paths. Skip the default directory.
     912         [ +  + ]:         39 :   if (s.include_arg_start != -1)
     913                 :            :     {
     914                 :          7 :       unsigned limit = s.include_path.size ();
     915         [ +  + ]:         10 :       for (unsigned i = s.include_arg_start; i < limit; ++i)
     916                 :            :         {
     917 [ +  - ][ +  - ]:          7 :           rc = add_package_arg ("-I");
                 [ +  - ]
     918         [ -  + ]:          7 :           if (rc != 0)
     919                 :          0 :             return rc;
     920 [ +  - ][ +  - ]:          7 :           rc = include_file_or_directory ("tapset", s.include_path[i]);
                 [ +  - ]
     921         [ +  + ]:          7 :           if (rc != 0)
     922                 :          4 :             return rc;
     923                 :            :         }
     924                 :            :     }
     925                 :            : 
     926                 :            :   // Add other options.
     927         [ +  - ]:         35 :   rc = add_package_args ();
     928         [ -  + ]:         35 :   if (rc != 0)
     929                 :          0 :     return rc;
     930                 :            : 
     931                 :            :   // Add the sysinfo file
     932 [ +  - ][ +  - ]:         35 :   string sysinfo = "sysinfo: " + s.kernel_release + " " + s.architecture;
         [ +  - ][ +  - ]
                 [ +  - ]
     933 [ +  - ][ +  - ]:         35 :   rc = write_to_file (client_tmpdir + "/sysinfo", sysinfo);
                 [ +  - ]
     934         [ -  + ]:         35 :   if (rc != 0)
     935                 :          0 :     return rc;
     936                 :            : 
     937                 :            :   // Add localization data
     938         [ +  - ]:         35 :   rc = add_localization_variables();
     939                 :            : 
     940         [ +  - ]:         39 :   return rc;
     941                 :            : }
     942                 :            : 
     943                 :            : // Add the arguments specified on the command line to the server request
     944                 :            : // package, as appropriate.
     945                 :            : int
     946                 :         35 : compile_server_client::add_package_args ()
     947                 :            : {
     948                 :            :   // stap arguments to be passed to the server.
     949                 :         35 :   int rc = 0;
     950                 :         35 :   unsigned limit = s.server_args.size();
     951         [ +  + ]:        116 :   for (unsigned i = 0; i < limit; ++i)
     952                 :            :     {
     953                 :         81 :       rc = add_package_arg (s.server_args[i]);
     954         [ -  + ]:         81 :       if (rc != 0)
     955                 :          0 :         return rc;
     956                 :            :     }
     957                 :            : 
     958                 :            :   // Script arguments.
     959                 :         35 :   limit = s.args.size();
     960         [ +  + ]:         35 :   if (limit > 0) {
     961 [ +  - ][ +  - ]:          2 :     rc = add_package_arg ("--");
                 [ +  - ]
     962         [ -  + ]:          2 :     if (rc != 0)
     963                 :          0 :       return rc;
     964         [ +  + ]:          4 :     for (unsigned i = 0; i < limit; ++i)
     965                 :            :       {
     966                 :          2 :         rc = add_package_arg (s.args[i]);
     967         [ -  + ]:          2 :         if (rc != 0)
     968                 :          0 :           return rc;
     969                 :            :       }
     970                 :            :   }
     971                 :         35 :   return rc;
     972                 :            : }  
     973                 :            : 
     974                 :            : int
     975                 :        106 : compile_server_client::add_package_arg (const string &arg)
     976                 :            : {
     977                 :        106 :   int rc = 0;
     978         [ +  - ]:        106 :   ostringstream fname;
     979 [ +  - ][ +  - ]:        106 :   fname << client_tmpdir << "/argv" << ++argc;
                 [ +  - ]
     980 [ +  - ][ +  - ]:        106 :   write_to_file (fname.str (), arg); // NB: No terminating newline
                 [ +  - ]
     981         [ +  - ]:        106 :   return rc;
     982                 :            : }
     983                 :            : 
     984                 :            : // Symbolically link the given file or directory into the client's temp
     985                 :            : // directory under the given subdirectory.
     986                 :            : int
     987                 :         18 : compile_server_client::include_file_or_directory (
     988                 :            :   const string &subdir, const string &path
     989                 :            : )
     990                 :            : {
     991                 :            :   // Must predeclare these because we do use 'goto done' to
     992                 :            :   // exit from error situations.
     993         [ +  - ]:         18 :   vector<string> components;
     994         [ +  - ]:         18 :   string name;
     995                 :            :   int rc;
     996                 :            : 
     997                 :            :   // Canonicalize the given path and remove the leading /.
     998         [ +  - ]:         18 :   string rpath;
     999         [ +  - ]:         18 :   char *cpath = canonicalize_file_name (path.c_str ());
    1000         [ +  + ]:         18 :   if (! cpath)
    1001                 :            :     {
    1002                 :            :       // It can not be canonicalized. Use the name relative to
    1003                 :            :       // the current working directory and let the server deal with it.
    1004                 :            :       char cwd[PATH_MAX];
    1005         [ -  + ]:         10 :       if (getcwd (cwd, sizeof (cwd)) == NULL)
    1006                 :            :         {
    1007         [ #  # ]:          0 :           rpath = path;
    1008                 :          0 :           rc = 1;
    1009                 :            :           goto done;
    1010                 :            :         }
    1011 [ +  - ][ +  - ]:         10 :         rpath = string (cwd) + "/" + path;
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
    1012                 :            :     }
    1013                 :            :   else
    1014                 :            :     {
    1015                 :            :       // It can be canonicalized. Use the canonicalized name and add this
    1016                 :            :       // file or directory to the request package.
    1017         [ +  - ]:          8 :       rpath = cpath;
    1018                 :          8 :       free (cpath);
    1019                 :            : 
    1020                 :            :       // Including / would require special handling in the code below and
    1021                 :            :       // is a bad idea anyway. Let's not allow it.
    1022 [ +  - ][ +  + ]:          8 :       if (rpath == "/")
    1023                 :            :         {
    1024 [ +  - ][ -  + ]:          4 :           if (rpath != path)
    1025 [ #  # ][ #  # ]:          0 :             clog << _F("%s resolves to %s\n", path.c_str (), rpath.c_str ());
         [ #  # ][ #  # ]
                 [ #  # ]
    1026 [ +  - ][ +  - ]:          4 :           clog << _F("Unable to send %s to the server\n", path.c_str ());
         [ +  - ][ +  - ]
    1027                 :          4 :           return 1;
    1028                 :            :         }
    1029                 :            : 
    1030                 :            :       // First create the requested subdirectory.
    1031 [ +  - ][ +  - ]:          4 :       name = client_tmpdir + "/" + subdir;
         [ +  - ][ +  - ]
                 [ +  - ]
    1032 [ +  - ][ +  - ]:          4 :       rc = create_dir (name.c_str ());
    1033         [ -  + ]:          4 :       if (rc) goto done;
    1034                 :            : 
    1035                 :            :       // Now create each component of the path within the sub directory.
    1036 [ +  - ][ -  + ]:          4 :       assert (rpath[0] == '/');
    1037 [ +  - ][ +  - ]:          4 :       tokenize (rpath.substr (1), components, "/");
         [ +  - ][ +  - ]
                 [ +  - ]
    1038         [ -  + ]:          4 :       assert (components.size () >= 1);
    1039                 :            :       unsigned i;
    1040         [ +  + ]:         32 :       for (i = 0; i < components.size() - 1; ++i)
    1041                 :            :         {
    1042 [ +  - ][ -  + ]:         28 :           if (components[i].empty ())
    1043                 :          0 :             continue; // embedded '//'
    1044 [ +  - ][ +  - ]:         28 :           name += "/" + components[i];
                 [ +  - ]
    1045 [ +  - ][ +  - ]:         28 :           rc = create_dir (name.c_str ());
    1046         [ -  + ]:         28 :           if (rc) goto done;
    1047                 :            :         }
    1048                 :            : 
    1049                 :            :       // Now make a symbolic link to the actual file or directory.
    1050         [ -  + ]:          4 :       assert (i == components.size () - 1);
    1051 [ +  - ][ +  - ]:          4 :       name += "/" + components[i];
                 [ +  - ]
    1052 [ +  - ][ +  - ]:          4 :       rc = symlink (rpath.c_str (), name.c_str ());
    1053         [ -  + ]:          4 :       if (rc) goto done;
    1054                 :            :     }
    1055                 :            : 
    1056                 :            :   // Name this file or directory in the packaged arguments.
    1057 [ +  - ][ +  - ]:         14 :   rc = add_package_arg (subdir + "/" + rpath.substr (1));
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
    1058                 :            : 
    1059                 :            :  done:
    1060         [ -  + ]:         14 :   if (rc != 0)
    1061                 :            :     {
    1062                 :          0 :       const char* e = strerror (errno);
    1063         [ #  # ]:          0 :       clog << "ERROR: unable to add "
    1064         [ #  # ]:          0 :            << rpath
    1065         [ #  # ]:          0 :            << " to temp directory as "
    1066 [ #  # ][ #  # ]:          0 :            << name << ": " << e
                 [ #  # ]
    1067         [ #  # ]:          0 :            << endl;
    1068                 :            :     }
    1069 [ +  - ][ +  - ]:         18 :   return rc;
                 [ +  - ]
    1070                 :            : }
    1071                 :            : 
    1072                 :            : // Add the localization variables to the server request
    1073                 :            : // package.
    1074                 :            : int
    1075                 :         35 : compile_server_client::add_localization_variables()
    1076                 :            : {
    1077                 :            :   int rc;
    1078         [ +  - ]:         35 :   string envVar;
    1079         [ +  - ]:         35 :   string fname;
    1080                 :            : 
    1081         [ +  - ]:         35 :   const set<string> &locVars = localization_variables();
    1082                 :         35 :   set<string>::iterator it;
    1083                 :            : 
    1084                 :            :   /* Note: We don't have to check for the contents of the environment
    1085                 :            :    * variables here, since they will be checked extensively on the
    1086                 :            :    * server.
    1087                 :            :    */
    1088 [ +  - ][ +  - ]:        315 :   for (it = locVars.begin(); it != locVars.end(); it++)
                 [ +  + ]
    1089                 :            :     {
    1090         [ +  - ]:        280 :       char* var = getenv((*it).c_str());
    1091         [ +  + ]:        280 :       if (var)
    1092 [ +  - ][ +  - ]:         43 :         envVar += *it + "=" + (string)var + "\n";
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
    1093                 :            :     }
    1094 [ +  - ][ +  - ]:         35 :   fname = client_tmpdir + "/locale";
                 [ +  - ]
    1095         [ +  - ]:         35 :   rc = write_to_file(fname, envVar);
    1096 [ +  - ][ +  - ]:         35 :   return rc;
    1097                 :            : }
    1098                 :            : 
    1099                 :            : // Package the client's temp directory into a form suitable for sending to the
    1100                 :            : // server.
    1101                 :            : int
    1102                 :         35 : compile_server_client::package_request ()
    1103                 :            : {
    1104                 :            :   // Package up the temporary directory into a zip file.
    1105 [ +  - ][ +  - ]:         35 :   client_zipfile = client_tmpdir + ".zip";
                 [ +  - ]
    1106                 :            :   string cmd = "cd " + cmdstr_quoted(client_tmpdir) + " && zip -qr "
    1107 [ +  - ][ +  - ]:         35 :       + cmdstr_quoted(client_zipfile) + " *";
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
    1108         [ +  - ]:         35 :   vector<string> sh_cmd;
    1109 [ +  - ][ +  - ]:         35 :   sh_cmd.push_back("sh");
                 [ +  - ]
    1110 [ +  - ][ +  - ]:         35 :   sh_cmd.push_back("-c");
                 [ +  - ]
    1111         [ +  - ]:         35 :   sh_cmd.push_back(cmd);
    1112         [ +  - ]:         35 :   int rc = stap_system (s.verbose, sh_cmd);
    1113 [ +  - ][ +  - ]:         35 :   return rc;
    1114                 :            : }
    1115                 :            : 
    1116                 :            : int
    1117                 :         35 : compile_server_client::find_and_connect_to_server ()
    1118                 :            : {
    1119                 :            :   // Accumulate info on the specified servers.
    1120         [ +  - ]:         35 :   vector<compile_server_info> specified_servers;
    1121         [ +  - ]:         35 :   get_specified_server_info (s, specified_servers);
    1122                 :            : 
    1123                 :            :   // Examine the specified servers to make sure that each has been resolved
    1124                 :            :   // with a host name, ip address and port. If not, try to obtain this
    1125                 :            :   // information by examining online servers.
    1126         [ +  - ]:         35 :   vector<compile_server_info> server_list;
    1127 [ +  - ][ +  - ]:        192 :   for (vector<compile_server_info>::const_iterator i = specified_servers.begin ();
         [ +  - ][ +  + ]
    1128         [ +  - ]:         96 :        i != specified_servers.end ();
    1129                 :            :        ++i)
    1130                 :            :     {
    1131                 :            :       // If we have an ip address and port number, then just use the one we've
    1132                 :            :       // been given. Otherwise, check for matching online servers and try their
    1133                 :            :       // ip addresses and ports.
    1134 [ +  - ][ +  - ]:         61 :       if (i->hasAddress() && i->port() != 0)
                 [ +  - ]
    1135         [ +  - ]:         61 :         add_server_info (*i, server_list);
    1136                 :            :       else
    1137                 :            :         {
    1138                 :            :           // Obtain a list of online servers.
    1139         [ #  # ]:          0 :           vector<compile_server_info> online_servers;
    1140         [ #  # ]:          0 :           get_or_keep_online_server_info (s, online_servers, false/*keep*/);
    1141                 :            : 
    1142                 :            :           // If no specific server (port) has been specified,
    1143                 :            :           // then we'll need the servers to be
    1144                 :            :           // compatible and possible trusted as signers as well.
    1145         [ #  # ]:          0 :           if (i->port() == 0)
    1146                 :            :             {
    1147         [ #  # ]:          0 :               get_or_keep_compatible_server_info (s, online_servers, true/*keep*/);
    1148 [ #  # ][ #  # ]:          0 :               if (! pr_contains (s.privilege, pr_stapdev))
    1149         [ #  # ]:          0 :                 get_or_keep_signing_server_info (s, online_servers, true/*keep*/);
    1150                 :            :             }
    1151                 :            : 
    1152                 :            :           // Keep the ones (if any) which match our server.
    1153         [ #  # ]:          0 :           keep_common_server_info (*i, online_servers);
    1154                 :            : 
    1155                 :            :           // Add these servers (if any) to the server list.
    1156 [ #  # ][ #  # ]:          0 :           add_server_info (online_servers, server_list);
    1157                 :            :         }
    1158                 :            :     }
    1159                 :            : 
    1160                 :            :   // Did we identify any potential servers?
    1161                 :         35 :   unsigned limit = server_list.size ();
    1162         [ -  + ]:         35 :   if (limit == 0)
    1163                 :            :     {
    1164 [ #  # ][ #  # ]:          0 :       clog << _("Unable to find a suitable compile server.") << endl;
    1165                 :            : 
    1166                 :            :       // Try to explain why.
    1167         [ #  # ]:          0 :       vector<compile_server_info> online_servers;
    1168         [ #  # ]:          0 :       get_or_keep_online_server_info (s, online_servers, false/*keep*/);
    1169 [ #  # ][ #  # ]:          0 :       if (online_servers.empty ())
    1170 [ #  # ][ #  # ]:          0 :         clog << _("No servers online to select from.") << endl;
    1171                 :            :       else
    1172                 :            :         {
    1173 [ #  # ][ #  # ]:          0 :           clog << _("The following servers are online:") << endl;
    1174         [ #  # ]:          0 :           clog << online_servers;
    1175 [ #  # ][ #  # ]:          0 :           if (! specified_servers.empty ())
    1176                 :            :             {
    1177 [ #  # ][ #  # ]:          0 :               clog << _("The following servers were requested:") << endl;
    1178         [ #  # ]:          0 :               clog << specified_servers;
    1179                 :            :             }
    1180                 :            :           else
    1181                 :            :             {
    1182         [ #  # ]:          0 :               string criteria = "online,trusted,compatible";
    1183 [ #  # ][ #  # ]:          0 :               if (! pr_contains (s.privilege, pr_stapdev))
    1184         [ #  # ]:          0 :                 criteria += ",signer";
    1185 [ #  # ][ #  # ]:          0 :               clog << _F("No servers matched the selection criteria of %s.", criteria.c_str())
         [ #  # ][ #  # ]
    1186 [ #  # ][ #  # ]:          0 :                    << endl;
    1187                 :            :             }
    1188                 :            :         }
    1189         [ #  # ]:          0 :       return 1;
    1190                 :            :     }
    1191                 :            : 
    1192                 :            :   // Sort the list of servers into a preferred order.
    1193         [ +  - ]:         35 :   preferred_order (server_list);
    1194                 :            : 
    1195                 :            :   // Now try each of the identified servers in turn.
    1196         [ +  - ]:         35 :   int rc = compile_using_server (server_list);
    1197         [ +  - ]:         35 :   if (rc == SUCCESS)
    1198                 :         35 :     return 0; // success!
    1199                 :            : 
    1200                 :            :   // If the error was that a server's cert was expired, try again. This is because the server
    1201                 :            :   // should generate a new cert which may be automatically trusted by us if it is our server.
    1202                 :            :   // Give the server a chance to do this before retrying.
    1203         [ #  # ]:          0 :   if (rc == SERVER_CERT_EXPIRED_ERROR)
    1204                 :            :     {
    1205         [ #  # ]:          0 :       if (s.verbose >= 2)
    1206 [ #  # ][ #  # ]:          0 :         clog << _("The server's certificate was expired. Trying again") << endl << flush;
                 [ #  # ]
    1207         [ #  # ]:          0 :       sleep (2);
    1208         [ #  # ]:          0 :       rc = compile_using_server (server_list);
    1209         [ #  # ]:          0 :       if (rc == SUCCESS)
    1210                 :          0 :         return 0; // success!
    1211                 :            :     }
    1212                 :            : 
    1213                 :            :   // We were unable to use any available server
    1214 [ #  # ][ #  # ]:          0 :   clog << _("Unable to connect to a server.") << endl;
    1215         [ #  # ]:          0 :   if (s.verbose == 1)
    1216                 :            :     {
    1217                 :            :       // This information is redundant at higher verbosity levels.
    1218 [ #  # ][ #  # ]:          0 :       clog << _("The following servers were tried:") << endl;
    1219         [ #  # ]:          0 :       clog << server_list;
    1220                 :            :     }
    1221 [ +  - ][ +  - ]:         35 :   return 1; // Failure
    1222                 :            : }
    1223                 :            : 
    1224                 :            : int 
    1225                 :         35 : compile_server_client::compile_using_server (
    1226                 :            :   const vector<compile_server_info> &servers
    1227                 :            : )
    1228                 :            : {
    1229                 :            :   // Make sure NSPR is initialized. Must be done before NSS is initialized
    1230         [ +  - ]:         35 :   s.NSPR_init ();
    1231                 :            : 
    1232                 :            :   // Attempt connection using each of the available client certificate
    1233                 :            :   // databases. Assume the server certificate is invalid until proven otherwise.
    1234         [ +  - ]:         35 :   PR_SetError (SEC_ERROR_CA_CERT_INVALID, 0);
    1235         [ +  - ]:         35 :   vector<string> dbs = private_ssl_dbs;
    1236         [ +  - ]:         35 :   vector<string>::iterator i = dbs.end();
    1237 [ +  - ][ +  - ]:         35 :   dbs.insert (i, public_ssl_dbs.begin (), public_ssl_dbs.end ());
                 [ +  - ]
    1238                 :         35 :   int rc = GENERAL_ERROR; // assume failure
    1239                 :         35 :   bool serverCertExpired = false;
    1240 [ +  - ][ +  - ]:         35 :   for (i = dbs.begin (); i != dbs.end (); ++i)
         [ +  - ][ +  - ]
    1241                 :            :     {
    1242                 :            :       // Make sure the database directory exists. It is not an error if it
    1243                 :            :       // doesn't.
    1244 [ +  - ][ -  + ]:         35 :       if (! file_exists (*i))
    1245                 :          0 :         continue;
    1246                 :            : 
    1247                 :            : #if 0 // no client authentication for now.
    1248                 :            :       // Set our password function callback.
    1249                 :            :       PK11_SetPasswordFunc (myPasswd);
    1250                 :            : #endif
    1251                 :            : 
    1252                 :            :       // Initialize the NSS libraries.
    1253         [ +  - ]:         35 :       const char *cert_dir = i->c_str ();
    1254         [ +  - ]:         35 :       SECStatus secStatus = nssInit (cert_dir);
    1255         [ -  + ]:         35 :       if (secStatus != SECSuccess)
    1256                 :            :         {
    1257                 :            :           // Message already issued.
    1258                 :          0 :           continue; // try next database
    1259                 :            :         }
    1260                 :            : 
    1261                 :            :       // Enable cipher suites which are allowed by U.S. export regulations.
    1262                 :            :       // SSL_ClearSessionCache is required for the new settings to take effect.
    1263         [ +  - ]:         35 :       secStatus = NSS_SetExportPolicy ();
    1264         [ +  - ]:         35 :       SSL_ClearSessionCache ();
    1265         [ -  + ]:         35 :       if (secStatus != SECSuccess)
    1266                 :            :         {
    1267         [ #  # ]:          0 :           clog << _("Unable to set NSS export policy");
    1268         [ #  # ]:          0 :           nssError ();
    1269         [ #  # ]:          0 :           nssCleanup (cert_dir);
    1270                 :          0 :           continue; // try next database
    1271                 :            :         }
    1272                 :            :   
    1273 [ +  - ][ +  - ]:         35 :       server_zipfile = s.tmpdir + "/server.zip";
                 [ +  - ]
    1274                 :            : 
    1275                 :            :       // Try each server in turn.
    1276 [ +  - ][ +  - ]:         70 :       for (vector<compile_server_info>::const_iterator j = servers.begin ();
                 [ +  - ]
    1277         [ +  - ]:         35 :            j != servers.end ();
    1278                 :            :            ++j)
    1279                 :            :         {
    1280                 :            :           // At a minimum we need an ip_address along with a port
    1281                 :            :           // number in order to contact the server.
    1282 [ +  - ][ -  + ]:         35 :           if (! j->hasAddress() || j->port() == 0)
                 [ -  + ]
    1283                 :          0 :             continue;
    1284                 :            : 
    1285         [ -  + ]:         35 :           if (s.verbose >= 2)
    1286 [ #  # ][ #  # ]:          0 :            clog << _F("Attempting SSL connection with %s\n"
         [ #  # ][ #  # ]
                 [ #  # ]
    1287                 :            :                 "  using certificates from the database in %s\n",
    1288         [ #  # ]:          0 :                 lex_cast(*j).c_str(), cert_dir);
    1289                 :            : 
    1290                 :         35 :           rc = client_connect (*j, client_zipfile.c_str(), server_zipfile.c_str (),
    1291 [ +  - ][ +  - ]:         35 :                                NULL/*trustNewServer_p*/);
                 [ +  - ]
    1292         [ +  - ]:         35 :           if (rc == SUCCESS)
    1293                 :            :             {
    1294 [ +  - ][ +  - ]:         35 :               s.winning_server = lex_cast(*j);
                 [ +  - ]
    1295                 :         35 :               break; // Success!
    1296                 :            :             }
    1297                 :            : 
    1298                 :            :           // Server cert has expired. Try other servers and/or databases, but take note because
    1299                 :            :           // server should generate a new certificate. If no other servers succeed, we'll try again
    1300                 :            :           // in case the new cert works.
    1301         [ #  # ]:          0 :           if (rc == SERVER_CERT_EXPIRED_ERROR)
    1302                 :            :             {
    1303                 :          0 :               serverCertExpired = true;
    1304                 :          0 :               continue;
    1305                 :            :             }
    1306                 :            : 
    1307         [ #  # ]:          0 :           if (s.verbose >= 2)
    1308                 :            :             {
    1309         [ #  # ]:          0 :               clog << _("  Unable to connect: ");
    1310         [ #  # ]:          0 :               nssError ();
    1311                 :            :               // Additional information: if the address is IPv6 and is link-local, then it must
    1312                 :            :               // have a scope_id.
    1313 [ #  # ][ #  # ]:          0 :               if (isIPv6LinkLocal (j->address) && j->address.ipv6.scope_id == 0)
                 [ #  # ]
    1314                 :            :                 {
    1315         [ #  # ]:          0 :                   clog << _("    The address is an IPv6 link-local address with no scope specifier.")
    1316         [ #  # ]:          0 :                        << endl;
    1317                 :            :                 }
    1318                 :            :             }
    1319                 :            :         }
    1320                 :            : 
    1321                 :            :       // SSL_ClearSessionCache is required before shutdown for client applications.
    1322         [ +  - ]:         35 :       SSL_ClearSessionCache ();
    1323         [ +  - ]:         35 :       nssCleanup (cert_dir);
    1324                 :            : 
    1325         [ +  - ]:         35 :       if (rc == SECSuccess)
    1326                 :         35 :         break; // Success!
    1327                 :            :     }
    1328                 :            : 
    1329                 :            :   // Indicate whether a server cert was expired, so we can try again, if desired.
    1330         [ -  + ]:         35 :   if (rc != SUCCESS)
    1331                 :            :     {
    1332         [ #  # ]:          0 :       if (serverCertExpired)
    1333                 :          0 :         rc = SERVER_CERT_EXPIRED_ERROR;
    1334                 :            :     }
    1335                 :            : 
    1336         [ +  - ]:         35 :   return rc;
    1337                 :            : }
    1338                 :            : 
    1339                 :            : int
    1340                 :         35 : compile_server_client::unpack_response ()
    1341                 :            : {
    1342                 :            :   // Unzip the response package.
    1343 [ +  - ][ +  - ]:         35 :   server_tmpdir = s.tmpdir + "/server";
                 [ +  - ]
    1344         [ +  - ]:         35 :   vector<string> cmd;
    1345 [ +  - ][ +  - ]:         35 :   cmd.push_back("unzip");
                 [ +  - ]
    1346 [ +  - ][ +  - ]:         35 :   cmd.push_back("-qd");
                 [ +  - ]
    1347         [ +  - ]:         35 :   cmd.push_back(server_tmpdir);
    1348         [ +  - ]:         35 :   cmd.push_back(server_zipfile);
    1349         [ +  - ]:         35 :   int rc = stap_system (s.verbose, cmd);
    1350         [ -  + ]:         35 :   if (rc != 0)
    1351                 :            :     {
    1352 [ #  # ][ #  # ]:          0 :       clog << _F("Unable to unzip the server response '%s'\n", server_zipfile.c_str());
         [ #  # ][ #  # ]
    1353                 :          0 :       return rc;
    1354                 :            :     }
    1355                 :            : 
    1356                 :            :   // Determine the server protocol version.
    1357         [ +  - ]:         35 :   string filename = server_tmpdir + "/version";
    1358 [ +  - ][ +  - ]:         35 :   if (file_exists (filename))
    1359         [ +  - ]:         35 :     ::read_from_file (filename, server_version);
    1360                 :            : 
    1361                 :            :   // Warn about the shortcomings of this server, if it is down level.
    1362         [ +  - ]:         35 :   show_server_compatibility ();
    1363                 :            : 
    1364                 :            :   // If the server's response contains a systemtap temp directory, move
    1365                 :            :   // its contents to our temp directory.
    1366                 :            :   glob_t globbuf;
    1367         [ +  - ]:         35 :   string filespec = server_tmpdir + "/stap??????";
    1368         [ -  + ]:         35 :   if (s.verbose >= 3)
    1369 [ #  # ][ #  # ]:          0 :     clog << _F("Searching \"%s\"\n", filespec.c_str());
         [ #  # ][ #  # ]
    1370         [ +  - ]:         35 :   int r = glob(filespec.c_str (), 0, NULL, & globbuf);
    1371 [ +  - ][ +  - ]:         35 :   if (r != GLOB_NOSPACE && r != GLOB_ABORTED && r != GLOB_NOMATCH)
                 [ +  - ]
    1372                 :            :     {
    1373         [ -  + ]:         35 :       if (globbuf.gl_pathc > 1)
    1374                 :            :         {
    1375 [ #  # ][ #  # ]:          0 :           clog << _("Incorrect number of files in server response") << endl;
    1376                 :          0 :           rc = 1;
    1377                 :            :           goto done;
    1378                 :            :         }
    1379                 :            : 
    1380         [ -  + ]:         35 :       assert (globbuf.gl_pathc == 1);
    1381         [ +  - ]:         35 :       string dirname = globbuf.gl_pathv[0];
    1382         [ -  + ]:         35 :       if (s.verbose >= 3)
    1383 [ #  # ][ #  # ]:          0 :         clog << _("  found ") << dirname << endl;
                 [ #  # ]
    1384                 :            : 
    1385 [ +  - ][ +  - ]:         35 :       filespec = dirname + "/*";
                 [ +  - ]
    1386         [ -  + ]:         35 :       if (s.verbose >= 3)
    1387 [ #  # ][ #  # ]:          0 :        clog << _F("Searching \"%s\"\n", filespec.c_str());
         [ #  # ][ #  # ]
    1388         [ +  - ]:         35 :       int r = glob(filespec.c_str (), GLOB_PERIOD, NULL, & globbuf);
    1389 [ +  - ][ +  - ]:         35 :       if (r != GLOB_NOSPACE && r != GLOB_ABORTED && r != GLOB_NOMATCH)
                 [ +  - ]
    1390                 :            :         {
    1391         [ +  - ]:         35 :           unsigned prefix_len = dirname.size () + 1;
    1392         [ +  + ]:        105 :           for (unsigned i = 0; i < globbuf.gl_pathc; ++i)
    1393                 :            :             {
    1394         [ +  - ]:         70 :               string oldname = globbuf.gl_pathv[i];
    1395 [ +  - ][ +  - ]:        175 :               if (oldname.substr (oldname.size () - 2) == "/." ||
         [ +  - ][ +  + ]
         [ +  - ][ +  - ]
                 [ +  - ]
           [ +  -  #  # ]
    1396 [ +  - ][ +  - ]:        105 :                   oldname.substr (oldname.size () - 3) == "/..")
         [ +  - ][ +  + ]
         [ +  - ][ #  # ]
    1397                 :         70 :                 continue;
    1398 [ #  # ][ #  # ]:          0 :               string newname = s.tmpdir + "/" + oldname.substr (prefix_len);
         [ #  # ][ #  # ]
                 [ #  # ]
    1399         [ #  # ]:          0 :               if (s.verbose >= 3)
    1400 [ #  # ][ #  # ]:          0 :                clog << _F("  found %s -- linking from %s", oldname.c_str(), newname.c_str());
         [ #  # ][ #  # ]
                 [ #  # ]
    1401 [ #  # ][ #  # ]:          0 :               rc = symlink (oldname.c_str (), newname.c_str ());
    1402         [ #  # ]:          0 :               if (rc != 0)
    1403                 :            :                 {
    1404 [ #  # ][ #  # ]:          0 :                  clog << _F("Unable to link '%s' to '%s':%s\n",
         [ #  # ][ #  # ]
    1405         [ #  # ]:          0 :                             oldname.c_str(), newname.c_str(), strerror(errno));
    1406                 :            :                   goto done;
    1407                 :            :                 }
    1408 [ #  # ][ #  # ]:         70 :             }
                 [ +  - ]
              [ -  +  - ]
    1409 [ +  - ][ +  - ]:         35 :         }
    1410                 :            :     }
    1411                 :            : 
    1412                 :            :   // If the server version is less that 1.6, remove the output line due to the synthetic
    1413                 :            :   // server-side -k. Look for a message containing the name of the temporary directory.
    1414                 :            :   // We can look for the English message since server versions before 1.6 do not support
    1415                 :            :   // localization.
    1416 [ +  - ][ +  - ]:         35 :   if (server_version < "1.6")
         [ +  - ][ -  + ]
    1417                 :            :     {
    1418         [ #  # ]:          0 :       cmd.clear();
    1419 [ #  # ][ #  # ]:          0 :       cmd.push_back("sed");
                 [ #  # ]
    1420 [ #  # ][ #  # ]:          0 :       cmd.push_back("-i");
                 [ #  # ]
    1421 [ #  # ][ #  # ]:          0 :       cmd.push_back("/^Keeping temporary directory.*/ d");
                 [ #  # ]
    1422 [ #  # ][ #  # ]:          0 :       cmd.push_back(server_tmpdir + "/stderr");
                 [ #  # ]
    1423         [ #  # ]:          0 :       stap_system (s.verbose, cmd);
    1424                 :            :     }
    1425                 :            : 
    1426                 :            :   // Remove the output line due to the synthetic server-side -p4
    1427         [ +  - ]:         35 :   cmd.clear();
    1428 [ +  - ][ +  - ]:         35 :   cmd.push_back("sed");
                 [ +  - ]
    1429 [ +  - ][ +  - ]:         35 :   cmd.push_back("-i");
                 [ +  - ]
    1430 [ +  - ][ +  - ]:         35 :   cmd.push_back("/^.*\\.ko$/ d");
                 [ +  - ]
    1431 [ +  - ][ +  - ]:         35 :   cmd.push_back(server_tmpdir + "/stdout");
                 [ +  - ]
    1432         [ +  - ]:         35 :   stap_system (s.verbose, cmd);
    1433                 :            : 
    1434                 :            :  done:
    1435                 :         35 :   globfree (& globbuf);
    1436 [ +  - ][ +  - ]:         35 :   return rc;
                 [ +  - ]
    1437                 :            : }
    1438                 :            : 
    1439                 :            : int
    1440                 :         35 : compile_server_client::process_response ()
    1441                 :            : {
    1442                 :            :   // Pick up the results of running stap on the server.
    1443         [ +  - ]:         35 :   string filename = server_tmpdir + "/rc";
    1444                 :            :   int stap_rc;
    1445         [ +  - ]:         35 :   int rc = read_from_file (filename, stap_rc);
    1446         [ -  + ]:         35 :   if (rc != 0)
    1447                 :          0 :     return rc;
    1448                 :         35 :   rc = stap_rc;
    1449                 :            : 
    1450         [ +  + ]:         35 :   if (s.last_pass >= 4)
    1451                 :            :     {
    1452                 :            :       // The server should have returned a module.
    1453         [ +  - ]:         29 :       string filespec = s.tmpdir + "/*.ko";
    1454         [ -  + ]:         29 :       if (s.verbose >= 3)
    1455 [ #  # ][ #  # ]:          0 :        clog << _F("Searching \"%s\"\n", filespec.c_str());
         [ #  # ][ #  # ]
    1456                 :            : 
    1457                 :            :       glob_t globbuf;
    1458         [ +  - ]:         29 :       int r = glob(filespec.c_str (), 0, NULL, & globbuf);
    1459 [ +  - ][ +  - ]:         29 :       if (r != GLOB_NOSPACE && r != GLOB_ABORTED && r != GLOB_NOMATCH)
                 [ -  + ]
    1460                 :            :         {
    1461         [ #  # ]:          0 :           if (globbuf.gl_pathc > 1)
    1462 [ #  # ][ #  # ]:          0 :             clog << _("Incorrect number of modules in server response") << endl;
    1463                 :            :           else
    1464                 :            :             {
    1465         [ #  # ]:          0 :               assert (globbuf.gl_pathc == 1);
    1466         [ #  # ]:          0 :               string modname = globbuf.gl_pathv[0];
    1467         [ #  # ]:          0 :               if (s.verbose >= 3)
    1468 [ #  # ][ #  # ]:          0 :                 clog << _("  found ") << modname << endl;
                 [ #  # ]
    1469                 :            : 
    1470                 :            :               // If a module name was not specified by the user, then set it to
    1471                 :            :               // be the one generated by the server.
    1472         [ #  # ]:          0 :               if (! s.save_module)
    1473                 :            :                 {
    1474         [ #  # ]:          0 :                   vector<string> components;
    1475 [ #  # ][ #  # ]:          0 :                   tokenize (modname, components, "/");
                 [ #  # ]
    1476 [ #  # ][ #  # ]:          0 :                   s.module_name = components.back ();
    1477 [ #  # ][ #  # ]:          0 :                   s.module_name.erase(s.module_name.size() - 3);
                 [ #  # ]
    1478                 :            :                 }
    1479                 :            : 
    1480                 :            :               // If a uprobes.ko module was returned, then make note of it.
    1481         [ #  # ]:          0 :               string uprobes_ko;
    1482 [ #  # ][ #  # ]:          0 :               if (server_version < "1.6")
         [ #  # ][ #  # ]
    1483 [ #  # ][ #  # ]:          0 :                 uprobes_ko = s.tmpdir + "/server/uprobes.ko";
                 [ #  # ]
    1484                 :            :               else
    1485 [ #  # ][ #  # ]:          0 :                 uprobes_ko = s.tmpdir + "/uprobes/uprobes.ko";
                 [ #  # ]
    1486                 :            : 
    1487 [ #  # ][ #  # ]:          0 :               if (file_exists (uprobes_ko))
    1488                 :            :                 {
    1489                 :          0 :                   s.need_uprobes = true;
    1490         [ #  # ]:          0 :                   s.uprobes_path = uprobes_ko;
    1491 [ #  # ][ #  # ]:          0 :                 }
    1492                 :          0 :             }
    1493                 :            :         }
    1494         [ +  - ]:         29 :       else if (s.have_script)
    1495                 :            :         {
    1496         [ +  - ]:         29 :           if (rc == 0)
    1497                 :            :             {
    1498 [ +  - ][ +  - ]:         29 :               clog << _("No module was returned by the server.") << endl;
    1499                 :         29 :               rc = 1;
    1500                 :            :             }
    1501                 :            :         }
    1502         [ +  - ]:         29 :       globfree (& globbuf);
    1503                 :            :     }
    1504                 :            : 
    1505                 :            :   // Output stdout and stderr.
    1506 [ +  - ][ +  - ]:         35 :   filename = server_tmpdir + "/stderr";
                 [ +  - ]
    1507         [ +  - ]:         35 :   flush_to_stream (filename, clog);
    1508                 :            : 
    1509 [ +  - ][ +  - ]:         35 :   filename = server_tmpdir + "/stdout";
                 [ +  - ]
    1510         [ +  - ]:         35 :   flush_to_stream (filename, cout);
    1511                 :            : 
    1512         [ +  - ]:         35 :   return rc;
    1513                 :            : }
    1514                 :            : 
    1515                 :            : int
    1516                 :         35 : compile_server_client::read_from_file (const string &fname, int &data)
    1517                 :            : {
    1518                 :            :   // C++ streams may not set errno in the even of a failure. However if we
    1519                 :            :   // set it to 0 before each operation and it gets set during the operation,
    1520                 :            :   // then we can use its value in order to determine what happened.
    1521                 :         35 :   errno = 0;
    1522 [ +  - ][ +  - ]:         35 :   ifstream f (fname.c_str ());
    1523 [ +  - ][ -  + ]:         35 :   if (! f.good ())
    1524                 :            :     {
    1525 [ #  # ][ #  # ]:          0 :       clog << _F("Unable to open file '%s' for reading: ", fname.c_str());
         [ #  # ][ #  # ]
    1526                 :          0 :       goto error;
    1527                 :            :     }
    1528                 :            : 
    1529                 :            :   // Read the data;
    1530                 :         35 :   errno = 0;
    1531         [ +  - ]:         35 :   f >> data;
    1532 [ +  - ][ -  + ]:         35 :   if (f.fail ())
    1533                 :            :     {
    1534 [ #  # ][ #  # ]:          0 :       clog << _F("Unable to read from file '%s': ", fname.c_str());
         [ #  # ][ #  # ]
    1535                 :          0 :       goto error;
    1536                 :            :     }
    1537                 :            : 
    1538                 :            :   // NB: not necessary to f.close ();
    1539                 :         35 :   return 0; // Success
    1540                 :            : 
    1541                 :            :  error:
    1542         [ #  # ]:          0 :   if (errno)
    1543 [ #  # ][ #  # ]:          0 :     clog << strerror (errno) << endl;
    1544                 :            :   else
    1545 [ #  # ][ #  # ]:          0 :     clog << _("unknown error") << endl;
    1546         [ +  - ]:         35 :   return 1; // Failure
    1547                 :            : }
    1548                 :            : 
    1549                 :            : template <class T>
    1550                 :            : int
    1551                 :        215 : compile_server_client::write_to_file (const string &fname, const T &data)
    1552                 :            : {
    1553                 :            :   // C++ streams may not set errno in the even of a failure. However if we
    1554                 :            :   // set it to 0 before each operation and it gets set during the operation,
    1555                 :            :   // then we can use its value in order to determine what happened.
    1556                 :        215 :   errno = 0;
    1557         [ +  - ]:        215 :   ofstream f (fname.c_str ());
           [ +  -  +  - ]
                 [ +  - ]
    1558 [ +  - ][ -  + ]:        215 :   if (! f.good ())
         [ +  - ][ -  + ]
    1559                 :            :     {
    1560 [ #  # ][ #  # ]:          0 :       clog << _F("Unable to open file '%s' for writing: ", fname.c_str());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1561                 :          0 :       goto error;
    1562                 :            :     }
    1563                 :            : 
    1564                 :            :   // Write the data;
    1565 [ +  - ][ +  - ]:        215 :   f << data;
    1566                 :        215 :   errno = 0;
    1567         [ +  - ]:        215 :   if (f.fail ())
           [ -  +  +  - ]
                 [ -  + ]
    1568                 :            :     {
    1569 [ #  # ][ #  # ]:          0 :       clog << _F("Unable to write to file '%s': ", fname.c_str());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1570                 :          0 :       goto error;
    1571                 :            :     }
    1572                 :            : 
    1573                 :            :   // NB: not necessary to f.close ();
    1574                 :        215 :   return 0; // Success
    1575                 :            : 
    1576                 :            :  error:
    1577 [ #  # ][ #  # ]:          0 :   if (errno)
    1578 [ #  # ][ #  # ]:          0 :     clog << strerror (errno) << endl;
         [ #  # ][ #  # ]
    1579                 :            :   else
    1580 [ #  # ][ #  # ]:          0 :     clog << _("unknown error") << endl;
         [ #  # ][ #  # ]
    1581 [ +  - ][ +  - ]:        215 :   return 1; // Failure
    1582                 :            : }
    1583                 :            : 
    1584                 :            : int
    1585                 :         70 : compile_server_client::flush_to_stream (const string &fname, ostream &o)
    1586                 :            : {
    1587                 :            :   // C++ streams may not set errno in the even of a failure. However if we
    1588                 :            :   // set it to 0 before each operation and it gets set during the operation,
    1589                 :            :   // then we can use its value in order to determine what happened.
    1590                 :         70 :   errno = 0;
    1591 [ +  - ][ +  - ]:         70 :   ifstream f (fname.c_str ());
    1592 [ +  - ][ -  + ]:         70 :   if (! f.good ())
    1593                 :            :     {
    1594 [ #  # ][ #  # ]:          0 :       clog << _F("Unable to open file '%s' for reading: ", fname.c_str());
         [ #  # ][ #  # ]
    1595                 :          0 :       goto error;
    1596                 :            :     }
    1597                 :            : 
    1598                 :            :   // Stream the data
    1599                 :            : 
    1600                 :            :   // NB: o << f.rdbuf() misbehaves for some reason, appearing to close o,
    1601                 :            :   // which is unfortunate if o == clog or cout.
    1602                 :       1586 :   while (1)
    1603                 :            :     {
    1604                 :       1656 :       errno = 0;
    1605         [ +  - ]:       1656 :       int c = f.get();
    1606 [ +  - ][ +  + ]:       1656 :       if (f.eof ()) return 0; // normal exit
    1607 [ +  - ][ -  + ]:       1586 :       if (! f.good()) break;
    1608         [ +  - ]:       1586 :       o.put(c);
    1609 [ +  - ][ -  + ]:       1586 :       if (! o.good()) break;
    1610                 :            :     }
    1611                 :            : 
    1612                 :            :   // NB: not necessary to f.close ();
    1613                 :            : 
    1614                 :            :  error:
    1615         [ #  # ]:          0 :   if (errno)
    1616 [ #  # ][ #  # ]:          0 :     clog << strerror (errno) << endl;
    1617                 :            :   else
    1618 [ #  # ][ #  # ]:          0 :     clog << _("unknown error") << endl;
    1619         [ +  - ]:         70 :   return 1; // Failure
    1620                 :            : }
    1621                 :            : 
    1622                 :            : void
    1623                 :         35 : compile_server_client::show_server_compatibility () const
    1624                 :            : {
    1625                 :            :   // Locale sensitivity was added in version 1.6
    1626 [ +  - ][ -  + ]:         35 :   if (server_version < "1.6")
    1627                 :            :     {
    1628         [ #  # ]:          0 :       clog << _F("Server protocol version is %s\n", server_version.v);
    1629                 :          0 :       clog << _("The server does not use localization information passed by the client\n");
    1630                 :            :     }
    1631                 :         35 : }
    1632                 :            : 
    1633                 :            : // Issue a status message for when a server's trust is already in place.
    1634                 :            : static void
    1635                 :          0 : trust_already_in_place (
    1636                 :            :   const compile_server_info &server,
    1637                 :            :   const vector<compile_server_info> &server_list,
    1638                 :            :   const string cert_db_path,
    1639                 :            :   bool revoking
    1640                 :            : )
    1641                 :            : {
    1642                 :            :   // What level of trust?
    1643         [ #  # ]:          0 :   string purpose;
    1644 [ #  # ][ #  # ]:          0 :   if (cert_db_path == signing_cert_db_path ())
         [ #  # ][ #  # ]
    1645         [ #  # ]:          0 :     purpose = _("as a module signer for all users");
    1646                 :            :   else
    1647                 :            :     {
    1648         [ #  # ]:          0 :       purpose = _("as an SSL peer");
    1649 [ #  # ][ #  # ]:          0 :       if (cert_db_path == global_ssl_cert_db_path ())
         [ #  # ][ #  # ]
    1650         [ #  # ]:          0 :         purpose += _(" for all users");
    1651                 :            :       else
    1652         [ #  # ]:          0 :         purpose += _(" for the current user");
    1653                 :            :     }
    1654                 :            : 
    1655                 :            :   // Issue a message for each server in the list with the same certificate.
    1656                 :          0 :   unsigned limit = server_list.size ();
    1657         [ #  # ]:          0 :   for (unsigned i = 0; i < limit; ++i)
    1658                 :            :     {
    1659 [ #  # ][ #  # ]:          0 :       if (server.certinfo != server_list[i].certinfo)
    1660                 :          0 :         continue;
    1661 [ #  # ][ #  # ]:          0 :       clog << server_list[i] << _(" is already ");
    1662         [ #  # ]:          0 :       if (revoking)
    1663 [ #  # ][ #  # ]:          0 :         clog << _("untrusted ") << purpose << endl;
                 [ #  # ]
    1664                 :            :       else
    1665 [ #  # ][ #  # ]:          0 :        clog << _("trusted ") << purpose << endl;
                 [ #  # ]
    1666         [ #  # ]:          0 :     }
    1667                 :          0 : }
    1668                 :            : 
    1669                 :            : // Add the given servers to the given database of trusted servers.
    1670                 :            : static void
    1671                 :          1 : add_server_trust (
    1672                 :            :   systemtap_session &s,
    1673                 :            :   const string &cert_db_path,
    1674                 :            :   const vector<compile_server_info> &server_list
    1675                 :            : )
    1676                 :            : {
    1677                 :            :   // Get a list of servers already trusted. This opens the database, so do it
    1678                 :            :   // before we open it for our own purposes.
    1679         [ +  - ]:          1 :   vector<compile_server_info> already_trusted;
    1680         [ +  - ]:          1 :   get_server_info_from_db (s, already_trusted, cert_db_path);
    1681                 :            : 
    1682                 :            :   // Make sure the given path exists.
    1683 [ +  - ][ +  - ]:          1 :   if (create_dir (cert_db_path.c_str (), 0755) != 0)
                 [ -  + ]
    1684                 :            :     {
    1685 [ #  # ][ #  # ]:          0 :       clog << _F("Unable to find or create the client certificate database directory %s: ", cert_db_path.c_str());
         [ #  # ][ #  # ]
    1686         [ #  # ]:          0 :       perror ("");
    1687                 :          1 :       return;
    1688                 :            :     }
    1689                 :            : 
    1690                 :            :   // Must predeclare this because of jumps to cleanup: below.
    1691         [ +  - ]:          1 :   vector<string> processed_certs;
    1692                 :            : 
    1693                 :            :   // Make sure NSPR is initialized. Must be done before NSS is initialized
    1694         [ +  - ]:          1 :   s.NSPR_init ();
    1695                 :            : 
    1696                 :            :   // Initialize the NSS libraries -- read/write
    1697 [ +  - ][ +  - ]:          1 :   SECStatus secStatus = nssInit (cert_db_path.c_str (), 1/*readwrite*/);
    1698         [ -  + ]:          1 :   if (secStatus != SECSuccess)
    1699                 :            :     {
    1700                 :            :       // Message already issued.
    1701                 :          0 :       goto cleanup;
    1702                 :            :     }
    1703                 :            : 
    1704                 :            :   // Enable cipher suites which are allowed by U.S. export regulations.
    1705                 :            :   // SSL_ClearSessionCache is required for the new settings to take effect.
    1706         [ +  - ]:          1 :   secStatus = NSS_SetExportPolicy ();
    1707         [ +  - ]:          1 :   SSL_ClearSessionCache ();
    1708         [ -  + ]:          1 :   if (secStatus != SECSuccess)
    1709                 :            :     {
    1710         [ #  # ]:          0 :       clog << _("Unable to set NSS export policy");
    1711         [ #  # ]:          0 :       nssError ();
    1712                 :          0 :       goto cleanup;
    1713                 :            :     }
    1714                 :            :   
    1715                 :            :   // Iterate over the servers to become trusted. Contact each one and
    1716                 :            :   // add it to the list of trusted servers if it is not already trusted.
    1717                 :            :   // client_connect will issue any error messages.
    1718 [ +  - ][ +  - ]:          4 :   for (vector<compile_server_info>::const_iterator server = server_list.begin();
                 [ +  + ]
    1719         [ +  - ]:          2 :        server != server_list.end ();
    1720                 :            :        ++server)
    1721                 :            :     {
    1722                 :            :       // Trust is based on certificates. We need only add trust in the
    1723                 :            :       // same certificate once.
    1724 [ +  - ][ -  + ]:          1 :       if (find (processed_certs.begin (), processed_certs.end (),
    1725 [ +  - ][ +  - ]:          1 :                 server->certinfo) != processed_certs.end ())
         [ +  - ][ +  - ]
    1726                 :          0 :         continue;
    1727         [ +  - ]:          1 :       processed_certs.push_back (server->certinfo);
    1728                 :            : 
    1729                 :            :       // We need not contact the server if it is already trusted.
    1730 [ +  - ][ +  - ]:          2 :       if (find (already_trusted.begin (), already_trusted.end (), *server) !=
         [ +  - ][ -  + ]
    1731 [ +  - ][ +  - ]:          1 :           already_trusted.end ())
    1732                 :            :         {
    1733         [ #  # ]:          0 :           if (s.verbose >= 2)
    1734 [ #  # ][ #  # ]:          0 :             trust_already_in_place (*server, server_list, cert_db_path, false/*revoking*/);
                 [ #  # ]
    1735                 :          0 :           continue;
    1736                 :            :         }
    1737                 :            :       // At a minimum we need an ip_address along with a port
    1738                 :            :       // number in order to contact the server.
    1739 [ +  - ][ -  + ]:          1 :       if (! server->hasAddress() || server->port() == 0)
                 [ -  + ]
    1740                 :          0 :         continue;
    1741         [ +  - ]:          1 :       int rc = client_connect (*server, NULL, NULL, "permanent");
    1742         [ -  + ]:          1 :       if (rc != SUCCESS)
    1743                 :            :         {
    1744 [ #  # ][ #  # ]:          0 :           clog << _F("Unable to connect to %s", lex_cast(*server).c_str()) << endl;
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1745         [ #  # ]:          0 :           nssError ();
    1746                 :            :           // Additional information: if the address is IPv6 and is link-local, then it must
    1747                 :            :           // have a scope_id.
    1748 [ #  # ][ #  # ]:          0 :           if (isIPv6LinkLocal (server->address) && server->address.ipv6.scope_id == 0)
                 [ #  # ]
    1749                 :            :             {
    1750         [ #  # ]:          0 :               clog << _("  The address is an IPv6 link-local address with no scope specifier.")
    1751         [ #  # ]:          0 :                    << endl;
    1752                 :            :             }
    1753                 :            :         }
    1754                 :            :     }
    1755                 :            : 
    1756                 :            :  cleanup:
    1757                 :            :   // Shutdown NSS.
    1758                 :            :   // SSL_ClearSessionCache is required before shutdown for client applications.
    1759         [ +  - ]:          1 :   SSL_ClearSessionCache ();
    1760 [ +  - ][ +  - ]:          1 :   nssCleanup (cert_db_path.c_str ());
    1761                 :            : 
    1762                 :            :   // Make sure the database files are readable.
    1763                 :            :   glob_t globbuf;
    1764         [ +  - ]:          1 :   string filespec = cert_db_path + "/*.db";
    1765         [ -  + ]:          1 :   if (s.verbose >= 3)
    1766 [ #  # ][ #  # ]:          0 :     clog << _F("Searching \"%s\"\n", filespec.c_str());
         [ #  # ][ #  # ]
    1767         [ +  - ]:          1 :   int r = glob (filespec.c_str (), 0, NULL, & globbuf);
    1768 [ +  - ][ +  - ]:          1 :   if (r != GLOB_NOSPACE && r != GLOB_ABORTED && r != GLOB_NOMATCH)
                 [ +  - ]
    1769                 :            :     {
    1770         [ +  + ]:          4 :       for (unsigned i = 0; i < globbuf.gl_pathc; ++i)
    1771                 :            :         {
    1772         [ +  - ]:          3 :           string filename = globbuf.gl_pathv[i];
    1773         [ -  + ]:          3 :           if (s.verbose >= 3)
    1774 [ #  # ][ #  # ]:          0 :             clog << _("  found ") << filename << endl;
                 [ #  # ]
    1775                 :            : 
    1776 [ +  - ][ -  + ]:          3 :           if (chmod (filename.c_str (), 0644) != 0)
    1777                 :            :             {
    1778 [ #  # ][ #  # ]:          0 :              s.print_warning("Unable to change permissions on " + filename + ": ");
         [ #  # ][ #  # ]
                 [ #  # ]
    1779         [ #  # ]:          0 :               perror ("");
    1780                 :            :             }
    1781         [ +  - ]:          3 :         }
    1782 [ +  - ][ +  - ]:          1 :     }
         [ +  - ][ +  - ]
    1783                 :            : }
    1784                 :            : 
    1785                 :            : // Remove the given servers from the given database of trusted servers.
    1786                 :            : static void
    1787                 :          1 : revoke_server_trust (
    1788                 :            :   systemtap_session &s,
    1789                 :            :   const string &cert_db_path,
    1790                 :            :   const vector<compile_server_info> &server_list
    1791                 :            : )
    1792                 :            : {
    1793                 :            :   // Make sure the given path exists.
    1794 [ +  - ][ -  + ]:          1 :   if (! file_exists (cert_db_path))
    1795                 :            :     {
    1796         [ #  # ]:          0 :       if (s.verbose >= 5)
    1797                 :            :         {
    1798 [ #  # ][ #  # ]:          0 :           clog << _F("Certificate database '%s' does not exist",
         [ #  # ][ #  # ]
    1799         [ #  # ]:          0 :                      cert_db_path.c_str()) << endl;
    1800 [ #  # ][ #  # ]:          0 :           for (vector<compile_server_info>::const_iterator server = server_list.begin();
                 [ #  # ]
    1801         [ #  # ]:          0 :                server != server_list.end ();
    1802                 :            :                ++server)
    1803 [ #  # ][ #  # ]:          0 :             trust_already_in_place (*server, server_list, cert_db_path, true/*revoking*/);
                 [ #  # ]
    1804                 :            :         }
    1805                 :          1 :       return;
    1806                 :            :     }
    1807                 :            : 
    1808                 :            :   // Must predeclare these because of jumps to cleanup: below.
    1809                 :            :   CERTCertDBHandle *handle;
    1810                 :          1 :   PRArenaPool *tmpArena = NULL;
    1811                 :          1 :   CERTCertList *certs = NULL;
    1812                 :            :   CERTCertificate *db_cert;
    1813         [ +  - ]:          1 :   vector<string> processed_certs;
    1814                 :            :   const char *nickname;
    1815                 :            : 
    1816                 :            :   // Make sure NSPR is initialized. Must be done before NSS is initialized
    1817         [ +  - ]:          1 :   s.NSPR_init ();
    1818                 :            : 
    1819                 :            :   // Initialize the NSS libraries -- read/write
    1820 [ +  - ][ +  - ]:          1 :   SECStatus secStatus = nssInit (cert_db_path.c_str (), 1/*readwrite*/);
    1821         [ -  + ]:          1 :   if (secStatus != SECSuccess)
    1822                 :            :     {
    1823                 :            :       // Message already issued
    1824                 :          0 :       goto cleanup;
    1825                 :            :     }
    1826         [ +  - ]:          1 :   handle = CERT_GetDefaultCertDB();
    1827                 :            : 
    1828                 :            :   // A memory pool to work in
    1829         [ +  - ]:          1 :   tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    1830         [ -  + ]:          1 :   if (! tmpArena) 
    1831                 :            :     {
    1832         [ #  # ]:          0 :       clog << _("Out of memory:");
    1833         [ #  # ]:          0 :       nssError ();
    1834                 :          0 :       goto cleanup;
    1835                 :            :     }
    1836                 :            : 
    1837                 :            :   // Iterate over the servers to become untrusted.
    1838         [ +  - ]:          1 :   nickname = server_cert_nickname ();
    1839 [ +  - ][ +  - ]:          4 :   for (vector<compile_server_info>::const_iterator server = server_list.begin();
                 [ +  + ]
    1840         [ +  - ]:          2 :        server != server_list.end ();
    1841                 :            :        ++server)
    1842                 :            :     {
    1843                 :            :       // If the server's certificate serial number is unknown, then we can't
    1844                 :            :       // match it with one in the database.
    1845 [ +  - ][ -  + ]:          1 :       if (server->certinfo.empty ())
    1846                 :          0 :         continue;
    1847                 :            : 
    1848                 :            :       // Trust is based on certificates. We need only revoke trust in the same
    1849                 :            :       // certificate once.
    1850 [ +  - ][ -  + ]:          1 :       if (find (processed_certs.begin (), processed_certs.end (),
    1851 [ +  - ][ +  - ]:          1 :                 server->certinfo) != processed_certs.end ())
         [ +  - ][ +  - ]
    1852                 :          0 :         continue;
    1853         [ +  - ]:          1 :       processed_certs.push_back (server->certinfo);
    1854                 :            : 
    1855                 :            :       // Search the client-side database of trusted servers.
    1856         [ +  - ]:          1 :       db_cert = PK11_FindCertFromNickname (nickname, NULL);
    1857         [ -  + ]:          1 :       if (! db_cert)
    1858                 :            :         {
    1859                 :            :           // No trusted servers. Not an error, but issue a status message.
    1860         [ #  # ]:          0 :           if (s.verbose >= 2)
    1861 [ #  # ][ #  # ]:          0 :             trust_already_in_place (*server, server_list, cert_db_path, true/*revoking*/);
                 [ #  # ]
    1862                 :          0 :           continue;
    1863                 :            :         }
    1864                 :            : 
    1865                 :            :       // Here, we have one cert with the desired nickname.
    1866                 :            :       // Now, we will attempt to get a list of ALL certs 
    1867                 :            :       // with the same subject name as the cert we have.  That list 
    1868                 :            :       // should contain, at a minimum, the one cert we have already found.
    1869                 :            :       // If the list of certs is empty (NULL), the libraries have failed.
    1870                 :            :       certs = CERT_CreateSubjectCertList (NULL, handle, & db_cert->derSubject,
    1871 [ +  - ][ +  - ]:          1 :                                           PR_Now (), PR_FALSE);
    1872         [ +  - ]:          1 :       CERT_DestroyCertificate (db_cert);
    1873         [ -  + ]:          1 :       if (! certs)
    1874                 :            :         {
    1875 [ #  # ][ #  # ]:          0 :          clog << _F("Unable to query certificate database %s: ",
         [ #  # ][ #  # ]
    1876         [ #  # ]:          0 :                     cert_db_path.c_str()) << endl;
    1877         [ #  # ]:          0 :           PORT_SetError (SEC_ERROR_LIBRARY_FAILURE);
    1878         [ #  # ]:          0 :           nssError ();
    1879                 :            :           goto cleanup;
    1880                 :            :         }
    1881                 :            : 
    1882                 :            :       // Find the certificate matching the one belonging to our server.
    1883                 :            :       CERTCertListNode *node;
    1884         [ +  - ]:          2 :       for (node = CERT_LIST_HEAD (certs);
    1885                 :          1 :            ! CERT_LIST_END (node, certs);
    1886                 :            :            node = CERT_LIST_NEXT (node))
    1887                 :            :         {
    1888                 :            :           // The certificate we're working with.
    1889                 :          1 :           db_cert = node->cert;
    1890                 :            : 
    1891                 :            :           // Get the serial number.
    1892         [ +  - ]:          1 :           string serialNumber = get_cert_serial_number (db_cert);
    1893                 :            : 
    1894                 :            :           // Does the serial number match that of the current server?
    1895 [ +  - ][ -  + ]:          1 :           if (serialNumber != server->certinfo)
    1896                 :          1 :             continue; // goto next certificate
    1897                 :            : 
    1898                 :            :           // All is ok! Remove the certificate from the database.
    1899                 :            :           break;
    1900 [ +  - ][ -  + ]:          1 :         } // Loop over certificates in the database
    1901                 :            : 
    1902                 :            :       // Was a certificate matching the server found?  */
    1903         [ -  + ]:          1 :       if (CERT_LIST_END (node, certs))
    1904                 :            :         {
    1905                 :            :           // Not found. Server is already untrusted.
    1906         [ #  # ]:          0 :           if (s.verbose >= 2)
    1907 [ #  # ][ #  # ]:          0 :             trust_already_in_place (*server, server_list, cert_db_path, true/*revoking*/);
                 [ #  # ]
    1908                 :            :         }
    1909                 :            :       else
    1910                 :            :         {
    1911         [ +  - ]:          1 :           secStatus = SEC_DeletePermCertificate (db_cert);
    1912         [ -  + ]:          1 :           if (secStatus != SECSuccess)
    1913                 :            :             {
    1914 [ #  # ][ #  # ]:          0 :              clog << _F("Unable to remove certificate from %s: ",
         [ #  # ][ #  # ]
    1915         [ #  # ]:          0 :                         cert_db_path.c_str()) << endl;
    1916         [ #  # ]:          0 :               nssError ();
    1917                 :            :             }
    1918                 :            :         }
    1919         [ +  - ]:          1 :       CERT_DestroyCertList (certs);
    1920                 :          1 :       certs = NULL;
    1921                 :            :     } // Loop over servers
    1922                 :            : 
    1923                 :            :  cleanup:
    1924         [ -  + ]:          1 :   assert(!certs);
    1925         [ +  - ]:          1 :   if (tmpArena)
    1926         [ +  - ]:          1 :     PORT_FreeArena (tmpArena, PR_FALSE);
    1927                 :            : 
    1928 [ +  - ][ +  - ]:          1 :   nssCleanup (cert_db_path.c_str ());
                 [ +  - ]
    1929                 :            : }
    1930                 :            : 
    1931                 :            : // Obtain information about servers from the certificates in the given database.
    1932                 :            : static void
    1933                 :        134 : get_server_info_from_db (
    1934                 :            :   systemtap_session &s,
    1935                 :            :   vector<compile_server_info> &servers,
    1936                 :            :   const string &cert_db_path
    1937                 :            : )
    1938                 :            : {
    1939                 :            :   // Make sure the given path exists.
    1940         [ +  + ]:        134 :   if (! file_exists (cert_db_path))
    1941                 :            :     {
    1942         [ -  + ]:         84 :       if (s.verbose >= 5)
    1943         [ #  # ]:          0 :        clog << _F("Certificate database '%s' does not exist.",
    1944         [ #  # ]:          0 :                   cert_db_path.c_str()) << endl;
    1945                 :         84 :       return;
    1946                 :            :     }
    1947                 :            : 
    1948                 :            :   // Make sure NSPR is initialized. Must be done before NSS is initialized
    1949                 :         50 :   s.NSPR_init ();
    1950                 :            : 
    1951                 :            :   // Initialize the NSS libraries -- readonly
    1952                 :         50 :   SECStatus secStatus = nssInit (cert_db_path.c_str ());
    1953         [ -  + ]:         50 :   if (secStatus != SECSuccess)
    1954                 :            :     {
    1955                 :            :       // Message already issued.
    1956                 :          0 :       return;
    1957                 :            :     }
    1958                 :            : 
    1959                 :            :   // Must predeclare this because of jumps to cleanup: below.
    1960                 :         50 :   PRArenaPool *tmpArena = NULL;
    1961 [ +  - ][ +  - ]:         50 :   CERTCertList *certs = get_cert_list_from_db (server_cert_nickname ());
                 [ +  - ]
    1962         [ +  + ]:         50 :   if (! certs)
    1963                 :            :     {
    1964         [ -  + ]:          3 :       if (s.verbose >= 5)
    1965 [ #  # ][ #  # ]:          0 :         clog << _F("No certificate found in database %s", cert_db_path.c_str ()) << endl;
    1966                 :          3 :       goto cleanup;
    1967                 :            :     }
    1968                 :            : 
    1969                 :            :   // A memory pool to work in
    1970                 :         47 :   tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    1971         [ -  + ]:         47 :   if (! tmpArena) 
    1972                 :            :     {
    1973                 :          0 :       clog << _("Out of memory:");
    1974                 :          0 :       nssError ();
    1975                 :          0 :       goto cleanup;
    1976                 :            :     }
    1977         [ +  + ]:         94 :   for (CERTCertListNode *node = CERT_LIST_HEAD (certs);
    1978                 :         94 :        ! CERT_LIST_END (node, certs);
    1979                 :            :        node = CERT_LIST_NEXT (node))
    1980                 :            :     {
    1981         [ +  - ]:         47 :       compile_server_info server_info;
    1982                 :            : 
    1983                 :            :       // The certificate we're working with.
    1984                 :         47 :       CERTCertificate *db_cert = node->cert;
    1985                 :            : 
    1986                 :            :       // Get the host name. It is in the alt-name extension of the
    1987                 :            :       // certificate.
    1988                 :            :       SECItem subAltName;
    1989                 :         47 :       subAltName.data = NULL;
    1990                 :            :       secStatus = CERT_FindCertExtension (db_cert,
    1991                 :            :                                           SEC_OID_X509_SUBJECT_ALT_NAME,
    1992         [ +  - ]:         47 :                                           & subAltName);
    1993 [ +  - ][ -  + ]:         47 :       if (secStatus != SECSuccess || ! subAltName.data)
    1994                 :            :         {
    1995 [ #  # ][ #  # ]:          0 :           clog << _("Unable to find alt name extension on server certificate: ") << endl;
    1996         [ #  # ]:          0 :           nssError ();
    1997                 :          0 :           continue;
    1998                 :            :         }
    1999                 :            : 
    2000                 :            :       // Decode the extension.
    2001         [ +  - ]:         47 :       CERTGeneralName *nameList = CERT_DecodeAltNameExtension (tmpArena, & subAltName);
    2002         [ +  - ]:         47 :       SECITEM_FreeItem(& subAltName, PR_FALSE);
    2003         [ -  + ]:         47 :       if (! nameList)
    2004                 :            :         {
    2005 [ #  # ][ #  # ]:          0 :           clog << _("Unable to decode alt name extension on server certificate: ") << endl;
    2006         [ #  # ]:          0 :           nssError ();
    2007                 :          0 :           continue;
    2008                 :            :         }
    2009                 :            : 
    2010                 :            :       // We're interested in the first alternate name.
    2011         [ -  + ]:         47 :       assert (nameList->type == certDNSName);
    2012                 :            :       server_info.host_name = string ((const char *)nameList->name.other.data,
    2013 [ +  - ][ +  - ]:         47 :                                       nameList->name.other.len);
                 [ +  - ]
    2014                 :            :       // Don't free nameList. It's part of the tmpArena.
    2015                 :            : 
    2016                 :            :       // Get the serial number.
    2017 [ +  - ][ +  - ]:         47 :       server_info.certinfo = get_cert_serial_number (db_cert);
                 [ +  - ]
    2018                 :            : 
    2019                 :            :       // Our results will at a minimum contain this server.
    2020         [ +  - ]:         47 :       add_server_info (server_info, servers);
    2021                 :            : 
    2022                 :            :       // Augment the list by querying all online servers and keeping the ones
    2023                 :            :       // with the same cert serial number.
    2024         [ +  - ]:         47 :       vector<compile_server_info> online_servers;
    2025         [ +  - ]:         47 :       get_or_keep_online_server_info (s, online_servers, false/*keep*/);
    2026         [ +  - ]:         47 :       keep_server_info_with_cert_and_port (s, server_info, online_servers);
    2027         [ +  - ]:         47 :       add_server_info (online_servers, servers);
    2028 [ +  - ][ +  - ]:         47 :     }
                 [ +  - ]
    2029                 :            : 
    2030                 :            :  cleanup:
    2031         [ +  + ]:         50 :   if (certs)
    2032                 :         47 :     CERT_DestroyCertList (certs);
    2033         [ +  + ]:         50 :   if (tmpArena)
    2034                 :         47 :     PORT_FreeArena (tmpArena, PR_FALSE);
    2035                 :            : 
    2036                 :        134 :   nssCleanup (cert_db_path.c_str ());
    2037                 :            : }
    2038                 :            : 
    2039                 :            : // Utility Functions.
    2040                 :            : //-----------------------------------------------------------------------
    2041                 :         59 : ostream &operator<< (ostream &s, const compile_server_info &i)
    2042                 :            : {
    2043                 :            :   // Don't print empty information
    2044         [ -  + ]:         59 :   if (i.empty ())
    2045                 :          0 :     return s;
    2046                 :            : 
    2047                 :         59 :   s << " host=";
    2048         [ +  - ]:         59 :   if (! i.host_name.empty ())
    2049                 :         59 :     s << i.host_name;
    2050                 :            :   else
    2051                 :          0 :     s << "unknown";
    2052                 :         59 :   s << " address=";
    2053         [ +  - ]:         59 :   if (i.hasAddress())
    2054                 :            :     {
    2055                 :            :       PRStatus prStatus;
    2056         [ +  - ]:         59 :       switch (i.address.raw.family)
    2057                 :            :         {
    2058                 :            :         case PR_AF_INET:
    2059                 :            :         case PR_AF_INET6:
    2060                 :            :           {
    2061                 :            : #define MAX_NETADDR_SIZE 46 // from the NSPR API reference.
    2062                 :            :             char buf[MAX_NETADDR_SIZE];
    2063         [ +  - ]:         59 :             prStatus = PR_NetAddrToString(& i.address, buf, sizeof (buf));
    2064         [ +  - ]:         59 :             if (prStatus == PR_SUCCESS) {
    2065         [ +  - ]:         59 :               s << buf;
    2066                 :            :               break;
    2067                 :            :             }
    2068                 :            :           }
    2069                 :            :           // Fall through
    2070                 :            :         default:
    2071                 :          0 :           s << "offline";
    2072                 :         59 :           break;
    2073                 :            :         }
    2074                 :            :     }
    2075                 :            :   else
    2076                 :          0 :     s << "offline";
    2077                 :         59 :   s << " port=";
    2078         [ +  - ]:         59 :   if (i.port() != 0)
    2079                 :         59 :     s << i.port();
    2080                 :            :   else
    2081                 :          0 :     s << "unknown";
    2082                 :         59 :   s << " sysinfo=\"";
    2083         [ +  - ]:         59 :   if (! i.sysinfo.empty ())
    2084                 :         59 :     s << i.sysinfo << '"';
    2085                 :            :   else
    2086                 :          0 :     s << "unknown\"";
    2087                 :         59 :   s << " version=";
    2088         [ +  - ]:         59 :   if (! i.version.empty ())
    2089                 :         59 :     s << i.version;
    2090                 :            :   else
    2091                 :          0 :     s << "unknown";
    2092                 :         59 :   s << " certinfo=\"";
    2093         [ +  - ]:         59 :   if (! i.certinfo.empty ())
    2094                 :         59 :     s << i.certinfo << '"';
    2095                 :            :   else
    2096                 :          0 :     s << "unknown\"";
    2097                 :         59 :   return s;
    2098                 :            :     }
    2099                 :            : 
    2100                 :          0 : ostream &operator<< (ostream &s, const vector<compile_server_info> &v)
    2101                 :            : {
    2102                 :            :   // Indicate an empty list.
    2103 [ #  # ][ #  # ]:          0 :   if (v.size () == 0 || (v.size () == 1 && v[0].empty()))
         [ #  # ][ #  # ]
    2104                 :          0 :     s << "No Servers" << endl;
    2105                 :            :   else
    2106                 :            :     {
    2107         [ #  # ]:          0 :       for (unsigned i = 0; i < v.size(); ++i)
    2108                 :            :         {
    2109                 :            :           // Don't print empty items.
    2110         [ #  # ]:          0 :           if (! v[i].empty())
    2111                 :          0 :             s << v[i] << endl;
    2112                 :            :         }
    2113                 :            :     }
    2114                 :          0 :   return s;
    2115                 :            : }
    2116                 :            : 
    2117                 :            : PRNetAddr &
    2118                 :        385 : copyNetAddr (PRNetAddr &x, const PRNetAddr &y)
    2119                 :            : {
    2120                 :        385 :   PRUint32 saveScope = 0;
    2121                 :            : 
    2122                 :            :   // For IPv6 addresses, don't overwrite the scope_id of x unless x is uninitialized or it is 0.
    2123         [ -  + ]:        385 :   if (x.raw.family == PR_AF_INET6)
    2124                 :          0 :     saveScope = x.ipv6.scope_id;
    2125                 :            : 
    2126                 :        385 :   x = y;
    2127                 :            : 
    2128         [ -  + ]:        385 :   if (saveScope != 0)
    2129                 :          0 :     x.ipv6.scope_id = saveScope;
    2130                 :            : 
    2131                 :        385 :   return x;
    2132                 :            : }
    2133                 :            : 
    2134                 :            : bool
    2135                 :       1495 : operator== (const PRNetAddr &x, const PRNetAddr &y)
    2136                 :            : {
    2137                 :            :   // Same address family?
    2138         [ -  + ]:       1495 :   if (x.raw.family != y.raw.family)
    2139                 :          0 :     return false;
    2140                 :            : 
    2141      [ -  +  - ]:       1495 :   switch (x.raw.family)
    2142                 :            :     {
    2143                 :            :     case PR_AF_INET6:
    2144                 :            :       // If both scope ids are set, compare them.
    2145 [ #  # ][ #  # ]:          0 :       if (x.ipv6.scope_id != 0 && y.ipv6.scope_id != 0 && x.ipv6.scope_id != y.ipv6.scope_id)
                 [ #  # ]
    2146                 :          0 :         return false; // not equal
    2147                 :            :       // Scope is not a factor. Compare the address bits
    2148                 :          0 :       return memcmp (& x.ipv6.ip, & y.ipv6.ip, sizeof(x.ipv6.ip)) == 0;
    2149                 :            :     case PR_AF_INET:
    2150                 :       1495 :       return x.inet.ip == y.inet.ip;
    2151                 :            :     default:
    2152                 :          0 :       break;
    2153                 :            :     }
    2154                 :       1495 :   return false;
    2155                 :            : }
    2156                 :            : 
    2157                 :            : bool
    2158                 :       1157 : operator!= (const PRNetAddr &x, const PRNetAddr &y)
    2159                 :            : {
    2160                 :       1157 :   return !(x == y);
    2161                 :            : }
    2162                 :            : 
    2163                 :            : static PRIPv6Addr &
    2164                 :          0 : copyAddress (PRIPv6Addr &PRin6, const in6_addr &in6)
    2165                 :            : {
    2166                 :            :   // The NSPR type is a typedef of struct in6_addr, but C++ won't let us copy it
    2167                 :            :   assert (sizeof (PRin6) == sizeof (in6));
    2168                 :          0 :   memcpy (& PRin6, & in6, sizeof (PRin6));
    2169                 :          0 :   return PRin6;
    2170                 :            : }
    2171                 :            : 
    2172                 :            : // Return the default server specification, used when none is given on the
    2173                 :            : // command line.
    2174                 :            : static string
    2175                 :         26 : default_server_spec (const systemtap_session &s)
    2176                 :            : {
    2177                 :            :   // If --privilege=X has been used, where X is not stapdev,
    2178                 :            :   //   the default is online,trusted,compatible,signer
    2179                 :            :   // otherwise
    2180                 :            :   //   the default is online,trusted,compatible
    2181                 :            :   //
    2182                 :            :   // Having said that,
    2183                 :            :   //   'online' and 'compatible' will only succeed if we have avahi
    2184                 :            :   //   'trusted' and 'signer' will only succeed if we have NSS
    2185                 :            :   //
    2186         [ +  - ]:         26 :   string working_string = "online,trusted,compatible";
    2187 [ +  - ][ -  + ]:         26 :   if (! pr_contains (s.privilege, pr_stapdev))
    2188         [ #  # ]:          0 :     working_string += ",signer";
    2189                 :         26 :   return working_string;
    2190                 :            : }
    2191                 :            : 
    2192                 :            : static int
    2193                 :         42 : server_spec_to_pmask (const string &server_spec)
    2194                 :            : {
    2195                 :            :   // Construct a mask of the server properties that have been requested.
    2196                 :            :   // The available properties are:
    2197                 :            :   //     trusted    - servers which are trusted SSL peers.
    2198                 :            :   //     online     - online servers.
    2199                 :            :   //     compatible - servers which compile for the current kernel release
    2200                 :            :   //                  and architecture.
    2201                 :            :   //     signer     - servers which are trusted module signers.
    2202                 :            :   //     specified  - servers which have been specified using --use-server=XXX.
    2203                 :            :   //                  If no servers have been specified, then this is
    2204                 :            :   //                  equivalent to --list-servers=trusted,online,compatible.
    2205                 :            :   //     all        - all trusted servers, trusted module signers,
    2206                 :            :   //                  servers currently online and specified servers.
    2207         [ +  - ]:         42 :   string working_spec = server_spec;
    2208         [ +  - ]:         42 :   vector<string> properties;
    2209 [ +  - ][ +  - ]:         42 :   tokenize (working_spec, properties, ",");
                 [ +  - ]
    2210                 :         42 :   int pmask = 0;
    2211                 :         42 :   unsigned limit = properties.size ();
    2212         [ +  + ]:        149 :   for (unsigned i = 0; i < limit; ++i)
    2213                 :            :     {
    2214                 :        107 :       const string &property = properties[i];
    2215                 :            :       // Tolerate (and ignore) empty properties.
    2216 [ +  - ][ -  + ]:        107 :       if (property.empty ())
    2217                 :          0 :         continue;
    2218 [ +  - ][ +  + ]:        107 :       if (property == "all")
    2219                 :            :         {
    2220                 :          1 :           pmask |= compile_server_all;
    2221                 :            :         }
    2222 [ +  - ][ -  + ]:        106 :       else if (property == "specified")
    2223                 :            :         {
    2224                 :          0 :           pmask |= compile_server_specified;
    2225                 :            :         }
    2226 [ +  - ][ +  + ]:        106 :       else if (property == "trusted")
    2227                 :            :         {
    2228                 :         35 :           pmask |= compile_server_trusted;
    2229                 :            :         }
    2230 [ +  - ][ +  + ]:         71 :       else if (property == "online")
    2231                 :            :         {
    2232                 :         36 :           pmask |= compile_server_online;
    2233                 :            :         }
    2234 [ +  - ][ +  + ]:         35 :       else if (property == "compatible")
    2235                 :            :         {
    2236                 :         31 :           pmask |= compile_server_compatible;
    2237                 :            :         }
    2238 [ +  - ][ +  - ]:          4 :       else if (property == "signer")
    2239                 :            :         {
    2240                 :          4 :           pmask |= compile_server_signer;
    2241                 :            :         }
    2242                 :            :       else
    2243                 :            :         {
    2244                 :            :           // XXX PR13274 needs-session to use print_warning()
    2245 [ #  # ][ #  # ]:          0 :           clog << _F("WARNING: unsupported compile server property: %s", property.c_str())
         [ #  # ][ #  # ]
    2246         [ #  # ]:          0 :                << endl;
    2247                 :            :         }
    2248                 :            :     }
    2249 [ +  - ][ +  - ]:         42 :   return pmask;
    2250                 :            : }
    2251                 :            : 
    2252                 :            : void
    2253                 :       2212 : query_server_status (systemtap_session &s)
    2254                 :            : {
    2255                 :       2212 :   unsigned limit = s.server_status_strings.size ();
    2256         [ +  + ]:       2228 :   for (unsigned i = 0; i < limit; ++i)
    2257                 :         16 :     query_server_status (s, s.server_status_strings[i]);
    2258                 :       2212 : }
    2259                 :            : 
    2260                 :            : static void
    2261                 :         16 : query_server_status (systemtap_session &s, const string &status_string)
    2262                 :            : {
    2263                 :            :   // If this string is empty, then the default is "specified"
    2264         [ +  - ]:         16 :   string working_string = status_string;
    2265 [ +  - ][ -  + ]:         16 :   if (working_string.empty ())
    2266         [ #  # ]:          0 :     working_string = "specified";
    2267                 :            : 
    2268                 :            :   // If the query is "specified" and no servers have been specified
    2269                 :            :   // (i.e. --use-server not used or used with no argument), then
    2270                 :            :   // use the default query.
    2271                 :            :   // TODO: This may not be necessary. The underlying queries should handle
    2272                 :            :   //       "specified" properly.
    2273 [ +  - ][ -  + ]:         16 :   if (working_string == "specified" &&
           [ #  #  #  # ]
         [ #  # ][ -  + ]
    2274         [ #  # ]:          0 :       (s.specified_servers.empty () ||
    2275         [ #  # ]:          0 :        (s.specified_servers.size () == 1 && s.specified_servers[0].empty ())))
    2276 [ #  # ][ #  # ]:          0 :     working_string = default_server_spec (s);
                 [ #  # ]
    2277                 :            : 
    2278         [ +  - ]:         16 :   int pmask = server_spec_to_pmask (working_string);
    2279                 :            : 
    2280                 :            :   // Now obtain a list of the servers which match the criteria.
    2281         [ +  - ]:         16 :   vector<compile_server_info> raw_servers;
    2282         [ +  - ]:         16 :   get_server_info (s, pmask, raw_servers);
    2283                 :            : 
    2284                 :            :   // Augment the listing with as much information as possible by adding
    2285                 :            :   // information from known servers.
    2286         [ +  - ]:         16 :   vector<compile_server_info> servers;
    2287         [ +  - ]:         16 :   get_all_server_info (s, servers);
    2288         [ +  - ]:         16 :   keep_common_server_info (raw_servers, servers);
    2289                 :            : 
    2290                 :            :   // Sort the list of servers into a preferred order.
    2291         [ +  - ]:         16 :   preferred_order (servers);
    2292                 :            : 
    2293                 :            :   // Print the server information. Skip the empty entry at the head of the list.
    2294 [ +  - ][ +  - ]:         16 :   clog << _F("Systemtap Compile Server Status for '%s'", working_string.c_str()) << endl;
         [ +  - ][ +  - ]
                 [ +  - ]
    2295                 :         16 :   bool found = false;
    2296                 :         16 :   unsigned limit = servers.size ();
    2297         [ +  + ]:         38 :   for (unsigned i = 0; i < limit; ++i)
    2298                 :            :     {
    2299 [ +  - ][ -  + ]:         22 :       assert (! servers[i].empty ());
    2300                 :            :       // Don't list servers with no cert information. They may not actually
    2301                 :            :       // exist.
    2302                 :            :       // TODO: Could try contacting the server and obtaining its cert
    2303 [ +  - ][ -  + ]:         22 :       if (servers[i].certinfo.empty ())
    2304                 :          0 :         continue;
    2305 [ +  - ][ +  - ]:         22 :       clog << servers[i] << endl;
    2306                 :         22 :       found = true;
    2307                 :            :     }
    2308         [ +  + ]:         16 :   if (! found)
    2309 [ +  - ][ +  - ]:         16 :     clog << _("No servers found") << endl;
         [ +  - ][ +  - ]
                 [ +  - ]
    2310                 :         16 : }
    2311                 :            : 
    2312                 :            : // Add or remove trust of the servers specified on the command line.
    2313                 :            : void
    2314                 :       2212 : manage_server_trust (systemtap_session &s)
    2315                 :            : {
    2316                 :            :   // This function should do nothing if we don't have NSS.
    2317                 :            :   // Nothing to do if --trust-servers was not specified.
    2318 [ +  - ][ +  + ]:       2212 :   if (s.server_trust_spec.empty ())
    2319                 :            :     return;
    2320                 :            : 
    2321                 :            :   // Break up and analyze the trust specification. Recognized components are:
    2322                 :            :   //   ssl       - trust the specified servers as ssl peers
    2323                 :            :   //   signer    - trust the specified servers as module signers
    2324                 :            :   //   revoke    - revoke the requested trust
    2325                 :            :   //   all-users - apply/revoke the requested trust for all users
    2326                 :            :   //   no-prompt - don't prompt the user for confirmation
    2327         [ +  - ]:          2 :   vector<string>components;
    2328 [ +  - ][ +  - ]:          2 :   tokenize (s.server_trust_spec, components, ",");
                 [ +  - ]
    2329                 :          2 :   bool ssl = false;
    2330                 :          2 :   bool signer = false;
    2331                 :          2 :   bool revoke = false;
    2332                 :          2 :   bool all_users = false;
    2333                 :          2 :   bool no_prompt = false;
    2334                 :          2 :   bool error = false;
    2335 [ +  - ][ +  - ]:         12 :   for (vector<string>::const_iterator i = components.begin ();
         [ +  - ][ +  + ]
    2336         [ +  - ]:          6 :        i != components.end ();
    2337                 :            :        ++i)
    2338                 :            :     {
    2339 [ +  - ][ +  + ]:          4 :       if (*i == "ssl")
    2340                 :          1 :         ssl = true;
    2341 [ +  - ][ -  + ]:          3 :       else if (*i == "signer")
    2342                 :            :         {
    2343         [ #  # ]:          0 :           if (geteuid () != 0)
    2344                 :            :             {
    2345 [ #  # ][ #  # ]:          0 :               clog << _("Only root can specify 'signer' on --trust-servers") << endl;
    2346                 :          0 :               error = true;
    2347                 :            :             }
    2348                 :            :           else
    2349                 :          0 :             signer = true;
    2350                 :            :         }
    2351 [ +  - ][ +  + ]:          3 :       else if (*i == "revoke")
    2352                 :          1 :         revoke = true;
    2353 [ +  - ][ -  + ]:          2 :       else if (*i == "all-users")
    2354                 :            :         {
    2355         [ #  # ]:          0 :           if (geteuid () != 0)
    2356                 :            :             {
    2357 [ #  # ][ #  # ]:          0 :               clog << _("Only root can specify 'all-users' on --trust-servers") << endl;
    2358                 :          0 :               error = true;
    2359                 :            :             }
    2360                 :            :           else
    2361                 :          0 :             all_users = true;
    2362                 :            :         }
    2363 [ +  - ][ +  - ]:          2 :       else if (*i == "no-prompt")
    2364                 :          2 :         no_prompt = true;
    2365                 :            :       else
    2366 [ #  # ][ #  # ]:          0 :         s.print_warning("Unrecognized server trust specification: " + *i);
                 [ #  # ]
    2367                 :            :     }
    2368         [ -  + ]:          2 :   if (error)
    2369                 :            :     return;
    2370                 :            : 
    2371                 :            :   // Make sure NSPR is initialized
    2372         [ +  - ]:          2 :   s.NSPR_init ();
    2373                 :            : 
    2374                 :            :   // Now obtain the list of specified servers.
    2375         [ +  - ]:          2 :   vector<compile_server_info> server_list;
    2376         [ +  - ]:          2 :   get_specified_server_info (s, server_list, true/*no_default*/);
    2377                 :            : 
    2378                 :            :   // Did we identify any potential servers?
    2379                 :          2 :   unsigned limit = server_list.size ();
    2380         [ -  + ]:          2 :   if (limit == 0)
    2381                 :            :     {
    2382 [ #  # ][ #  # ]:          0 :       clog << _("No servers identified for trust") << endl;
    2383                 :            :       return;
    2384                 :            :     }
    2385                 :            : 
    2386                 :            :   // Create a string representing the request in English.
    2387                 :            :   // If neither 'ssl' or 'signer' was specified, the default is 'ssl'.
    2388 [ +  + ][ +  - ]:          2 :   if (! ssl && ! signer)
    2389                 :          1 :     ssl = true;
    2390         [ +  - ]:          2 :   ostringstream trustString;
    2391         [ +  - ]:          2 :   if (ssl)
    2392                 :            :     {
    2393         [ +  - ]:          2 :       trustString << _("as an SSL peer");
    2394         [ -  + ]:          2 :       if (all_users)
    2395         [ #  # ]:          0 :         trustString << _(" for all users");
    2396                 :            :       else
    2397         [ +  - ]:          2 :         trustString << _(" for the current user");
    2398                 :            :     }
    2399         [ -  + ]:          2 :   if (signer)
    2400                 :            :     {
    2401         [ #  # ]:          0 :       if (ssl)
    2402         [ #  # ]:          0 :         trustString << _(" and ");
    2403         [ #  # ]:          0 :       trustString << _("as a module signer for all users");
    2404                 :            :     }
    2405                 :            : 
    2406                 :            :   // Prompt the user to confirm what's about to happen.
    2407         [ +  - ]:          2 :   if (no_prompt)
    2408                 :            :     {
    2409         [ +  + ]:          2 :       if (revoke)
    2410         [ +  - ]:          1 :         clog << _("Revoking trust ");
    2411                 :            :       else
    2412         [ +  - ]:          1 :         clog << _("Adding trust ");
    2413                 :            :     }
    2414                 :            :   else
    2415                 :            :     {
    2416         [ #  # ]:          0 :       if (revoke)
    2417         [ #  # ]:          0 :         clog << _("Revoke trust ");
    2418                 :            :       else
    2419         [ #  # ]:          0 :         clog << _("Add trust ");
    2420                 :            :     }
    2421 [ +  - ][ +  - ]:          2 :   clog << _F("in the following servers %s", trustString.str().c_str());
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
    2422         [ -  + ]:          2 :   if (! no_prompt)
    2423         [ #  # ]:          0 :     clog << '?';
    2424         [ +  - ]:          2 :   clog << endl;
    2425         [ +  + ]:          4 :   for (unsigned i = 0; i < limit; ++i)
    2426 [ +  - ][ +  - ]:          2 :     clog << "  " << server_list[i] << endl;
                 [ +  - ]
    2427         [ -  + ]:          2 :   if (! no_prompt)
    2428                 :            :     {
    2429 [ #  # ][ #  # ]:          0 :       clog << "[y/N] " << flush;
    2430                 :            : 
    2431                 :            :       // Only carry out the operation if the response is "yes"
    2432         [ #  # ]:          0 :       string response;
    2433         [ #  # ]:          0 :       cin >> response;
    2434 [ #  # ][ #  # ]:          0 :       if (response[0] != 'y' && response [0] != 'Y')
         [ #  # ][ #  # ]
                 [ #  # ]
    2435                 :            :         {
    2436 [ #  # ][ #  # ]:          0 :           clog << _("Server trust unchanged") << endl;
    2437                 :            :           return;
    2438 [ #  # ][ #  # ]:          0 :         }
    2439                 :            :     }
    2440                 :            : 
    2441                 :            :   // Now add/revoke the requested trust.
    2442         [ +  - ]:          2 :   string cert_db_path;
    2443         [ +  - ]:          2 :   if (ssl)
    2444                 :            :     {
    2445         [ -  + ]:          2 :       if (all_users)
    2446 [ #  # ][ #  # ]:          0 :         cert_db_path = global_ssl_cert_db_path ();
                 [ #  # ]
    2447                 :            :       else
    2448 [ +  - ][ +  - ]:          2 :         cert_db_path = private_ssl_cert_db_path ();
                 [ +  - ]
    2449         [ +  + ]:          2 :       if (revoke)
    2450         [ +  - ]:          1 :         revoke_server_trust (s, cert_db_path, server_list);
    2451                 :            :       else
    2452         [ +  - ]:          1 :         add_server_trust (s, cert_db_path, server_list);
    2453                 :            :     }
    2454         [ -  + ]:          2 :   if (signer)
    2455                 :            :     {
    2456 [ #  # ][ #  # ]:          0 :       cert_db_path = signing_cert_db_path ();
                 [ #  # ]
    2457         [ #  # ]:          0 :       if (revoke)
    2458         [ #  # ]:          0 :         revoke_server_trust (s, cert_db_path, server_list);
    2459                 :            :       else
    2460         [ #  # ]:          0 :         add_server_trust (s, cert_db_path, server_list);
    2461 [ +  - ][ +  - ]:       2212 :     }
         [ -  + ][ +  - ]
         [ -  + ][ +  - ]
                 [ +  - ]
    2462                 :            : }
    2463                 :            : 
    2464                 :            : static compile_server_cache*
    2465                 :        443 : cscache(systemtap_session& s)
    2466                 :            : {
    2467         [ +  + ]:        443 :   if (!s.server_cache)
    2468         [ +  - ]:         53 :     s.server_cache = new compile_server_cache();
    2469                 :        443 :   return s.server_cache;
    2470                 :            : }
    2471                 :            : 
    2472                 :            : static void
    2473                 :         42 : get_server_info (
    2474                 :            :   systemtap_session &s,
    2475                 :            :   int pmask,
    2476                 :            :   vector<compile_server_info> &servers
    2477                 :            : )
    2478                 :            : {
    2479                 :            :   // Get information on compile servers matching the requested criteria.
    2480                 :            :   // The order of queries is significant. Accumulating queries must go first
    2481                 :            :   // followed by accumulating/filtering queries.
    2482                 :         42 :   bool keep = false;
    2483         [ +  + ]:         42 :   if (((pmask & compile_server_all)))
    2484                 :            :     {
    2485                 :          1 :       get_all_server_info (s, servers);
    2486                 :          1 :       keep = true;
    2487                 :            :     }
    2488                 :            :   // Add the specified servers, if requested
    2489         [ -  + ]:         42 :   if ((pmask & compile_server_specified))
    2490                 :            :     {
    2491                 :          0 :       get_specified_server_info (s, servers);
    2492                 :          0 :       keep = true;
    2493                 :            :     }
    2494                 :            :   // Now filter or accumulate the list depending on whether a query has
    2495                 :            :   // already been made.
    2496         [ +  + ]:         42 :   if ((pmask & compile_server_online))
    2497                 :            :     {
    2498                 :         36 :       get_or_keep_online_server_info (s, servers, keep);
    2499                 :         36 :       keep = true;
    2500                 :            :     }
    2501         [ +  + ]:         42 :   if ((pmask & compile_server_trusted))
    2502                 :            :     {
    2503                 :         35 :       get_or_keep_trusted_server_info (s, servers, keep);
    2504                 :         35 :       keep = true;
    2505                 :            :     }
    2506         [ +  + ]:         42 :   if ((pmask & compile_server_signer))
    2507                 :            :     {
    2508                 :          4 :       get_or_keep_signing_server_info (s, servers, keep);
    2509                 :          4 :       keep = true;
    2510                 :            :     }
    2511         [ +  + ]:         42 :   if ((pmask & compile_server_compatible))
    2512                 :            :     {
    2513                 :         31 :       get_or_keep_compatible_server_info (s, servers, keep);
    2514                 :         31 :       keep = true;
    2515                 :            :     }
    2516                 :         42 : }
    2517                 :            : 
    2518                 :            : // Get information about all online servers as well as servers trusted
    2519                 :            : // as SSL peers and servers trusted as signers.
    2520                 :            : static void
    2521                 :         28 : get_all_server_info (
    2522                 :            :   systemtap_session &s,
    2523                 :            :   vector<compile_server_info> &servers
    2524                 :            : )
    2525                 :            : {
    2526                 :            :   // We only need to obtain this once per session. This is a good thing(tm)
    2527                 :            :   // since obtaining this information is expensive.
    2528                 :         28 :   vector<compile_server_info>& all_servers = cscache(s)->all_servers;
    2529         [ +  - ]:         28 :   if (all_servers.empty ())
    2530                 :            :     {
    2531                 :         28 :       get_or_keep_online_server_info (s, all_servers, false/*keep*/);
    2532                 :         28 :       get_or_keep_trusted_server_info (s, all_servers, false/*keep*/);
    2533                 :         28 :       get_or_keep_signing_server_info (s, all_servers, false/*keep*/);
    2534                 :            : 
    2535         [ -  + ]:         28 :       if (s.verbose >= 4)
    2536                 :            :         {
    2537                 :          0 :           clog << _("All known servers:") << endl;
    2538                 :          0 :           clog << all_servers;
    2539                 :            :         }
    2540                 :            :     }
    2541                 :            : 
    2542                 :            :   // Add the information, but not duplicates.
    2543                 :         28 :   add_server_info (all_servers, servers);
    2544                 :         28 : }
    2545                 :            : 
    2546                 :            : static void
    2547                 :         26 : get_default_server_info (
    2548                 :            :   systemtap_session &s,
    2549                 :            :   vector<compile_server_info> &servers
    2550                 :            : )
    2551                 :            : {
    2552         [ -  + ]:         26 :   if (s.verbose >= 3)
    2553                 :          0 :     clog << _("Using the default servers") << endl;
    2554                 :            : 
    2555                 :            :   // We only need to obtain this once per session. This is a good thing(tm)
    2556                 :            :   // since obtaining this information is expensive.
    2557                 :         26 :   vector<compile_server_info>& default_servers = cscache(s)->default_servers;
    2558         [ +  - ]:         26 :   if (default_servers.empty ())
    2559                 :            :     {
    2560                 :            :       // Get the required information.
    2561                 :            :       // get_server_info will add an empty entry at the beginning to indicate
    2562                 :            :       // that the search has been performed, in case the search comes up empty.
    2563         [ +  - ]:         26 :       int pmask = server_spec_to_pmask (default_server_spec (s));
    2564                 :         26 :       get_server_info (s, pmask, default_servers);
    2565                 :            : 
    2566         [ -  + ]:         26 :       if (s.verbose >= 3)
    2567                 :            :         {
    2568                 :          0 :           clog << _("Default servers are:") << endl;
    2569                 :          0 :           clog << default_servers;
    2570                 :            :         }
    2571                 :            :     }
    2572                 :            : 
    2573                 :            :   // Add the information, but not duplicates.
    2574                 :         26 :   add_server_info (default_servers, servers);
    2575                 :         26 : }
    2576                 :            : 
    2577                 :            : static bool
    2578                 :          9 : isPort (const char *pstr, compile_server_info &server_info)
    2579                 :            : {
    2580                 :          9 :   errno = 0;
    2581                 :            :   char *estr;
    2582                 :          9 :   unsigned long p = strtoul (pstr, & estr, 10);
    2583 [ +  - ][ +  - ]:          9 :   if (errno != 0 || *estr != '\0' || p > USHRT_MAX)
                 [ -  + ]
    2584                 :            :     {
    2585 [ #  # ][ #  # ]:          0 :       clog << _F("Invalid port number specified: %s", pstr) << endl;
         [ #  # ][ #  # ]
    2586                 :          0 :       return false;
    2587                 :            :     }
    2588                 :          9 :   server_info.setPort (p);
    2589                 :          9 :   return true;
    2590                 :            : }
    2591                 :            : 
    2592                 :            : static bool
    2593                 :         11 : isIPv6 (const string &server, compile_server_info &server_info)
    2594                 :            : {
    2595                 :            :   // An IPv6 address is 8 hex components separated by colons.
    2596                 :            :   // One contiguous block of zero segments in the address may be elided using ::.
    2597                 :            :   // An interface may be specified by appending %IF_NAME to the address (e.g. %eth0).
    2598                 :            :   // A port may be specified by enclosing the ip address in [] and adding :<port>.
    2599                 :            :   // Allow a bracketed address without a port.
    2600 [ +  - ][ -  + ]:         11 :   assert (! server.empty());
    2601         [ +  - ]:         11 :   string ip;
    2602                 :            :   string::size_type portIx;
    2603 [ +  - ][ -  + ]:         11 :   if (server[0] == '[')
    2604                 :            :     {
    2605         [ #  # ]:          0 :       string::size_type endBracket = server.find (']');
    2606         [ #  # ]:          0 :       if (endBracket == string::npos)
    2607                 :          0 :         return false; // Not a valid IPv6 address
    2608                 :            :       // Extract the address.
    2609 [ #  # ][ #  # ]:          0 :       ip = server.substr (1, endBracket - 1);
                 [ #  # ]
    2610                 :          0 :       portIx = endBracket + 1;
    2611                 :            :     }
    2612                 :            :   else
    2613                 :            :     {
    2614         [ +  - ]:         11 :       ip = server;
    2615                 :         11 :       portIx = string::npos;
    2616                 :            :     }
    2617                 :            : 
    2618                 :            :   // Find out how many components there are. The maximum is 8
    2619                 :         11 :   unsigned empty = 0;
    2620         [ +  - ]:         11 :   vector<string> components;
    2621 [ +  - ][ +  - ]:         11 :   tokenize_full (ip, components, ":");
                 [ +  - ]
    2622         [ -  + ]:         11 :   if (components.size() > 8)
    2623                 :          0 :     return false; // Not a valid IPv6 address
    2624                 :            : 
    2625                 :            :   // The components must be either hex values between 0 and 0xffff, or must be empty.
    2626                 :            :   // There can be only one empty component.
    2627         [ +  - ]:         11 :   string interface;
    2628         [ +  + ]:         11 :   for (unsigned i = 0; i < components.size(); ++i)
    2629                 :            :     {
    2630 [ +  - ][ -  + ]:          9 :       if (components[i].empty())
    2631                 :            :         {
    2632         [ #  # ]:          0 :           if (++empty > 1)
    2633                 :          0 :             return false; // Not a valid IPv6 address
    2634                 :            :         }
    2635                 :            :       // If it's the final component, see if it specifies the interface. If so, strip it from the
    2636                 :            :       // component in order to simplify parsing. It still remains as part of the original ip address
    2637                 :            :       // string.
    2638         [ -  + ]:          9 :       if (i == components.size() - 1)
    2639                 :            :         {
    2640         [ #  # ]:          0 :           size_t ix = components[i].find ('%');
    2641         [ #  # ]:          0 :           if (ix != string::npos)
    2642                 :            :             {
    2643 [ #  # ][ #  # ]:          0 :               interface = components[i].substr(ix);
                 [ #  # ]
    2644 [ #  # ][ #  # ]:          0 :               components[i] = components[i].substr(0, ix);
                 [ #  # ]
    2645                 :            :             }
    2646                 :            :         }
    2647                 :            :       // Skip leading zeroes.
    2648                 :            :       unsigned j;
    2649 [ +  - ][ +  - ]:          9 :       for (j = 0; j < components[i].size(); ++j)
    2650                 :            :         {
    2651 [ +  - ][ +  - ]:          9 :           if (components[i][j] != '0')
    2652                 :          9 :             break;
    2653                 :            :         }
    2654                 :            :       // Max of 4 hex digits
    2655 [ +  - ][ +  - ]:          9 :       if (components[i].size() - j > 4)
    2656                 :          9 :         return false; // Not a valid IPv6 address
    2657 [ #  # ][ #  # ]:          0 :       for (/**/; j < components[i].size(); ++j)
    2658                 :            :         {
    2659 [ #  # ][ #  # ]:          0 :           if (! isxdigit (components[i][j]))
    2660                 :          0 :             return false; // Not a valid IPv6 address
    2661                 :            :         }
    2662                 :            :     }
    2663                 :            :   // If there is no empty component, then there must be exactly 8 components.
    2664 [ +  - ][ +  - ]:          2 :   if (! empty && components.size() != 8)
                 [ +  - ]
    2665                 :          2 :     return false; // Not a valid IPv6 address
    2666                 :            : 
    2667                 :            :   // Calls to setPort and isPort need to know that this is an IPv6 address.
    2668                 :          0 :   server_info.address.raw.family = PR_AF_INET6;
    2669                 :            : 
    2670                 :            :   // Examine the optional port
    2671         [ #  # ]:          0 :   if (portIx != string::npos)
    2672                 :            :     {
    2673         [ #  # ]:          0 :       string port = server.substr (portIx);
    2674 [ #  # ][ #  # ]:          0 :       if (port.size() != 0)
    2675                 :            :         {
    2676 [ #  # ][ #  # ]:          0 :           if (port.size() < 2 || port[0] != ':')
         [ #  # ][ #  # ]
                 [ #  # ]
    2677                 :          0 :             return false; // Not a valid Port
    2678                 :            : 
    2679 [ #  # ][ #  # ]:          0 :           port = port.substr (1);
                 [ #  # ]
    2680 [ #  # ][ #  # ]:          0 :           if (! isPort (port.c_str(), server_info))
                 [ #  # ]
    2681                 :          0 :             return false; // not a valid port
    2682 [ #  # ][ #  # ]:          0 :         }
    2683                 :            :     }
    2684                 :            :   else
    2685                 :          0 :     server_info.setPort (0);
    2686                 :            : 
    2687                 :            :   // Treat the ip address string like a host name.
    2688         [ #  # ]:          0 :   server_info.host_name = ip;
    2689 [ +  - ][ +  - ]:         11 :   return true; // valid IPv6 address.
                 [ +  - ]
    2690                 :            : }
    2691                 :            : 
    2692                 :            : static bool
    2693                 :         11 : isIPv4 (const string &server, compile_server_info &server_info)
    2694                 :            : {
    2695                 :            :   // An IPv4 address is 4 decimal components separated by periods with an
    2696                 :            :   // additional optional decimal port separated from the address by a colon.
    2697 [ +  - ][ -  + ]:         11 :   assert (! server.empty());
    2698                 :            : 
    2699                 :            :   // Find out how many components there are. The maximum is 8
    2700         [ +  - ]:         11 :   vector<string> components;
    2701 [ +  - ][ +  - ]:         11 :   tokenize (server, components, ":");
                 [ +  - ]
    2702         [ -  + ]:         11 :   if (components.size() > 2)
    2703                 :          0 :     return false; // Not a valid IPv4 address
    2704                 :            : 
    2705                 :            :   // Separate the host from the port (if any).
    2706         [ +  - ]:         11 :   string host;
    2707         [ +  - ]:         11 :   string port;
    2708         [ +  + ]:         11 :   if (components.size() <= 1)
    2709         [ +  - ]:          2 :     host = server;
    2710                 :            :   else {
    2711         [ +  - ]:          9 :     host = components[0];
    2712         [ +  - ]:          9 :     port = components[1];
    2713                 :            :   }
    2714                 :            : 
    2715                 :            :   // Separate the host components.
    2716                 :            :   // There must be exactly 4 components.
    2717         [ +  - ]:         11 :   components.clear ();
    2718 [ +  - ][ +  - ]:         11 :   tokenize (server, components, ".");
                 [ +  - ]
    2719         [ +  + ]:         11 :   if (components.size() != 4)
    2720                 :         10 :     return false; // Not a valid IPv4 address
    2721                 :            :   
    2722                 :            :   // The components must be decimal values between 0 and 255.
    2723         [ +  + ]:          5 :   for (unsigned i = 0; i < components.size(); ++i)
    2724                 :            :     {
    2725 [ +  - ][ -  + ]:          4 :       if (components[i].empty())
    2726                 :          0 :         return false; // Not a valid IPv4 address
    2727                 :          4 :       errno = 0;
    2728                 :            :       char *estr;
    2729         [ +  - ]:          4 :       long p = strtol (components[i].c_str(), & estr, 10);
    2730 [ +  - ][ +  - ]:          4 :       if (errno != 0 || *estr != '\0' || p < 0 || p > 255)
         [ +  - ][ -  + ]
    2731                 :          0 :         return false; // Not a valid IPv4 address
    2732                 :            :     }
    2733                 :            : 
    2734                 :            :   // Calls to setPort and isPort need to know that this is an IPv4 address.
    2735                 :          1 :   server_info.address.raw.family = PR_AF_INET;
    2736                 :            : 
    2737                 :            :   // Examine the optional port
    2738 [ +  - ][ -  + ]:          1 :   if (! port.empty ()) {
    2739 [ #  # ][ #  # ]:          0 :     if (! isPort (port.c_str(), server_info))
                 [ #  # ]
    2740                 :          0 :       return false; // not a valid port
    2741                 :            :   }
    2742                 :            :   else
    2743                 :          1 :     server_info.setPort (0);
    2744                 :            : 
    2745                 :            :   // Treat the ip address string like a host name.
    2746         [ +  - ]:          1 :   server_info.host_name = host;
    2747 [ +  - ][ +  - ]:         11 :   return true; // valid IPv4 address.
                 [ +  - ]
    2748                 :            : }
    2749                 :            : 
    2750                 :            : static bool
    2751                 :          0 : isCertSerialNumber (const string &server, compile_server_info &server_info)
    2752                 :            : {
    2753                 :            :   // This function assumes that we have already ruled out the server spec being an IPv6 address.
    2754                 :            :   // Certificate serial numbers are 5 fields separated by colons plus an optional 6th decimal
    2755                 :            :   // field specifying a port.
    2756                 :            :   // Assume IPv4 (for now) when storing the port.
    2757                 :          0 :   server_info.address.raw.family = PR_AF_INET;
    2758 [ #  # ][ #  # ]:          0 :   assert (! server.empty());
    2759         [ #  # ]:          0 :   string host = server;
    2760         [ #  # ]:          0 :   vector<string> components;
    2761 [ #  # ][ #  # ]:          0 :   tokenize (host, components, ":");
                 [ #  # ]
    2762      [ #  #  # ]:          0 :   switch (components.size ())
    2763                 :            :     {
    2764                 :            :     case 6:
    2765 [ #  # ][ #  # ]:          0 :       if (! isPort (components.back().c_str(), server_info))
         [ #  # ][ #  # ]
    2766                 :          0 :         return false; // not a valid port
    2767 [ #  # ][ #  # ]:          0 :       host = host.substr (0, host.find_last_of (':'));
         [ #  # ][ #  # ]
    2768                 :            :       // fall through
    2769                 :            :     case 5:
    2770         [ #  # ]:          0 :       server_info.certinfo = host;
    2771                 :          0 :       break;
    2772                 :            :     default:
    2773                 :          0 :       return false; // not a cert serial number
    2774                 :            :     }
    2775                 :            : 
    2776 [ #  # ][ #  # ]:          0 :   return true; // valid cert serial number and optional port
    2777                 :            : }
    2778                 :            : 
    2779                 :            : static bool
    2780                 :         10 : isDomain (const string &server, compile_server_info &server_info)
    2781                 :            : {
    2782                 :            :   // Accept one or two components separated by a colon. The first will be the domain name and
    2783                 :            :   // the second must a port number.
    2784                 :            :   // Assume IPv4 (for now) when storing the port.
    2785                 :         10 :   server_info.address.raw.family = PR_AF_INET;
    2786 [ +  - ][ -  + ]:         10 :   assert (! server.empty());
    2787         [ +  - ]:         10 :   string host = server;
    2788         [ +  - ]:         10 :   vector<string> components;
    2789 [ +  - ][ +  - ]:         10 :   tokenize (host, components, ":");
                 [ +  - ]
    2790      [ +  +  - ]:         10 :   switch (components.size ())
    2791                 :            :     {
    2792                 :            :     case 2:
    2793 [ +  - ][ +  - ]:          9 :       if (! isPort (components.back().c_str(), server_info))
         [ +  - ][ -  + ]
    2794                 :          0 :         return false; // not a valid port
    2795 [ +  - ][ +  - ]:          9 :       host = host.substr (0, host.find_last_of (':'));
         [ +  - ][ +  - ]
    2796                 :            :       // fall through
    2797                 :            :     case 1:
    2798         [ +  - ]:         10 :       server_info.host_name = host;
    2799                 :         10 :       break;
    2800                 :            :     default:
    2801                 :          0 :       return false; // not a valid domain name
    2802                 :            :     }
    2803                 :            : 
    2804 [ +  - ][ +  - ]:         10 :   return true;
    2805                 :            : }
    2806                 :            : 
    2807                 :            : static void
    2808                 :         37 : get_specified_server_info (
    2809                 :            :   systemtap_session &s,
    2810                 :            :   vector<compile_server_info> &servers,
    2811                 :            :   bool no_default
    2812                 :            : )
    2813                 :            : {
    2814                 :            :   // We only need to obtain this once per session. This is a good thing(tm)
    2815                 :            :   // since obtaining this information is expensive.
    2816                 :         37 :   vector<compile_server_info>& specified_servers = cscache(s)->specified_servers;
    2817         [ +  - ]:         37 :   if (specified_servers.empty ())
    2818                 :            :     {
    2819                 :            :       // Maintain an empty entry to indicate that this search has been
    2820                 :            :       // performed, in case the search comes up empty.
    2821         [ +  - ]:         37 :       specified_servers.push_back (compile_server_info ());
    2822                 :            : 
    2823                 :            :       // If --use-server was not specified at all, then return info for the
    2824                 :            :       // default server list.
    2825         [ -  + ]:         37 :       if (s.specified_servers.empty ())
    2826                 :            :         {
    2827         [ #  # ]:          0 :           if (s.verbose >= 3)
    2828                 :          0 :             clog << _("No servers specified") << endl;
    2829         [ #  # ]:          0 :           if (! no_default)
    2830                 :          0 :             get_default_server_info (s, specified_servers);
    2831                 :            :         }
    2832                 :            :       else
    2833                 :            :         {
    2834                 :            :           // Iterate over the specified servers. For each specification, add to
    2835                 :            :           // the list of servers.
    2836                 :         37 :           unsigned num_specified_servers = s.specified_servers.size ();
    2837         [ +  + ]:         74 :           for (unsigned i = 0; i < num_specified_servers; ++i)
    2838                 :            :             {
    2839                 :         37 :               string &server = s.specified_servers[i];
    2840                 :            : 
    2841                 :            :               // If no specific server(s) specified, then use the default servers.
    2842 [ +  - ][ +  + ]:         37 :               if (server.empty ())
    2843                 :            :                 {
    2844         [ -  + ]:         26 :                   if (s.verbose >= 3)
    2845 [ #  # ][ #  # ]:          0 :                     clog << _("No servers specified") << endl;
    2846         [ +  - ]:         26 :                   if (! no_default)
    2847         [ +  - ]:         26 :                     get_default_server_info (s, specified_servers);
    2848                 :         26 :                   continue;
    2849                 :            :                 }
    2850                 :            : 
    2851                 :            :               // Determine what has been specified. Servers may be specified by:
    2852                 :            :               // - domain{:port}
    2853                 :            :               // - certificate-serial-number{:port}
    2854                 :            :               // - IPv4-address{:port}
    2855                 :            :               // - IPv6-address{:port}
    2856                 :            :               // where items within {} are optional.
    2857                 :            :               // Check for IPv6 addresses first. It reduces the amount of checking necessary for
    2858                 :            :               // certificate serial numbers.
    2859         [ +  - ]:         11 :               compile_server_info server_info;
    2860         [ +  - ]:         11 :               vector<compile_server_info> known_servers;
    2861 [ +  - ][ +  - ]:         21 :               if (isIPv6 (server, server_info) || isIPv4 (server, server_info) ||
         [ +  - ][ +  + ]
         [ +  - ][ +  - ]
    2862         [ +  - ]:         10 :                   isDomain (server, server_info))
    2863                 :            :                 {
    2864                 :            :                   // Resolve this host and add any information that is discovered.
    2865                 :            :                   // Try to augment the resolved servers with information about known servers.
    2866                 :            :                   // There may be no intersection.
    2867         [ +  - ]:         11 :                   get_all_server_info (s, known_servers);
    2868                 :            : 
    2869         [ +  - ]:         11 :                   vector<compile_server_info> resolved_servers;
    2870         [ +  - ]:         11 :                   resolve_host (s, server_info, resolved_servers);
    2871                 :            : 
    2872         [ +  - ]:         11 :                   vector<compile_server_info> common_servers = resolved_servers;
    2873         [ +  - ]:         11 :                   keep_common_server_info (known_servers, common_servers);
    2874 [ +  - ][ +  - ]:         11 :                   if (! common_servers.empty ())
    2875         [ +  - ]:         11 :                     add_server_info (common_servers, resolved_servers);
    2876                 :            : 
    2877         [ -  + ]:         11 :                   if (s.verbose >= 3)
    2878                 :            :                     {
    2879 [ #  # ][ #  # ]:          0 :                       clog << _F("Servers matching %s: ", server.c_str()) << endl;
         [ #  # ][ #  # ]
                 [ #  # ]
    2880         [ #  # ]:          0 :                       clog << resolved_servers;
    2881                 :            :                     }
    2882 [ +  - ][ +  - ]:         11 :                   add_server_info (resolved_servers, specified_servers);
                 [ +  - ]
    2883                 :            :                 }
    2884 [ #  # ][ #  # ]:          0 :               else if (isCertSerialNumber (server, server_info))
    2885                 :            :                 {
    2886                 :            :                   // The host could not be resolved. Try resolving it as a certificate serial
    2887                 :            :                   // number. Look for all known servers with this serial number and (optional)
    2888                 :            :                   // port number.
    2889         [ #  # ]:          0 :                   get_all_server_info (s, known_servers);
    2890         [ #  # ]:          0 :                   keep_server_info_with_cert_and_port (s, server_info, known_servers);
    2891         [ #  # ]:          0 :                   if (s.verbose >= 3)
    2892                 :            :                     {
    2893 [ #  # ][ #  # ]:          0 :                       clog << _F("Servers matching %s: ", server.c_str()) << endl;
         [ #  # ][ #  # ]
                 [ #  # ]
    2894         [ #  # ]:          0 :                       clog << known_servers;
    2895                 :            :                     }
    2896                 :            : 
    2897         [ #  # ]:          0 :                   add_server_info (known_servers, specified_servers);
    2898                 :            :                 }
    2899                 :            :               else
    2900                 :            :                 {
    2901 [ #  # ][ #  # ]:          0 :                   clog << _F("Invalid server specification for --use-server: %s", server.c_str())
         [ #  # ][ #  # ]
    2902         [ #  # ]:          0 :                        << endl;
    2903                 :            :                 }
    2904 [ +  - ][ +  - ]:         11 :             } // Loop over --use-server options
    2905                 :            :         } // -- use-server specified
    2906                 :            : 
    2907         [ -  + ]:         37 :       if (s.verbose >= 2)
    2908                 :            :         {
    2909                 :          0 :           clog << _("All specified servers:") << endl;
    2910                 :          0 :           clog << specified_servers;
    2911                 :            :         }
    2912                 :            :     } // Server information is not cached
    2913                 :            : 
    2914                 :            :   // Add the information, but not duplicates.
    2915                 :         37 :   add_server_info (specified_servers, servers);
    2916                 :         37 : }
    2917                 :            : 
    2918                 :            : static void
    2919                 :         63 : get_or_keep_trusted_server_info (
    2920                 :            :   systemtap_session &s,
    2921                 :            :   vector<compile_server_info> &servers,
    2922                 :            :   bool keep
    2923                 :            : )
    2924                 :            : {
    2925                 :            :   // If we're filtering the list and it's already empty, then
    2926                 :            :   // there's nothing to do.
    2927 [ +  + ][ -  + ]:         63 :   if (keep && servers.empty ())
                 [ -  + ]
    2928                 :         63 :     return;
    2929                 :            : 
    2930                 :            :   // We only need to obtain this once per session. This is a good thing(tm)
    2931                 :            :   // since obtaining this information is expensive.
    2932                 :         63 :   vector<compile_server_info>& trusted_servers = cscache(s)->trusted_servers;
    2933         [ +  + ]:         63 :   if (trusted_servers.empty ())
    2934                 :            :     {
    2935                 :            :       // Maintain an empty entry to indicate that this search has been
    2936                 :            :       // performed, in case the search comes up empty.
    2937 [ +  - ][ +  - ]:         53 :       trusted_servers.push_back (compile_server_info ());
                 [ +  - ]
    2938                 :            : 
    2939                 :            :       // Check the private database first.
    2940         [ +  - ]:         53 :       string cert_db_path = private_ssl_cert_db_path ();
    2941         [ +  - ]:         53 :       get_server_info_from_db (s, trusted_servers, cert_db_path);
    2942                 :            : 
    2943                 :            :       // Now check the global database.
    2944 [ +  - ][ +  - ]:         53 :       cert_db_path = global_ssl_cert_db_path ();
                 [ +  - ]
    2945         [ +  - ]:         53 :       get_server_info_from_db (s, trusted_servers, cert_db_path);
    2946                 :            : 
    2947         [ -  + ]:         53 :       if (s.verbose >= 5)
    2948                 :            :         {
    2949 [ #  # ][ #  # ]:          0 :           clog << _("All servers trusted as ssl peers:") << endl;
    2950         [ #  # ]:          0 :           clog << trusted_servers;
    2951         [ +  - ]:         53 :         }
    2952                 :            :     } // Server information is not cached
    2953                 :            : 
    2954         [ +  + ]:         63 :   if (keep)
    2955                 :            :     {
    2956                 :            :       // Filter the existing vector by keeping the information in common with
    2957                 :            :       // the trusted_server vector.
    2958                 :         33 :       keep_common_server_info (trusted_servers, servers);
    2959                 :            :     }
    2960                 :            :   else
    2961                 :            :     {
    2962                 :            :       // Add the information, but not duplicates.
    2963                 :         30 :       add_server_info (trusted_servers, servers);
    2964                 :            :     }
    2965                 :            : }
    2966                 :            : 
    2967                 :            : static void
    2968                 :         32 : get_or_keep_signing_server_info (
    2969                 :            :   systemtap_session &s,
    2970                 :            :   vector<compile_server_info> &servers,
    2971                 :            :   bool keep
    2972                 :            : )
    2973                 :            : {
    2974                 :            :   // If we're filtering the list and it's already empty, then
    2975                 :            :   // there's nothing to do.
    2976 [ +  + ][ -  + ]:         32 :   if (keep && servers.empty ())
                 [ -  + ]
    2977                 :         32 :     return;
    2978                 :            : 
    2979                 :            :   // We only need to obtain this once per session. This is a good thing(tm)
    2980                 :            :   // since obtaining this information is expensive.
    2981                 :         32 :   vector<compile_server_info>& signing_servers = cscache(s)->signing_servers;
    2982         [ +  + ]:         32 :   if (signing_servers.empty ())
    2983                 :            :     {
    2984                 :            :       // Maintain an empty entry to indicate that this search has been
    2985                 :            :       // performed, in case the search comes up empty.
    2986 [ +  - ][ +  - ]:         27 :       signing_servers.push_back (compile_server_info ());
                 [ +  - ]
    2987                 :            : 
    2988                 :            :       // For all users, check the global database.
    2989         [ +  - ]:         27 :       string cert_db_path = signing_cert_db_path ();
    2990         [ +  - ]:         27 :       get_server_info_from_db (s, signing_servers, cert_db_path);
    2991                 :            : 
    2992         [ -  + ]:         27 :       if (s.verbose >= 5)
    2993                 :            :         {
    2994 [ #  # ][ #  # ]:          0 :           clog << _("All servers trusted as module signers:") << endl;
    2995         [ #  # ]:          0 :           clog << signing_servers;
    2996         [ +  - ]:         27 :         }
    2997                 :            :     } // Server information is not cached
    2998                 :            : 
    2999         [ +  + ]:         32 :   if (keep)
    3000                 :            :     {
    3001                 :            :       // Filter the existing vector by keeping the information in common with
    3002                 :            :       // the signing_server vector.
    3003                 :          1 :       keep_common_server_info (signing_servers, servers);
    3004                 :            :     }
    3005                 :            :   else
    3006                 :            :     {
    3007                 :            :       // Add the information, but not duplicates.
    3008                 :         31 :       add_server_info (signing_servers, servers);
    3009                 :            :     }
    3010                 :            : }
    3011                 :            : 
    3012                 :            : 
    3013                 :            : static void
    3014                 :         31 : get_or_keep_compatible_server_info (
    3015                 :            :   systemtap_session &s,
    3016                 :            :   vector<compile_server_info> &servers,
    3017                 :            :   bool keep
    3018                 :            : )
    3019                 :            : {
    3020                 :            : #if HAVE_AVAHI
    3021                 :            :   // If we're filtering the list and it's already empty, then
    3022                 :            :   // there's nothing to do.
    3023 [ +  - ][ +  - ]:         31 :   if (keep && servers.empty ())
         [ -  + ][ +  - ]
    3024                 :         31 :     return;
    3025                 :            : 
    3026                 :            :   // Remove entries for servers incompatible with the host environment
    3027                 :            :   // from the given list of servers.
    3028                 :            :   // A compatible server compiles for the kernel release and architecture
    3029                 :            :   // of the host environment.
    3030                 :            :   //
    3031                 :            :   // Compatibility can only be determined for online servers. So, augment
    3032                 :            :   // and filter the information we have with information for online servers.
    3033         [ +  - ]:         31 :   vector<compile_server_info> online_servers;
    3034         [ +  - ]:         31 :   get_or_keep_online_server_info (s, online_servers, false/*keep*/);
    3035         [ +  - ]:         31 :   if (keep)
    3036         [ +  - ]:         31 :     keep_common_server_info (online_servers, servers);
    3037                 :            :   else
    3038         [ #  # ]:          0 :     add_server_info (online_servers, servers);
    3039                 :            : 
    3040                 :            :   // Now look to see which ones are compatible.
    3041                 :            :   // The vector can change size as we go, so be careful!!
    3042         [ +  + ]:         99 :   for (unsigned i = 0; i < servers.size (); /**/)
    3043                 :            :     {
    3044                 :            :       // Retain empty entries.
    3045 [ +  - ][ -  + ]:         68 :       assert (! servers[i].empty ());
    3046                 :            : 
    3047                 :            :       // Check the target of the server.
    3048 [ +  - ][ +  - ]:         68 :       if (servers[i].sysinfo != s.kernel_release + " " + s.architecture)
         [ +  - ][ +  - ]
         [ +  - ][ -  + ]
    3049                 :            :         {
    3050                 :            :           // Target platform mismatch.
    3051 [ #  # ][ #  # ]:          0 :           servers.erase (servers.begin () + i);
                 [ #  # ]
    3052                 :          0 :           continue;
    3053                 :            :         }
    3054                 :            :   
    3055                 :            :       // The server is compatible. Leave it in the list.
    3056                 :         68 :       ++i;
    3057         [ +  - ]:         31 :     }
    3058                 :            : #else // ! HAVE_AVAHI
    3059                 :            :   // Without Avahi, we can't obtain the target platform of the server.
    3060                 :            :   // Issue a warning.
    3061                 :            :   if (s.verbose >= 2)
    3062                 :            :     clog << _("Unable to detect server compatibility without avahi") << endl;
    3063                 :            :   if (keep)
    3064                 :            :     servers.clear ();
    3065                 :            : #endif
    3066                 :            : }
    3067                 :            : 
    3068                 :            : static void
    3069                 :         47 : keep_server_info_with_cert_and_port (
    3070                 :            :   systemtap_session &,
    3071                 :            :   const compile_server_info &server,
    3072                 :            :   vector<compile_server_info> &servers
    3073                 :            : )
    3074                 :            : {
    3075         [ -  + ]:         47 :   assert (! server.certinfo.empty ());
    3076                 :            : 
    3077                 :            :   // Search the list of servers for ones matching the
    3078                 :            :   // serial number specified.
    3079                 :            :   // The vector can change size as we go, so be careful!!
    3080         [ +  + ]:        147 :   for (unsigned i = 0; i < servers.size (); /**/)
    3081                 :            :     {
    3082                 :            :       // Retain empty entries.
    3083         [ -  + ]:        100 :       if (servers[i].empty ())
    3084                 :            :         {
    3085                 :          0 :           ++i;
    3086                 :          0 :           continue;
    3087                 :            :         }
    3088   [ +  -  +  -  :        300 :       if (servers[i].certinfo == server.certinfo &&
             -  +  #  # ]
                 [ +  - ]
    3089                 :        200 :           (servers[i].port() == 0 || server.port() == 0 ||
    3090                 :          0 :            servers[i].port() == server.port()))
    3091                 :            :         {
    3092                 :            :           // If the server is not online, then use the specified
    3093                 :            :           // port, if any.
    3094         [ -  + ]:        100 :           if (servers[i].port() == 0)
    3095                 :          0 :             servers[i].setPort (server.port());
    3096                 :        100 :           ++i;
    3097                 :        100 :           continue;
    3098                 :            :         }
    3099                 :            :       // The item does not match. Delete it.
    3100 [ #  # ][ #  # ]:          0 :       servers.erase (servers.begin () + i);
    3101                 :            :     }
    3102                 :         47 : }
    3103                 :            : 
    3104                 :            : // Obtain missing host name or ip address, if any. Return 0 on success.
    3105                 :            : static void
    3106                 :        115 : resolve_host (
    3107                 :            :   systemtap_session& s,
    3108                 :            :   compile_server_info &server,
    3109                 :            :   vector<compile_server_info> &resolved_servers
    3110                 :            : )
    3111                 :            : {
    3112                 :        115 :   vector<compile_server_info>& cached_servers = cscache(s)->resolved_servers[server.host_name];
    3113         [ +  + ]:        115 :   if (cached_servers.empty ())
    3114                 :            :     {
    3115                 :            :       // The server's host_name member is a string containing either a host name or an ip address.
    3116                 :            :       // Either is acceptable for lookup.
    3117         [ +  - ]:         50 :       const char *lookup_name = server.host_name.c_str();
    3118         [ -  + ]:         50 :       if (s.verbose >= 6)
    3119 [ #  # ][ #  # ]:          0 :         clog << _F("Looking up %s", lookup_name) << endl;
         [ #  # ][ #  # ]
    3120                 :            : 
    3121                 :            :       struct addrinfo hints;
    3122                 :         50 :       memset(& hints, 0, sizeof (hints));
    3123                 :         50 :       hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version
    3124                 :         50 :       struct addrinfo *addr_info = 0;
    3125         [ +  - ]:         50 :       int rc = getaddrinfo (lookup_name, NULL, & hints, & addr_info);
    3126                 :            : 
    3127                 :            :       // Failure to resolve will result in an appropriate message later, if other methods fail.
    3128         [ +  + ]:         50 :       if (rc != 0)
    3129                 :            :         {
    3130                 :            :           // At a minimum, return the information we were given.
    3131         [ -  + ]:         49 :           if (s.verbose >= 6)
    3132 [ #  # ][ #  # ]:          0 :             clog << _F("%s not found: %s", lookup_name, gai_strerror (rc)) << endl;
         [ #  # ][ #  # ]
    3133         [ +  - ]:         49 :           add_server_info (server, cached_servers);
    3134                 :            :         }
    3135                 :            :       else
    3136                 :            :         {
    3137                 :            :           // Loop over the results collecting information.
    3138         [ -  + ]:          1 :           assert (addr_info);
    3139         [ +  + ]:          4 :           for (const struct addrinfo *ai = addr_info; ai != NULL; ai = ai->ai_next)
    3140                 :            :             {
    3141                 :            :               // Start with the info we were given.
    3142         [ +  - ]:          3 :               compile_server_info new_server = server;
    3143                 :            : 
    3144                 :            :               // We support IPv4 and IPv6, Ignore other protocols,
    3145         [ +  - ]:          3 :               if (ai->ai_family == AF_INET)
    3146                 :            :                 {
    3147                 :            :                   // IPv4 Address
    3148                 :          3 :                   struct sockaddr_in *ip = (struct sockaddr_in *)ai->ai_addr;
    3149                 :          3 :                   new_server.address.inet.family = PR_AF_INET;
    3150         [ -  + ]:          3 :                   if (ip->sin_port != 0)
    3151                 :          0 :                     new_server.address.inet.port = ip->sin_port;
    3152                 :          3 :                   new_server.address.inet.ip = ip->sin_addr.s_addr;
    3153                 :            :                 }
    3154         [ #  # ]:          0 :               else if (ai->ai_family == AF_INET6)
    3155                 :            :                 {
    3156                 :            :                   // IPv6 Address
    3157                 :          0 :                   struct sockaddr_in6 *ip = (struct sockaddr_in6 *)ai->ai_addr;
    3158                 :          0 :                   new_server.address.ipv6.family = PR_AF_INET6;
    3159         [ #  # ]:          0 :                   if (ip->sin6_port != 0)
    3160                 :          0 :                     new_server.address.ipv6.port = ip->sin6_port;
    3161                 :          0 :                   new_server.address.ipv6.scope_id = ip->sin6_scope_id;
    3162                 :          0 :                   copyAddress (new_server.address.ipv6.ip, ip->sin6_addr);
    3163                 :            :                 }
    3164                 :            :               else
    3165                 :          0 :                 continue;
    3166                 :            : 
    3167                 :            :               // Try to obtain a host name. Otherwise, leave it empty.
    3168                 :            :               char hbuf[NI_MAXHOST];
    3169                 :            :               int status = getnameinfo (ai->ai_addr, ai->ai_addrlen, hbuf, sizeof (hbuf), NULL, 0,
    3170         [ +  - ]:          3 :                                         NI_NAMEREQD | NI_IDN);
    3171         [ -  + ]:          3 :               if (status == 0)
    3172         [ #  # ]:          0 :                 new_server.host_name = hbuf;
    3173                 :            : 
    3174                 :            :               // Add the new resolved server to the list.
    3175         [ +  - ]:          3 :               add_server_info (new_server, cached_servers);
    3176 [ +  - ][ +  - ]:          3 :             }
    3177                 :            :         }
    3178         [ +  + ]:         50 :       if (addr_info)
    3179                 :          1 :         freeaddrinfo (addr_info); // free the linked list
    3180                 :            : 
    3181         [ -  + ]:         50 :       if (s.verbose >= 6)
    3182                 :            :         {
    3183 [ #  # ][ #  # ]:          0 :           clog << _F("%s resolves to:", lookup_name) << endl;
         [ #  # ][ #  # ]
    3184         [ #  # ]:         50 :           clog << cached_servers;
    3185                 :            :         }
    3186                 :            :     }
    3187                 :            : 
    3188                 :            :   // Add the information, but not duplicates.
    3189                 :        115 :   add_server_info (cached_servers, resolved_servers);
    3190                 :        115 : }
    3191                 :            : 
    3192                 :            : #if HAVE_AVAHI
    3193                 :            : // Avahi API Callbacks.
    3194                 :            : //-----------------------------------------------------------------------
    3195                 :            : struct browsing_context {
    3196                 :            :   AvahiSimplePoll *simple_poll;
    3197                 :            :   AvahiClient *client;
    3198                 :            :   vector<compile_server_info> *servers;
    3199                 :            : };
    3200                 :            : 
    3201                 :            : static string
    3202                 :        312 : extract_field_from_avahi_txt (const string &label, const string &txt)
    3203                 :            : {
    3204                 :            :   // Extract the requested field from the Avahi TXT.
    3205         [ +  - ]:        312 :   string prefix = "\"" + label;
    3206         [ +  - ]:        312 :   size_t ix = txt.find (prefix);
    3207         [ -  + ]:        312 :   if (ix == string::npos)
    3208                 :            :     {
    3209                 :            :       // Label not found.
    3210         [ #  # ]:          0 :       return "";
    3211                 :            :     }
    3212                 :            : 
    3213                 :            :   // This is the start of the field.
    3214 [ +  - ][ +  - ]:        312 :   string field = txt.substr (ix + prefix.size ());
    3215                 :            : 
    3216                 :            :   // Find the end of the field.
    3217         [ +  - ]:        312 :   ix = field.find('"');
    3218         [ +  - ]:        312 :   if (ix != string::npos)
    3219 [ +  - ][ +  - ]:        312 :     field = field.substr (0, ix);
                 [ +  - ]
    3220                 :            : 
    3221 [ +  - ][ +  - ]:        312 :   return field;
                 [ +  - ]
    3222                 :            : }
    3223                 :            : 
    3224                 :            : extern "C"
    3225                 :        104 : void resolve_callback(
    3226                 :            :     AvahiServiceResolver *r,
    3227                 :            :     AvahiIfIndex interface,
    3228                 :            :     AvahiProtocol protocol,
    3229                 :            :     AvahiResolverEvent event,
    3230                 :            :     const char *name,
    3231                 :            :     const char *type,
    3232                 :            :     const char *domain,
    3233                 :            :     const char *host_name,
    3234                 :            :     const AvahiAddress *address,
    3235                 :            :     uint16_t port,
    3236                 :            :     AvahiStringList *txt,
    3237                 :            :     AvahiLookupResultFlags /*flags*/,
    3238                 :            :     AVAHI_GCC_UNUSED void* userdata)
    3239                 :            :  {
    3240                 :            :    PRStatus prStatus;
    3241                 :            : 
    3242         [ -  + ]:        104 :     assert(r);
    3243                 :        104 :     const browsing_context *context = (browsing_context *)userdata;
    3244                 :        104 :     vector<compile_server_info> *servers = context->servers;
    3245                 :            : 
    3246                 :            :     // Called whenever a service has been resolved successfully or timed out.
    3247                 :            : 
    3248      [ -  +  - ]:        104 :     switch (event) {
    3249                 :            :         case AVAHI_RESOLVER_FAILURE:
    3250         [ #  # ]:          0 :          clog << _F("Failed to resolve service '%s' of type '%s' in domain '%s': %s",
    3251                 :            :                  name, type, domain,
    3252         [ #  # ]:          0 :                  avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r)))) << endl;
    3253                 :          0 :             break;
    3254                 :            : 
    3255                 :            :         case AVAHI_RESOLVER_FOUND: {
    3256         [ +  - ]:        104 :             compile_server_info info;
    3257                 :            : 
    3258                 :            :             // Decode the address.
    3259                 :            :             char a[AVAHI_ADDRESS_STR_MAX];
    3260         [ +  - ]:        104 :             avahi_address_snprint(a, sizeof(a), address);
    3261         [ +  - ]:        104 :             prStatus = PR_StringToNetAddr (a, & info.address);
    3262         [ -  + ]:        104 :             if (prStatus != PR_SUCCESS) {
    3263 [ #  # ][ #  # ]:          0 :               clog << _F("Invalid address '%s' from avahi", a) << endl;
         [ #  # ][ #  # ]
    3264                 :            :               break;
    3265                 :            :             }
    3266                 :            :   
    3267                 :            :             // We support both IPv4 and IPv6. Ignore other protocols.
    3268         [ -  + ]:        104 :             if (protocol == AVAHI_PROTO_INET6) {
    3269                 :          0 :               info.address.ipv6.family = PR_AF_INET6;
    3270                 :          0 :               info.address.ipv6.port = htons (port);
    3271                 :          0 :               info.address.ipv6.scope_id = interface;
    3272                 :            :             }
    3273         [ +  - ]:        104 :             else if (protocol == AVAHI_PROTO_INET) {
    3274                 :        104 :               info.address.inet.family = PR_AF_INET;
    3275                 :        104 :               info.address.inet.port = htons (port);
    3276                 :            :             }
    3277                 :            :             else
    3278                 :            :               break;
    3279                 :            : 
    3280                 :            :             // Save the host name.
    3281         [ +  - ]:        104 :             info.host_name = host_name;
    3282                 :            : 
    3283                 :            :             // Save the text tags.
    3284         [ +  - ]:        104 :             char *t = avahi_string_list_to_string(txt);
    3285 [ +  - ][ +  - ]:        104 :             info.sysinfo = extract_field_from_avahi_txt ("sysinfo=", t);
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
    3286 [ +  - ][ +  - ]:        104 :             info.certinfo = extract_field_from_avahi_txt ("certinfo=", t);
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
    3287 [ +  - ][ +  - ]:        104 :             info.version = extract_field_from_avahi_txt ("version=", t);
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
    3288 [ +  - ][ -  + ]:        104 :             if (info.version.empty ())
    3289         [ #  # ]:          0 :               info.version = "1.0"; // default version is 1.0
    3290         [ +  - ]:        104 :             avahi_free(t);
    3291                 :            : 
    3292                 :            :             // Add this server to the list of discovered servers.
    3293 [ +  - ][ +  - ]:        104 :             add_server_info (info, *servers);
                 [ +  - ]
    3294                 :            :         }
    3295                 :            :     }
    3296                 :            : 
    3297                 :        104 :     avahi_service_resolver_free(r);
    3298                 :        104 : }
    3299                 :            : 
    3300                 :            : extern "C"
    3301                 :        216 : void browse_callback(
    3302                 :            :     AvahiServiceBrowser *b,
    3303                 :            :     AvahiIfIndex interface,
    3304                 :            :     AvahiProtocol protocol,
    3305                 :            :     AvahiBrowserEvent event,
    3306                 :            :     const char *name,
    3307                 :            :     const char *type,
    3308                 :            :     const char *domain,
    3309                 :            :     AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
    3310                 :            :     void* userdata) {
    3311                 :            :     
    3312                 :        216 :     browsing_context *context = (browsing_context *)userdata;
    3313                 :        216 :     AvahiClient *c = context->client;
    3314                 :        216 :     AvahiSimplePoll *simple_poll = context->simple_poll;
    3315         [ -  + ]:        216 :     assert(b);
    3316                 :            : 
    3317                 :            :     // Called whenever a new services becomes available on the LAN or is removed from the LAN.
    3318                 :            : 
    3319   [ -  +  +  - ]:        216 :     switch (event) {
    3320                 :            :         case AVAHI_BROWSER_FAILURE:
    3321         [ #  # ]:          0 :             clog << _F("Avahi browse failed: %s",
    3322                 :            :                   avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b))))
    3323         [ #  # ]:          0 :                  << endl;
    3324                 :          0 :             avahi_simple_poll_quit(simple_poll);
    3325                 :          0 :             break;
    3326                 :            : 
    3327                 :            :         case AVAHI_BROWSER_NEW:
    3328                 :            :             // We ignore the returned resolver object. In the callback
    3329                 :            :             // function we free it. If the server is terminated before
    3330                 :            :             // the callback function is called the server will free
    3331                 :            :             // the resolver for us.
    3332         [ -  + ]:        104 :             if (!(avahi_service_resolver_new(c, interface, protocol, name, type, domain,
    3333                 :        104 :                                              AVAHI_PROTO_UNSPEC, (AvahiLookupFlags)0, resolve_callback, context))) {
    3334         [ #  # ]:          0 :              clog << _F("Failed to resolve service '%s': %s",
    3335         [ #  # ]:          0 :                      name, avahi_strerror(avahi_client_errno(c))) << endl;
    3336                 :            :             }
    3337                 :        104 :             break;
    3338                 :            : 
    3339                 :            :         case AVAHI_BROWSER_REMOVE:
    3340                 :            :         case AVAHI_BROWSER_ALL_FOR_NOW:
    3341                 :            :         case AVAHI_BROWSER_CACHE_EXHAUSTED:
    3342                 :        112 :             break;
    3343                 :            :     }
    3344                 :        216 : }
    3345                 :            : 
    3346                 :            : extern "C"
    3347                 :         53 : void client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata) {
    3348         [ -  + ]:         53 :     assert(c);
    3349                 :         53 :     browsing_context *context = (browsing_context *)userdata;
    3350                 :         53 :     AvahiSimplePoll *simple_poll = context->simple_poll;
    3351                 :            : 
    3352                 :            :     // Called whenever the client or server state changes.
    3353                 :            : 
    3354         [ -  + ]:         53 :     if (state == AVAHI_CLIENT_FAILURE) {
    3355 [ #  # ][ #  # ]:          0 :         clog << _F("Avahi Server connection failure: %s", avahi_strerror(avahi_client_errno(c))) << endl;
    3356                 :          0 :         avahi_simple_poll_quit(simple_poll);
    3357                 :            :     }
    3358                 :         53 : }
    3359                 :            : 
    3360                 :            : extern "C"
    3361                 :         53 : void timeout_callback(AVAHI_GCC_UNUSED AvahiTimeout *e, AVAHI_GCC_UNUSED void *userdata) {
    3362                 :         53 :   browsing_context *context = (browsing_context *)userdata;
    3363                 :         53 :   AvahiSimplePoll *simple_poll = context->simple_poll;
    3364                 :         53 :   avahi_simple_poll_quit(simple_poll);
    3365                 :         53 : }
    3366                 :            : #endif // HAVE_AVAHI
    3367                 :            : 
    3368                 :            : static void
    3369                 :        142 : get_or_keep_online_server_info (
    3370                 :            :   systemtap_session &s,
    3371                 :            :   vector<compile_server_info> &servers,
    3372                 :            :   bool keep
    3373                 :            : )
    3374                 :            : {
    3375                 :            :   // If we're filtering the list and it's already empty, then
    3376                 :            :   // there's nothing to do.
    3377 [ -  + ][ #  # ]:        142 :   if (keep && servers.empty ())
                 [ -  + ]
    3378                 :        142 :     return;
    3379                 :            : 
    3380                 :            :   // We only need to obtain this once per session. This is a good thing(tm)
    3381                 :            :   // since obtaining this information is expensive.
    3382                 :        142 :   vector<compile_server_info>& online_servers = cscache(s)->online_servers;
    3383         [ +  + ]:        142 :   if (online_servers.empty ())
    3384                 :            :     {
    3385                 :            :       // Maintain an empty entry to indicate that this search has been
    3386                 :            :       // performed, in case the search comes up empty.
    3387 [ +  - ][ +  - ]:         53 :       online_servers.push_back (compile_server_info ());
                 [ +  - ]
    3388                 :            : #if HAVE_AVAHI
    3389                 :            :       // Must predeclare these due to jumping on error to fail:
    3390                 :            :       unsigned limit;
    3391         [ +  - ]:         53 :       vector<compile_server_info> avahi_servers;
    3392                 :            : 
    3393                 :            :       // Initialize.
    3394                 :         53 :       AvahiClient *client = NULL;
    3395                 :         53 :       AvahiServiceBrowser *sb = NULL;
    3396                 :            :  
    3397                 :            :       // Allocate main loop object.
    3398                 :            :       AvahiSimplePoll *simple_poll;
    3399 [ +  - ][ -  + ]:         53 :       if (!(simple_poll = avahi_simple_poll_new()))
    3400                 :            :         {
    3401 [ #  # ][ #  # ]:          0 :           clog << _("Failed to create Avahi simple poll object") << endl;
    3402                 :          0 :           goto fail;
    3403                 :            :         }
    3404                 :            :       browsing_context context;
    3405                 :         53 :       context.simple_poll = simple_poll;
    3406                 :         53 :       context.servers = & avahi_servers;
    3407                 :            : 
    3408                 :            :       // Allocate a new Avahi client
    3409                 :            :       int error;
    3410                 :            :       client = avahi_client_new (avahi_simple_poll_get (simple_poll),
    3411                 :            :                                  (AvahiClientFlags)0,
    3412 [ +  - ][ +  - ]:         53 :                                  client_callback, & context, & error);
    3413                 :            : 
    3414                 :            :       // Check whether creating the client object succeeded.
    3415         [ -  + ]:         53 :       if (! client)
    3416                 :            :         {
    3417 [ #  # ][ #  # ]:          0 :          clog << _F("Failed to create Avahi client: %s",
         [ #  # ][ #  # ]
    3418         [ #  # ]:          0 :                     avahi_strerror(error)) << endl;
    3419                 :          0 :           goto fail;
    3420                 :            :         }
    3421                 :         53 :       context.client = client;
    3422                 :            :     
    3423                 :            :       // Create the service browser.
    3424 [ +  - ][ -  + ]:         53 :       if (!(sb = avahi_service_browser_new (client, AVAHI_IF_UNSPEC,
    3425                 :            :                                             AVAHI_PROTO_UNSPEC, "_stap._tcp",
    3426                 :            :                                             NULL, (AvahiLookupFlags)0,
    3427                 :            :                                             browse_callback, & context)))
    3428                 :            :         {
    3429 [ #  # ][ #  # ]:          0 :          clog << _F("Failed to create Avahi service browser: %s",
         [ #  # ][ #  # ]
                 [ #  # ]
    3430         [ #  # ]:          0 :                      avahi_strerror(avahi_client_errno(client))) << endl;
    3431                 :          0 :           goto fail;
    3432                 :            :         }
    3433                 :            : 
    3434                 :            :       // Timeout after 2 seconds.
    3435                 :            :       struct timeval tv;
    3436         [ +  - ]:         53 :       avahi_simple_poll_get(simple_poll)->timeout_new(
    3437                 :            :         avahi_simple_poll_get(simple_poll),
    3438         [ +  - ]:         53 :         avahi_elapse_time(&tv, 1000*2, 0),
    3439                 :            :         timeout_callback,
    3440 [ +  - ][ +  - ]:        106 :         & context);
    3441                 :            : 
    3442                 :            :       // Run the main loop.
    3443         [ +  - ]:         53 :       avahi_simple_poll_loop(simple_poll);
    3444                 :            : 
    3445         [ -  + ]:         53 :       if (s.verbose >= 6)
    3446                 :            :         {
    3447 [ #  # ][ #  # ]:          0 :           clog << _("Avahi reports the following servers online:") << endl;
    3448         [ #  # ]:          0 :           clog << avahi_servers;
    3449                 :            :         }
    3450                 :            : 
    3451                 :            :       // Resolve each server discovered, in case there are alternate ways to reach them
    3452                 :            :       // (e.g. localhost).
    3453                 :         53 :       limit = avahi_servers.size ();
    3454         [ +  + ]:        157 :       for (unsigned i = 0; i < limit; ++i)
    3455                 :            :         {
    3456                 :        104 :           compile_server_info &avahi_server = avahi_servers[i];
    3457                 :            : 
    3458                 :            :           // Delete the domain, if it is '.local'
    3459                 :        104 :           string &host_name = avahi_server.host_name;
    3460         [ +  - ]:        104 :           string::size_type dot_index = host_name.find ('.');
    3461         [ -  + ]:        104 :           assert (dot_index != 0);
    3462         [ +  - ]:        104 :           string domain = host_name.substr (dot_index + 1);
    3463 [ +  - ][ +  - ]:        104 :           if (domain == "local")
    3464 [ +  - ][ +  - ]:        104 :             host_name = host_name.substr (0, dot_index);
                 [ +  - ]
    3465                 :            : 
    3466                 :            :           // Add it to the list of servers, unless it is duplicate.
    3467         [ +  - ]:        104 :           resolve_host (s, avahi_server, online_servers);
    3468         [ +  - ]:        104 :         }
    3469                 :            : 
    3470                 :            :       // Merge with the list of servers, as obtained by avahi.
    3471         [ +  - ]:         53 :       add_server_info (avahi_servers, online_servers);
    3472                 :            : 
    3473                 :            :     fail:
    3474                 :            :       // Cleanup.
    3475         [ +  - ]:         53 :       if (sb)
    3476         [ +  - ]:         53 :         avahi_service_browser_free(sb);
    3477                 :            :     
    3478         [ +  - ]:         53 :       if (client)
    3479         [ +  - ]:         53 :         avahi_client_free(client);
    3480                 :            : 
    3481         [ +  - ]:         53 :       if (simple_poll)
    3482         [ +  - ]:         53 :         avahi_simple_poll_free(simple_poll);
    3483                 :            : #else // ! HAVE_AVAHI
    3484                 :            :       // Without Avahi, we can't detect online servers. Issue a warning.
    3485                 :            :       if (s.verbose >= 2)
    3486                 :            :         clog << _("Unable to detect online servers without avahi") << endl;
    3487                 :            : #endif // ! HAVE_AVAHI
    3488                 :            : 
    3489         [ -  + ]:         53 :       if (s.verbose >= 5)
    3490                 :            :         {
    3491 [ #  # ][ #  # ]:          0 :           clog << _("All online servers:") << endl;
    3492         [ #  # ]:          0 :           clog << online_servers;
    3493         [ +  - ]:         53 :         }
    3494                 :            :     } // Server information is not cached.
    3495                 :            : 
    3496         [ -  + ]:        142 :   if (keep)
    3497                 :            :     {
    3498                 :            :       // Filter the existing vector by keeping the information in common with
    3499                 :            :       // the online_server vector.
    3500                 :          0 :       keep_common_server_info (online_servers, servers);
    3501                 :            :     }
    3502                 :            :   else
    3503                 :            :     {
    3504                 :            :       // Add the information, but not duplicates.
    3505                 :        142 :       add_server_info (online_servers, servers);
    3506                 :            :     }
    3507                 :            : }
    3508                 :            : 
    3509                 :            : // Add server info to a list, avoiding duplicates. Merge information from
    3510                 :            : // two duplicate items.
    3511                 :            : static void
    3512                 :       1356 : add_server_info (
    3513                 :            :   const compile_server_info &info, vector<compile_server_info>& target
    3514                 :            : )
    3515                 :            : {
    3516         [ +  + ]:       1356 :   if (info.empty ())
    3517                 :       1356 :     return;
    3518                 :            : 
    3519                 :       1116 :   bool found = false;
    3520 [ +  - ][ +  - ]:       4640 :   for (vector<compile_server_info>::iterator i = target.begin ();
                 [ +  + ]
    3521         [ +  - ]:       2320 :        i != target.end ();
    3522                 :            :        ++i)
    3523                 :            :     {
    3524 [ +  - ][ +  + ]:       1204 :       if (info == *i)
    3525                 :            :         {
    3526                 :            :           // Duplicate. Merge the two items.
    3527         [ +  - ]:        212 :           merge_server_info (info, *i);
    3528                 :        212 :           found = true;
    3529                 :            :         }
    3530                 :            :     }
    3531         [ +  + ]:       1116 :   if (! found)
    3532                 :        904 :     target.push_back (info);
    3533                 :            : }
    3534                 :            : 
    3535                 :            : // Add server info from one vector to another.
    3536                 :            : static void
    3537                 :        531 : add_server_info (
    3538                 :            :   const vector<compile_server_info> &source,
    3539                 :            :   vector<compile_server_info> &target
    3540                 :            : )
    3541                 :            : {
    3542 [ +  - ][ +  - ]:       3246 :   for (vector<compile_server_info>::const_iterator i = source.begin ();
                 [ +  + ]
    3543         [ +  - ]:       1623 :        i != source.end ();
    3544                 :            :        ++i)
    3545                 :            :     {
    3546         [ +  - ]:       1092 :       add_server_info (*i, target);
    3547                 :            :     }
    3548                 :        531 : }
    3549                 :            : 
    3550                 :            : // Filter the vector by keeping information in common with the item.
    3551                 :            : static void
    3552                 :          0 : keep_common_server_info (
    3553                 :            :   const compile_server_info &info_to_keep,
    3554                 :            :   vector<compile_server_info> &filtered_info
    3555                 :            : )
    3556                 :            : {
    3557         [ #  # ]:          0 :   assert (! info_to_keep.empty ());
    3558                 :            : 
    3559                 :            :   // The vector may change size as we go. Be careful!!
    3560         [ #  # ]:          0 :   for (unsigned i = 0; i < filtered_info.size (); /**/)
    3561                 :            :     {
    3562                 :            :       // Retain empty entries.
    3563         [ #  # ]:          0 :       if (filtered_info[i].empty ())
    3564                 :            :         {
    3565                 :          0 :           ++i;
    3566                 :          0 :           continue;
    3567                 :            :         }
    3568         [ #  # ]:          0 :       if (info_to_keep == filtered_info[i])
    3569                 :            :         {
    3570                 :          0 :           merge_server_info (info_to_keep, filtered_info[i]);
    3571                 :          0 :           ++i;
    3572                 :          0 :           continue;
    3573                 :            :         }
    3574                 :            :       // The item does not match. Delete it.
    3575 [ #  # ][ #  # ]:          0 :       filtered_info.erase (filtered_info.begin () + i);
    3576                 :          0 :       continue;
    3577                 :            :     }
    3578                 :          0 : }
    3579                 :            : 
    3580                 :            : // Filter the second vector by keeping information in common with the first
    3581                 :            : // vector.
    3582                 :            : static void
    3583                 :         92 : keep_common_server_info (
    3584                 :            :   const vector<compile_server_info> &info_to_keep,
    3585                 :            :   vector<compile_server_info> &filtered_info
    3586                 :            : )
    3587                 :            : {
    3588                 :            :   // The vector may change size as we go. Be careful!!
    3589         [ +  + ]:        275 :   for (unsigned i = 0; i < filtered_info.size (); /**/)
    3590                 :            :     {
    3591                 :            :       // Retain empty entries.
    3592         [ -  + ]:        183 :       if (filtered_info[i].empty ())
    3593                 :            :         {
    3594                 :          0 :           ++i;
    3595                 :          0 :           continue;
    3596                 :            :         }
    3597                 :        183 :       bool found = false;
    3598         [ +  + ]:        675 :       for (unsigned j = 0; j < info_to_keep.size (); ++j)
    3599                 :            :         {
    3600         [ +  + ]:        492 :           if (filtered_info[i] == info_to_keep[j])
    3601                 :            :             {
    3602                 :        173 :               merge_server_info (info_to_keep[j], filtered_info[i]);
    3603                 :        173 :               found = true;
    3604                 :            :             }
    3605                 :            :         }
    3606                 :            : 
    3607                 :            :       // If the item was not found. Delete it. Otherwise, advance to the next
    3608                 :            :       // item.
    3609         [ +  + ]:        183 :       if (found)
    3610                 :        173 :         ++i;
    3611                 :            :       else
    3612 [ +  - ][ +  - ]:         10 :         filtered_info.erase (filtered_info.begin () + i);
    3613                 :            :     }
    3614                 :         92 : }
    3615                 :            : 
    3616                 :            : // Merge two compile server info items.
    3617                 :            : static void
    3618                 :        385 : merge_server_info (
    3619                 :            :   const compile_server_info &source,
    3620                 :            :   compile_server_info &target
    3621                 :            : )
    3622                 :            : {
    3623         [ -  + ]:        385 :   if (target.host_name.empty ())
    3624                 :          0 :     target.host_name = source.host_name;
    3625                 :            :   // Copy the address unconditionally, if the source has an address, even if they are already
    3626                 :            :   // equal. The source address may be an IPv6 address with a scope_id that the target is missing.
    3627 [ +  + ][ +  - ]:        385 :   assert (! target.hasAddress () || ! source.hasAddress () || source.address == target.address);
                 [ -  + ]
    3628         [ +  - ]:        385 :   if (source.hasAddress ())
    3629                 :        385 :     copyNetAddr (target.address, source.address);
    3630         [ +  + ]:        385 :   if (target.port() == 0)
    3631                 :          2 :     target.setPort (source.port());
    3632         [ +  + ]:        385 :   if (target.sysinfo.empty ())
    3633                 :         51 :     target.sysinfo = source.sysinfo;
    3634         [ +  + ]:        385 :   if (target.version.empty ())
    3635                 :         51 :     target.version = source.version;
    3636         [ +  + ]:        385 :   if (target.certinfo.empty ())
    3637                 :          4 :     target.certinfo = source.certinfo;
    3638 [ +  - ][ +  - ]:       7627 : }
    3639                 :            : 
    3640                 :            : #if 0 // not used right now
    3641                 :            : // Merge compile server info from one item into a vector.
    3642                 :            : static void
    3643                 :            : merge_server_info (
    3644                 :            :   const compile_server_info &source,
    3645                 :            :   vector<compile_server_info> &target
    3646                 :            : )
    3647                 :            : {
    3648                 :            :   for (vector<compile_server_info>::iterator i = target.begin ();
    3649                 :            :       i != target.end ();
    3650                 :            :       ++i)
    3651                 :            :     {
    3652                 :            :       if (source == *i)
    3653                 :            :         merge_server_info (source, *i);
    3654                 :            :     }
    3655                 :            : }
    3656                 :            : 
    3657                 :            : // Merge compile server from one vector into another.
    3658                 :            : static void
    3659                 :            : merge_server_info (
    3660                 :            :   const vector<compile_server_info> &source,
    3661                 :            :   vector <compile_server_info> &target
    3662                 :            : )
    3663                 :            : {
    3664                 :            :   for (vector<compile_server_info>::const_iterator i = source.begin ();
    3665                 :            :       i != source.end ();
    3666                 :            :       ++i)
    3667                 :            :     merge_server_info (*i, target);
    3668                 :            : }
    3669                 :            : #endif
    3670                 :            : #endif // HAVE_NSS
    3671                 :            : 
    3672                 :            : /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */

Generated by: LCOV version 1.9