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
This commit is contained in:
parent
8a6cba17f1
commit
90d9d492b7
8 changed files with 82 additions and 25 deletions
5
configure
vendored
5
configure
vendored
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -51,6 +51,8 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/poll.h>
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include <fcntl.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -62,7 +63,10 @@
|
|||
#include <sys/utsname.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef HAVE_UTMPX_H
|
||||
#include <utmpx.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SECURITY_PAM_APPL_H) && defined(HAVE_SECURITY_PAM_MISC_H)
|
||||
#include <security/pam_appl.h>
|
||||
|
@ -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
|
||||
|
|
|
@ -54,12 +54,15 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef HAVE_SYS_PRCTL_H
|
||||
#include <sys/prctl.h>
|
||||
#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
|
||||
|
|
Loading…
Reference in a new issue