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