From 90d9d492b70083f945a8aa2512a12da784afa0aa Mon Sep 17 00:00:00 2001 From: zodiac Date: Mon, 2 Feb 2009 00:55:15 +0000 Subject: [PATCH] Added better compatibility with different versions of compilers and libaries. In particular, work around a problem with gcc complaining about NULL format strings. And added additional system header files that might be required on some platforms. This should fix some of the problems reported when compiling on BSD-style systems. But we are still using SysV style session management code. This probably needs to be rewritten before ShellInABox can be run on BSD-style system. In particular, we rely on grantpt(), we use the utmpx API, and we access /dev/urandom. git-svn-id: https://shellinabox.googlecode.com/svn/trunk@55 0da03de8-d603-11dd-86c2-0f8696b7b6f9 --- configure | 5 ++++- configure.ac | 3 ++- libhttp/httpconnection.c | 18 +++++++++++------- libhttp/server.c | 7 +++++-- libhttp/ssl.c | 12 +++++++++++- shellinabox/externalfile.c | 16 ++++++++++------ shellinabox/launcher.c | 20 ++++++++++++++++++++ shellinabox/shellinaboxd.c | 26 +++++++++++++++++++------- 8 files changed, 82 insertions(+), 25 deletions(-) diff --git a/configure b/configure index 92506d7..4b855d8 100755 --- a/configure +++ b/configure @@ -19994,8 +19994,11 @@ fi + + for ac_header in openssl/bio.h openssl/err.h openssl/ssl.h pthread.h \ - security/pam_appl.h security/pam_misc.h + security/pam_appl.h security/pam_misc.h sys/prctrl.h \ + utmpx.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then diff --git a/configure.ac b/configure.ac index 49eecd7..f321526 100644 --- a/configure.ac +++ b/configure.ac @@ -8,6 +8,7 @@ AC_SUBST(LIBTOOL_DEPS) AC_C_CONST AC_PROG_GCC_TRADITIONAL AC_CHECK_HEADERS([openssl/bio.h openssl/err.h openssl/ssl.h pthread.h \ - security/pam_appl.h security/pam_misc.h]) + security/pam_appl.h security/pam_misc.h sys/prctrl.h \ + utmpx.h]) AC_CONFIG_FILES([Makefile]) AC_OUTPUT diff --git a/libhttp/httpconnection.c b/libhttp/httpconnection.c index 627f896..3084720 100644 --- a/libhttp/httpconnection.c +++ b/libhttp/httpconnection.c @@ -51,6 +51,8 @@ #include #include #include +#include +#include #include #include "libhttp/httpconnection.h" @@ -59,6 +61,8 @@ #define MAX_HEADER_LENGTH (64<<10) #define CONNECTION_TIMEOUT (10*60) +static const char *NO_MSG; + static int httpPromoteToSSL(struct HttpConnection *http, const char *buf, int len) { if (http->ssl->enabled && !http->sslHndl) { @@ -545,10 +549,10 @@ static int httpHandleCommand(struct HttpConnection *http, !strcmp(http->method, "DELETE") || !strcmp(http->method, "TRACE") || !strcmp(http->method, "CONNECT")) { - httpSendReply(http, 405, "Method Not Allowed", NULL); + httpSendReply(http, 405, "Method Not Allowed", NO_MSG); return HTTP_DONE; } else { - httpSendReply(http, 501, "Method Not Implemented", NULL); + httpSendReply(http, 501, "Method Not Implemented", NO_MSG); return HTTP_DONE; } const char *host = getFromHashMap(&http->header, @@ -562,7 +566,7 @@ static int httpHandleCommand(struct HttpConnection *http, if (ch != '-' && ch != '.' && (ch < '0' ||(ch > '9' && ch < 'A') || (ch > 'Z' && ch < 'a')|| ch > 'z')) { - httpSendReply(http, 400, "Bad Request", NULL); + httpSendReply(http, 400, "Bad Request", NO_MSG); return HTTP_DONE; } } @@ -599,7 +603,7 @@ static int httpHandleCommand(struct HttpConnection *http, return h->handler(http, h->arg); } } - httpSendReply(http, 404, "File Not Found", NULL); + httpSendReply(http, 404, "File Not Found", NO_MSG); return HTTP_DONE; } @@ -628,7 +632,7 @@ static int httpParseCommand(struct HttpConnection *http, int offset, if (!http->version) { http->version = strdup(""); } - httpSendReply(http, 400, "Bad Request", NULL); + httpSendReply(http, 400, "Bad Request", NO_MSG); httpSetState(http, COMMAND); return 0; } @@ -775,7 +779,7 @@ static int httpParseHeaders(struct HttpConnection *http, } } else { if (colon <= 0) { - httpSendReply(http, 400, "Bad Request", NULL); + httpSendReply(http, 400, "Bad Request", NO_MSG); return 0; } check(colon < lineLength); @@ -934,7 +938,7 @@ int httpHandleConnection(struct ServerConnection *connection, void *http_, if (bytes > 0) { http->headerLength += bytes; if (http->headerLength > MAX_HEADER_LENGTH) { - httpSendReply(http, 413, "Header too big", NULL); + httpSendReply(http, 413, "Header too big", NO_MSG); bytes = 0; eof = 1; } diff --git a/libhttp/server.c b/libhttp/server.c index d1e5486..3b738f9 100644 --- a/libhttp/server.c +++ b/libhttp/server.c @@ -45,6 +45,7 @@ #include #include +#include #include #include #include @@ -65,6 +66,8 @@ // API should be used, instead. #define MAX_PAYLOAD_LENGTH (64<<10) +static const char *NO_MSG; + time_t currentTime; struct PayLoad { @@ -80,7 +83,7 @@ static int serverCollectFullPayload(struct HttpConnection *http, struct PayLoad *payload = (struct PayLoad *)payload_; if (buf && len) { if (payload->len + len > MAX_PAYLOAD_LENGTH) { - httpSendReply(http, 400, "Bad Request", NULL); + httpSendReply(http, 400, "Bad Request", NO_MSG); return HTTP_DONE; } check(len > 0); @@ -162,7 +165,7 @@ void serverRegisterStreamingHttpHandler(struct Server *server, const char *url, } static int serverQuitHandler(struct HttpConnection *http, void *arg) { - httpSendReply(http, 200, "Good Bye", NULL); + httpSendReply(http, 200, "Good Bye", NO_MSG); httpExitLoop(http, 1); return HTTP_DONE; } diff --git a/libhttp/ssl.c b/libhttp/ssl.c index b0987e3..8b8a714 100644 --- a/libhttp/ssl.c +++ b/libhttp/ssl.c @@ -167,7 +167,11 @@ static void *loadSymbol(const char *lib, const char *fn) { void *dl = RTLD_DEFAULT; void *rc = dlsym(dl, fn); if (!rc) { +#ifdef RTLD_NOLOAD dl = dlopen(lib, RTLD_LAZY|RTLD_GLOBAL|RTLD_NOLOAD); +#else + dl = NULL; +#endif if (dl == NULL) { dl = dlopen(lib, RTLD_LAZY|RTLD_GLOBAL); } @@ -540,7 +544,11 @@ void sslSetCertificateFd(struct SSLSupport *ssl, int fd) { const unsigned char *rsa = sslPEMtoASN1(data, "RSA PRIVATE KEY", &rsaSize); const unsigned char *dsa = sslPEMtoASN1(data, "DSA PRIVATE KEY", &dsaSize); const unsigned char *ec = sslPEMtoASN1(data, "EC PRIVATE KEY", &ecSize); - if (!certSize || !(rsaSize > 0 || dsaSize > 0 || ecSize > 0) || + if (!certSize || !(rsaSize > 0 || dsaSize > 0 +#ifdef EVP_PKEY_EC + || ecSize > 0 +#endif + ) || !SSL_CTX_use_certificate_ASN1(ssl->sslContext, certSize, cert) || (rsaSize > 0 && !SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_RSA, ssl->sslContext, rsa, @@ -548,9 +556,11 @@ void sslSetCertificateFd(struct SSLSupport *ssl, int fd) { (dsaSize > 0 && !SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_DSA, ssl->sslContext, dsa, dsaSize)) || +#ifdef EVP_PKEY_EC (ecSize > 0 && !SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_EC, ssl->sslContext, ec, ecSize)) || +#endif !SSL_CTX_check_private_key(ssl->sslContext)) { fatal("Cannot read valid certificate from fd %d. Check file format.", fd); } diff --git a/shellinabox/externalfile.c b/shellinabox/externalfile.c index a7dbb0c..888e059 100644 --- a/shellinabox/externalfile.c +++ b/shellinabox/externalfile.c @@ -58,6 +58,7 @@ #include "libhttp/server.h" #include "logging/logging.h" +static const char *NO_MSG; static int externalFileHttpHandler(HttpConnection *http, void *arg, const char *buf, int len) { @@ -91,7 +92,7 @@ static int externalFileHttpHandler(HttpConnection *http, void *arg, if (*ptr == '.') { deleteURL(url); free(fn); - httpSendReply(http, 404, "File not found", NULL); + httpSendReply(http, 404, "File not found", NO_MSG); return HTTP_DONE; } ptr = strchr(ptr + 1, '/'); @@ -99,6 +100,9 @@ static int externalFileHttpHandler(HttpConnection *http, void *arg, } // Open file for reading +#ifndef O_LARGEFILE +#define O_LARGEFILE 0 +#endif int fd = NOINTR(open(fn, O_RDONLY|O_LARGEFILE)); // Recognize a couple of common MIME types @@ -135,20 +139,20 @@ static int externalFileHttpHandler(HttpConnection *http, void *arg, if (fd < 0) { free(fn); - httpSendReply(http, 404, "File not found", NULL); + httpSendReply(http, 404, "File not found", NO_MSG); return HTTP_DONE; } // We only serve regular files, and restrict the file size to 100MB. // As a special-case, we also allow access to /dev/null. - struct stat64 sb = { 0 }; + struct stat sb = { 0 }; if (strcmp(fn, "/dev/null") && - (fstat64(fd, &sb) || + (fstat(fd, &sb) || !S_ISREG(sb.st_mode) || sb.st_size > (100 << 20))) { free(fn); NOINTR(close(fd)); - httpSendReply(http, 404, "File not found", NULL); + httpSendReply(http, 404, "File not found", NO_MSG); return HTTP_DONE; } free(fn); @@ -175,7 +179,7 @@ static int externalFileHttpHandler(HttpConnection *http, void *arg, if (bytes < 0) { free(response); NOINTR(close(fd)); - httpSendReply(http, 404, "File not found", NULL); + httpSendReply(http, 404, "File not found", NO_MSG); return HTTP_DONE; } } diff --git a/shellinabox/launcher.c b/shellinabox/launcher.c index 65d8377..8c3c07c 100644 --- a/shellinabox/launcher.c +++ b/shellinabox/launcher.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -62,7 +63,10 @@ #include #include #include + +#ifdef HAVE_UTMPX_H #include +#endif #if defined(HAVE_SECURITY_PAM_APPL_H) && defined(HAVE_SECURITY_PAM_MISC_H) #include @@ -228,7 +232,9 @@ struct Utmp { const char pid[32]; int pty; int useLogin; +#ifdef HAVE_UTMPX_H struct utmpx utmpx; +#endif }; static HashMap *childProcesses; @@ -238,6 +244,7 @@ void initUtmp(struct Utmp *utmp, int useLogin, const char *ptyPath, memset(utmp, 0, sizeof(struct Utmp)); utmp->pty = -1; utmp->useLogin = useLogin; +#ifdef HAVE_UTMPX_H utmp->utmpx.ut_type = useLogin ? LOGIN_PROCESS : USER_PROCESS; dcheck(!strncmp(ptyPath, "/dev/pts", 8)); strncat(&utmp->utmpx.ut_line[0], ptyPath + 5, sizeof(utmp->utmpx.ut_line)); @@ -248,6 +255,7 @@ void initUtmp(struct Utmp *utmp, int useLogin, const char *ptyPath, check(!gettimeofday(&tv, NULL)); utmp->utmpx.ut_tv.tv_sec = tv.tv_sec; utmp->utmpx.ut_tv.tv_usec = tv.tv_usec; +#endif } struct Utmp *newUtmp(int useLogin, const char *ptyPath, @@ -261,6 +269,7 @@ struct Utmp *newUtmp(int useLogin, const char *ptyPath, void destroyUtmp(struct Utmp *utmp) { if (utmp) { if (utmp->pty >= 0) { +#ifdef HAVE_UTMPX_H utmp->utmpx.ut_type = DEAD_PROCESS; memset(&utmp->utmpx.ut_user, 0, sizeof(utmp->utmpx.ut_user)); memset(&utmp->utmpx.ut_host, 0, sizeof(utmp->utmpx.ut_host)); @@ -287,6 +296,7 @@ void destroyUtmp(struct Utmp *utmp) { // Switch back to the lower privileges check(!setresgid(r_gid, e_gid, s_gid)); check(!setresuid(r_uid, e_uid, s_uid)); +#endif NOINTR(close(utmp->pty)); } @@ -388,7 +398,9 @@ static int forkPty(int *pty, int useLogin, struct Utmp **utmp, } else if (pid == 0) { pid = getpid(); snprintf((char *)&(*utmp)->pid[0], sizeof((*utmp)->pid), "%d", pid); +#ifdef HAVE_UTMPX_H (*utmp)->utmpx.ut_pid = pid; +#endif (*utmp)->pty = slave; closeAllFds((int []){ slave }, 1); @@ -412,7 +424,9 @@ static int forkPty(int *pty, int useLogin, struct Utmp **utmp, return 0; } else { snprintf((char *)&(*utmp)->pid[0], sizeof((*utmp)->pid), "%d", pid); +#ifdef HAVE_UTMPX_H (*utmp)->utmpx.ut_pid = pid; +#endif (*utmp)->pty = *pty; fcntl(*pty, F_SETFL, O_NONBLOCK|O_RDWR); NOINTR(close(slave)); @@ -557,8 +571,10 @@ static pam_handle_t *internalLogin(struct Service *service, struct Utmp *utmp, #if defined(HAVE_SECURITY_PAM_APPL_H) && defined(HAVE_SECURITY_PAM_MISC_H) if (pam) { +#ifdef HAVE_UTMPX_H check(x_pam_set_item(pam, PAM_TTY, (const void **)utmp->utmpx.ut_line) == PAM_SUCCESS); +#endif } #else check(!pam); @@ -608,12 +624,14 @@ static pam_handle_t *internalLogin(struct Service *service, struct Utmp *utmp, free((void *)pw); // Update utmp/wtmp entries +#ifdef HAVE_UTMPX_H memset(&utmp->utmpx.ut_user, 0, sizeof(utmp->utmpx.ut_user)); strncat(&utmp->utmpx.ut_user[0], service->user, sizeof(utmp->utmpx.ut_user)); setutxent(); pututxline(&utmp->utmpx); endutxent(); updwtmpx("/var/log/wtmp", &utmp->utmpx); +#endif alarm(0); return pam; @@ -849,6 +867,7 @@ static void childProcess(struct Service *service, int width, int height, // Assert root privileges in order to update utmp entry. setresuid(0, 0, 0); setresgid(0, 0, 0); +#ifdef HAVE_UTMPX_H setutxent(); struct utmpx utmpx = utmp->utmpx; if (service->useLogin || service->authUser) { @@ -862,6 +881,7 @@ static void childProcess(struct Service *service, int width, int height, strncat(&utmpx.ut_user[0], "LOGIN", sizeof(utmpx.ut_user)); updwtmpx("/var/log/wtmp", &utmpx); } +#endif // Create session. We might have to fork another process as PAM wants us // to close the session when the child terminates. And we must retain diff --git a/shellinabox/shellinaboxd.c b/shellinabox/shellinaboxd.c index 385f63c..0db9ff1 100644 --- a/shellinabox/shellinaboxd.c +++ b/shellinabox/shellinaboxd.c @@ -54,12 +54,15 @@ #include #include #include -#include #include #include #include #include +#ifdef HAVE_SYS_PRCTL_H +#include +#endif + #include "libhttp/http.h" #include "logging/logging.h" #include "shellinabox/externalfile.h" @@ -71,6 +74,8 @@ #define PORTNUM 4200 #define MAX_RESPONSE 2048 +static const char *NO_MSG; + static int port; static int portMin; static int portMax; @@ -296,7 +301,7 @@ static int dataHandler(HttpConnection *http, struct Service *service, int isNew; struct Session *session = findCGISession(&isNew, http, url, cgiSessionKey); if (session == NULL) { - httpSendReply(http, 400, "Bad Request", NULL); + httpSendReply(http, 400, "Bad Request", NO_MSG); return HTTP_DONE; } @@ -304,7 +309,7 @@ static int dataHandler(HttpConnection *http, struct Service *service, if (!isNew && strcmp(session->peerName, httpGetPeerName(http))) { error("Peername changed from %s to %s", session->peerName, httpGetPeerName(http)); - httpSendReply(http, 400, "Bad Request", NULL); + httpSendReply(http, 400, "Bad Request", NO_MSG); return HTTP_DONE; } @@ -326,13 +331,13 @@ static int dataHandler(HttpConnection *http, struct Service *service, if (cgiServer && cgiSessions++) { serverExitLoop(cgiServer, 1); abandonSession(session); - httpSendReply(http, 400, "Bad Request", NULL); + httpSendReply(http, 400, "Bad Request", NO_MSG); return HTTP_DONE; } session->http = http; if (launchChild(service->id, session) < 0) { abandonSession(session); - httpSendReply(http, 500, "Internal Error", NULL); + httpSendReply(http, 500, "Internal Error", NO_MSG); return HTTP_DONE; } if (cgiServer) { @@ -381,7 +386,7 @@ static int dataHandler(HttpConnection *http, struct Service *service, // queue (or process) a new one. if (session->http && session->http != http && !completePendingRequest(session, "", 0, MAX_RESPONSE)) { - httpSendReply(http, 400, "Bad Request", NULL); + httpSendReply(http, 400, "Bad Request", NO_MSG); return HTTP_DONE; } session->http = http; @@ -523,7 +528,7 @@ static int shellInABoxHttpHandler(HttpConnection *http, void *arg, extern char stylesEnd[]; serveStaticFile(http, "text/css; charset=utf-8", stylesStart, stylesEnd); } else { - httpSendReply(http, 404, "File not found", NULL); + httpSendReply(http, 404, "File not found", NO_MSG); } deleteURL(url); @@ -852,6 +857,9 @@ static void parseArgs(int argc, char * const argv[]) { } setsid(); if (pidfile) { +#ifndef O_LARGEFILE +#define O_LARGEFILE 0 +#endif int fd = NOINTR(open(pidfile, O_WRONLY|O_TRUNC|O_LARGEFILE|O_CREAT, 0644)); @@ -905,8 +913,12 @@ static void setUpSSL(Server *server) { } int main(int argc, char * const argv[]) { +#ifdef HAVE_SYS_PRCTL_H // Disable core files prctl(PR_SET_DUMPABLE, 0, 0, 0, 0); +#endif + struct rlimit rl = { 0 }; + setrlimit(RLIMIT_CORE, &rl); removeLimits(); // Parse command line arguments