2 Compile server client functions
3 Copyright (C) 2010-2011 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
14 #include "stap-probe.h"
16 #include <sys/times.h>
26 #include <linux/limits.h>
30 #include <sys/socket.h>
33 #include <arpa/inet.h>
39 #include <avahi-client/client.h>
40 #include <avahi-client/lookup.h>
42 #include <avahi-common/simple-watch.h>
43 #include <avahi-common/malloc.h>
44 #include <avahi-common/error.h>
45 #include <avahi-common/timeval.h>
61 #include "nsscommon.h"
67 #define STAP_CSC_01 _("WARNING: The domain name, \%s, does not match the DNS name(s) on the server certificate:\n")
68 #define STAP_CSC_02 _("could not find input file %s\n")
69 #define STAP_CSC_03 _("could not open input file %s\n")
70 #define STAP_CSC_04 _("Unable to open output file %s\n")
71 #define STAP_CSC_05 _("could not write to %s\n")
75 nsscommon_error (const char *msg
, int logit
__attribute ((unused
)))
77 clog
<< msg
<< endl
<< flush
;
80 // Information about compile servers.
81 struct compile_server_info
83 compile_server_info () : port (0) {}
94 return host_name
.empty () && ip_address
.empty ();
97 bool operator== (const compile_server_info
&that
) const
99 // If the ip address is not set, then the host names must match, otherwise
100 // the ip addresses must match.
101 if (this->ip_address
.empty () || that
.ip_address
.empty ())
103 if (this->host_name
!= that
.host_name
)
106 else if (this->ip_address
!= that
.ip_address
)
109 // Compare the other fields only if they have both been set.
110 if (this->port
!= 0 && that
.port
!= 0 && this->port
!= that
.port
)
112 if (! this->version
.empty () && ! that
.version
.empty () &&
113 this->version
!= that
.version
)
115 if (! this->sysinfo
.empty () && ! that
.sysinfo
.empty () &&
116 this->sysinfo
!= that
.sysinfo
)
118 if (! this->certinfo
.empty () && ! that
.certinfo
.empty () &&
119 this->certinfo
!= that
.certinfo
)
125 ostream
&operator<< (ostream
&s
, const compile_server_info
&i
);
127 struct compile_server_cache
129 vector
<compile_server_info
> default_servers
;
130 vector
<compile_server_info
> specified_servers
;
131 vector
<compile_server_info
> trusted_servers
;
132 vector
<compile_server_info
> signing_servers
;
133 vector
<compile_server_info
> online_servers
;
136 // For filtering queries.
137 enum compile_server_properties
{
138 compile_server_all
= 0x1,
139 compile_server_trusted
= 0x2,
140 compile_server_online
= 0x4,
141 compile_server_compatible
= 0x8,
142 compile_server_signer
= 0x10,
143 compile_server_specified
= 0x20
147 static compile_server_cache
* cscache(systemtap_session
& s
);
148 static void query_server_status (systemtap_session
&s
, const string
&status_string
);
150 static void get_server_info (systemtap_session
&s
, int pmask
, vector
<compile_server_info
> &servers
);
151 static void get_all_server_info (systemtap_session
&s
, vector
<compile_server_info
> &servers
);
152 static void get_default_server_info (systemtap_session
&s
, vector
<compile_server_info
> &servers
);
153 static void get_specified_server_info (systemtap_session
&s
, vector
<compile_server_info
> &servers
, bool no_default
= false);
154 static void get_or_keep_online_server_info (systemtap_session
&s
, vector
<compile_server_info
> &servers
, bool keep
);
155 static void get_or_keep_trusted_server_info (systemtap_session
&s
, vector
<compile_server_info
> &servers
, bool keep
);
156 static void get_or_keep_signing_server_info (systemtap_session
&s
, vector
<compile_server_info
> &servers
, bool keep
);
157 static void get_or_keep_compatible_server_info (systemtap_session
&s
, vector
<compile_server_info
> &servers
, bool keep
);
158 static void keep_common_server_info (const compile_server_info
&info_to_keep
, vector
<compile_server_info
> &filtered_info
);
159 static void keep_common_server_info (const vector
<compile_server_info
> &info_to_keep
, vector
<compile_server_info
> &filtered_info
);
160 static void keep_server_info_with_cert_and_port (systemtap_session
&s
, const compile_server_info
&server
, vector
<compile_server_info
> &servers
);
162 static void add_server_info (const compile_server_info
&info
, vector
<compile_server_info
>& list
);
163 static void add_server_info (const vector
<compile_server_info
> &source
, vector
<compile_server_info
> &target
);
164 static void merge_server_info (const compile_server_info
&source
, compile_server_info
&target
);
165 #if 0 // not used right now
166 static void merge_server_info (const compile_server_info
&source
, vector
<compile_server_info
> &target
);
167 static void merge_server_info (const vector
<compile_server_info
> &source
, vector
<compile_server_info
> &target
);
169 static void resolve_host (systemtap_session
& s
, compile_server_info
&server
, vector
<compile_server_info
> &servers
);
171 /* Exit error codes */
173 #define GENERAL_ERROR 1
174 #define CA_CERT_INVALID_ERROR 2
175 #define SERVER_CERT_EXPIRED_ERROR 3
178 // -----------------------------------------------------
179 // NSS related code used by the compile server client
180 // -----------------------------------------------------
181 static void add_server_trust (systemtap_session
&s
, const string
&cert_db_path
, const vector
<compile_server_info
> &server_list
);
182 static void revoke_server_trust (systemtap_session
&s
, const string
&cert_db_path
, const vector
<compile_server_info
> &server_list
);
183 static void get_server_info_from_db (systemtap_session
&s
, vector
<compile_server_info
> &servers
, const string
&cert_db_path
);
186 private_ssl_cert_db_path ()
188 return local_client_cert_db_path ();
192 global_ssl_cert_db_path ()
194 return global_client_cert_db_path ();
198 signing_cert_db_path ()
200 return SYSCONFDIR
"/systemtap/staprun";
203 /* Connection state. */
204 typedef struct connectionState_t
206 const char *hostName
;
209 const char *infileName
;
210 const char *outfileName
;
211 const char *trustNewServerMode
;
214 #if 0 /* No client authorization */
216 myPasswd(PK11SlotInfo
*info
, PRBool retry
, void *arg
)
218 char * passwd
= NULL
;
220 if ( (!retry
) && arg
)
221 passwd
= PORT_Strdup((char *)arg
);
227 /* Add the server's certificate to our database of trusted servers. */
229 trustNewServer (CERTCertificate
*serverCert
)
232 CERTCertTrust
*trust
= NULL
;
233 PK11SlotInfo
*slot
= NULL
;
235 /* Import the certificate. */
236 slot
= PK11_GetInternalKeySlot();
237 const char *nickname
= server_cert_nickname ();
238 secStatus
= PK11_ImportCert(slot
, serverCert
, CK_INVALID_HANDLE
, nickname
, PR_FALSE
);
239 if (secStatus
!= SECSuccess
)
242 /* Make it a trusted peer. */
243 trust
= (CERTCertTrust
*)PORT_ZAlloc(sizeof(CERTCertTrust
));
246 secStatus
= SECFailure
;
250 secStatus
= CERT_DecodeTrustString(trust
, "P,P,P");
251 if (secStatus
!= SECSuccess
)
254 secStatus
= CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), serverCert
, trust
);
258 PK11_FreeSlot (slot
);
264 /* Called when the server certificate verification fails. This gives us
265 the chance to trust the server anyway and add the certificate to the
268 badCertHandler(void *arg
, PRFileDesc
*sslSocket
)
271 PRErrorCode errorNumber
;
272 CERTCertificate
*serverCert
= NULL
;
274 PRArenaPool
*tmpArena
= NULL
;
275 CERTGeneralName
*nameList
, *current
;
276 char *expected
= NULL
;
277 const connectionState_t
*connectionState
= (connectionState_t
*)arg
;
279 errorNumber
= PR_GetError ();
282 case SSL_ERROR_BAD_CERT_DOMAIN
:
283 /* Since we administer our own client-side databases of trustworthy
284 certificates, we don't need the domain name(s) on the certificate to
285 match. If the cert is in our database, then we can trust it.
286 Issue a warning and accept the certificate. */
287 expected
= SSL_RevealURL (sslSocket
);
288 fprintf (stderr
, STAP_CSC_01
, expected
);
290 /* List the DNS names from the server cert as part of the warning.
291 First, find the alt-name extension on the certificate. */
292 subAltName
.data
= NULL
;
293 serverCert
= SSL_PeerCertificate (sslSocket
);
294 secStatus
= CERT_FindCertExtension (serverCert
,
295 SEC_OID_X509_SUBJECT_ALT_NAME
,
297 if (secStatus
!= SECSuccess
|| ! subAltName
.data
)
299 fprintf (stderr
, _("Unable to find alt name extension on the server certificate\n"));
300 secStatus
= SECSuccess
; /* Not a fatal error */
304 // Now, decode the extension.
305 tmpArena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
308 fprintf (stderr
, _("Out of memory\n"));
309 secStatus
= SECSuccess
; /* Not a fatal error here */
312 nameList
= CERT_DecodeAltNameExtension (tmpArena
, & subAltName
);
313 SECITEM_FreeItem(& subAltName
, PR_FALSE
);
316 fprintf (stderr
, _("Unable to decode alt name extension on server certificate\n"));
317 secStatus
= SECSuccess
; /* Not a fatal error */
321 /* List the DNS names from the server cert as part of the warning.
322 The names are in a circular list. */
326 /* Make sure this is a DNS name. */
327 if (current
->type
== certDNSName
)
329 fprintf (stderr
, " %.*s\n",
330 (int)current
->name
.other
.len
, current
->name
.other
.data
);
332 current
= CERT_GetNextGeneralName (current
);
334 while (current
!= nameList
);
336 /* Accept the certificate */
337 secStatus
= SECSuccess
;
340 case SEC_ERROR_CA_CERT_INVALID
:
341 /* The server's certificate is not trusted. Should we trust it? */
342 secStatus
= SECFailure
; /* Do not trust by default. */
343 if (! connectionState
->trustNewServerMode
)
346 /* Trust it for this session only? */
347 if (strcmp (connectionState
->trustNewServerMode
, "session") == 0)
349 secStatus
= SECSuccess
;
353 /* Trust it permanently? */
354 if (strcmp (connectionState
->trustNewServerMode
, "permanent") == 0)
356 /* The user wants to trust this server. Get the server's certificate so
357 and add it to our database. */
358 serverCert
= SSL_PeerCertificate (sslSocket
);
359 if (serverCert
!= NULL
)
361 secStatus
= trustNewServer (serverCert
);
366 secStatus
= SECFailure
; /* Do not trust this server */
371 PORT_Free (expected
);
373 PORT_FreeArena (tmpArena
, PR_FALSE
);
375 if (serverCert
!= NULL
)
377 CERT_DestroyCertificate (serverCert
);
384 setupSSLSocket (connectionState_t
*connectionState
)
386 PRFileDesc
*tcpSocket
;
387 PRFileDesc
*sslSocket
;
388 PRSocketOptionData socketOption
;
392 tcpSocket
= PR_NewTCPSocket();
393 if (tcpSocket
== NULL
)
396 /* Make the socket blocking. */
397 socketOption
.option
= PR_SockOpt_Nonblocking
;
398 socketOption
.value
.non_blocking
= PR_FALSE
;
400 prStatus
= PR_SetSocketOption(tcpSocket
, &socketOption
);
401 if (prStatus
!= PR_SUCCESS
)
404 /* Import the socket into the SSL layer. */
405 sslSocket
= SSL_ImportFD(NULL
, tcpSocket
);
409 /* Set configuration options. */
410 secStatus
= SSL_OptionSet(sslSocket
, SSL_SECURITY
, PR_TRUE
);
411 if (secStatus
!= SECSuccess
)
414 secStatus
= SSL_OptionSet(sslSocket
, SSL_HANDSHAKE_AS_CLIENT
, PR_TRUE
);
415 if (secStatus
!= SECSuccess
)
418 /* Set SSL callback routines. */
419 #if 0 /* no client authentication */
420 secStatus
= SSL_GetClientAuthDataHook(sslSocket
,
421 (SSLGetClientAuthData
)myGetClientAuthData
,
422 (void *)certNickname
);
423 if (secStatus
!= SECSuccess
)
426 #if 0 /* Use the default */
427 secStatus
= SSL_AuthCertificateHook(sslSocket
,
428 (SSLAuthCertificate
)myAuthCertificate
,
429 (void *)CERT_GetDefaultCertDB());
430 if (secStatus
!= SECSuccess
)
434 secStatus
= SSL_BadCertHook(sslSocket
, (SSLBadCertHandler
)badCertHandler
,
436 if (secStatus
!= SECSuccess
)
439 #if 0 /* No handshake callback */
440 secStatus
= SSL_HandshakeCallback(sslSocket
, myHandshakeCallback
, NULL
);
441 if (secStatus
!= SECSuccess
)
455 handle_connection (PRFileDesc
*sslSocket
, connectionState_t
*connectionState
)
460 PRFileDesc
*local_file_fd
;
462 SECStatus secStatus
= SECSuccess
;
464 #define READ_BUFFER_SIZE (60 * 1024)
466 /* If we don't have both the input and output file names, then we're
467 contacting this server only in order to establish trust. In this case send
468 0 as the file size and exit. */
469 if (! connectionState
->infileName
|| ! connectionState
->outfileName
)
471 numBytes
= htonl ((PRInt32
)0);
472 numBytes
= PR_Write (sslSocket
, & numBytes
, sizeof (numBytes
));
478 /* read and send the data. */
479 /* Try to open the local file named.
480 * If successful, then write it to the server
482 prStatus
= PR_GetFileInfo(connectionState
->infileName
, &info
);
483 if (prStatus
!= PR_SUCCESS
||
484 info
.type
!= PR_FILE_FILE
||
487 fprintf (stderr
, STAP_CSC_02
,
488 connectionState
->infileName
);
492 local_file_fd
= PR_Open(connectionState
->infileName
, PR_RDONLY
, 0);
493 if (local_file_fd
== NULL
)
495 fprintf (stderr
, STAP_CSC_03
, connectionState
->infileName
);
499 /* Send the file size first, so the server knows when it has the entire file. */
500 numBytes
= htonl ((PRInt32
)info
.size
);
501 numBytes
= PR_Write(sslSocket
, & numBytes
, sizeof (numBytes
));
504 PR_Close(local_file_fd
);
508 /* Transmit the local file across the socket. */
509 numBytes
= PR_TransmitFile(sslSocket
, local_file_fd
,
511 PR_TRANSMITFILE_KEEP_OPEN
,
512 PR_INTERVAL_NO_TIMEOUT
);
515 PR_Close(local_file_fd
);
519 PR_Close(local_file_fd
);
522 readBuffer
= (char *)PORT_Alloc(READ_BUFFER_SIZE
);
524 fprintf (stderr
, _("Out of memory\n"));
528 local_file_fd
= PR_Open(connectionState
->outfileName
, PR_WRONLY
| PR_CREATE_FILE
| PR_TRUNCATE
,
529 PR_IRUSR
| PR_IWUSR
| PR_IRGRP
| PR_IWGRP
| PR_IROTH
);
530 if (local_file_fd
== NULL
)
532 fprintf (stderr
, STAP_CSC_04
, connectionState
->outfileName
);
537 numBytes
= PR_Read(sslSocket
, readBuffer
, READ_BUFFER_SIZE
);
543 secStatus
= SECFailure
;
547 /* Write to output file */
548 numBytes
= PR_Write(local_file_fd
, readBuffer
, numBytes
);
551 fprintf (stderr
, STAP_CSC_05
, connectionState
->outfileName
);
552 secStatus
= SECFailure
;
558 PR_Close(local_file_fd
);
560 /* Caller closes the socket. */
564 /* make the connection.
567 do_connect (connectionState_t
*connectionState
)
569 PRFileDesc
*sslSocket
;
573 secStatus
= SECSuccess
;
575 /* Set up SSL secure socket. */
576 sslSocket
= setupSSLSocket (connectionState
);
577 if (sslSocket
== NULL
)
580 #if 0 /* no client authentication */
581 secStatus
= SSL_SetPKCS11PinArg(sslSocket
, password
);
582 if (secStatus
!= SECSuccess
)
586 secStatus
= SSL_SetURL(sslSocket
, connectionState
->hostName
);
587 if (secStatus
!= SECSuccess
)
590 prStatus
= PR_Connect(sslSocket
, & connectionState
->addr
, PR_INTERVAL_NO_TIMEOUT
);
591 if (prStatus
!= PR_SUCCESS
)
593 secStatus
= SECFailure
;
597 /* Established SSL connection, ready to send data. */
598 secStatus
= SSL_ResetHandshake(sslSocket
, /* asServer */ PR_FALSE
);
599 if (secStatus
!= SECSuccess
)
602 /* This is normally done automatically on the first I/O operation,
603 but doing it here catches any authentication problems early. */
604 secStatus
= SSL_ForceHandshake(sslSocket
);
605 if (secStatus
!= SECSuccess
)
608 // Connect to the server and make the request.
609 secStatus
= handle_connection(sslSocket
, connectionState
);
612 prStatus
= PR_Close(sslSocket
);
617 client_connect (const char *hostName
, PRUint32 ip
,
619 const char* infileName
, const char* outfileName
,
620 const char* trustNewServer
)
626 PRErrorCode errorNumber
;
627 char buffer
[PR_NETDB_BUF_SIZE
];
629 int errCode
= GENERAL_ERROR
;
630 struct connectionState_t connectionState
;
632 connectionState
.hostName
= hostName
;
633 connectionState
.port
= port
;
634 connectionState
.infileName
= infileName
;
635 connectionState
.outfileName
= outfileName
;
636 connectionState
.trustNewServerMode
= trustNewServer
;
638 /* Setup network connection. If we have an ip address, then
639 simply use it, otherwise we need to resolve the host name. */
642 connectionState
.addr
.inet
.family
= PR_AF_INET
;
643 connectionState
.addr
.inet
.port
= htons (port
);
644 connectionState
.addr
.inet
.ip
= htonl (ip
);
648 prStatus
= PR_GetHostByName(hostName
, buffer
, sizeof (buffer
), &hostEntry
);
649 if (prStatus
!= PR_SUCCESS
) {
650 fprintf (stderr
, _("Unable to resolve server host name"));
654 rv
= PR_EnumerateHostEnt(0, &hostEntry
, port
, &connectionState
.addr
);
656 fprintf (stderr
, _("Unable to resolve server host address"));
661 /* Some errors (see below) represent a situation in which trying again
662 should succeed. However, don't try forever. */
663 for (attempt
= 0; attempt
< 5; ++attempt
)
665 secStatus
= do_connect (& connectionState
);
666 if (secStatus
== SECSuccess
)
669 errorNumber
= PR_GetError ();
672 case PR_CONNECT_RESET_ERROR
:
673 /* Server was not ready. */
675 break; /* Try again */
676 case SEC_ERROR_EXPIRED_CERTIFICATE
:
677 /* The server's certificate has expired. It should
678 generate a new certificate. Return now and we'll try again. */
679 errCode
= SERVER_CERT_EXPIRED_ERROR
;
681 case SEC_ERROR_CA_CERT_INVALID
:
682 /* The server's certificate is not trusted. The exit code must
684 errCode
= CA_CERT_INVALID_ERROR
;
687 /* This error is fatal. */
696 static compile_server_cache
*
697 cscache(systemtap_session
& s
)
700 s
.server_cache
= new compile_server_cache();
701 return s
.server_cache
;
705 compile_server_client::passes_0_4 ()
707 PROBE1(stap
, client__start
, &s
);
710 // This code will never be called, if we don't have NSS, but it must still
714 // arguments parsed; get down to business
716 clog
<< _("Using a compile server") << endl
;
718 struct tms tms_before
;
719 times (& tms_before
);
720 struct timeval tv_before
;
721 gettimeofday (&tv_before
, NULL
);
723 // Create the request package.
724 int rc
= initialize ();
725 if (rc
!= 0 || pending_interrupts
) goto done
;
726 rc
= create_request ();
727 if (rc
!= 0 || pending_interrupts
) goto done
;
728 rc
= package_request ();
729 if (rc
!= 0 || pending_interrupts
) goto done
;
731 // Submit it to the server.
732 rc
= find_and_connect_to_server ();
733 if (rc
!= 0 || pending_interrupts
) goto done
;
735 // Unpack and process the response.
736 rc
= unpack_response ();
737 if (rc
!= 0 || pending_interrupts
) goto done
;
738 rc
= process_response ();
740 if (rc
== 0 && s
.last_pass
== 4)
742 cout
<< s
.module_name
+ ".ko";
747 struct tms tms_after
;
749 unsigned _sc_clk_tck
= sysconf (_SC_CLK_TCK
);
750 struct timeval tv_after
;
751 gettimeofday (&tv_after
, NULL
);
753 #define TIMESPRINT "in " << \
754 (tms_after.tms_cutime + tms_after.tms_utime \
755 - tms_before.tms_cutime - tms_before.tms_utime) * 1000 / (_sc_clk_tck) << "usr/" \
756 << (tms_after.tms_cstime + tms_after.tms_stime \
757 - tms_before.tms_cstime - tms_before.tms_stime) * 1000 / (_sc_clk_tck) << "sys/" \
758 << ((tv_after.tv_sec - tv_before.tv_sec) * 1000 + \
759 ((long)tv_after.tv_usec - (long)tv_before.tv_usec) / 1000) << "real ms."
761 // syntax errors, if any, are already printed
764 clog
<< _("Passes: via server ") << s
.winning_server
<< " "
772 // Save the module, if necessary.
773 if (s
.last_pass
== 4)
774 s
.save_module
= true;
776 // Copy module to the current directory.
777 if (s
.save_module
&& ! pending_interrupts
)
779 string module_src_path
= s
.tmpdir
+ "/" + s
.module_name
+ ".ko";
780 string module_dest_path
= s
.module_name
+ ".ko";
781 copy_file (module_src_path
, module_dest_path
, s
.verbose
> 1);
782 // Also copy the module signature, it it exists.
783 module_src_path
+= ".sgn";
784 if (file_exists (module_src_path
))
786 module_dest_path
+= ".sgn";
787 copy_file(module_src_path
, module_dest_path
, s
.verbose
> 1);
792 PROBE1(stap
, client__end
, &s
);
799 // Initialize a client/server session.
801 compile_server_client::initialize ()
805 // Initialize session state
808 // Private location for server certificates.
809 private_ssl_dbs
.push_back (private_ssl_cert_db_path ());
811 // Additional public location.
812 public_ssl_dbs
.push_back (global_ssl_cert_db_path ());
814 // Create a temporary directory to package things in.
815 client_tmpdir
= s
.tmpdir
+ "/client";
816 rc
= create_dir (client_tmpdir
.c_str ());
819 const char* e
= strerror (errno
);
820 clog
<< _("ERROR: cannot create temporary directory (\"")
821 << client_tmpdir
<< "\"): " << e
828 // Create the request package.
830 compile_server_client::create_request ()
832 // Add the current protocol version.
833 int rc
= write_to_file (client_tmpdir
+ "/version", CURRENT_CS_PROTOCOL_VERSION
);
837 // Add the script file or script option
838 if (s
.script_file
!= "")
840 if (s
.script_file
== "-")
842 // Copy the script from stdin
843 string packaged_script_dir
= client_tmpdir
+ "/script";
844 rc
= create_dir (packaged_script_dir
.c_str ());
847 const char* e
= strerror (errno
);
848 clog
<< _("ERROR: cannot create temporary directory ")
849 << packaged_script_dir
<< ": " << e
853 rc
= ! copy_file("/dev/stdin", packaged_script_dir
+ "/-");
857 // Name the script in the packaged arguments.
858 rc
= add_package_arg ("script/-");
864 // Add the script to our package. This will also name the script
865 // in the packaged arguments.
866 rc
= include_file_or_directory ("script", s
.script_file
);
872 // Add -I paths. Skip the default directory.
873 if (s
.include_arg_start
!= -1)
875 unsigned limit
= s
.include_path
.size ();
876 for (unsigned i
= s
.include_arg_start
; i
< limit
; ++i
)
878 rc
= add_package_arg ("-I");
881 rc
= include_file_or_directory ("tapset", s
.include_path
[i
]);
887 // Add other options.
888 rc
= add_package_args ();
892 // Add the sysinfo file
893 string sysinfo
= "sysinfo: " + s
.kernel_release
+ " " + s
.architecture
;
894 rc
= write_to_file (client_tmpdir
+ "/sysinfo", sysinfo
);
898 // Add localization data
899 rc
= add_localization_variables();
904 // Add the arguments specified on the command line to the server request
905 // package, as appropriate.
907 compile_server_client::add_package_args ()
909 // stap arguments to be passed to the server.
911 unsigned limit
= s
.server_args
.size();
912 for (unsigned i
= 0; i
< limit
; ++i
)
914 rc
= add_package_arg (s
.server_args
[i
]);
920 limit
= s
.args
.size();
922 rc
= add_package_arg ("--");
925 for (unsigned i
= 0; i
< limit
; ++i
)
927 rc
= add_package_arg (s
.args
[i
]);
936 compile_server_client::add_package_arg (const string
&arg
)
940 fname
<< client_tmpdir
<< "/argv" << ++argc
;
941 write_to_file (fname
.str (), arg
); // NB: No terminating newline
945 // Symbolically link the given file or directory into the client's temp
946 // directory under the given subdirectory.
948 compile_server_client::include_file_or_directory (
949 const string
&subdir
, const string
&path
, const char *option
952 // Must predeclare these because we do use 'goto done' to
953 // exit from error situations.
954 vector
<string
> components
;
958 // Canonicalize the given path and remove the leading /.
960 char *cpath
= canonicalize_file_name (path
.c_str ());
963 // It can not be canonicalized. Use the name relative to
964 // the current working directory and let the server deal with it.
966 if (getcwd (cwd
, sizeof (cwd
)) == NULL
)
972 rpath
= string (cwd
) + "/" + path
;
976 // It can be canonicalized. Use the canonicalized name and add this
977 // file or directory to the request package.
981 // First create the requested subdirectory.
982 name
= client_tmpdir
+ "/" + subdir
;
983 rc
= create_dir (name
.c_str ());
986 // Now create each component of the path within the sub directory.
987 assert (rpath
[0] == '/');
988 tokenize (rpath
.substr (1), components
, "/");
989 assert (components
.size () >= 1);
991 for (i
= 0; i
< components
.size() - 1; ++i
)
993 if (components
[i
].empty ())
994 continue; // embedded '//'
995 name
+= "/" + components
[i
];
996 rc
= create_dir (name
.c_str ());
1000 // Now make a symbolic link to the actual file or directory.
1001 assert (i
== components
.size () - 1);
1002 name
+= "/" + components
[i
];
1003 rc
= symlink (rpath
.c_str (), name
.c_str ());
1007 // Name this file or directory in the packaged arguments along with any
1008 // associated option.
1011 rc
= add_package_arg (option
);
1015 rc
= add_package_arg (subdir
+ "/" + rpath
.substr (1));
1020 const char* e
= strerror (errno
);
1021 clog
<< "ERROR: unable to add "
1023 << " to temp directory as "
1024 << name
<< ": " << e
1030 // Add the localization variables to the server request
1033 compile_server_client::add_localization_variables()
1039 const set
<string
> &locVars
= localization_variables();
1040 set
<string
>::iterator it
;
1042 /* Note: We don't have to check for the contents of the environment
1043 * variables here, since they will be checked extensively on the
1046 for (it
= locVars
.begin(); it
!= locVars
.end(); it
++)
1048 char* var
= getenv((*it
).c_str());
1050 envVar
+= *it
+ "=" + (string
)var
+ "\n";
1052 fname
= client_tmpdir
+ "/locale";
1053 rc
= write_to_file(fname
, envVar
);
1057 // Package the client's temp directory into a form suitable for sending to the
1060 compile_server_client::package_request ()
1062 // Package up the temporary directory into a zip file.
1063 client_zipfile
= client_tmpdir
+ ".zip";
1064 string cmd
= "cd " + cmdstr_quoted(client_tmpdir
) + " && zip -qr "
1065 + cmdstr_quoted(client_zipfile
) + " *";
1066 vector
<string
> sh_cmd
;
1067 sh_cmd
.push_back("sh");
1068 sh_cmd
.push_back("-c");
1069 sh_cmd
.push_back(cmd
);
1070 int rc
= stap_system (s
.verbose
, sh_cmd
);
1075 compile_server_client::find_and_connect_to_server ()
1077 // Accumulate info on the specified servers.
1078 vector
<compile_server_info
> specified_servers
;
1079 get_specified_server_info (s
, specified_servers
);
1081 // Examine the specified servers to make sure that each has been resolved
1082 // with a host name, ip address and port. If not, try to obtain this
1083 // information by examining online servers.
1084 vector
<compile_server_info
> server_list
= specified_servers
;
1085 for (vector
<compile_server_info
>::const_iterator i
= specified_servers
.begin ();
1086 i
!= specified_servers
.end ();
1089 // If we have an ip address and port number, then just use the one we've
1090 // been given. Otherwise, check for matching online servers and try their
1091 // ip addresses and ports.
1092 if (! i
->host_name
.empty () && ! i
->ip_address
.empty () && i
->port
!= 0)
1093 add_server_info (*i
, server_list
);
1096 // Obtain a list of online servers.
1097 vector
<compile_server_info
> online_servers
;
1098 get_or_keep_online_server_info (s
, online_servers
, false/*keep*/);
1100 // If no specific server (port) has been specified,
1101 // then we'll need the servers to be
1102 // compatible and possible trusted as signers as well.
1105 get_or_keep_compatible_server_info (s
, online_servers
, true/*keep*/);
1107 get_or_keep_signing_server_info (s
, online_servers
, true/*keep*/);
1110 // Keep the ones (if any) which match our server.
1111 keep_common_server_info (*i
, online_servers
);
1113 // Add these servers (if any) to the server list.
1114 add_server_info (online_servers
, server_list
);
1118 // Did we identify any potential servers?
1119 unsigned limit
= server_list
.size ();
1122 clog
<< _("Unable to find a server") << endl
;
1126 // Now try each of the identified servers in turn.
1127 int rc
= compile_using_server (server_list
);
1129 return 0; // success!
1131 // If the error was that a server's cert was expired, try again. This is because the server
1132 // should generate a new cert which may be automatically trusted by us if it is our server.
1133 // Give the server a chance to do this before retrying.
1134 if (rc
== SERVER_CERT_EXPIRED_ERROR
)
1137 clog
<< _("A server's certificate was expired. Trying again") << endl
<< flush
;
1139 rc
= compile_using_server (server_list
);
1141 return 0; // success!
1144 // We were unable to use any available server
1145 clog
<< _("Unable to connect to a server") << endl
;
1146 return 1; // Failure
1150 // Convert the given string to an ip address in host byte order.
1152 stringToIpAddress (const string
&s
)
1155 return 0; // unknown
1157 vector
<string
>components
;
1158 tokenize (s
, components
, ".");
1159 assert (components
.size () >= 1);
1163 for (i
= 0; i
< components
.size (); ++i
)
1165 const char *ipstr
= components
[i
].c_str ();
1168 unsigned a
= strtoul (ipstr
, & estr
, 10);
1169 if (errno
== 0 && *estr
== '\0' && a
<= UCHAR_MAX
)
1179 compile_server_client::compile_using_server (
1180 const vector
<compile_server_info
> &servers
1183 // This code will never be called if we don't have NSS, but it must still
1186 // Make sure NSPR is initialized. Must be done before NSS is initialized
1189 // Attempt connection using each of the available client certificate
1190 // databases. Assume the server certificate is invalid until proven otherwise.
1191 PR_SetError (SEC_ERROR_CA_CERT_INVALID
, 0);
1192 vector
<string
> dbs
= private_ssl_dbs
;
1193 vector
<string
>::iterator i
= dbs
.end();
1194 dbs
.insert (i
, public_ssl_dbs
.begin (), public_ssl_dbs
.end ());
1195 int rc
= GENERAL_ERROR
; // assume failure
1196 bool serverCertExpired
= false;
1197 for (i
= dbs
.begin (); i
!= dbs
.end (); ++i
)
1199 // Make sure the database directory exists. It is not an error if it
1201 if (! file_exists (*i
))
1204 #if 0 // no client authentication for now.
1205 // Set our password function callback.
1206 PK11_SetPasswordFunc (myPasswd
);
1209 // Initialize the NSS libraries.
1210 const char *cert_dir
= i
->c_str ();
1211 SECStatus secStatus
= nssInit (cert_dir
);
1212 if (secStatus
!= SECSuccess
)
1214 // Message already issued.
1215 continue; // try next database
1218 // Enable cipher suites which are allowed by U.S. export regulations.
1219 // SSL_ClearSessionCache is required for the new settings to take effect.
1220 secStatus
= NSS_SetExportPolicy ();
1221 SSL_ClearSessionCache ();
1222 if (secStatus
!= SECSuccess
)
1224 clog
<< _("Unable to set NSS export policy");
1226 nssCleanup (cert_dir
);
1227 continue; // try next database
1230 server_zipfile
= s
.tmpdir
+ "/server.zip";
1232 // Try each server in turn.
1233 for (vector
<compile_server_info
>::const_iterator j
= servers
.begin ();
1234 j
!= servers
.end ();
1238 clog
<< _F("Attempting SSL connection with %s\n"
1239 " using certificates from the database in %s\n",
1240 lex_cast(*j
).c_str(), cert_dir
);
1242 // The host name defaults to the ip address, if not specified.
1244 if (j
->host_name
.empty ())
1246 assert (! j
->ip_address
.empty ());
1247 hostName
= j
->ip_address
;
1250 hostName
= j
->host_name
;
1252 rc
= client_connect (hostName
.c_str (),
1253 stringToIpAddress (j
->ip_address
),
1255 client_zipfile
.c_str(), server_zipfile
.c_str (),
1256 NULL
/*trustNewServer_p*/);
1260 hostName
+ string(" [") +
1261 j
->ip_address
+ string(":") +
1262 lex_cast(j
->port
) + string("]");
1266 // Server cert has expired. Try other servers and/or databases, but take note because
1267 // server should generate a new certificate. If no other servers succeed, we'll try again
1268 // in case the new cert works.
1269 if (rc
== SERVER_CERT_EXPIRED_ERROR
)
1271 serverCertExpired
= true;
1277 clog
<< _(" Unable to connect: ");
1282 // SSL_ClearSessionCache is required before shutdown for client applications.
1283 SSL_ClearSessionCache ();
1284 nssCleanup (cert_dir
);
1286 if (rc
== SECSuccess
)
1290 // Indicate whether a server cert was expired, so we can try again, if desired.
1293 if (serverCertExpired
)
1294 rc
= SERVER_CERT_EXPIRED_ERROR
;
1300 return GENERAL_ERROR
;
1305 compile_server_client::unpack_response ()
1307 // Unzip the response package.
1308 server_tmpdir
= s
.tmpdir
+ "/server";
1310 cmd
.push_back("unzip");
1311 cmd
.push_back("-qd");
1312 cmd
.push_back(server_tmpdir
);
1313 cmd
.push_back(server_zipfile
);
1314 int rc
= stap_system (s
.verbose
, cmd
);
1317 clog
<< _F("Unable to unzip the server response '%s'\n", server_zipfile
.c_str());
1321 // Determine the server protocol version.
1322 cs_protocol_version server_version
;
1323 string filename
= server_tmpdir
+ "/version";
1324 if (file_exists (filename
))
1325 ::read_from_file (filename
, server_version
);
1327 // Warn about the shortcomings of this server, if it is down level.
1328 show_server_compatibility (server_version
);
1330 // If the server's response contains a systemtap temp directory, move
1331 // its contents to our temp directory.
1333 string filespec
= server_tmpdir
+ "/stap??????";
1335 clog
<< _F("Searching \"%s\"\n", filespec
.c_str());
1336 int r
= glob(filespec
.c_str (), 0, NULL
, & globbuf
);
1337 if (r
!= GLOB_NOSPACE
&& r
!= GLOB_ABORTED
&& r
!= GLOB_NOMATCH
)
1339 if (globbuf
.gl_pathc
> 1)
1341 clog
<< _("Incorrect number of files in server response") << endl
;
1346 assert (globbuf
.gl_pathc
== 1);
1347 string dirname
= globbuf
.gl_pathv
[0];
1349 clog
<< _(" found ") << dirname
<< endl
;
1351 filespec
= dirname
+ "/*";
1353 clog
<< _F("Searching \"%s\"\n", filespec
.c_str());
1354 int r
= glob(filespec
.c_str (), GLOB_PERIOD
, NULL
, & globbuf
);
1355 if (r
!= GLOB_NOSPACE
&& r
!= GLOB_ABORTED
&& r
!= GLOB_NOMATCH
)
1357 unsigned prefix_len
= dirname
.size () + 1;
1358 for (unsigned i
= 0; i
< globbuf
.gl_pathc
; ++i
)
1360 string oldname
= globbuf
.gl_pathv
[i
];
1361 if (oldname
.substr (oldname
.size () - 2) == "/." ||
1362 oldname
.substr (oldname
.size () - 3) == "/..")
1364 string newname
= s
.tmpdir
+ "/" + oldname
.substr (prefix_len
);
1366 clog
<< _F(" found %s -- linking from %s", oldname
.c_str(), newname
.c_str());
1367 rc
= symlink (oldname
.c_str (), newname
.c_str ());
1370 clog
<< _F("Unable to link '%s' to '%s':%s\n",
1371 oldname
.c_str(), newname
.c_str(), strerror(errno
));
1378 // If the server version is less that 1.6, remove the output line due to the synthetic
1379 // server-side -k. Look for a message containing the name of the temporary directory.
1380 // We can look for the English message since server versions before 1.1 do not support
1382 if (server_version
< "1.6")
1385 cmd
.push_back("sed");
1386 cmd
.push_back("-i");
1387 cmd
.push_back("/^Keeping temporary directory.*/ d");
1388 cmd
.push_back(server_tmpdir
+ "/stderr");
1389 stap_system (s
.verbose
, cmd
);
1392 // Remove the output line due to the synthetic server-side -p4
1394 cmd
.push_back("sed");
1395 cmd
.push_back("-i");
1396 cmd
.push_back("/^.*\\.ko$/ d");
1397 cmd
.push_back(server_tmpdir
+ "/stdout");
1398 stap_system (s
.verbose
, cmd
);
1401 globfree (& globbuf
);
1406 compile_server_client::process_response ()
1408 // Pick up the results of running stap on the server.
1409 string filename
= server_tmpdir
+ "/rc";
1411 int rc
= read_from_file (filename
, stap_rc
);
1416 if (s
.last_pass
>= 4)
1418 // The server should have returned a module.
1419 string filespec
= s
.tmpdir
+ "/*.ko";
1421 clog
<< _F("Searching \"%s\"\n", filespec
.c_str());
1424 int r
= glob(filespec
.c_str (), 0, NULL
, & globbuf
);
1425 if (r
!= GLOB_NOSPACE
&& r
!= GLOB_ABORTED
&& r
!= GLOB_NOMATCH
)
1427 if (globbuf
.gl_pathc
> 1)
1428 clog
<< _("Incorrect number of modules in server response") << endl
;
1431 assert (globbuf
.gl_pathc
== 1);
1432 string modname
= globbuf
.gl_pathv
[0];
1434 clog
<< _(" found ") << modname
<< endl
;
1436 // If a module name was not specified by the user, then set it to
1437 // be the one generated by the server.
1438 if (! s
.save_module
)
1440 vector
<string
> components
;
1441 tokenize (modname
, components
, "/");
1442 s
.module_name
= components
.back ();
1443 s
.module_name
.erase(s
.module_name
.size() - 3);
1446 // If a uprobes.ko module was returned, then make note of it.
1447 if (file_exists (s
.tmpdir
+ "/server/uprobes.ko"))
1449 s
.need_uprobes
= true;
1450 s
.uprobes_path
= s
.tmpdir
+ "/server/uprobes.ko";
1454 else if (s
.have_script
)
1458 clog
<< _("No module was returned by the server") << endl
;
1462 globfree (& globbuf
);
1465 // Output stdout and stderr.
1466 filename
= server_tmpdir
+ "/stderr";
1467 flush_to_stream (filename
, clog
);
1469 filename
= server_tmpdir
+ "/stdout";
1470 flush_to_stream (filename
, cout
);
1476 compile_server_client::read_from_file (const string
&fname
, int &data
)
1478 // C++ streams may not set errno in the even of a failure. However if we
1479 // set it to 0 before each operation and it gets set during the operation,
1480 // then we can use its value in order to determine what happened.
1482 ifstream
f (fname
.c_str ());
1485 clog
<< _F("Unable to open file '%s' for reading: ", fname
.c_str());
1494 clog
<< _F("Unable to read from file '%s': ", fname
.c_str());
1498 // NB: not necessary to f.close ();
1499 return 0; // Success
1503 clog
<< strerror (errno
) << endl
;
1505 clog
<< _("unknown error") << endl
;
1506 return 1; // Failure
1511 compile_server_client::write_to_file (const string
&fname
, const T
&data
)
1513 // C++ streams may not set errno in the even of a failure. However if we
1514 // set it to 0 before each operation and it gets set during the operation,
1515 // then we can use its value in order to determine what happened.
1517 ofstream
f (fname
.c_str ());
1520 clog
<< _F("Unable to open file '%s' for writing: ", fname
.c_str());
1529 clog
<< _F("Unable to write to file '%s': ", fname
.c_str());
1533 // NB: not necessary to f.close ();
1534 return 0; // Success
1538 clog
<< strerror (errno
) << endl
;
1540 clog
<< _("unknown error") << endl
;
1541 return 1; // Failure
1545 compile_server_client::flush_to_stream (const string
&fname
, ostream
&o
)
1547 // C++ streams may not set errno in the even of a failure. However if we
1548 // set it to 0 before each operation and it gets set during the operation,
1549 // then we can use its value in order to determine what happened.
1551 ifstream
f (fname
.c_str ());
1554 clog
<< _F("Unable to open file '%s' for reading: ", fname
.c_str());
1560 // NB: o << f.rdbuf() misbehaves for some reason, appearing to close o,
1561 // which is unfortunate if o == clog or cout.
1566 if (f
.eof ()) return 0; // normal exit
1567 if (! f
.good()) break;
1569 if (! o
.good()) break;
1572 // NB: not necessary to f.close ();
1576 clog
<< strerror (errno
) << endl
;
1578 clog
<< _("unknown error") << endl
;
1579 return 1; // Failure
1583 compile_server_client::show_server_compatibility (const cs_protocol_version
&server_version
)
1585 // Locale sensitivity was added in version 1.6
1586 if (server_version
< "1.6")
1588 clog
<< _F("Server protocol version is %s\n", server_version
.v
);
1589 clog
<< _("The server does not use localization information passed by the client\n");
1595 // Utility Functions.
1596 //-----------------------------------------------------------------------
1597 ostream
&operator<< (ostream
&s
, const compile_server_info
&i
)
1600 if (! i
.host_name
.empty ())
1605 if (! i
.ip_address
.empty ())
1615 if (! i
.sysinfo
.empty ())
1616 s
<< i
.sysinfo
<< '"';
1620 if (! i
.version
.empty ())
1624 s
<< " certinfo=\"";
1625 if (! i
.certinfo
.empty ())
1626 s
<< i
.certinfo
<< '"';
1632 // Return the default server specification, used when none is given on the
1635 default_server_spec (const systemtap_session
&s
)
1637 // If the --use-server option has been used
1638 // the default is 'specified'
1639 // otherwise if the --unprivileged has been used
1640 // the default is online,trusted,compatible,signer
1642 // the default is online,compatible
1644 // Having said that,
1645 // 'online' and 'compatible' will only succeed if we have avahi
1646 // 'trusted' and 'signer' will only succeed if we have NSS
1648 string working_string
= "online,trusted,compatible";
1650 working_string
+= ",signer";
1651 return working_string
;
1655 server_spec_to_pmask (const string
&server_spec
)
1657 // Construct a mask of the server properties that have been requested.
1658 // The available properties are:
1659 // trusted - servers which are trusted SSL peers.
1660 // online - online servers.
1661 // compatible - servers which compile for the current kernel release
1662 // and architecture.
1663 // signer - servers which are trusted module signers.
1664 // specified - servers which have been specified using --use-server=XXX.
1665 // If no servers have been specified, then this is
1666 // equivalent to --list-servers=trusted,online,compatible.
1667 // all - all trusted servers, trusted module signers,
1668 // servers currently online and specified servers.
1669 string working_spec
= server_spec
;
1670 vector
<string
> properties
;
1671 tokenize (working_spec
, properties
, ",");
1673 unsigned limit
= properties
.size ();
1674 for (unsigned i
= 0; i
< limit
; ++i
)
1676 const string
&property
= properties
[i
];
1677 // Tolerate (and ignore) empty properties.
1678 if (property
.empty ())
1680 if (property
== "all")
1682 pmask
|= compile_server_all
;
1684 else if (property
== "specified")
1686 pmask
|= compile_server_specified
;
1688 else if (property
== "trusted")
1690 pmask
|= compile_server_trusted
;
1692 else if (property
== "online")
1694 pmask
|= compile_server_online
;
1696 else if (property
== "compatible")
1698 pmask
|= compile_server_compatible
;
1700 else if (property
== "signer")
1702 pmask
|= compile_server_signer
;
1706 clog
<< _F("Warning: unsupported compile server property: %s", property
.c_str())
1714 query_server_status (systemtap_session
&s
)
1716 // Make sure NSPR is initialized
1719 unsigned limit
= s
.server_status_strings
.size ();
1720 for (unsigned i
= 0; i
< limit
; ++i
)
1721 query_server_status (s
, s
.server_status_strings
[i
]);
1725 query_server_status (systemtap_session
&s
, const string
&status_string
)
1727 // If this string is empty, then the default is "specified"
1728 string working_string
= status_string
;
1729 if (working_string
.empty ())
1730 working_string
= "specified";
1732 // If the query is "specified" and no servers have been specified
1733 // (i.e. --use-server not used or used with no argument), then
1734 // use the default query.
1735 // TODO: This may not be necessary. The underlying queries should handle
1736 // "specified" properly.
1737 if (working_string
== "specified" &&
1738 (s
.specified_servers
.empty () ||
1739 (s
.specified_servers
.size () == 1 && s
.specified_servers
[0].empty ())))
1740 working_string
= default_server_spec (s
);
1742 int pmask
= server_spec_to_pmask (working_string
);
1744 // Now obtain a list of the servers which match the criteria.
1745 vector
<compile_server_info
> raw_servers
;
1746 get_server_info (s
, pmask
, raw_servers
);
1748 // Augment the listing with as much information as possible by adding
1749 // information from known servers.
1750 vector
<compile_server_info
> servers
;
1751 get_all_server_info (s
, servers
);
1752 keep_common_server_info (raw_servers
, servers
);
1754 // Print the server information. Skip the empty entry at the head of the list.
1755 clog
<< _F("Systemtap Compile Server Status for '%s'", working_string
.c_str()) << endl
;
1757 unsigned limit
= servers
.size ();
1758 for (unsigned i
= 0; i
< limit
; ++i
)
1760 assert (! servers
[i
].empty ());
1761 // Don't list servers with no cert information. They may not actually
1763 // TODO: Could try contacting the server and obtaining its cert
1764 if (servers
[i
].certinfo
.empty ())
1766 clog
<< servers
[i
] << endl
;
1770 clog
<< _("No servers found") << endl
;
1773 // Add or remove trust of the servers specified on the command line.
1775 manage_server_trust (systemtap_session
&s
)
1777 // This function will never be called if we don't have NSS, but it must
1780 // Nothing to do if --trust-servers was not specified.
1781 if (s
.server_trust_spec
.empty ())
1784 // Break up and analyze the trust specification. Recognized components are:
1785 // ssl - trust the specified servers as ssl peers
1786 // signer - trust the specified servers as module signers
1787 // revoke - revoke the requested trust
1788 // all-users - apply/revoke the requested trust for all users
1789 // no-prompt - don't prompt the user for confirmation
1790 vector
<string
>components
;
1791 tokenize (s
.server_trust_spec
, components
, ",");
1793 bool signer
= false;
1794 bool revoke
= false;
1795 bool all_users
= false;
1796 bool no_prompt
= false;
1798 for (vector
<string
>::const_iterator i
= components
.begin ();
1799 i
!= components
.end ();
1804 else if (*i
== "signer")
1806 if (geteuid () != 0)
1808 clog
<< _("Only root can specify 'signer' on --trust-servers") << endl
;
1814 else if (*i
== "revoke")
1816 else if (*i
== "all-users")
1818 if (geteuid () != 0)
1820 clog
<< _("Only root can specify 'all-users' on --trust-servers") << endl
;
1826 else if (*i
== "no-prompt")
1829 clog
<< _("Warning: Unrecognized server trust specification: ") << *i
1835 // Make sure NSPR is initialized
1838 // Now obtain the list of specified servers.
1839 vector
<compile_server_info
> server_list
;
1840 get_specified_server_info (s
, server_list
, true/*no_default*/);
1842 // Did we identify any potential servers?
1843 unsigned limit
= server_list
.size ();
1846 clog
<< _("No servers identified for trust") << endl
;
1850 // Create a string representing the request in English.
1851 // If neither 'ssl' or 'signer' was specified, the default is 'ssl'.
1852 if (! ssl
&& ! signer
)
1854 ostringstream trustString
;
1857 trustString
<< _("as an SSL peer");
1859 trustString
<< _(" for all users");
1861 trustString
<< _(" for the current user");
1866 trustString
<< _(" and ");
1867 trustString
<< _("as a module signer for all users");
1870 // Prompt the user to confirm what's about to happen.
1874 clog
<< _("Revoking trust ");
1876 clog
<< _("Adding trust ");
1881 clog
<< _("Revoke trust ");
1883 clog
<< _("Add trust ");
1885 clog
<< _F("in the following servers %s", trustString
.str().c_str());
1889 for (unsigned i
= 0; i
< limit
; ++i
)
1890 clog
<< " " << server_list
[i
] << endl
;
1893 clog
<< "[y/N] " << flush
;
1895 // Only carry out the operation if the response is "yes"
1898 if (response
[0] != 'y' && response
[0] != 'Y')
1900 clog
<< _("Server trust unchanged") << endl
;
1905 // Now add/revoke the requested trust.
1906 string cert_db_path
;
1910 cert_db_path
= global_ssl_cert_db_path ();
1912 cert_db_path
= private_ssl_cert_db_path ();
1914 revoke_server_trust (s
, cert_db_path
, server_list
);
1916 add_server_trust (s
, cert_db_path
, server_list
);
1920 cert_db_path
= signing_cert_db_path ();
1922 revoke_server_trust (s
, cert_db_path
, server_list
);
1924 add_server_trust (s
, cert_db_path
, server_list
);
1930 // Issue a status message for when a server's trust is already in place.
1932 trust_already_in_place (
1933 const compile_server_info
&server
,
1934 const vector
<compile_server_info
> &server_list
,
1935 const string cert_db_path
,
1939 // What level of trust?
1941 if (cert_db_path
== signing_cert_db_path ())
1942 purpose
= _("as a module signer for all users");
1945 purpose
= _("as an SSL peer");
1946 if (cert_db_path
== global_ssl_cert_db_path ())
1947 purpose
+= _(" for all users");
1949 purpose
+= _(" for the current user");
1952 // Issue a message for each server in the list with the same certificate.
1953 unsigned limit
= server_list
.size ();
1954 for (unsigned i
= 0; i
< limit
; ++i
)
1956 if (server
.certinfo
!= server_list
[i
].certinfo
)
1958 clog
<< server_list
[i
] << _(" is already ");
1960 clog
<< _("untrusted ") << purpose
<< endl
;
1962 clog
<< _("trusted ") << purpose
<< endl
;
1966 // Add the given servers to the given database of trusted servers.
1969 systemtap_session
&s
,
1970 const string
&cert_db_path
,
1971 const vector
<compile_server_info
> &server_list
1974 // Get a list of servers already trusted. This opens the database, so do it
1975 // before we open it for our own purposes.
1976 vector
<compile_server_info
> already_trusted
;
1977 get_server_info_from_db (s
, already_trusted
, cert_db_path
);
1979 // Make sure the given path exists.
1980 if (create_dir (cert_db_path
.c_str (), 0755) != 0)
1982 clog
<< _F("Unable to find or create the client certificate database directory %s: ", cert_db_path
.c_str());
1987 // Must predeclare this because of jumps to cleanup: below.
1988 vector
<string
> processed_certs
;
1990 // Make sure NSPR is initialized. Must be done before NSS is initialized
1993 // Initialize the NSS libraries -- read/write
1994 SECStatus secStatus
= nssInit (cert_db_path
.c_str (), 1/*readwrite*/);
1995 if (secStatus
!= SECSuccess
)
1997 // Message already issued.
2001 // Enable cipher suites which are allowed by U.S. export regulations.
2002 // SSL_ClearSessionCache is required for the new settings to take effect.
2003 secStatus
= NSS_SetExportPolicy ();
2004 SSL_ClearSessionCache ();
2005 if (secStatus
!= SECSuccess
)
2007 clog
<< _("Unable to set NSS export policy");
2012 // Iterate over the servers to become trusted. Contact each one and
2013 // add it to the list of trusted servers if it is not already trusted.
2014 // client_connect will issue any error messages.
2015 for (vector
<compile_server_info
>::const_iterator server
= server_list
.begin();
2016 server
!= server_list
.end ();
2019 // Trust is based on certificates. We need only add trust in the
2020 // same certificate once.
2021 if (find (processed_certs
.begin (), processed_certs
.end (),
2022 server
->certinfo
) != processed_certs
.end ())
2024 processed_certs
.push_back (server
->certinfo
);
2026 // We need not contact the server if it is already trusted.
2027 if (find (already_trusted
.begin (), already_trusted
.end (), *server
) !=
2028 already_trusted
.end ())
2031 trust_already_in_place (*server
, server_list
, cert_db_path
, false/*revoking*/);
2034 // At a minimum we need a host name or ip_address along with a port
2035 // number in order to contact the server.
2036 if (server
->empty () || server
->port
== 0)
2038 int rc
= client_connect (server
->host_name
.c_str (),
2039 stringToIpAddress (server
->ip_address
),
2041 NULL
, NULL
, "permanent");
2044 clog
<< _F("Unable to connect to %s", lex_cast(*server
).c_str()) << endl
;
2051 // SSL_ClearSessionCache is required before shutdown for client applications.
2052 SSL_ClearSessionCache ();
2053 nssCleanup (cert_db_path
.c_str ());
2055 // Make sure the database files are readable.
2057 string filespec
= cert_db_path
+ "/*.db";
2059 clog
<< _F("Searching \"%s\"\n", filespec
.c_str());
2060 int r
= glob (filespec
.c_str (), 0, NULL
, & globbuf
);
2061 if (r
!= GLOB_NOSPACE
&& r
!= GLOB_ABORTED
&& r
!= GLOB_NOMATCH
)
2063 for (unsigned i
= 0; i
< globbuf
.gl_pathc
; ++i
)
2065 string filename
= globbuf
.gl_pathv
[i
];
2067 clog
<< _(" found ") << filename
<< endl
;
2069 if (chmod (filename
.c_str (), 0644) != 0)
2071 clog
<< _F("Warning: Unable to change permissions on %s: ", filename
.c_str());
2078 // Remove the given servers from the given database of trusted servers.
2080 revoke_server_trust (
2081 systemtap_session
&s
,
2082 const string
&cert_db_path
,
2083 const vector
<compile_server_info
> &server_list
2086 // Make sure the given path exists.
2087 if (! file_exists (cert_db_path
))
2090 clog
<< _F("Certificate database '%s' does not exist",
2091 cert_db_path
.c_str()) << endl
;
2094 for (vector
<compile_server_info
>::const_iterator server
= server_list
.begin();
2095 server
!= server_list
.end ();
2097 trust_already_in_place (*server
, server_list
, cert_db_path
, true/*revoking*/);
2102 // Must predeclare these because of jumps to cleanup: below.
2103 CERTCertDBHandle
*handle
;
2104 PRArenaPool
*tmpArena
= NULL
;
2105 CERTCertList
*certs
= NULL
;
2106 CERTCertificate
*db_cert
;
2107 vector
<string
> processed_certs
;
2108 const char *nickname
;
2110 // Make sure NSPR is initialized. Must be done before NSS is initialized
2113 // Initialize the NSS libraries -- read/write
2114 SECStatus secStatus
= nssInit (cert_db_path
.c_str (), 1/*readwrite*/);
2115 if (secStatus
!= SECSuccess
)
2117 // Message already issued
2120 handle
= CERT_GetDefaultCertDB();
2122 // A memory pool to work in
2123 tmpArena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
2126 clog
<< _("Out of memory:");
2131 // Iterate over the servers to become untrusted.
2132 nickname
= server_cert_nickname ();
2133 for (vector
<compile_server_info
>::const_iterator server
= server_list
.begin();
2134 server
!= server_list
.end ();
2137 // If the server's certificate serial number is unknown, then we can't
2138 // match it with one in the database.
2139 if (server
->certinfo
.empty ())
2142 // Trust is based on certificates. We need only revoke trust in the same
2143 // certificate once.
2144 if (find (processed_certs
.begin (), processed_certs
.end (),
2145 server
->certinfo
) != processed_certs
.end ())
2147 processed_certs
.push_back (server
->certinfo
);
2149 // Search the client-side database of trusted servers.
2150 db_cert
= PK11_FindCertFromNickname (nickname
, NULL
);
2153 // No trusted servers. Not an error, but issue a status message.
2155 trust_already_in_place (*server
, server_list
, cert_db_path
, true/*revoking*/);
2159 // Here, we have one cert with the desired nickname.
2160 // Now, we will attempt to get a list of ALL certs
2161 // with the same subject name as the cert we have. That list
2162 // should contain, at a minimum, the one cert we have already found.
2163 // If the list of certs is empty (NULL), the libraries have failed.
2164 certs
= CERT_CreateSubjectCertList (NULL
, handle
, & db_cert
->derSubject
,
2165 PR_Now (), PR_FALSE
);
2166 CERT_DestroyCertificate (db_cert
);
2169 clog
<< _F("Unable to query certificate database %s: ",
2170 cert_db_path
.c_str()) << endl
;
2171 PORT_SetError (SEC_ERROR_LIBRARY_FAILURE
);
2176 // Find the certificate matching the one belonging to our server.
2177 CERTCertListNode
*node
;
2178 for (node
= CERT_LIST_HEAD (certs
);
2179 ! CERT_LIST_END (node
, certs
);
2180 node
= CERT_LIST_NEXT (node
))
2182 // The certificate we're working with.
2183 db_cert
= node
->cert
;
2185 // Get the serial number.
2186 string serialNumber
= get_cert_serial_number (db_cert
);
2188 // Does the serial number match that of the current server?
2189 if (serialNumber
!= server
->certinfo
)
2190 continue; // goto next certificate
2192 // All is ok! Remove the certificate from the database.
2194 } // Loop over certificates in the database
2196 // Was a certificate matching the server found? */
2197 if (CERT_LIST_END (node
, certs
))
2199 // Not found. Server is already untrusted.
2201 trust_already_in_place (*server
, server_list
, cert_db_path
, true/*revoking*/);
2205 secStatus
= SEC_DeletePermCertificate (db_cert
);
2206 if (secStatus
!= SECSuccess
)
2208 clog
<< _F("Unable to remove certificate from %s: ",
2209 cert_db_path
.c_str()) << endl
;
2213 CERT_DestroyCertList (certs
);
2215 } // Loop over servers
2219 CERT_DestroyCertList (certs
);
2221 PORT_FreeArena (tmpArena
, PR_FALSE
);
2223 nssCleanup (cert_db_path
.c_str ());
2229 systemtap_session
&s
,
2231 vector
<compile_server_info
> &servers
2234 // Get information on compile servers matching the requested criteria.
2235 // The order of queries is significant. Accumulating queries must go first
2236 // followed by accumulating/filtering queries.
2238 if (((pmask
& compile_server_all
)))
2240 get_all_server_info (s
, servers
);
2243 // Add the specified servers, if requested
2244 if ((pmask
& compile_server_specified
))
2246 get_specified_server_info (s
, servers
);
2249 // Now filter the or accumulate the list depending on whether a query has
2250 // already been made.
2251 if ((pmask
& compile_server_online
))
2253 get_or_keep_online_server_info (s
, servers
, keep
);
2256 if ((pmask
& compile_server_trusted
))
2258 get_or_keep_trusted_server_info (s
, servers
, keep
);
2261 if ((pmask
& compile_server_signer
))
2263 get_or_keep_signing_server_info (s
, servers
, keep
);
2266 if ((pmask
& compile_server_compatible
))
2268 get_or_keep_compatible_server_info (s
, servers
, keep
);
2273 // Get information about all online servers as well as servers trusted
2274 // as SSL peers and servers trusted as signers.
2276 get_all_server_info (
2277 systemtap_session
&s
,
2278 vector
<compile_server_info
> &servers
2281 get_or_keep_online_server_info (s
, servers
, false/*keep*/);
2282 get_or_keep_trusted_server_info (s
, servers
, false/*keep*/);
2283 get_or_keep_signing_server_info (s
, servers
, false/*keep*/);
2287 get_default_server_info (
2288 systemtap_session
&s
,
2289 vector
<compile_server_info
> &servers
2292 // We only need to obtain this once per session. This is a good thing(tm)
2293 // since obtaining this information is expensive.
2294 vector
<compile_server_info
>& default_servers
= cscache(s
)->default_servers
;
2295 if (default_servers
.empty ())
2297 // Get the required information.
2298 // get_server_info will add an empty entry at the beginning to indicate
2299 // that the search has been performed, in case the search comes up empty.
2300 int pmask
= server_spec_to_pmask (default_server_spec (s
));
2301 get_server_info (s
, pmask
, default_servers
);
2304 // Add the information, but not duplicates.
2305 add_server_info (default_servers
, servers
);
2309 get_specified_server_info (
2310 systemtap_session
&s
,
2311 vector
<compile_server_info
> &servers
,
2315 // We only need to obtain this once per session. This is a good thing(tm)
2316 // since obtaining this information is expensive.
2317 vector
<compile_server_info
>& specified_servers
= cscache(s
)->specified_servers
;
2318 if (specified_servers
.empty ())
2320 // Maintain an empty entry to indicate that this search has been
2321 // performed, in case the search comes up empty.
2322 specified_servers
.push_back (compile_server_info ());
2324 // If --use-servers was not specified at all, then return info for the
2325 // default server list.
2326 if (s
.specified_servers
.empty ())
2329 get_default_server_info (s
, specified_servers
);
2333 // Iterate over the specified servers. For each specification, add to
2334 // the list of servers.
2335 unsigned num_specified_servers
= s
.specified_servers
.size ();
2336 for (unsigned i
= 0; i
< num_specified_servers
; ++i
)
2338 string
&server
= s
.specified_servers
[i
];
2339 if (server
.empty ())
2341 // No server specified. Use the default servers.
2343 get_default_server_info (s
, specified_servers
);
2347 // Work with the specified server
2348 compile_server_info server_info
;
2350 // See if a port was specified (:n suffix)
2351 vector
<string
> components
;
2352 tokenize (server
, components
, ":");
2353 if (components
.size () > 2)
2355 // Treat it as a certificate serial number. The final
2356 // component may still be a port number.
2357 if (components
.size () > 5)
2359 // Obtain the port number.
2360 const char *pstr
= components
.back ().c_str ();
2363 unsigned long port
= strtoul (pstr
, & estr
, 10);
2364 if (errno
== 0 && *estr
== '\0' && port
<= USHRT_MAX
)
2365 server_info
.port
= port
;
2368 clog
<< _F("Invalid port number specified: %s",
2369 components
.back().c_str()) << endl
;
2372 // Remove the port number from the spec
2373 server_info
.certinfo
= server
.substr (0, server
.find_last_of (':'));
2376 server_info
.certinfo
= server
;
2378 // Look for all known servers with this serial number and
2379 // (optional) port number.
2380 vector
<compile_server_info
> known_servers
;
2381 get_all_server_info (s
, known_servers
);
2382 keep_server_info_with_cert_and_port (s
, server_info
, known_servers
);
2384 if (known_servers
.empty ())
2387 clog
<< _F("No server matching %s found", server
.c_str()) << endl
;
2390 add_server_info (known_servers
, specified_servers
);
2391 } // specified by cert serial number
2393 // Not specified by serial number. Treat it as host name or
2394 // ip address and optional port number.
2395 if (components
.size () == 2)
2397 // Obtain the port number.
2398 const char *pstr
= components
.back ().c_str ();
2401 unsigned long port
= strtoul (pstr
, & estr
, 10);
2402 if (errno
== 0 && *estr
== '\0' && port
<= USHRT_MAX
)
2403 server_info
.port
= port
;
2406 clog
<< _F("Invalid port number specified: %s",
2407 components
.back().c_str()) << endl
;
2412 // Obtain the host name or ip address.
2413 if (stringToIpAddress (components
.front ()))
2414 server_info
.ip_address
= components
.front ();
2416 server_info
.host_name
= components
.front ();
2418 // Find known servers matching the specified information.
2419 vector
<compile_server_info
> known_servers
;
2420 get_all_server_info (s
, known_servers
);
2421 keep_common_server_info (server_info
, known_servers
);
2422 add_server_info (known_servers
, specified_servers
);
2424 // Resolve this host and add any information that is discovered.
2425 resolve_host (s
, server_info
, specified_servers
);
2426 } // Not specified by cert serial number
2427 } // Loop over --use-server options
2428 } // -- use-server specified
2429 } // Server information is not cached
2431 // Add the information, but not duplicates.
2432 add_server_info (specified_servers
, servers
);
2436 get_or_keep_trusted_server_info (
2437 systemtap_session
&s
,
2438 vector
<compile_server_info
> &servers
,
2442 // If we're filtering the list and it's already empty, then
2443 // there's nothing to do.
2444 if (keep
&& servers
.empty ())
2447 // We only need to obtain this once per session. This is a good thing(tm)
2448 // since obtaining this information is expensive.
2449 vector
<compile_server_info
>& trusted_servers
= cscache(s
)->trusted_servers
;
2450 if (trusted_servers
.empty ())
2452 // Maintain an empty entry to indicate that this search has been
2453 // performed, in case the search comes up empty.
2454 trusted_servers
.push_back (compile_server_info ());
2457 // Check the private database first.
2458 string cert_db_path
= private_ssl_cert_db_path ();
2459 get_server_info_from_db (s
, trusted_servers
, cert_db_path
);
2461 // Now check the global database.
2462 cert_db_path
= global_ssl_cert_db_path ();
2463 get_server_info_from_db (s
, trusted_servers
, cert_db_path
);
2465 // Without NSS, we can't determine whether a server is trusted.
2468 clog
<< _("Unable to determine server trust as an SSL peer") << endl
;
2469 #endif // ! HAVE_NSS
2470 } // Server information is not cached
2474 // Filter the existing vector by keeping the information in common with
2475 // the trusted_server vector.
2476 keep_common_server_info (trusted_servers
, servers
);
2480 // Add the information, but not duplicates.
2481 add_server_info (trusted_servers
, servers
);
2486 get_or_keep_signing_server_info (
2487 systemtap_session
&s
,
2488 vector
<compile_server_info
> &servers
,
2492 // If we're filtering the list and it's already empty, then
2493 // there's nothing to do.
2494 if (keep
&& servers
.empty ())
2497 // We only need to obtain this once per session. This is a good thing(tm)
2498 // since obtaining this information is expensive.
2499 vector
<compile_server_info
>& signing_servers
= cscache(s
)->signing_servers
;
2500 if (signing_servers
.empty ())
2502 // Maintain an empty entry to indicate that this search has been
2503 // performed, in case the search comes up empty.
2504 signing_servers
.push_back (compile_server_info ());
2507 // For all users, check the global database.
2508 string cert_db_path
= signing_cert_db_path ();
2509 get_server_info_from_db (s
, signing_servers
, cert_db_path
);
2511 // Without NSS, we can't determine whether a server is a trusted
2512 // signer. Issue a warning.
2514 clog
<< _("Unable to determine server trust as a module signer") << endl
;
2515 #endif // ! HAVE_NSS
2516 } // Server information is not cached
2520 // Filter the existing vector by keeping the information in common with
2521 // the signing_server vector.
2522 keep_common_server_info (signing_servers
, servers
);
2526 // Add the information, but not duplicates.
2527 add_server_info (signing_servers
, servers
);
2532 // Obtain information about servers from the certificates in the given database.
2534 get_server_info_from_db (
2535 systemtap_session
&s
,
2536 vector
<compile_server_info
> &servers
,
2537 const string
&cert_db_path
2540 // Make sure the given path exists.
2541 if (! file_exists (cert_db_path
))
2544 clog
<< _F("Certificate database '%s' does not exist.",
2545 cert_db_path
.c_str()) << endl
;
2549 // Make sure NSPR is initialized. Must be done before NSS is initialized
2552 // Initialize the NSS libraries -- readonly
2553 SECStatus secStatus
= nssInit (cert_db_path
.c_str ());
2554 if (secStatus
!= SECSuccess
)
2556 // Message already issued.
2560 // Must predeclare this because of jumps to cleanup: below.
2561 PRArenaPool
*tmpArena
= NULL
;
2562 CERTCertList
*certs
= get_cert_list_from_db (server_cert_nickname ());
2566 clog
<< _F("No certificate found in database %s", cert_db_path
.c_str ()) << endl
;
2570 // A memory pool to work in
2571 tmpArena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
2574 clog
<< _("Out of memory:");
2578 for (CERTCertListNode
*node
= CERT_LIST_HEAD (certs
);
2579 ! CERT_LIST_END (node
, certs
);
2580 node
= CERT_LIST_NEXT (node
))
2582 compile_server_info server_info
;
2584 // The certificate we're working with.
2585 CERTCertificate
*db_cert
= node
->cert
;
2587 // Get the host name. It is in the alt-name extension of the
2590 subAltName
.data
= NULL
;
2591 secStatus
= CERT_FindCertExtension (db_cert
,
2592 SEC_OID_X509_SUBJECT_ALT_NAME
,
2594 if (secStatus
!= SECSuccess
|| ! subAltName
.data
)
2596 clog
<< _("Unable to find alt name extension on server certificate: ") << endl
;
2601 // Decode the extension.
2602 CERTGeneralName
*nameList
= CERT_DecodeAltNameExtension (tmpArena
, & subAltName
);
2603 SECITEM_FreeItem(& subAltName
, PR_FALSE
);
2606 clog
<< _("Unable to decode alt name extension on server certificate: ") << endl
;
2611 // We're interested in the first alternate name.
2612 assert (nameList
->type
== certDNSName
);
2613 server_info
.host_name
= string ((const char *)nameList
->name
.other
.data
,
2614 nameList
->name
.other
.len
);
2615 // Don't free nameList. It's part of the tmpArena.
2617 // Get the serial number.
2618 server_info
.certinfo
= get_cert_serial_number (db_cert
);
2620 // Our results will at a minimum contain this server.
2621 add_server_info (server_info
, servers
);
2623 // Augment the list by querying all online servers and keeping the ones
2624 // with the same cert serial number.
2625 vector
<compile_server_info
> online_servers
;
2626 get_or_keep_online_server_info (s
, online_servers
, false/*keep*/);
2627 keep_server_info_with_cert_and_port (s
, server_info
, online_servers
);
2628 add_server_info (online_servers
, servers
);
2633 CERT_DestroyCertList (certs
);
2635 PORT_FreeArena (tmpArena
, PR_FALSE
);
2637 nssCleanup (cert_db_path
.c_str ());
2642 get_or_keep_compatible_server_info (
2643 systemtap_session
&s
,
2644 vector
<compile_server_info
> &servers
,
2649 // If we're filtering the list and it's already empty, then
2650 // there's nothing to do.
2651 if (keep
&& servers
.empty ())
2654 // Remove entries for servers incompatible with the host environment
2655 // from the given list of servers.
2656 // A compatible server compiles for the kernel release and architecture
2657 // of the host environment.
2659 // Compatibility can only be determined for online servers. So, augment
2660 // and filter the information we have with information for online servers.
2661 vector
<compile_server_info
> online_servers
;
2662 get_or_keep_online_server_info (s
, online_servers
, false/*keep*/);
2664 keep_common_server_info (online_servers
, servers
);
2666 add_server_info (online_servers
, servers
);
2668 // Now look to see which ones are compatible.
2669 // The vector can change size as we go, so be careful!!
2670 for (unsigned i
= 0; i
< servers
.size (); /**/)
2672 // Retain empty entries.
2673 assert (! servers
[i
].empty ());
2675 // Check the target of the server.
2676 if (servers
[i
].sysinfo
!= s
.kernel_release
+ " " + s
.architecture
)
2678 // Target platform mismatch.
2679 servers
.erase (servers
.begin () + i
);
2683 // The server is compatible. Leave it in the list.
2686 #else // ! HAVE_AVAHI
2687 // Without Avahi, we can't obtain the target platform of the server.
2690 clog
<< _("Unable to detect server compatibility") << endl
;
2697 keep_server_info_with_cert_and_port (
2698 systemtap_session
&,
2699 const compile_server_info
&server
,
2700 vector
<compile_server_info
> &servers
2703 assert (! server
.certinfo
.empty ());
2705 // Search the list of servers for ones matching the
2706 // serial number specified.
2707 // The vector can change size as we go, so be careful!!
2708 for (unsigned i
= 0; i
< servers
.size (); /**/)
2710 // Retain empty entries.
2711 if (servers
[i
].empty ())
2716 if (servers
[i
].certinfo
== server
.certinfo
&&
2717 (servers
[i
].port
== 0 || server
.port
== 0 ||
2718 servers
[i
].port
== server
.port
))
2720 // If the server is not online, then use the specified
2722 if (servers
[i
].port
== 0)
2723 servers
[i
].port
= server
.port
;
2727 // The item does not match. Delete it.
2728 servers
.erase (servers
.begin () + i
);
2732 // Obtain missing host name or ip address, if any.
2736 compile_server_info
&server
,
2737 vector
<compile_server_info
> &resolved_servers
2740 // Either the host name or the ip address or both are already set.
2741 const char *lookup_name
;
2742 if (! server
.host_name
.empty ())
2744 // Use the host name to do the lookup.
2745 lookup_name
= server
.host_name
.c_str ();
2749 // Use the ip address to do the lookup.
2750 // getaddrinfo works on both host names and ip addresses.
2751 assert (! server
.ip_address
.empty ());
2752 lookup_name
= server
.ip_address
.c_str ();
2755 // Resolve the server.
2756 struct addrinfo hints
;
2757 memset(& hints
, 0, sizeof (hints
));
2758 hints
.ai_family
= AF_INET
; // AF_UNSPEC or AF_INET6 to force version
2759 struct addrinfo
*addr_info
= NULL
;
2760 int status
= getaddrinfo (lookup_name
, NULL
, & hints
, & addr_info
);
2762 // Failure to resolve will result in an appropriate error later if other
2768 // Loop over the results collecting information.
2769 for (const struct addrinfo
*ai
= addr_info
; ai
!= NULL
; ai
= ai
->ai_next
)
2771 if (ai
->ai_family
!= AF_INET
)
2772 continue; // Not an IPv4 address
2774 // Start with the info we were given.
2775 compile_server_info new_server
= server
;
2777 // Obtain the ip address.
2778 // Start with the pointer to the address itself,
2779 struct sockaddr_in
*ipv4
= (struct sockaddr_in
*)ai
->ai_addr
;
2780 void *addr
= & ipv4
->sin_addr
;
2782 // convert the IP to a string.
2783 char ipstr
[INET_ADDRSTRLEN
];
2784 inet_ntop (ai
->ai_family
, addr
, ipstr
, sizeof (ipstr
));
2785 new_server
.ip_address
= ipstr
;
2787 // Try to obtain a host name.
2788 char hbuf
[NI_MAXHOST
];
2789 status
= getnameinfo (ai
->ai_addr
, sizeof (*ai
->ai_addr
),
2790 hbuf
, sizeof (hbuf
), NULL
, 0,
2791 NI_NAMEREQD
| NI_IDN
);
2793 new_server
.host_name
= hbuf
;
2795 // Don't resolve to localhost or localhost.localdomain, unless that's
2796 // what was asked for.
2797 if ((new_server
.host_name
== "localhost" ||
2798 new_server
.host_name
== "localhost.localdomain") &&
2799 new_server
.host_name
!= server
.host_name
)
2802 // Add the new resolved server to the list.
2803 add_server_info (new_server
, resolved_servers
);
2808 freeaddrinfo (addr_info
); // free the linked list
2811 // At a minimum, return the information we were given.
2812 add_server_info (server
, resolved_servers
);
2819 // Avahi API Callbacks.
2820 //-----------------------------------------------------------------------
2821 struct browsing_context
{
2822 AvahiSimplePoll
*simple_poll
;
2823 AvahiClient
*client
;
2824 vector
<compile_server_info
> *servers
;
2828 extract_field_from_avahi_txt (const string
&label
, const string
&txt
)
2830 // Extract the requested field from the Avahi TXT.
2831 string prefix
= "\"" + label
;
2832 size_t ix
= txt
.find (prefix
);
2833 if (ix
== string::npos
)
2839 // This is the start of the field.
2840 string field
= txt
.substr (ix
+ prefix
.size ());
2842 // Find the end of the field.
2843 ix
= field
.find('"');
2844 if (ix
!= string::npos
)
2845 field
= field
.substr (0, ix
);
2851 void resolve_callback(
2852 AvahiServiceResolver
*r
,
2853 AVAHI_GCC_UNUSED AvahiIfIndex interface
,
2854 AVAHI_GCC_UNUSED AvahiProtocol protocol
,
2855 AvahiResolverEvent event
,
2859 const char *host_name
,
2860 const AvahiAddress
*address
,
2862 AvahiStringList
*txt
,
2863 AvahiLookupResultFlags
/*flags*/,
2864 AVAHI_GCC_UNUSED
void* userdata
) {
2867 const browsing_context
*context
= (browsing_context
*)userdata
;
2868 vector
<compile_server_info
> *servers
= context
->servers
;
2870 // Called whenever a service has been resolved successfully or timed out.
2873 case AVAHI_RESOLVER_FAILURE
:
2874 clog
<< _F("Failed to resolve service '%s' of type '%s' in domain '%s': %s",
2876 avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r
)))) << endl
;
2879 case AVAHI_RESOLVER_FOUND
: {
2880 char a
[AVAHI_ADDRESS_STR_MAX
], *t
;
2881 avahi_address_snprint(a
, sizeof(a
), address
);
2883 // Ignore entries using IPv6 addresses for now
2884 vector
<string
> parts
;
2885 tokenize (a
, parts
, ".");
2886 if (parts
.size () == 4)
2888 // Save the information of interest.
2889 compile_server_info info
;
2890 info
.host_name
= host_name
;
2891 info
.ip_address
= strdup (a
);
2893 t
= avahi_string_list_to_string(txt
);
2894 info
.sysinfo
= extract_field_from_avahi_txt ("sysinfo=", t
);
2895 info
.certinfo
= extract_field_from_avahi_txt ("certinfo=", t
);
2896 info
.version
= extract_field_from_avahi_txt ("version=", t
);
2897 if (info
.version
.empty ())
2898 info
.version
= "1.0"; // default version is 1.0
2901 // Add this server to the list of discovered servers.
2902 add_server_info (info
, *servers
);
2907 avahi_service_resolver_free(r
);
2911 void browse_callback(
2912 AvahiServiceBrowser
*b
,
2913 AvahiIfIndex interface
,
2914 AvahiProtocol protocol
,
2915 AvahiBrowserEvent event
,
2919 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags
,
2922 browsing_context
*context
= (browsing_context
*)userdata
;
2923 AvahiClient
*c
= context
->client
;
2924 AvahiSimplePoll
*simple_poll
= context
->simple_poll
;
2927 // Called whenever a new services becomes available on the LAN or is removed from the LAN.
2930 case AVAHI_BROWSER_FAILURE
:
2931 clog
<< _F("Avahi browse failed: %s",
2932 avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b
))))
2934 avahi_simple_poll_quit(simple_poll
);
2937 case AVAHI_BROWSER_NEW
:
2938 // We ignore the returned resolver object. In the callback
2939 // function we free it. If the server is terminated before
2940 // the callback function is called the server will free
2941 // the resolver for us.
2942 if (!(avahi_service_resolver_new(c
, interface
, protocol
, name
, type
, domain
,
2943 AVAHI_PROTO_UNSPEC
, (AvahiLookupFlags
)0, resolve_callback
, context
))) {
2944 clog
<< _F("Failed to resolve service '%s': %s",
2945 name
, avahi_strerror(avahi_client_errno(c
))) << endl
;
2949 case AVAHI_BROWSER_REMOVE
:
2950 case AVAHI_BROWSER_ALL_FOR_NOW
:
2951 case AVAHI_BROWSER_CACHE_EXHAUSTED
:
2957 void client_callback(AvahiClient
*c
, AvahiClientState state
, AVAHI_GCC_UNUSED
void * userdata
) {
2959 browsing_context
*context
= (browsing_context
*)userdata
;
2960 AvahiSimplePoll
*simple_poll
= context
->simple_poll
;
2962 // Called whenever the client or server state changes.
2964 if (state
== AVAHI_CLIENT_FAILURE
) {
2965 clog
<< _F("Avahi Server connection failure: %s", avahi_strerror(avahi_client_errno(c
))) << endl
;
2966 avahi_simple_poll_quit(simple_poll
);
2971 void timeout_callback(AVAHI_GCC_UNUSED AvahiTimeout
*e
, AVAHI_GCC_UNUSED
void *userdata
) {
2972 browsing_context
*context
= (browsing_context
*)userdata
;
2973 AvahiSimplePoll
*simple_poll
= context
->simple_poll
;
2974 avahi_simple_poll_quit(simple_poll
);
2976 #endif // HAVE_AVAHI
2979 get_or_keep_online_server_info (
2980 systemtap_session
&s
,
2981 vector
<compile_server_info
> &servers
,
2985 // If we're filtering the list and it's already empty, then
2986 // there's nothing to do.
2987 if (keep
&& servers
.empty ())
2990 // We only need to obtain this once per session. This is a good thing(tm)
2991 // since obtaining this information is expensive.
2992 vector
<compile_server_info
>& online_servers
= cscache(s
)->online_servers
;
2993 if (online_servers
.empty ())
2995 // Maintain an empty entry to indicate that this search has been
2996 // performed, in case the search comes up empty.
2997 online_servers
.push_back (compile_server_info ());
2999 // Must predeclare these due to jumping on error to fail:
3001 vector
<compile_server_info
> raw_servers
;
3004 AvahiClient
*client
= NULL
;
3005 AvahiServiceBrowser
*sb
= NULL
;
3007 // Allocate main loop object.
3008 AvahiSimplePoll
*simple_poll
;
3009 if (!(simple_poll
= avahi_simple_poll_new()))
3011 clog
<< _("Failed to create Avahi simple poll object") << endl
;
3014 browsing_context context
;
3015 context
.simple_poll
= simple_poll
;
3016 context
.servers
= & raw_servers
;
3018 // Allocate a new Avahi client
3020 client
= avahi_client_new (avahi_simple_poll_get (simple_poll
),
3021 (AvahiClientFlags
)0,
3022 client_callback
, & context
, & error
);
3024 // Check whether creating the client object succeeded.
3027 clog
<< _F("Failed to create Avahi client: %s",
3028 avahi_strerror(error
)) << endl
;
3031 context
.client
= client
;
3033 // Create the service browser.
3034 if (!(sb
= avahi_service_browser_new (client
, AVAHI_IF_UNSPEC
,
3035 AVAHI_PROTO_UNSPEC
, "_stap._tcp",
3036 NULL
, (AvahiLookupFlags
)0,
3037 browse_callback
, & context
)))
3039 clog
<< _F("Failed to create Avahi service browser: %s",
3040 avahi_strerror(avahi_client_errno(client
))) << endl
;
3044 // Timeout after 2 seconds.
3046 avahi_simple_poll_get(simple_poll
)->timeout_new(
3047 avahi_simple_poll_get(simple_poll
),
3048 avahi_elapse_time(&tv
, 1000*2, 0),
3052 // Run the main loop.
3053 avahi_simple_poll_loop(simple_poll
);
3055 // Resolve each server discovered and eliminate duplicates.
3056 limit
= raw_servers
.size ();
3057 for (unsigned i
= 0; i
< limit
; ++i
)
3059 compile_server_info
&raw_server
= raw_servers
[i
];
3061 // Delete the domain, if it is '.local'
3062 string
&host_name
= raw_server
.host_name
;
3063 string::size_type dot_index
= host_name
.find ('.');
3064 assert (dot_index
!= 0);
3065 string domain
= host_name
.substr (dot_index
+ 1);
3066 if (domain
== "local")
3067 host_name
= host_name
.substr (0, dot_index
);
3069 // Add it to the list of servers, unless it is duplicate.
3070 resolve_host (s
, raw_server
, online_servers
);
3076 avahi_service_browser_free(sb
);
3079 avahi_client_free(client
);
3082 avahi_simple_poll_free(simple_poll
);
3083 #else // ! HAVE_AVAHI
3084 // Without Avahi, we can't detect online servers. Issue a warning.
3086 clog
<< _("Unable to detect online servers") << endl
;
3087 #endif // ! HAVE_AVAHI
3088 } // Server information is not cached.
3092 // Filter the existing vector by keeping the information in common with
3093 // the online_server vector.
3094 keep_common_server_info (online_servers
, servers
);
3098 // Add the information, but not duplicates.
3099 add_server_info (online_servers
, servers
);
3103 // Add server info to a list, avoiding duplicates. Merge information from
3104 // two duplicate items.
3107 const compile_server_info
&info
, vector
<compile_server_info
>& target
3114 for (vector
<compile_server_info
>::iterator i
= target
.begin ();
3120 // Duplicate. Merge the two items.
3121 merge_server_info (info
, *i
);
3126 target
.push_back (info
);
3129 // Add server info from one vector to another.
3132 const vector
<compile_server_info
> &source
,
3133 vector
<compile_server_info
> &target
3136 for (vector
<compile_server_info
>::const_iterator i
= source
.begin ();
3140 add_server_info (*i
, target
);
3144 // Filter the vector by keeping information in common with the item.
3146 keep_common_server_info (
3147 const compile_server_info
&info_to_keep
,
3148 vector
<compile_server_info
> &filtered_info
3151 assert (! info_to_keep
.empty ());
3153 // The vector may change size as we go. Be careful!!
3154 for (unsigned i
= 0; i
< filtered_info
.size (); /**/)
3156 // Retain empty entries.
3157 if (filtered_info
[i
].empty ())
3162 if (info_to_keep
== filtered_info
[i
])
3164 merge_server_info (info_to_keep
, filtered_info
[i
]);
3168 // The item does not match. Delete it.
3169 filtered_info
.erase (filtered_info
.begin () + i
);
3174 // Filter the second vector by keeping information in common with the first
3177 keep_common_server_info (
3178 const vector
<compile_server_info
> &info_to_keep
,
3179 vector
<compile_server_info
> &filtered_info
3182 // The vector may change size as we go. Be careful!!
3183 for (unsigned i
= 0; i
< filtered_info
.size (); /**/)
3185 // Retain empty entries.
3186 if (filtered_info
[i
].empty ())
3192 for (unsigned j
= 0; j
< info_to_keep
.size (); ++j
)
3194 if (filtered_info
[i
] == info_to_keep
[j
])
3196 merge_server_info (info_to_keep
[j
], filtered_info
[i
]);
3201 // If the item was not found. Delete it. Otherwise, advance to the next
3206 filtered_info
.erase (filtered_info
.begin () + i
);
3210 // Merge two compile server info items.
3213 const compile_server_info
&source
,
3214 compile_server_info
&target
3217 if (target
.host_name
.empty ())
3218 target
.host_name
= source
.host_name
;
3219 if (target
.ip_address
.empty ())
3220 target
.ip_address
= source
.ip_address
;
3221 if (target
.port
== 0)
3222 target
.port
= source
.port
;
3223 if (target
.sysinfo
.empty ())
3224 target
.sysinfo
= source
.sysinfo
;
3225 if (target
.version
.empty ())
3226 target
.version
= source
.version
;
3227 if (target
.certinfo
.empty ())
3228 target
.certinfo
= source
.certinfo
;
3231 #if 0 // not used right now
3232 // Merge compile server info from one item into a vector.
3235 const compile_server_info
&source
,
3236 vector
<compile_server_info
> &target
3239 for (vector
<compile_server_info
>::iterator i
= target
.begin ();
3244 merge_server_info (source
, *i
);
3248 // Merge compile server from one vector into another.
3251 const vector
<compile_server_info
> &source
,
3252 vector
<compile_server_info
> &target
3255 for (vector
<compile_server_info
>::const_iterator i
= source
.begin ();
3258 merge_server_info (*i
, target
);
3262 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */