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