Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libhttp/httpconnection.c
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,7 @@ void httpTransfer(struct HttpConnection *http, char *msg, int len) {
// also has difficulties with SSL connections that are being proxied.
int ieBug = 0;
const char *userAgent = getFromHashMap(&http->header, "user-agent");
const char *msie = userAgent ? strstr(userAgent, "MSIE ") : NULL;
const char *msie = userAgent ? strstr(userAgent, "Trident") : NULL;
if (msie) {
ieBug++;
}
Expand Down
43 changes: 39 additions & 4 deletions libhttp/ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ int (*SSL_write)(SSL *, const void *, int);
SSL_METHOD * (*SSLv23_server_method)(void);
X509 * (*d2i_X509)(X509 **px, const unsigned char **in, int len);
void (*X509_free)(X509 *a);
int (*x_SSL_CTX_set_cipher_list)(SSL_CTX *ctx, const char *str);
void (*x_sk_zero)(void *st);
void * (*x_SSL_COMP_get_compression_methods)(void);
#endif

static void sslDestroyCachedContext(void *ssl_, char *context_) {
Expand Down Expand Up @@ -308,7 +311,9 @@ static void loadSSL(void) {
{ { &SSL_write }, "SSL_write" },
{ { &SSLv23_server_method }, "SSLv23_server_method" },
{ { &d2i_X509 }, "d2i_X509" },
{ { &X509_free }, "X509_free" }
{ { &X509_free }, "X509_free" },
{ { &x_SSL_CTX_set_cipher_list }, "SSL_CTX_set_cipher_list" },
{ { &x_sk_zero }, "sk_zero" }
};
for (unsigned i = 0; i < sizeof(symbols)/sizeof(symbols[0]); i++) {
if (!(*symbols[i].var = loadSymbol(path_libssl, symbols[i].fn))) {
Expand All @@ -320,6 +325,10 @@ static void loadSSL(void) {
return;
}
}
// These are optional
x_SSL_COMP_get_compression_methods = loadSymbol(path_libssl, "SSL_COMP_get_compression_methods");
// ends

SSL_library_init();
dcheck(!ERR_peek_error());
debug("Loaded SSL suppport");
Expand Down Expand Up @@ -583,6 +592,32 @@ static int sslSetCertificateFromFile(SSL_CTX *context,
}
#endif

static SSL_CTX *sslMakeContext(void) {
SSL_CTX *context;
check(context = SSL_CTX_new(SSLv23_server_method()));
SSL_CTX_set_options(context, SSL_OP_ALL);
SSL_CTX_set_options(context, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
#ifdef SSL_OP_NO_COMPRESSION
SSL_CTX_set_options(context, SSL_OP_NO_COMPRESSION);
#endif
#if defined(HAVE_DLOPEN)
if (SSL_COMP_get_compression_methods) {
sk_SSL_COMP_zero(SSL_COMP_get_compression_methods());
}
#elif OPENSSL_VERSION_NUMBER >= 0x00908000L
sk_SSL_COMP_zero(SSL_COMP_get_compression_methods());
#endif
SSL_CTX_set_options(context, SSL_OP_SINGLE_DH_USE);
#ifdef SSL_OP_SINGLE_ECDH_USE
SSL_CTX_set_options(context, SSL_OP_SINGLE_ECDH_USE);
#endif
#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
SSL_CTX_set_options(context, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
#endif
check(SSL_CTX_set_cipher_list(context, "HIGH:MEDIUM:!aNULL:!MD5"));
return context;
}

#ifdef HAVE_TLSEXT
static int sslSNICallback(SSL *sslHndl, int *al ATTR_UNUSED,
struct SSLSupport *ssl) {
Expand Down Expand Up @@ -619,7 +654,7 @@ static int sslSNICallback(SSL *sslHndl, int *al ATTR_UNUSED,
serverName+1,
NULL);
if (context == NULL) {
check(context = SSL_CTX_new(SSLv23_server_method()));
context = sslMakeContext();
check(ssl->sniCertificatePattern);
char *certificate = stringPrintfUnchecked(NULL,
ssl->sniCertificatePattern,
Expand Down Expand Up @@ -697,7 +732,7 @@ void sslSetCertificate(struct SSLSupport *ssl, const char *filename,
}

// Try to set the default certificate. If necessary, (re-)generate it.
check(ssl->sslContext = SSL_CTX_new(SSLv23_server_method()));
ssl->sslContext = sslMakeContext();
if (autoGenerateMissing) {
if (sslSetCertificateFromFile(ssl->sslContext, defaultCertificate) < 0) {
char hostname[256], buf[4096];
Expand Down Expand Up @@ -781,7 +816,7 @@ static char *sslFdToFilename(int fd) {

void sslSetCertificateFd(struct SSLSupport *ssl, int fd) {
#ifdef HAVE_OPENSSL
check(ssl->sslContext = SSL_CTX_new(SSLv23_server_method()));
ssl->sslContext = sslMakeContext();
char *filename = sslFdToFilename(fd);
if (!sslSetCertificateFromFd(ssl->sslContext, fd)) {
fatal("Cannot read valid certificate from %s. Check file format.",
Expand Down
6 changes: 6 additions & 0 deletions libhttp/ssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ extern int (*x_SSL_write)(SSL *, const void *, int);
extern SSL_METHOD *(*x_SSLv23_server_method)(void);
extern X509 * (*x_d2i_X509)(X509 **px, const unsigned char **in, int len);
extern void (*x_X509_free)(X509 *a);
extern int (*x_SSL_CTX_set_cipher_list)(SSL_CTX *ctx, const char *str);
extern void (*x_sk_zero)(void *st);
extern void *(*x_SSL_COMP_get_compression_methods)(void);

#define BIO_ctrl x_BIO_ctrl
#define BIO_f_buffer x_BIO_f_buffer
Expand Down Expand Up @@ -151,6 +154,9 @@ extern void (*x_X509_free)(X509 *a);
#define SSLv23_server_method x_SSLv23_server_method
#define d2i_X509 x_d2i_X509
#define X509_free x_X509_free
#define SSL_CTX_set_cipher_list x_SSL_CTX_set_cipher_list
#define sk_zero x_sk_zero
#define SSL_COMP_get_compression_methods x_SSL_COMP_get_compression_methods

#undef BIO_set_buffer_read_data
#undef SSL_CTX_set_tlsext_servername_arg
Expand Down
52 changes: 50 additions & 2 deletions shellinabox/launcher.c
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,7 @@ int launchChild(int service, struct Session *session, const char *url) {
ssize_t len = sizeof(struct LaunchRequest) + strlen(u) + 1;
check(request = calloc(len, 1));
request->service = service;
request->terminate = -1;
request->width = session->width;
request->height = session->height;
strncat(request->peerName, httpGetPeerName(session->http),
Expand Down Expand Up @@ -547,6 +548,7 @@ int launchChild(int service, struct Session *session, const char *url) {
return -1;
}
check(bytes == sizeof(pid));
check(session->pid = pid);
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
check(cmsg);
check(cmsg->cmsg_level == SOL_SOCKET);
Expand All @@ -555,6 +557,34 @@ int launchChild(int service, struct Session *session, const char *url) {
return pid;
}

int terminateChild(struct Session *session) {
if (launcher < 0) {
errno = EINVAL;
return -1;
}

if (session->pid < 1) {
debug("Child pid for termination not valid!");
return -1;
}

// Send terminate request to launcher process
struct LaunchRequest *request;
ssize_t len = sizeof(struct LaunchRequest);
check(request = calloc(len, 1));
request->terminate = session->pid;
if (NOINTR(write(launcher, request, len)) != len) {
debug("Child %d termination request failed!", request->terminate);
free(request);
return -1;
}

free(request);
session->pid = 0;
session->cleanup = 0;
return 0;
}

struct Utmp {
const char pid[32];
int pty;
Expand Down Expand Up @@ -1616,7 +1646,8 @@ static void launcherDaemon(int fd) {
int status;
pid_t pid;
while (NOINTR(pid = waitpid(-1, &status, WNOHANG)) > 0) {
if (WIFEXITED(pid) || WIFSIGNALED(pid)) {
debug("Child %d exited with exit code %d", pid, WEXITSTATUS(status));
if (WIFEXITED(status) || WIFSIGNALED(status)) {
char key[32];
snprintf(&key[0], sizeof(key), "%d", pid);
deleteFromHashMap(childProcesses, key);
Expand All @@ -1626,6 +1657,21 @@ static void launcherDaemon(int fd) {
continue;
}

// Check if we received terminate request from parent process and
// try to terminate child, if child is still running
if (request.terminate > 0) {
errno = 0;
NOINTR(pid = waitpid(request.terminate, &status, WNOHANG));
if (pid == 0 && errno == 0) {
if (kill(request.terminate, SIGTERM) == 0) {
debug("Terminating child %d (kill)", request.terminate);
} else {
debug("Terminating child failed [%s]", strerror(errno));
}
}
continue;
}

char *url;
check(url = calloc(request.urlLength + 1, 1));
readURL:
Expand All @@ -1636,7 +1682,8 @@ static void launcherDaemon(int fd) {
break;
}
while (NOINTR(pid = waitpid(-1, &status, WNOHANG)) > 0) {
if (WIFEXITED(pid) || WIFSIGNALED(pid)) {
debug("Child %d exited with exit code %d", pid, WEXITSTATUS(status));
if (WIFEXITED(status) || WIFSIGNALED(status)) {
char key[32];
snprintf(&key[0], sizeof(key), "%d", pid);
deleteFromHashMap(childProcesses, key);
Expand Down Expand Up @@ -1680,6 +1727,7 @@ static void launcherDaemon(int fd) {
childProcesses = newHashMap(destroyUtmpHashEntry, NULL);
}
addToHashMap(childProcesses, utmp->pid, (char *)utmp);
debug("Child %d launched", pid);
} else {
int fds[2];
if (!pipe(fds)) {
Expand Down
12 changes: 7 additions & 5 deletions shellinabox/launcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,17 @@


struct LaunchRequest {
int service;
int width, height;
char peerName[128];
int urlLength;
char url[0];
int service;
int width, height;
pid_t terminate;
char peerName[128];
int urlLength;
char url[0];
};

int supportsPAM(void);
int launchChild(int service, struct Session *session, const char *url);
int terminateChild(struct Session *session);
void setWindowSize(int pty, int width, int height);
int forkLauncher(void);
void terminateLauncher(void);
Expand Down
2 changes: 2 additions & 0 deletions shellinabox/session.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ void initSession(struct Session *session, const char *sessionKey,
session->height = 0;
session->buffered = NULL;
session->len = 0;
session->pid = 0;
session->cleanup = 0;
}

struct Session *newSession(const char *sessionKey, Server *server, URL *url,
Expand Down
2 changes: 2 additions & 0 deletions shellinabox/session.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ struct Session {
int height;
char *buffered;
int len;
pid_t pid;
int cleanup;
};

void addToGraveyard(struct Session *session);
Expand Down
6 changes: 5 additions & 1 deletion shellinabox/shellinaboxd.c
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,11 @@ static int completePendingRequest(struct Session *session,
}

static void sessionDone(void *arg) {
debug("Child terminated");
struct Session *session = (struct Session *)arg;
debug("Session %s done", session->sessionKey);
if (session->cleanup) {
terminateChild(session);
}
session->done = 1;
addToGraveyard(session);
completePendingRequest(session, "", 0, INT_MAX);
Expand All @@ -301,6 +304,7 @@ static int handleSession(struct ServerConnection *connection, void *arg,
if (bytes || timedOut) {
if (!session->http && timedOut) {
debug("Timeout. Closing session.");
session->cleanup = 1;
return 0;
}
check(!session->done);
Expand Down