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