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:
zodiac 2009-02-02 00:55:15 +00:00
parent 8a6cba17f1
commit 90d9d492b7
8 changed files with 82 additions and 25 deletions

5
configure vendored
View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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;
}
}

View file

@ -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

View file

@ -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