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