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