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