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