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