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