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