]> sourceware.org Git - systemtap.git/blob - stap-serverd.cxx
Initial MOK signed module support.
[systemtap.git] / stap-serverd.cxx
1 /*
2 SSL server program listens on a port, accepts client connection, reads
3 the data into a temporary file, calls the systemtap translator and
4 then transmits the resulting file back to the client.
5
6 Copyright (C) 2011-2013 Red Hat Inc.
7
8 This file is part of systemtap, and is free software. You can
9 redistribute it and/or modify it under the terms of the GNU General Public
10 License as published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21 #include "config.h"
22
23 #include <fstream>
24 #include <string>
25 #include <cerrno>
26 #include <cassert>
27 #include <climits>
28 #include <iostream>
29 #include <map>
30
31 extern "C" {
32 #include <unistd.h>
33 #include <getopt.h>
34 #include <wordexp.h>
35 #include <glob.h>
36 #include <fcntl.h>
37 #include <sys/stat.h>
38 #include <sys/utsname.h>
39 #include <sys/types.h>
40 #include <pwd.h>
41 #include <semaphore.h>
42
43 #include <nspr.h>
44 #include <ssl.h>
45 #include <nss.h>
46 #include <keyhi.h>
47 #include <regex.h>
48 #include <dirent.h>
49
50 #if HAVE_AVAHI
51 #include <avahi-client/publish.h>
52 #include <avahi-common/alternative.h>
53 #include <avahi-common/thread-watch.h>
54 #include <avahi-common/malloc.h>
55 #include <avahi-common/error.h>
56 #include <avahi-common/domain.h>
57 #endif
58 }
59
60 #include "util.h"
61 #include "nsscommon.h"
62 #include "cscommon.h"
63 #include "cmdline.h"
64
65 using namespace std;
66
67 static void cleanup ();
68 static PRStatus spawn_and_wait (const vector<string> &argv, int *result,
69 const char* fd0, const char* fd1, const char* fd2,
70 const char *pwd, const vector<string>& envVec = vector<string> ());
71
72 typedef struct
73 {
74 string issuer;
75 string serial_number;
76 string fingerprint;
77 string directory;
78 } mok_info_t;
79 typedef map<string, mok_info_t *> mok_map_t;
80 typedef map<string, mok_info_t *>::const_iterator mok_map_iterator;
81
82 /* getopt variables */
83 extern int optind;
84
85 /* File scope statics. Set during argument parsing and initialization. */
86 static bool use_db_password;
87 static unsigned short port;
88 static long max_threads;
89 static string cert_db_path;
90 static string stap_options;
91 static string uname_r;
92 static string kernel_build_tree;
93 static string arch;
94 static string cert_serial_number;
95 static string B_options;
96 static string I_options;
97 static string R_option;
98 static string D_options;
99 static bool keep_temp;
100 static mok_map_t server_mok_map;
101
102 sem_t sem_client;
103 static int pending_interrupts;
104 #define CONCURRENCY_TIMEOUT_S 3
105
106 // Message handling.
107 // Server_error messages are printed to stderr and logged, if requested.
108 static void
109 server_error (const string &msg, int logit = true)
110 {
111 cerr << msg << endl << flush;
112 // Log it, but avoid repeated messages to the terminal.
113 if (logit && log_ok ())
114 log (msg);
115 }
116
117 // client_error messages are treated as server errors and also printed to the client's stderr.
118 static void
119 client_error (const string &msg, string stapstderr)
120 {
121 server_error (msg);
122 if (! stapstderr.empty ())
123 {
124 ofstream errfile;
125 errfile.open (stapstderr.c_str (), ios_base::app);
126 if (! errfile.good ())
127 server_error (_F("Could not open client stderr file %s: %s", stapstderr.c_str (),
128 strerror (errno)));
129 else
130 errfile << "Server: " << msg << endl;
131 // NB: No need to close errfile
132 }
133 }
134
135 // Messages from the nss common code are treated as server errors.
136 extern "C"
137 void
138 nsscommon_error (const char *msg, int logit)
139 {
140 server_error (msg, logit);
141 }
142
143 // Fatal errors are treated as server errors but also result in termination
144 // of the server.
145 static void
146 fatal (const string &msg)
147 {
148 server_error (msg);
149 cleanup ();
150 exit (1);
151 }
152
153 // Argument handling
154 static void
155 process_a (const string &arg)
156 {
157 arch = arg;
158 stap_options += " -a " + arg;
159 }
160
161 static void
162 process_r (const string &arg)
163 {
164 if (arg[0] == '/') // fully specified path
165 {
166 kernel_build_tree = arg;
167 uname_r = kernel_release_from_build_tree (arg);
168 }
169 else
170 {
171 kernel_build_tree = "/lib/modules/" + arg + "/build";
172 uname_r = arg;
173 }
174 stap_options += " -r " + arg; // Pass the argument to stap directly.
175 }
176
177 static void
178 process_log (const char *arg)
179 {
180 start_log (arg);
181 }
182
183 static void
184 parse_options (int argc, char **argv)
185 {
186 // Examine the command line. This is the command line for us (stap-serverd) not the command
187 // line for spawned stap instances.
188 optind = 1;
189 while (true)
190 {
191 char *num_endptr;
192 long port_tmp;
193 // NB: The values of these enumerators must not conflict with the values of ordinary
194 // characters, since those are returned by getopt_long for short options.
195 enum {
196 LONG_OPT_PORT = 256,
197 LONG_OPT_SSL,
198 LONG_OPT_LOG,
199 LONG_OPT_MAXTHREADS
200 };
201 static struct option long_options[] = {
202 { "port", 1, NULL, LONG_OPT_PORT },
203 { "ssl", 1, NULL, LONG_OPT_SSL },
204 { "log", 1, NULL, LONG_OPT_LOG },
205 { "max-threads", 1, NULL, LONG_OPT_MAXTHREADS },
206 { NULL, 0, NULL, 0 }
207 };
208 int grc = getopt_long (argc, argv, "a:B:D:I:kPr:R:", long_options, NULL);
209 if (grc < 0)
210 break;
211 switch (grc)
212 {
213 case 'a':
214 process_a (optarg);
215 break;
216 case 'B':
217 B_options += string (" -") + (char)grc + optarg;
218 stap_options += string (" -") + (char)grc + optarg;
219 break;
220 case 'D':
221 D_options += string (" -") + (char)grc + optarg;
222 stap_options += string (" -") + (char)grc + optarg;
223 break;
224 case 'I':
225 I_options += string (" -") + (char)grc + optarg;
226 stap_options += string (" -") + (char)grc + optarg;
227 break;
228 case 'k':
229 keep_temp = true;
230 break;
231 case 'P':
232 use_db_password = true;
233 break;
234 case 'r':
235 process_r (optarg);
236 break;
237 case 'R':
238 R_option = string (" -") + (char)grc + optarg;
239 stap_options += string (" -") + (char)grc + optarg;
240 break;
241 case LONG_OPT_PORT:
242 port_tmp = strtol (optarg, &num_endptr, 10);
243 if (*num_endptr != '\0')
244 fatal (_F("%s: cannot parse number '--port=%s'", argv[0], optarg));
245 else if (port_tmp < 0 || port_tmp > 65535)
246 fatal (_F("%s: invalid entry: port must be between 0 and 65535 '--port=%s'", argv[0],
247 optarg));
248 else
249 port = (unsigned short) port_tmp;
250 break;
251 case LONG_OPT_SSL:
252 cert_db_path = optarg;
253 break;
254 case LONG_OPT_LOG:
255 process_log (optarg);
256 break;
257 case LONG_OPT_MAXTHREADS:
258 max_threads = strtol (optarg, &num_endptr, 0);
259 if (*num_endptr != '\0')
260 fatal (_F("%s: cannot parse number '--max-threads=%s'", argv[0], optarg));
261 else if (max_threads < 0)
262 fatal (_F("%s: invalid entry: max threads must not be negative '--max-threads=%s'",
263 argv[0], optarg));
264 break;
265 case '?':
266 // Invalid/unrecognized option given. Message has already been issued.
267 break;
268 default:
269 // Reached when one added a getopt option but not a corresponding switch/case:
270 if (optarg)
271 server_error (_F("%s: unhandled option '%c %s'", argv[0], (char)grc, optarg));
272 else
273 server_error (_F("%s: unhandled option '%c'", argv[0], (char)grc));
274 break;
275 }
276 }
277
278 for (int i = optind; i < argc; i++)
279 server_error (_F("%s: unrecognized argument '%s'", argv[0], argv[i]));
280 }
281
282 static string
283 server_cert_file ()
284 {
285 return server_cert_db_path () + "/stap.cert";
286 }
287
288 // Signal handling. When an interrupt is received, kill any spawned processes
289 // and exit.
290 extern "C"
291 void
292 handle_interrupt (int sig)
293 {
294 pending_interrupts++;
295 if(pending_interrupts >= 2)
296 {
297 log (_F("Received another signal %d, exiting (forced)", sig));
298 _exit(0);
299 }
300 log (_F("Received signal %d, exiting", sig));
301 }
302
303 static void
304 setup_signals (sighandler_t handler)
305 {
306 struct sigaction sa;
307
308 memset(&sa, 0, sizeof(sa));
309 sa.sa_handler = handler;
310 sigemptyset (&sa.sa_mask);
311 if (handler != SIG_IGN)
312 {
313 sigaddset (&sa.sa_mask, SIGHUP);
314 sigaddset (&sa.sa_mask, SIGPIPE);
315 sigaddset (&sa.sa_mask, SIGINT);
316 sigaddset (&sa.sa_mask, SIGTERM);
317 sigaddset (&sa.sa_mask, SIGTTIN);
318 sigaddset (&sa.sa_mask, SIGTTOU);
319 sigaddset (&sa.sa_mask, SIGXFSZ);
320 sigaddset (&sa.sa_mask, SIGXCPU);
321 }
322 sa.sa_flags = SA_RESTART;
323
324 sigaction (SIGHUP, &sa, NULL);
325 sigaction (SIGPIPE, &sa, NULL);
326 sigaction (SIGINT, &sa, NULL);
327 sigaction (SIGTERM, &sa, NULL);
328 sigaction (SIGTTIN, &sa, NULL);
329 sigaction (SIGTTOU, &sa, NULL);
330 sigaction (SIGXFSZ, &sa, NULL);
331 sigaction (SIGXCPU, &sa, NULL);
332 }
333
334 #if HAVE_AVAHI
335 static AvahiEntryGroup *avahi_group = NULL;
336 static AvahiThreadedPoll *avahi_threaded_poll = NULL;
337 static char *avahi_service_name = NULL;
338 static const char * const avahi_service_tag = "_stap._tcp";
339 static AvahiClient *avahi_client = 0;
340 static int avahi_collisions = 0;
341
342 static void create_services (AvahiClient *c);
343
344 static int
345 rename_service ()
346 {
347 /*
348 * Each service must have a unique name on the local network.
349 * When there is a collision, we try to rename the service.
350 * However, we need to limit the number of attempts, since the
351 * service namespace could be maliciously flooded with service
352 * names designed to maximize collisions.
353 * Arbitrarily choose a limit of 65535, which is the number of
354 * TCP ports.
355 */
356 ++avahi_collisions;
357 if (avahi_collisions >= 65535) {
358 server_error (_F("Too many service name collisions for Avahi service %s",
359 avahi_service_tag));
360 return -EBUSY;
361 }
362
363 /*
364 * Use the avahi-supplied function to generate a new service name.
365 */
366 char *n = avahi_alternative_service_name(avahi_service_name);
367
368 server_error (_F("Avahi service name collision, renaming service '%s' to '%s'",
369 avahi_service_name, n));
370 avahi_free(avahi_service_name);
371 avahi_service_name = n;
372
373 return 0;
374 }
375
376 static void
377 entry_group_callback (
378 AvahiEntryGroup *g,
379 AvahiEntryGroupState state,
380 AVAHI_GCC_UNUSED void *userdata
381 ) {
382 assert(g == avahi_group || avahi_group == NULL);
383 avahi_group = g;
384
385 // Called whenever the entry group state changes.
386 switch (state)
387 {
388 case AVAHI_ENTRY_GROUP_ESTABLISHED:
389 // The entry group has been established successfully.
390 log (_F("Avahi service '%s' successfully established.", avahi_service_name));
391 break;
392
393 case AVAHI_ENTRY_GROUP_COLLISION:
394 // A service name collision with a remote service happened.
395 // Unfortunately, we don't know which entry collided.
396 // We need to rename them all and recreate the services.
397 if (rename_service () == 0)
398 create_services (avahi_entry_group_get_client (g));
399 break;
400
401 case AVAHI_ENTRY_GROUP_FAILURE:
402 // Some kind of failure happened.
403 server_error (_F("Avahi entry group failure: %s",
404 avahi_strerror (avahi_client_errno (avahi_entry_group_get_client (g)))));
405 break;
406
407 case AVAHI_ENTRY_GROUP_UNCOMMITED:
408 case AVAHI_ENTRY_GROUP_REGISTERING:
409 break;
410 }
411 }
412
413 static void
414 create_services (AvahiClient *c) {
415 assert (c);
416
417 // Create a new entry group, if necessary, or reset the existing one.
418 if (! avahi_group)
419 {
420 if (! (avahi_group = avahi_entry_group_new (c, entry_group_callback, NULL)))
421 {
422 server_error (_F("avahi_entry_group_new () failed: %s",
423 avahi_strerror (avahi_client_errno (c))));
424 return;
425 }
426 }
427 else
428 avahi_entry_group_reset(avahi_group);
429
430
431 // Contruct the information needed for our service.
432 log (_F("Adding Avahi service '%s'", avahi_service_name));
433
434 // Create the txt tags that will be registered with our service.
435 string sysinfo = "sysinfo=" + uname_r + " " + arch;
436 string certinfo = "certinfo=" + cert_serial_number;
437 string version = string ("version=") + CURRENT_CS_PROTOCOL_VERSION;;
438 string optinfo = "optinfo=";
439 string separator;
440 // These option strings already have a leading space.
441 if (! R_option.empty ())
442 {
443 optinfo += R_option.substr(1);
444 separator = " ";
445 }
446 if (! B_options.empty ())
447 {
448 optinfo += separator + B_options.substr(1);
449 separator = " ";
450 }
451 if (! D_options.empty ())
452 {
453 optinfo += separator + D_options.substr(1);
454 separator = " ";
455 }
456 if (! I_options.empty ())
457 optinfo += separator + I_options.substr(1);
458
459 // Create an avahi string list with the info we have so far.
460 AvahiStringList *strlst = avahi_string_list_new(sysinfo.c_str (),
461 optinfo.c_str (),
462 version.c_str (),
463 certinfo.c_str (), NULL);
464 if (strlst == NULL)
465 {
466 server_error (_("Failed to allocate string list"));
467 goto fail;
468 }
469
470 // Add server MOK info, if available.
471 //
472 // FIXME: Hmm, is this the right way to transmit this data? This
473 // method is fairly easy, but I wonder if we're abusing the avahi
474 // stuff with too much data here.
475 if (! server_mok_map.empty())
476 {
477 mok_map_iterator it;
478 int i;
479 for (it = server_mok_map.begin(), i = 1; it != server_mok_map.end();
480 it++, i++)
481 {
482 string tmp = _F("mok_info%d=", i) + it->second->fingerprint + " "
483 + it->second->serial_number + " " + it->second->issuer;
484 strlst = avahi_string_list_add(strlst, tmp.c_str ());
485 if (strlst == NULL)
486 {
487 server_error (_("Failed to add a string to the list"));
488 goto fail;
489 }
490 }
491 }
492
493 // We will now add our service to the entry group.
494 // Loop until no collisions.
495 int ret;
496 for (;;) {
497 ret = avahi_entry_group_add_service_strlst (avahi_group,
498 AVAHI_IF_UNSPEC,
499 AVAHI_PROTO_UNSPEC,
500 (AvahiPublishFlags)0,
501 avahi_service_name,
502 avahi_service_tag,
503 NULL, NULL, port, strlst);
504 if (ret == AVAHI_OK)
505 break; // success!
506
507 if (ret == AVAHI_ERR_COLLISION)
508 {
509 // A service name collision with a local service happened.
510 // Pick a new name.
511 if (rename_service () < 0) {
512 // Too many collisions. Message already issued.
513 goto fail;
514 }
515 continue; // try again.
516 }
517
518 server_error (_F("Failed to add %s service: %s",
519 avahi_service_tag, avahi_strerror (ret)));
520 goto fail;
521 }
522
523 // Tell the server to register the service.
524 if ((ret = avahi_entry_group_commit (avahi_group)) < 0)
525 {
526 server_error (_F("Failed to commit avahi entry group: %s", avahi_strerror (ret)));
527 goto fail;
528 }
529
530 avahi_string_list_free(strlst);
531 return;
532
533 fail:
534 avahi_entry_group_reset (avahi_group);
535 avahi_string_list_free(strlst);
536 }
537
538 static void avahi_cleanup_client () {
539 // This also frees the entry group, if any
540 if (avahi_client) {
541 avahi_client_free (avahi_client);
542 avahi_client = 0;
543 avahi_group = 0;
544 }
545 }
546
547 static void
548 client_callback (AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata)
549 {
550 assert(c);
551
552 // Called whenever the client or server state changes.
553 switch (state)
554 {
555 case AVAHI_CLIENT_S_RUNNING:
556 // The server has startup successfully and registered its host
557 // name on the network, so it's time to create our services.
558 create_services (c);
559 break;
560
561 case AVAHI_CLIENT_FAILURE:
562 server_error (_F("Avahi client failure: %s", avahi_strerror (avahi_client_errno (c))));
563 if (avahi_client_errno (c) == AVAHI_ERR_DISCONNECTED)
564 {
565 // The client has been disconnected; probably because the avahi daemon has been
566 // restarted. We can free the client here and try to reconnect using a new one.
567 // Passing AVAHI_CLIENT_NO_FAIL allows the new client to be
568 // created, even if the avahi daemon is not running. Our service will be advertised
569 // if/when the daemon is started.
570 avahi_cleanup_client ();
571 int error;
572 avahi_client = avahi_client_new (avahi_threaded_poll_get (avahi_threaded_poll),
573 (AvahiClientFlags)AVAHI_CLIENT_NO_FAIL,
574 client_callback, NULL, & error);
575 }
576 break;
577
578 case AVAHI_CLIENT_S_COLLISION:
579 // Let's drop our registered services. When the server is back
580 // in AVAHI_SERVER_RUNNING state we will register them
581 // again with the new host name.
582 // Fall through ...
583 case AVAHI_CLIENT_S_REGISTERING:
584 // The server records are now being established. This
585 // might be caused by a host name change. We need to wait
586 // for our own records to register until the host name is
587 // properly esatblished.
588 if (avahi_group)
589 avahi_entry_group_reset (avahi_group);
590 break;
591
592 case AVAHI_CLIENT_CONNECTING:
593 // The avahi-daemon is not currently running. Our service will be advertised
594 // if/when the deamon is started.
595 server_error (_F("The Avahi daemon is not running. Avahi service '%s' will be established when the deamon is started", avahi_service_name));
596 break;
597 }
598 }
599
600 static void
601 avahi_cleanup () {
602 if (avahi_service_name)
603 log (_F("Removing Avahi service '%s'", avahi_service_name));
604
605 // Stop the avahi client, if it's running
606 if (avahi_threaded_poll)
607 avahi_threaded_poll_stop (avahi_threaded_poll);
608
609 // Clean up the avahi objects. The order of freeing these is significant.
610 avahi_cleanup_client ();
611 if (avahi_threaded_poll) {
612 avahi_threaded_poll_free (avahi_threaded_poll);
613 avahi_threaded_poll = 0;
614 }
615 if (avahi_service_name) {
616 avahi_free (avahi_service_name);
617 avahi_service_name = 0;
618 }
619 }
620
621 // The entry point for the avahi client thread.
622 static void
623 avahi_publish_service (CERTCertificate *cert)
624 {
625 // Get the certificate serial number.
626 cert_serial_number = get_cert_serial_number (cert);
627
628 // Construct the Avahi service name.
629 char host[HOST_NAME_MAX + 1];
630 gethostname (host, sizeof(host));
631 host[sizeof(host) - 1] = '\0';
632 string buf;
633 buf = string ("Systemtap Compile Server on ") + host;
634
635 // Make sure the service name is valid
636 const char *initial_service_name = buf.c_str ();
637 if (! avahi_is_valid_service_name (initial_service_name)) {
638 // The only restriction on service names is that the buffer must not exceed
639 // AVAHI_LABEL_MAX in size, which means that the name cannot be longer than
640 // AVAHI_LABEL_MAX-1 in length.
641 assert (strlen (initial_service_name) >= AVAHI_LABEL_MAX);
642 buf = buf.substr (0, AVAHI_LABEL_MAX - 1);
643 initial_service_name = buf.c_str ();
644 assert (avahi_is_valid_service_name (initial_service_name));
645 }
646 avahi_service_name = avahi_strdup (initial_service_name);
647
648 // Allocate main loop object.
649 if (! (avahi_threaded_poll = avahi_threaded_poll_new ()))
650 {
651 server_error (_("Failed to create avahi threaded poll object."));
652 return;
653 }
654
655 // Always allocate a new client. Passing AVAHI_CLIENT_NO_FAIL allows the client to be
656 // created, even if the avahi daemon is not running. Our service will be advertised
657 // if/when the daemon is started.
658 int error;
659 avahi_client = avahi_client_new (avahi_threaded_poll_get (avahi_threaded_poll),
660 (AvahiClientFlags)AVAHI_CLIENT_NO_FAIL,
661 client_callback, NULL, & error);
662 // Check whether creating the client object succeeded.
663 if (! avahi_client)
664 {
665 server_error (_F("Failed to create avahi client: %s", avahi_strerror(error)));
666 return;
667 }
668
669 // Run the main loop.
670 avahi_threaded_poll_start (avahi_threaded_poll);
671
672 return;
673 }
674 #endif // HAVE_AVAHI
675
676 static void
677 advertise_presence (CERTCertificate *cert __attribute ((unused)))
678 {
679 #if HAVE_AVAHI
680 avahi_publish_service (cert);
681 #else
682 server_error (_("Unable to advertise presence on the network. Avahi is not available"));
683 #endif
684 }
685
686 static void
687 unadvertise_presence ()
688 {
689 #if HAVE_AVAHI
690 avahi_cleanup ();
691 #endif
692 }
693
694 static void
695 initialize_server_moks()
696 {
697 string mok_path = server_cert_db_path() + "/moks";
698 DIR *dirp = opendir(mok_path.c_str());
699 struct dirent *direntp;
700 vector<string> temp;
701 bool initialized_nss = false;
702
703 // The directory of machine owner keys (MOK) is optional, so if it
704 // doesn't exist, we don't worry about it.
705 if (dirp == NULL) {
706 // If the error isn't ENOENT (Directory does not exist), we've got
707 // a non-fatal error.
708 if (errno != ENOENT)
709 server_error(_F("Could not open server MOK directory %s: %s",
710 mok_path.c_str(), strerror(errno)));
711 return;
712 }
713
714 // Create a regular expression object to verify MOK fingerprints
715 // directory name.
716 regex_t checkre;
717 if ((regcomp(&checkre, "^[0-9a-f]{2}(:[0-9a-f]{2})+$",
718 REG_EXTENDED | REG_NOSUB) != 0)) {
719 // Not fatal, just ignore the MOK fingerprints.
720 server_error(_F("Error in MOK fingerprint regcomp: %s", strerror (errno)));
721 closedir(dirp);
722 return;
723 }
724
725 // We've opened the directory, so read all the directory names from
726 // it.
727 while ((direntp = readdir(dirp)) != NULL) {
728 // We're only interested in directories (of key files).
729 if (direntp->d_type != DT_DIR)
730 continue;
731
732 // We've got a directory. If the directory name isn't in the right
733 // format for a MOK fingerprint, skip it.
734 if ((regexec(&checkre, direntp->d_name, (size_t) 0, NULL, 0) != 0))
735 continue;
736
737 // OK, we've got a directory name in the right format, so save it.
738 temp.push_back(string(direntp->d_name));
739 }
740 regfree(&checkre);
741 closedir(dirp);
742
743 // read_cert_info_from_file() needs NSS to be initialized...
744 if (! NSS_IsInitialized ()) {
745 // If NSS can't be initialized, just return (a message should have
746 // been already issued).
747 if (nssInit (cert_db_path.c_str ()) != SECSuccess)
748 return;
749 initialized_nss = true;
750 }
751
752 // At this point, we've got a list of directories with names in the
753 // proper format. Make sure each directory contains a x509
754 // certificate and private key file.
755 vector<string>::const_iterator it;
756 for (it = temp.begin(); it != temp.end(); it++) {
757 string keydir = mok_path + "/" + *it;
758 dirp = opendir(keydir.c_str());
759 if (dirp == NULL) {
760 // The directory name was in the right format, but we can't open
761 // it for some reason. Just skip it.
762 server_error(_F("Could not open server MOK fingerprint directory %s: %s",
763 keydir.c_str(), strerror(errno)));
764 continue;
765 }
766
767 // Find both the x509 certificate and private key files.
768 //
769 // FIXME: We could verify that the private key file's mode is 0600
770 // here and refuse to use it otherwise. Really needed?
771 bool priv_found = false;
772 bool cert_found = false;
773 while ((direntp = readdir(dirp)) != NULL) {
774 if (! priv_found && direntp->d_type == DT_REG
775 && strcmp(direntp->d_name, "signing_key.priv") == 0) {
776 priv_found = true;
777 continue;
778 }
779 if (! cert_found && direntp->d_type == DT_REG
780 && strcmp(direntp->d_name, "signing_key.x509") == 0) {
781 cert_found = true;
782 continue;
783 }
784 if (priv_found && cert_found)
785 break;
786 }
787 closedir(dirp);
788 if (!priv_found || !cert_found) {
789 // We didn't find one (or both) of the required files. Skip the
790 // directory.
791 server_error(_F("Could not find server MOK files in directory %s",
792 keydir.c_str()));
793 continue;
794 }
795
796 // Grab info from the cert.
797 string issuer, serial_number, fingerprint;
798 if (read_cert_info_from_file(keydir + "/signing_key.x509", issuer,
799 serial_number, fingerprint) == SECSuccess) {
800 // Make sure the fingerprint from the certificate matches the
801 // directory name.
802 if (fingerprint != *it) {
803 server_error(_F("Server MOK directory name '%s' doesn't match fingerprint from certificate %s",
804 keydir.c_str(), fingerprint.c_str()));
805 continue;
806 }
807
808 // Save the info.
809 mok_info_t *mki = new mok_info_t;
810 mki->issuer = issuer;
811 mki->serial_number = serial_number;
812 mki->fingerprint = fingerprint;
813 mki->directory = keydir;
814 server_mok_map[fingerprint] = mki;
815 server_error(_F("Found MOK: issuer='%s' serial number='%s'",
816 issuer.c_str(), serial_number.c_str()));
817 }
818 }
819
820 // If we initialized NSS, clean it up.
821 if (initialized_nss)
822 nssCleanup (cert_db_path.c_str ());
823
824 return;
825 }
826
827 static void
828 initialize (int argc, char **argv) {
829 pending_interrupts = 0;
830 setup_signals (& handle_interrupt);
831
832 // Seed the random number generator. Used to generate noise used during key generation.
833 srand (time (NULL));
834
835 // Initial values.
836 use_db_password = false;
837 port = 0;
838 max_threads = sysconf( _SC_NPROCESSORS_ONLN ); // Default to number of processors
839 keep_temp = false;
840 struct utsname utsname;
841 uname (& utsname);
842 uname_r = utsname.release;
843 kernel_build_tree = "/lib/modules/" + uname_r + "/build";
844 arch = normalize_machine (utsname.machine);
845
846 // Parse the arguments. This also starts the server log, if any, and should be done before
847 // any messages are issued.
848 parse_options (argc, argv);
849
850 // PR11197: security prophylactics.
851 // Reject use as root, except via a special environment variable.
852 if (! getenv ("STAP_PR11197_OVERRIDE")) {
853 if (geteuid () == 0)
854 fatal ("For security reasons, invocation of stap-serverd as root is not supported.");
855 }
856
857 struct passwd *pw = getpwuid (geteuid ());
858 if (! pw)
859 fatal (_F("Unable to determine effective user name: %s", strerror (errno)));
860 string username = pw->pw_name;
861 pid_t pid = getpid ();
862 log (_F("===== compile server pid %d starting as %s =====", pid, username.c_str ()));
863
864 // Where is the ssl certificate/key database?
865 if (cert_db_path.empty ())
866 cert_db_path = server_cert_db_path ();
867
868 // Make sure NSPR is initialized. Must be done before NSS is initialized
869 PR_Init (PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
870 /* Set the cert database password callback. */
871 PK11_SetPasswordFunc (nssPasswordCallback);
872
873 // Get the list of optional machine owner keys (MOK) this server
874 // knows about.
875 initialize_server_moks ();
876 }
877
878 static void
879 cleanup ()
880 {
881 unadvertise_presence ();
882 end_log ();
883 }
884
885 /* Function: readDataFromSocket()
886 *
887 * Purpose: Read data from the socket into a temporary file.
888 *
889 */
890 static PRInt32
891 readDataFromSocket(PRFileDesc *sslSocket, const char *requestFileName)
892 {
893 PRFileDesc *local_file_fd = 0;
894 PRInt32 numBytesExpected;
895 PRInt32 numBytesRead;
896 PRInt32 numBytesWritten;
897 PRInt32 totalBytes = 0;
898 #define READ_BUFFER_SIZE 4096
899 char buffer[READ_BUFFER_SIZE];
900
901 // Read the number of bytes to be received.
902 /* XXX: impose a limit to prevent disk space consumption DoS */
903 numBytesRead = PR_Read_Complete (sslSocket, & numBytesExpected,
904 (PRInt32)sizeof (numBytesExpected));
905 if (numBytesRead == 0) /* EOF */
906 {
907 server_error (_("Error reading size of request file"));
908 goto done;
909 }
910 if (numBytesRead < 0)
911 {
912 server_error (_("Error in PR_Read"));
913 nssError ();
914 goto done;
915 }
916
917 /* Convert numBytesExpected from network byte order to host byte order. */
918 numBytesExpected = ntohl (numBytesExpected);
919
920 /* If 0 bytes are expected, then we were contacted only to obtain our certificate.
921 There is no client request. */
922 if (numBytesExpected == 0)
923 return 0;
924
925 /* Open the output file. */
926 local_file_fd = PR_Open(requestFileName, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
927 PR_IRUSR | PR_IWUSR);
928 if (local_file_fd == NULL)
929 {
930 server_error (_F("Could not open output file %s", requestFileName));
931 nssError ();
932 return -1;
933 }
934
935 // Read until EOF or until the expected number of bytes has been read.
936 for (totalBytes = 0; totalBytes < numBytesExpected; totalBytes += numBytesRead)
937 {
938 // No need for PR_Read_Complete here, since we're already managing multiple
939 // reads to a fixed size buffer.
940 numBytesRead = PR_Read (sslSocket, buffer, READ_BUFFER_SIZE);
941 if (numBytesRead == 0)
942 break; /* EOF */
943 if (numBytesRead < 0)
944 {
945 server_error (_("Error in PR_Read"));
946 nssError ();
947 goto done;
948 }
949
950 /* Write to the request file. */
951 numBytesWritten = PR_Write(local_file_fd, buffer, numBytesRead);
952 if (numBytesWritten < 0 || (numBytesWritten != numBytesRead))
953 {
954 server_error (_F("Could not write to output file %s", requestFileName));
955 nssError ();
956 goto done;
957 }
958 }
959
960 if (totalBytes != numBytesExpected)
961 {
962 server_error (_F("Expected %d bytes, got %d while reading client request from socket",
963 numBytesExpected, totalBytes));
964 goto done;
965 }
966
967 done:
968 if (local_file_fd)
969 PR_Close (local_file_fd);
970 return totalBytes;
971 }
972
973 /* Function: setupSSLSocket()
974 *
975 * Purpose: Configure a socket for SSL.
976 *
977 *
978 */
979 static PRFileDesc *
980 setupSSLSocket (PRFileDesc *tcpSocket, CERTCertificate *cert, SECKEYPrivateKey *privKey)
981 {
982 PRFileDesc *sslSocket;
983 SSLKEAType certKEA;
984 SECStatus secStatus;
985
986 /* Inport the socket into SSL. */
987 sslSocket = SSL_ImportFD (NULL, tcpSocket);
988 if (sslSocket == NULL)
989 {
990 server_error (_("Could not import socket into SSL"));
991 nssError ();
992 return NULL;
993 }
994
995 /* Set the appropriate flags. */
996 secStatus = SSL_OptionSet (sslSocket, SSL_SECURITY, PR_TRUE);
997 if (secStatus != SECSuccess)
998 {
999 server_error (_("Error setting SSL security for socket"));
1000 nssError ();
1001 return NULL;
1002 }
1003
1004 secStatus = SSL_OptionSet(sslSocket, SSL_HANDSHAKE_AS_SERVER, PR_TRUE);
1005 if (secStatus != SECSuccess)
1006 {
1007 server_error (_("Error setting handshake as server for socket"));
1008 nssError ();
1009 return NULL;
1010 }
1011
1012 secStatus = SSL_OptionSet(sslSocket, SSL_REQUEST_CERTIFICATE, PR_FALSE);
1013 if (secStatus != SECSuccess)
1014 {
1015 server_error (_("Error setting SSL client authentication mode for socket"));
1016 nssError ();
1017 return NULL;
1018 }
1019
1020 secStatus = SSL_OptionSet(sslSocket, SSL_REQUIRE_CERTIFICATE, PR_FALSE);
1021 if (secStatus != SECSuccess)
1022 {
1023 server_error (_("Error setting SSL client authentication mode for socket"));
1024 nssError ();
1025 return NULL;
1026 }
1027
1028 /* Set the appropriate callback routines. */
1029 #if 0 /* use the default */
1030 secStatus = SSL_AuthCertificateHook (sslSocket, myAuthCertificate, CERT_GetDefaultCertDB());
1031 if (secStatus != SECSuccess)
1032 {
1033 nssError ();
1034 server_error (_("Error in SSL_AuthCertificateHook"));
1035 return NULL;
1036 }
1037 #endif
1038 #if 0 /* Use the default */
1039 secStatus = SSL_BadCertHook(sslSocket, (SSLBadCertHandler)myBadCertHandler, &certErr);
1040 if (secStatus != SECSuccess)
1041 {
1042 nssError ();
1043 server_error (_("Error in SSL_BadCertHook"));
1044 return NULL;
1045 }
1046 #endif
1047 #if 0 /* no handshake callback */
1048 secStatus = SSL_HandshakeCallback(sslSocket, myHandshakeCallback, NULL);
1049 if (secStatus != SECSuccess)
1050 {
1051 server_error (_("Error in SSL_HandshakeCallback"));
1052 nssError ();
1053 return NULL;
1054 }
1055 #endif
1056
1057 certKEA = NSS_FindCertKEAType (cert);
1058
1059 secStatus = SSL_ConfigSecureServer (sslSocket, cert, privKey, certKEA);
1060 if (secStatus != SECSuccess)
1061 {
1062 server_error (_("Error configuring SSL server"));
1063 nssError ();
1064 return NULL;
1065 }
1066
1067 return sslSocket;
1068 }
1069
1070 #if 0 /* No client authentication (for now) and not authenticating after each transaction. */
1071 /* Function: authenticateSocket()
1072 *
1073 * Purpose: Perform client authentication on the socket.
1074 *
1075 */
1076 static SECStatus
1077 authenticateSocket (PRFileDesc *sslSocket, PRBool requireCert)
1078 {
1079 CERTCertificate *cert;
1080 SECStatus secStatus;
1081
1082 /* Returns NULL if client authentication is not enabled or if the
1083 * client had no certificate. */
1084 cert = SSL_PeerCertificate(sslSocket);
1085 if (cert)
1086 {
1087 /* Client had a certificate, so authentication is through. */
1088 CERT_DestroyCertificate(cert);
1089 return SECSuccess;
1090 }
1091
1092 /* Request client to authenticate itself. */
1093 secStatus = SSL_OptionSet(sslSocket, SSL_REQUEST_CERTIFICATE, PR_TRUE);
1094 if (secStatus != SECSuccess)
1095 {
1096 server_error (_("Error in SSL_OptionSet:SSL_REQUEST_CERTIFICATE"));
1097 nssError ();
1098 return SECFailure;
1099 }
1100
1101 /* If desired, require client to authenticate itself. Note
1102 * SSL_REQUEST_CERTIFICATE must also be on, as above. */
1103 secStatus = SSL_OptionSet(sslSocket, SSL_REQUIRE_CERTIFICATE, requireCert);
1104 if (secStatus != SECSuccess)
1105 {
1106 server_error (_("Error in SSL_OptionSet:SSL_REQUIRE_CERTIFICATE"));
1107 nssError ();
1108 return SECFailure;
1109 }
1110
1111 /* Having changed socket configuration parameters, redo handshake. */
1112 secStatus = SSL_ReHandshake(sslSocket, PR_TRUE);
1113 if (secStatus != SECSuccess)
1114 {
1115 server_error (_("Error in SSL_ReHandshake"));
1116 nssError ();
1117 return SECFailure;
1118 }
1119
1120 /* Force the handshake to complete before moving on. */
1121 secStatus = SSL_ForceHandshake(sslSocket);
1122 if (secStatus != SECSuccess)
1123 {
1124 server_error (_("Error in SSL_ForceHandshake"));
1125 nssError ();
1126 return SECFailure;
1127 }
1128
1129 return SECSuccess;
1130 }
1131 #endif /* No client authentication and not authenticating after each transaction. */
1132
1133 /* Function: writeDataToSocket
1134 *
1135 * Purpose: Write the server's response back to the socket.
1136 *
1137 */
1138 static SECStatus
1139 writeDataToSocket(PRFileDesc *sslSocket, const char *responseFileName)
1140 {
1141 PRFileDesc *local_file_fd = PR_Open (responseFileName, PR_RDONLY, 0);
1142 if (local_file_fd == NULL)
1143 {
1144 server_error (_F("Could not open input file %s", responseFileName));
1145 nssError ();
1146 return SECFailure;
1147 }
1148
1149 /* Transmit the local file across the socket.
1150 */
1151 int numBytes = PR_TransmitFile (sslSocket, local_file_fd,
1152 NULL, 0,
1153 PR_TRANSMITFILE_KEEP_OPEN,
1154 PR_INTERVAL_NO_TIMEOUT);
1155
1156 /* Error in transmission. */
1157 SECStatus secStatus = SECSuccess;
1158 if (numBytes < 0)
1159 {
1160 server_error (_("Error writing response to socket"));
1161 nssError ();
1162 secStatus = SECFailure;
1163 }
1164
1165 PR_Close (local_file_fd);
1166 return secStatus;
1167 }
1168
1169 static void
1170 get_stap_locale (const string &staplang, vector<string> &envVec, string stapstderr, cs_protocol_version *client_version)
1171 {
1172 // If the client version is < 1.6, then no file containing environment
1173 // variables defining the locale has been passed.
1174 if (*client_version < "1.6")
1175 return;
1176
1177 /* Go through each line of the file, verify it, then add it to the vector */
1178 ifstream langfile;
1179 langfile.open(staplang.c_str());
1180 if (!langfile.is_open())
1181 {
1182 // Not fatal. Proceed with the environment we have.
1183 server_error(_F("Unable to open file %s for reading: %s", staplang.c_str(),
1184 strerror (errno)));
1185 return;
1186 }
1187
1188 /* Unpackage internationalization variables and verify their contents */
1189 map<string, string> envMap; /* To temporarily store the entire array of strings */
1190 string line;
1191 const set<string> &locVars = localization_variables();
1192
1193 /* Copy the global environ variable into the map */
1194 if(environ != NULL)
1195 {
1196 for (unsigned i=0; environ[i]; i++)
1197 {
1198 string line = (string)environ[i];
1199
1200 /* Find the first '=' sign */
1201 size_t pos = line.find("=");
1202
1203 /* Make sure it found an '=' sign */
1204 if(pos != string::npos)
1205 /* Everything before the '=' sign is the key, and everything after is the value. */
1206 envMap[line.substr(0, pos)] = line.substr(pos+1);
1207 }
1208 }
1209
1210 /* Create regular expression objects to verify lines read from file. Should not allow
1211 spaces, ctrl characters, etc */
1212 regex_t checkre;
1213 if ((regcomp(&checkre, "^[a-zA-Z0-9@_.=-]*$", REG_EXTENDED | REG_NOSUB) != 0))
1214 {
1215 // Not fatal. Proceed with the environment we have.
1216 server_error(_F("Error in regcomp: %s", strerror (errno)));
1217 return;
1218 }
1219
1220 while (1)
1221 {
1222 getline(langfile, line);
1223 if (!langfile.good())
1224 break;
1225
1226 /* Extract key and value from the line. Note: value may contain "=". */
1227 string key;
1228 string value;
1229 size_t pos;
1230 pos = line.find("=");
1231 if (pos == string::npos)
1232 {
1233 client_error(_F("Localization key=value line '%s' cannot be parsed", line.c_str()), stapstderr);
1234 continue;
1235 }
1236 key = line.substr(0, pos);
1237 pos++;
1238 value = line.substr(pos);
1239
1240 /* Make sure the key is found in the localization variables global set */
1241 if (locVars.find(key) == locVars.end())
1242 {
1243 // Not fatal. Just ignore it.
1244 client_error(_F("Localization key '%s' not found in global list", key.c_str()), stapstderr);
1245 continue;
1246 }
1247
1248 /* Make sure the value does not contain illegal characters */
1249 if ((regexec(&checkre, value.c_str(), (size_t) 0, NULL, 0) != 0))
1250 {
1251 // Not fatal. Just ignore it.
1252 client_error(_F("Localization value '%s' contains illegal characters", value.c_str()), stapstderr);
1253 continue;
1254 }
1255
1256 /* All is good, copy line into envMap, replacing if already there */
1257 envMap[key] = value;
1258 }
1259
1260 if (!langfile.eof())
1261 {
1262 // Not fatal. Proceed with what we have.
1263 server_error(_F("Error reading file %s: %s", staplang.c_str(), strerror (errno)));
1264 }
1265
1266 regfree(&checkre);
1267
1268 /* Copy map into vector */
1269 for (map<string, string>::iterator it = envMap.begin(); it != envMap.end(); it++)
1270 envVec.push_back(it->first + "=" + it->second);
1271 }
1272
1273 static void
1274 get_client_mok_fingerprints (const string &filename,
1275 vector<string> &mok_fingerprints,
1276 string stapstderr,
1277 cs_protocol_version *client_version)
1278 {
1279 // If the client version is < 1.6, then no file containing MOK
1280 // fingerprints could have been passed.
1281 if (*client_version < "1.6") {
1282 return;
1283 }
1284
1285 // Go through each line of the file and add it to the vector.
1286 ifstream file;
1287 file.open(filename.c_str());
1288 if (! file.is_open())
1289 // If the file isn't present, that's fine. It just means that the
1290 // module doesn't need to be signed.
1291 return;
1292
1293 // Create a regular expression object to verify lines read from the
1294 // file.
1295 regex_t checkre;
1296 if (regcomp(&checkre, "^([0-9a-f]{2}(:[0-9a-f]{2})+)$", REG_EXTENDED)
1297 != 0)
1298 {
1299 // Not fatal, just ignore the MOK fingerprints.
1300 server_error(_F("Error in MOK fingerprint regcomp: %s",
1301 strerror (errno)));
1302 return;
1303 }
1304
1305 // Unpack the MOK fingerprints. Notice we make sure the fingerprint
1306 // is in the right format, but that's all we can do at this
1307 // point. Later we'll check this client list against our server
1308 // list.
1309 string line;
1310 regmatch_t matches[3];
1311 while (getline (file, line))
1312 {
1313 string fingerprint, issuer;
1314
1315 if ((regexec(&checkre, line.c_str(), 3, matches, 0) != 0))
1316 {
1317 // Not fatal. Just ignore it.
1318 client_error(_F("MOK fingerprint value '%s' isn't in the correct forma",
1319 line.c_str()), stapstderr);
1320 continue;
1321 }
1322
1323 // Save the fingerprint:
1324 // matches[0] is the range of the entire match
1325 // matches[1] is the entire fingerprint
1326 // matches[2] is a portion of the fingerprint
1327 if (matches[1].rm_so >= 0)
1328 fingerprint = line.substr(matches[1].rm_so,
1329 matches[1].rm_eo - matches[1].rm_so);
1330 if (! fingerprint.empty())
1331 mok_fingerprints.push_back(fingerprint);
1332 }
1333 regfree(&checkre);
1334 }
1335
1336 void
1337 mok_sign_file (mok_info_t &mok_info,
1338 const std::string &kernel_build_tree,
1339 const std::string &name,
1340 std::string stapstderr)
1341 {
1342 vector<string> cmd;
1343 int rc;
1344
1345 cmd.clear();
1346 cmd.push_back (kernel_build_tree + "/scripts/sign-file");
1347 cmd.push_back ("sha512");
1348 cmd.push_back (mok_info.directory + "/signing_key.priv");
1349 cmd.push_back (mok_info.directory + "/signing_key.x509");
1350 cmd.push_back (name);
1351 // FIXME: Should we do anything if this fails?
1352 rc = stap_system (0, cmd);
1353 if (rc != 0)
1354 server_error (_F("Running sign-file failed, rc = %d", rc));
1355 else
1356 client_error (_F("Module signed with MOK, issuer \"%s\", serial number \"%s\"",
1357 mok_info.issuer.c_str(), mok_info.serial_number.c_str()),
1358 stapstderr);
1359 }
1360
1361 // Filter paths prefixed with the server's home directory from the given file.
1362 //
1363 static void
1364 filter_response_file (const string &file_name, const string &responseDirName)
1365 {
1366 vector<string> cmd;
1367
1368 // Filter the server's home directory name
1369 cmd.clear();
1370 cmd.push_back ("sed");
1371 cmd.push_back ("-i");
1372 cmd.push_back (string ("s,") + get_home_directory () + ",<server>,g");
1373 cmd.push_back (file_name);
1374 stap_system (0, cmd);
1375
1376 // Filter the server's response directory name
1377 cmd.clear();
1378 cmd.push_back ("sed");
1379 cmd.push_back ("-i");
1380 cmd.push_back (string ("s,") + responseDirName + ",<server>,g");
1381 cmd.push_back (file_name);
1382 stap_system (0, cmd);
1383 }
1384
1385 static privilege_t
1386 getRequestedPrivilege (const vector<string> &stapargv)
1387 {
1388 // The purpose of this function is to find the --privilege or --unprivileged option specified
1389 // by the user on the client side. We need to parse the command line completely, but we can
1390 // exit when we find the first --privilege or --unprivileged option, since stap does not allow
1391 // multiple privilege levels to specified on the same command line.
1392 //
1393 // Note that we need not do any options consistency checking since our spawned stap instance
1394 // will do that.
1395 //
1396 // Create an argv/argc for use by getopt_long.
1397 int argc = stapargv.size();
1398 char ** argv = new char *[argc + 1];
1399 for (unsigned i = 0; i < stapargv.size(); ++i)
1400 argv[i] = (char *)stapargv[i].c_str();
1401 argv[argc] = NULL;
1402
1403 privilege_t privilege = pr_highest; // Until specified otherwise.
1404 optind = 1;
1405 while (true)
1406 {
1407 // We need only allow getopt to parse the options until we find a
1408 // --privilege or --unprivileged option.
1409 int grc = getopt_long (argc, argv, STAP_SHORT_OPTIONS, stap_long_options, NULL);
1410 if (grc < 0)
1411 break;
1412 switch (grc)
1413 {
1414 default:
1415 // We can ignore all options other than --privilege and --unprivileged.
1416 break;
1417 case LONG_OPT_PRIVILEGE:
1418 if (strcmp (optarg, "stapdev") == 0)
1419 privilege = pr_stapdev;
1420 else if (strcmp (optarg, "stapsys") == 0)
1421 privilege = pr_stapsys;
1422 else if (strcmp (optarg, "stapusr") == 0)
1423 privilege = pr_stapusr;
1424 else
1425 {
1426 server_error (_F("Invalid argument '%s' for --privilege", optarg));
1427 privilege = pr_highest;
1428 }
1429 // We have discovered the client side --privilege option. We can exit now since
1430 // stap only tolerates one privilege setting option.
1431 goto done; // break 2 switches and a loop
1432 case LONG_OPT_UNPRIVILEGED:
1433 privilege = pr_unprivileged;
1434 // We have discovered the client side --unprivileged option. We can exit now since
1435 // stap only tolerates one privilege setting option.
1436 goto done; // break 2 switches and a loop
1437 }
1438 }
1439 done:
1440 delete[] argv;
1441 return privilege;
1442 }
1443
1444 /* Run the translator on the data in the request directory, and produce output
1445 in the given output directory. */
1446 static void
1447 handleRequest (const string &requestDirName, const string &responseDirName, string stapstderr)
1448 {
1449 vector<string> stapargv;
1450 cs_protocol_version client_version = "1.0"; // Assumed until discovered otherwise
1451 int rc;
1452 wordexp_t words;
1453 unsigned u;
1454 unsigned i;
1455 FILE* f;
1456
1457 // Save the server version. Do this early, so the client knows what version of the server
1458 // it is dealing with, even if the request is not fully completed.
1459 string stapversion = responseDirName + "/version";
1460 f = fopen (stapversion.c_str (), "w");
1461 if (f)
1462 {
1463 fputs (CURRENT_CS_PROTOCOL_VERSION, f);
1464 fclose(f);
1465 }
1466 else
1467 server_error (_F("Unable to open client version file %s", stapversion.c_str ()));
1468
1469 // Get the client version. The default version is already set. Use it if we fail here.
1470 string filename = requestDirName + "/version";
1471 if (file_exists (filename))
1472 read_from_file (filename, client_version);
1473 log (_F("Client version is %s", client_version.v));
1474
1475 // The name of the translator executable.
1476 stapargv.push_back ((char *)(getenv ("SYSTEMTAP_STAP") ?: STAP_PREFIX "/bin/stap"));
1477
1478 /* Transcribe stap_options. We use plain wordexp(3), since these
1479 options are coming from the local trusted user, so malicious
1480 content is not a concern. */
1481 // TODO: Use tokenize here.
1482 rc = wordexp (stap_options.c_str (), & words, WRDE_NOCMD|WRDE_UNDEF);
1483 if (rc)
1484 {
1485 server_error (_("Cannot parse stap options"));
1486 return;
1487 }
1488
1489 for (u=0; u<words.we_wordc; u++)
1490 stapargv.push_back (words.we_wordv[u]);
1491
1492 /* Process the saved command line arguments. Avoid quoting/unquoting errors by
1493 transcribing literally. */
1494 string new_staptmpdir = responseDirName + "/stap000000";
1495 rc = mkdir(new_staptmpdir.c_str(), 0700);
1496 if (rc)
1497 server_error(_F("Could not create temporary directory %s", new_staptmpdir.c_str()));
1498
1499 stapargv.push_back("--tmpdir=" + new_staptmpdir);
1500
1501 stapargv.push_back ("--client-options");
1502 for (i=1 ; ; i++)
1503 {
1504 char stapargfile[PATH_MAX];
1505 FILE* argfile;
1506 struct stat st;
1507 char *arg;
1508
1509 snprintf (stapargfile, PATH_MAX, "%s/argv%d", requestDirName.c_str (), i);
1510
1511 rc = stat(stapargfile, & st);
1512 if (rc) break;
1513
1514 arg = (char *)malloc (st.st_size+1);
1515 if (!arg)
1516 {
1517 server_error (_("Out of memory"));
1518 return;
1519 }
1520
1521 argfile = fopen(stapargfile, "r");
1522 if (! argfile)
1523 {
1524 free(arg);
1525 server_error (_F("Error opening %s: %s", stapargfile, strerror (errno)));
1526 return;
1527 }
1528
1529 rc = fread(arg, 1, st.st_size, argfile);
1530 if (rc != st.st_size)
1531 {
1532 free(arg);
1533 fclose(argfile);
1534 server_error (_F("Error reading %s: %s", stapargfile, strerror (errno)));
1535 return;
1536 }
1537
1538 arg[st.st_size] = '\0';
1539 stapargv.push_back (arg);
1540 free (arg);
1541 fclose (argfile);
1542 }
1543
1544 string stapstdout = responseDirName + "/stdout";
1545
1546 // NB: Before, when we did not fully parse the client's command line using getopt_long,
1547 // we used to insert a --privilege=XXX option here in case some other argument was mistaken
1548 // for a --privilege or --unprivileged option by our spawned stap. Since we now parse
1549 // the client's command line using getopt_long and share the getopt_long options
1550 // string and table with stap, this is no longer necessary. stap will parse the
1551 // command line identically to the way we have parsed it and will discover the same
1552 // privilege-setting option.
1553
1554 // Environment variables (possibly empty) to be passed to spawn_and_wait().
1555 string staplang = requestDirName + "/locale";
1556 vector<string> envVec;
1557 get_stap_locale (staplang, envVec, stapstderr, &client_version);
1558
1559 // Machine owner keys (MOK) fingerprints (possibly nonexistent), to
1560 // be used as a list of valid keys that the module must be signed with.
1561 vector<string> client_mok_fingerprints;
1562
1563 // Matching MOK fingerprint path and issuer.
1564 mok_info_t *mok_info = NULL;
1565 get_client_mok_fingerprints(requestDirName + "/mok_fingerprints",
1566 client_mok_fingerprints, stapstderr,
1567 &client_version);
1568 if (! client_mok_fingerprints.empty())
1569 {
1570 // If the client requires signing, and we don't have any keys on
1571 // the server, we can't build a signed module.
1572 if (server_mok_map.empty())
1573 {
1574 client_error(_("No machine owner keys (MOK) are available on the server to sign the module."), stapstderr);
1575 return;
1576 }
1577
1578 // Check the list of client MOK fingerprints against the list of
1579 // server MOK fingerprints. Look for any match.
1580 vector<string>::const_iterator it;
1581 for (it = client_mok_fingerprints.begin();
1582 it != client_mok_fingerprints.end(); it++)
1583 {
1584 mok_map_iterator mi;
1585 mi = server_mok_map.find(*it);
1586 if (mi != server_mok_map.end())
1587 {
1588 mok_info = mi->second;
1589 break;
1590 }
1591 }
1592
1593 // If the client requires signing, but we couldn't find a
1594 // matching machine owner key installed on the server, we can't
1595 // build a signed module.
1596 if (mok_info == NULL)
1597 {
1598 client_error(_("No matching machine owner key (MOK) available on the server to sign the module."), stapstderr);
1599 return;
1600 }
1601 server_error(_F("The module will be signed with the following MOK, issuer=\"%s\" serial number=\"%s\"",
1602 mok_info->issuer.c_str(),
1603 mok_info->serial_number.c_str()));
1604 }
1605
1606 /* All ready, let's run the translator! */
1607 int staprc;
1608 rc = spawn_and_wait(stapargv, &staprc, "/dev/null", stapstdout.c_str (),
1609 stapstderr.c_str (), requestDirName.c_str (), envVec);
1610 if (rc != PR_SUCCESS)
1611 {
1612 server_error(_("Failed spawning translator"));
1613 return;
1614 }
1615
1616 /* Save the RC */
1617 ofstream ofs((responseDirName + "/rc").c_str());
1618 ofs << staprc;
1619 ofs.close();
1620
1621 // In unprivileged modes, if we have a module built, we need to sign
1622 // the sucker. We also might need to sign the module for secure
1623 // boot purposes.
1624 privilege_t privilege = getRequestedPrivilege (stapargv);
1625 if (pr_contains (privilege, pr_stapusr)
1626 || pr_contains (privilege, pr_stapsys) || mok_info)
1627 {
1628 glob_t globber;
1629 char pattern[PATH_MAX];
1630 snprintf (pattern, PATH_MAX, "%s/*.ko", new_staptmpdir.c_str());
1631 rc = glob (pattern, GLOB_ERR, NULL, &globber);
1632 if (rc)
1633 server_error (_F("Unable to find a module in %s", new_staptmpdir.c_str()));
1634 else if (globber.gl_pathc != 1)
1635 server_error (_F("Too many modules (%zu) in %s", globber.gl_pathc, new_staptmpdir.c_str()));
1636 else
1637 {
1638 if (pr_contains (privilege, pr_stapusr)
1639 || pr_contains (privilege, pr_stapsys))
1640 sign_file (cert_db_path, server_cert_nickname(),
1641 globber.gl_pathv[0],
1642 string(globber.gl_pathv[0]) + ".sgn");
1643 if (mok_info)
1644 mok_sign_file(*mok_info, kernel_build_tree, globber.gl_pathv[0],
1645 stapstderr);
1646 }
1647 }
1648
1649 /* If uprobes.ko is required, it will have been built or cache-copied into
1650 * the temp directory. We need to pack it into the response where the client
1651 * can find it, and sign, if necessary, for unprivileged users.
1652 */
1653 string uprobes_ko = new_staptmpdir + "/uprobes/uprobes.ko";
1654 if (get_file_size(uprobes_ko) > 0)
1655 {
1656 /* uprobes.ko is required.
1657 *
1658 * It's already underneath the stap tmpdir, but older stap clients
1659 * don't know to look for it there, so, for these clients, we end up packing uprobes twice
1660 * into the zip. We could move instead of symlink.
1661 */
1662 string uprobes_response;
1663 if (client_version < "1.6")
1664 {
1665 uprobes_response = (string)responseDirName + "/uprobes.ko";
1666 rc = symlink(uprobes_ko.c_str(), uprobes_response.c_str());
1667 if (rc != 0)
1668 server_error (_F("Could not link to %s from %s",
1669 uprobes_ko.c_str(), uprobes_response.c_str()));
1670 }
1671 else
1672 uprobes_response = uprobes_ko;
1673
1674 /* In unprivileged mode, we need a signature on uprobes as well. */
1675 if (! pr_contains (privilege, pr_stapdev))
1676 {
1677 sign_file (cert_db_path, server_cert_nickname(),
1678 uprobes_response, uprobes_response + ".sgn");
1679 }
1680 if (mok_info)
1681 mok_sign_file(*mok_info, kernel_build_tree, uprobes_response,
1682 stapstderr);
1683 }
1684
1685 /* Free up all the arg string copies. Note that the first few were alloc'd
1686 by wordexp(), which wordfree() frees; others were hand-set to literal strings. */
1687 wordfree (& words);
1688
1689 // Filter paths prefixed with the server's home directory from the stdout and stderr
1690 // files in the response.
1691 filter_response_file (stapstdout, responseDirName);
1692 filter_response_file (stapstderr, responseDirName);
1693
1694 /* Sorry about the inconvenience. C string/file processing is such a pleasure. */
1695 }
1696
1697
1698 /* A front end for stap_spawn that handles stdin, stdout, stderr, switches to a working
1699 directory and returns overall success or failure. */
1700 static PRStatus
1701 spawn_and_wait (const vector<string> &argv, int *spawnrc,
1702 const char* fd0, const char* fd1, const char* fd2,
1703 const char *pwd, const vector<string>& envVec)
1704 {
1705 pid_t pid;
1706 int rc;
1707 posix_spawn_file_actions_t actions;
1708 int dotfd = -1;
1709
1710 #define CHECKRC(msg) do { if (rc) { server_error (_(msg)); return PR_FAILURE; } } while (0)
1711
1712 rc = posix_spawn_file_actions_init (& actions);
1713 CHECKRC ("Error in spawn file actions ctor");
1714 if (fd0) {
1715 rc = posix_spawn_file_actions_addopen(& actions, 0, fd0, O_RDONLY, 0600);
1716 CHECKRC ("Error in spawn file actions fd0");
1717 }
1718 if (fd1) {
1719 rc = posix_spawn_file_actions_addopen(& actions, 1, fd1, O_WRONLY|O_CREAT, 0600);
1720 CHECKRC ("Error in spawn file actions fd1");
1721 }
1722 if (fd2) {
1723 // Use append mode for stderr because it gets written to in other places in the server.
1724 rc = posix_spawn_file_actions_addopen(& actions, 2, fd2, O_WRONLY|O_APPEND|O_CREAT, 0600);
1725 CHECKRC ("Error in spawn file actions fd2");
1726 }
1727
1728 /* change temporarily to a directory if requested */
1729 if (pwd)
1730 {
1731 dotfd = open (".", O_RDONLY);
1732 if (dotfd < 0)
1733 {
1734 server_error (_("Error in spawn getcwd"));
1735 return PR_FAILURE;
1736 }
1737
1738 rc = chdir (pwd);
1739 if (rc)
1740 {
1741 close(dotfd);
1742 server_error(_("Error in spawn chdir"));
1743 return PR_FAILURE;
1744 }
1745 }
1746
1747 pid = stap_spawn (0, argv, & actions, envVec);
1748 /* NB: don't react to pid==-1 right away; need to chdir back first. */
1749
1750 if (pwd && dotfd >= 0)
1751 {
1752 int subrc;
1753 subrc = fchdir (dotfd);
1754 subrc |= close (dotfd);
1755 if (subrc)
1756 server_error (_("Error in spawn unchdir"));
1757 }
1758
1759 if (pid == -1)
1760 {
1761 server_error (_F("Error in spawn: %s", strerror (errno)));
1762 return PR_FAILURE;
1763 }
1764
1765 *spawnrc = stap_waitpid (0, pid);
1766 if (*spawnrc == -1) // something wrong with waitpid() call itself
1767 {
1768 server_error (_("Error in waitpid"));
1769 return PR_FAILURE;
1770 }
1771
1772 rc = posix_spawn_file_actions_destroy (&actions);
1773 CHECKRC ("Error in spawn file actions dtor");
1774
1775 return PR_SUCCESS;
1776 #undef CHECKRC
1777 }
1778
1779 /* Function: void *handle_connection()
1780 *
1781 * Purpose: Handle a connection to a socket. Copy in request zip
1782 * file, process it, copy out response. Temporary directories are
1783 * created & destroyed here.
1784 */
1785
1786 void *
1787 handle_connection (void *arg)
1788 {
1789 PRFileDesc * sslSocket = NULL;
1790 SECStatus secStatus = SECFailure;
1791 PRStatus prStatus;
1792 int rc;
1793 char *rc1;
1794 char tmpdir[PATH_MAX];
1795 char requestFileName[PATH_MAX];
1796 char requestDirName[PATH_MAX];
1797 char responseDirName[PATH_MAX];
1798 char responseFileName[PATH_MAX];
1799 string stapstderr; /* Cannot be global since we need a unique
1800 copy for each connection.*/
1801 vector<string> argv;
1802 PRInt32 bytesRead;
1803
1804 /* Detatch to avoid a memory leak */
1805 if(max_threads > 0)
1806 pthread_detach(pthread_self());
1807
1808 /* Unpack the arg */
1809 thread_arg *t_arg = (thread_arg *) arg;
1810 PRFileDesc *tcpSocket = t_arg->tcpSocket;
1811 CERTCertificate *cert = t_arg->cert;
1812 SECKEYPrivateKey *privKey = t_arg->privKey;
1813 PRNetAddr addr = t_arg->addr;
1814
1815 tmpdir[0]='\0'; /* prevent cleanup-time /bin/rm of uninitialized directory */
1816
1817 #if 0 // already done on the listenSocket
1818 /* Make sure the socket is blocking. */
1819 PRSocketOptionData socketOption;
1820 socketOption.option = PR_SockOpt_Nonblocking;
1821 socketOption.value.non_blocking = PR_FALSE;
1822 PR_SetSocketOption (tcpSocket, &socketOption);
1823 #endif
1824 secStatus = SECFailure;
1825 sslSocket = setupSSLSocket (tcpSocket, cert, privKey);
1826 if (sslSocket == NULL)
1827 {
1828 // Message already issued.
1829 goto cleanup;
1830 }
1831
1832 secStatus = SSL_ResetHandshake(sslSocket, /* asServer */ PR_TRUE);
1833 if (secStatus != SECSuccess)
1834 {
1835 server_error (_("Error resetting SSL handshake"));
1836 nssError ();
1837 goto cleanup;
1838 }
1839
1840 #if 0 // The client authenticates the server, so the client initiates the handshake
1841 /* Force the handshake to complete before moving on. */
1842 secStatus = SSL_ForceHandshake(sslSocket);
1843 if (secStatus != SECSuccess)
1844 {
1845 server_error (_("Error forcing SSL handshake"));
1846 nssError ();
1847 goto cleanup;
1848 }
1849 #endif
1850
1851 secStatus = SECFailure;
1852 snprintf(tmpdir, PATH_MAX, "%s/stap-server.XXXXXX", getenv("TMPDIR") ?: "/tmp");
1853 rc1 = mkdtemp(tmpdir);
1854 if (! rc1)
1855 {
1856 server_error (_F("Could not create temporary directory %s: %s", tmpdir, strerror(errno)));
1857 tmpdir[0]=0; /* prevent /bin/rm */
1858 goto cleanup;
1859 }
1860
1861 /* Create a temporary files names and directories. */
1862 snprintf (requestFileName, PATH_MAX, "%s/request.zip", tmpdir);
1863
1864 snprintf (requestDirName, PATH_MAX, "%s/request", tmpdir);
1865 rc = mkdir(requestDirName, 0700);
1866 if (rc)
1867 {
1868 server_error (_F("Could not create temporary directory %s: %s", requestDirName, strerror (errno)));
1869 goto cleanup;
1870 }
1871
1872 snprintf (responseDirName, PATH_MAX, "%s/response", tmpdir);
1873 rc = mkdir(responseDirName, 0700);
1874 if (rc)
1875 {
1876 server_error (_F("Could not create temporary directory %s: %s", responseDirName, strerror (errno)));
1877 goto cleanup;
1878 }
1879 // Set this early, since it gets used for errors to be returned to the client.
1880 stapstderr = string(responseDirName) + "/stderr";
1881
1882 snprintf (responseFileName, PATH_MAX, "%s/response.zip", tmpdir);
1883
1884 /* Read data from the socket.
1885 * If the user is requesting/requiring authentication, authenticate
1886 * the socket. */
1887 bytesRead = readDataFromSocket(sslSocket, requestFileName);
1888 if (bytesRead < 0) // Error
1889 goto cleanup;
1890 if (bytesRead == 0) // No request -- not an error
1891 {
1892 secStatus = SECSuccess;
1893 goto cleanup;
1894 }
1895
1896 #if 0 /* Don't authenticate after each transaction */
1897 if (REQUEST_CERT_ALL)
1898 {
1899 secStatus = authenticateSocket(sslSocket);
1900 if (secStatus != SECSuccess)
1901 goto cleanup;
1902 }
1903 #endif
1904
1905 /* Unzip the request. */
1906 secStatus = SECFailure;
1907 argv.push_back ("unzip");
1908 argv.push_back ("-q");
1909 argv.push_back ("-d");
1910 argv.push_back (requestDirName);
1911 argv.push_back (requestFileName);
1912 rc = stap_system (0, argv);
1913 if (rc != 0)
1914 {
1915 server_error (_("Unable to extract client request"));
1916 goto cleanup;
1917 }
1918
1919 /* Handle the request zip file. An error therein should still result
1920 in a response zip file (containing stderr etc.) so we don't have to
1921 have a result code here. */
1922 handleRequest(requestDirName, responseDirName, stapstderr);
1923
1924 /* Zip the response. */
1925 int ziprc;
1926 argv.clear ();
1927 argv.push_back ("zip");
1928 argv.push_back ("-q");
1929 argv.push_back ("-r");
1930 argv.push_back (responseFileName);
1931 argv.push_back (".");
1932 rc = spawn_and_wait (argv, &ziprc, NULL, NULL, NULL, responseDirName);
1933 if (rc != PR_SUCCESS || ziprc != 0)
1934 {
1935 server_error (_("Unable to compress server response"));
1936 goto cleanup;
1937 }
1938
1939 secStatus = writeDataToSocket (sslSocket, responseFileName);
1940
1941 cleanup:
1942 if (sslSocket)
1943 if (PR_Close (sslSocket) != PR_SUCCESS)
1944 {
1945 server_error (_("Error closing ssl socket"));
1946 nssError ();
1947 }
1948
1949 if (tmpdir[0])
1950 {
1951 // Remove the whole tmpdir and all that lies beneath, unless -k was specified.
1952 if (keep_temp)
1953 log (_F("Keeping temporary directory %s", tmpdir));
1954 else
1955 {
1956 argv.clear ();
1957 argv.push_back ("rm");
1958 argv.push_back ("-r");
1959 argv.push_back (tmpdir);
1960 rc = stap_system (0, argv);
1961 if (rc != 0)
1962 server_error (_("Error in tmpdir cleanup"));
1963 }
1964 }
1965
1966 if (secStatus != SECSuccess)
1967 server_error (_("Error processing client request"));
1968
1969 // Log the end of the request.
1970 char buf[1024];
1971 prStatus = PR_NetAddrToString (& addr, buf, sizeof (buf));
1972 if (prStatus == PR_SUCCESS)
1973 {
1974 if (addr.raw.family == PR_AF_INET)
1975 log (_F("Request from %s:%d complete", buf, addr.inet.port));
1976 else if (addr.raw.family == PR_AF_INET6)
1977 log (_F("Request from [%s]:%d complete", buf, addr.ipv6.port));
1978 }
1979
1980 /* Increment semephore to indicate this thread is finished. */
1981 free(t_arg);
1982 if (max_threads > 0)
1983 {
1984 sem_post(&sem_client);
1985 pthread_exit(0);
1986 }
1987 else
1988 return 0;
1989 }
1990
1991 /* Function: int accept_connection()
1992 *
1993 * Purpose: Accept a connection to the socket.
1994 *
1995 */
1996 static SECStatus
1997 accept_connections (PRFileDesc *listenSocket, CERTCertificate *cert)
1998 {
1999 PRNetAddr addr;
2000 PRFileDesc *tcpSocket;
2001 PRStatus prStatus;
2002 SECStatus secStatus;
2003 CERTCertDBHandle *dbHandle;
2004 pthread_t tid;
2005 thread_arg *t_arg;
2006
2007
2008 dbHandle = CERT_GetDefaultCertDB ();
2009
2010 // cert_db_path gets passed to nssPasswordCallback.
2011 SECKEYPrivateKey *privKey = PK11_FindKeyByAnyCert (cert, (void*)cert_db_path.c_str ());
2012 if (privKey == NULL)
2013 {
2014 server_error (_("Unable to obtain certificate private key"));
2015 nssError ();
2016 return SECFailure;
2017 }
2018
2019 while (pending_interrupts == 0)
2020 {
2021 /* Accept a connection to the socket. */
2022 tcpSocket = PR_Accept (listenSocket, &addr, PR_INTERVAL_MIN);
2023 if (tcpSocket == NULL)
2024 {
2025 if(PR_GetError() == PR_IO_TIMEOUT_ERROR)
2026 continue;
2027 else
2028 {
2029 server_error (_("Error accepting client connection"));
2030 break;
2031 }
2032 }
2033
2034 /* Log the accepted connection. */
2035 char buf[1024];
2036 prStatus = PR_NetAddrToString (&addr, buf, sizeof (buf));
2037 if (prStatus == PR_SUCCESS)
2038 {
2039 if (addr.raw.family == PR_AF_INET)
2040 log (_F("Accepted connection from %s:%d", buf, addr.inet.port));
2041 else if (addr.raw.family == PR_AF_INET6)
2042 log (_F("Accepted connection from [%s]:%d", buf, addr.ipv6.port));
2043 }
2044
2045 /* XXX: alarm() or somesuch to set a timeout. */
2046
2047 /* Accepted the connection, now handle it. */
2048
2049 /* Wait for a thread to finish if there are none available */
2050 if(max_threads >0)
2051 {
2052 int idle_threads;
2053 sem_getvalue(&sem_client, &idle_threads);
2054 if(idle_threads <= 0)
2055 log(_("Server is overloaded. Processing times may be longer than normal."));
2056 else if (idle_threads == max_threads)
2057 log(_("Processing 1 request..."));
2058 else
2059 log(_F("Processing %d concurrent requests...", ((int)max_threads - idle_threads) + 1));
2060
2061 sem_wait(&sem_client);
2062 }
2063
2064 /* Create the argument structure to pass to pthread_create
2065 * (or directly to handle_connection if max_threads == 0 */
2066 t_arg = (thread_arg *)malloc(sizeof(*t_arg));
2067 if (t_arg == 0)
2068 fatal(_("No memory available for new thread arg!"));
2069 t_arg->tcpSocket = tcpSocket;
2070 t_arg->cert = cert;
2071 t_arg->privKey = privKey;
2072 t_arg->addr = addr;
2073
2074 /* Handle the conncection */
2075 if (max_threads > 0)
2076 /* Create the worker thread and handle the connection. */
2077 pthread_create(&tid, NULL, handle_connection, t_arg);
2078 else
2079 /* Since max_threads == 0, don't spawn a new thread,
2080 * just handle in the current thread. */
2081 handle_connection(t_arg);
2082
2083 // If our certificate is no longer valid (e.g. has expired), then exit.
2084 secStatus = CERT_VerifyCertNow (dbHandle, cert, PR_TRUE/*checkSig*/,
2085 certUsageSSLServer, NULL/*wincx*/);
2086 if (secStatus != SECSuccess)
2087 {
2088 // Not an error. Exit the loop so a new cert can be generated.
2089 break;
2090 }
2091 }
2092
2093 SECKEY_DestroyPrivateKey (privKey);
2094 return SECSuccess;
2095 }
2096
2097 /* Function: void server_main()
2098 *
2099 * Purpose: This is the server's main function. It configures a socket
2100 * and listens to it.
2101 *
2102 */
2103 static SECStatus
2104 server_main (PRFileDesc *listenSocket)
2105 {
2106 int idle_threads;
2107 int timeout = 0;
2108
2109 // Initialize NSS.
2110 SECStatus secStatus = nssInit (cert_db_path.c_str ());
2111 if (secStatus != SECSuccess)
2112 {
2113 // Message already issued.
2114 return secStatus;
2115 }
2116
2117 // Preinitialized here due to jumps to the label 'done'.
2118 CERTCertificate *cert = NULL;
2119 bool serverCacheConfigured = false;
2120
2121 // Enable all cipher suites.
2122 // NB: The NSS docs say that SSL_ClearSessionCache is required for the new settings to take
2123 // effect, however, calling it puts NSS in a state where it will not shut down cleanly.
2124 // We need to be able to shut down NSS cleanly if we are to generate a new certificate when
2125 // ours expires. It should be noted however, thet SSL_ClearSessionCache only clears the
2126 // client cache, and we are a server.
2127 /* Some NSS versions don't do this correctly in NSS_SetDomesticPolicy. */
2128 do {
2129 const PRUint16 *cipher;
2130 for (cipher = SSL_ImplementedCiphers; *cipher != 0; ++cipher)
2131 SSL_CipherPolicySet(*cipher, SSL_ALLOWED);
2132 } while (0);
2133 // SSL_ClearSessionCache ();
2134
2135 // Configure the SSL session cache for a single process server with the default settings.
2136 secStatus = SSL_ConfigServerSessionIDCache (0, 0, 0, NULL);
2137 if (secStatus != SECSuccess)
2138 {
2139 server_error (_("Unable to configure SSL server session ID cache"));
2140 nssError ();
2141 goto done;
2142 }
2143 serverCacheConfigured = true;
2144
2145 /* Get own certificate. */
2146 cert = PK11_FindCertFromNickname (server_cert_nickname (), NULL);
2147 if (cert == NULL)
2148 {
2149 server_error (_F("Unable to find our certificate in the database at %s",
2150 cert_db_path.c_str ()));
2151 nssError ();
2152 goto done;
2153 }
2154
2155 // Tell the world that we're listening.
2156 advertise_presence (cert);
2157
2158 /* Handle connections to the socket. */
2159 secStatus = accept_connections (listenSocket, cert);
2160
2161 // Tell the world we're no longer listening.
2162 unadvertise_presence ();
2163
2164 sem_getvalue(&sem_client, &idle_threads);
2165
2166 /* Wait for requests to finish or the timeout to be reached.
2167 * If we got here from an interrupt, exit immediately if
2168 * the timeout is reached. Otherwise, wait indefinitiely
2169 * until the threads exit (or an interrupt is recieved).*/
2170 if(idle_threads < max_threads)
2171 log(_F("Waiting for %d outstanding requests to complete...", (int)max_threads - idle_threads));
2172 while(idle_threads < max_threads)
2173 {
2174 if(pending_interrupts && timeout++ > CONCURRENCY_TIMEOUT_S)
2175 {
2176 log(_("Timeout reached, exiting (forced)"));
2177 kill_stap_spawn (SIGTERM);
2178 cleanup ();
2179 _exit(0);
2180 }
2181 sleep(1);
2182 sem_getvalue(&sem_client, &idle_threads);
2183 }
2184
2185 done:
2186 // Clean up
2187 if (cert)
2188 CERT_DestroyCertificate (cert);
2189
2190 // Shutdown NSS
2191 if (serverCacheConfigured && SSL_ShutdownServerSessionIDCache () != SECSuccess)
2192 {
2193 server_error (_("Unable to shut down server session ID cache"));
2194 nssError ();
2195 }
2196 nssCleanup (cert_db_path.c_str ());
2197
2198 return secStatus;
2199 }
2200
2201 static void
2202 listen ()
2203 {
2204 // Create a new socket.
2205 PRFileDesc *listenSocket = PR_OpenTCPSocket (PR_AF_INET6); // Accepts IPv4 too
2206 if (listenSocket == NULL)
2207 {
2208 server_error (_("Error creating socket"));
2209 nssError ();
2210 return;
2211 }
2212
2213 // Set socket to be blocking - on some platforms the default is nonblocking.
2214 PRSocketOptionData socketOption;
2215 socketOption.option = PR_SockOpt_Nonblocking;
2216 socketOption.value.non_blocking = PR_FALSE;
2217 PRStatus prStatus = PR_SetSocketOption (listenSocket, & socketOption);
2218 if (prStatus != PR_SUCCESS)
2219 {
2220 server_error (_("Error setting socket properties"));
2221 nssError ();
2222 goto done;
2223 }
2224
2225 // Allow the socket address to be reused, in case we want the same port across a
2226 // 'service stap-server restart'
2227 socketOption.option = PR_SockOpt_Reuseaddr;
2228 socketOption.value.reuse_addr = PR_TRUE;
2229 prStatus = PR_SetSocketOption (listenSocket, & socketOption);
2230 if (prStatus != PR_SUCCESS)
2231 {
2232 server_error (_("Error setting socket properties"));
2233 nssError ();
2234 goto done;
2235 }
2236
2237 // Configure the network connection.
2238 PRNetAddr addr;
2239 memset (& addr, 0, sizeof(addr));
2240 prStatus = PR_InitializeNetAddr (PR_IpAddrAny, port, & addr);
2241 addr.ipv6.family = PR_AF_INET6;
2242 #if 0
2243 // addr.inet.ip = PR_htonl(PR_INADDR_ANY);
2244 PR_StringToNetAddr ("::", & addr);
2245 // PR_StringToNetAddr ("fe80::5eff:35ff:fe07:55ca", & addr);
2246 // PR_StringToNetAddr ("::1", & addr);
2247 addr.ipv6.port = PR_htons (port);
2248 #endif
2249
2250 // Bind the socket to an address. Retry if the selected port is busy, unless the port was
2251 // specified directly.
2252 for (;;)
2253 {
2254 /* Bind the address to the listener socket. */
2255 prStatus = PR_Bind (listenSocket, & addr);
2256 if (prStatus == PR_SUCCESS)
2257 break;
2258
2259 // If the selected port is busy. Try another, but only if a specific port was not specified.
2260 PRErrorCode errorNumber = PR_GetError ();
2261 switch (errorNumber)
2262 {
2263 case PR_ADDRESS_NOT_AVAILABLE_ERROR:
2264 if (port == 0)
2265 {
2266 server_error (_F("Network port %hu is unavailable. Trying another port", port));
2267 continue;
2268 }
2269 break;
2270 case PR_ADDRESS_IN_USE_ERROR:
2271 if (port == 0)
2272 {
2273 server_error (_F("Network port %hu is busy. Trying another port", port));
2274 continue;
2275 }
2276 break;
2277 default:
2278 break;
2279 }
2280 server_error (_("Error setting socket address"));
2281 nssError ();
2282 goto done;
2283 }
2284
2285 // Query the socket for the port that was assigned.
2286 prStatus = PR_GetSockName (listenSocket, &addr);
2287 if (prStatus != PR_SUCCESS)
2288 {
2289 server_error (_("Unable to obtain socket address"));
2290 nssError ();
2291 goto done;
2292 }
2293 char buf[1024];
2294 prStatus = PR_NetAddrToString (&addr, buf, sizeof (buf));
2295 port = PR_ntohs (addr.ipv6.port);
2296 log (_F("Using network address [%s]:%hu", buf, port));
2297
2298 if (max_threads > 0)
2299 log (_F("Using a maximum of %ld threads", max_threads));
2300 else
2301 log (_("Concurrency disabled"));
2302
2303 // Listen for connection on the socket. The second argument is the maximum size of the queue
2304 // for pending connections.
2305 prStatus = PR_Listen (listenSocket, 5);
2306 if (prStatus != PR_SUCCESS)
2307 {
2308 server_error (_("Error listening on socket"));
2309 nssError ();
2310 goto done;
2311 }
2312
2313 /* Initialize semephore with the maximum number of threads
2314 * defined by --max-threads. If it is not defined, the
2315 * default is the number of processors */
2316 sem_init(&sem_client, 0, max_threads);
2317
2318 // Loop forever. We check our certificate (and regenerate, if necessary) and then start the
2319 // server. The server will go down when our certificate is no longer valid (e.g. expired). We
2320 // then generate a new one and start the server again.
2321 while(!pending_interrupts)
2322 {
2323 // Ensure that our certificate is valid. Generate a new one if not.
2324 if (check_cert (cert_db_path, server_cert_nickname (), use_db_password) != 0)
2325 {
2326 // Message already issued
2327 goto done;
2328 }
2329
2330 // Ensure that our certificate is trusted by our local client.
2331 // Construct the client database path relative to the server database path.
2332 SECStatus secStatus = add_client_cert (server_cert_file (),
2333 local_client_cert_db_path ());
2334 if (secStatus != SECSuccess)
2335 {
2336 // Not fatal. Other clients may trust the server and trust can be added
2337 // for the local client in other ways.
2338 server_error (_("Unable to authorize certificate for the local client"));
2339 }
2340
2341 // Launch the server.
2342 secStatus = server_main (listenSocket);
2343 } // loop forever
2344
2345 done:
2346 sem_destroy(&sem_client); /*Not really necessary, as we are shutting down...but for correctness */
2347 if (PR_Close (listenSocket) != PR_SUCCESS)
2348 {
2349 server_error (_("Error closing listen socket"));
2350 nssError ();
2351 }
2352 }
2353
2354 int
2355 main (int argc, char **argv) {
2356 initialize (argc, argv);
2357 listen ();
2358 cleanup ();
2359 return 0;
2360 }
2361
2362 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.234801 seconds and 6 git commands to generate.