2 Compile server client functions
3 Copyright (C) 2010-2014 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 #define MOK_PUBLIC_CERT_NAME "signing_key.x509"
78 static PRIPv6Addr
©Address (PRIPv6Addr
&PRin6
, const in6_addr
&in6
);
79 static PRNetAddr
©NetAddr (PRNetAddr
&x
, const PRNetAddr
&y
);
80 bool operator!= (const PRNetAddr
&x
, const PRNetAddr
&y
);
81 bool operator== (const PRNetAddr
&x
, const PRNetAddr
&y
);
85 nsscommon_error (const char *msg
, int logit
__attribute ((unused
)))
87 clog
<< msg
<< endl
<< flush
;
90 // Information about compile servers.
91 struct compile_server_info
93 compile_server_info () : port(0), fully_specified(false)
95 memset (& address
, 0, sizeof (address
));
101 bool fully_specified
;
105 vector
<string
> mok_fingerprints
;
109 return this->host_name
.empty () && ! this->hasAddress () && certinfo
.empty ();
111 bool hasAddress () const
113 return this->address
.raw
.family
!= 0;
115 unsigned short setAddressPort (unsigned short port
)
117 if (this->address
.raw
.family
== PR_AF_INET
)
118 return this->address
.inet
.port
= htons (port
);
119 if (this->address
.raw
.family
== PR_AF_INET6
)
120 return this->address
.ipv6
.port
= htons (port
);
124 bool isComplete () const
126 return this->hasAddress () && port
!= 0;
129 bool operator== (const compile_server_info
&that
) const
131 // If one item or the other has only a name, and possibly a port specified,
132 // then allow a match by name and port only. This is so that the user can specify
133 // names which are returned by avahi, but are not dns resolvable.
134 // Otherwise, we will ignore the host_name.
135 if ((! this->hasAddress() && this->version
.empty () &&
136 this->sysinfo
.empty () && this->certinfo
.empty ()) ||
137 (! that
.hasAddress() && that
.version
.empty () &&
138 that
.sysinfo
.empty () && that
.certinfo
.empty ()))
140 if (this->host_name
!= that
.host_name
)
144 // Compare the other fields only if they have both been set.
145 if (this->hasAddress() && that
.hasAddress() &&
146 this->address
!= that
.address
)
148 if (this->port
!= 0 && that
.port
!= 0 &&
149 this->port
!= that
.port
)
151 if (! this->version
.empty () && ! that
.version
.empty () &&
152 this->version
!= that
.version
)
154 if (! this->sysinfo
.empty () && ! that
.sysinfo
.empty () &&
155 this->sysinfo
!= that
.sysinfo
)
157 if (! this->certinfo
.empty () && ! that
.certinfo
.empty () &&
158 this->certinfo
!= that
.certinfo
)
160 if (! this->mok_fingerprints
.empty () && ! that
.mok_fingerprints
.empty ()
161 && this->mok_fingerprints
!= that
.mok_fingerprints
)
164 return true; // They are equal
167 // Used to sort servers by preference for order of contact. The preferred server is
168 // "less" than the other one.
169 bool operator< (const compile_server_info
&that
) const
171 // Prefer servers with a later (higher) version number.
172 cs_protocol_version
this_version (this->version
.c_str ());
173 cs_protocol_version
that_version (that
.version
.c_str ());
174 return that_version
< this_version
;
178 ostream
&operator<< (ostream
&s
, const compile_server_info
&i
);
179 ostream
&operator<< (ostream
&s
, const vector
<compile_server_info
> &v
);
182 preferred_order (vector
<compile_server_info
> &servers
)
184 // Sort the given list of servers into the preferred order for contacting.
185 // Don't bother if there are less than 2 servers in the list.
186 if (servers
.size () < 2)
189 // Sort the list using compile_server_info::operator<
190 sort (servers
.begin (), servers
.end ());
193 struct resolved_host
// see also PR16326, PR16342
197 resolved_host(string chost_name
, PRNetAddr caddress
):
198 host_name(chost_name
), address(caddress
) {}
201 struct compile_server_cache
203 vector
<compile_server_info
> default_servers
;
204 vector
<compile_server_info
> specified_servers
;
205 vector
<compile_server_info
> trusted_servers
;
206 vector
<compile_server_info
> signing_servers
;
207 vector
<compile_server_info
> online_servers
;
208 vector
<compile_server_info
> all_servers
;
209 map
<string
,vector
<resolved_host
> > resolved_hosts
;
212 // For filtering queries.
213 enum compile_server_properties
{
214 compile_server_all
= 0x1,
215 compile_server_trusted
= 0x2,
216 compile_server_online
= 0x4,
217 compile_server_compatible
= 0x8,
218 compile_server_signer
= 0x10,
219 compile_server_specified
= 0x20
223 static compile_server_cache
* cscache(systemtap_session
& s
);
224 static void query_server_status (systemtap_session
&s
, const string
&status_string
);
226 static void get_server_info (systemtap_session
&s
, int pmask
, vector
<compile_server_info
> &servers
);
227 static void get_all_server_info (systemtap_session
&s
, vector
<compile_server_info
> &servers
);
228 static void get_default_server_info (systemtap_session
&s
, vector
<compile_server_info
> &servers
);
229 static void get_specified_server_info (systemtap_session
&s
, vector
<compile_server_info
> &servers
, bool no_default
= false);
230 static void get_or_keep_online_server_info (systemtap_session
&s
, vector
<compile_server_info
> &servers
, bool keep
);
231 static void get_or_keep_trusted_server_info (systemtap_session
&s
, vector
<compile_server_info
> &servers
, bool keep
);
232 static void get_or_keep_signing_server_info (systemtap_session
&s
, vector
<compile_server_info
> &servers
, bool keep
);
233 static void get_or_keep_compatible_server_info (systemtap_session
&s
, vector
<compile_server_info
> &servers
, bool keep
);
234 static void keep_common_server_info (const compile_server_info
&info_to_keep
, vector
<compile_server_info
> &filtered_info
);
235 static void keep_common_server_info (const vector
<compile_server_info
> &info_to_keep
, vector
<compile_server_info
> &filtered_info
);
236 static void keep_server_info_with_cert_and_port (systemtap_session
&s
, const compile_server_info
&server
, vector
<compile_server_info
> &servers
);
238 static void add_server_info (const compile_server_info
&info
, vector
<compile_server_info
>& list
);
239 static void add_server_info (const vector
<compile_server_info
> &source
, vector
<compile_server_info
> &target
);
240 static void merge_server_info (const compile_server_info
&source
, compile_server_info
&target
);
241 #if 0 // not used right now
242 static void merge_server_info (const compile_server_info
&source
, vector
<compile_server_info
> &target
);
243 static void merge_server_info (const vector
<compile_server_info
> &source
, vector
<compile_server_info
> &target
);
245 static void resolve_host (systemtap_session
& s
, compile_server_info
&server
, vector
<compile_server_info
> &servers
);
247 /* Exit error codes */
249 #define GENERAL_ERROR 1
250 #define CA_CERT_INVALID_ERROR 2
251 #define SERVER_CERT_EXPIRED_ERROR 3
253 // -----------------------------------------------------
254 // NSS related code used by the compile server client
255 // -----------------------------------------------------
256 static void add_server_trust (systemtap_session
&s
, const string
&cert_db_path
, vector
<compile_server_info
> &server_list
);
257 static void revoke_server_trust (systemtap_session
&s
, const string
&cert_db_path
, const vector
<compile_server_info
> &server_list
);
258 static void get_server_info_from_db (systemtap_session
&s
, vector
<compile_server_info
> &servers
, const string
&cert_db_path
);
260 static string
global_client_cert_db_path () {
261 return SYSCONFDIR
"/systemtap/ssl/client";
265 private_ssl_cert_db_path ()
267 return local_client_cert_db_path ();
271 global_ssl_cert_db_path ()
273 return global_client_cert_db_path ();
277 signing_cert_db_path ()
279 return SYSCONFDIR
"/systemtap/staprun";
282 /* Connection state. */
283 typedef struct connectionState_t
285 const char *hostName
;
287 const char *infileName
;
288 const char *outfileName
;
289 const char *trustNewServerMode
;
292 #if 0 /* No client authorization */
294 myPasswd(PK11SlotInfo
*info
, PRBool retry
, void *arg
)
296 char * passwd
= NULL
;
298 if ( (!retry
) && arg
)
299 passwd
= PORT_Strdup((char *)arg
);
305 /* Add the server's certificate to our database of trusted servers. */
307 trustNewServer (CERTCertificate
*serverCert
)
310 CERTCertTrust
*trust
= NULL
;
311 PK11SlotInfo
*slot
= NULL
;
313 /* Import the certificate. */
314 slot
= PK11_GetInternalKeySlot();
315 const char *nickname
= server_cert_nickname ();
316 secStatus
= PK11_ImportCert(slot
, serverCert
, CK_INVALID_HANDLE
, nickname
, PR_FALSE
);
317 if (secStatus
!= SECSuccess
)
320 /* Make it a trusted peer. */
321 trust
= (CERTCertTrust
*)PORT_ZAlloc(sizeof(CERTCertTrust
));
324 secStatus
= SECFailure
;
328 secStatus
= CERT_DecodeTrustString(trust
, "P,P,P");
329 if (secStatus
!= SECSuccess
)
332 secStatus
= CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), serverCert
, trust
);
336 PK11_FreeSlot (slot
);
342 /* Called when the server certificate verification fails. This gives us
343 the chance to trust the server anyway and add the certificate to the
346 badCertHandler(void *arg
, PRFileDesc
*sslSocket
)
349 PRErrorCode errorNumber
;
350 CERTCertificate
*serverCert
= NULL
;
352 PRArenaPool
*tmpArena
= NULL
;
353 CERTGeneralName
*nameList
, *current
;
354 char *expected
= NULL
;
355 const connectionState_t
*connectionState
= (connectionState_t
*)arg
;
357 errorNumber
= PR_GetError ();
360 case SSL_ERROR_BAD_CERT_DOMAIN
:
361 /* Since we administer our own client-side databases of trustworthy
362 certificates, we don't need the domain name(s) on the certificate to
363 match. If the cert is in our database, then we can trust it.
364 If we know the expected domain name, then issue a warning but,
365 in any case, accept the certificate. */
366 secStatus
= SECSuccess
;
368 expected
= SSL_RevealURL (sslSocket
);
369 if (expected
== NULL
|| *expected
== '\0')
372 fprintf (stderr
, STAP_CSC_01
, expected
);
374 /* List the DNS names from the server cert as part of the warning.
375 First, find the alt-name extension on the certificate. */
376 subAltName
.data
= NULL
;
377 serverCert
= SSL_PeerCertificate (sslSocket
);
378 secStatus
= CERT_FindCertExtension (serverCert
,
379 SEC_OID_X509_SUBJECT_ALT_NAME
,
381 if (secStatus
!= SECSuccess
|| ! subAltName
.data
)
383 fprintf (stderr
, _("Unable to find alt name extension on the server certificate\n"));
384 secStatus
= SECSuccess
; /* Not a fatal error */
388 // Now, decode the extension.
389 tmpArena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
392 fprintf (stderr
, _("Out of memory\n"));
393 SECITEM_FreeItem(& subAltName
, PR_FALSE
);
394 secStatus
= SECSuccess
; /* Not a fatal error here */
397 nameList
= CERT_DecodeAltNameExtension (tmpArena
, & subAltName
);
398 SECITEM_FreeItem(& subAltName
, PR_FALSE
);
401 fprintf (stderr
, _("Unable to decode alt name extension on server certificate\n"));
402 secStatus
= SECSuccess
; /* Not a fatal error */
406 /* List the DNS names from the server cert as part of the warning.
407 The names are in a circular list. */
411 /* Make sure this is a DNS name. */
412 if (current
->type
== certDNSName
)
414 fprintf (stderr
, " %.*s\n",
415 (int)current
->name
.other
.len
, current
->name
.other
.data
);
417 current
= CERT_GetNextGeneralName (current
);
419 while (current
!= nameList
);
423 case SEC_ERROR_CA_CERT_INVALID
:
424 /* The server's certificate is not trusted. Should we trust it? */
425 secStatus
= SECFailure
; /* Do not trust by default. */
426 if (! connectionState
->trustNewServerMode
)
429 /* Trust it for this session only? */
430 if (strcmp (connectionState
->trustNewServerMode
, "session") == 0)
432 secStatus
= SECSuccess
;
436 /* Trust it permanently? */
437 if (strcmp (connectionState
->trustNewServerMode
, "permanent") == 0)
439 /* The user wants to trust this server. Get the server's certificate so
440 and add it to our database. */
441 serverCert
= SSL_PeerCertificate (sslSocket
);
442 if (serverCert
!= NULL
)
444 secStatus
= trustNewServer (serverCert
);
449 secStatus
= SECFailure
; /* Do not trust this server */
454 PORT_Free (expected
);
456 PORT_FreeArena (tmpArena
, PR_FALSE
);
458 if (serverCert
!= NULL
)
460 CERT_DestroyCertificate (serverCert
);
467 setupSSLSocket (connectionState_t
*connectionState
)
469 PRFileDesc
*tcpSocket
;
470 PRFileDesc
*sslSocket
;
471 PRSocketOptionData socketOption
;
475 tcpSocket
= PR_OpenTCPSocket(connectionState
->addr
.raw
.family
);
476 if (tcpSocket
== NULL
)
479 /* Make the socket blocking. */
480 socketOption
.option
= PR_SockOpt_Nonblocking
;
481 socketOption
.value
.non_blocking
= PR_FALSE
;
483 prStatus
= PR_SetSocketOption(tcpSocket
, &socketOption
);
484 if (prStatus
!= PR_SUCCESS
)
487 /* Import the socket into the SSL layer. */
488 sslSocket
= SSL_ImportFD(NULL
, tcpSocket
);
492 /* Set configuration options. */
493 secStatus
= SSL_OptionSet(sslSocket
, SSL_SECURITY
, PR_TRUE
);
494 if (secStatus
!= SECSuccess
)
497 secStatus
= SSL_OptionSet(sslSocket
, SSL_HANDSHAKE_AS_CLIENT
, PR_TRUE
);
498 if (secStatus
!= SECSuccess
)
501 /* Set SSL callback routines. */
502 #if 0 /* no client authentication */
503 secStatus
= SSL_GetClientAuthDataHook(sslSocket
,
504 (SSLGetClientAuthData
)myGetClientAuthData
,
505 (void *)certNickname
);
506 if (secStatus
!= SECSuccess
)
509 #if 0 /* Use the default */
510 secStatus
= SSL_AuthCertificateHook(sslSocket
,
511 (SSLAuthCertificate
)myAuthCertificate
,
512 (void *)CERT_GetDefaultCertDB());
513 if (secStatus
!= SECSuccess
)
517 secStatus
= SSL_BadCertHook(sslSocket
, (SSLBadCertHandler
)badCertHandler
,
519 if (secStatus
!= SECSuccess
)
522 #if 0 /* No handshake callback */
523 secStatus
= SSL_HandshakeCallback(sslSocket
, myHandshakeCallback
, NULL
);
524 if (secStatus
!= SECSuccess
)
538 handle_connection (PRFileDesc
*sslSocket
, connectionState_t
*connectionState
)
543 PRFileDesc
*local_file_fd
;
545 SECStatus secStatus
= SECSuccess
;
547 #define READ_BUFFER_SIZE (60 * 1024)
549 /* If we don't have both the input and output file names, then we're
550 contacting this server only in order to establish trust. In this case send
551 0 as the file size and exit. */
552 if (! connectionState
->infileName
|| ! connectionState
->outfileName
)
554 numBytes
= htonl ((PRInt32
)0);
555 numBytes
= PR_Write (sslSocket
, & numBytes
, sizeof (numBytes
));
561 /* read and send the data. */
562 /* Try to open the local file named.
563 * If successful, then write it to the server
565 prStatus
= PR_GetFileInfo(connectionState
->infileName
, &info
);
566 if (prStatus
!= PR_SUCCESS
||
567 info
.type
!= PR_FILE_FILE
||
570 fprintf (stderr
, STAP_CSC_02
,
571 connectionState
->infileName
);
575 local_file_fd
= PR_Open(connectionState
->infileName
, PR_RDONLY
, 0);
576 if (local_file_fd
== NULL
)
578 fprintf (stderr
, STAP_CSC_03
, connectionState
->infileName
);
582 /* Send the file size first, so the server knows when it has the entire file. */
583 numBytes
= htonl ((PRInt32
)info
.size
);
584 numBytes
= PR_Write(sslSocket
, & numBytes
, sizeof (numBytes
));
587 PR_Close(local_file_fd
);
591 /* Transmit the local file across the socket. */
592 numBytes
= PR_TransmitFile(sslSocket
, local_file_fd
,
594 PR_TRANSMITFILE_KEEP_OPEN
,
595 PR_INTERVAL_NO_TIMEOUT
);
598 PR_Close(local_file_fd
);
602 PR_Close(local_file_fd
);
605 readBuffer
= (char *)PORT_Alloc(READ_BUFFER_SIZE
);
607 fprintf (stderr
, _("Out of memory\n"));
611 local_file_fd
= PR_Open(connectionState
->outfileName
, PR_WRONLY
| PR_CREATE_FILE
| PR_TRUNCATE
,
612 PR_IRUSR
| PR_IWUSR
| PR_IRGRP
| PR_IWGRP
| PR_IROTH
);
613 if (local_file_fd
== NULL
)
615 fprintf (stderr
, STAP_CSC_04
, connectionState
->outfileName
);
620 // No need for PR_Read_Complete here, since we're already managing multiple
621 // reads to a fixed size buffer.
622 numBytes
= PR_Read (sslSocket
, readBuffer
, READ_BUFFER_SIZE
);
628 secStatus
= SECFailure
;
632 /* Write to output file */
633 numBytes
= PR_Write(local_file_fd
, readBuffer
, numBytes
);
636 fprintf (stderr
, STAP_CSC_05
, connectionState
->outfileName
);
637 secStatus
= SECFailure
;
643 PR_Close(local_file_fd
);
645 /* Caller closes the socket. */
649 /* make the connection.
652 do_connect (connectionState_t
*connectionState
)
654 PRFileDesc
*sslSocket
;
658 secStatus
= SECSuccess
;
660 /* Set up SSL secure socket. */
661 sslSocket
= setupSSLSocket (connectionState
);
662 if (sslSocket
== NULL
)
665 #if 0 /* no client authentication */
666 secStatus
= SSL_SetPKCS11PinArg(sslSocket
, password
);
667 if (secStatus
!= SECSuccess
)
671 secStatus
= SSL_SetURL(sslSocket
, connectionState
->hostName
);
672 if (secStatus
!= SECSuccess
)
675 prStatus
= PR_Connect(sslSocket
, & connectionState
->addr
, PR_INTERVAL_NO_TIMEOUT
);
676 if (prStatus
!= PR_SUCCESS
)
678 secStatus
= SECFailure
;
682 /* Established SSL connection, ready to send data. */
683 secStatus
= SSL_ResetHandshake(sslSocket
, /* asServer */ PR_FALSE
);
684 if (secStatus
!= SECSuccess
)
687 /* This is normally done automatically on the first I/O operation,
688 but doing it here catches any authentication problems early. */
689 secStatus
= SSL_ForceHandshake(sslSocket
);
690 if (secStatus
!= SECSuccess
)
693 // Connect to the server and make the request.
694 secStatus
= handle_connection(sslSocket
, connectionState
);
697 prStatus
= PR_Close(sslSocket
);
702 isIPv6LinkLocal (const PRNetAddr
&address
)
704 // Link-local addresses are members of the address block fe80::
705 if (address
.raw
.family
== PR_AF_INET6
&&
706 address
.ipv6
.ip
.pr_s6_addr
[0] == 0xfe && address
.ipv6
.ip
.pr_s6_addr
[1] == 0x80)
712 client_connect (const compile_server_info
&server
,
713 const char* infileName
, const char* outfileName
,
714 const char* trustNewServer
)
717 PRErrorCode errorNumber
;
719 int errCode
= GENERAL_ERROR
;
720 struct connectionState_t connectionState
;
722 // Set up a connection state for use by NSS error callbacks.
723 memset (& connectionState
, 0, sizeof (connectionState
));
724 connectionState
.hostName
= server
.host_name
.c_str ();
725 connectionState
.addr
= server
.address
;
726 connectionState
.infileName
= infileName
;
727 connectionState
.outfileName
= outfileName
;
728 connectionState
.trustNewServerMode
= trustNewServer
;
730 /* Some errors (see below) represent a situation in which trying again
731 should succeed. However, don't try forever. */
732 for (attempt
= 0; attempt
< 5; ++attempt
)
734 secStatus
= do_connect (& connectionState
);
735 if (secStatus
== SECSuccess
)
738 errorNumber
= PR_GetError ();
741 case PR_CONNECT_RESET_ERROR
:
742 /* Server was not ready. */
744 break; /* Try again */
745 case SEC_ERROR_EXPIRED_CERTIFICATE
:
746 /* The server's certificate has expired. It should
747 generate a new certificate. Return now and we'll try again. */
748 errCode
= SERVER_CERT_EXPIRED_ERROR
;
750 case SEC_ERROR_CA_CERT_INVALID
:
751 /* The server's certificate is not trusted. The exit code must
753 errCode
= CA_CERT_INVALID_ERROR
;
756 /* This error is fatal. */
765 compile_server_client::passes_0_4 ()
767 PROBE1(stap
, client__start
, &s
);
769 // arguments parsed; get down to business
770 if (s
.verbose
|| ! s
.auto_server_msgs
.empty ())
771 clog
<< _("Using a compile server.") << endl
;
773 struct tms tms_before
;
774 times (& tms_before
);
775 struct timeval tv_before
;
776 gettimeofday (&tv_before
, NULL
);
778 // Create the request package.
779 int rc
= initialize ();
780 assert_no_interrupts();
781 if (rc
!= 0) goto done
;
782 rc
= create_request ();
783 assert_no_interrupts();
784 if (rc
!= 0) goto done
;
785 rc
= package_request ();
786 assert_no_interrupts();
787 if (rc
!= 0) goto done
;
789 // Submit it to the server.
790 rc
= find_and_connect_to_server ();
791 assert_no_interrupts();
792 if (rc
!= 0) goto done
;
794 // Unpack and process the response.
795 rc
= unpack_response ();
796 assert_no_interrupts();
797 if (rc
!= 0) goto done
;
798 rc
= process_response ();
801 struct tms tms_after
;
803 unsigned _sc_clk_tck
= sysconf (_SC_CLK_TCK
);
804 struct timeval tv_after
;
805 gettimeofday (&tv_after
, NULL
);
807 #define TIMESPRINT "in " << \
808 (tms_after.tms_cutime + tms_after.tms_utime \
809 - tms_before.tms_cutime - tms_before.tms_utime) * 1000 / (_sc_clk_tck) << "usr/" \
810 << (tms_after.tms_cstime + tms_after.tms_stime \
811 - tms_before.tms_cstime - tms_before.tms_stime) * 1000 / (_sc_clk_tck) << "sys/" \
812 << ((tv_after.tv_sec - tv_before.tv_sec) * 1000 + \
813 ((long)tv_after.tv_usec - (long)tv_before.tv_usec) / 1000) << "real ms."
817 // Save the module, if necessary.
818 if (s
.last_pass
== 4)
819 s
.save_module
= true;
821 // Copy module to the current directory.
822 if (! pending_interrupts
)
826 string module_src_path
= s
.tmpdir
+ "/" + s
.module_filename();
827 string module_dest_path
= s
.module_filename();
828 copy_file (module_src_path
, module_dest_path
, s
.verbose
>= 3);
829 // Also copy the module signature, it it exists.
830 module_src_path
+= ".sgn";
831 if (file_exists (module_src_path
))
833 module_dest_path
+= ".sgn";
834 copy_file(module_src_path
, module_dest_path
, s
.verbose
>= 3);
837 // Print the name of the module
838 if (s
.last_pass
== 4)
840 cout
<< s
.module_filename() << endl
;
845 // syntax errors, if any, are already printed
848 string ws
= s
.winning_server
;
849 if (ws
== "") ws
= "?";
850 clog
<< _("Passes: via server ") << ws
<< " "
855 if (rc
&& !s
.dump_mode
)
857 clog
<< _("Passes: via server failed. Try again with another '-v' option.") << endl
;
860 PROBE1(stap
, client__end
, &s
);
865 // Initialize a client/server session.
867 compile_server_client::initialize ()
871 // Initialize session state
874 // Private location for server certificates.
875 private_ssl_dbs
.push_back (private_ssl_cert_db_path ());
877 // Additional public location.
878 public_ssl_dbs
.push_back (global_ssl_cert_db_path ());
880 // Create a temporary directory to package things in.
881 client_tmpdir
= s
.tmpdir
+ "/client";
882 rc
= create_dir (client_tmpdir
.c_str ());
885 const char* e
= strerror (errno
);
886 clog
<< _("ERROR: cannot create temporary directory (\"")
887 << client_tmpdir
<< "\"): " << e
894 // Create the request package.
896 compile_server_client::create_request ()
898 // Add the current protocol version.
899 int rc
= write_to_file (client_tmpdir
+ "/version", CURRENT_CS_PROTOCOL_VERSION
);
903 // Add the script file or script option
904 if (s
.script_file
!= "")
906 if (s
.script_file
== "-")
908 // Copy the script from stdin
909 string packaged_script_dir
= client_tmpdir
+ "/script";
910 rc
= create_dir (packaged_script_dir
.c_str ());
913 const char* e
= strerror (errno
);
914 clog
<< _("ERROR: cannot create temporary directory ")
915 << packaged_script_dir
<< ": " << e
919 rc
= ! copy_file("/dev/stdin", packaged_script_dir
+ "/-");
923 // Name the script in the packaged arguments.
924 rc
= add_package_arg ("script/-");
930 // Add the script to our package. This will also name the script
931 // in the packaged arguments.
932 rc
= include_file_or_directory ("script", s
.script_file
);
938 // Add -I paths. Skip the default directory.
939 if (s
.include_arg_start
!= -1)
941 unsigned limit
= s
.include_path
.size ();
942 for (unsigned i
= s
.include_arg_start
; i
< limit
; ++i
)
944 rc
= add_package_arg ("-I");
947 rc
= include_file_or_directory ("tapset", s
.include_path
[i
]);
953 // Add other options.
954 rc
= add_package_args ();
958 // Add the sysinfo file
959 string sysinfo
= "sysinfo: " + s
.kernel_release
+ " " + s
.architecture
;
960 rc
= write_to_file (client_tmpdir
+ "/sysinfo", sysinfo
);
964 // Add localization data
965 rc
= add_localization_variables();
967 // Add the machine owner key (MOK) fingerprints file, if needed.
968 if (! s
.mok_fingerprints
.empty())
970 ostringstream fingerprints
;
971 vector
<string
>::const_iterator it
;
972 for (it
= s
.mok_fingerprints
.begin(); it
!= s
.mok_fingerprints
.end();
974 fingerprints
<< *it
<< endl
;
976 rc
= write_to_file(client_tmpdir
+ "/mok_fingerprints",
985 // Add the arguments specified on the command line to the server request
986 // package, as appropriate.
988 compile_server_client::add_package_args ()
990 // stap arguments to be passed to the server.
992 unsigned limit
= s
.server_args
.size();
993 for (unsigned i
= 0; i
< limit
; ++i
)
995 rc
= add_package_arg (s
.server_args
[i
]);
1000 // Script arguments.
1001 limit
= s
.args
.size();
1003 rc
= add_package_arg ("--");
1006 for (unsigned i
= 0; i
< limit
; ++i
)
1008 rc
= add_package_arg (s
.args
[i
]);
1017 compile_server_client::add_package_arg (const string
&arg
)
1020 ostringstream fname
;
1021 fname
<< client_tmpdir
<< "/argv" << ++argc
;
1022 write_to_file (fname
.str (), arg
); // NB: No terminating newline
1026 // Symbolically link the given file or directory into the client's temp
1027 // directory under the given subdirectory.
1029 compile_server_client::include_file_or_directory (
1030 const string
&subdir
, const string
&path
1033 // Must predeclare these because we do use 'goto done' to
1034 // exit from error situations.
1035 vector
<string
> components
;
1039 // Canonicalize the given path and remove the leading /.
1041 char *cpath
= canonicalize_file_name (path
.c_str ());
1044 // It can not be canonicalized. Use the name relative to
1045 // the current working directory and let the server deal with it.
1047 if (getcwd (cwd
, sizeof (cwd
)) == NULL
)
1053 rpath
= string (cwd
) + "/" + path
;
1057 // It can be canonicalized. Use the canonicalized name and add this
1058 // file or directory to the request package.
1062 // Including / would require special handling in the code below and
1063 // is a bad idea anyway. Let's not allow it.
1067 clog
<< _F("%s resolves to %s\n", path
.c_str (), rpath
.c_str ());
1068 clog
<< _F("Unable to send %s to the server\n", path
.c_str ());
1072 // First create the requested subdirectory.
1073 name
= client_tmpdir
+ "/" + subdir
;
1074 rc
= create_dir (name
.c_str ());
1077 // Now create each component of the path within the sub directory.
1078 assert (rpath
[0] == '/');
1079 tokenize (rpath
.substr (1), components
, "/");
1080 assert (components
.size () >= 1);
1082 for (i
= 0; i
< components
.size() - 1; ++i
)
1084 if (components
[i
].empty ())
1085 continue; // embedded '//'
1086 name
+= "/" + components
[i
];
1087 rc
= create_dir (name
.c_str ());
1091 // Now make a symbolic link to the actual file or directory.
1092 assert (i
== components
.size () - 1);
1093 name
+= "/" + components
[i
];
1094 rc
= symlink (rpath
.c_str (), name
.c_str ());
1098 // Name this file or directory in the packaged arguments.
1099 rc
= add_package_arg (subdir
+ "/" + rpath
.substr (1));
1104 const char* e
= strerror (errno
);
1105 clog
<< "ERROR: unable to add "
1107 << " to temp directory as "
1108 << name
<< ": " << e
1114 // Add the localization variables to the server request
1117 compile_server_client::add_localization_variables()
1123 const set
<string
> &locVars
= localization_variables();
1124 set
<string
>::iterator it
;
1126 /* Note: We don't have to check for the contents of the environment
1127 * variables here, since they will be checked extensively on the
1130 for (it
= locVars
.begin(); it
!= locVars
.end(); it
++)
1132 char* var
= getenv((*it
).c_str());
1134 envVar
+= *it
+ "=" + (string
)var
+ "\n";
1136 fname
= client_tmpdir
+ "/locale";
1137 rc
= write_to_file(fname
, envVar
);
1141 // Package the client's temp directory into a form suitable for sending to the
1144 compile_server_client::package_request ()
1146 // Package up the temporary directory into a zip file.
1147 client_zipfile
= client_tmpdir
+ ".zip";
1148 string cmd
= "cd " + cmdstr_quoted(client_tmpdir
) + " && zip -qr "
1149 + cmdstr_quoted(client_zipfile
) + " *";
1150 vector
<string
> sh_cmd
;
1151 sh_cmd
.push_back("sh");
1152 sh_cmd
.push_back("-c");
1153 sh_cmd
.push_back(cmd
);
1154 int rc
= stap_system (s
.verbose
, sh_cmd
);
1159 compile_server_client::find_and_connect_to_server ()
1161 // Accumulate info on the specified servers.
1162 vector
<compile_server_info
> specified_servers
;
1163 get_specified_server_info (s
, specified_servers
);
1165 // Examine the specified servers to make sure that each has been resolved
1166 // with a host name, ip address and port. If not, try to obtain this
1167 // information by examining online servers.
1168 vector
<compile_server_info
> server_list
;
1169 for (vector
<compile_server_info
>::const_iterator i
= specified_servers
.begin ();
1170 i
!= specified_servers
.end ();
1173 // If we have an ip address and were given a port number, then just use the one we've
1174 // been given. Otherwise, check for matching compatible online servers and try their
1175 // ip addresses and ports.
1176 if (i
->hasAddress() && i
->fully_specified
)
1177 add_server_info (*i
, server_list
);
1180 // Obtain a list of online servers.
1181 vector
<compile_server_info
> online_servers
;
1182 get_or_keep_online_server_info (s
, online_servers
, false/*keep*/);
1184 // If no specific server (port) has been specified,
1185 // then we'll need the servers to be
1186 // compatible and possibly trusted as signers as well.
1187 if (! i
->fully_specified
)
1189 get_or_keep_compatible_server_info (s
, online_servers
, true/*keep*/);
1190 if (! pr_contains (s
.privilege
, pr_stapdev
))
1191 get_or_keep_signing_server_info (s
, online_servers
, true/*keep*/);
1194 // Keep the ones (if any) which match our server.
1195 keep_common_server_info (*i
, online_servers
);
1197 // Add these servers (if any) to the server list.
1198 add_server_info (online_servers
, server_list
);
1202 // Did we identify any potential servers?
1203 unsigned limit
= server_list
.size ();
1206 clog
<< _("Unable to find a suitable compile server. [man stap-server]") << endl
;
1208 // Try to explain why.
1209 vector
<compile_server_info
> online_servers
;
1210 get_or_keep_online_server_info (s
, online_servers
, false/*keep*/);
1211 if (online_servers
.empty ())
1212 clog
<< _("No servers online to select from.") << endl
;
1215 clog
<< _("The following servers are online:") << endl
;
1216 clog
<< online_servers
;
1217 if (! specified_servers
.empty ())
1219 clog
<< _("The following servers were requested:") << endl
;
1220 clog
<< specified_servers
;
1224 string criteria
= "online,trusted,compatible";
1225 if (! pr_contains (s
.privilege
, pr_stapdev
))
1226 criteria
+= ",signer";
1227 clog
<< _F("No servers matched the selection criteria of %s.", criteria
.c_str())
1234 // Sort the list of servers into a preferred order.
1235 preferred_order (server_list
);
1237 // Now try each of the identified servers in turn.
1238 int rc
= compile_using_server (server_list
);
1240 return 0; // success!
1242 // If the error was that a server's cert was expired, try again. This is because the server
1243 // should generate a new cert which may be automatically trusted by us if it is our server.
1244 // Give the server a chance to do this before retrying.
1245 if (rc
== SERVER_CERT_EXPIRED_ERROR
)
1248 clog
<< _("The server's certificate was expired. Trying again") << endl
<< flush
;
1250 rc
= compile_using_server (server_list
);
1252 return 0; // success!
1255 // We were unable to use any available server
1256 clog
<< _("Unable to connect to a server.") << endl
;
1259 // This information is redundant at higher verbosity levels.
1260 clog
<< _("The following servers were tried:") << endl
;
1261 clog
<< server_list
;
1263 return 1; // Failure
1267 compile_server_client::compile_using_server (
1268 vector
<compile_server_info
> &servers
1271 // Make sure NSPR is initialized. Must be done before NSS is initialized
1274 // Attempt connection using each of the available client certificate
1275 // databases. Assume the server certificate is invalid until proven otherwise.
1276 PR_SetError (SEC_ERROR_CA_CERT_INVALID
, 0);
1277 vector
<string
> dbs
= private_ssl_dbs
;
1278 vector
<string
>::iterator i
= dbs
.end();
1279 dbs
.insert (i
, public_ssl_dbs
.begin (), public_ssl_dbs
.end ());
1280 int rc
= GENERAL_ERROR
; // assume failure
1281 bool serverCertExpired
= false;
1282 for (i
= dbs
.begin (); i
!= dbs
.end (); ++i
)
1284 // Make sure the database directory exists. It is not an error if it
1286 if (! file_exists (*i
))
1289 #if 0 // no client authentication for now.
1290 // Set our password function callback.
1291 PK11_SetPasswordFunc (myPasswd
);
1294 // Initialize the NSS libraries.
1295 const char *cert_dir
= i
->c_str ();
1296 SECStatus secStatus
= nssInit (cert_dir
);
1297 if (secStatus
!= SECSuccess
)
1299 // Message already issued.
1300 continue; // try next database
1303 // Enable all cipher suites.
1304 // SSL_ClearSessionCache is required for the new settings to take effect.
1305 /* Some NSS versions don't do this correctly in NSS_SetDomesticPolicy. */
1307 const PRUint16
*cipher
;
1308 for (cipher
= SSL_GetImplementedCiphers(); *cipher
!= 0; ++cipher
)
1309 SSL_CipherPolicySet(*cipher
, SSL_ALLOWED
);
1311 SSL_ClearSessionCache ();
1313 server_zipfile
= s
.tmpdir
+ "/server.zip";
1315 // Try each server in turn.
1316 for (vector
<compile_server_info
>::iterator j
= servers
.begin ();
1317 j
!= servers
.end ();
1320 // At a minimum we need an ip_address along with a port
1321 // number in order to contact the server.
1322 if (! j
->hasAddress() || j
->port
== 0)
1324 // Set the port within the address.
1325 j
->setAddressPort (j
->port
);
1328 clog
<< _F("Attempting SSL connection with %s\n"
1329 " using certificates from the database in %s\n",
1330 lex_cast(*j
).c_str(), cert_dir
);
1332 rc
= client_connect (*j
, client_zipfile
.c_str(), server_zipfile
.c_str (),
1333 NULL
/*trustNewServer_p*/);
1336 s
.winning_server
= lex_cast(*j
);
1340 // Server cert has expired. Try other servers and/or databases, but take note because
1341 // server should generate a new certificate. If no other servers succeed, we'll try again
1342 // in case the new cert works.
1343 if (rc
== SERVER_CERT_EXPIRED_ERROR
)
1345 serverCertExpired
= true;
1351 clog
<< _(" Unable to connect: ");
1353 // Additional information: if the address is IPv6 and is link-local, then it must
1355 if (isIPv6LinkLocal (j
->address
) && j
->address
.ipv6
.scope_id
== 0)
1357 clog
<< _(" The address is an IPv6 link-local address with no scope specifier.")
1363 // SSL_ClearSessionCache is required before shutdown for client applications.
1364 SSL_ClearSessionCache ();
1365 nssCleanup (cert_dir
);
1367 if (rc
== SECSuccess
)
1371 // Indicate whether a server cert was expired, so we can try again, if desired.
1374 if (serverCertExpired
)
1375 rc
= SERVER_CERT_EXPIRED_ERROR
;
1382 compile_server_client::unpack_response ()
1384 // Unzip the response package.
1385 server_tmpdir
= s
.tmpdir
+ "/server";
1387 cmd
.push_back("unzip");
1388 cmd
.push_back("-qd");
1389 cmd
.push_back(server_tmpdir
);
1390 cmd
.push_back(server_zipfile
);
1391 int rc
= stap_system (s
.verbose
, cmd
);
1394 clog
<< _F("Unable to unzip the server response '%s'\n", server_zipfile
.c_str());
1398 // Determine the server protocol version.
1399 string filename
= server_tmpdir
+ "/version";
1400 if (file_exists (filename
))
1401 ::read_from_file (filename
, server_version
);
1403 // Warn about the shortcomings of this server, if it is down level.
1404 show_server_compatibility ();
1406 // If the server's response contains a systemtap temp directory, move
1407 // its contents to our temp directory.
1409 string filespec
= server_tmpdir
+ "/stap??????";
1411 clog
<< _F("Searching \"%s\"\n", filespec
.c_str());
1412 int r
= glob(filespec
.c_str (), 0, NULL
, & globbuf
);
1413 if (r
!= GLOB_NOSPACE
&& r
!= GLOB_ABORTED
&& r
!= GLOB_NOMATCH
)
1415 if (globbuf
.gl_pathc
> 1)
1417 clog
<< _("Incorrect number of files in server response") << endl
;
1422 assert (globbuf
.gl_pathc
== 1);
1423 string dirname
= globbuf
.gl_pathv
[0];
1425 clog
<< _(" found ") << dirname
<< endl
;
1427 filespec
= dirname
+ "/*";
1429 clog
<< _F("Searching \"%s\"\n", filespec
.c_str());
1430 int r
= glob(filespec
.c_str (), GLOB_PERIOD
, NULL
, & globbuf
);
1431 if (r
!= GLOB_NOSPACE
&& r
!= GLOB_ABORTED
&& r
!= GLOB_NOMATCH
)
1433 unsigned prefix_len
= dirname
.size () + 1;
1434 for (unsigned i
= 0; i
< globbuf
.gl_pathc
; ++i
)
1436 string oldname
= globbuf
.gl_pathv
[i
];
1437 if (oldname
.substr (oldname
.size () - 2) == "/." ||
1438 oldname
.substr (oldname
.size () - 3) == "/..")
1440 string newname
= s
.tmpdir
+ "/" + oldname
.substr (prefix_len
);
1442 clog
<< _F(" found %s -- linking from %s", oldname
.c_str(), newname
.c_str());
1443 rc
= symlink (oldname
.c_str (), newname
.c_str ());
1446 clog
<< _F("Unable to link '%s' to '%s':%s\n",
1447 oldname
.c_str(), newname
.c_str(), strerror(errno
));
1454 // If the server version is less that 1.6, remove the output line due to the synthetic
1455 // server-side -k. Look for a message containing the name of the temporary directory.
1456 // We can look for the English message since server versions before 1.6 do not support
1458 if (server_version
< "1.6")
1461 cmd
.push_back("sed");
1462 cmd
.push_back("-i");
1463 cmd
.push_back("/^Keeping temporary directory.*/ d");
1464 cmd
.push_back(server_tmpdir
+ "/stderr");
1465 stap_system (s
.verbose
, cmd
);
1468 // Remove the output line due to the synthetic server-side -p4
1470 cmd
.push_back("sed");
1471 cmd
.push_back("-i");
1472 cmd
.push_back("/^.*\\.ko$/ d");
1473 cmd
.push_back(server_tmpdir
+ "/stdout");
1474 stap_system (s
.verbose
, cmd
);
1477 globfree (& globbuf
);
1482 compile_server_client::process_response ()
1484 // Pick up the results of running stap on the server.
1485 string filename
= server_tmpdir
+ "/rc";
1487 int rc
= read_from_file (filename
, stap_rc
);
1492 if (s
.last_pass
>= 4)
1494 // The server should have returned a module.
1495 string filespec
= s
.tmpdir
+ "/*.ko";
1497 clog
<< _F("Searching \"%s\"\n", filespec
.c_str());
1500 int r
= glob(filespec
.c_str (), 0, NULL
, & globbuf
);
1501 if (r
!= GLOB_NOSPACE
&& r
!= GLOB_ABORTED
&& r
!= GLOB_NOMATCH
)
1503 if (globbuf
.gl_pathc
> 1)
1504 clog
<< _("Incorrect number of modules in server response") << endl
;
1507 assert (globbuf
.gl_pathc
== 1);
1508 string modname
= globbuf
.gl_pathv
[0];
1510 clog
<< _(" found ") << modname
<< endl
;
1512 // If a module name was not specified by the user, then set it to
1513 // be the one generated by the server.
1514 if (! s
.save_module
)
1516 vector
<string
> components
;
1517 tokenize (modname
, components
, "/");
1518 s
.module_name
= components
.back ();
1519 s
.module_name
.erase(s
.module_name
.size() - 3);
1522 // If a uprobes.ko module was returned, then make note of it.
1524 if (server_version
< "1.6")
1525 uprobes_ko
= s
.tmpdir
+ "/server/uprobes.ko";
1527 uprobes_ko
= s
.tmpdir
+ "/uprobes/uprobes.ko";
1529 if (file_exists (uprobes_ko
))
1531 s
.need_uprobes
= true;
1532 s
.uprobes_path
= uprobes_ko
;
1536 else if (s
.have_script
)
1540 clog
<< _("No module was returned by the server.") << endl
;
1544 globfree (& globbuf
);
1547 // If the server returned a MOK certificate, copy it to the user's
1548 // current directory.
1549 string server_MOK_public_cert
= s
.tmpdir
+ "/server/" MOK_PUBLIC_CERT_NAME
;
1550 if (file_exists (server_MOK_public_cert
))
1552 string dst
= MOK_PUBLIC_CERT_NAME
;
1553 copy_file (server_MOK_public_cert
, dst
, (s
.verbose
>= 3));
1556 // Output stdout and stderr.
1557 filename
= server_tmpdir
+ "/stderr";
1558 flush_to_stream (filename
, clog
);
1560 filename
= server_tmpdir
+ "/stdout";
1561 flush_to_stream (filename
, cout
);
1567 compile_server_client::read_from_file (const string
&fname
, int &data
)
1569 // C++ streams may not set errno in the even of a failure. However if we
1570 // set it to 0 before each operation and it gets set during the operation,
1571 // then we can use its value in order to determine what happened.
1573 ifstream
f (fname
.c_str ());
1576 clog
<< _F("Unable to open file '%s' for reading: ", fname
.c_str());
1585 clog
<< _F("Unable to read from file '%s': ", fname
.c_str());
1589 // NB: not necessary to f.close ();
1590 return 0; // Success
1594 clog
<< strerror (errno
) << endl
;
1596 clog
<< _("unknown error") << endl
;
1597 return 1; // Failure
1602 compile_server_client::write_to_file (const string
&fname
, const T
&data
)
1604 // C++ streams may not set errno in the even of a failure. However if we
1605 // set it to 0 before each operation and it gets set during the operation,
1606 // then we can use its value in order to determine what happened.
1608 ofstream
f (fname
.c_str ());
1611 clog
<< _F("Unable to open file '%s' for writing: ", fname
.c_str());
1620 clog
<< _F("Unable to write to file '%s': ", fname
.c_str());
1624 // NB: not necessary to f.close ();
1625 return 0; // Success
1629 clog
<< strerror (errno
) << endl
;
1631 clog
<< _("unknown error") << endl
;
1632 return 1; // Failure
1636 compile_server_client::flush_to_stream (const string
&fname
, ostream
&o
)
1638 // C++ streams may not set errno in the even of a failure. However if we
1639 // set it to 0 before each operation and it gets set during the operation,
1640 // then we can use its value in order to determine what happened.
1642 ifstream
f (fname
.c_str ());
1645 clog
<< _F("Unable to open file '%s' for reading: ", fname
.c_str());
1651 // NB: o << f.rdbuf() misbehaves for some reason, appearing to close o,
1652 // which is unfortunate if o == clog or cout.
1657 if (f
.eof ()) return 0; // normal exit
1658 if (! f
.good()) break;
1660 if (! o
.good()) break;
1663 // NB: not necessary to f.close ();
1667 clog
<< strerror (errno
) << endl
;
1669 clog
<< _("unknown error") << endl
;
1670 return 1; // Failure
1674 compile_server_client::show_server_compatibility () const
1676 // Locale sensitivity was added in version 1.6
1677 if (server_version
< "1.6")
1679 clog
<< _F("Server protocol version is %s\n", server_version
.v
);
1680 clog
<< _("The server does not use localization information passed by the client\n");
1684 // Issue a status message for when a server's trust is already in place.
1686 trust_already_in_place (
1687 const compile_server_info
&server
,
1688 const vector
<compile_server_info
> &server_list
,
1689 const string cert_db_path
,
1693 // What level of trust?
1695 if (cert_db_path
== signing_cert_db_path ())
1696 purpose
= _("as a module signer for all users");
1699 purpose
= _("as an SSL peer");
1700 if (cert_db_path
== global_ssl_cert_db_path ())
1701 purpose
+= _(" for all users");
1703 purpose
+= _(" for the current user");
1706 // Issue a message for each server in the list with the same certificate.
1707 unsigned limit
= server_list
.size ();
1708 for (unsigned i
= 0; i
< limit
; ++i
)
1710 if (server
.certinfo
!= server_list
[i
].certinfo
)
1712 clog
<< server_list
[i
] << _(" is already ");
1714 clog
<< _("untrusted ") << purpose
<< endl
;
1716 clog
<< _("trusted ") << purpose
<< endl
;
1720 // Add the given servers to the given database of trusted servers.
1723 systemtap_session
&s
,
1724 const string
&cert_db_path
,
1725 vector
<compile_server_info
> &server_list
1728 // Get a list of servers already trusted. This opens the database, so do it
1729 // before we open it for our own purposes.
1730 vector
<compile_server_info
> already_trusted
;
1731 get_server_info_from_db (s
, already_trusted
, cert_db_path
);
1733 // Make sure the given path exists.
1734 if (create_dir (cert_db_path
.c_str (), 0755) != 0)
1736 clog
<< _F("Unable to find or create the client certificate database directory %s: ", cert_db_path
.c_str());
1741 // Must predeclare this because of jumps to cleanup: below.
1742 vector
<string
> processed_certs
;
1744 // Make sure NSPR is initialized. Must be done before NSS is initialized
1747 // Initialize the NSS libraries -- read/write
1748 SECStatus secStatus
= nssInit (cert_db_path
.c_str (), 1/*readwrite*/);
1749 if (secStatus
!= SECSuccess
)
1751 // Message already issued.
1755 // Enable all cipher suites.
1756 // SSL_ClearSessionCache is required for the new settings to take effect.
1757 /* Some NSS versions don't do this correctly in NSS_SetDomesticPolicy. */
1759 const PRUint16
*cipher
;
1760 for (cipher
= SSL_GetImplementedCiphers(); *cipher
!= 0; ++cipher
)
1761 SSL_CipherPolicySet(*cipher
, SSL_ALLOWED
);
1763 SSL_ClearSessionCache ();
1765 // Iterate over the servers to become trusted. Contact each one and
1766 // add it to the list of trusted servers if it is not already trusted.
1767 // client_connect will issue any error messages.
1768 for (vector
<compile_server_info
>::iterator server
= server_list
.begin();
1769 server
!= server_list
.end ();
1772 // Trust is based on certificates. We need only add trust in the
1773 // same certificate once.
1775 // RHBZ 1075685: If the new server to be trusted is selected by address + port,
1776 // and there is no avahi assistance available, or the server is not known
1777 // to avahi, then its certificate serial number field will be empty. We
1778 // therefore have no basis for comparing it to the serial numbers on already-trusted
1779 // certificates. In this case, unconditionally contact the new server to obtain
1781 if (! server
->certinfo
.empty ())
1783 // We need not contact the server if it has already been processed.
1784 if (find (processed_certs
.begin (), processed_certs
.end (),
1785 server
->certinfo
) != processed_certs
.end ())
1787 processed_certs
.push_back (server
->certinfo
);
1789 // We need not contact the server if it is already trusted.
1790 if (find (already_trusted
.begin (), already_trusted
.end (), *server
) !=
1791 already_trusted
.end ())
1794 trust_already_in_place (*server
, server_list
, cert_db_path
, false/*revoking*/);
1799 // At a minimum we need an ip_address along with a port
1800 // number in order to contact the server.
1801 if (! server
->hasAddress() || server
->port
== 0)
1803 // Set the port within the address.
1804 server
->setAddressPort (server
->port
);
1806 int rc
= client_connect (*server
, NULL
, NULL
, "permanent");
1809 clog
<< _F("Unable to connect to %s", lex_cast(*server
).c_str()) << endl
;
1811 // Additional information: if the address is IPv6 and is link-local, then it must
1813 if (isIPv6LinkLocal (server
->address
) && server
->address
.ipv6
.scope_id
== 0)
1815 clog
<< _(" The address is an IPv6 link-local address with no scope specifier.")
1823 // SSL_ClearSessionCache is required before shutdown for client applications.
1824 SSL_ClearSessionCache ();
1825 nssCleanup (cert_db_path
.c_str ());
1827 // Make sure the database files are readable.
1829 string filespec
= cert_db_path
+ "/*.db";
1831 clog
<< _F("Searching \"%s\"\n", filespec
.c_str());
1832 int r
= glob (filespec
.c_str (), 0, NULL
, & globbuf
);
1833 if (r
!= GLOB_NOSPACE
&& r
!= GLOB_ABORTED
&& r
!= GLOB_NOMATCH
)
1835 for (unsigned i
= 0; i
< globbuf
.gl_pathc
; ++i
)
1837 string filename
= globbuf
.gl_pathv
[i
];
1839 clog
<< _(" found ") << filename
<< endl
;
1841 if (chmod (filename
.c_str (), 0644) != 0)
1843 s
.print_warning("Unable to change permissions on " + filename
+ ": ");
1850 // Remove the given servers from the given database of trusted servers.
1852 revoke_server_trust (
1853 systemtap_session
&s
,
1854 const string
&cert_db_path
,
1855 const vector
<compile_server_info
> &server_list
1858 // Make sure the given path exists.
1859 if (! file_exists (cert_db_path
))
1863 clog
<< _F("Certificate database '%s' does not exist",
1864 cert_db_path
.c_str()) << endl
;
1865 for (vector
<compile_server_info
>::const_iterator server
= server_list
.begin();
1866 server
!= server_list
.end ();
1868 trust_already_in_place (*server
, server_list
, cert_db_path
, true/*revoking*/);
1873 // Must predeclare these because of jumps to cleanup: below.
1874 CERTCertDBHandle
*handle
;
1875 PRArenaPool
*tmpArena
= NULL
;
1876 CERTCertList
*certs
= NULL
;
1877 CERTCertificate
*db_cert
;
1878 vector
<string
> processed_certs
;
1879 const char *nickname
;
1881 // Make sure NSPR is initialized. Must be done before NSS is initialized
1884 // Initialize the NSS libraries -- read/write
1885 SECStatus secStatus
= nssInit (cert_db_path
.c_str (), 1/*readwrite*/);
1886 if (secStatus
!= SECSuccess
)
1888 // Message already issued
1891 handle
= CERT_GetDefaultCertDB();
1893 // A memory pool to work in
1894 tmpArena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
1897 clog
<< _("Out of memory:");
1902 // Iterate over the servers to become untrusted.
1903 nickname
= server_cert_nickname ();
1904 for (vector
<compile_server_info
>::const_iterator server
= server_list
.begin();
1905 server
!= server_list
.end ();
1908 // If the server's certificate serial number is unknown, then we can't
1909 // match it with one in the database.
1910 if (server
->certinfo
.empty ())
1913 // Trust is based on certificates. We need only revoke trust in the same
1914 // certificate once.
1915 if (find (processed_certs
.begin (), processed_certs
.end (),
1916 server
->certinfo
) != processed_certs
.end ())
1918 processed_certs
.push_back (server
->certinfo
);
1920 // Search the client-side database of trusted servers.
1921 db_cert
= PK11_FindCertFromNickname (nickname
, NULL
);
1924 // No trusted servers. Not an error, but issue a status message.
1926 trust_already_in_place (*server
, server_list
, cert_db_path
, true/*revoking*/);
1930 // Here, we have one cert with the desired nickname.
1931 // Now, we will attempt to get a list of ALL certs
1932 // with the same subject name as the cert we have. That list
1933 // should contain, at a minimum, the one cert we have already found.
1934 // If the list of certs is empty (NULL), the libraries have failed.
1935 certs
= CERT_CreateSubjectCertList (NULL
, handle
, & db_cert
->derSubject
,
1936 PR_Now (), PR_FALSE
);
1937 CERT_DestroyCertificate (db_cert
);
1940 clog
<< _F("Unable to query certificate database %s: ",
1941 cert_db_path
.c_str()) << endl
;
1942 PORT_SetError (SEC_ERROR_LIBRARY_FAILURE
);
1947 // Find the certificate matching the one belonging to our server.
1948 CERTCertListNode
*node
;
1949 for (node
= CERT_LIST_HEAD (certs
);
1950 ! CERT_LIST_END (node
, certs
);
1951 node
= CERT_LIST_NEXT (node
))
1953 // The certificate we're working with.
1954 db_cert
= node
->cert
;
1956 // Get the serial number.
1957 string serialNumber
= get_cert_serial_number (db_cert
);
1959 // Does the serial number match that of the current server?
1960 if (serialNumber
!= server
->certinfo
)
1961 continue; // goto next certificate
1963 // All is ok! Remove the certificate from the database.
1965 } // Loop over certificates in the database
1967 // Was a certificate matching the server found? */
1968 if (CERT_LIST_END (node
, certs
))
1970 // Not found. Server is already untrusted.
1972 trust_already_in_place (*server
, server_list
, cert_db_path
, true/*revoking*/);
1976 secStatus
= SEC_DeletePermCertificate (db_cert
);
1977 if (secStatus
!= SECSuccess
)
1979 clog
<< _F("Unable to remove certificate from %s: ",
1980 cert_db_path
.c_str()) << endl
;
1984 CERT_DestroyCertList (certs
);
1986 } // Loop over servers
1991 PORT_FreeArena (tmpArena
, PR_FALSE
);
1993 nssCleanup (cert_db_path
.c_str ());
1996 // Obtain information about servers from the certificates in the given database.
1998 get_server_info_from_db (
1999 systemtap_session
&s
,
2000 vector
<compile_server_info
> &servers
,
2001 const string
&cert_db_path
2004 // Make sure the given path exists.
2005 if (! file_exists (cert_db_path
))
2008 clog
<< _F("Certificate database '%s' does not exist.",
2009 cert_db_path
.c_str()) << endl
;
2013 // Make sure NSPR is initialized. Must be done before NSS is initialized
2016 // Initialize the NSS libraries -- readonly
2017 SECStatus secStatus
= nssInit (cert_db_path
.c_str ());
2018 if (secStatus
!= SECSuccess
)
2020 // Message already issued.
2024 // Must predeclare this because of jumps to cleanup: below.
2025 PRArenaPool
*tmpArena
= NULL
;
2026 CERTCertList
*certs
= get_cert_list_from_db (server_cert_nickname ());
2030 clog
<< _F("No certificate found in database %s", cert_db_path
.c_str ()) << endl
;
2034 // A memory pool to work in
2035 tmpArena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
2038 clog
<< _("Out of memory:");
2042 for (CERTCertListNode
*node
= CERT_LIST_HEAD (certs
);
2043 ! CERT_LIST_END (node
, certs
);
2044 node
= CERT_LIST_NEXT (node
))
2046 compile_server_info server_info
;
2048 // The certificate we're working with.
2049 CERTCertificate
*db_cert
= node
->cert
;
2051 // Get the host name. It is in the alt-name extension of the
2054 subAltName
.data
= NULL
;
2055 secStatus
= CERT_FindCertExtension (db_cert
,
2056 SEC_OID_X509_SUBJECT_ALT_NAME
,
2058 if (secStatus
!= SECSuccess
|| ! subAltName
.data
)
2060 clog
<< _("Unable to find alt name extension on server certificate: ") << endl
;
2065 // Decode the extension.
2066 CERTGeneralName
*nameList
= CERT_DecodeAltNameExtension (tmpArena
, & subAltName
);
2067 SECITEM_FreeItem(& subAltName
, PR_FALSE
);
2070 clog
<< _("Unable to decode alt name extension on server certificate: ") << endl
;
2075 // We're interested in the first alternate name.
2076 assert (nameList
->type
== certDNSName
);
2077 server_info
.host_name
= string ((const char *)nameList
->name
.other
.data
,
2078 nameList
->name
.other
.len
);
2079 // Don't free nameList. It's part of the tmpArena.
2081 // Get the serial number.
2082 server_info
.certinfo
= get_cert_serial_number (db_cert
);
2084 // Our results will at a minimum contain this server.
2085 add_server_info (server_info
, servers
);
2087 // Augment the list by querying all online servers and keeping the ones
2088 // with the same cert serial number.
2089 vector
<compile_server_info
> online_servers
;
2090 get_or_keep_online_server_info (s
, online_servers
, false/*keep*/);
2091 keep_server_info_with_cert_and_port (s
, server_info
, online_servers
);
2092 add_server_info (online_servers
, servers
);
2097 CERT_DestroyCertList (certs
);
2099 PORT_FreeArena (tmpArena
, PR_FALSE
);
2101 nssCleanup (cert_db_path
.c_str ());
2104 // Utility Functions.
2105 //-----------------------------------------------------------------------
2106 ostream
&operator<< (ostream
&s
, const compile_server_info
&i
)
2108 // Don't print empty information
2113 if (! i
.host_name
.empty ())
2121 switch (i
.address
.raw
.family
)
2126 #define MAX_NETADDR_SIZE 46 // from the NSPR API reference.
2127 char buf
[MAX_NETADDR_SIZE
];
2128 prStatus
= PR_NetAddrToString(& i
.address
, buf
, sizeof (buf
));
2129 if (prStatus
== PR_SUCCESS
) {
2148 if (! i
.sysinfo
.empty ())
2149 s
<< i
.sysinfo
<< '"';
2153 if (! i
.version
.empty ())
2157 s
<< " certinfo=\"";
2158 if (! i
.certinfo
.empty ())
2159 s
<< i
.certinfo
<< '"';
2162 if (! i
.mok_fingerprints
.empty ())
2164 // FIXME: Yikes, this output is ugly. Perhaps the server output
2165 // needs a more structured approach.
2166 s
<< " mok_fingerprints=\"";
2167 vector
<string
>::const_iterator it
;
2168 for (it
= i
.mok_fingerprints
.begin (); it
!= i
.mok_fingerprints
.end ();
2171 if (it
!= i
.mok_fingerprints
.begin ())
2180 ostream
&operator<< (ostream
&s
, const vector
<compile_server_info
> &v
)
2182 // Indicate an empty list.
2183 if (v
.size () == 0 || (v
.size () == 1 && v
[0].empty()))
2184 s
<< "No Servers" << endl
;
2187 for (unsigned i
= 0; i
< v
.size(); ++i
)
2189 // Don't print empty items.
2198 copyNetAddr (PRNetAddr
&x
, const PRNetAddr
&y
)
2200 PRUint32 saveScope
= 0;
2202 // For IPv6 addresses, don't overwrite the scope_id of x unless x is uninitialized or it is 0.
2203 if (x
.raw
.family
== PR_AF_INET6
)
2204 saveScope
= x
.ipv6
.scope_id
;
2209 x
.ipv6
.scope_id
= saveScope
;
2215 operator== (const PRNetAddr
&x
, const PRNetAddr
&y
)
2217 // Same address family?
2218 if (x
.raw
.family
!= y
.raw
.family
)
2221 switch (x
.raw
.family
)
2224 // If both scope ids are set, compare them.
2225 if (x
.ipv6
.scope_id
!= 0 && y
.ipv6
.scope_id
!= 0 && x
.ipv6
.scope_id
!= y
.ipv6
.scope_id
)
2226 return false; // not equal
2227 // Scope is not a factor. Compare the address bits
2228 return memcmp (& x
.ipv6
.ip
, & y
.ipv6
.ip
, sizeof(x
.ipv6
.ip
)) == 0;
2230 return x
.inet
.ip
== y
.inet
.ip
;
2238 operator!= (const PRNetAddr
&x
, const PRNetAddr
&y
)
2244 copyAddress (PRIPv6Addr
&PRin6
, const in6_addr
&in6
)
2246 // The NSPR type is a typedef of struct in6_addr, but C++ won't let us copy it
2247 assert (sizeof (PRin6
) == sizeof (in6
));
2248 memcpy (& PRin6
, & in6
, sizeof (PRin6
));
2252 // Return the default server specification, used when none is given on the
2255 default_server_spec (const systemtap_session
&s
)
2257 // If --privilege=X has been used, where X is not stapdev,
2258 // the default is online,trusted,compatible,signer
2260 // the default is online,trusted,compatible
2262 // Having said that,
2263 // 'online' and 'compatible' will only succeed if we have avahi
2264 // 'trusted' and 'signer' will only succeed if we have NSS
2266 string working_string
= "online,trusted,compatible";
2267 if (! pr_contains (s
.privilege
, pr_stapdev
))
2268 working_string
+= ",signer";
2269 return working_string
;
2273 server_spec_to_pmask (const string
&server_spec
)
2275 // Construct a mask of the server properties that have been requested.
2276 // The available properties are:
2277 // trusted - servers which are trusted SSL peers.
2278 // online - online servers.
2279 // compatible - servers which compile for the current kernel release
2280 // and architecture.
2281 // signer - servers which are trusted module signers.
2282 // specified - servers which have been specified using --use-server=XXX.
2283 // If no servers have been specified, then this is
2284 // equivalent to --list-servers=trusted,online,compatible.
2285 // all - all trusted servers, trusted module signers,
2286 // servers currently online and specified servers.
2287 string working_spec
= server_spec
;
2288 vector
<string
> properties
;
2289 tokenize (working_spec
, properties
, ",");
2291 unsigned limit
= properties
.size ();
2292 for (unsigned i
= 0; i
< limit
; ++i
)
2294 const string
&property
= properties
[i
];
2295 // Tolerate (and ignore) empty properties.
2296 if (property
.empty ())
2298 if (property
== "all")
2300 pmask
|= compile_server_all
;
2302 else if (property
== "specified")
2304 pmask
|= compile_server_specified
;
2306 else if (property
== "trusted")
2308 pmask
|= compile_server_trusted
;
2310 else if (property
== "online")
2312 pmask
|= compile_server_online
;
2314 else if (property
== "compatible")
2316 pmask
|= compile_server_compatible
;
2318 else if (property
== "signer")
2320 pmask
|= compile_server_signer
;
2324 // XXX PR13274 needs-session to use print_warning()
2325 clog
<< _F("WARNING: unsupported compile server property: %s", property
.c_str())
2333 query_server_status (systemtap_session
&s
)
2335 unsigned limit
= s
.server_status_strings
.size ();
2336 for (unsigned i
= 0; i
< limit
; ++i
)
2337 query_server_status (s
, s
.server_status_strings
[i
]);
2341 query_server_status (systemtap_session
&s
, const string
&status_string
)
2343 // If this string is empty, then the default is "specified"
2344 string working_string
= status_string
;
2345 if (working_string
.empty ())
2346 working_string
= "specified";
2348 // If the query is "specified" and no servers have been specified
2349 // (i.e. --use-server not used or used with no argument), then
2350 // use the default query.
2351 // TODO: This may not be necessary. The underlying queries should handle
2352 // "specified" properly.
2353 if (working_string
== "specified" &&
2354 (s
.specified_servers
.empty () ||
2355 (s
.specified_servers
.size () == 1 && s
.specified_servers
[0].empty ())))
2356 working_string
= default_server_spec (s
);
2358 int pmask
= server_spec_to_pmask (working_string
);
2360 // Now obtain a list of the servers which match the criteria.
2361 vector
<compile_server_info
> raw_servers
;
2362 get_server_info (s
, pmask
, raw_servers
);
2364 // Augment the listing with as much information as possible by adding
2365 // information from known servers.
2366 vector
<compile_server_info
> servers
;
2367 get_all_server_info (s
, servers
);
2368 keep_common_server_info (raw_servers
, servers
);
2370 // Sort the list of servers into a preferred order.
2371 preferred_order (servers
);
2373 // Print the server information. Skip the empty entry at the head of the list.
2374 clog
<< _F("Systemtap Compile Server Status for '%s'", working_string
.c_str()) << endl
;
2376 unsigned limit
= servers
.size ();
2377 for (unsigned i
= 0; i
< limit
; ++i
)
2379 assert (! servers
[i
].empty ());
2380 // Don't list servers with no cert information. They may not actually
2382 // TODO: Could try contacting the server and obtaining its cert
2383 if (servers
[i
].certinfo
.empty ())
2385 clog
<< servers
[i
] << endl
;
2389 clog
<< _("No servers found") << endl
;
2392 // Add or remove trust of the servers specified on the command line.
2394 manage_server_trust (systemtap_session
&s
)
2396 // This function should do nothing if we don't have NSS.
2397 // Nothing to do if --trust-servers was not specified.
2398 if (s
.server_trust_spec
.empty ())
2401 // Break up and analyze the trust specification. Recognized components are:
2402 // ssl - trust the specified servers as ssl peers
2403 // signer - trust the specified servers as module signers
2404 // revoke - revoke the requested trust
2405 // all-users - apply/revoke the requested trust for all users
2406 // no-prompt - don't prompt the user for confirmation
2407 vector
<string
>components
;
2408 tokenize (s
.server_trust_spec
, components
, ",");
2410 bool signer
= false;
2411 bool revoke
= false;
2412 bool all_users
= false;
2413 bool no_prompt
= false;
2415 for (vector
<string
>::const_iterator i
= components
.begin ();
2416 i
!= components
.end ();
2421 else if (*i
== "signer")
2423 if (geteuid () != 0)
2425 clog
<< _("Only root can specify 'signer' on --trust-servers") << endl
;
2431 else if (*i
== "revoke")
2433 else if (*i
== "all-users")
2435 if (geteuid () != 0)
2437 clog
<< _("Only root can specify 'all-users' on --trust-servers") << endl
;
2443 else if (*i
== "no-prompt")
2446 s
.print_warning("Unrecognized server trust specification: " + *i
);
2451 // Make sure NSPR is initialized
2454 // Now obtain the list of specified servers.
2455 vector
<compile_server_info
> server_list
;
2456 get_specified_server_info (s
, server_list
, true/*no_default*/);
2458 // Did we identify any potential servers?
2459 unsigned limit
= server_list
.size ();
2462 clog
<< _("No servers identified for trust") << endl
;
2466 // Create a string representing the request in English.
2467 // If neither 'ssl' or 'signer' was specified, the default is 'ssl'.
2468 if (! ssl
&& ! signer
)
2470 ostringstream trustString
;
2473 trustString
<< _("as an SSL peer");
2475 trustString
<< _(" for all users");
2477 trustString
<< _(" for the current user");
2482 trustString
<< _(" and ");
2483 trustString
<< _("as a module signer for all users");
2486 // Prompt the user to confirm what's about to happen.
2490 clog
<< _("Revoking trust ");
2492 clog
<< _("Adding trust ");
2497 clog
<< _("Revoke trust ");
2499 clog
<< _("Add trust ");
2501 clog
<< _F("in the following servers %s", trustString
.str().c_str());
2505 for (unsigned i
= 0; i
< limit
; ++i
)
2506 clog
<< " " << server_list
[i
] << endl
;
2509 clog
<< "[y/N] " << flush
;
2511 // Only carry out the operation if the response is "yes"
2514 if (response
[0] != 'y' && response
[0] != 'Y')
2516 clog
<< _("Server trust unchanged") << endl
;
2521 // Now add/revoke the requested trust.
2522 string cert_db_path
;
2526 cert_db_path
= global_ssl_cert_db_path ();
2528 cert_db_path
= private_ssl_cert_db_path ();
2530 revoke_server_trust (s
, cert_db_path
, server_list
);
2532 add_server_trust (s
, cert_db_path
, server_list
);
2536 cert_db_path
= signing_cert_db_path ();
2538 revoke_server_trust (s
, cert_db_path
, server_list
);
2540 add_server_trust (s
, cert_db_path
, server_list
);
2544 static compile_server_cache
*
2545 cscache(systemtap_session
& s
)
2547 if (!s
.server_cache
)
2548 s
.server_cache
= new compile_server_cache();
2549 return s
.server_cache
;
2554 systemtap_session
&s
,
2556 vector
<compile_server_info
> &servers
2559 // Get information on compile servers matching the requested criteria.
2560 // The order of queries is significant. Accumulating queries must go first
2561 // followed by accumulating/filtering queries.
2563 if (((pmask
& compile_server_all
)))
2565 get_all_server_info (s
, servers
);
2568 // Add the specified servers, if requested
2569 if ((pmask
& compile_server_specified
))
2571 get_specified_server_info (s
, servers
);
2574 // Now filter or accumulate the list depending on whether a query has
2575 // already been made.
2576 if ((pmask
& compile_server_online
))
2578 get_or_keep_online_server_info (s
, servers
, keep
);
2581 if ((pmask
& compile_server_trusted
))
2583 get_or_keep_trusted_server_info (s
, servers
, keep
);
2586 if ((pmask
& compile_server_signer
))
2588 get_or_keep_signing_server_info (s
, servers
, keep
);
2591 if ((pmask
& compile_server_compatible
))
2593 get_or_keep_compatible_server_info (s
, servers
, keep
);
2598 // Get information about all online servers as well as servers trusted
2599 // as SSL peers and servers trusted as signers.
2601 get_all_server_info (
2602 systemtap_session
&s
,
2603 vector
<compile_server_info
> &servers
2606 // We only need to obtain this once per session. This is a good thing(tm)
2607 // since obtaining this information is expensive.
2608 vector
<compile_server_info
>& all_servers
= cscache(s
)->all_servers
;
2609 if (all_servers
.empty ())
2611 get_or_keep_online_server_info (s
, all_servers
, false/*keep*/);
2612 get_or_keep_trusted_server_info (s
, all_servers
, false/*keep*/);
2613 get_or_keep_signing_server_info (s
, all_servers
, false/*keep*/);
2617 clog
<< _("All known servers:") << endl
;
2618 clog
<< all_servers
;
2622 // Add the information, but not duplicates.
2623 add_server_info (all_servers
, servers
);
2627 get_default_server_info (
2628 systemtap_session
&s
,
2629 vector
<compile_server_info
> &servers
2633 clog
<< _("Using the default servers") << endl
;
2635 // We only need to obtain this once per session. This is a good thing(tm)
2636 // since obtaining this information is expensive.
2637 vector
<compile_server_info
>& default_servers
= cscache(s
)->default_servers
;
2638 if (default_servers
.empty ())
2640 // Get the required information.
2641 // get_server_info will add an empty entry at the beginning to indicate
2642 // that the search has been performed, in case the search comes up empty.
2643 int pmask
= server_spec_to_pmask (default_server_spec (s
));
2644 get_server_info (s
, pmask
, default_servers
);
2648 clog
<< _("Default servers are:") << endl
;
2649 clog
<< default_servers
;
2653 // Add the information, but not duplicates.
2654 add_server_info (default_servers
, servers
);
2658 isPort (const char *pstr
, compile_server_info
&server_info
)
2662 unsigned long p
= strtoul (pstr
, & estr
, 10);
2663 if (errno
!= 0 || *estr
!= '\0' || p
> USHRT_MAX
)
2665 clog
<< _F("Invalid port number specified: %s", pstr
) << endl
;
2668 server_info
.port
= p
;
2669 server_info
.fully_specified
= true;
2674 isIPv6 (const string
&server
, compile_server_info
&server_info
)
2676 // An IPv6 address is 8 hex components separated by colons.
2677 // One contiguous block of zero segments in the address may be elided using ::.
2678 // An interface may be specified by appending %IF_NAME to the address (e.g. %eth0).
2679 // A port may be specified by enclosing the ip address in [] and adding :<port>.
2680 // Allow a bracketed address without a port.
2681 assert (! server
.empty());
2683 string::size_type portIx
;
2684 if (server
[0] == '[')
2686 string::size_type endBracket
= server
.find (']');
2687 if (endBracket
== string::npos
)
2688 return false; // Not a valid IPv6 address
2689 // Extract the address.
2690 ip
= server
.substr (1, endBracket
- 1);
2691 portIx
= endBracket
+ 1;
2696 portIx
= string::npos
;
2699 // Find out how many components there are. The maximum is 8
2701 vector
<string
> components
;
2702 tokenize_full (ip
, components
, ":");
2703 if (components
.size() > 8)
2704 return false; // Not a valid IPv6 address
2706 // The components must be either hex values between 0 and 0xffff, or must be empty.
2707 // There can be only one empty component.
2709 for (unsigned i
= 0; i
< components
.size(); ++i
)
2711 if (components
[i
].empty())
2714 return false; // Not a valid IPv6 address
2716 // If it's the final component, see if it specifies the interface. If so, strip it from the
2717 // component in order to simplify parsing. It still remains as part of the original ip address
2719 if (i
== components
.size() - 1)
2721 size_t ix
= components
[i
].find ('%');
2722 if (ix
!= string::npos
)
2724 interface
= components
[i
].substr(ix
);
2725 components
[i
] = components
[i
].substr(0, ix
);
2728 // Skip leading zeroes.
2730 for (j
= 0; j
< components
[i
].size(); ++j
)
2732 if (components
[i
][j
] != '0')
2735 // Max of 4 hex digits
2736 if (components
[i
].size() - j
> 4)
2737 return false; // Not a valid IPv6 address
2738 for (/**/; j
< components
[i
].size(); ++j
)
2740 if (! isxdigit (components
[i
][j
]))
2741 return false; // Not a valid IPv6 address
2744 // If there is no empty component, then there must be exactly 8 components.
2745 if (! empty
&& components
.size() != 8)
2746 return false; // Not a valid IPv6 address
2748 // Try to convert the string to an address.
2749 PRStatus prStatus
= PR_StringToNetAddr (ip
.c_str(), & server_info
.address
);
2750 if (prStatus
!= PR_SUCCESS
)
2753 // Examine the optional port
2754 if (portIx
!= string::npos
)
2756 string port
= server
.substr (portIx
);
2757 if (port
.size() != 0)
2759 if (port
.size() < 2 || port
[0] != ':')
2760 return false; // Not a valid Port
2762 port
= port
.substr (1);
2763 if (! isPort (port
.c_str(), server_info
))
2764 return false; // not a valid port
2768 server_info
.port
= 0;
2770 return true; // valid IPv6 address.
2774 isIPv4 (const string
&server
, compile_server_info
&server_info
)
2776 // An IPv4 address is 4 decimal components separated by periods with an
2777 // additional optional decimal port separated from the address by a colon.
2778 assert (! server
.empty());
2780 // Find out how many components there are. The maximum is 8
2781 vector
<string
> components
;
2782 tokenize (server
, components
, ":");
2783 if (components
.size() > 2)
2784 return false; // Not a valid IPv4 address
2786 // Separate the address from the port (if any).
2789 if (components
.size() <= 1)
2792 addr
= components
[0];
2793 port
= components
[1];
2796 // Separate the address components.
2797 // There must be exactly 4 components.
2798 components
.clear ();
2799 tokenize (addr
, components
, ".");
2800 if (components
.size() != 4)
2801 return false; // Not a valid IPv4 address
2803 // The components must be decimal values between 0 and 255.
2804 for (unsigned i
= 0; i
< components
.size(); ++i
)
2806 if (components
[i
].empty())
2807 return false; // Not a valid IPv4 address
2810 long p
= strtol (components
[i
].c_str(), & estr
, 10);
2811 if (errno
!= 0 || *estr
!= '\0' || p
< 0 || p
> 255)
2812 return false; // Not a valid IPv4 address
2815 // Try to convert the string to an address.
2816 PRStatus prStatus
= PR_StringToNetAddr (addr
.c_str(), & server_info
.address
);
2817 if (prStatus
!= PR_SUCCESS
)
2820 // Examine the optional port
2821 if (! port
.empty ()) {
2822 if (! isPort (port
.c_str(), server_info
))
2823 return false; // not a valid port
2826 server_info
.port
= 0;
2828 return true; // valid IPv4 address.
2832 isCertSerialNumber (const string
&server
, compile_server_info
&server_info
)
2834 // This function assumes that we have already ruled out the server spec being an IPv6 address.
2835 // Certificate serial numbers are 5 fields separated by colons plus an optional 6th decimal
2836 // field specifying a port.
2837 assert (! server
.empty());
2838 string host
= server
;
2839 vector
<string
> components
;
2840 tokenize (host
, components
, ":");
2841 switch (components
.size ())
2844 if (! isPort (components
.back().c_str(), server_info
))
2845 return false; // not a valid port
2846 host
= host
.substr (0, host
.find_last_of (':'));
2849 server_info
.certinfo
= host
;
2852 return false; // not a cert serial number
2855 return true; // valid cert serial number and optional port
2859 isDomain (const string
&server
, compile_server_info
&server_info
)
2861 // Accept one or two components separated by a colon. The first will be the domain name and
2862 // the second must a port number.
2863 assert (! server
.empty());
2864 string host
= server
;
2865 vector
<string
> components
;
2866 tokenize (host
, components
, ":");
2867 switch (components
.size ())
2870 if (! isPort (components
.back().c_str(), server_info
))
2871 return false; // not a valid port
2872 host
= host
.substr (0, host
.find_last_of (':'));
2875 server_info
.host_name
= host
;
2878 return false; // not a valid domain name
2885 get_specified_server_info (
2886 systemtap_session
&s
,
2887 vector
<compile_server_info
> &servers
,
2891 // We only need to obtain this once per session. This is a good thing(tm)
2892 // since obtaining this information is expensive.
2893 vector
<compile_server_info
>& specified_servers
= cscache(s
)->specified_servers
;
2894 if (specified_servers
.empty ())
2896 // Maintain an empty entry to indicate that this search has been
2897 // performed, in case the search comes up empty.
2898 specified_servers
.push_back (compile_server_info ());
2900 // If --use-server was not specified at all, then return info for the
2901 // default server list.
2902 if (s
.specified_servers
.empty ())
2905 clog
<< _("No servers specified") << endl
;
2907 get_default_server_info (s
, specified_servers
);
2911 // Iterate over the specified servers. For each specification, add to
2912 // the list of servers.
2913 unsigned num_specified_servers
= s
.specified_servers
.size ();
2914 for (unsigned i
= 0; i
< num_specified_servers
; ++i
)
2916 string
&server
= s
.specified_servers
[i
];
2918 // If no specific server(s) specified, then use the default servers.
2919 if (server
.empty ())
2922 clog
<< _("No servers specified") << endl
;
2924 get_default_server_info (s
, specified_servers
);
2928 // Determine what has been specified. Servers may be specified by:
2930 // - certificate-serial-number{:port}
2931 // - IPv4-address{:port}
2932 // - IPv6-address{:port}
2933 // where items within {} are optional.
2934 // Check for IPv6 addresses first. It reduces the amount of checking necessary for
2935 // certificate serial numbers.
2936 compile_server_info server_info
;
2937 vector
<compile_server_info
> resolved_servers
;
2938 if (isIPv6 (server
, server_info
) || isIPv4 (server
, server_info
) ||
2939 isCertSerialNumber (server
, server_info
))
2941 // An address or cert serial number has been specified.
2942 // No resolution is needed.
2943 resolved_servers
.push_back (server_info
);
2945 else if (isDomain (server
, server_info
))
2947 // Try to resolve the given name.
2948 resolve_host (s
, server_info
, resolved_servers
);
2952 clog
<< _F("Invalid server specification for --use-server: %s", server
.c_str())
2957 // Now examine the server(s) identified and add them to the list of specified
2959 vector
<compile_server_info
> known_servers
;
2960 vector
<compile_server_info
> new_servers
;
2961 for (vector
<compile_server_info
>::iterator i
= resolved_servers
.begin();
2962 i
!= resolved_servers
.end();
2965 // If this item was fully specified, then just add it.
2966 if (i
->fully_specified
)
2967 add_server_info (*i
, new_servers
);
2969 // It was not fully specified, so we need additional info. Try
2970 // to get it by matching what we have against other known servers.
2971 if (known_servers
.empty ())
2972 get_all_server_info (s
, known_servers
);
2974 // See if this server spec matches that of a known server
2975 vector
<compile_server_info
> matched_servers
= known_servers
;
2976 keep_common_server_info (*i
, matched_servers
);
2978 // If this server spec matches one or more known servers, then add the
2979 // augmented info to the specified_servers. Otherwise, if this server
2980 // spec is complete, then add it directly. Otherwise this server spec
2982 if (! matched_servers
.empty())
2983 add_server_info (matched_servers
, new_servers
);
2984 else if (i
->isComplete ())
2985 add_server_info (*i
, new_servers
);
2986 else if (s
.verbose
>= 3)
2987 clog
<< _("Incomplete server spec: ") << *i
<< endl
;
2993 clog
<< _F("Servers matching %s: ", server
.c_str()) << endl
;
2994 clog
<< new_servers
;
2997 // Add the newly identified servers to the list.
2998 if (! new_servers
.empty())
2999 add_server_info (new_servers
, specified_servers
);
3000 } // Loop over --use-server options
3001 } // -- use-server specified
3005 clog
<< _("All specified servers:") << endl
;
3006 clog
<< specified_servers
;
3008 } // Server information is not cached
3010 // Add the information, but not duplicates.
3011 add_server_info (specified_servers
, servers
);
3015 get_or_keep_trusted_server_info (
3016 systemtap_session
&s
,
3017 vector
<compile_server_info
> &servers
,
3021 // If we're filtering the list and it's already empty, then
3022 // there's nothing to do.
3023 if (keep
&& servers
.empty ())
3026 // We only need to obtain this once per session. This is a good thing(tm)
3027 // since obtaining this information is expensive.
3028 vector
<compile_server_info
>& trusted_servers
= cscache(s
)->trusted_servers
;
3029 if (trusted_servers
.empty ())
3031 // Maintain an empty entry to indicate that this search has been
3032 // performed, in case the search comes up empty.
3033 trusted_servers
.push_back (compile_server_info ());
3035 // Check the private database first.
3036 string cert_db_path
= private_ssl_cert_db_path ();
3037 get_server_info_from_db (s
, trusted_servers
, cert_db_path
);
3039 // Now check the global database.
3040 cert_db_path
= global_ssl_cert_db_path ();
3041 get_server_info_from_db (s
, trusted_servers
, cert_db_path
);
3045 clog
<< _("All servers trusted as ssl peers:") << endl
;
3046 clog
<< trusted_servers
;
3048 } // Server information is not cached
3052 // Filter the existing vector by keeping the information in common with
3053 // the trusted_server vector.
3054 keep_common_server_info (trusted_servers
, servers
);
3058 // Add the information, but not duplicates.
3059 add_server_info (trusted_servers
, servers
);
3064 get_or_keep_signing_server_info (
3065 systemtap_session
&s
,
3066 vector
<compile_server_info
> &servers
,
3070 // If we're filtering the list and it's already empty, then
3071 // there's nothing to do.
3072 if (keep
&& servers
.empty ())
3075 // We only need to obtain this once per session. This is a good thing(tm)
3076 // since obtaining this information is expensive.
3077 vector
<compile_server_info
>& signing_servers
= cscache(s
)->signing_servers
;
3078 if (signing_servers
.empty ())
3080 // Maintain an empty entry to indicate that this search has been
3081 // performed, in case the search comes up empty.
3082 signing_servers
.push_back (compile_server_info ());
3084 // For all users, check the global database.
3085 string cert_db_path
= signing_cert_db_path ();
3086 get_server_info_from_db (s
, signing_servers
, cert_db_path
);
3090 clog
<< _("All servers trusted as module signers:") << endl
;
3091 clog
<< signing_servers
;
3093 } // Server information is not cached
3097 // Filter the existing vector by keeping the information in common with
3098 // the signing_server vector.
3099 keep_common_server_info (signing_servers
, servers
);
3103 // Add the information, but not duplicates.
3104 add_server_info (signing_servers
, servers
);
3110 get_or_keep_compatible_server_info (
3111 systemtap_session
&s
,
3112 vector
<compile_server_info
> &servers
,
3117 // If we're filtering the list and it's already empty, then
3118 // there's nothing to do.
3119 if (keep
&& servers
.empty ())
3122 // Remove entries for servers incompatible with the host environment
3123 // from the given list of servers.
3124 // A compatible server compiles for the kernel release and architecture
3125 // of the host environment.
3127 // Compatibility can only be determined for online servers. So, augment
3128 // and filter the information we have with information for online servers.
3129 vector
<compile_server_info
> online_servers
;
3130 get_or_keep_online_server_info (s
, online_servers
, false/*keep*/);
3132 keep_common_server_info (online_servers
, servers
);
3134 add_server_info (online_servers
, servers
);
3136 // Now look to see which ones are compatible.
3137 // The vector can change size as we go, so be careful!!
3138 for (unsigned i
= 0; i
< servers
.size (); /**/)
3140 // Retain empty entries.
3141 assert (! servers
[i
].empty ());
3143 // Check the target of the server.
3144 if (servers
[i
].sysinfo
!= s
.kernel_release
+ " " + s
.architecture
)
3146 // Target platform mismatch.
3147 servers
.erase (servers
.begin () + i
);
3151 // If the client requires secure boot signing, make sure the
3152 // server has the right MOK.
3153 if (! s
.mok_fingerprints
.empty ())
3155 // This server has no MOKs.
3156 if (servers
[i
].mok_fingerprints
.empty ())
3158 servers
.erase (servers
.begin () + i
);
3162 // Make sure the server has at least one MOK in common with
3164 vector
<string
>::const_iterator it
;
3165 bool mok_found
= false;
3166 for (it
= s
.mok_fingerprints
.begin(); it
!= s
.mok_fingerprints
.end(); it
++)
3168 if (find(servers
[i
].mok_fingerprints
.begin(),
3169 servers
[i
].mok_fingerprints
.end(), *it
)
3170 != servers
[i
].mok_fingerprints
.end ())
3177 // This server has no MOK in common with the client.
3180 servers
.erase (servers
.begin () + i
);
3185 // The server is compatible. Leave it in the list.
3188 #else // ! HAVE_AVAHI
3189 // Without Avahi, we can't obtain the target platform of the server.
3192 clog
<< _("Unable to detect server compatibility without avahi") << endl
;
3199 keep_server_info_with_cert_and_port (
3200 systemtap_session
&,
3201 const compile_server_info
&server
,
3202 vector
<compile_server_info
> &servers
3205 assert (! server
.certinfo
.empty ());
3207 // Search the list of servers for ones matching the
3208 // serial number specified.
3209 // The vector can change size as we go, so be careful!!
3210 for (unsigned i
= 0; i
< servers
.size (); /**/)
3212 // Retain empty entries.
3213 if (servers
[i
].empty ())
3218 if (servers
[i
].certinfo
== server
.certinfo
&&
3219 (servers
[i
].port
== 0 || server
.port
== 0 ||
3220 servers
[i
].port
== server
.port
))
3222 // If the server is not online, then use the specified
3224 if (servers
[i
].port
== 0)
3226 servers
[i
].port
= server
.port
;
3227 servers
[i
].fully_specified
= server
.fully_specified
;
3232 // The item does not match. Delete it.
3233 servers
.erase (servers
.begin () + i
);
3237 // Obtain missing host name or ip address, if any. Return 0 on success.
3240 systemtap_session
& s
,
3241 compile_server_info
&server
,
3242 vector
<compile_server_info
> &resolved_servers
3245 vector
<resolved_host
>& cached_hosts
= cscache(s
)->resolved_hosts
[server
.host_name
];
3246 if (cached_hosts
.empty ())
3248 // The server's host_name member is a string containing either a host name or an ip address.
3249 // Either is acceptable for lookup.
3250 const char *lookup_name
= server
.host_name
.c_str();
3252 clog
<< _F("Looking up %s", lookup_name
) << endl
;
3254 struct addrinfo hints
;
3255 memset(& hints
, 0, sizeof (hints
));
3256 hints
.ai_family
= AF_UNSPEC
; // AF_INET or AF_INET6 to force version
3257 struct addrinfo
*addr_info
= 0;
3258 int rc
= getaddrinfo (lookup_name
, NULL
, & hints
, & addr_info
);
3260 // Failure to resolve will result in an appropriate message later, if other methods fail.
3264 clog
<< _F("%s not found: %s", lookup_name
, gai_strerror (rc
)) << endl
;
3268 // Loop over the results collecting information.
3270 for (const struct addrinfo
*ai
= addr_info
; ai
!= NULL
; ai
= ai
->ai_next
)
3272 PRNetAddr new_address
;
3274 // We support IPv4 and IPv6, Ignore other protocols,
3275 if (ai
->ai_family
== AF_INET
)
3278 struct sockaddr_in
*ip
= (struct sockaddr_in
*)ai
->ai_addr
;
3279 new_address
.inet
.family
= PR_AF_INET
;
3280 new_address
.inet
.ip
= ip
->sin_addr
.s_addr
;
3282 else if (ai
->ai_family
== AF_INET6
)
3285 struct sockaddr_in6
*ip
= (struct sockaddr_in6
*)ai
->ai_addr
;
3286 new_address
.ipv6
.family
= PR_AF_INET6
;
3287 new_address
.ipv6
.scope_id
= ip
->sin6_scope_id
;
3288 copyAddress (new_address
.ipv6
.ip
, ip
->sin6_addr
);
3293 // Try to obtain a host name. Otherwise, leave it empty.
3294 char hbuf
[NI_MAXHOST
];
3295 int status
= getnameinfo (ai
->ai_addr
, ai
->ai_addrlen
, hbuf
, sizeof (hbuf
), NULL
, 0,
3296 NI_NAMEREQD
| NI_IDN
);
3300 cached_hosts
.push_back(resolved_host(hbuf
, new_address
));
3304 freeaddrinfo (addr_info
); // free the linked list
3307 // If no addresses were resolved, then return the info we were given.
3308 if (cached_hosts
.empty())
3309 add_server_info (server
, resolved_servers
);
3311 // We will add a new server for each address resolved
3312 vector
<compile_server_info
> new_servers
;
3313 for (vector
<resolved_host
>::const_iterator it
= cached_hosts
.begin();
3314 it
!= cached_hosts
.end(); ++it
)
3316 // Start with the info we were given
3317 compile_server_info new_server
= server
;
3319 // NB: do not overwrite port info
3320 if (it
->address
.raw
.family
== AF_INET
)
3322 new_server
.address
.inet
.family
= PR_AF_INET
;
3323 new_server
.address
.inet
.ip
= it
->address
.inet
.ip
;
3327 new_server
.address
.ipv6
.family
= PR_AF_INET6
;
3328 new_server
.address
.ipv6
.scope_id
= it
->address
.ipv6
.scope_id
;
3329 new_server
.address
.ipv6
.ip
= it
->address
.ipv6
.ip
;
3331 if (!it
->host_name
.empty())
3332 new_server
.host_name
= it
->host_name
;
3333 add_server_info (new_server
, new_servers
);
3338 clog
<< _F("%s resolves to:", server
.host_name
.c_str()) << endl
;
3339 clog
<< new_servers
;
3342 add_server_info (new_servers
, resolved_servers
);
3347 // Avahi API Callbacks.
3348 //-----------------------------------------------------------------------
3349 struct browsing_context
{
3350 AvahiSimplePoll
*simple_poll
;
3351 AvahiClient
*client
;
3352 vector
<compile_server_info
> *servers
;
3355 // Get the value of the requested key from the Avahi string list.
3357 get_value_from_avahi_string_list (AvahiStringList
*strlst
, const string
&key
)
3359 AvahiStringList
*p
= avahi_string_list_find (strlst
, key
.c_str ());
3367 int rc
= avahi_string_list_get_pair(p
, &k
, &v
, NULL
);
3368 if (rc
< 0 || v
== NULL
)
3380 // Get a vector of values of the requested key from the Avahi string
3381 // list. This is for multiple values having the same key.
3383 get_values_from_avahi_string_list (AvahiStringList
*strlst
, const string
&key
,
3384 vector
<string
> &value_vector
)
3388 value_vector
.clear();
3389 p
= avahi_string_list_find (strlst
, key
.c_str ());
3390 for (; p
!= NULL
; p
= avahi_string_list_get_next(p
))
3393 int rc
= avahi_string_list_get_pair(p
, &k
, &v
, NULL
);
3394 if (rc
< 0 || v
== NULL
)
3400 value_vector
.push_back(v
);
3408 void resolve_callback(
3409 AvahiServiceResolver
*r
,
3410 AvahiIfIndex interface
,
3411 AvahiProtocol protocol
,
3412 AvahiResolverEvent event
,
3416 const char *host_name
,
3417 const AvahiAddress
*address
,
3419 AvahiStringList
*txt
,
3420 AvahiLookupResultFlags
/*flags*/,
3421 AVAHI_GCC_UNUSED
void* userdata
)
3426 const browsing_context
*context
= (browsing_context
*)userdata
;
3427 vector
<compile_server_info
> *servers
= context
->servers
;
3429 // Called whenever a service has been resolved successfully or timed out.
3432 case AVAHI_RESOLVER_FAILURE
:
3433 clog
<< _F("Failed to resolve service '%s' of type '%s' in domain '%s': %s",
3435 avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r
)))) << endl
;
3438 case AVAHI_RESOLVER_FOUND
: {
3439 compile_server_info info
;
3441 // Decode the address.
3442 char a
[AVAHI_ADDRESS_STR_MAX
];
3443 avahi_address_snprint(a
, sizeof(a
), address
);
3444 prStatus
= PR_StringToNetAddr (a
, & info
.address
);
3445 if (prStatus
!= PR_SUCCESS
) {
3446 clog
<< _F("Invalid address '%s' from avahi", a
) << endl
;
3450 // We support both IPv4 and IPv6. Ignore other protocols.
3451 if (protocol
== AVAHI_PROTO_INET6
) {
3452 info
.address
.ipv6
.family
= PR_AF_INET6
;
3453 info
.address
.ipv6
.scope_id
= interface
;
3456 else if (protocol
== AVAHI_PROTO_INET
) {
3457 info
.address
.inet
.family
= PR_AF_INET
;
3463 // Save the host name.
3464 info
.host_name
= host_name
;
3466 // Save the text tags.
3467 info
.sysinfo
= get_value_from_avahi_string_list (txt
, "sysinfo");
3468 info
.certinfo
= get_value_from_avahi_string_list (txt
, "certinfo");
3469 info
.version
= get_value_from_avahi_string_list (txt
, "version");
3470 if (info
.version
.empty ())
3471 info
.version
= "1.0"; // default version is 1.0
3473 // The server might provide one or more MOK certificate's
3475 get_values_from_avahi_string_list(txt
, "mok_info",
3476 info
.mok_fingerprints
);
3478 // Add this server to the list of discovered servers.
3479 add_server_info (info
, *servers
);
3486 avahi_service_resolver_free(r
);
3490 void browse_callback(
3491 AvahiServiceBrowser
*b
,
3492 AvahiIfIndex interface
,
3493 AvahiProtocol protocol
,
3494 AvahiBrowserEvent event
,
3498 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags
,
3501 browsing_context
*context
= (browsing_context
*)userdata
;
3502 AvahiClient
*c
= context
->client
;
3503 AvahiSimplePoll
*simple_poll
= context
->simple_poll
;
3506 // Called whenever a new services becomes available on the LAN or is removed from the LAN.
3509 case AVAHI_BROWSER_FAILURE
:
3510 clog
<< _F("Avahi browse failed: %s",
3511 avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b
))))
3513 avahi_simple_poll_quit(simple_poll
);
3516 case AVAHI_BROWSER_NEW
:
3517 // We ignore the returned resolver object. In the callback
3518 // function we free it. If the server is terminated before
3519 // the callback function is called the server will free
3520 // the resolver for us.
3521 if (!(avahi_service_resolver_new(c
, interface
, protocol
, name
, type
, domain
,
3522 AVAHI_PROTO_UNSPEC
, (AvahiLookupFlags
)0, resolve_callback
, context
))) {
3523 clog
<< _F("Failed to resolve service '%s': %s",
3524 name
, avahi_strerror(avahi_client_errno(c
))) << endl
;
3528 case AVAHI_BROWSER_REMOVE
:
3529 case AVAHI_BROWSER_ALL_FOR_NOW
:
3530 case AVAHI_BROWSER_CACHE_EXHAUSTED
:
3536 void client_callback(AvahiClient
*c
, AvahiClientState state
, AVAHI_GCC_UNUSED
void * userdata
) {
3538 browsing_context
*context
= (browsing_context
*)userdata
;
3539 AvahiSimplePoll
*simple_poll
= context
->simple_poll
;
3541 // Called whenever the client or server state changes.
3543 if (state
== AVAHI_CLIENT_FAILURE
) {
3544 clog
<< _F("Avahi Server connection failure: %s", avahi_strerror(avahi_client_errno(c
))) << endl
;
3545 avahi_simple_poll_quit(simple_poll
);
3550 void timeout_callback(AVAHI_GCC_UNUSED AvahiTimeout
*e
, AVAHI_GCC_UNUSED
void *userdata
) {
3551 browsing_context
*context
= (browsing_context
*)userdata
;
3552 AvahiSimplePoll
*simple_poll
= context
->simple_poll
;
3553 avahi_simple_poll_quit(simple_poll
);
3555 #endif // HAVE_AVAHI
3558 get_or_keep_online_server_info (
3559 systemtap_session
&s
,
3560 vector
<compile_server_info
> &servers
,
3564 // If we're filtering the list and it's already empty, then
3565 // there's nothing to do.
3566 if (keep
&& servers
.empty ())
3569 // We only need to obtain this once per session. This is a good thing(tm)
3570 // since obtaining this information is expensive.
3571 vector
<compile_server_info
>& online_servers
= cscache(s
)->online_servers
;
3572 if (online_servers
.empty ())
3574 // Maintain an empty entry to indicate that this search has been
3575 // performed, in case the search comes up empty.
3576 online_servers
.push_back (compile_server_info ());
3578 // Must predeclare these due to jumping on error to fail:
3579 vector
<compile_server_info
> avahi_servers
;
3582 AvahiClient
*client
= NULL
;
3583 AvahiServiceBrowser
*sb
= NULL
;
3585 // Allocate main loop object.
3586 AvahiSimplePoll
*simple_poll
;
3587 if (!(simple_poll
= avahi_simple_poll_new()))
3589 clog
<< _("Failed to create Avahi simple poll object") << endl
;
3592 browsing_context context
;
3593 context
.simple_poll
= simple_poll
;
3594 context
.servers
= & avahi_servers
;
3596 // Allocate a new Avahi client
3598 client
= avahi_client_new (avahi_simple_poll_get (simple_poll
),
3599 (AvahiClientFlags
)0,
3600 client_callback
, & context
, & error
);
3602 // Check whether creating the client object succeeded.
3605 clog
<< _F("Failed to create Avahi client: %s",
3606 avahi_strerror(error
)) << endl
;
3609 context
.client
= client
;
3611 // Create the service browser.
3612 if (!(sb
= avahi_service_browser_new (client
, AVAHI_IF_UNSPEC
,
3613 AVAHI_PROTO_UNSPEC
, "_stap._tcp",
3614 NULL
, (AvahiLookupFlags
)0,
3615 browse_callback
, & context
)))
3617 clog
<< _F("Failed to create Avahi service browser: %s",
3618 avahi_strerror(avahi_client_errno(client
))) << endl
;
3622 // Timeout after 0.5 seconds.
3624 avahi_simple_poll_get(simple_poll
)->timeout_new(
3625 avahi_simple_poll_get(simple_poll
),
3626 avahi_elapse_time(&tv
, 1000/2, 0),
3630 // Run the main loop.
3631 avahi_simple_poll_loop(simple_poll
);
3635 clog
<< _("Avahi reports the following servers online:") << endl
;
3636 clog
<< avahi_servers
;
3639 // Merge with the list of servers, as obtained by avahi.
3640 add_server_info (avahi_servers
, online_servers
);
3645 // Also frees the service browser
3646 avahi_client_free(client
);
3649 avahi_simple_poll_free(simple_poll
);
3650 #else // ! HAVE_AVAHI
3651 // Without Avahi, we can't detect online servers. Issue a warning.
3653 clog
<< _("Unable to detect online servers without avahi") << endl
;
3654 #endif // ! HAVE_AVAHI
3658 clog
<< _("All online servers:") << endl
;
3659 clog
<< online_servers
;
3661 } // Server information is not cached.
3665 // Filter the existing vector by keeping the information in common with
3666 // the online_server vector.
3667 keep_common_server_info (online_servers
, servers
);
3671 // Add the information, but not duplicates.
3672 add_server_info (online_servers
, servers
);
3676 // Add server info to a list, avoiding duplicates. Merge information from
3677 // two duplicate items.
3680 const compile_server_info
&info
, vector
<compile_server_info
>& target
3687 for (vector
<compile_server_info
>::iterator i
= target
.begin ();
3693 // Duplicate. Merge the two items.
3694 merge_server_info (info
, *i
);
3699 target
.push_back (info
);
3702 // Add server info from one vector to another.
3705 const vector
<compile_server_info
> &source
,
3706 vector
<compile_server_info
> &target
3709 for (vector
<compile_server_info
>::const_iterator i
= source
.begin ();
3713 add_server_info (*i
, target
);
3717 // Filter the vector by keeping information in common with the item.
3719 keep_common_server_info (
3720 const compile_server_info
&info_to_keep
,
3721 vector
<compile_server_info
> &filtered_info
3724 assert (! info_to_keep
.empty ());
3726 // The vector may change size as we go. Be careful!!
3727 for (unsigned i
= 0; i
< filtered_info
.size (); /**/)
3729 // Retain empty entries.
3730 if (filtered_info
[i
].empty ())
3735 if (info_to_keep
== filtered_info
[i
])
3737 merge_server_info (info_to_keep
, filtered_info
[i
]);
3741 // The item does not match. Delete it.
3742 filtered_info
.erase (filtered_info
.begin () + i
);
3747 // Filter the second vector by keeping information in common with the first
3750 keep_common_server_info (
3751 const vector
<compile_server_info
> &info_to_keep
,
3752 vector
<compile_server_info
> &filtered_info
3755 // The vector may change size as we go. Be careful!!
3756 for (unsigned i
= 0; i
< filtered_info
.size (); /**/)
3758 // Retain empty entries.
3759 if (filtered_info
[i
].empty ())
3765 for (unsigned j
= 0; j
< info_to_keep
.size (); ++j
)
3767 if (filtered_info
[i
] == info_to_keep
[j
])
3769 merge_server_info (info_to_keep
[j
], filtered_info
[i
]);
3774 // If the item was not found. Delete it. Otherwise, advance to the next
3779 filtered_info
.erase (filtered_info
.begin () + i
);
3783 // Merge two compile server info items.
3786 const compile_server_info
&source
,
3787 compile_server_info
&target
3790 // Copy the host name if the source has one.
3791 if (! source
.host_name
.empty())
3792 target
.host_name
= source
.host_name
;
3793 // Copy the address unconditionally, if the source has an address, even if they are already
3794 // equal. The source address may be an IPv6 address with a scope_id that the target is missing.
3795 assert (! target
.hasAddress () || ! source
.hasAddress () || source
.address
== target
.address
);
3796 if (source
.hasAddress ())
3797 copyNetAddr (target
.address
, source
.address
);
3798 if (target
.port
== 0)
3800 target
.port
= source
.port
;
3801 target
.fully_specified
= source
.fully_specified
;
3803 if (target
.sysinfo
.empty ())
3804 target
.sysinfo
= source
.sysinfo
;
3805 if (target
.version
.empty ())
3806 target
.version
= source
.version
;
3807 if (target
.certinfo
.empty ())
3808 target
.certinfo
= source
.certinfo
;
3811 #if 0 // not used right now
3812 // Merge compile server info from one item into a vector.
3815 const compile_server_info
&source
,
3816 vector
<compile_server_info
> &target
3819 for (vector
<compile_server_info
>::iterator i
= target
.begin ();
3824 merge_server_info (source
, *i
);
3828 // Merge compile server from one vector into another.
3831 const vector
<compile_server_info
> &source
,
3832 vector
<compile_server_info
> &target
3835 for (vector
<compile_server_info
>::const_iterator i
= source
.begin ();
3838 merge_server_info (*i
, target
);
3843 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */