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.
6 Copyright (C) 2011 Red Hat Inc.
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.
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.
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/>.
36 #include <sys/resource.h>
38 #include <sys/utsname.h>
39 #include <sys/types.h>
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>
58 #include "nsscommon.h"
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
> ());
68 /* getopt variables */
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
;
76 static string cert_db_path
;
77 static string stap_options
;
78 static string uname_r
;
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
;
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
;
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
;
100 static string stapstderr
;
103 // Server_error messages are printed to stderr and logged, if requested.
105 server_error (const string
&msg
, int logit
= true)
107 cerr
<< msg
<< endl
<< flush
;
108 // Log it, but avoid repeated messages to the terminal.
109 if (logit
&& log_ok ())
113 // client_error messages are treated as server errors and also printed to the client's stderr.
115 client_error (const string
&msg
)
118 if (! stapstderr
.empty ())
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 (),
126 errfile
<< "Server: " << msg
<< endl
;
127 // NB: No need to close errfile
131 // Messages from the nss common code are treated as server errors.
134 nsscommon_error (const char *msg
, int logit
)
136 server_error (msg
, logit
);
139 // Fatal errors are treated as server errors but also result in termination
142 fatal (const string
&msg
)
151 process_a (const string
&arg
)
154 stap_options
+= " -a " + arg
;
158 process_r (const string
&arg
)
160 if (arg
[0] == '/') // fully specified path
161 uname_r
= kernel_release_from_build_tree (arg
);
164 stap_options
+= " -r " + arg
; // Pass the argument to stap directly.
168 process_log (const char *arg
)
174 parse_options (int argc
, char **argv
)
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.
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
},
191 int grc
= getopt_long (argc
, argv
, "a:B:I:kPr:R:", long_options
, NULL
);
201 stap_options
+= string (" -") + (char)grc
+ optarg
;
205 stap_options
+= string (" -") + (char)grc
+ optarg
;
211 use_db_password
= true;
218 stap_options
+= string (" -") + (char)grc
+ optarg
;
221 // Invalid/unrecognized option given. Message has already been issued.
224 // Reached when one added a getopt option but not a corresponding switch/case:
226 server_error (_F("%s: unhandled option '%c %s'", argv
[0], (char)grc
, optarg
));
228 server_error (_F("%s: unhandled option '%c'", argv
[0], (char)grc
));
234 port
= (int) strtoul (optarg
, &num_endptr
, 10);
237 cert_db_path
= optarg
;
240 process_log (optarg
);
244 server_error (_F("%s: unhandled option '--%s=%s'", argv
[0],
245 long_options
[long_opt
- 1].name
, optarg
));
247 server_error (_F("%s: unhandled option '--%s'", argv
[0],
248 long_options
[long_opt
- 1].name
));
254 for (int i
= optind
; i
< argc
; i
++)
255 server_error (_F("%s: unrecognized argument '%s'", argv
[0], argv
[i
]));
261 return server_cert_db_path () + "/stap.cert";
264 // Signal handling. When an interrupt is received, kill any spawned processes
268 handle_interrupt (int sig
)
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.
277 rc
= getrlimit (RLIMIT_FSIZE
, & rl
);
278 if (rc
== 0 && rl
.rlim_cur
< our_RLIMIT_FSIZE
.rlim_cur
)
282 rc
= getrlimit (RLIMIT_CPU
, & rl
);
283 if (rc
== 0 && rl
.rlim_cur
< our_RLIMIT_CPU
.rlim_cur
)
290 // Otherwise, it's game over.
291 log (_F("Received signal %d, exiting", sig
));
292 kill_stap_spawn (sig
);
298 setup_signals (sighandler_t handler
)
302 memset(&sa
, 0, sizeof(sa
));
303 sa
.sa_handler
= handler
;
304 sigemptyset (&sa
.sa_mask
);
305 if (handler
!= SIG_IGN
)
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
);
316 sa
.sa_flags
= SA_RESTART
;
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
);
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;
334 static void create_services (AvahiClient
*c
);
337 entry_group_callback (
339 AvahiEntryGroupState state
,
340 AVAHI_GCC_UNUSED
void *userdata
342 assert(g
== avahi_group
|| avahi_group
== NULL
);
345 // Called whenever the entry group state changes.
348 case AVAHI_ENTRY_GROUP_ESTABLISHED
:
349 // The entry group has been established successfully.
350 log (_F("Service '%s' successfully established.", avahi_service_name
));
353 case AVAHI_ENTRY_GROUP_COLLISION
: {
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
));
362 // And recreate the services.
363 create_services (avahi_entry_group_get_client (g
));
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
);
374 case AVAHI_ENTRY_GROUP_UNCOMMITED
:
375 case AVAHI_ENTRY_GROUP_REGISTERING
:
381 create_services (AvahiClient
*c
) {
384 // If this is the first time we're called, let's create a new
385 // entry group if necessary.
387 if (! (avahi_group
= avahi_entry_group_new (c
, entry_group_callback
, NULL
)))
389 server_error (_F("avahi_entry_group_new () failed: %s",
390 avahi_strerror (avahi_client_errno (c
))));
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
))
398 log (_F("Adding Avahi service '%s'", avahi_service_name
));
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=";
406 if (! R_option
.empty ())
411 if (! B_options
.empty ())
413 optinfo
+= separator
+ B_options
;
416 if (! I_options
.empty ())
417 optinfo
+= separator
+ I_options
;
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.
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)
428 if (ret
== AVAHI_ERR_COLLISION
)
431 server_error (_F("Failed to add _stap._tcp service: %s", avahi_strerror (ret
)));
435 // Tell the server to register the service.
436 if ((ret
= avahi_entry_group_commit (avahi_group
)) < 0)
438 server_error (_F("Failed to commit avahi entry group: %s", avahi_strerror (ret
)));
445 // A service name collision with a local service happened. Let's
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
);
457 avahi_entry_group_reset (avahi_group
);
458 avahi_threaded_poll_stop (avahi_threaded_poll
);
462 client_callback (AvahiClient
*c
, AvahiClientState state
, AVAHI_GCC_UNUSED
void * userdata
)
466 // Called whenever the client or server state changes.
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.
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
);
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.
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.
491 avahi_entry_group_reset (avahi_group
);
494 case AVAHI_CLIENT_CONNECTING
:
501 if (avahi_service_name
)
502 log (_F("Removing Avahi service '%s'", avahi_service_name
));
504 // Stop the avahi client, if it's running
505 if (avahi_threaded_poll
)
506 avahi_threaded_poll_stop (avahi_threaded_poll
);
508 // Clean up the avahi objects. The order of freeing these is significant.
510 avahi_entry_group_reset (avahi_group
);
511 avahi_entry_group_free (avahi_group
);
515 avahi_client_free (avahi_client
);
518 if (avahi_threaded_poll
) {
519 avahi_threaded_poll_free (avahi_threaded_poll
);
520 avahi_threaded_poll
= 0;
522 if (avahi_service_name
) {
523 avahi_free (avahi_service_name
);
524 avahi_service_name
= 0;
528 // The entry point for the avahi client thread.
530 avahi_publish_service (CERTCertificate
*cert
)
532 cert_serial_number
= get_cert_serial_number (cert
);
534 string buf
= "Systemtap Compile Server, pid=" + lex_cast (getpid ());
535 avahi_service_name
= avahi_strdup (buf
.c_str ());
537 // Allocate main loop object.
538 if (! (avahi_threaded_poll
= avahi_threaded_poll_new ()))
540 server_error (_("Failed to create avahi threaded poll object."));
544 // Always allocate a new client.
546 avahi_client
= avahi_client_new (avahi_threaded_poll_get (avahi_threaded_poll
),
548 client_callback
, NULL
, & error
);
549 // Check wether creating the client object succeeded.
552 server_error (_F("Failed to create avahi client: %s", avahi_strerror(error
)));
556 // Run the main loop.
557 avahi_threaded_poll_start (avahi_threaded_poll
);
564 advertise_presence (CERTCertificate
*cert
__attribute ((unused
)))
567 avahi_publish_service (cert
);
569 server_error (_("Unable to advertise presence on the network. Avahi is not available"));
574 unadvertise_presence ()
582 initialize (int argc
, char **argv
) {
583 setup_signals (& handle_interrupt
);
585 // Seed the random number generator. Used to generate noise used during key generation.
589 client_version
= "1.0"; // Assumed until discovered otherwise
590 use_db_password
= false;
593 struct utsname utsname
;
595 uname_r
= utsname
.release
;
596 arch
= normalize_machine (utsname
.machine
);
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
);
602 // PR11197: security prophylactics.
603 // 1) Reject use as root, except via a special environment variable.
604 if (! getenv ("STAP_PR11197_OVERRIDE")) {
606 fatal ("For security reasons, invocation of stap-serverd as root is not supported.");
608 // 2) resource limits should be set if the user is the 'stap-server' daemon.
609 struct passwd
*pw
= getpwuid (geteuid ());
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
);
621 fatal (_F("Unable to obtain current resource limits: %s", strerror (errno
)));
623 // Now establish limits for the translator. Make sure these limits do not exceed the current
625 #define TRANSLATOR_LIMIT(category, limit) \
627 translator_RLIMIT_##category = our_RLIMIT_##category; \
628 if (translator_RLIMIT_##category.rlim_cur > (limit)) \
629 translator_RLIMIT_##category.rlim_cur = (limit); \
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);
637 #undef TRANSLATOR_LIMIT
642 pid_t pid
= getpid ();
643 log (_F("===== compile server pid %d starting as %s =====", pid
, username
.c_str ()));
645 // Where is the ssl certificate/key database?
646 if (cert_db_path
.empty ())
647 cert_db_path
= server_cert_db_path ();
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
);
658 unadvertise_presence ();
662 /* Function: readDataFromSocket()
664 * Purpose: Read data from the socket into a temporary file.
668 readDataFromSocket(PRFileDesc
*sslSocket
, const char *requestFileName
)
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
];
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 */
683 server_error (_("Error reading size of request file"));
686 if (numBytesRead
< 0)
688 server_error (_("Error in PR_Read"));
693 /* Convert numBytesExpected from network byte order to host byte order. */
694 numBytesExpected
= ntohl (numBytesExpected
);
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)
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
)
706 server_error (_F("Could not open output file %s", requestFileName
));
711 /* Read until EOF or until the expected number of bytes has been read. */
712 for (totalBytes
= 0; totalBytes
< numBytesExpected
; totalBytes
+= numBytesRead
)
714 numBytesRead
= PR_Read(sslSocket
, buffer
, READ_BUFFER_SIZE
);
715 if (numBytesRead
== 0)
717 if (numBytesRead
< 0)
719 server_error (_("Error in PR_Read"));
724 /* Write to the request file. */
725 numBytesWritten
= PR_Write(local_file_fd
, buffer
, numBytesRead
);
726 if (numBytesWritten
< 0 || (numBytesWritten
!= numBytesRead
))
728 server_error (_F("Could not write to output file %s", requestFileName
));
734 if (totalBytes
!= numBytesExpected
)
736 server_error (_F("Expected %d bytes, got %d while reading client request from socket",
737 numBytesExpected
, totalBytes
));
743 PR_Close (local_file_fd
);
747 /* Function: setupSSLSocket()
749 * Purpose: Configure a socket for SSL.
754 setupSSLSocket (PRFileDesc
*tcpSocket
, CERTCertificate
*cert
, SECKEYPrivateKey
*privKey
)
756 PRFileDesc
*sslSocket
;
760 /* Inport the socket into SSL. */
761 sslSocket
= SSL_ImportFD (NULL
, tcpSocket
);
762 if (sslSocket
== NULL
)
764 server_error (_("Could not import socket into SSL"));
769 /* Set the appropriate flags. */
770 secStatus
= SSL_OptionSet (sslSocket
, SSL_SECURITY
, PR_TRUE
);
771 if (secStatus
!= SECSuccess
)
773 server_error (_("Error setting SSL security for socket"));
778 secStatus
= SSL_OptionSet(sslSocket
, SSL_HANDSHAKE_AS_SERVER
, PR_TRUE
);
779 if (secStatus
!= SECSuccess
)
781 server_error (_("Error setting handshake as server for socket"));
786 secStatus
= SSL_OptionSet(sslSocket
, SSL_REQUEST_CERTIFICATE
, PR_FALSE
);
787 if (secStatus
!= SECSuccess
)
789 server_error (_("Error setting SSL client authentication mode for socket"));
794 secStatus
= SSL_OptionSet(sslSocket
, SSL_REQUIRE_CERTIFICATE
, PR_FALSE
);
795 if (secStatus
!= SECSuccess
)
797 server_error (_("Error setting SSL client authentication mode for socket"));
802 /* Set the appropriate callback routines. */
803 #if 0 /* use the default */
804 secStatus
= SSL_AuthCertificateHook (sslSocket
, myAuthCertificate
, CERT_GetDefaultCertDB());
805 if (secStatus
!= SECSuccess
)
808 server_error (_("Error in SSL_AuthCertificateHook"));
812 #if 0 /* Use the default */
813 secStatus
= SSL_BadCertHook(sslSocket
, (SSLBadCertHandler
)myBadCertHandler
, &certErr
);
814 if (secStatus
!= SECSuccess
)
817 server_error (_("Error in SSL_BadCertHook"));
821 #if 0 /* no handshake callback */
822 secStatus
= SSL_HandshakeCallback(sslSocket
, myHandshakeCallback
, NULL
);
823 if (secStatus
!= SECSuccess
)
825 server_error (_("Error in SSL_HandshakeCallback"));
831 certKEA
= NSS_FindCertKEAType (cert
);
833 secStatus
= SSL_ConfigSecureServer (sslSocket
, cert
, privKey
, certKEA
);
834 if (secStatus
!= SECSuccess
)
836 server_error (_("Error configuring SSL server"));
844 #if 0 /* No client authentication (for now) and not authenticating after each transaction. */
845 /* Function: authenticateSocket()
847 * Purpose: Perform client authentication on the socket.
851 authenticateSocket (PRFileDesc
*sslSocket
, PRBool requireCert
)
853 CERTCertificate
*cert
;
856 /* Returns NULL if client authentication is not enabled or if the
857 * client had no certificate. */
858 cert
= SSL_PeerCertificate(sslSocket
);
861 /* Client had a certificate, so authentication is through. */
862 CERT_DestroyCertificate(cert
);
866 /* Request client to authenticate itself. */
867 secStatus
= SSL_OptionSet(sslSocket
, SSL_REQUEST_CERTIFICATE
, PR_TRUE
);
868 if (secStatus
!= SECSuccess
)
870 server_error (_("Error in SSL_OptionSet:SSL_REQUEST_CERTIFICATE"));
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
)
880 server_error (_("Error in SSL_OptionSet:SSL_REQUIRE_CERTIFICATE"));
885 /* Having changed socket configuration parameters, redo handshake. */
886 secStatus
= SSL_ReHandshake(sslSocket
, PR_TRUE
);
887 if (secStatus
!= SECSuccess
)
889 server_error (_("Error in SSL_ReHandshake"));
894 /* Force the handshake to complete before moving on. */
895 secStatus
= SSL_ForceHandshake(sslSocket
);
896 if (secStatus
!= SECSuccess
)
898 server_error (_("Error in SSL_ForceHandshake"));
905 #endif /* No client authentication and not authenticating after each transaction. */
907 /* Function: writeDataToSocket
909 * Purpose: Write the server's response back to the socket.
913 writeDataToSocket(PRFileDesc
*sslSocket
, const char *responseFileName
)
915 PRFileDesc
*local_file_fd
= PR_Open (responseFileName
, PR_RDONLY
, 0);
916 if (local_file_fd
== NULL
)
918 server_error (_F("Could not open input file %s", responseFileName
));
923 /* Transmit the local file across the socket.
925 int numBytes
= PR_TransmitFile (sslSocket
, local_file_fd
,
927 PR_TRANSMITFILE_KEEP_OPEN
,
928 PR_INTERVAL_NO_TIMEOUT
);
930 /* Error in transmission. */
931 SECStatus secStatus
= SECSuccess
;
934 server_error (_("Error writing response to socket"));
936 secStatus
= SECFailure
;
939 PR_Close (local_file_fd
);
944 get_stap_locale (const string
&staplang
, vector
<string
> &envVec
)
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")
951 /* Go through each line of the file, verify it, then add it to the vector */
953 langfile
.open(staplang
.c_str());
954 if (!langfile
.is_open())
956 // Not fatal. Proceed with the environment we have.
957 server_error(_F("Unable to open file %s for reading: %s", staplang
.c_str(),
962 /* Unpackage internationalization variables and verify their contents */
963 map
<string
, string
> envMap
; /* To temporarily store the entire array of strings */
965 const set
<string
> &locVars
= localization_variables();
967 /* Copy the global environ variable into the map */
970 for (unsigned i
=0; environ
[i
]; i
++)
972 string line
= (string
)environ
[i
];
974 /* Find the first '=' sign */
975 size_t pos
= line
.find("=");
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);
984 /* Create regular expression objects to verify lines read from file. Should not allow
985 spaces, ctrl characters, etc */
987 if ((regcomp(&checkre
, "^[a-zA-Z0-9@_.=-]*$", REG_EXTENDED
| REG_NOSUB
) != 0))
989 // Not fatal. Proceed with the environment we have.
990 server_error(_F("Error in regcomp: %s", strerror (errno
)));
996 getline(langfile
, line
);
997 if (!langfile
.good())
1000 /* Extract key and value from the line. Note: value may contain "=". */
1004 pos
= line
.find("=");
1005 if (pos
== string::npos
)
1007 client_error(_F("Localization key=value line '%s' cannot be parsed", line
.c_str()));
1010 key
= line
.substr(0, pos
);
1012 value
= line
.substr(pos
);
1014 /* Make sure the key is found in the localization variables global set */
1015 if (locVars
.find(key
) == locVars
.end())
1017 // Not fatal. Just ignore it.
1018 client_error(_F("Localization key '%s' not found in global list", key
.c_str()));
1022 /* Make sure the value does not contain illegal characters */
1023 if ((regexec(&checkre
, value
.c_str(), (size_t) 0, NULL
, 0) != 0))
1025 // Not fatal. Just ignore it.
1026 client_error(_F("Localization value '%s' contains illegal characters", value
.c_str()));
1030 /* All is good, copy line into envMap, replacing if already there */
1031 envMap
[key
] = value
;
1034 if (!langfile
.eof())
1036 // Not fatal. Proceed with what we have.
1037 server_error(_F("Error reading file %s: %s", staplang
.c_str(), strerror (errno
)));
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
);
1047 // Filter paths prefixed with the server's home directory from the given file.
1050 filter_response_file (const string
&file_name
, const string
&responseDirName
)
1054 // Filter the server's home directory name
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
);
1062 // Filter the server's response directory name
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
);
1071 /* Run the translator on the data in the request directory, and produce output
1072 in the given output directory. */
1074 handleRequest (const string
&requestDirName
, const string
&responseDirName
)
1076 vector
<string
> stapargv
;
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");
1089 fputs (CURRENT_CS_PROTOCOL_VERSION
, f
);
1093 server_error (_F("Unable to open client version file %s", stapversion
.c_str ()));
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
));
1101 // The name of the translator executable.
1102 stapargv
.push_back ((char *)(getenv ("SYSTEMTAP_STAP") ?: STAP_PREFIX
"/bin/stap"));
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
);
1111 server_error (_("Cannot parse stap options"));
1115 for (u
=0; u
<words
.we_wordc
; u
++)
1116 stapargv
.push_back (words
.we_wordv
[u
]);
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);
1123 server_error(_F("Could not create temporary directory %s", new_staptmpdir
.c_str()));
1125 stapargv
.push_back("--tmpdir=" + new_staptmpdir
);
1127 stapargv
.push_back ("--client-options");
1130 char stapargfile
[PATH_MAX
];
1135 snprintf (stapargfile
, PATH_MAX
, "%s/argv%d", requestDirName
.c_str (), i
);
1137 rc
= stat(stapargfile
, & st
);
1140 arg
= (char *)malloc (st
.st_size
+1);
1143 server_error (_("Out of memory"));
1147 argfile
= fopen(stapargfile
, "r");
1151 server_error (_F("Error opening %s: %s", stapargfile
, strerror (errno
)));
1155 rc
= fread(arg
, 1, st
.st_size
, argfile
);
1156 if (rc
!= st
.st_size
)
1160 server_error (_F("Error reading %s: %s", stapargfile
, strerror (errno
)));
1164 arg
[st
.st_size
] = '\0';
1165 stapargv
.push_back (arg
);
1170 string stapstdout
= responseDirName
+ "/stdout";
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
++)
1176 if (stapargv
[i
] == "--unprivileged")
1178 privilege
= pr_stapusr
;
1181 if (stapargv
[i
].substr (0, 12) == "--privilege=")
1183 string arg
= stapargv
[i
].substr (12);
1184 if (arg
== "stapdev")
1186 // privilege is already pr_stapdev
1189 if (arg
== "stapusr")
1191 privilege
= pr_stapusr
;
1194 // Not fatal, but generate a message.
1195 server_error (_F("Unknown argument to --privilege: %s", arg
.c_str ()));
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.
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
1209 if (! pr_contains (privilege
, pr_stapdev
))
1211 string opt
= string("--privilege=") + pr_name (privilege
);
1212 stapargv
.insert (stapargv
.begin () + 1, opt
); /* better not be resettable by later option */
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
);
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
);
1225 string staprc
= responseDirName
+ "/rc";
1226 f
= fopen(staprc
.c_str (), "w");
1229 /* best effort basis */
1230 fprintf(f
, "%d", rc
);
1234 /* In unprivileged mode, if we have a module built, we need to sign the sucker. */
1235 if (! pr_contains (privilege
, pr_stapdev
))
1238 char pattern
[PATH_MAX
];
1239 snprintf (pattern
, PATH_MAX
, "%s/*.ko", new_staptmpdir
.c_str());
1240 rc
= glob (pattern
, GLOB_ERR
, NULL
, &globber
);
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()));
1247 sign_file (cert_db_path
, server_cert_nickname(),
1248 globber
.gl_pathv
[0], string(globber
.gl_pathv
[0]) + ".sgn");
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.
1256 string uprobes_ko
= new_staptmpdir
+ "/uprobes/uprobes.ko";
1257 if (get_file_size(uprobes_ko
) > 0)
1259 /* uprobes.ko is required.
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.
1265 string uprobes_response
;
1266 if (client_version
< "1.6")
1268 uprobes_response
= (string
)responseDirName
+ "/uprobes.ko";
1269 rc
= symlink(uprobes_ko
.c_str(), uprobes_response
.c_str());
1271 server_error (_F("Could not link to %s from %s",
1272 uprobes_ko
.c_str(), uprobes_response
.c_str()));
1275 uprobes_response
= uprobes_ko
;
1277 /* In unprivileged mode, we need a signature on uprobes as well. */
1278 if (! pr_contains (privilege
, pr_stapdev
))
1280 sign_file (cert_db_path
, server_cert_nickname(),
1281 uprobes_response
, uprobes_response
+ ".sgn");
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. */
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
);
1294 /* Sorry about the inconvenience. C string/file processing is such a pleasure. */
1298 /* A front end for stap_spawn that handles stdin, stdout, stderr, switches to a working
1299 directory and returns overall success or failure. */
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
)
1307 posix_spawn_file_actions_t actions
;
1310 #define CHECKRC(msg) do { if (rc) { server_error (_(msg)); return PR_FAILURE; } } while (0)
1312 rc
= posix_spawn_file_actions_init (& actions
);
1313 CHECKRC ("Error in spawn file actions ctor");
1315 rc
= posix_spawn_file_actions_addopen(& actions
, 0, fd0
, O_RDONLY
, 0600);
1316 CHECKRC ("Error in spawn file actions fd0");
1319 rc
= posix_spawn_file_actions_addopen(& actions
, 1, fd1
, O_WRONLY
|O_CREAT
, 0600);
1320 CHECKRC ("Error in spawn file actions fd1");
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");
1328 /* change temporarily to a directory if requested */
1331 dotfd
= open (".", O_RDONLY
);
1334 server_error (_("Error in spawn getcwd"));
1342 server_error(_("Error in spawn chdir"));
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).
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
);
1361 pid
= stap_spawn (0, argv
, & actions
, envVec
);
1362 /* NB: don't react to pid==-1 right away; need to chdir back first. */
1365 server_error (_F("Unable to set resource limits for %s: %s",
1366 argv
[0].c_str (), strerror (errno
)));
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
);
1376 log (_F("Unable to restore resource limits after %s: %s",
1377 argv
[0].c_str (), strerror (errno
)));
1380 if (pwd
&& dotfd
>= 0)
1383 subrc
= fchdir (dotfd
);
1384 subrc
|= close (dotfd
);
1386 server_error (_("Error in spawn unchdir"));
1391 server_error (_F("Error in spawn: %s", strerror (errno
)));
1395 rc
= stap_waitpid (0, pid
);
1398 server_error (_("Error in waitpid"));
1402 rc
= posix_spawn_file_actions_destroy (&actions
);
1403 CHECKRC ("Error in spawn file actions dtor");
1409 /* Function: int handle_connection()
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.
1416 handle_connection (PRFileDesc
*tcpSocket
, CERTCertificate
*cert
, SECKEYPrivateKey
*privKey
)
1418 PRFileDesc
* sslSocket
= NULL
;
1419 SECStatus secStatus
= SECFailure
;
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
;
1430 tmpdir
[0]='\0'; /* prevent cleanup-time /bin/rm of uninitialized directory */
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
);
1439 secStatus
= SECFailure
;
1440 sslSocket
= setupSSLSocket (tcpSocket
, cert
, privKey
);
1441 if (sslSocket
== NULL
)
1443 // Message already issued.
1447 secStatus
= SSL_ResetHandshake(sslSocket
, /* asServer */ PR_TRUE
);
1448 if (secStatus
!= SECSuccess
)
1450 server_error (_("Error resetting SSL handshake"));
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
)
1460 server_error (_("Error forcing SSL handshake"));
1466 secStatus
= SECFailure
;
1467 snprintf(tmpdir
, PATH_MAX
, "%s/stap-server.XXXXXX", getenv("TMPDIR") ?: "/tmp");
1468 rc1
= mkdtemp(tmpdir
);
1471 server_error (_F("Could not create temporary directory %s: %s", tmpdir
, strerror(errno
)));
1472 tmpdir
[0]=0; /* prevent /bin/rm */
1476 /* Create a temporary files names and directories. */
1477 snprintf (requestFileName
, PATH_MAX
, "%s/request.zip", tmpdir
);
1479 snprintf (requestDirName
, PATH_MAX
, "%s/request", tmpdir
);
1480 rc
= mkdir(requestDirName
, 0700);
1483 server_error (_F("Could not create temporary directory %s: %s", requestDirName
, strerror (errno
)));
1487 snprintf (responseDirName
, PATH_MAX
, "%s/response", tmpdir
);
1488 rc
= mkdir(responseDirName
, 0700);
1491 server_error (_F("Could not create temporary directory %s: %s", responseDirName
, strerror (errno
)));
1494 // Set this early, since it gets used for errors to be returned to the client.
1495 stapstderr
= string(responseDirName
) + "/stderr";
1497 snprintf (responseFileName
, PATH_MAX
, "%s/response.zip", tmpdir
);
1499 /* Read data from the socket.
1500 * If the user is requesting/requiring authentication, authenticate
1502 bytesRead
= readDataFromSocket(sslSocket
, requestFileName
);
1503 if (bytesRead
< 0) // Error
1505 if (bytesRead
== 0) // No request -- not an error
1507 secStatus
= SECSuccess
;
1511 #if 0 /* Don't authenticate after each transaction */
1512 if (REQUEST_CERT_ALL
)
1514 secStatus
= authenticateSocket(sslSocket
);
1515 if (secStatus
!= SECSuccess
)
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
);
1530 server_error (_("Unable to extract client request"));
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
);
1539 /* Zip the response. */
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
)
1549 server_error (_("Unable to compress server response"));
1553 secStatus
= writeDataToSocket (sslSocket
, responseFileName
);
1557 if (PR_Close (sslSocket
) != PR_SUCCESS
)
1559 server_error (_("Error closing ssl socket"));
1565 // Remove the whole tmpdir and all that lies beneath, unless -k was specified.
1567 log (_F("Keeping temporary directory %s", tmpdir
));
1571 argv
.push_back ("rm");
1572 argv
.push_back ("-r");
1573 argv
.push_back (tmpdir
);
1574 rc
= stap_system (0, argv
);
1576 server_error (_("Error in tmpdir cleanup"));
1583 /* Function: int accept_connection()
1585 * Purpose: Accept a connection to the socket.
1589 accept_connections (PRFileDesc
*listenSocket
, CERTCertificate
*cert
)
1592 PRFileDesc
*tcpSocket
;
1593 SECStatus secStatus
;
1594 CERTCertDBHandle
*dbHandle
;
1596 dbHandle
= CERT_GetDefaultCertDB ();
1598 // cert_db_path gets passed to nssPasswordCallback.
1599 SECKEYPrivateKey
*privKey
= PK11_FindKeyByAnyCert (cert
, (void*)cert_db_path
.c_str ());
1600 if (privKey
== NULL
)
1602 server_error (_("Unable to obtain certificate private key"));
1609 /* Accept a connection to the socket. */
1610 tcpSocket
= PR_Accept (listenSocket
, &addr
, PR_INTERVAL_NO_TIMEOUT
);
1611 if (tcpSocket
== NULL
)
1613 server_error (_("Error accepting client connection"));
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,
1625 /* XXX: alarm() or somesuch to set a timeout. */
1626 /* XXX: fork() or somesuch to handle concurrent requests. */
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"));
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,
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
)
1646 // Not an error. Exit the loop so a new cert can be generated.
1651 SECKEY_DestroyPrivateKey (privKey
);
1655 /* Function: void server_main()
1657 * Purpose: This is the server's main function. It configures a socket
1658 * and listens to it.
1662 server_main (PRFileDesc
*listenSocket
)
1665 SECStatus secStatus
= nssInit (cert_db_path
.c_str ());
1666 if (secStatus
!= SECSuccess
)
1668 // Message already issued.
1672 // Preinitialized here due to jumps to the label 'done'.
1673 CERTCertificate
*cert
= NULL
;
1674 bool serverCacheConfigured
= false;
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
)
1686 server_error (_("Unable to set NSS export policy"));
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
)
1695 server_error (_("Unable to configure SSL server session ID cache"));
1699 serverCacheConfigured
= true;
1701 /* Get own certificate. */
1702 cert
= PK11_FindCertFromNickname (server_cert_nickname (), NULL
);
1705 server_error (_F("Unable to find our certificate in the database at %s",
1706 cert_db_path
.c_str ()));
1711 // Tell the world that we're listening.
1712 advertise_presence (cert
);
1714 /* Handle connections to the socket. */
1715 secStatus
= accept_connections (listenSocket
, cert
);
1717 // Tell the world we're no longer listening.
1718 unadvertise_presence ();
1723 CERT_DestroyCertificate (cert
);
1726 if (serverCacheConfigured
&& SSL_ShutdownServerSessionIDCache () != SECSuccess
)
1728 server_error (_("Unable to shut down server session ID cache"));
1731 nssCleanup (cert_db_path
.c_str ());
1739 // Create a new socket.
1740 PRFileDesc
*listenSocket
= PR_NewTCPSocket ();
1741 if (listenSocket
== NULL
)
1743 server_error (_("Error creating socket"));
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
)
1755 server_error (_("Error setting socket properties"));
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
)
1767 server_error (_("Error setting socket properties"));
1772 // Configure the network connection.
1774 addr
.inet
.family
= PR_AF_INET
;
1775 addr
.inet
.ip
= PR_INADDR_ANY
;
1777 // Bind the socket to an address. Retry if the selected port is busy.
1780 addr
.inet
.port
= PR_htons (port
);
1782 /* Bind the address to the listener socket. */
1783 prStatus
= PR_Bind (listenSocket
, & addr
);
1784 if (prStatus
== PR_SUCCESS
)
1787 // If the selected port is busy. Try another.
1788 PRErrorCode errorNumber
= PR_GetError ();
1789 switch (errorNumber
)
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
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
1800 server_error (_("Error setting socket address"));
1806 // Query the socket for the port that was assigned.
1807 prStatus
= PR_GetSockName (listenSocket
, &addr
);
1808 if (prStatus
!= PR_SUCCESS
)
1810 server_error (_("Unable to obtain socket address"));
1814 port
= PR_ntohs (addr
.inet
.port
);
1815 log (_F("Using network port %d", port
));
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
)
1822 server_error (_("Error listening on socket"));
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.
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)
1835 // Message already issued
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
)
1845 server_error (_("Unable to authorize certificate for the local client"));
1849 // Launch the server.
1850 secStatus
= server_main (listenSocket
);
1854 if (PR_Close (listenSocket
) != PR_SUCCESS
)
1856 server_error (_("Error closing listen socket"));
1862 main (int argc
, char **argv
) {
1863 initialize (argc
, argv
);
1869 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */