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