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-2013 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/>.
38 #include <sys/utsname.h>
39 #include <sys/types.h>
41 #include <semaphore.h>
50 #include <avahi-client/publish.h>
51 #include <avahi-common/alternative.h>
52 #include <avahi-common/thread-watch.h>
53 #include <avahi-common/malloc.h>
54 #include <avahi-common/error.h>
59 #include "nsscommon.h"
65 static void cleanup ();
66 static PRStatus
spawn_and_wait (const vector
<string
> &argv
,
67 const char* fd0
, const char* fd1
, const char* fd2
,
68 const char *pwd
, const vector
<string
>& envVec
= vector
<string
> ());
70 /* getopt variables */
73 /* File scope statics. Set during argument parsing and initialization. */
74 static bool use_db_password
;
75 static unsigned short port
;
76 static long max_threads
;
77 static string cert_db_path
;
78 static string stap_options
;
79 static string uname_r
;
81 static string cert_serial_number
;
82 static string B_options
;
83 static string I_options
;
84 static string R_option
;
85 static string D_options
;
86 static bool keep_temp
;
89 static int pending_interrupts
;
90 #define CONCURRENCY_TIMEOUT_S 3
93 // Server_error messages are printed to stderr and logged, if requested.
95 server_error (const string
&msg
, int logit
= true)
97 cerr
<< msg
<< endl
<< flush
;
98 // Log it, but avoid repeated messages to the terminal.
99 if (logit
&& log_ok ())
103 // client_error messages are treated as server errors and also printed to the client's stderr.
105 client_error (const string
&msg
, string stapstderr
)
108 if (! stapstderr
.empty ())
111 errfile
.open (stapstderr
.c_str (), ios_base::app
);
112 if (! errfile
.good ())
113 server_error (_F("Could not open client stderr file %s: %s", stapstderr
.c_str (),
116 errfile
<< "Server: " << msg
<< endl
;
117 // NB: No need to close errfile
121 // Messages from the nss common code are treated as server errors.
124 nsscommon_error (const char *msg
, int logit
)
126 server_error (msg
, logit
);
129 // Fatal errors are treated as server errors but also result in termination
132 fatal (const string
&msg
)
141 process_a (const string
&arg
)
144 stap_options
+= " -a " + arg
;
148 process_r (const string
&arg
)
150 if (arg
[0] == '/') // fully specified path
151 uname_r
= kernel_release_from_build_tree (arg
);
154 stap_options
+= " -r " + arg
; // Pass the argument to stap directly.
158 process_log (const char *arg
)
164 parse_options (int argc
, char **argv
)
166 // Examine the command line. This is the command line for us (stap-serverd) not the command
167 // line for spawned stap instances.
173 // NB: The values of these enumerators must not conflict with the values of ordinary
174 // characters, since those are returned by getopt_long for short options.
181 static struct option long_options
[] = {
182 { "port", 1, NULL
, LONG_OPT_PORT
},
183 { "ssl", 1, NULL
, LONG_OPT_SSL
},
184 { "log", 1, NULL
, LONG_OPT_LOG
},
185 { "max-threads", 1, NULL
, LONG_OPT_MAXTHREADS
},
188 int grc
= getopt_long (argc
, argv
, "a:B:D:I:kPr:R:", long_options
, NULL
);
197 B_options
+= string (" -") + (char)grc
+ optarg
;
198 stap_options
+= string (" -") + (char)grc
+ optarg
;
201 D_options
+= string (" -") + (char)grc
+ optarg
;
202 stap_options
+= string (" -") + (char)grc
+ optarg
;
205 I_options
+= string (" -") + (char)grc
+ optarg
;
206 stap_options
+= string (" -") + (char)grc
+ optarg
;
212 use_db_password
= true;
218 R_option
= string (" -") + (char)grc
+ optarg
;
219 stap_options
+= string (" -") + (char)grc
+ optarg
;
222 port_tmp
= strtol (optarg
, &num_endptr
, 10);
223 if (*num_endptr
!= '\0')
224 fatal (_F("%s: cannot parse number '--port=%s'", argv
[0], optarg
));
225 else if (port_tmp
< 0 || port_tmp
> 65535)
226 fatal (_F("%s: invalid entry: port must be between 0 and 65535 '--port=%s'", argv
[0],
229 port
= (unsigned short) port_tmp
;
232 cert_db_path
= optarg
;
235 process_log (optarg
);
237 case LONG_OPT_MAXTHREADS
:
238 max_threads
= strtol (optarg
, &num_endptr
, 0);
239 if (*num_endptr
!= '\0')
240 fatal (_F("%s: cannot parse number '--max-threads=%s'", argv
[0], optarg
));
241 else if (max_threads
< 0)
242 fatal (_F("%s: invalid entry: max threads must not be negative '--max-threads=%s'",
246 // Invalid/unrecognized option given. Message has already been issued.
249 // Reached when one added a getopt option but not a corresponding switch/case:
251 server_error (_F("%s: unhandled option '%c %s'", argv
[0], (char)grc
, optarg
));
253 server_error (_F("%s: unhandled option '%c'", argv
[0], (char)grc
));
258 for (int i
= optind
; i
< argc
; i
++)
259 server_error (_F("%s: unrecognized argument '%s'", argv
[0], argv
[i
]));
265 return server_cert_db_path () + "/stap.cert";
268 // Signal handling. When an interrupt is received, kill any spawned processes
272 handle_interrupt (int sig
)
274 pending_interrupts
++;
275 if(pending_interrupts
>= 2)
277 log (_F("Received another signal %d, exiting (forced)", sig
));
280 log (_F("Received signal %d, exiting", sig
));
284 setup_signals (sighandler_t handler
)
288 memset(&sa
, 0, sizeof(sa
));
289 sa
.sa_handler
= handler
;
290 sigemptyset (&sa
.sa_mask
);
291 if (handler
!= SIG_IGN
)
293 sigaddset (&sa
.sa_mask
, SIGHUP
);
294 sigaddset (&sa
.sa_mask
, SIGPIPE
);
295 sigaddset (&sa
.sa_mask
, SIGINT
);
296 sigaddset (&sa
.sa_mask
, SIGTERM
);
297 sigaddset (&sa
.sa_mask
, SIGTTIN
);
298 sigaddset (&sa
.sa_mask
, SIGTTOU
);
299 sigaddset (&sa
.sa_mask
, SIGXFSZ
);
300 sigaddset (&sa
.sa_mask
, SIGXCPU
);
302 sa
.sa_flags
= SA_RESTART
;
304 sigaction (SIGHUP
, &sa
, NULL
);
305 sigaction (SIGPIPE
, &sa
, NULL
);
306 sigaction (SIGINT
, &sa
, NULL
);
307 sigaction (SIGTERM
, &sa
, NULL
);
308 sigaction (SIGTTIN
, &sa
, NULL
);
309 sigaction (SIGTTOU
, &sa
, NULL
);
310 sigaction (SIGXFSZ
, &sa
, NULL
);
311 sigaction (SIGXCPU
, &sa
, NULL
);
315 static AvahiEntryGroup
*avahi_group
= NULL
;
316 static AvahiThreadedPoll
*avahi_threaded_poll
= NULL
;
317 static char *avahi_service_name
= NULL
;
318 static AvahiClient
*avahi_client
= 0;
320 static void create_services (AvahiClient
*c
);
323 entry_group_callback (
325 AvahiEntryGroupState state
,
326 AVAHI_GCC_UNUSED
void *userdata
328 assert(g
== avahi_group
|| avahi_group
== NULL
);
331 // Called whenever the entry group state changes.
334 case AVAHI_ENTRY_GROUP_ESTABLISHED
:
335 // The entry group has been established successfully.
336 log (_F("Avahi service '%s' successfully established.", avahi_service_name
));
339 case AVAHI_ENTRY_GROUP_COLLISION
: {
341 // A service name collision with a remote service.
342 // happened. Let's pick a new name.
343 n
= avahi_alternative_service_name (avahi_service_name
);
344 avahi_free (avahi_service_name
);
345 avahi_service_name
= n
;
346 server_error (_F("Avahi service name collision, renaming service to '%s'", avahi_service_name
));
348 // And recreate the services.
349 create_services (avahi_entry_group_get_client (g
));
353 case AVAHI_ENTRY_GROUP_FAILURE
:
354 // Some kind of failure happened.
355 server_error (_F("Avahi entry group failure: %s",
356 avahi_strerror (avahi_client_errno (avahi_entry_group_get_client (g
)))));
359 case AVAHI_ENTRY_GROUP_UNCOMMITED
:
360 case AVAHI_ENTRY_GROUP_REGISTERING
:
366 create_services (AvahiClient
*c
) {
369 // If this is the first time we're called, let's create a new
370 // entry group if necessary.
372 if (! (avahi_group
= avahi_entry_group_new (c
, entry_group_callback
, NULL
)))
374 server_error (_F("avahi_entry_group_new () failed: %s",
375 avahi_strerror (avahi_client_errno (c
))));
379 // If the group is empty (either because it was just created, or
380 // because it was reset previously, add our entries.
381 if (avahi_entry_group_is_empty (avahi_group
))
383 log (_F("Adding Avahi service '%s'", avahi_service_name
));
385 // Create the txt tags that will be registered with our service.
386 string sysinfo
= "sysinfo=" + uname_r
+ " " + arch
;
387 string certinfo
= "certinfo=" + cert_serial_number
;
388 string version
= string ("version=") + CURRENT_CS_PROTOCOL_VERSION
;;
389 string optinfo
= "optinfo=";
391 // These option strings already have a leading space.
392 if (! R_option
.empty ())
394 optinfo
+= R_option
.substr(1);
397 if (! B_options
.empty ())
399 optinfo
+= separator
+ B_options
.substr(1);
402 if (! D_options
.empty ())
404 optinfo
+= separator
+ D_options
.substr(1);
407 if (! I_options
.empty ())
408 optinfo
+= separator
+ I_options
.substr(1);
410 // We will now add our service to the entry group. Only services with the
411 // same name should be put in the same entry group.
413 if ((ret
= avahi_entry_group_add_service (avahi_group
, AVAHI_IF_UNSPEC
, AVAHI_PROTO_UNSPEC
,
414 (AvahiPublishFlags
)0,
415 avahi_service_name
, "_stap._tcp", NULL
, NULL
, port
,
416 sysinfo
.c_str (), optinfo
.c_str (),
417 version
.c_str (), certinfo
.c_str (), NULL
)) < 0)
419 if (ret
== AVAHI_ERR_COLLISION
)
422 server_error (_F("Failed to add _stap._tcp service: %s", avahi_strerror (ret
)));
426 // Tell the server to register the service.
427 if ((ret
= avahi_entry_group_commit (avahi_group
)) < 0)
429 server_error (_F("Failed to commit avahi entry group: %s", avahi_strerror (ret
)));
436 // A service name collision with a local service happened. Let's
439 n
= avahi_alternative_service_name (avahi_service_name
);
440 avahi_free(avahi_service_name
);
441 avahi_service_name
= n
;
442 server_error (_F("Avahi service name collision, renaming service to '%s'", avahi_service_name
));
443 avahi_entry_group_reset (avahi_group
);
448 avahi_entry_group_reset (avahi_group
);
451 static void avahi_cleanup_client () {
452 // This also frees the entry group, if any
454 avahi_client_free (avahi_client
);
461 client_callback (AvahiClient
*c
, AvahiClientState state
, AVAHI_GCC_UNUSED
void * userdata
)
465 // Called whenever the client or server state changes.
468 case AVAHI_CLIENT_S_RUNNING
:
469 // The server has startup successfully and registered its host
470 // name on the network, so it's time to create our services.
474 case AVAHI_CLIENT_FAILURE
:
475 server_error (_F("Avahi client failure: %s", avahi_strerror (avahi_client_errno (c
))));
476 if (avahi_client_errno (c
) == AVAHI_ERR_DISCONNECTED
)
478 // The client has been disconnected; probably because the avahi daemon has been
479 // restarted. We can free the client here and try to reconnect using a new one.
480 // Passing AVAHI_CLIENT_NO_FAIL allows the new client to be
481 // created, even if the avahi daemon is not running. Our service will be advertised
482 // if/when the daemon is started.
483 avahi_cleanup_client ();
485 avahi_client
= avahi_client_new (avahi_threaded_poll_get (avahi_threaded_poll
),
486 (AvahiClientFlags
)AVAHI_CLIENT_NO_FAIL
,
487 client_callback
, NULL
, & error
);
491 case AVAHI_CLIENT_S_COLLISION
:
492 // Let's drop our registered services. When the server is back
493 // in AVAHI_SERVER_RUNNING state we will register them
494 // again with the new host name.
496 case AVAHI_CLIENT_S_REGISTERING
:
497 // The server records are now being established. This
498 // might be caused by a host name change. We need to wait
499 // for our own records to register until the host name is
500 // properly esatblished.
502 avahi_entry_group_reset (avahi_group
);
505 case AVAHI_CLIENT_CONNECTING
:
506 // The avahi-daemon is not currently running. Our service will be advertised
507 // if/when the deamon is started.
508 server_error (_F("The Avahi daemon is not running. Avahi service '%s' will be established when the deamon is started", avahi_service_name
));
515 if (avahi_service_name
)
516 log (_F("Removing Avahi service '%s'", avahi_service_name
));
518 // Stop the avahi client, if it's running
519 if (avahi_threaded_poll
)
520 avahi_threaded_poll_stop (avahi_threaded_poll
);
522 // Clean up the avahi objects. The order of freeing these is significant.
523 avahi_cleanup_client ();
524 if (avahi_threaded_poll
) {
525 avahi_threaded_poll_free (avahi_threaded_poll
);
526 avahi_threaded_poll
= 0;
528 if (avahi_service_name
) {
529 avahi_free (avahi_service_name
);
530 avahi_service_name
= 0;
534 // The entry point for the avahi client thread.
536 avahi_publish_service (CERTCertificate
*cert
)
538 cert_serial_number
= get_cert_serial_number (cert
);
542 buf
= "Systemtap Compile Server, pid=" + lex_cast (getpid ());
544 catch (const runtime_error
&e
)
546 server_error(_F("Failed to cast pid '%d' to a string: %s", getpid(), e
.what()));
549 avahi_service_name
= avahi_strdup (buf
.c_str ());
551 // Allocate main loop object.
552 if (! (avahi_threaded_poll
= avahi_threaded_poll_new ()))
554 server_error (_("Failed to create avahi threaded poll object."));
558 // Always allocate a new client. Passing AVAHI_CLIENT_NO_FAIL allows the client to be
559 // created, even if the avahi daemon is not running. Our service will be advertised
560 // if/when the daemon is started.
562 avahi_client
= avahi_client_new (avahi_threaded_poll_get (avahi_threaded_poll
),
563 (AvahiClientFlags
)AVAHI_CLIENT_NO_FAIL
,
564 client_callback
, NULL
, & error
);
565 // Check whether creating the client object succeeded.
568 server_error (_F("Failed to create avahi client: %s", avahi_strerror(error
)));
572 // Run the main loop.
573 avahi_threaded_poll_start (avahi_threaded_poll
);
580 advertise_presence (CERTCertificate
*cert
__attribute ((unused
)))
583 avahi_publish_service (cert
);
585 server_error (_("Unable to advertise presence on the network. Avahi is not available"));
590 unadvertise_presence ()
598 initialize (int argc
, char **argv
) {
599 pending_interrupts
= 0;
600 setup_signals (& handle_interrupt
);
602 // Seed the random number generator. Used to generate noise used during key generation.
606 use_db_password
= false;
608 max_threads
= sysconf( _SC_NPROCESSORS_ONLN
); // Default to number of processors
610 struct utsname utsname
;
612 uname_r
= utsname
.release
;
613 arch
= normalize_machine (utsname
.machine
);
615 // Parse the arguments. This also starts the server log, if any, and should be done before
616 // any messages are issued.
617 parse_options (argc
, argv
);
619 // PR11197: security prophylactics.
620 // Reject use as root, except via a special environment variable.
621 if (! getenv ("STAP_PR11197_OVERRIDE")) {
623 fatal ("For security reasons, invocation of stap-serverd as root is not supported.");
626 struct passwd
*pw
= getpwuid (geteuid ());
628 fatal (_F("Unable to determine effective user name: %s", strerror (errno
)));
629 string username
= pw
->pw_name
;
630 pid_t pid
= getpid ();
631 log (_F("===== compile server pid %d starting as %s =====", pid
, username
.c_str ()));
633 // Where is the ssl certificate/key database?
634 if (cert_db_path
.empty ())
635 cert_db_path
= server_cert_db_path ();
637 // Make sure NSPR is initialized. Must be done before NSS is initialized
638 PR_Init (PR_SYSTEM_THREAD
, PR_PRIORITY_NORMAL
, 1);
639 /* Set the cert database password callback. */
640 PK11_SetPasswordFunc (nssPasswordCallback
);
646 unadvertise_presence ();
650 /* Function: readDataFromSocket()
652 * Purpose: Read data from the socket into a temporary file.
656 readDataFromSocket(PRFileDesc
*sslSocket
, const char *requestFileName
)
658 PRFileDesc
*local_file_fd
= 0;
659 PRInt32 numBytesExpected
;
660 PRInt32 numBytesRead
;
661 PRInt32 numBytesWritten
;
662 PRInt32 totalBytes
= 0;
663 #define READ_BUFFER_SIZE 4096
664 char buffer
[READ_BUFFER_SIZE
];
666 // Read the number of bytes to be received.
667 /* XXX: impose a limit to prevent disk space consumption DoS */
668 numBytesRead
= PR_Read_Complete (sslSocket
, & numBytesExpected
,
669 (PRInt32
)sizeof (numBytesExpected
));
670 if (numBytesRead
== 0) /* EOF */
672 server_error (_("Error reading size of request file"));
675 if (numBytesRead
< 0)
677 server_error (_("Error in PR_Read"));
682 /* Convert numBytesExpected from network byte order to host byte order. */
683 numBytesExpected
= ntohl (numBytesExpected
);
685 /* If 0 bytes are expected, then we were contacted only to obtain our certificate.
686 There is no client request. */
687 if (numBytesExpected
== 0)
690 /* Open the output file. */
691 local_file_fd
= PR_Open(requestFileName
, PR_WRONLY
| PR_CREATE_FILE
| PR_TRUNCATE
,
692 PR_IRUSR
| PR_IWUSR
);
693 if (local_file_fd
== NULL
)
695 server_error (_F("Could not open output file %s", requestFileName
));
700 // Read until EOF or until the expected number of bytes has been read.
701 for (totalBytes
= 0; totalBytes
< numBytesExpected
; totalBytes
+= numBytesRead
)
703 // No need for PR_Read_Complete here, since we're already managing multiple
704 // reads to a fixed size buffer.
705 numBytesRead
= PR_Read (sslSocket
, buffer
, READ_BUFFER_SIZE
);
706 if (numBytesRead
== 0)
708 if (numBytesRead
< 0)
710 server_error (_("Error in PR_Read"));
715 /* Write to the request file. */
716 numBytesWritten
= PR_Write(local_file_fd
, buffer
, numBytesRead
);
717 if (numBytesWritten
< 0 || (numBytesWritten
!= numBytesRead
))
719 server_error (_F("Could not write to output file %s", requestFileName
));
725 if (totalBytes
!= numBytesExpected
)
727 server_error (_F("Expected %d bytes, got %d while reading client request from socket",
728 numBytesExpected
, totalBytes
));
734 PR_Close (local_file_fd
);
738 /* Function: setupSSLSocket()
740 * Purpose: Configure a socket for SSL.
745 setupSSLSocket (PRFileDesc
*tcpSocket
, CERTCertificate
*cert
, SECKEYPrivateKey
*privKey
)
747 PRFileDesc
*sslSocket
;
751 /* Inport the socket into SSL. */
752 sslSocket
= SSL_ImportFD (NULL
, tcpSocket
);
753 if (sslSocket
== NULL
)
755 server_error (_("Could not import socket into SSL"));
760 /* Set the appropriate flags. */
761 secStatus
= SSL_OptionSet (sslSocket
, SSL_SECURITY
, PR_TRUE
);
762 if (secStatus
!= SECSuccess
)
764 server_error (_("Error setting SSL security for socket"));
769 secStatus
= SSL_OptionSet(sslSocket
, SSL_HANDSHAKE_AS_SERVER
, PR_TRUE
);
770 if (secStatus
!= SECSuccess
)
772 server_error (_("Error setting handshake as server for socket"));
777 secStatus
= SSL_OptionSet(sslSocket
, SSL_REQUEST_CERTIFICATE
, PR_FALSE
);
778 if (secStatus
!= SECSuccess
)
780 server_error (_("Error setting SSL client authentication mode for socket"));
785 secStatus
= SSL_OptionSet(sslSocket
, SSL_REQUIRE_CERTIFICATE
, PR_FALSE
);
786 if (secStatus
!= SECSuccess
)
788 server_error (_("Error setting SSL client authentication mode for socket"));
793 /* Set the appropriate callback routines. */
794 #if 0 /* use the default */
795 secStatus
= SSL_AuthCertificateHook (sslSocket
, myAuthCertificate
, CERT_GetDefaultCertDB());
796 if (secStatus
!= SECSuccess
)
799 server_error (_("Error in SSL_AuthCertificateHook"));
803 #if 0 /* Use the default */
804 secStatus
= SSL_BadCertHook(sslSocket
, (SSLBadCertHandler
)myBadCertHandler
, &certErr
);
805 if (secStatus
!= SECSuccess
)
808 server_error (_("Error in SSL_BadCertHook"));
812 #if 0 /* no handshake callback */
813 secStatus
= SSL_HandshakeCallback(sslSocket
, myHandshakeCallback
, NULL
);
814 if (secStatus
!= SECSuccess
)
816 server_error (_("Error in SSL_HandshakeCallback"));
822 certKEA
= NSS_FindCertKEAType (cert
);
824 secStatus
= SSL_ConfigSecureServer (sslSocket
, cert
, privKey
, certKEA
);
825 if (secStatus
!= SECSuccess
)
827 server_error (_("Error configuring SSL server"));
835 #if 0 /* No client authentication (for now) and not authenticating after each transaction. */
836 /* Function: authenticateSocket()
838 * Purpose: Perform client authentication on the socket.
842 authenticateSocket (PRFileDesc
*sslSocket
, PRBool requireCert
)
844 CERTCertificate
*cert
;
847 /* Returns NULL if client authentication is not enabled or if the
848 * client had no certificate. */
849 cert
= SSL_PeerCertificate(sslSocket
);
852 /* Client had a certificate, so authentication is through. */
853 CERT_DestroyCertificate(cert
);
857 /* Request client to authenticate itself. */
858 secStatus
= SSL_OptionSet(sslSocket
, SSL_REQUEST_CERTIFICATE
, PR_TRUE
);
859 if (secStatus
!= SECSuccess
)
861 server_error (_("Error in SSL_OptionSet:SSL_REQUEST_CERTIFICATE"));
866 /* If desired, require client to authenticate itself. Note
867 * SSL_REQUEST_CERTIFICATE must also be on, as above. */
868 secStatus
= SSL_OptionSet(sslSocket
, SSL_REQUIRE_CERTIFICATE
, requireCert
);
869 if (secStatus
!= SECSuccess
)
871 server_error (_("Error in SSL_OptionSet:SSL_REQUIRE_CERTIFICATE"));
876 /* Having changed socket configuration parameters, redo handshake. */
877 secStatus
= SSL_ReHandshake(sslSocket
, PR_TRUE
);
878 if (secStatus
!= SECSuccess
)
880 server_error (_("Error in SSL_ReHandshake"));
885 /* Force the handshake to complete before moving on. */
886 secStatus
= SSL_ForceHandshake(sslSocket
);
887 if (secStatus
!= SECSuccess
)
889 server_error (_("Error in SSL_ForceHandshake"));
896 #endif /* No client authentication and not authenticating after each transaction. */
898 /* Function: writeDataToSocket
900 * Purpose: Write the server's response back to the socket.
904 writeDataToSocket(PRFileDesc
*sslSocket
, const char *responseFileName
)
906 PRFileDesc
*local_file_fd
= PR_Open (responseFileName
, PR_RDONLY
, 0);
907 if (local_file_fd
== NULL
)
909 server_error (_F("Could not open input file %s", responseFileName
));
914 /* Transmit the local file across the socket.
916 int numBytes
= PR_TransmitFile (sslSocket
, local_file_fd
,
918 PR_TRANSMITFILE_KEEP_OPEN
,
919 PR_INTERVAL_NO_TIMEOUT
);
921 /* Error in transmission. */
922 SECStatus secStatus
= SECSuccess
;
925 server_error (_("Error writing response to socket"));
927 secStatus
= SECFailure
;
930 PR_Close (local_file_fd
);
935 get_stap_locale (const string
&staplang
, vector
<string
> &envVec
, string stapstderr
, cs_protocol_version
*client_version
)
937 // If the client version is < 1.6, then no file containing environment
938 // variables defining the locale has been passed.
939 if (*client_version
< "1.6")
942 /* Go through each line of the file, verify it, then add it to the vector */
944 langfile
.open(staplang
.c_str());
945 if (!langfile
.is_open())
947 // Not fatal. Proceed with the environment we have.
948 server_error(_F("Unable to open file %s for reading: %s", staplang
.c_str(),
953 /* Unpackage internationalization variables and verify their contents */
954 map
<string
, string
> envMap
; /* To temporarily store the entire array of strings */
956 const set
<string
> &locVars
= localization_variables();
958 /* Copy the global environ variable into the map */
961 for (unsigned i
=0; environ
[i
]; i
++)
963 string line
= (string
)environ
[i
];
965 /* Find the first '=' sign */
966 size_t pos
= line
.find("=");
968 /* Make sure it found an '=' sign */
969 if(pos
!= string::npos
)
970 /* Everything before the '=' sign is the key, and everything after is the value. */
971 envMap
[line
.substr(0, pos
)] = line
.substr(pos
+1);
975 /* Create regular expression objects to verify lines read from file. Should not allow
976 spaces, ctrl characters, etc */
978 if ((regcomp(&checkre
, "^[a-zA-Z0-9@_.=-]*$", REG_EXTENDED
| REG_NOSUB
) != 0))
980 // Not fatal. Proceed with the environment we have.
981 server_error(_F("Error in regcomp: %s", strerror (errno
)));
987 getline(langfile
, line
);
988 if (!langfile
.good())
991 /* Extract key and value from the line. Note: value may contain "=". */
995 pos
= line
.find("=");
996 if (pos
== string::npos
)
998 client_error(_F("Localization key=value line '%s' cannot be parsed", line
.c_str()), stapstderr
);
1001 key
= line
.substr(0, pos
);
1003 value
= line
.substr(pos
);
1005 /* Make sure the key is found in the localization variables global set */
1006 if (locVars
.find(key
) == locVars
.end())
1008 // Not fatal. Just ignore it.
1009 client_error(_F("Localization key '%s' not found in global list", key
.c_str()), stapstderr
);
1013 /* Make sure the value does not contain illegal characters */
1014 if ((regexec(&checkre
, value
.c_str(), (size_t) 0, NULL
, 0) != 0))
1016 // Not fatal. Just ignore it.
1017 client_error(_F("Localization value '%s' contains illegal characters", value
.c_str()), stapstderr
);
1021 /* All is good, copy line into envMap, replacing if already there */
1022 envMap
[key
] = value
;
1025 if (!langfile
.eof())
1027 // Not fatal. Proceed with what we have.
1028 server_error(_F("Error reading file %s: %s", staplang
.c_str(), strerror (errno
)));
1033 /* Copy map into vector */
1034 for (map
<string
, string
>::iterator it
= envMap
.begin(); it
!= envMap
.end(); it
++)
1035 envVec
.push_back(it
->first
+ "=" + it
->second
);
1038 // Filter paths prefixed with the server's home directory from the given file.
1041 filter_response_file (const string
&file_name
, const string
&responseDirName
)
1045 // Filter the server's home directory name
1047 cmd
.push_back ("sed");
1048 cmd
.push_back ("-i");
1049 cmd
.push_back (string ("s,") + get_home_directory () + ",<server>,g");
1050 cmd
.push_back (file_name
);
1051 stap_system (0, cmd
);
1053 // Filter the server's response directory name
1055 cmd
.push_back ("sed");
1056 cmd
.push_back ("-i");
1057 cmd
.push_back (string ("s,") + responseDirName
+ ",<server>,g");
1058 cmd
.push_back (file_name
);
1059 stap_system (0, cmd
);
1063 getRequestedPrivilege (const vector
<string
> &stapargv
)
1065 // The purpose of this function is to find the --privilege or --unprivileged option specified
1066 // by the user on the client side. We need to parse the command line completely, but we can
1067 // exit when we find the first --privilege or --unprivileged option, since stap does not allow
1068 // multiple privilege levels to specified on the same command line.
1070 // Note that we need not do any options consistency checking since our spawned stap instance
1073 // Create an argv/argc for use by getopt_long.
1074 int argc
= stapargv
.size();
1075 char ** argv
= new char *[argc
+ 1];
1076 for (unsigned i
= 0; i
< stapargv
.size(); ++i
)
1077 argv
[i
] = (char *)stapargv
[i
].c_str();
1080 privilege_t privilege
= pr_highest
; // Until specified otherwise.
1084 // We need only allow getopt to parse the options until we find a
1085 // --privilege or --unprivileged option.
1086 int grc
= getopt_long (argc
, argv
, STAP_SHORT_OPTIONS
, stap_long_options
, NULL
);
1092 // We can ignore all options other than --privilege and --unprivileged.
1094 case LONG_OPT_PRIVILEGE
:
1095 if (strcmp (optarg
, "stapdev") == 0)
1096 privilege
= pr_stapdev
;
1097 else if (strcmp (optarg
, "stapsys") == 0)
1098 privilege
= pr_stapsys
;
1099 else if (strcmp (optarg
, "stapusr") == 0)
1100 privilege
= pr_stapusr
;
1103 server_error (_F("Invalid argument '%s' for --privilege", optarg
));
1104 privilege
= pr_highest
;
1106 // We have discovered the client side --privilege option. We can exit now since
1107 // stap only tolerates one privilege setting option.
1108 goto done
; // break 2 switches and a loop
1109 case LONG_OPT_UNPRIVILEGED
:
1110 privilege
= pr_unprivileged
;
1111 // We have discovered the client side --unprivileged option. We can exit now since
1112 // stap only tolerates one privilege setting option.
1113 goto done
; // break 2 switches and a loop
1121 /* Run the translator on the data in the request directory, and produce output
1122 in the given output directory. */
1124 handleRequest (const string
&requestDirName
, const string
&responseDirName
, string stapstderr
)
1126 vector
<string
> stapargv
;
1127 cs_protocol_version client_version
= "1.0"; // Assumed until discovered otherwise
1134 // Save the server version. Do this early, so the client knows what version of the server
1135 // it is dealing with, even if the request is not fully completed.
1136 string stapversion
= responseDirName
+ "/version";
1137 f
= fopen (stapversion
.c_str (), "w");
1140 fputs (CURRENT_CS_PROTOCOL_VERSION
, f
);
1144 server_error (_F("Unable to open client version file %s", stapversion
.c_str ()));
1146 // Get the client version. The default version is already set. Use it if we fail here.
1147 string filename
= requestDirName
+ "/version";
1148 if (file_exists (filename
))
1149 read_from_file (filename
, client_version
);
1150 log (_F("Client version is %s", client_version
.v
));
1152 // The name of the translator executable.
1153 stapargv
.push_back ((char *)(getenv ("SYSTEMTAP_STAP") ?: STAP_PREFIX
"/bin/stap"));
1155 /* Transcribe stap_options. We use plain wordexp(3), since these
1156 options are coming from the local trusted user, so malicious
1157 content is not a concern. */
1158 // TODO: Use tokenize here.
1159 rc
= wordexp (stap_options
.c_str (), & words
, WRDE_NOCMD
|WRDE_UNDEF
);
1162 server_error (_("Cannot parse stap options"));
1166 for (u
=0; u
<words
.we_wordc
; u
++)
1167 stapargv
.push_back (words
.we_wordv
[u
]);
1169 /* Process the saved command line arguments. Avoid quoting/unquoting errors by
1170 transcribing literally. */
1171 string new_staptmpdir
= responseDirName
+ "/stap000000";
1172 rc
= mkdir(new_staptmpdir
.c_str(), 0700);
1174 server_error(_F("Could not create temporary directory %s", new_staptmpdir
.c_str()));
1176 stapargv
.push_back("--tmpdir=" + new_staptmpdir
);
1178 stapargv
.push_back ("--client-options");
1181 char stapargfile
[PATH_MAX
];
1186 snprintf (stapargfile
, PATH_MAX
, "%s/argv%d", requestDirName
.c_str (), i
);
1188 rc
= stat(stapargfile
, & st
);
1191 arg
= (char *)malloc (st
.st_size
+1);
1194 server_error (_("Out of memory"));
1198 argfile
= fopen(stapargfile
, "r");
1202 server_error (_F("Error opening %s: %s", stapargfile
, strerror (errno
)));
1206 rc
= fread(arg
, 1, st
.st_size
, argfile
);
1207 if (rc
!= st
.st_size
)
1211 server_error (_F("Error reading %s: %s", stapargfile
, strerror (errno
)));
1215 arg
[st
.st_size
] = '\0';
1216 stapargv
.push_back (arg
);
1221 string stapstdout
= responseDirName
+ "/stdout";
1223 // NB: Before, when we did not fully parse the client's command line using getopt_long,
1224 // we used to insert a --privilege=XXX option here in case some other argument was mistaken
1225 // for a --privilege or --unprivileged option by our spawned stap. Since we now parse
1226 // the client's command line using getopt_long and share the getopt_long options
1227 // string and table with stap, this is no longer necessary. stap will parse the
1228 // command line identically to the way we have parsed it and will discover the same
1229 // privilege-setting option.
1231 // Environment variables (possibly empty) to be passed to spawn_and_wait().
1232 string staplang
= requestDirName
+ "/locale";
1233 vector
<string
> envVec
;
1234 get_stap_locale (staplang
, envVec
, stapstderr
, &client_version
);
1236 /* All ready, let's run the translator! */
1237 rc
= spawn_and_wait(stapargv
, "/dev/null", stapstdout
.c_str (), stapstderr
.c_str (),
1238 requestDirName
.c_str (), envVec
);
1241 string staprc
= responseDirName
+ "/rc";
1242 f
= fopen(staprc
.c_str (), "w");
1245 /* best effort basis */
1246 fprintf(f
, "%d", rc
);
1250 // In unprivileged modes, if we have a module built, we need to sign the sucker.
1251 privilege_t privilege
= getRequestedPrivilege (stapargv
);
1252 if (pr_contains (privilege
, pr_stapusr
) || pr_contains (privilege
, pr_stapsys
))
1255 char pattern
[PATH_MAX
];
1256 snprintf (pattern
, PATH_MAX
, "%s/*.ko", new_staptmpdir
.c_str());
1257 rc
= glob (pattern
, GLOB_ERR
, NULL
, &globber
);
1259 server_error (_F("Unable to find a module in %s", new_staptmpdir
.c_str()));
1260 else if (globber
.gl_pathc
!= 1)
1261 server_error (_F("Too many modules (%zu) in %s", globber
.gl_pathc
, new_staptmpdir
.c_str()));
1264 sign_file (cert_db_path
, server_cert_nickname(),
1265 globber
.gl_pathv
[0], string(globber
.gl_pathv
[0]) + ".sgn");
1269 /* If uprobes.ko is required, it will have been built or cache-copied into
1270 * the temp directory. We need to pack it into the response where the client
1271 * can find it, and sign, if necessary, for unprivileged users.
1273 string uprobes_ko
= new_staptmpdir
+ "/uprobes/uprobes.ko";
1274 if (get_file_size(uprobes_ko
) > 0)
1276 /* uprobes.ko is required.
1278 * It's already underneath the stap tmpdir, but older stap clients
1279 * don't know to look for it there, so, for these clients, we end up packing uprobes twice
1280 * into the zip. We could move instead of symlink.
1282 string uprobes_response
;
1283 if (client_version
< "1.6")
1285 uprobes_response
= (string
)responseDirName
+ "/uprobes.ko";
1286 rc
= symlink(uprobes_ko
.c_str(), uprobes_response
.c_str());
1288 server_error (_F("Could not link to %s from %s",
1289 uprobes_ko
.c_str(), uprobes_response
.c_str()));
1292 uprobes_response
= uprobes_ko
;
1294 /* In unprivileged mode, we need a signature on uprobes as well. */
1295 if (! pr_contains (privilege
, pr_stapdev
))
1297 sign_file (cert_db_path
, server_cert_nickname(),
1298 uprobes_response
, uprobes_response
+ ".sgn");
1303 /* Free up all the arg string copies. Note that the first few were alloc'd
1304 by wordexp(), which wordfree() frees; others were hand-set to literal strings. */
1307 // Filter paths prefixed with the server's home directory from the stdout and stderr
1308 // files in the response.
1309 filter_response_file (stapstdout
, responseDirName
);
1310 filter_response_file (stapstderr
, responseDirName
);
1312 /* Sorry about the inconvenience. C string/file processing is such a pleasure. */
1316 /* A front end for stap_spawn that handles stdin, stdout, stderr, switches to a working
1317 directory and returns overall success or failure. */
1319 spawn_and_wait (const vector
<string
> &argv
,
1320 const char* fd0
, const char* fd1
, const char* fd2
,
1321 const char *pwd
, const vector
<string
>& envVec
)
1325 posix_spawn_file_actions_t actions
;
1328 #define CHECKRC(msg) do { if (rc) { server_error (_(msg)); return PR_FAILURE; } } while (0)
1330 rc
= posix_spawn_file_actions_init (& actions
);
1331 CHECKRC ("Error in spawn file actions ctor");
1333 rc
= posix_spawn_file_actions_addopen(& actions
, 0, fd0
, O_RDONLY
, 0600);
1334 CHECKRC ("Error in spawn file actions fd0");
1337 rc
= posix_spawn_file_actions_addopen(& actions
, 1, fd1
, O_WRONLY
|O_CREAT
, 0600);
1338 CHECKRC ("Error in spawn file actions fd1");
1341 // Use append mode for stderr because it gets written to in other places in the server.
1342 rc
= posix_spawn_file_actions_addopen(& actions
, 2, fd2
, O_WRONLY
|O_APPEND
|O_CREAT
, 0600);
1343 CHECKRC ("Error in spawn file actions fd2");
1346 /* change temporarily to a directory if requested */
1349 dotfd
= open (".", O_RDONLY
);
1352 server_error (_("Error in spawn getcwd"));
1360 server_error(_("Error in spawn chdir"));
1365 pid
= stap_spawn (0, argv
, & actions
, envVec
);
1366 /* NB: don't react to pid==-1 right away; need to chdir back first. */
1368 if (pwd
&& dotfd
>= 0)
1371 subrc
= fchdir (dotfd
);
1372 subrc
|= close (dotfd
);
1374 server_error (_("Error in spawn unchdir"));
1379 server_error (_F("Error in spawn: %s", strerror (errno
)));
1383 rc
= stap_waitpid (0, pid
);
1386 server_error (_("Error in waitpid"));
1390 rc
= posix_spawn_file_actions_destroy (&actions
);
1391 CHECKRC ("Error in spawn file actions dtor");
1397 /* Function: void *handle_connection()
1399 * Purpose: Handle a connection to a socket. Copy in request zip
1400 * file, process it, copy out response. Temporary directories are
1401 * created & destroyed here.
1405 handle_connection (void *arg
)
1407 PRFileDesc
* sslSocket
= NULL
;
1408 SECStatus secStatus
= SECFailure
;
1412 char tmpdir
[PATH_MAX
];
1413 char requestFileName
[PATH_MAX
];
1414 char requestDirName
[PATH_MAX
];
1415 char responseDirName
[PATH_MAX
];
1416 char responseFileName
[PATH_MAX
];
1417 string stapstderr
; /* Cannot be global since we need a unique
1418 copy for each connection.*/
1419 vector
<string
> argv
;
1422 /* Detatch to avoid a memory leak */
1424 pthread_detach(pthread_self());
1426 /* Unpack the arg */
1427 thread_arg
*t_arg
= (thread_arg
*) arg
;
1428 PRFileDesc
*tcpSocket
= t_arg
->tcpSocket
;
1429 CERTCertificate
*cert
= t_arg
->cert
;
1430 SECKEYPrivateKey
*privKey
= t_arg
->privKey
;
1431 PRNetAddr addr
= t_arg
->addr
;
1433 tmpdir
[0]='\0'; /* prevent cleanup-time /bin/rm of uninitialized directory */
1435 #if 0 // already done on the listenSocket
1436 /* Make sure the socket is blocking. */
1437 PRSocketOptionData socketOption
;
1438 socketOption
.option
= PR_SockOpt_Nonblocking
;
1439 socketOption
.value
.non_blocking
= PR_FALSE
;
1440 PR_SetSocketOption (tcpSocket
, &socketOption
);
1442 secStatus
= SECFailure
;
1443 sslSocket
= setupSSLSocket (tcpSocket
, cert
, privKey
);
1444 if (sslSocket
== NULL
)
1446 // Message already issued.
1450 secStatus
= SSL_ResetHandshake(sslSocket
, /* asServer */ PR_TRUE
);
1451 if (secStatus
!= SECSuccess
)
1453 server_error (_("Error resetting SSL handshake"));
1458 #if 0 // The client authenticates the server, so the client initiates the handshake
1459 /* Force the handshake to complete before moving on. */
1460 secStatus
= SSL_ForceHandshake(sslSocket
);
1461 if (secStatus
!= SECSuccess
)
1463 server_error (_("Error forcing SSL handshake"));
1469 secStatus
= SECFailure
;
1470 snprintf(tmpdir
, PATH_MAX
, "%s/stap-server.XXXXXX", getenv("TMPDIR") ?: "/tmp");
1471 rc1
= mkdtemp(tmpdir
);
1474 server_error (_F("Could not create temporary directory %s: %s", tmpdir
, strerror(errno
)));
1475 tmpdir
[0]=0; /* prevent /bin/rm */
1479 /* Create a temporary files names and directories. */
1480 snprintf (requestFileName
, PATH_MAX
, "%s/request.zip", tmpdir
);
1482 snprintf (requestDirName
, PATH_MAX
, "%s/request", tmpdir
);
1483 rc
= mkdir(requestDirName
, 0700);
1486 server_error (_F("Could not create temporary directory %s: %s", requestDirName
, strerror (errno
)));
1490 snprintf (responseDirName
, PATH_MAX
, "%s/response", tmpdir
);
1491 rc
= mkdir(responseDirName
, 0700);
1494 server_error (_F("Could not create temporary directory %s: %s", responseDirName
, strerror (errno
)));
1497 // Set this early, since it gets used for errors to be returned to the client.
1498 stapstderr
= string(responseDirName
) + "/stderr";
1500 snprintf (responseFileName
, PATH_MAX
, "%s/response.zip", tmpdir
);
1502 /* Read data from the socket.
1503 * If the user is requesting/requiring authentication, authenticate
1505 bytesRead
= readDataFromSocket(sslSocket
, requestFileName
);
1506 if (bytesRead
< 0) // Error
1508 if (bytesRead
== 0) // No request -- not an error
1510 secStatus
= SECSuccess
;
1514 #if 0 /* Don't authenticate after each transaction */
1515 if (REQUEST_CERT_ALL
)
1517 secStatus
= authenticateSocket(sslSocket
);
1518 if (secStatus
!= SECSuccess
)
1523 /* Unzip the request. */
1524 secStatus
= SECFailure
;
1525 argv
.push_back ("unzip");
1526 argv
.push_back ("-q");
1527 argv
.push_back ("-d");
1528 argv
.push_back (requestDirName
);
1529 argv
.push_back (requestFileName
);
1530 rc
= stap_system (0, argv
);
1533 server_error (_("Unable to extract client request"));
1537 /* Handle the request zip file. An error therein should still result
1538 in a response zip file (containing stderr etc.) so we don't have to
1539 have a result code here. */
1540 handleRequest(requestDirName
, responseDirName
, stapstderr
);
1542 /* Zip the response. */
1544 argv
.push_back ("zip");
1545 argv
.push_back ("-q");
1546 argv
.push_back ("-r");
1547 argv
.push_back (responseFileName
);
1548 argv
.push_back (".");
1549 rc
= spawn_and_wait (argv
, NULL
, NULL
, NULL
, responseDirName
);
1550 if (rc
!= PR_SUCCESS
)
1552 server_error (_("Unable to compress server response"));
1556 secStatus
= writeDataToSocket (sslSocket
, responseFileName
);
1560 if (PR_Close (sslSocket
) != PR_SUCCESS
)
1562 server_error (_("Error closing ssl socket"));
1568 // Remove the whole tmpdir and all that lies beneath, unless -k was specified.
1570 log (_F("Keeping temporary directory %s", tmpdir
));
1574 argv
.push_back ("rm");
1575 argv
.push_back ("-r");
1576 argv
.push_back (tmpdir
);
1577 rc
= stap_system (0, argv
);
1579 server_error (_("Error in tmpdir cleanup"));
1583 if (secStatus
!= SECSuccess
)
1584 server_error (_("Error processing client request"));
1586 // Log the end of the request.
1588 prStatus
= PR_NetAddrToString (& addr
, buf
, sizeof (buf
));
1589 if (prStatus
== PR_SUCCESS
)
1591 if (addr
.raw
.family
== PR_AF_INET
)
1592 log (_F("Request from %s:%d complete", buf
, addr
.inet
.port
));
1593 else if (addr
.raw
.family
== PR_AF_INET6
)
1594 log (_F("Request from [%s]:%d complete", buf
, addr
.ipv6
.port
));
1597 /* Increment semephore to indicate this thread is finished. */
1599 if (max_threads
> 0)
1601 sem_post(&sem_client
);
1608 /* Function: int accept_connection()
1610 * Purpose: Accept a connection to the socket.
1614 accept_connections (PRFileDesc
*listenSocket
, CERTCertificate
*cert
)
1617 PRFileDesc
*tcpSocket
;
1619 SECStatus secStatus
;
1620 CERTCertDBHandle
*dbHandle
;
1625 dbHandle
= CERT_GetDefaultCertDB ();
1627 // cert_db_path gets passed to nssPasswordCallback.
1628 SECKEYPrivateKey
*privKey
= PK11_FindKeyByAnyCert (cert
, (void*)cert_db_path
.c_str ());
1629 if (privKey
== NULL
)
1631 server_error (_("Unable to obtain certificate private key"));
1636 while (pending_interrupts
== 0)
1638 /* Accept a connection to the socket. */
1639 tcpSocket
= PR_Accept (listenSocket
, &addr
, PR_INTERVAL_MIN
);
1640 if (tcpSocket
== NULL
)
1642 if(PR_GetError() == PR_IO_TIMEOUT_ERROR
)
1646 server_error (_("Error accepting client connection"));
1651 /* Log the accepted connection. */
1653 prStatus
= PR_NetAddrToString (&addr
, buf
, sizeof (buf
));
1654 if (prStatus
== PR_SUCCESS
)
1656 if (addr
.raw
.family
== PR_AF_INET
)
1657 log (_F("Accepted connection from %s:%d", buf
, addr
.inet
.port
));
1658 else if (addr
.raw
.family
== PR_AF_INET6
)
1659 log (_F("Accepted connection from [%s]:%d", buf
, addr
.ipv6
.port
));
1662 /* XXX: alarm() or somesuch to set a timeout. */
1664 /* Accepted the connection, now handle it. */
1666 /* Wait for a thread to finish if there are none available */
1670 sem_getvalue(&sem_client
, &idle_threads
);
1671 if(idle_threads
<= 0)
1672 log(_("Server is overloaded. Processing times may be longer than normal."));
1673 else if (idle_threads
== max_threads
)
1674 log(_("Processing 1 request..."));
1676 log(_F("Processing %d concurrent requests...", ((int)max_threads
- idle_threads
) + 1));
1678 sem_wait(&sem_client
);
1681 /* Create the argument structure to pass to pthread_create
1682 * (or directly to handle_connection if max_threads == 0 */
1683 t_arg
= (thread_arg
*)malloc(sizeof(*t_arg
));
1685 fatal(_("No memory available for new thread arg!"));
1686 t_arg
->tcpSocket
= tcpSocket
;
1688 t_arg
->privKey
= privKey
;
1691 /* Handle the conncection */
1692 if (max_threads
> 0)
1693 /* Create the worker thread and handle the connection. */
1694 pthread_create(&tid
, NULL
, handle_connection
, t_arg
);
1696 /* Since max_threads == 0, don't spawn a new thread,
1697 * just handle in the current thread. */
1698 handle_connection(t_arg
);
1700 // If our certificate is no longer valid (e.g. has expired), then exit.
1701 secStatus
= CERT_VerifyCertNow (dbHandle
, cert
, PR_TRUE
/*checkSig*/,
1702 certUsageSSLServer
, NULL
/*wincx*/);
1703 if (secStatus
!= SECSuccess
)
1705 // Not an error. Exit the loop so a new cert can be generated.
1710 SECKEY_DestroyPrivateKey (privKey
);
1714 /* Function: void server_main()
1716 * Purpose: This is the server's main function. It configures a socket
1717 * and listens to it.
1721 server_main (PRFileDesc
*listenSocket
)
1727 SECStatus secStatus
= nssInit (cert_db_path
.c_str ());
1728 if (secStatus
!= SECSuccess
)
1730 // Message already issued.
1734 // Preinitialized here due to jumps to the label 'done'.
1735 CERTCertificate
*cert
= NULL
;
1736 bool serverCacheConfigured
= false;
1738 // Enable cipher suites which are allowed by U.S. export regulations.
1739 // NB: The NSS docs say that SSL_ClearSessionCache is required for the new settings to take
1740 // effect, however, calling it puts NSS in a state where it will not shut down cleanly.
1741 // We need to be able to shut down NSS cleanly if we are to generate a new certificate when
1742 // ours expires. It should be noted however, thet SSL_ClearSessionCache only clears the
1743 // client cache, and we are a server.
1744 secStatus
= NSS_SetExportPolicy ();
1745 // SSL_ClearSessionCache ();
1746 if (secStatus
!= SECSuccess
)
1748 server_error (_("Unable to set NSS export policy"));
1753 // Configure the SSL session cache for a single process server with the default settings.
1754 secStatus
= SSL_ConfigServerSessionIDCache (0, 0, 0, NULL
);
1755 if (secStatus
!= SECSuccess
)
1757 server_error (_("Unable to configure SSL server session ID cache"));
1761 serverCacheConfigured
= true;
1763 /* Get own certificate. */
1764 cert
= PK11_FindCertFromNickname (server_cert_nickname (), NULL
);
1767 server_error (_F("Unable to find our certificate in the database at %s",
1768 cert_db_path
.c_str ()));
1773 // Tell the world that we're listening.
1774 advertise_presence (cert
);
1776 /* Handle connections to the socket. */
1777 secStatus
= accept_connections (listenSocket
, cert
);
1779 // Tell the world we're no longer listening.
1780 unadvertise_presence ();
1782 sem_getvalue(&sem_client
, &idle_threads
);
1784 /* Wait for requests to finish or the timeout to be reached.
1785 * If we got here from an interrupt, exit immediately if
1786 * the timeout is reached. Otherwise, wait indefinitiely
1787 * until the threads exit (or an interrupt is recieved).*/
1788 if(idle_threads
< max_threads
)
1789 log(_F("Waiting for %d outstanding requests to complete...", (int)max_threads
- idle_threads
));
1790 while(idle_threads
< max_threads
)
1792 if(pending_interrupts
&& timeout
++ > CONCURRENCY_TIMEOUT_S
)
1794 log(_("Timeout reached, exiting (forced)"));
1795 kill_stap_spawn (SIGTERM
);
1800 sem_getvalue(&sem_client
, &idle_threads
);
1806 CERT_DestroyCertificate (cert
);
1809 if (serverCacheConfigured
&& SSL_ShutdownServerSessionIDCache () != SECSuccess
)
1811 server_error (_("Unable to shut down server session ID cache"));
1814 nssCleanup (cert_db_path
.c_str ());
1822 // Create a new socket.
1823 PRFileDesc
*listenSocket
= PR_OpenTCPSocket (PR_AF_INET6
); // Accepts IPv4 too
1824 if (listenSocket
== NULL
)
1826 server_error (_("Error creating socket"));
1831 // Set socket to be blocking - on some platforms the default is nonblocking.
1832 PRSocketOptionData socketOption
;
1833 socketOption
.option
= PR_SockOpt_Nonblocking
;
1834 socketOption
.value
.non_blocking
= PR_FALSE
;
1835 PRStatus prStatus
= PR_SetSocketOption (listenSocket
, & socketOption
);
1836 if (prStatus
!= PR_SUCCESS
)
1838 server_error (_("Error setting socket properties"));
1843 // Allow the socket address to be reused, in case we want the same port across a
1844 // 'service stap-server restart'
1845 socketOption
.option
= PR_SockOpt_Reuseaddr
;
1846 socketOption
.value
.reuse_addr
= PR_TRUE
;
1847 prStatus
= PR_SetSocketOption (listenSocket
, & socketOption
);
1848 if (prStatus
!= PR_SUCCESS
)
1850 server_error (_("Error setting socket properties"));
1855 // Configure the network connection.
1857 memset (& addr
, 0, sizeof(addr
));
1858 prStatus
= PR_InitializeNetAddr (PR_IpAddrAny
, port
, & addr
);
1859 addr
.ipv6
.family
= PR_AF_INET6
;
1861 // addr.inet.ip = PR_htonl(PR_INADDR_ANY);
1862 PR_StringToNetAddr ("::", & addr
);
1863 // PR_StringToNetAddr ("fe80::5eff:35ff:fe07:55ca", & addr);
1864 // PR_StringToNetAddr ("::1", & addr);
1865 addr
.ipv6
.port
= PR_htons (port
);
1868 // Bind the socket to an address. Retry if the selected port is busy, unless the port was
1869 // specified directly.
1872 /* Bind the address to the listener socket. */
1873 prStatus
= PR_Bind (listenSocket
, & addr
);
1874 if (prStatus
== PR_SUCCESS
)
1877 // If the selected port is busy. Try another, but only if a specific port was not specified.
1878 PRErrorCode errorNumber
= PR_GetError ();
1879 switch (errorNumber
)
1881 case PR_ADDRESS_NOT_AVAILABLE_ERROR
:
1884 server_error (_F("Network port %hu is unavailable. Trying another port", port
));
1888 case PR_ADDRESS_IN_USE_ERROR
:
1891 server_error (_F("Network port %hu is busy. Trying another port", port
));
1898 server_error (_("Error setting socket address"));
1903 // Query the socket for the port that was assigned.
1904 prStatus
= PR_GetSockName (listenSocket
, &addr
);
1905 if (prStatus
!= PR_SUCCESS
)
1907 server_error (_("Unable to obtain socket address"));
1912 prStatus
= PR_NetAddrToString (&addr
, buf
, sizeof (buf
));
1913 port
= PR_ntohs (addr
.ipv6
.port
);
1914 log (_F("Using network address [%s]:%hu", buf
, port
));
1916 if (max_threads
> 0)
1917 log (_F("Using a maximum of %ld threads", max_threads
));
1919 log (_("Concurrency disabled"));
1921 // Listen for connection on the socket. The second argument is the maximum size of the queue
1922 // for pending connections.
1923 prStatus
= PR_Listen (listenSocket
, 5);
1924 if (prStatus
!= PR_SUCCESS
)
1926 server_error (_("Error listening on socket"));
1931 /* Initialize semephore with the maximum number of threads
1932 * defined by --max-threads. If it is not defined, the
1933 * default is the number of processors */
1934 sem_init(&sem_client
, 0, max_threads
);
1936 // Loop forever. We check our certificate (and regenerate, if necessary) and then start the
1937 // server. The server will go down when our certificate is no longer valid (e.g. expired). We
1938 // then generate a new one and start the server again.
1939 while(!pending_interrupts
)
1941 // Ensure that our certificate is valid. Generate a new one if not.
1942 if (check_cert (cert_db_path
, server_cert_nickname (), use_db_password
) != 0)
1944 // Message already issued
1948 // Ensure that our certificate is trusted by our local client.
1949 // Construct the client database path relative to the server database path.
1950 SECStatus secStatus
= add_client_cert (server_cert_file (),
1951 local_client_cert_db_path ());
1952 if (secStatus
!= SECSuccess
)
1954 server_error (_("Unable to authorize certificate for the local client"));
1958 // Launch the server.
1959 secStatus
= server_main (listenSocket
);
1963 sem_destroy(&sem_client
); /*Not really necessary, as we are shutting down...but for correctness */
1964 if (PR_Close (listenSocket
) != PR_SUCCESS
)
1966 server_error (_("Error closing listen socket"));
1972 main (int argc
, char **argv
) {
1973 initialize (argc
, argv
);
1979 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */