2 Compile server client functions
3 Copyright (C) 2010-2012 Red Hat Inc.
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
11 // Completely disable the client if NSS is not available.
18 #include "stap-probe.h"
20 #include <sys/times.h>
31 #include <linux/limits.h>
35 #include <sys/socket.h>
39 #include <arpa/inet.h>
45 #include <avahi-client/client.h>
46 #include <avahi-client/lookup.h>
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>
66 #include "nsscommon.h"
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")
76 static PRIPv6Addr
©Address (PRIPv6Addr
&PRin6
, const in6_addr
&in6
);
77 bool operator!= (const PRNetAddr
&x
, const PRNetAddr
&y
);
81 nsscommon_error (const char *msg
, int logit
__attribute ((unused
)))
83 clog
<< msg
<< endl
<< flush
;
86 // Information about compile servers.
87 struct compile_server_info
89 compile_server_info ()
91 memset (& address
, 0, sizeof (address
));
102 return this->host_name
.empty () && ! this->hasAddress ();
104 bool hasAddress () const
106 return this->address
.raw
.family
!= 0;
108 unsigned short port () const
110 if (this->address
.raw
.family
== PR_AF_INET
)
111 return ntohs (this->address
.inet
.port
);
112 if (this->address
.raw
.family
== PR_AF_INET6
)
113 return ntohs (this->address
.ipv6
.port
);
116 unsigned short setPort (unsigned short port
)
118 if (this->address
.raw
.family
== PR_AF_INET
)
119 return this->address
.inet
.port
= htons (port
);
120 if (this->address
.raw
.family
== PR_AF_INET6
)
121 return this->address
.ipv6
.port
= htons (port
);
125 bool operator== (const compile_server_info
&that
) const
127 // If both ip addressed are not set, then the host names must match, otherwise
128 // the addresses must match.
129 if (! this->hasAddress() || ! that
.hasAddress())
131 if (this->host_name
!= that
.host_name
)
134 else if (this->address
!= that
.address
)
137 // Compare the other fields only if they have both been set.
138 if (this->port() != 0 && that
.port() != 0 &&
139 this->port() != that
.port())
141 if (! this->version
.empty () && ! that
.version
.empty () &&
142 this->version
!= that
.version
)
144 if (! this->sysinfo
.empty () && ! that
.sysinfo
.empty () &&
145 this->sysinfo
!= that
.sysinfo
)
147 if (! this->certinfo
.empty () && ! that
.certinfo
.empty () &&
148 this->certinfo
!= that
.certinfo
)
151 return true; // They are equal
154 // Used to sort servers by preference for order of contact. The preferred server is
155 // "less" than the other one.
156 bool operator< (const compile_server_info
&that
) const
158 // Prefer servers with a later (higher) version number.
159 cs_protocol_version
this_version (this->version
.c_str ());
160 cs_protocol_version
that_version (that
.version
.c_str ());
161 return that_version
< this_version
;
165 ostream
&operator<< (ostream
&s
, const compile_server_info
&i
);
166 ostream
&operator<< (ostream
&s
, const vector
<compile_server_info
> &v
);
169 preferred_order (vector
<compile_server_info
> &servers
)
171 // Sort the given list of servers into the preferred order for contacting.
172 // Don't bother if there are less than 2 servers in the list.
173 if (servers
.size () < 2)
176 // Sort the list using compile_server_info::operator<
177 sort (servers
.begin (), servers
.end ());
180 struct compile_server_cache
182 vector
<compile_server_info
> default_servers
;
183 vector
<compile_server_info
> specified_servers
;
184 vector
<compile_server_info
> trusted_servers
;
185 vector
<compile_server_info
> signing_servers
;
186 vector
<compile_server_info
> online_servers
;
189 // For filtering queries.
190 enum compile_server_properties
{
191 compile_server_all
= 0x1,
192 compile_server_trusted
= 0x2,
193 compile_server_online
= 0x4,
194 compile_server_compatible
= 0x8,
195 compile_server_signer
= 0x10,
196 compile_server_specified
= 0x20
200 static compile_server_cache
* cscache(systemtap_session
& s
);
201 static void query_server_status (systemtap_session
&s
, const string
&status_string
);
203 static void get_server_info (systemtap_session
&s
, int pmask
, vector
<compile_server_info
> &servers
);
204 static void get_all_server_info (systemtap_session
&s
, vector
<compile_server_info
> &servers
);
205 static void get_default_server_info (systemtap_session
&s
, vector
<compile_server_info
> &servers
);
206 static void get_specified_server_info (systemtap_session
&s
, vector
<compile_server_info
> &servers
, bool no_default
= false);
207 static void get_or_keep_online_server_info (systemtap_session
&s
, vector
<compile_server_info
> &servers
, bool keep
);
208 static void get_or_keep_trusted_server_info (systemtap_session
&s
, vector
<compile_server_info
> &servers
, bool keep
);
209 static void get_or_keep_signing_server_info (systemtap_session
&s
, vector
<compile_server_info
> &servers
, bool keep
);
210 static void get_or_keep_compatible_server_info (systemtap_session
&s
, vector
<compile_server_info
> &servers
, bool keep
);
211 static void keep_common_server_info (const compile_server_info
&info_to_keep
, vector
<compile_server_info
> &filtered_info
);
212 static void keep_common_server_info (const vector
<compile_server_info
> &info_to_keep
, vector
<compile_server_info
> &filtered_info
);
213 static void keep_server_info_with_cert_and_port (systemtap_session
&s
, const compile_server_info
&server
, vector
<compile_server_info
> &servers
);
215 static void add_server_info (const compile_server_info
&info
, vector
<compile_server_info
>& list
);
216 static void add_server_info (const vector
<compile_server_info
> &source
, vector
<compile_server_info
> &target
);
217 static void merge_server_info (const compile_server_info
&source
, compile_server_info
&target
);
218 #if 0 // not used right now
219 static void merge_server_info (const compile_server_info
&source
, vector
<compile_server_info
> &target
);
220 static void merge_server_info (const vector
<compile_server_info
> &source
, vector
<compile_server_info
> &target
);
222 static void resolve_host (systemtap_session
& s
, compile_server_info
&server
, vector
<compile_server_info
> &servers
);
224 /* Exit error codes */
226 #define GENERAL_ERROR 1
227 #define CA_CERT_INVALID_ERROR 2
228 #define SERVER_CERT_EXPIRED_ERROR 3
230 // -----------------------------------------------------
231 // NSS related code used by the compile server client
232 // -----------------------------------------------------
233 static void add_server_trust (systemtap_session
&s
, const string
&cert_db_path
, const vector
<compile_server_info
> &server_list
);
234 static void revoke_server_trust (systemtap_session
&s
, const string
&cert_db_path
, const vector
<compile_server_info
> &server_list
);
235 static void get_server_info_from_db (systemtap_session
&s
, vector
<compile_server_info
> &servers
, const string
&cert_db_path
);
237 static string
global_client_cert_db_path () {
238 return SYSCONFDIR
"/systemtap/ssl/client";
242 private_ssl_cert_db_path ()
244 return local_client_cert_db_path ();
248 global_ssl_cert_db_path ()
250 return global_client_cert_db_path ();
254 signing_cert_db_path ()
256 return SYSCONFDIR
"/systemtap/staprun";
259 /* Connection state. */
260 typedef struct connectionState_t
262 const char *hostName
;
264 const char *infileName
;
265 const char *outfileName
;
266 const char *trustNewServerMode
;
269 #if 0 /* No client authorization */
271 myPasswd(PK11SlotInfo
*info
, PRBool retry
, void *arg
)
273 char * passwd
= NULL
;
275 if ( (!retry
) && arg
)
276 passwd
= PORT_Strdup((char *)arg
);
282 /* Add the server's certificate to our database of trusted servers. */
284 trustNewServer (CERTCertificate
*serverCert
)
287 CERTCertTrust
*trust
= NULL
;
288 PK11SlotInfo
*slot
= NULL
;
290 /* Import the certificate. */
291 slot
= PK11_GetInternalKeySlot();
292 const char *nickname
= server_cert_nickname ();
293 secStatus
= PK11_ImportCert(slot
, serverCert
, CK_INVALID_HANDLE
, nickname
, PR_FALSE
);
294 if (secStatus
!= SECSuccess
)
297 /* Make it a trusted peer. */
298 trust
= (CERTCertTrust
*)PORT_ZAlloc(sizeof(CERTCertTrust
));
301 secStatus
= SECFailure
;
305 secStatus
= CERT_DecodeTrustString(trust
, "P,P,P");
306 if (secStatus
!= SECSuccess
)
309 secStatus
= CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), serverCert
, trust
);
313 PK11_FreeSlot (slot
);
319 /* Called when the server certificate verification fails. This gives us
320 the chance to trust the server anyway and add the certificate to the
323 badCertHandler(void *arg
, PRFileDesc
*sslSocket
)
326 PRErrorCode errorNumber
;
327 CERTCertificate
*serverCert
= NULL
;
329 PRArenaPool
*tmpArena
= NULL
;
330 CERTGeneralName
*nameList
, *current
;
331 char *expected
= NULL
;
332 const connectionState_t
*connectionState
= (connectionState_t
*)arg
;
334 errorNumber
= PR_GetError ();
337 case SSL_ERROR_BAD_CERT_DOMAIN
:
338 /* Since we administer our own client-side databases of trustworthy
339 certificates, we don't need the domain name(s) on the certificate to
340 match. If the cert is in our database, then we can trust it.
341 Issue a warning and accept the certificate. */
342 expected
= SSL_RevealURL (sslSocket
);
343 fprintf (stderr
, STAP_CSC_01
, expected
);
345 /* List the DNS names from the server cert as part of the warning.
346 First, find the alt-name extension on the certificate. */
347 subAltName
.data
= NULL
;
348 serverCert
= SSL_PeerCertificate (sslSocket
);
349 secStatus
= CERT_FindCertExtension (serverCert
,
350 SEC_OID_X509_SUBJECT_ALT_NAME
,
352 if (secStatus
!= SECSuccess
|| ! subAltName
.data
)
354 fprintf (stderr
, _("Unable to find alt name extension on the server certificate\n"));
355 secStatus
= SECSuccess
; /* Not a fatal error */
359 // Now, decode the extension.
360 tmpArena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
363 fprintf (stderr
, _("Out of memory\n"));
364 secStatus
= SECSuccess
; /* Not a fatal error here */
367 nameList
= CERT_DecodeAltNameExtension (tmpArena
, & subAltName
);
368 SECITEM_FreeItem(& subAltName
, PR_FALSE
);
371 fprintf (stderr
, _("Unable to decode alt name extension on server certificate\n"));
372 secStatus
= SECSuccess
; /* Not a fatal error */
376 /* List the DNS names from the server cert as part of the warning.
377 The names are in a circular list. */
381 /* Make sure this is a DNS name. */
382 if (current
->type
== certDNSName
)
384 fprintf (stderr
, " %.*s\n",
385 (int)current
->name
.other
.len
, current
->name
.other
.data
);
387 current
= CERT_GetNextGeneralName (current
);
389 while (current
!= nameList
);
391 /* Accept the certificate */
392 secStatus
= SECSuccess
;
395 case SEC_ERROR_CA_CERT_INVALID
:
396 /* The server's certificate is not trusted. Should we trust it? */
397 secStatus
= SECFailure
; /* Do not trust by default. */
398 if (! connectionState
->trustNewServerMode
)
401 /* Trust it for this session only? */
402 if (strcmp (connectionState
->trustNewServerMode
, "session") == 0)
404 secStatus
= SECSuccess
;
408 /* Trust it permanently? */
409 if (strcmp (connectionState
->trustNewServerMode
, "permanent") == 0)
411 /* The user wants to trust this server. Get the server's certificate so
412 and add it to our database. */
413 serverCert
= SSL_PeerCertificate (sslSocket
);
414 if (serverCert
!= NULL
)
416 secStatus
= trustNewServer (serverCert
);
421 secStatus
= SECFailure
; /* Do not trust this server */
426 PORT_Free (expected
);
428 PORT_FreeArena (tmpArena
, PR_FALSE
);
430 if (serverCert
!= NULL
)
432 CERT_DestroyCertificate (serverCert
);
439 setupSSLSocket (connectionState_t
*connectionState
)
441 PRFileDesc
*tcpSocket
;
442 PRFileDesc
*sslSocket
;
443 PRSocketOptionData socketOption
;
447 tcpSocket
= PR_OpenTCPSocket(connectionState
->addr
.raw
.family
);
448 if (tcpSocket
== NULL
)
451 /* Make the socket blocking. */
452 socketOption
.option
= PR_SockOpt_Nonblocking
;
453 socketOption
.value
.non_blocking
= PR_FALSE
;
455 prStatus
= PR_SetSocketOption(tcpSocket
, &socketOption
);
456 if (prStatus
!= PR_SUCCESS
)
459 /* Import the socket into the SSL layer. */
460 sslSocket
= SSL_ImportFD(NULL
, tcpSocket
);
464 /* Set configuration options. */
465 secStatus
= SSL_OptionSet(sslSocket
, SSL_SECURITY
, PR_TRUE
);
466 if (secStatus
!= SECSuccess
)
469 secStatus
= SSL_OptionSet(sslSocket
, SSL_HANDSHAKE_AS_CLIENT
, PR_TRUE
);
470 if (secStatus
!= SECSuccess
)
473 /* Set SSL callback routines. */
474 #if 0 /* no client authentication */
475 secStatus
= SSL_GetClientAuthDataHook(sslSocket
,
476 (SSLGetClientAuthData
)myGetClientAuthData
,
477 (void *)certNickname
);
478 if (secStatus
!= SECSuccess
)
481 #if 0 /* Use the default */
482 secStatus
= SSL_AuthCertificateHook(sslSocket
,
483 (SSLAuthCertificate
)myAuthCertificate
,
484 (void *)CERT_GetDefaultCertDB());
485 if (secStatus
!= SECSuccess
)
489 secStatus
= SSL_BadCertHook(sslSocket
, (SSLBadCertHandler
)badCertHandler
,
491 if (secStatus
!= SECSuccess
)
494 #if 0 /* No handshake callback */
495 secStatus
= SSL_HandshakeCallback(sslSocket
, myHandshakeCallback
, NULL
);
496 if (secStatus
!= SECSuccess
)
510 handle_connection (PRFileDesc
*sslSocket
, connectionState_t
*connectionState
)
515 PRFileDesc
*local_file_fd
;
517 SECStatus secStatus
= SECSuccess
;
519 #define READ_BUFFER_SIZE (60 * 1024)
521 /* If we don't have both the input and output file names, then we're
522 contacting this server only in order to establish trust. In this case send
523 0 as the file size and exit. */
524 if (! connectionState
->infileName
|| ! connectionState
->outfileName
)
526 numBytes
= htonl ((PRInt32
)0);
527 numBytes
= PR_Write (sslSocket
, & numBytes
, sizeof (numBytes
));
533 /* read and send the data. */
534 /* Try to open the local file named.
535 * If successful, then write it to the server
537 prStatus
= PR_GetFileInfo(connectionState
->infileName
, &info
);
538 if (prStatus
!= PR_SUCCESS
||
539 info
.type
!= PR_FILE_FILE
||
542 fprintf (stderr
, STAP_CSC_02
,
543 connectionState
->infileName
);
547 local_file_fd
= PR_Open(connectionState
->infileName
, PR_RDONLY
, 0);
548 if (local_file_fd
== NULL
)
550 fprintf (stderr
, STAP_CSC_03
, connectionState
->infileName
);
554 /* Send the file size first, so the server knows when it has the entire file. */
555 numBytes
= htonl ((PRInt32
)info
.size
);
556 numBytes
= PR_Write(sslSocket
, & numBytes
, sizeof (numBytes
));
559 PR_Close(local_file_fd
);
563 /* Transmit the local file across the socket. */
564 numBytes
= PR_TransmitFile(sslSocket
, local_file_fd
,
566 PR_TRANSMITFILE_KEEP_OPEN
,
567 PR_INTERVAL_NO_TIMEOUT
);
570 PR_Close(local_file_fd
);
574 PR_Close(local_file_fd
);
577 readBuffer
= (char *)PORT_Alloc(READ_BUFFER_SIZE
);
579 fprintf (stderr
, _("Out of memory\n"));
583 local_file_fd
= PR_Open(connectionState
->outfileName
, PR_WRONLY
| PR_CREATE_FILE
| PR_TRUNCATE
,
584 PR_IRUSR
| PR_IWUSR
| PR_IRGRP
| PR_IWGRP
| PR_IROTH
);
585 if (local_file_fd
== NULL
)
587 fprintf (stderr
, STAP_CSC_04
, connectionState
->outfileName
);
592 numBytes
= PR_Read(sslSocket
, readBuffer
, READ_BUFFER_SIZE
);
598 secStatus
= SECFailure
;
602 /* Write to output file */
603 numBytes
= PR_Write(local_file_fd
, readBuffer
, numBytes
);
606 fprintf (stderr
, STAP_CSC_05
, connectionState
->outfileName
);
607 secStatus
= SECFailure
;
613 PR_Close(local_file_fd
);
615 /* Caller closes the socket. */
619 /* make the connection.
622 do_connect (connectionState_t
*connectionState
)
624 PRFileDesc
*sslSocket
;
628 secStatus
= SECSuccess
;
630 /* Set up SSL secure socket. */
631 sslSocket
= setupSSLSocket (connectionState
);
632 if (sslSocket
== NULL
)
635 #if 0 /* no client authentication */
636 secStatus
= SSL_SetPKCS11PinArg(sslSocket
, password
);
637 if (secStatus
!= SECSuccess
)
641 secStatus
= SSL_SetURL(sslSocket
, connectionState
->hostName
);
642 if (secStatus
!= SECSuccess
)
645 prStatus
= PR_Connect(sslSocket
, & connectionState
->addr
, PR_INTERVAL_NO_TIMEOUT
);
646 if (prStatus
!= PR_SUCCESS
)
648 secStatus
= SECFailure
;
652 /* Established SSL connection, ready to send data. */
653 secStatus
= SSL_ResetHandshake(sslSocket
, /* asServer */ PR_FALSE
);
654 if (secStatus
!= SECSuccess
)
657 /* This is normally done automatically on the first I/O operation,
658 but doing it here catches any authentication problems early. */
659 secStatus
= SSL_ForceHandshake(sslSocket
);
660 if (secStatus
!= SECSuccess
)
663 // Connect to the server and make the request.
664 secStatus
= handle_connection(sslSocket
, connectionState
);
667 prStatus
= PR_Close(sslSocket
);
672 client_connect (const compile_server_info
&server
,
673 const char* infileName
, const char* outfileName
,
674 const char* trustNewServer
)
677 PRErrorCode errorNumber
;
679 int errCode
= GENERAL_ERROR
;
680 struct connectionState_t connectionState
;
682 // Set up a connection state for use by NSS error callbacks.
683 memset (& connectionState
, 0, sizeof (connectionState
));
684 connectionState
.hostName
= server
.host_name
.c_str ();
685 connectionState
.addr
= server
.address
;
686 connectionState
.infileName
= infileName
;
687 connectionState
.outfileName
= outfileName
;
688 connectionState
.trustNewServerMode
= trustNewServer
;
690 /* Some errors (see below) represent a situation in which trying again
691 should succeed. However, don't try forever. */
692 for (attempt
= 0; attempt
< 5; ++attempt
)
694 secStatus
= do_connect (& connectionState
);
695 if (secStatus
== SECSuccess
)
698 errorNumber
= PR_GetError ();
701 case PR_CONNECT_RESET_ERROR
:
702 /* Server was not ready. */
704 break; /* Try again */
705 case SEC_ERROR_EXPIRED_CERTIFICATE
:
706 /* The server's certificate has expired. It should
707 generate a new certificate. Return now and we'll try again. */
708 errCode
= SERVER_CERT_EXPIRED_ERROR
;
710 case SEC_ERROR_CA_CERT_INVALID
:
711 /* The server's certificate is not trusted. The exit code must
713 errCode
= CA_CERT_INVALID_ERROR
;
716 /* This error is fatal. */
725 compile_server_client::passes_0_4 ()
727 PROBE1(stap
, client__start
, &s
);
729 // arguments parsed; get down to business
731 clog
<< _("Using a compile server.") << endl
;
733 struct tms tms_before
;
734 times (& tms_before
);
735 struct timeval tv_before
;
736 gettimeofday (&tv_before
, NULL
);
738 // Create the request package.
739 int rc
= initialize ();
740 if (rc
!= 0 || pending_interrupts
) goto done
;
741 rc
= create_request ();
742 if (rc
!= 0 || pending_interrupts
) goto done
;
743 rc
= package_request ();
744 if (rc
!= 0 || pending_interrupts
) goto done
;
746 // Submit it to the server.
747 rc
= find_and_connect_to_server ();
748 if (rc
!= 0 || pending_interrupts
) goto done
;
750 // Unpack and process the response.
751 rc
= unpack_response ();
752 if (rc
!= 0 || pending_interrupts
) goto done
;
753 rc
= process_response ();
755 if (rc
== 0 && s
.last_pass
== 4)
757 cout
<< s
.module_name
+ ".ko";
762 struct tms tms_after
;
764 unsigned _sc_clk_tck
= sysconf (_SC_CLK_TCK
);
765 struct timeval tv_after
;
766 gettimeofday (&tv_after
, NULL
);
768 #define TIMESPRINT "in " << \
769 (tms_after.tms_cutime + tms_after.tms_utime \
770 - tms_before.tms_cutime - tms_before.tms_utime) * 1000 / (_sc_clk_tck) << "usr/" \
771 << (tms_after.tms_cstime + tms_after.tms_stime \
772 - tms_before.tms_cstime - tms_before.tms_stime) * 1000 / (_sc_clk_tck) << "sys/" \
773 << ((tv_after.tv_sec - tv_before.tv_sec) * 1000 + \
774 ((long)tv_after.tv_usec - (long)tv_before.tv_usec) / 1000) << "real ms."
776 // syntax errors, if any, are already printed
779 string ws
= s
.winning_server
;
780 if (ws
== "") ws
= "?";
781 clog
<< _("Passes: via server ") << ws
<< " "
788 clog
<< _("Passes: via server failed. Try again with another '-v' option.") << endl
;
793 // Save the module, if necessary.
794 if (s
.last_pass
== 4)
795 s
.save_module
= true;
797 // Copy module to the current directory.
798 if (s
.save_module
&& ! pending_interrupts
)
800 string module_src_path
= s
.tmpdir
+ "/" + s
.module_name
+ ".ko";
801 string module_dest_path
= s
.module_name
+ ".ko";
802 copy_file (module_src_path
, module_dest_path
, s
.verbose
>= 3);
803 // Also copy the module signature, it it exists.
804 module_src_path
+= ".sgn";
805 if (file_exists (module_src_path
))
807 module_dest_path
+= ".sgn";
808 copy_file(module_src_path
, module_dest_path
, s
.verbose
>= 3);
813 PROBE1(stap
, client__end
, &s
);
818 // Initialize a client/server session.
820 compile_server_client::initialize ()
824 // Initialize session state
827 // Private location for server certificates.
828 private_ssl_dbs
.push_back (private_ssl_cert_db_path ());
830 // Additional public location.
831 public_ssl_dbs
.push_back (global_ssl_cert_db_path ());
833 // Create a temporary directory to package things in.
834 client_tmpdir
= s
.tmpdir
+ "/client";
835 rc
= create_dir (client_tmpdir
.c_str ());
838 const char* e
= strerror (errno
);
839 clog
<< _("ERROR: cannot create temporary directory (\"")
840 << client_tmpdir
<< "\"): " << e
847 // Create the request package.
849 compile_server_client::create_request ()
851 // Add the current protocol version.
852 int rc
= write_to_file (client_tmpdir
+ "/version", CURRENT_CS_PROTOCOL_VERSION
);
856 // Add the script file or script option
857 if (s
.script_file
!= "")
859 if (s
.script_file
== "-")
861 // Copy the script from stdin
862 string packaged_script_dir
= client_tmpdir
+ "/script";
863 rc
= create_dir (packaged_script_dir
.c_str ());
866 const char* e
= strerror (errno
);
867 clog
<< _("ERROR: cannot create temporary directory ")
868 << packaged_script_dir
<< ": " << e
872 rc
= ! copy_file("/dev/stdin", packaged_script_dir
+ "/-");
876 // Name the script in the packaged arguments.
877 rc
= add_package_arg ("script/-");
883 // Add the script to our package. This will also name the script
884 // in the packaged arguments.
885 rc
= include_file_or_directory ("script", s
.script_file
);
891 // Add -I paths. Skip the default directory.
892 if (s
.include_arg_start
!= -1)
894 unsigned limit
= s
.include_path
.size ();
895 for (unsigned i
= s
.include_arg_start
; i
< limit
; ++i
)
897 rc
= add_package_arg ("-I");
900 rc
= include_file_or_directory ("tapset", s
.include_path
[i
]);
906 // Add other options.
907 rc
= add_package_args ();
911 // Add the sysinfo file
912 string sysinfo
= "sysinfo: " + s
.kernel_release
+ " " + s
.architecture
;
913 rc
= write_to_file (client_tmpdir
+ "/sysinfo", sysinfo
);
917 // Add localization data
918 rc
= add_localization_variables();
923 // Add the arguments specified on the command line to the server request
924 // package, as appropriate.
926 compile_server_client::add_package_args ()
928 // stap arguments to be passed to the server.
930 unsigned limit
= s
.server_args
.size();
931 for (unsigned i
= 0; i
< limit
; ++i
)
933 rc
= add_package_arg (s
.server_args
[i
]);
939 limit
= s
.args
.size();
941 rc
= add_package_arg ("--");
944 for (unsigned i
= 0; i
< limit
; ++i
)
946 rc
= add_package_arg (s
.args
[i
]);
955 compile_server_client::add_package_arg (const string
&arg
)
959 fname
<< client_tmpdir
<< "/argv" << ++argc
;
960 write_to_file (fname
.str (), arg
); // NB: No terminating newline
964 // Symbolically link the given file or directory into the client's temp
965 // directory under the given subdirectory.
967 compile_server_client::include_file_or_directory (
968 const string
&subdir
, const string
&path
971 // Must predeclare these because we do use 'goto done' to
972 // exit from error situations.
973 vector
<string
> components
;
977 // Canonicalize the given path and remove the leading /.
979 char *cpath
= canonicalize_file_name (path
.c_str ());
982 // It can not be canonicalized. Use the name relative to
983 // the current working directory and let the server deal with it.
985 if (getcwd (cwd
, sizeof (cwd
)) == NULL
)
991 rpath
= string (cwd
) + "/" + path
;
995 // It can be canonicalized. Use the canonicalized name and add this
996 // file or directory to the request package.
1000 // Including / would require special handling in the code below and
1001 // is a bad idea anyway. Let's not allow it.
1005 clog
<< _F("%s resolves to %s\n", path
.c_str (), rpath
.c_str ());
1006 clog
<< _F("Unable to send %s to the server\n", path
.c_str ());
1010 // First create the requested subdirectory.
1011 name
= client_tmpdir
+ "/" + subdir
;
1012 rc
= create_dir (name
.c_str ());
1015 // Now create each component of the path within the sub directory.
1016 assert (rpath
[0] == '/');
1017 tokenize (rpath
.substr (1), components
, "/");
1018 assert (components
.size () >= 1);
1020 for (i
= 0; i
< components
.size() - 1; ++i
)
1022 if (components
[i
].empty ())
1023 continue; // embedded '//'
1024 name
+= "/" + components
[i
];
1025 rc
= create_dir (name
.c_str ());
1029 // Now make a symbolic link to the actual file or directory.
1030 assert (i
== components
.size () - 1);
1031 name
+= "/" + components
[i
];
1032 rc
= symlink (rpath
.c_str (), name
.c_str ());
1036 // Name this file or directory in the packaged arguments.
1037 rc
= add_package_arg (subdir
+ "/" + rpath
.substr (1));
1042 const char* e
= strerror (errno
);
1043 clog
<< "ERROR: unable to add "
1045 << " to temp directory as "
1046 << name
<< ": " << e
1052 // Add the localization variables to the server request
1055 compile_server_client::add_localization_variables()
1061 const set
<string
> &locVars
= localization_variables();
1062 set
<string
>::iterator it
;
1064 /* Note: We don't have to check for the contents of the environment
1065 * variables here, since they will be checked extensively on the
1068 for (it
= locVars
.begin(); it
!= locVars
.end(); it
++)
1070 char* var
= getenv((*it
).c_str());
1072 envVar
+= *it
+ "=" + (string
)var
+ "\n";
1074 fname
= client_tmpdir
+ "/locale";
1075 rc
= write_to_file(fname
, envVar
);
1079 // Package the client's temp directory into a form suitable for sending to the
1082 compile_server_client::package_request ()
1084 // Package up the temporary directory into a zip file.
1085 client_zipfile
= client_tmpdir
+ ".zip";
1086 string cmd
= "cd " + cmdstr_quoted(client_tmpdir
) + " && zip -qr "
1087 + cmdstr_quoted(client_zipfile
) + " *";
1088 vector
<string
> sh_cmd
;
1089 sh_cmd
.push_back("sh");
1090 sh_cmd
.push_back("-c");
1091 sh_cmd
.push_back(cmd
);
1092 int rc
= stap_system (s
.verbose
, sh_cmd
);
1097 compile_server_client::find_and_connect_to_server ()
1099 // Accumulate info on the specified servers.
1100 vector
<compile_server_info
> specified_servers
;
1101 get_specified_server_info (s
, specified_servers
);
1103 // Examine the specified servers to make sure that each has been resolved
1104 // with a host name, ip address and port. If not, try to obtain this
1105 // information by examining online servers.
1106 vector
<compile_server_info
> server_list
;
1107 for (vector
<compile_server_info
>::const_iterator i
= specified_servers
.begin ();
1108 i
!= specified_servers
.end ();
1111 // If we have an ip address and port number, then just use the one we've
1112 // been given. Otherwise, check for matching online servers and try their
1113 // ip addresses and ports.
1114 if (i
->hasAddress() && i
->port() != 0)
1115 add_server_info (*i
, server_list
);
1118 // Obtain a list of online servers.
1119 vector
<compile_server_info
> online_servers
;
1120 get_or_keep_online_server_info (s
, online_servers
, false/*keep*/);
1122 // If no specific server (port) has been specified,
1123 // then we'll need the servers to be
1124 // compatible and possible trusted as signers as well.
1127 get_or_keep_compatible_server_info (s
, online_servers
, true/*keep*/);
1128 if (! pr_contains (s
.privilege
, pr_stapdev
))
1129 get_or_keep_signing_server_info (s
, online_servers
, true/*keep*/);
1132 // Keep the ones (if any) which match our server.
1133 keep_common_server_info (*i
, online_servers
);
1135 // Add these servers (if any) to the server list.
1136 add_server_info (online_servers
, server_list
);
1140 // Did we identify any potential servers?
1141 unsigned limit
= server_list
.size ();
1144 clog
<< _("Unable to find a suitable compile server.") << endl
;
1146 // Try to explain why.
1147 vector
<compile_server_info
> online_servers
;
1148 get_or_keep_online_server_info (s
, online_servers
, false/*keep*/);
1149 if (online_servers
.empty ())
1150 clog
<< _("No servers online to select from.") << endl
;
1153 clog
<< _("The following servers are online:") << endl
;
1154 clog
<< online_servers
;
1155 if (! specified_servers
.empty ())
1157 clog
<< _("The following servers were requested:") << endl
;
1158 clog
<< specified_servers
;
1162 string criteria
= "online,trusted,compatible";
1163 if (! pr_contains (s
.privilege
, pr_stapdev
))
1164 criteria
+= ",signer";
1165 clog
<< _F("No servers matched the selection criteria of %s.", criteria
.c_str())
1172 // Sort the list of servers into a preferred order.
1173 preferred_order (server_list
);
1175 // Now try each of the identified servers in turn.
1176 int rc
= compile_using_server (server_list
);
1178 return 0; // success!
1180 // If the error was that a server's cert was expired, try again. This is because the server
1181 // should generate a new cert which may be automatically trusted by us if it is our server.
1182 // Give the server a chance to do this before retrying.
1183 if (rc
== SERVER_CERT_EXPIRED_ERROR
)
1186 clog
<< _("The server's certificate was expired. Trying again") << endl
<< flush
;
1188 rc
= compile_using_server (server_list
);
1190 return 0; // success!
1193 // We were unable to use any available server
1194 clog
<< _("Unable to connect to a server.") << endl
;
1195 clog
<< _("The following servers were tried:") << endl
;
1196 clog
<< server_list
;
1197 return 1; // Failure
1201 compile_server_client::compile_using_server (
1202 const vector
<compile_server_info
> &servers
1205 // Make sure NSPR is initialized. Must be done before NSS is initialized
1208 // Attempt connection using each of the available client certificate
1209 // databases. Assume the server certificate is invalid until proven otherwise.
1210 PR_SetError (SEC_ERROR_CA_CERT_INVALID
, 0);
1211 vector
<string
> dbs
= private_ssl_dbs
;
1212 vector
<string
>::iterator i
= dbs
.end();
1213 dbs
.insert (i
, public_ssl_dbs
.begin (), public_ssl_dbs
.end ());
1214 int rc
= GENERAL_ERROR
; // assume failure
1215 bool serverCertExpired
= false;
1216 for (i
= dbs
.begin (); i
!= dbs
.end (); ++i
)
1218 // Make sure the database directory exists. It is not an error if it
1220 if (! file_exists (*i
))
1223 #if 0 // no client authentication for now.
1224 // Set our password function callback.
1225 PK11_SetPasswordFunc (myPasswd
);
1228 // Initialize the NSS libraries.
1229 const char *cert_dir
= i
->c_str ();
1230 SECStatus secStatus
= nssInit (cert_dir
);
1231 if (secStatus
!= SECSuccess
)
1233 // Message already issued.
1234 continue; // try next database
1237 // Enable cipher suites which are allowed by U.S. export regulations.
1238 // SSL_ClearSessionCache is required for the new settings to take effect.
1239 secStatus
= NSS_SetExportPolicy ();
1240 SSL_ClearSessionCache ();
1241 if (secStatus
!= SECSuccess
)
1243 clog
<< _("Unable to set NSS export policy");
1245 nssCleanup (cert_dir
);
1246 continue; // try next database
1249 server_zipfile
= s
.tmpdir
+ "/server.zip";
1251 // Try each server in turn.
1252 for (vector
<compile_server_info
>::const_iterator j
= servers
.begin ();
1253 j
!= servers
.end ();
1256 // At a minimum we need an ip_address along with a port
1257 // number in order to contact the server.
1258 if (! j
->hasAddress() || j
->port() == 0)
1262 clog
<< _F("Attempting SSL connection with %s\n"
1263 " using certificates from the database in %s\n",
1264 lex_cast(*j
).c_str(), cert_dir
);
1266 rc
= client_connect (*j
, client_zipfile
.c_str(), server_zipfile
.c_str (),
1267 NULL
/*trustNewServer_p*/);
1270 s
.winning_server
= lex_cast(*j
);
1274 // Server cert has expired. Try other servers and/or databases, but take note because
1275 // server should generate a new certificate. If no other servers succeed, we'll try again
1276 // in case the new cert works.
1277 if (rc
== SERVER_CERT_EXPIRED_ERROR
)
1279 serverCertExpired
= true;
1285 clog
<< _(" Unable to connect: ");
1290 // SSL_ClearSessionCache is required before shutdown for client applications.
1291 SSL_ClearSessionCache ();
1292 nssCleanup (cert_dir
);
1294 if (rc
== SECSuccess
)
1298 // Indicate whether a server cert was expired, so we can try again, if desired.
1301 if (serverCertExpired
)
1302 rc
= SERVER_CERT_EXPIRED_ERROR
;
1309 compile_server_client::unpack_response ()
1311 // Unzip the response package.
1312 server_tmpdir
= s
.tmpdir
+ "/server";
1314 cmd
.push_back("unzip");
1315 cmd
.push_back("-qd");
1316 cmd
.push_back(server_tmpdir
);
1317 cmd
.push_back(server_zipfile
);
1318 int rc
= stap_system (s
.verbose
, cmd
);
1321 clog
<< _F("Unable to unzip the server response '%s'\n", server_zipfile
.c_str());
1325 // Determine the server protocol version.
1326 string filename
= server_tmpdir
+ "/version";
1327 if (file_exists (filename
))
1328 ::read_from_file (filename
, server_version
);
1330 // Warn about the shortcomings of this server, if it is down level.
1331 show_server_compatibility ();
1333 // If the server's response contains a systemtap temp directory, move
1334 // its contents to our temp directory.
1336 string filespec
= server_tmpdir
+ "/stap??????";
1338 clog
<< _F("Searching \"%s\"\n", filespec
.c_str());
1339 int r
= glob(filespec
.c_str (), 0, NULL
, & globbuf
);
1340 if (r
!= GLOB_NOSPACE
&& r
!= GLOB_ABORTED
&& r
!= GLOB_NOMATCH
)
1342 if (globbuf
.gl_pathc
> 1)
1344 clog
<< _("Incorrect number of files in server response") << endl
;
1349 assert (globbuf
.gl_pathc
== 1);
1350 string dirname
= globbuf
.gl_pathv
[0];
1352 clog
<< _(" found ") << dirname
<< endl
;
1354 filespec
= dirname
+ "/*";
1356 clog
<< _F("Searching \"%s\"\n", filespec
.c_str());
1357 int r
= glob(filespec
.c_str (), GLOB_PERIOD
, NULL
, & globbuf
);
1358 if (r
!= GLOB_NOSPACE
&& r
!= GLOB_ABORTED
&& r
!= GLOB_NOMATCH
)
1360 unsigned prefix_len
= dirname
.size () + 1;
1361 for (unsigned i
= 0; i
< globbuf
.gl_pathc
; ++i
)
1363 string oldname
= globbuf
.gl_pathv
[i
];
1364 if (oldname
.substr (oldname
.size () - 2) == "/." ||
1365 oldname
.substr (oldname
.size () - 3) == "/..")
1367 string newname
= s
.tmpdir
+ "/" + oldname
.substr (prefix_len
);
1369 clog
<< _F(" found %s -- linking from %s", oldname
.c_str(), newname
.c_str());
1370 rc
= symlink (oldname
.c_str (), newname
.c_str ());
1373 clog
<< _F("Unable to link '%s' to '%s':%s\n",
1374 oldname
.c_str(), newname
.c_str(), strerror(errno
));
1381 // If the server version is less that 1.6, remove the output line due to the synthetic
1382 // server-side -k. Look for a message containing the name of the temporary directory.
1383 // We can look for the English message since server versions before 1.6 do not support
1385 if (server_version
< "1.6")
1388 cmd
.push_back("sed");
1389 cmd
.push_back("-i");
1390 cmd
.push_back("/^Keeping temporary directory.*/ d");
1391 cmd
.push_back(server_tmpdir
+ "/stderr");
1392 stap_system (s
.verbose
, cmd
);
1395 // Remove the output line due to the synthetic server-side -p4
1397 cmd
.push_back("sed");
1398 cmd
.push_back("-i");
1399 cmd
.push_back("/^.*\\.ko$/ d");
1400 cmd
.push_back(server_tmpdir
+ "/stdout");
1401 stap_system (s
.verbose
, cmd
);
1404 globfree (& globbuf
);
1409 compile_server_client::process_response ()
1411 // Pick up the results of running stap on the server.
1412 string filename
= server_tmpdir
+ "/rc";
1414 int rc
= read_from_file (filename
, stap_rc
);
1419 if (s
.last_pass
>= 4)
1421 // The server should have returned a module.
1422 string filespec
= s
.tmpdir
+ "/*.ko";
1424 clog
<< _F("Searching \"%s\"\n", filespec
.c_str());
1427 int r
= glob(filespec
.c_str (), 0, NULL
, & globbuf
);
1428 if (r
!= GLOB_NOSPACE
&& r
!= GLOB_ABORTED
&& r
!= GLOB_NOMATCH
)
1430 if (globbuf
.gl_pathc
> 1)
1431 clog
<< _("Incorrect number of modules in server response") << endl
;
1434 assert (globbuf
.gl_pathc
== 1);
1435 string modname
= globbuf
.gl_pathv
[0];
1437 clog
<< _(" found ") << modname
<< endl
;
1439 // If a module name was not specified by the user, then set it to
1440 // be the one generated by the server.
1441 if (! s
.save_module
)
1443 vector
<string
> components
;
1444 tokenize (modname
, components
, "/");
1445 s
.module_name
= components
.back ();
1446 s
.module_name
.erase(s
.module_name
.size() - 3);
1449 // If a uprobes.ko module was returned, then make note of it.
1451 if (server_version
< "1.6")
1452 uprobes_ko
= s
.tmpdir
+ "/server/uprobes.ko";
1454 uprobes_ko
= s
.tmpdir
+ "/uprobes/uprobes.ko";
1456 if (file_exists (uprobes_ko
))
1458 s
.need_uprobes
= true;
1459 s
.uprobes_path
= uprobes_ko
;
1463 else if (s
.have_script
)
1467 clog
<< _("No module was returned by the server.") << endl
;
1471 globfree (& globbuf
);
1474 // Output stdout and stderr.
1475 filename
= server_tmpdir
+ "/stderr";
1476 flush_to_stream (filename
, clog
);
1478 filename
= server_tmpdir
+ "/stdout";
1479 flush_to_stream (filename
, cout
);
1485 compile_server_client::read_from_file (const string
&fname
, int &data
)
1487 // C++ streams may not set errno in the even of a failure. However if we
1488 // set it to 0 before each operation and it gets set during the operation,
1489 // then we can use its value in order to determine what happened.
1491 ifstream
f (fname
.c_str ());
1494 clog
<< _F("Unable to open file '%s' for reading: ", fname
.c_str());
1503 clog
<< _F("Unable to read from file '%s': ", fname
.c_str());
1507 // NB: not necessary to f.close ();
1508 return 0; // Success
1512 clog
<< strerror (errno
) << endl
;
1514 clog
<< _("unknown error") << endl
;
1515 return 1; // Failure
1520 compile_server_client::write_to_file (const string
&fname
, const T
&data
)
1522 // C++ streams may not set errno in the even of a failure. However if we
1523 // set it to 0 before each operation and it gets set during the operation,
1524 // then we can use its value in order to determine what happened.
1526 ofstream
f (fname
.c_str ());
1529 clog
<< _F("Unable to open file '%s' for writing: ", fname
.c_str());
1538 clog
<< _F("Unable to write to file '%s': ", fname
.c_str());
1542 // NB: not necessary to f.close ();
1543 return 0; // Success
1547 clog
<< strerror (errno
) << endl
;
1549 clog
<< _("unknown error") << endl
;
1550 return 1; // Failure
1554 compile_server_client::flush_to_stream (const string
&fname
, ostream
&o
)
1556 // C++ streams may not set errno in the even of a failure. However if we
1557 // set it to 0 before each operation and it gets set during the operation,
1558 // then we can use its value in order to determine what happened.
1560 ifstream
f (fname
.c_str ());
1563 clog
<< _F("Unable to open file '%s' for reading: ", fname
.c_str());
1569 // NB: o << f.rdbuf() misbehaves for some reason, appearing to close o,
1570 // which is unfortunate if o == clog or cout.
1575 if (f
.eof ()) return 0; // normal exit
1576 if (! f
.good()) break;
1578 if (! o
.good()) break;
1581 // NB: not necessary to f.close ();
1585 clog
<< strerror (errno
) << endl
;
1587 clog
<< _("unknown error") << endl
;
1588 return 1; // Failure
1592 compile_server_client::show_server_compatibility () const
1594 // Locale sensitivity was added in version 1.6
1595 if (server_version
< "1.6")
1597 clog
<< _F("Server protocol version is %s\n", server_version
.v
);
1598 clog
<< _("The server does not use localization information passed by the client\n");
1602 // Issue a status message for when a server's trust is already in place.
1604 trust_already_in_place (
1605 const compile_server_info
&server
,
1606 const vector
<compile_server_info
> &server_list
,
1607 const string cert_db_path
,
1611 // What level of trust?
1613 if (cert_db_path
== signing_cert_db_path ())
1614 purpose
= _("as a module signer for all users");
1617 purpose
= _("as an SSL peer");
1618 if (cert_db_path
== global_ssl_cert_db_path ())
1619 purpose
+= _(" for all users");
1621 purpose
+= _(" for the current user");
1624 // Issue a message for each server in the list with the same certificate.
1625 unsigned limit
= server_list
.size ();
1626 for (unsigned i
= 0; i
< limit
; ++i
)
1628 if (server
.certinfo
!= server_list
[i
].certinfo
)
1630 clog
<< server_list
[i
] << _(" is already ");
1632 clog
<< _("untrusted ") << purpose
<< endl
;
1634 clog
<< _("trusted ") << purpose
<< endl
;
1638 // Add the given servers to the given database of trusted servers.
1641 systemtap_session
&s
,
1642 const string
&cert_db_path
,
1643 const vector
<compile_server_info
> &server_list
1646 // Get a list of servers already trusted. This opens the database, so do it
1647 // before we open it for our own purposes.
1648 vector
<compile_server_info
> already_trusted
;
1649 get_server_info_from_db (s
, already_trusted
, cert_db_path
);
1651 // Make sure the given path exists.
1652 if (create_dir (cert_db_path
.c_str (), 0755) != 0)
1654 clog
<< _F("Unable to find or create the client certificate database directory %s: ", cert_db_path
.c_str());
1659 // Must predeclare this because of jumps to cleanup: below.
1660 vector
<string
> processed_certs
;
1662 // Make sure NSPR is initialized. Must be done before NSS is initialized
1665 // Initialize the NSS libraries -- read/write
1666 SECStatus secStatus
= nssInit (cert_db_path
.c_str (), 1/*readwrite*/);
1667 if (secStatus
!= SECSuccess
)
1669 // Message already issued.
1673 // Enable cipher suites which are allowed by U.S. export regulations.
1674 // SSL_ClearSessionCache is required for the new settings to take effect.
1675 secStatus
= NSS_SetExportPolicy ();
1676 SSL_ClearSessionCache ();
1677 if (secStatus
!= SECSuccess
)
1679 clog
<< _("Unable to set NSS export policy");
1684 // Iterate over the servers to become trusted. Contact each one and
1685 // add it to the list of trusted servers if it is not already trusted.
1686 // client_connect will issue any error messages.
1687 for (vector
<compile_server_info
>::const_iterator server
= server_list
.begin();
1688 server
!= server_list
.end ();
1691 // Trust is based on certificates. We need only add trust in the
1692 // same certificate once.
1693 if (find (processed_certs
.begin (), processed_certs
.end (),
1694 server
->certinfo
) != processed_certs
.end ())
1696 processed_certs
.push_back (server
->certinfo
);
1698 // We need not contact the server if it is already trusted.
1699 if (find (already_trusted
.begin (), already_trusted
.end (), *server
) !=
1700 already_trusted
.end ())
1703 trust_already_in_place (*server
, server_list
, cert_db_path
, false/*revoking*/);
1706 // At a minimum we need an ip_address along with a port
1707 // number in order to contact the server.
1708 if (! server
->hasAddress() || server
->port() == 0)
1710 int rc
= client_connect (*server
, NULL
, NULL
, "permanent");
1713 clog
<< _F("Unable to connect to %s", lex_cast(*server
).c_str()) << endl
;
1720 // SSL_ClearSessionCache is required before shutdown for client applications.
1721 SSL_ClearSessionCache ();
1722 nssCleanup (cert_db_path
.c_str ());
1724 // Make sure the database files are readable.
1726 string filespec
= cert_db_path
+ "/*.db";
1728 clog
<< _F("Searching \"%s\"\n", filespec
.c_str());
1729 int r
= glob (filespec
.c_str (), 0, NULL
, & globbuf
);
1730 if (r
!= GLOB_NOSPACE
&& r
!= GLOB_ABORTED
&& r
!= GLOB_NOMATCH
)
1732 for (unsigned i
= 0; i
< globbuf
.gl_pathc
; ++i
)
1734 string filename
= globbuf
.gl_pathv
[i
];
1736 clog
<< _(" found ") << filename
<< endl
;
1738 if (chmod (filename
.c_str (), 0644) != 0)
1740 s
.print_warning("Unable to change permissions on " + filename
+ ": ");
1747 // Remove the given servers from the given database of trusted servers.
1749 revoke_server_trust (
1750 systemtap_session
&s
,
1751 const string
&cert_db_path
,
1752 const vector
<compile_server_info
> &server_list
1755 // Make sure the given path exists.
1756 if (! file_exists (cert_db_path
))
1760 clog
<< _F("Certificate database '%s' does not exist",
1761 cert_db_path
.c_str()) << endl
;
1762 for (vector
<compile_server_info
>::const_iterator server
= server_list
.begin();
1763 server
!= server_list
.end ();
1765 trust_already_in_place (*server
, server_list
, cert_db_path
, true/*revoking*/);
1770 // Must predeclare these because of jumps to cleanup: below.
1771 CERTCertDBHandle
*handle
;
1772 PRArenaPool
*tmpArena
= NULL
;
1773 CERTCertList
*certs
= NULL
;
1774 CERTCertificate
*db_cert
;
1775 vector
<string
> processed_certs
;
1776 const char *nickname
;
1778 // Make sure NSPR is initialized. Must be done before NSS is initialized
1781 // Initialize the NSS libraries -- read/write
1782 SECStatus secStatus
= nssInit (cert_db_path
.c_str (), 1/*readwrite*/);
1783 if (secStatus
!= SECSuccess
)
1785 // Message already issued
1788 handle
= CERT_GetDefaultCertDB();
1790 // A memory pool to work in
1791 tmpArena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
1794 clog
<< _("Out of memory:");
1799 // Iterate over the servers to become untrusted.
1800 nickname
= server_cert_nickname ();
1801 for (vector
<compile_server_info
>::const_iterator server
= server_list
.begin();
1802 server
!= server_list
.end ();
1805 // If the server's certificate serial number is unknown, then we can't
1806 // match it with one in the database.
1807 if (server
->certinfo
.empty ())
1810 // Trust is based on certificates. We need only revoke trust in the same
1811 // certificate once.
1812 if (find (processed_certs
.begin (), processed_certs
.end (),
1813 server
->certinfo
) != processed_certs
.end ())
1815 processed_certs
.push_back (server
->certinfo
);
1817 // Search the client-side database of trusted servers.
1818 db_cert
= PK11_FindCertFromNickname (nickname
, NULL
);
1821 // No trusted servers. Not an error, but issue a status message.
1823 trust_already_in_place (*server
, server_list
, cert_db_path
, true/*revoking*/);
1827 // Here, we have one cert with the desired nickname.
1828 // Now, we will attempt to get a list of ALL certs
1829 // with the same subject name as the cert we have. That list
1830 // should contain, at a minimum, the one cert we have already found.
1831 // If the list of certs is empty (NULL), the libraries have failed.
1832 certs
= CERT_CreateSubjectCertList (NULL
, handle
, & db_cert
->derSubject
,
1833 PR_Now (), PR_FALSE
);
1834 CERT_DestroyCertificate (db_cert
);
1837 clog
<< _F("Unable to query certificate database %s: ",
1838 cert_db_path
.c_str()) << endl
;
1839 PORT_SetError (SEC_ERROR_LIBRARY_FAILURE
);
1844 // Find the certificate matching the one belonging to our server.
1845 CERTCertListNode
*node
;
1846 for (node
= CERT_LIST_HEAD (certs
);
1847 ! CERT_LIST_END (node
, certs
);
1848 node
= CERT_LIST_NEXT (node
))
1850 // The certificate we're working with.
1851 db_cert
= node
->cert
;
1853 // Get the serial number.
1854 string serialNumber
= get_cert_serial_number (db_cert
);
1856 // Does the serial number match that of the current server?
1857 if (serialNumber
!= server
->certinfo
)
1858 continue; // goto next certificate
1860 // All is ok! Remove the certificate from the database.
1862 } // Loop over certificates in the database
1864 // Was a certificate matching the server found? */
1865 if (CERT_LIST_END (node
, certs
))
1867 // Not found. Server is already untrusted.
1869 trust_already_in_place (*server
, server_list
, cert_db_path
, true/*revoking*/);
1873 secStatus
= SEC_DeletePermCertificate (db_cert
);
1874 if (secStatus
!= SECSuccess
)
1876 clog
<< _F("Unable to remove certificate from %s: ",
1877 cert_db_path
.c_str()) << endl
;
1881 CERT_DestroyCertList (certs
);
1883 } // Loop over servers
1887 CERT_DestroyCertList (certs
);
1889 PORT_FreeArena (tmpArena
, PR_FALSE
);
1891 nssCleanup (cert_db_path
.c_str ());
1894 // Obtain information about servers from the certificates in the given database.
1896 get_server_info_from_db (
1897 systemtap_session
&s
,
1898 vector
<compile_server_info
> &servers
,
1899 const string
&cert_db_path
1902 // Make sure the given path exists.
1903 if (! file_exists (cert_db_path
))
1906 clog
<< _F("Certificate database '%s' does not exist.",
1907 cert_db_path
.c_str()) << endl
;
1911 // Make sure NSPR is initialized. Must be done before NSS is initialized
1914 // Initialize the NSS libraries -- readonly
1915 SECStatus secStatus
= nssInit (cert_db_path
.c_str ());
1916 if (secStatus
!= SECSuccess
)
1918 // Message already issued.
1922 // Must predeclare this because of jumps to cleanup: below.
1923 PRArenaPool
*tmpArena
= NULL
;
1924 CERTCertList
*certs
= get_cert_list_from_db (server_cert_nickname ());
1928 clog
<< _F("No certificate found in database %s", cert_db_path
.c_str ()) << endl
;
1932 // A memory pool to work in
1933 tmpArena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
1936 clog
<< _("Out of memory:");
1940 for (CERTCertListNode
*node
= CERT_LIST_HEAD (certs
);
1941 ! CERT_LIST_END (node
, certs
);
1942 node
= CERT_LIST_NEXT (node
))
1944 compile_server_info server_info
;
1946 // The certificate we're working with.
1947 CERTCertificate
*db_cert
= node
->cert
;
1949 // Get the host name. It is in the alt-name extension of the
1952 subAltName
.data
= NULL
;
1953 secStatus
= CERT_FindCertExtension (db_cert
,
1954 SEC_OID_X509_SUBJECT_ALT_NAME
,
1956 if (secStatus
!= SECSuccess
|| ! subAltName
.data
)
1958 clog
<< _("Unable to find alt name extension on server certificate: ") << endl
;
1963 // Decode the extension.
1964 CERTGeneralName
*nameList
= CERT_DecodeAltNameExtension (tmpArena
, & subAltName
);
1965 SECITEM_FreeItem(& subAltName
, PR_FALSE
);
1968 clog
<< _("Unable to decode alt name extension on server certificate: ") << endl
;
1973 // We're interested in the first alternate name.
1974 assert (nameList
->type
== certDNSName
);
1975 server_info
.host_name
= string ((const char *)nameList
->name
.other
.data
,
1976 nameList
->name
.other
.len
);
1977 // Don't free nameList. It's part of the tmpArena.
1979 // Get the serial number.
1980 server_info
.certinfo
= get_cert_serial_number (db_cert
);
1982 // Our results will at a minimum contain this server.
1983 add_server_info (server_info
, servers
);
1985 // Augment the list by querying all online servers and keeping the ones
1986 // with the same cert serial number.
1987 vector
<compile_server_info
> online_servers
;
1988 get_or_keep_online_server_info (s
, online_servers
, false/*keep*/);
1989 keep_server_info_with_cert_and_port (s
, server_info
, online_servers
);
1990 add_server_info (online_servers
, servers
);
1995 CERT_DestroyCertList (certs
);
1997 PORT_FreeArena (tmpArena
, PR_FALSE
);
1999 nssCleanup (cert_db_path
.c_str ());
2002 // Utility Functions.
2003 //-----------------------------------------------------------------------
2004 ostream
&operator<< (ostream
&s
, const compile_server_info
&i
)
2007 if (! i
.host_name
.empty ())
2015 switch (i
.address
.raw
.family
)
2020 #define MAX_NETADDR_SIZE 46 // from the NSPR API reference.
2021 char buf
[MAX_NETADDR_SIZE
];
2022 prStatus
= PR_NetAddrToString(& i
.address
, buf
, sizeof (buf
));
2023 if (prStatus
== PR_SUCCESS
) {
2042 if (! i
.sysinfo
.empty ())
2043 s
<< i
.sysinfo
<< '"';
2047 if (! i
.version
.empty ())
2051 s
<< " certinfo=\"";
2052 if (! i
.certinfo
.empty ())
2053 s
<< i
.certinfo
<< '"';
2059 ostream
&operator<< (ostream
&s
, const vector
<compile_server_info
> &v
)
2061 for (unsigned i
= 0; i
< v
.size(); ++i
)
2067 operator!= (const PRNetAddr
&x
, const PRNetAddr
&y
)
2069 // Same address family?
2070 if (x
.raw
.family
!= y
.raw
.family
)
2073 // Compare all fields except the port and the flow info. Do this by comparing the other fields
2074 // directly as the other (unused) fields can sometimes contain garbage.
2075 switch (x
.raw
.family
)
2078 return x
.ipv6
.scope_id
!= y
.ipv6
.scope_id
||
2079 memcmp (& x
.ipv6
.ip
, & y
.ipv6
.ip
, sizeof(x
.ipv6
.ip
)) != 0;
2082 return x
.inet
.ip
!= y
.inet
.ip
;
2091 copyAddress (PRIPv6Addr
&PRin6
, const in6_addr
&in6
)
2093 // The NSPR type is a typedef of struct in6_addr, but C++ won't let us copy it
2094 assert (sizeof (PRin6
) == sizeof (in6
));
2095 memcpy (& PRin6
, & in6
, sizeof (PRin6
));
2099 // Return the default server specification, used when none is given on the
2102 default_server_spec (const systemtap_session
&s
)
2104 // If --privilege=X has been used, where X is not stapdev,
2105 // the default is online,trusted,compatible,signer
2107 // the default is online,trusted,compatible
2109 // Having said that,
2110 // 'online' and 'compatible' will only succeed if we have avahi
2111 // 'trusted' and 'signer' will only succeed if we have NSS
2113 string working_string
= "online,trusted,compatible";
2114 if (! pr_contains (s
.privilege
, pr_stapdev
))
2115 working_string
+= ",signer";
2116 return working_string
;
2120 server_spec_to_pmask (const string
&server_spec
)
2122 // Construct a mask of the server properties that have been requested.
2123 // The available properties are:
2124 // trusted - servers which are trusted SSL peers.
2125 // online - online servers.
2126 // compatible - servers which compile for the current kernel release
2127 // and architecture.
2128 // signer - servers which are trusted module signers.
2129 // specified - servers which have been specified using --use-server=XXX.
2130 // If no servers have been specified, then this is
2131 // equivalent to --list-servers=trusted,online,compatible.
2132 // all - all trusted servers, trusted module signers,
2133 // servers currently online and specified servers.
2134 string working_spec
= server_spec
;
2135 vector
<string
> properties
;
2136 tokenize (working_spec
, properties
, ",");
2138 unsigned limit
= properties
.size ();
2139 for (unsigned i
= 0; i
< limit
; ++i
)
2141 const string
&property
= properties
[i
];
2142 // Tolerate (and ignore) empty properties.
2143 if (property
.empty ())
2145 if (property
== "all")
2147 pmask
|= compile_server_all
;
2149 else if (property
== "specified")
2151 pmask
|= compile_server_specified
;
2153 else if (property
== "trusted")
2155 pmask
|= compile_server_trusted
;
2157 else if (property
== "online")
2159 pmask
|= compile_server_online
;
2161 else if (property
== "compatible")
2163 pmask
|= compile_server_compatible
;
2165 else if (property
== "signer")
2167 pmask
|= compile_server_signer
;
2171 // XXX PR13274 needs-session to use print_warning()
2172 clog
<< _F("WARNING: unsupported compile server property: %s", property
.c_str())
2180 query_server_status (systemtap_session
&s
)
2182 unsigned limit
= s
.server_status_strings
.size ();
2183 for (unsigned i
= 0; i
< limit
; ++i
)
2184 query_server_status (s
, s
.server_status_strings
[i
]);
2188 query_server_status (systemtap_session
&s
, const string
&status_string
)
2190 // If this string is empty, then the default is "specified"
2191 string working_string
= status_string
;
2192 if (working_string
.empty ())
2193 working_string
= "specified";
2195 // If the query is "specified" and no servers have been specified
2196 // (i.e. --use-server not used or used with no argument), then
2197 // use the default query.
2198 // TODO: This may not be necessary. The underlying queries should handle
2199 // "specified" properly.
2200 if (working_string
== "specified" &&
2201 (s
.specified_servers
.empty () ||
2202 (s
.specified_servers
.size () == 1 && s
.specified_servers
[0].empty ())))
2203 working_string
= default_server_spec (s
);
2205 int pmask
= server_spec_to_pmask (working_string
);
2207 // Now obtain a list of the servers which match the criteria.
2208 vector
<compile_server_info
> raw_servers
;
2209 get_server_info (s
, pmask
, raw_servers
);
2211 // Augment the listing with as much information as possible by adding
2212 // information from known servers.
2213 vector
<compile_server_info
> servers
;
2214 get_all_server_info (s
, servers
);
2215 keep_common_server_info (raw_servers
, servers
);
2217 // Sort the list of servers into a preferred order.
2218 preferred_order (servers
);
2220 // Print the server information. Skip the empty entry at the head of the list.
2221 clog
<< _F("Systemtap Compile Server Status for '%s'", working_string
.c_str()) << endl
;
2223 unsigned limit
= servers
.size ();
2224 for (unsigned i
= 0; i
< limit
; ++i
)
2226 assert (! servers
[i
].empty ());
2227 // Don't list servers with no cert information. They may not actually
2229 // TODO: Could try contacting the server and obtaining its cert
2230 if (servers
[i
].certinfo
.empty ())
2232 clog
<< servers
[i
] << endl
;
2236 clog
<< _("No servers found") << endl
;
2239 // Add or remove trust of the servers specified on the command line.
2241 manage_server_trust (systemtap_session
&s
)
2243 // This function should do nothing if we don't have NSS.
2244 // Nothing to do if --trust-servers was not specified.
2245 if (s
.server_trust_spec
.empty ())
2248 // Break up and analyze the trust specification. Recognized components are:
2249 // ssl - trust the specified servers as ssl peers
2250 // signer - trust the specified servers as module signers
2251 // revoke - revoke the requested trust
2252 // all-users - apply/revoke the requested trust for all users
2253 // no-prompt - don't prompt the user for confirmation
2254 vector
<string
>components
;
2255 tokenize (s
.server_trust_spec
, components
, ",");
2257 bool signer
= false;
2258 bool revoke
= false;
2259 bool all_users
= false;
2260 bool no_prompt
= false;
2262 for (vector
<string
>::const_iterator i
= components
.begin ();
2263 i
!= components
.end ();
2268 else if (*i
== "signer")
2270 if (geteuid () != 0)
2272 clog
<< _("Only root can specify 'signer' on --trust-servers") << endl
;
2278 else if (*i
== "revoke")
2280 else if (*i
== "all-users")
2282 if (geteuid () != 0)
2284 clog
<< _("Only root can specify 'all-users' on --trust-servers") << endl
;
2290 else if (*i
== "no-prompt")
2293 s
.print_warning("Unrecognized server trust specification: " + *i
);
2298 // Make sure NSPR is initialized
2301 // Now obtain the list of specified servers.
2302 vector
<compile_server_info
> server_list
;
2303 get_specified_server_info (s
, server_list
, true/*no_default*/);
2305 // Did we identify any potential servers?
2306 unsigned limit
= server_list
.size ();
2309 clog
<< _("No servers identified for trust") << endl
;
2313 // Create a string representing the request in English.
2314 // If neither 'ssl' or 'signer' was specified, the default is 'ssl'.
2315 if (! ssl
&& ! signer
)
2317 ostringstream trustString
;
2320 trustString
<< _("as an SSL peer");
2322 trustString
<< _(" for all users");
2324 trustString
<< _(" for the current user");
2329 trustString
<< _(" and ");
2330 trustString
<< _("as a module signer for all users");
2333 // Prompt the user to confirm what's about to happen.
2337 clog
<< _("Revoking trust ");
2339 clog
<< _("Adding trust ");
2344 clog
<< _("Revoke trust ");
2346 clog
<< _("Add trust ");
2348 clog
<< _F("in the following servers %s", trustString
.str().c_str());
2352 for (unsigned i
= 0; i
< limit
; ++i
)
2353 clog
<< " " << server_list
[i
] << endl
;
2356 clog
<< "[y/N] " << flush
;
2358 // Only carry out the operation if the response is "yes"
2361 if (response
[0] != 'y' && response
[0] != 'Y')
2363 clog
<< _("Server trust unchanged") << endl
;
2368 // Now add/revoke the requested trust.
2369 string cert_db_path
;
2373 cert_db_path
= global_ssl_cert_db_path ();
2375 cert_db_path
= private_ssl_cert_db_path ();
2377 revoke_server_trust (s
, cert_db_path
, server_list
);
2379 add_server_trust (s
, cert_db_path
, server_list
);
2383 cert_db_path
= signing_cert_db_path ();
2385 revoke_server_trust (s
, cert_db_path
, server_list
);
2387 add_server_trust (s
, cert_db_path
, server_list
);
2391 static compile_server_cache
*
2392 cscache(systemtap_session
& s
)
2394 if (!s
.server_cache
)
2395 s
.server_cache
= new compile_server_cache();
2396 return s
.server_cache
;
2401 systemtap_session
&s
,
2403 vector
<compile_server_info
> &servers
2406 // Get information on compile servers matching the requested criteria.
2407 // The order of queries is significant. Accumulating queries must go first
2408 // followed by accumulating/filtering queries.
2410 if (((pmask
& compile_server_all
)))
2412 get_all_server_info (s
, servers
);
2415 // Add the specified servers, if requested
2416 if ((pmask
& compile_server_specified
))
2418 get_specified_server_info (s
, servers
);
2421 // Now filter or accumulate the list depending on whether a query has
2422 // already been made.
2423 if ((pmask
& compile_server_online
))
2425 get_or_keep_online_server_info (s
, servers
, keep
);
2428 if ((pmask
& compile_server_trusted
))
2430 get_or_keep_trusted_server_info (s
, servers
, keep
);
2433 if ((pmask
& compile_server_signer
))
2435 get_or_keep_signing_server_info (s
, servers
, keep
);
2438 if ((pmask
& compile_server_compatible
))
2440 get_or_keep_compatible_server_info (s
, servers
, keep
);
2445 // Get information about all online servers as well as servers trusted
2446 // as SSL peers and servers trusted as signers.
2448 get_all_server_info (
2449 systemtap_session
&s
,
2450 vector
<compile_server_info
> &servers
2453 get_or_keep_online_server_info (s
, servers
, false/*keep*/);
2454 get_or_keep_trusted_server_info (s
, servers
, false/*keep*/);
2455 get_or_keep_signing_server_info (s
, servers
, false/*keep*/);
2459 get_default_server_info (
2460 systemtap_session
&s
,
2461 vector
<compile_server_info
> &servers
2464 // We only need to obtain this once per session. This is a good thing(tm)
2465 // since obtaining this information is expensive.
2466 vector
<compile_server_info
>& default_servers
= cscache(s
)->default_servers
;
2467 if (default_servers
.empty ())
2469 // Get the required information.
2470 // get_server_info will add an empty entry at the beginning to indicate
2471 // that the search has been performed, in case the search comes up empty.
2472 int pmask
= server_spec_to_pmask (default_server_spec (s
));
2473 get_server_info (s
, pmask
, default_servers
);
2476 // Add the information, but not duplicates.
2477 add_server_info (default_servers
, servers
);
2481 isPort (const char *pstr
, compile_server_info
&server_info
)
2485 unsigned long p
= strtoul (pstr
, & estr
, 10);
2486 if (errno
!= 0 || *estr
!= '\0' || p
> USHRT_MAX
)
2488 clog
<< _F("Invalid port number specified: %s", pstr
) << endl
;
2491 server_info
.setPort (p
);
2496 isIPv6 (const string
&server
, compile_server_info
&server_info
)
2498 // An IPv6 address is 8 hex components separated by colons.
2499 // One contiguous block of zero segments in the address may be elided using ::.
2500 // An interface may be specified by appending %IF_NAME to the address (e.g. %eth0).
2501 // For now, assume eth0 if none is specified.
2502 // A port may be specified by enclosing the ip address in [] and adding :<port>.
2503 // Allow a bracketed address without a port.
2504 assert (! server
.empty());
2506 string::size_type portIx
;
2507 if (server
[0] == '[')
2509 string::size_type endBracket
= server
.find (']');
2510 if (endBracket
== string::npos
)
2511 return false; // Not a valid IPv6 address
2512 // Extract the address.
2513 ip
= server
.substr (1, endBracket
- 1);
2514 portIx
= endBracket
+ 1;
2519 portIx
= string::npos
;
2522 // Find out how many components there are. The maximum is 8
2524 vector
<string
> components
;
2525 tokenize_full (ip
, components
, ":");
2526 if (components
.size() > 8)
2527 return false; // Not a valid IPv6 address
2529 // The components must be either hex values between 0 and 0xffff, or must be empty.
2530 // There can be only one empty component.
2532 for (unsigned i
= 0; i
< components
.size(); ++i
)
2534 if (components
[i
].empty())
2537 return false; // Not a valid IPv6 address
2539 // If it's the final component, see if it specifies the interface. If so, strip it from the
2540 // component in order to simplify parsing. It still remains as part of the original ip address
2542 if (i
== components
.size() - 1)
2544 size_t ix
= components
[i
].find ('%');
2545 if (ix
!= string::npos
)
2547 interface
= components
[i
].substr(ix
);
2548 components
[i
] = components
[i
].substr(0, ix
);
2551 // Skip leading zeroes.
2553 for (j
= 0; j
< components
[i
].size(); ++j
)
2555 if (components
[i
][j
] != '0')
2558 // Max of 4 hex digits
2559 if (components
[i
].size() - j
> 4)
2560 return false; // Not a valid IPv6 address
2561 for (/**/; j
< components
[i
].size(); ++j
)
2563 if (! isxdigit (components
[i
][j
]))
2564 return false; // Not a valid IPv6 address
2567 // If there is no empty component, then there must be exactly 8 components.
2568 if (! empty
&& components
.size() != 8)
2569 return false; // Not a valid IPv6 address
2571 // Calls to setPort is isPort need to know that this is an IPv6 address.
2572 server_info
.address
.raw
.family
= PR_AF_INET6
;
2574 // Examine the optional port
2575 if (portIx
!= string::npos
)
2577 string port
= server
.substr (portIx
);
2578 if (port
.size() != 0)
2580 if (port
.size() < 2 || port
[0] != ':')
2581 return false; // Not a valid Port
2583 port
= port
.substr (1);
2584 if (! isPort (port
.c_str(), server_info
))
2585 return false; // not a valid port
2589 server_info
.setPort (0);
2591 // If no interface as specified, the use eth0.
2592 if (interface
.empty() && ip
!= "::1")
2595 // Treat the ip address string like a host name.
2596 server_info
.host_name
= ip
;
2597 return true; // valid IPv6 address.
2601 isIPv4 (const string
&server
, compile_server_info
&server_info
)
2603 // An IPv4 address is 4 decimal components separated by periods with an
2604 // additional optional decimal port separated from the address by a colon.
2605 assert (! server
.empty());
2607 // Find out how many components there are. The maximum is 8
2608 vector
<string
> components
;
2609 tokenize (server
, components
, ":");
2610 if (components
.size() > 2)
2611 return false; // Not a valid IPv4 address
2613 // Separate the host from the port (if any).
2616 if (components
.size() <= 1)
2619 host
= components
[0];
2620 port
= components
[1];
2623 // Separate the host components.
2624 // There must be exactly 4 components.
2625 components
.clear ();
2626 tokenize (server
, components
, ".");
2627 if (components
.size() != 4)
2628 return false; // Not a valid IPv4 address
2630 // The components must be decimal values between 0 and 255.
2631 for (unsigned i
= 0; i
< components
.size(); ++i
)
2633 if (components
[i
].empty())
2634 return false; // Not a valid IPv4 address
2637 unsigned long p
= strtoul (components
[i
].c_str(), & estr
, 10);
2638 if (errno
!= 0 || *estr
!= '\0' || p
< 0 || p
> 255)
2639 return false; // Not a valid IPv4 address
2642 // Calls to setPort is isPort need to know that this is an IPv4 address.
2643 server_info
.address
.raw
.family
= PR_AF_INET
;
2645 // Examine the optional port
2646 if (! port
.empty ()) {
2647 if (! isPort (port
.c_str(), server_info
))
2648 return false; // not a valid port
2651 server_info
.setPort (0);
2653 // Treat the ip address string like a host name.
2654 server_info
.host_name
= host
;
2655 return true; // valid IPv4 address.
2659 isCertSerialNumber (const string
&server
, compile_server_info
&server_info
)
2661 // This function assumes that we have already ruled out the server spec being an IPv6 address.
2662 // Certificate serial numbers are 5 fields separated by colons plus an optional 6th decimal
2663 // field specifying a port.
2664 // Assume IPv4 (for now) when storing the port.
2665 server_info
.address
.raw
.family
= PR_AF_INET
;
2666 assert (! server
.empty());
2667 string host
= server
;
2668 vector
<string
> components
;
2669 tokenize (host
, components
, ":");
2670 switch (components
.size ())
2673 if (! isPort (components
.back().c_str(), server_info
))
2674 return false; // not a valid port
2675 host
= host
.substr (0, host
.find_last_of (':'));
2678 server_info
.certinfo
= host
;
2681 return false; // not a cert serial number
2684 return true; // valid cert serial number and optional port
2688 isDomain (const string
&server
, compile_server_info
&server_info
)
2690 // Accept one or two components separated by a colon. The first will be the domain name and
2691 // the second must a port number.
2692 // Assume IPv4 (for now) when storing the port.
2693 server_info
.address
.raw
.family
= PR_AF_INET
;
2694 assert (! server
.empty());
2695 string host
= server
;
2696 vector
<string
> components
;
2697 tokenize (host
, components
, ":");
2698 switch (components
.size ())
2701 if (! isPort (components
.back().c_str(), server_info
))
2702 return false; // not a valid port
2703 host
= host
.substr (0, host
.find_last_of (':'));
2706 server_info
.host_name
= host
;
2709 return false; // not a valid domain name
2716 get_specified_server_info (
2717 systemtap_session
&s
,
2718 vector
<compile_server_info
> &servers
,
2722 // We only need to obtain this once per session. This is a good thing(tm)
2723 // since obtaining this information is expensive.
2724 vector
<compile_server_info
>& specified_servers
= cscache(s
)->specified_servers
;
2725 if (specified_servers
.empty ())
2727 // Maintain an empty entry to indicate that this search has been
2728 // performed, in case the search comes up empty.
2729 specified_servers
.push_back (compile_server_info ());
2731 // If --use-server was not specified at all, then return info for the
2732 // default server list.
2733 if (s
.specified_servers
.empty ())
2736 get_default_server_info (s
, specified_servers
);
2740 // Iterate over the specified servers. For each specification, add to
2741 // the list of servers.
2742 unsigned num_specified_servers
= s
.specified_servers
.size ();
2743 for (unsigned i
= 0; i
< num_specified_servers
; ++i
)
2745 string
&server
= s
.specified_servers
[i
];
2747 // If no specific server(s) specified, then use the default servers.
2748 if (server
.empty ())
2751 get_default_server_info (s
, specified_servers
);
2755 // Determine what has been specified. Servers may be specified by:
2757 // - certificate-serial-number{:port}
2758 // - IPv4-address{:port}
2759 // - IPv6-address{:port}
2760 // where items within {} are optional.
2761 // Check for IPv6 addresses first. It reduces the amount of checking necessary for
2762 // certificate serial numbers.
2763 compile_server_info server_info
;
2764 vector
<compile_server_info
> known_servers
;
2765 if (isIPv6 (server
, server_info
) || isIPv4 (server
, server_info
) ||
2766 isDomain (server
, server_info
))
2768 // Find known servers matching the specified information.
2769 get_all_server_info (s
, known_servers
);
2770 // Resolve this host and add any information that is discovered.
2771 resolve_host (s
, server_info
, specified_servers
);
2772 // Keep the common server info.
2773 keep_common_server_info (known_servers
, specified_servers
);
2775 else if (isCertSerialNumber (server
, server_info
))
2777 // The host could not be resolved. Try resolving it as a certificate serial
2778 // number. Look for all known servers with this serial number and (optional)
2780 get_all_server_info (s
, known_servers
);
2781 keep_server_info_with_cert_and_port (s
, server_info
, known_servers
);
2783 if (known_servers
.empty ())
2786 clog
<< _F("No server matching %s found", server
.c_str()) << endl
;
2789 add_server_info (known_servers
, specified_servers
);
2793 clog
<< _F("Invalid server specification for --use-server: %s", server
.c_str())
2796 } // Loop over --use-server options
2797 } // -- use-server specified
2798 } // Server information is not cached
2800 // Add the information, but not duplicates.
2801 add_server_info (specified_servers
, servers
);
2805 get_or_keep_trusted_server_info (
2806 systemtap_session
&s
,
2807 vector
<compile_server_info
> &servers
,
2811 // If we're filtering the list and it's already empty, then
2812 // there's nothing to do.
2813 if (keep
&& servers
.empty ())
2816 // We only need to obtain this once per session. This is a good thing(tm)
2817 // since obtaining this information is expensive.
2818 vector
<compile_server_info
>& trusted_servers
= cscache(s
)->trusted_servers
;
2819 if (trusted_servers
.empty ())
2821 // Maintain an empty entry to indicate that this search has been
2822 // performed, in case the search comes up empty.
2823 trusted_servers
.push_back (compile_server_info ());
2825 // Check the private database first.
2826 string cert_db_path
= private_ssl_cert_db_path ();
2827 get_server_info_from_db (s
, trusted_servers
, cert_db_path
);
2829 // Now check the global database.
2830 cert_db_path
= global_ssl_cert_db_path ();
2831 get_server_info_from_db (s
, trusted_servers
, cert_db_path
);
2832 } // Server information is not cached
2836 // Filter the existing vector by keeping the information in common with
2837 // the trusted_server vector.
2838 keep_common_server_info (trusted_servers
, servers
);
2842 // Add the information, but not duplicates.
2843 add_server_info (trusted_servers
, servers
);
2848 get_or_keep_signing_server_info (
2849 systemtap_session
&s
,
2850 vector
<compile_server_info
> &servers
,
2854 // If we're filtering the list and it's already empty, then
2855 // there's nothing to do.
2856 if (keep
&& servers
.empty ())
2859 // We only need to obtain this once per session. This is a good thing(tm)
2860 // since obtaining this information is expensive.
2861 vector
<compile_server_info
>& signing_servers
= cscache(s
)->signing_servers
;
2862 if (signing_servers
.empty ())
2864 // Maintain an empty entry to indicate that this search has been
2865 // performed, in case the search comes up empty.
2866 signing_servers
.push_back (compile_server_info ());
2868 // For all users, check the global database.
2869 string cert_db_path
= signing_cert_db_path ();
2870 get_server_info_from_db (s
, signing_servers
, cert_db_path
);
2871 } // Server information is not cached
2875 // Filter the existing vector by keeping the information in common with
2876 // the signing_server vector.
2877 keep_common_server_info (signing_servers
, servers
);
2881 // Add the information, but not duplicates.
2882 add_server_info (signing_servers
, servers
);
2888 get_or_keep_compatible_server_info (
2889 systemtap_session
&s
,
2890 vector
<compile_server_info
> &servers
,
2895 // If we're filtering the list and it's already empty, then
2896 // there's nothing to do.
2897 if (keep
&& servers
.empty ())
2900 // Remove entries for servers incompatible with the host environment
2901 // from the given list of servers.
2902 // A compatible server compiles for the kernel release and architecture
2903 // of the host environment.
2905 // Compatibility can only be determined for online servers. So, augment
2906 // and filter the information we have with information for online servers.
2907 vector
<compile_server_info
> online_servers
;
2908 get_or_keep_online_server_info (s
, online_servers
, false/*keep*/);
2910 keep_common_server_info (online_servers
, servers
);
2912 add_server_info (online_servers
, servers
);
2914 // Now look to see which ones are compatible.
2915 // The vector can change size as we go, so be careful!!
2916 for (unsigned i
= 0; i
< servers
.size (); /**/)
2918 // Retain empty entries.
2919 assert (! servers
[i
].empty ());
2921 // Check the target of the server.
2922 if (servers
[i
].sysinfo
!= s
.kernel_release
+ " " + s
.architecture
)
2924 // Target platform mismatch.
2925 servers
.erase (servers
.begin () + i
);
2929 // The server is compatible. Leave it in the list.
2932 #else // ! HAVE_AVAHI
2933 // Without Avahi, we can't obtain the target platform of the server.
2936 clog
<< _("Unable to detect server compatibility without avahi") << endl
;
2943 keep_server_info_with_cert_and_port (
2944 systemtap_session
&,
2945 const compile_server_info
&server
,
2946 vector
<compile_server_info
> &servers
2949 assert (! server
.certinfo
.empty ());
2951 // Search the list of servers for ones matching the
2952 // serial number specified.
2953 // The vector can change size as we go, so be careful!!
2954 for (unsigned i
= 0; i
< servers
.size (); /**/)
2956 // Retain empty entries.
2957 if (servers
[i
].empty ())
2962 if (servers
[i
].certinfo
== server
.certinfo
&&
2963 (servers
[i
].port() == 0 || server
.port() == 0 ||
2964 servers
[i
].port() == server
.port()))
2966 // If the server is not online, then use the specified
2968 if (servers
[i
].port() == 0)
2969 servers
[i
].setPort (server
.port());
2973 // The item does not match. Delete it.
2974 servers
.erase (servers
.begin () + i
);
2978 // Obtain missing host name or ip address, if any. Return 0 on success.
2982 compile_server_info
&server
,
2983 vector
<compile_server_info
> &resolved_servers
2986 // The server's host_name member is a string containing either a host name or an ip address.
2987 // Either is acceptable for lookup.
2988 const char *lookup_name
= server
.host_name
.c_str();
2989 struct addrinfo hints
;
2990 memset(& hints
, 0, sizeof (hints
));
2991 hints
.ai_family
= AF_UNSPEC
; // AF_INET or AF_INET6 to force version
2992 struct addrinfo
*addr_info
;
2993 int rc
= getaddrinfo (lookup_name
, NULL
, & hints
, & addr_info
);
2995 // Failure to resolve will result in an appropriate message later, if other methods fail.
2998 // At a minimum, return the information we were given.
2999 add_server_info (server
, resolved_servers
);
3003 // Loop over the results collecting information.
3005 for (const struct addrinfo
*ai
= addr_info
; ai
!= NULL
; ai
= ai
->ai_next
)
3007 // Start with the info we were given.
3008 compile_server_info new_server
= server
;
3010 // We support IPv4 and IPv6, Ignore other protocols,
3011 if (ai
->ai_family
== AF_INET
)
3014 struct sockaddr_in
*ip
= (struct sockaddr_in
*)ai
->ai_addr
;
3015 new_server
.address
.inet
.family
= PR_AF_INET
;
3016 if (ip
->sin_port
!= 0)
3017 new_server
.address
.inet
.port
= ip
->sin_port
;
3018 new_server
.address
.inet
.ip
= ip
->sin_addr
.s_addr
;
3020 else if (ai
->ai_family
== AF_INET6
)
3023 struct sockaddr_in6
*ip
= (struct sockaddr_in6
*)ai
->ai_addr
;
3024 new_server
.address
.ipv6
.family
= PR_AF_INET6
;
3025 if (ip
->sin6_port
!= 0)
3026 new_server
.address
.ipv6
.port
= ip
->sin6_port
;
3027 new_server
.address
.ipv6
.scope_id
= ip
->sin6_scope_id
;
3028 copyAddress (new_server
.address
.ipv6
.ip
, ip
->sin6_addr
);
3033 // Try to obtain a host name. Otherwise, leave it empty.
3034 char hbuf
[NI_MAXHOST
];
3035 int status
= getnameinfo (ai
->ai_addr
, ai
->ai_addrlen
, hbuf
, sizeof (hbuf
), NULL
, 0,
3036 NI_NAMEREQD
| NI_IDN
);
3038 new_server
.host_name
= hbuf
;
3040 // Add the new resolved server to the list.
3041 add_server_info (new_server
, resolved_servers
);
3045 freeaddrinfo (addr_info
); // free the linked list
3049 // Avahi API Callbacks.
3050 //-----------------------------------------------------------------------
3051 struct browsing_context
{
3052 AvahiSimplePoll
*simple_poll
;
3053 AvahiClient
*client
;
3054 vector
<compile_server_info
> *servers
;
3058 extract_field_from_avahi_txt (const string
&label
, const string
&txt
)
3060 // Extract the requested field from the Avahi TXT.
3061 string prefix
= "\"" + label
;
3062 size_t ix
= txt
.find (prefix
);
3063 if (ix
== string::npos
)
3069 // This is the start of the field.
3070 string field
= txt
.substr (ix
+ prefix
.size ());
3072 // Find the end of the field.
3073 ix
= field
.find('"');
3074 if (ix
!= string::npos
)
3075 field
= field
.substr (0, ix
);
3081 void resolve_callback(
3082 AvahiServiceResolver
*r
,
3083 AvahiIfIndex interface
,
3084 AvahiProtocol protocol
,
3085 AvahiResolverEvent event
,
3089 const char *host_name
,
3090 const AvahiAddress
*address
,
3092 AvahiStringList
*txt
,
3093 AvahiLookupResultFlags
/*flags*/,
3094 AVAHI_GCC_UNUSED
void* userdata
)
3099 const browsing_context
*context
= (browsing_context
*)userdata
;
3100 vector
<compile_server_info
> *servers
= context
->servers
;
3102 // Called whenever a service has been resolved successfully or timed out.
3105 case AVAHI_RESOLVER_FAILURE
:
3106 clog
<< _F("Failed to resolve service '%s' of type '%s' in domain '%s': %s",
3108 avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r
)))) << endl
;
3111 case AVAHI_RESOLVER_FOUND
: {
3112 compile_server_info info
;
3114 // Decode the address.
3115 char a
[AVAHI_ADDRESS_STR_MAX
];
3116 avahi_address_snprint(a
, sizeof(a
), address
);
3117 prStatus
= PR_StringToNetAddr (a
, & info
.address
);
3118 if (prStatus
!= PR_SUCCESS
) {
3119 clog
<< _F("Invalid address '%s' from avahi", a
) << endl
;
3123 // We support both IPv4 and IPv6. Ignore other protocols.
3124 if (protocol
== AVAHI_PROTO_INET6
) {
3125 assert (info
.address
.ipv6
.family
== PR_AF_INET6
);
3126 info
.address
.ipv6
.port
= htons (port
);
3127 info
.address
.ipv6
.scope_id
= interface
;
3129 else if (protocol
== AVAHI_PROTO_INET
) {
3130 assert (info
.address
.inet
.family
== PR_AF_INET
);
3131 info
.address
.inet
.port
= htons (port
);
3136 // Save the host name.
3137 info
.host_name
= host_name
;
3139 // Save the text tags.
3140 char *t
= avahi_string_list_to_string(txt
);
3141 info
.sysinfo
= extract_field_from_avahi_txt ("sysinfo=", t
);
3142 info
.certinfo
= extract_field_from_avahi_txt ("certinfo=", t
);
3143 info
.version
= extract_field_from_avahi_txt ("version=", t
);
3144 if (info
.version
.empty ())
3145 info
.version
= "1.0"; // default version is 1.0
3148 // Add this server to the list of discovered servers.
3149 add_server_info (info
, *servers
);
3153 avahi_service_resolver_free(r
);
3157 void browse_callback(
3158 AvahiServiceBrowser
*b
,
3159 AvahiIfIndex interface
,
3160 AvahiProtocol protocol
,
3161 AvahiBrowserEvent event
,
3165 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags
,
3168 browsing_context
*context
= (browsing_context
*)userdata
;
3169 AvahiClient
*c
= context
->client
;
3170 AvahiSimplePoll
*simple_poll
= context
->simple_poll
;
3173 // Called whenever a new services becomes available on the LAN or is removed from the LAN.
3176 case AVAHI_BROWSER_FAILURE
:
3177 clog
<< _F("Avahi browse failed: %s",
3178 avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b
))))
3180 avahi_simple_poll_quit(simple_poll
);
3183 case AVAHI_BROWSER_NEW
:
3184 // We ignore the returned resolver object. In the callback
3185 // function we free it. If the server is terminated before
3186 // the callback function is called the server will free
3187 // the resolver for us.
3188 if (!(avahi_service_resolver_new(c
, interface
, protocol
, name
, type
, domain
,
3189 AVAHI_PROTO_UNSPEC
, (AvahiLookupFlags
)0, resolve_callback
, context
))) {
3190 clog
<< _F("Failed to resolve service '%s': %s",
3191 name
, avahi_strerror(avahi_client_errno(c
))) << endl
;
3195 case AVAHI_BROWSER_REMOVE
:
3196 case AVAHI_BROWSER_ALL_FOR_NOW
:
3197 case AVAHI_BROWSER_CACHE_EXHAUSTED
:
3203 void client_callback(AvahiClient
*c
, AvahiClientState state
, AVAHI_GCC_UNUSED
void * userdata
) {
3205 browsing_context
*context
= (browsing_context
*)userdata
;
3206 AvahiSimplePoll
*simple_poll
= context
->simple_poll
;
3208 // Called whenever the client or server state changes.
3210 if (state
== AVAHI_CLIENT_FAILURE
) {
3211 clog
<< _F("Avahi Server connection failure: %s", avahi_strerror(avahi_client_errno(c
))) << endl
;
3212 avahi_simple_poll_quit(simple_poll
);
3217 void timeout_callback(AVAHI_GCC_UNUSED AvahiTimeout
*e
, AVAHI_GCC_UNUSED
void *userdata
) {
3218 browsing_context
*context
= (browsing_context
*)userdata
;
3219 AvahiSimplePoll
*simple_poll
= context
->simple_poll
;
3220 avahi_simple_poll_quit(simple_poll
);
3222 #endif // HAVE_AVAHI
3225 get_or_keep_online_server_info (
3226 systemtap_session
&s
,
3227 vector
<compile_server_info
> &servers
,
3231 // If we're filtering the list and it's already empty, then
3232 // there's nothing to do.
3233 if (keep
&& servers
.empty ())
3236 // We only need to obtain this once per session. This is a good thing(tm)
3237 // since obtaining this information is expensive.
3238 vector
<compile_server_info
>& online_servers
= cscache(s
)->online_servers
;
3239 if (online_servers
.empty ())
3241 // Maintain an empty entry to indicate that this search has been
3242 // performed, in case the search comes up empty.
3243 online_servers
.push_back (compile_server_info ());
3245 // Must predeclare these due to jumping on error to fail:
3247 vector
<compile_server_info
> avahi_servers
;
3250 AvahiClient
*client
= NULL
;
3251 AvahiServiceBrowser
*sb
= NULL
;
3253 // Allocate main loop object.
3254 AvahiSimplePoll
*simple_poll
;
3255 if (!(simple_poll
= avahi_simple_poll_new()))
3257 clog
<< _("Failed to create Avahi simple poll object") << endl
;
3260 browsing_context context
;
3261 context
.simple_poll
= simple_poll
;
3262 context
.servers
= & avahi_servers
;
3264 // Allocate a new Avahi client
3266 client
= avahi_client_new (avahi_simple_poll_get (simple_poll
),
3267 (AvahiClientFlags
)0,
3268 client_callback
, & context
, & error
);
3270 // Check whether creating the client object succeeded.
3273 clog
<< _F("Failed to create Avahi client: %s",
3274 avahi_strerror(error
)) << endl
;
3277 context
.client
= client
;
3279 // Create the service browser.
3280 if (!(sb
= avahi_service_browser_new (client
, AVAHI_IF_UNSPEC
,
3281 AVAHI_PROTO_UNSPEC
, "_stap._tcp",
3282 NULL
, (AvahiLookupFlags
)0,
3283 browse_callback
, & context
)))
3285 clog
<< _F("Failed to create Avahi service browser: %s",
3286 avahi_strerror(avahi_client_errno(client
))) << endl
;
3290 // Timeout after 2 seconds.
3292 avahi_simple_poll_get(simple_poll
)->timeout_new(
3293 avahi_simple_poll_get(simple_poll
),
3294 avahi_elapse_time(&tv
, 1000*2, 0),
3298 // Run the main loop.
3299 avahi_simple_poll_loop(simple_poll
);
3301 // Resolve each server discovered, in case there are alternate ways to reach them
3302 // (e.g. localhost).
3303 limit
= avahi_servers
.size ();
3304 for (unsigned i
= 0; i
< limit
; ++i
)
3306 compile_server_info
&avahi_server
= avahi_servers
[i
];
3308 // Delete the domain, if it is '.local'
3309 string
&host_name
= avahi_server
.host_name
;
3310 string::size_type dot_index
= host_name
.find ('.');
3311 assert (dot_index
!= 0);
3312 string domain
= host_name
.substr (dot_index
+ 1);
3313 if (domain
== "local")
3314 host_name
= host_name
.substr (0, dot_index
);
3316 // Add it to the list of servers, unless it is duplicate.
3317 resolve_host (s
, avahi_server
, online_servers
);
3320 // Merge with the list of servers, as obtained by avahi.
3321 add_server_info (avahi_servers
, online_servers
);
3326 avahi_service_browser_free(sb
);
3329 avahi_client_free(client
);
3332 avahi_simple_poll_free(simple_poll
);
3333 #else // ! HAVE_AVAHI
3334 // Without Avahi, we can't detect online servers. Issue a warning.
3336 clog
<< _("Unable to detect online servers without avahi") << endl
;
3337 #endif // ! HAVE_AVAHI
3338 } // Server information is not cached.
3342 // Filter the existing vector by keeping the information in common with
3343 // the online_server vector.
3344 keep_common_server_info (online_servers
, servers
);
3348 // Add the information, but not duplicates.
3349 add_server_info (online_servers
, servers
);
3353 // Add server info to a list, avoiding duplicates. Merge information from
3354 // two duplicate items.
3357 const compile_server_info
&info
, vector
<compile_server_info
>& target
3364 for (vector
<compile_server_info
>::iterator i
= target
.begin ();
3370 // Duplicate. Merge the two items.
3371 merge_server_info (info
, *i
);
3376 target
.push_back (info
);
3379 // Add server info from one vector to another.
3382 const vector
<compile_server_info
> &source
,
3383 vector
<compile_server_info
> &target
3386 for (vector
<compile_server_info
>::const_iterator i
= source
.begin ();
3390 add_server_info (*i
, target
);
3394 // Filter the vector by keeping information in common with the item.
3396 keep_common_server_info (
3397 const compile_server_info
&info_to_keep
,
3398 vector
<compile_server_info
> &filtered_info
3401 assert (! info_to_keep
.empty ());
3403 // The vector may change size as we go. Be careful!!
3404 for (unsigned i
= 0; i
< filtered_info
.size (); /**/)
3406 // Retain empty entries.
3407 if (filtered_info
[i
].empty ())
3412 if (info_to_keep
== filtered_info
[i
])
3414 merge_server_info (info_to_keep
, filtered_info
[i
]);
3418 // The item does not match. Delete it.
3419 filtered_info
.erase (filtered_info
.begin () + i
);
3424 // Filter the second vector by keeping information in common with the first
3427 keep_common_server_info (
3428 const vector
<compile_server_info
> &info_to_keep
,
3429 vector
<compile_server_info
> &filtered_info
3432 // The vector may change size as we go. Be careful!!
3433 for (unsigned i
= 0; i
< filtered_info
.size (); /**/)
3435 // Retain empty entries.
3436 if (filtered_info
[i
].empty ())
3442 for (unsigned j
= 0; j
< info_to_keep
.size (); ++j
)
3444 if (filtered_info
[i
] == info_to_keep
[j
])
3446 merge_server_info (info_to_keep
[j
], filtered_info
[i
]);
3451 // If the item was not found. Delete it. Otherwise, advance to the next
3456 filtered_info
.erase (filtered_info
.begin () + i
);
3460 // Merge two compile server info items.
3463 const compile_server_info
&source
,
3464 compile_server_info
&target
3467 if (target
.host_name
.empty ())
3468 target
.host_name
= source
.host_name
;
3469 if (! target
.hasAddress ())
3470 target
.address
= source
.address
;
3471 if (target
.port() == 0)
3472 target
.setPort (source
.port());
3473 if (target
.sysinfo
.empty ())
3474 target
.sysinfo
= source
.sysinfo
;
3475 if (target
.version
.empty ())
3476 target
.version
= source
.version
;
3477 if (target
.certinfo
.empty ())
3478 target
.certinfo
= source
.certinfo
;
3481 #if 0 // not used right now
3482 // Merge compile server info from one item into a vector.
3485 const compile_server_info
&source
,
3486 vector
<compile_server_info
> &target
3489 for (vector
<compile_server_info
>::iterator i
= target
.begin ();
3494 merge_server_info (source
, *i
);
3498 // Merge compile server from one vector into another.
3501 const vector
<compile_server_info
> &source
,
3502 vector
<compile_server_info
> &target
3505 for (vector
<compile_server_info
>::const_iterator i
= source
.begin ();
3508 merge_server_info (*i
, target
);
3513 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */