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