mirror of
https://github.com/cesanta/mongoose.git
synced 2024-11-24 02:59:01 +08:00
put back dynamic SSL lib loading
This commit is contained in:
parent
4f716e2b9a
commit
ee997ba7d4
14
Makefile
14
Makefile
@ -22,8 +22,7 @@ all:
|
||||
|
||||
CFLAGS= -W -Wall -std=c99 -pedantic -Os -fomit-frame-pointer $(COPT)
|
||||
MAC_SHARED= -flat_namespace -bundle -undefined suppress
|
||||
SSLFLAGS= -lssl -lcrypto
|
||||
LINFLAGS= -ldl -pthread $(SSLFLAGS) $(CFLAGS)
|
||||
LINFLAGS= -ldl -pthread $(CFLAGS)
|
||||
LIB= _$(PROG).so
|
||||
|
||||
linux:
|
||||
@ -32,17 +31,16 @@ linux:
|
||||
|
||||
bsd:
|
||||
$(CC) $(CFLAGS) mongoose.c -shared -pthread -fpic -fPIC -o $(LIB)
|
||||
$(CC) $(CFLAGS) mongoose.c main.c -pthread $(SSLFLAGS) -o $(PROG)
|
||||
$(CC) $(CFLAGS) mongoose.c main.c -pthread -o $(PROG)
|
||||
|
||||
mac:
|
||||
$(CC) $(CFLAGS) $(MAC_SHARED) mongoose.c -pthread $(SSLFLAGS) -o $(LIB)
|
||||
$(CC) $(CFLAGS) mongoose.c main.c -pthread $(SSLFLAGS) -o $(PROG)
|
||||
$(CC) $(CFLAGS) $(MAC_SHARED) mongoose.c -pthread -o $(LIB)
|
||||
$(CC) $(CFLAGS) mongoose.c main.c -pthread -o $(PROG)
|
||||
|
||||
solaris:
|
||||
gcc $(CFLAGS) mongoose.c -pthread -lnsl \
|
||||
-lsocket $(SSLFLAGS) -fpic -fPIC -shared -o $(LIB)
|
||||
gcc $(CFLAGS) mongoose.c main.c -pthread -lnsl -lsocket $(SSLFLAGS) \
|
||||
-o $(PROG)
|
||||
-lsocket -fpic -fPIC -shared -o $(LIB)
|
||||
gcc $(CFLAGS) mongoose.c main.c -pthread -lnsl -lsocket -o $(PROG)
|
||||
|
||||
|
||||
##########################################################################
|
||||
|
195
mongoose.c
195
mongoose.c
@ -90,6 +90,8 @@ typedef long off_t;
|
||||
|
||||
#define ERRNO GetLastError()
|
||||
#define NO_SOCKLEN_T
|
||||
#define SSL_LIB "ssleay32.dll"
|
||||
#define CRYPTO_LIB "libeay32.dll"
|
||||
#define DIRSEP '\\'
|
||||
#define IS_DIRSEP_CHAR(c) ((c) == '/' || (c) == '\\')
|
||||
#define O_NONBLOCK 0
|
||||
@ -172,6 +174,13 @@ typedef struct DIR {
|
||||
#include <dirent.h>
|
||||
#include <dlfcn.h>
|
||||
#include <pthread.h>
|
||||
#if defined(__MACH__)
|
||||
#define SSL_LIB "libssl.dylib"
|
||||
#define CRYPTO_LIB "libcrypto.dylib"
|
||||
#else
|
||||
#define SSL_LIB "libssl.so"
|
||||
#define CRYPTO_LIB "libcrypto.so"
|
||||
#endif
|
||||
#define DIRSEP '/'
|
||||
#define IS_DIRSEP_CHAR(c) ((c) == '/')
|
||||
#define O_BINARY 0
|
||||
@ -230,27 +239,76 @@ typedef struct ssl_ctx_st SSL_CTX;
|
||||
#define SSL_FILETYPE_PEM 1
|
||||
#define CRYPTO_LOCK 1
|
||||
|
||||
extern void SSL_free(SSL *);
|
||||
extern int SSL_accept(SSL *);
|
||||
extern int SSL_connect(SSL *);
|
||||
extern int SSL_read(SSL *, void *, int);
|
||||
extern int SSL_write(SSL *, const void *, int);
|
||||
extern int SSL_get_error(const SSL *, int);
|
||||
extern int SSL_set_fd(SSL *, int);
|
||||
extern SSL *SSL_new(SSL_CTX *);
|
||||
extern SSL_CTX *SSL_CTX_new(SSL_METHOD *);
|
||||
extern SSL_METHOD *SSLv23_server_method(void);
|
||||
extern int SSL_library_init(void);
|
||||
extern void SSL_load_error_strings(void);
|
||||
extern int SSL_CTX_use_PrivateKey_file(SSL_CTX *, const char *, int);
|
||||
extern int SSL_CTX_use_certificate_file(SSL_CTX *, const char *, int);
|
||||
extern void SSL_CTX_set_default_passwd_cb(SSL_CTX *, mg_callback_t);
|
||||
extern void SSL_CTX_free(SSL_CTX *);
|
||||
extern unsigned long ERR_get_error(void);
|
||||
extern char *ERR_error_string(unsigned long, char *);
|
||||
extern int CRYPTO_num_locks(void);
|
||||
extern void CRYPTO_set_locking_callback(void (*)(int, int, const char *, int));
|
||||
extern void CRYPTO_set_id_callback(unsigned long (*)(void));
|
||||
// Dynamically loaded SSL functionality
|
||||
struct ssl_func {
|
||||
const char *name; // SSL function name
|
||||
void (*ptr)(void); // Function pointer
|
||||
};
|
||||
|
||||
#define SSL_free(x) (* (void (*)(SSL *)) ssl_sw[0].ptr)(x)
|
||||
#define SSL_accept(x) (* (int (*)(SSL *)) ssl_sw[1].ptr)(x)
|
||||
#define SSL_connect(x) (* (int (*)(SSL *)) ssl_sw[2].ptr)(x)
|
||||
#define SSL_read(x,y,z) (* (int (*)(SSL *, void *, int)) \
|
||||
ssl_sw[3].ptr)((x),(y),(z))
|
||||
#define SSL_write(x,y,z) (* (int (*)(SSL *, const void *,int)) \
|
||||
ssl_sw[4].ptr)((x), (y), (z))
|
||||
#define SSL_get_error(x,y)(* (int (*)(SSL *, int)) ssl_sw[5])((x), (y))
|
||||
#define SSL_set_fd(x,y) (* (int (*)(SSL *, SOCKET)) ssl_sw[6].ptr)((x), (y))
|
||||
#define SSL_new(x) (* (SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr)(x)
|
||||
#define SSL_CTX_new(x) (* (SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr)(x)
|
||||
#define SSLv23_server_method() (* (SSL_METHOD * (*)(void)) ssl_sw[9].ptr)()
|
||||
#define SSL_library_init() (* (int (*)(void)) ssl_sw[10].ptr)()
|
||||
#define SSL_CTX_use_PrivateKey_file(x,y,z) (* (int (*)(SSL_CTX *, \
|
||||
const char *, int)) ssl_sw[11].ptr)((x), (y), (z))
|
||||
#define SSL_CTX_use_certificate_file(x,y,z) (* (int (*)(SSL_CTX *, \
|
||||
const char *, int)) ssl_sw[12].ptr)((x), (y), (z))
|
||||
#define SSL_CTX_set_default_passwd_cb(x,y) \
|
||||
(* (void (*)(SSL_CTX *, mg_callback_t)) ssl_sw[13].ptr)((x),(y))
|
||||
#define SSL_CTX_free(x) (* (void (*)(SSL_CTX *)) ssl_sw[14].ptr)(x)
|
||||
#define ERR_get_error() (* (unsigned long (*)(void)) ssl_sw[15].ptr)()
|
||||
#define ERR_error_string(x, y) (* (char * (*)(unsigned long, char *)) ssl_sw[16].ptr)((x), (y))
|
||||
#define SSL_load_error_strings() (* (void (*)(void)) ssl_sw[17].ptr)()
|
||||
|
||||
#define CRYPTO_num_locks() (* (int (*)(void)) crypto_sw[0].ptr)()
|
||||
#define CRYPTO_set_locking_callback(x) \
|
||||
(* (void (*)(void (*)(int, int, const char *, int))) \
|
||||
crypto_sw[1].ptr)(x)
|
||||
#define CRYPTO_set_id_callback(x) \
|
||||
(* (void (*)(unsigned long (*)(void))) crypto_sw[2].ptr)(x)
|
||||
|
||||
// set_ssl_option() function updates this array.
|
||||
// It loads SSL library dynamically and changes NULLs to the actual addresses
|
||||
// of respective functions. The macros above (like SSL_connect()) are really
|
||||
// just calling these functions indirectly via the pointer.
|
||||
static struct ssl_func ssl_sw[] = {
|
||||
{"SSL_free", NULL},
|
||||
{"SSL_accept", NULL},
|
||||
{"SSL_connect", NULL},
|
||||
{"SSL_read", NULL},
|
||||
{"SSL_write", NULL},
|
||||
{"SSL_get_error", NULL},
|
||||
{"SSL_set_fd", NULL},
|
||||
{"SSL_new", NULL},
|
||||
{"SSL_CTX_new", NULL},
|
||||
{"SSLv23_server_method", NULL},
|
||||
{"SSL_library_init", NULL},
|
||||
{"SSL_CTX_use_PrivateKey_file", NULL},
|
||||
{"SSL_CTX_use_certificate_file",NULL},
|
||||
{"SSL_CTX_set_default_passwd_cb",NULL},
|
||||
{"SSL_CTX_free", NULL},
|
||||
{"ERR_get_error", NULL},
|
||||
{"ERR_error_string", NULL},
|
||||
{"SSL_load_error_strings", NULL},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
// Similar array as ssl_sw. These functions could be located in different lib.
|
||||
static struct ssl_func crypto_sw[] = {
|
||||
{"CRYPTO_num_locks", NULL},
|
||||
{"CRYPTO_set_locking_callback", NULL},
|
||||
{"CRYPTO_set_id_callback", NULL},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static const char *month_names[] = {
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
@ -291,15 +349,15 @@ struct socket {
|
||||
};
|
||||
|
||||
struct mg_context {
|
||||
int stop_flag; // Should we stop event loop
|
||||
SSL_CTX *ssl_ctx; // SSL context
|
||||
int stop_flag; // Should we stop event loop
|
||||
SSL_CTX *ssl_ctx; // SSL context
|
||||
const struct mg_config *config; // Mongoose configuration
|
||||
|
||||
struct socket *listening_sockets;
|
||||
|
||||
int num_threads; // Number of threads
|
||||
pthread_mutex_t mutex; // Protects (max|num)_threads
|
||||
pthread_cond_t cond; // Condvar for tracking workers terminations
|
||||
int num_threads; // Number of threads
|
||||
pthread_mutex_t mutex; // Protects (max|num)_threads
|
||||
pthread_cond_t cond; // Condvar for tracking workers terminations
|
||||
|
||||
struct socket queue[20]; // Accepted sockets
|
||||
int sq_head; // Head of the socket queue
|
||||
@ -373,6 +431,13 @@ static void cry(struct mg_connection *conn, const char *fmt, ...) {
|
||||
conn->request_info.log_message = NULL;
|
||||
}
|
||||
|
||||
// Return OpenSSL error message
|
||||
static const char *ssl_error(void) {
|
||||
unsigned long err;
|
||||
err = ERR_get_error();
|
||||
return err == 0 ? "" : ERR_error_string(err, NULL);
|
||||
}
|
||||
|
||||
// Return fake connection structure. Used for logging, if connection
|
||||
// is not applicable at the moment of logging.
|
||||
static struct mg_connection *fc(struct mg_context *ctx) {
|
||||
@ -920,14 +985,12 @@ static int start_thread(struct mg_context *ctx, mg_thread_func_t func,
|
||||
return hThread == NULL ? -1 : 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static HANDLE dlopen(const char *dll_name, int flags) {
|
||||
wchar_t wbuf[PATH_MAX];
|
||||
flags = 0; // Unused
|
||||
to_unicode(dll_name, wbuf, ARRAY_SIZE(wbuf));
|
||||
return LoadLibraryW(wbuf);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(NO_CGI)
|
||||
#define SIGKILL 0
|
||||
@ -1125,12 +1188,9 @@ static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf,
|
||||
/* How many bytes we send in this iteration */
|
||||
k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent);
|
||||
|
||||
#if !defined(NO_SSL)
|
||||
if (ssl != NULL) {
|
||||
n = SSL_write(ssl, buf + sent, k);
|
||||
} else
|
||||
#endif // !NO_SSL
|
||||
if (fp != NULL) {
|
||||
} else if (fp != NULL) {
|
||||
n = fwrite(buf + sent, 1, k, fp);
|
||||
if (ferror(fp))
|
||||
n = -1;
|
||||
@ -1152,12 +1212,9 @@ static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf,
|
||||
static int pull(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int len) {
|
||||
int nread;
|
||||
|
||||
#if !defined(NO_SSL)
|
||||
if (ssl != NULL) {
|
||||
nread = SSL_read(ssl, buf, len);
|
||||
} else
|
||||
#endif // !NO_SSL
|
||||
if (fp != NULL) {
|
||||
} else if (fp != NULL) {
|
||||
nread = fread(buf, 1, (size_t) len, fp);
|
||||
if (ferror(fp))
|
||||
nread = -1;
|
||||
@ -3251,33 +3308,68 @@ static unsigned long ssl_id_callback(void) {
|
||||
return (unsigned long) pthread_self();
|
||||
}
|
||||
|
||||
// Return OpenSSL error message
|
||||
static const char *ssl_error(void) {
|
||||
unsigned long err;
|
||||
err = ERR_get_error();
|
||||
return err == 0 ? "" : ERR_error_string(err, NULL);
|
||||
static bool_t load_dll(struct mg_context *ctx, const char *dll_name,
|
||||
struct ssl_func *sw) {
|
||||
union {void *p; void (*fp)(void);} u;
|
||||
void *dll_handle;
|
||||
struct ssl_func *fp;
|
||||
|
||||
if ((dll_handle = dlopen(dll_name, RTLD_LAZY)) == NULL) {
|
||||
cry(fc(ctx), "%s: cannot load %s", __func__, dll_name);
|
||||
return MG_FALSE;
|
||||
}
|
||||
|
||||
for (fp = sw; fp->name != NULL; fp++) {
|
||||
#ifdef _WIN32
|
||||
// GetProcAddress() returns pointer to function
|
||||
u.fp = (void (*)(void)) dlsym(dll_handle, fp->name);
|
||||
#else
|
||||
// dlsym() on UNIX returns void *. ISO C forbids casts of data pointers to
|
||||
// function pointers. We need to use a union to make a cast.
|
||||
u.p = dlsym(dll_handle, fp->name);
|
||||
#endif /* _WIN32 */
|
||||
if (u.fp == NULL) {
|
||||
cry(fc(ctx), "%s: cannot find %s", __func__, fp->name);
|
||||
return MG_FALSE;
|
||||
} else {
|
||||
fp->ptr = u.fp;
|
||||
}
|
||||
}
|
||||
|
||||
return MG_TRUE;
|
||||
}
|
||||
|
||||
// Dynamically load SSL library. Set up ctx->ssl_ctx pointer.
|
||||
static enum mg_error_t set_ssl_option(struct mg_context *ctx) {
|
||||
SSL_CTX *CTX;
|
||||
int i, size;
|
||||
const char *pem = ctx->config->ssl_certificate;
|
||||
|
||||
if (pem == NULL) {
|
||||
return MG_SUCCESS;
|
||||
}
|
||||
|
||||
if (load_dll(ctx, SSL_LIB, ssl_sw) == MG_FALSE ||
|
||||
load_dll(ctx, CRYPTO_LIB, crypto_sw) == MG_FALSE) {
|
||||
return MG_ERROR;
|
||||
}
|
||||
|
||||
// Initialize SSL crap
|
||||
SSL_library_init();
|
||||
SSL_load_error_strings();
|
||||
|
||||
if ((CTX = SSL_CTX_new(SSLv23_server_method())) == NULL) {
|
||||
cry(fc(ctx), "SSL_CTX_new error: %s", ssl_error());
|
||||
return MG_ERROR;
|
||||
} else if (ctx->config->ssl_password_handler != NULL) {
|
||||
SSL_CTX_set_default_passwd_cb(CTX, ctx->config->ssl_password_handler);
|
||||
}
|
||||
|
||||
if (SSL_CTX_use_certificate_file(CTX, pem, SSL_FILETYPE_PEM) == 0) {
|
||||
if (CTX != NULL && SSL_CTX_use_certificate_file(CTX, pem,
|
||||
SSL_FILETYPE_PEM) == 0) {
|
||||
cry(fc(ctx), "%s: cannot open %s: %s", __func__, pem, ssl_error());
|
||||
return MG_ERROR;
|
||||
} else if (SSL_CTX_use_PrivateKey_file(CTX, pem, SSL_FILETYPE_PEM) == 0) {
|
||||
} else if (CTX != NULL && SSL_CTX_use_PrivateKey_file(CTX, pem,
|
||||
SSL_FILETYPE_PEM) == 0) {
|
||||
cry(fc(ctx), "%s: cannot open %s: %s", NULL, pem, ssl_error());
|
||||
return MG_ERROR;
|
||||
}
|
||||
@ -3365,12 +3457,10 @@ static void close_socket_gracefully(SOCKET sock) {
|
||||
}
|
||||
|
||||
static void close_connection(struct mg_connection *conn) {
|
||||
#if !defined(NO_SSL)
|
||||
if (conn->ssl) {
|
||||
SSL_free(conn->ssl);
|
||||
conn->ssl = NULL;
|
||||
}
|
||||
#endif // !NO_SSL
|
||||
|
||||
if (conn->client.sock != INVALID_SOCKET) {
|
||||
close_socket_gracefully(conn->client.sock);
|
||||
@ -3486,7 +3576,6 @@ static void worker_thread(struct mg_context *ctx) {
|
||||
conn->request_info.remote_ip = ntohl(conn->request_info.remote_ip);
|
||||
conn->request_info.is_ssl = conn->client.is_ssl;
|
||||
|
||||
#if !defined(NO_SSL)
|
||||
if (conn->client.is_ssl && (conn->ssl = SSL_new(ctx->ssl_ctx)) == NULL) {
|
||||
cry(conn, "%s: SSL_new: %s", __func__, ssl_error());
|
||||
} else if (conn->client.is_ssl &&
|
||||
@ -3494,9 +3583,7 @@ static void worker_thread(struct mg_context *ctx) {
|
||||
cry(conn, "%s: SSL_set_fd: %s", __func__, ssl_error());
|
||||
} else if (conn->client.is_ssl && SSL_accept(conn->ssl) != 1) {
|
||||
cry(conn, "%s: SSL handshake error: %s", __func__, ssl_error());
|
||||
} else
|
||||
#endif // !NO_SSL
|
||||
{
|
||||
} else {
|
||||
process_new_connection(conn);
|
||||
}
|
||||
|
||||
@ -3604,12 +3691,10 @@ static void master_thread(struct mg_context *ctx) {
|
||||
}
|
||||
(void) pthread_mutex_unlock(&ctx->mutex);
|
||||
|
||||
#if !defined(NO_SSL)
|
||||
// Deallocate SSL context
|
||||
if (ctx->ssl_ctx != NULL) {
|
||||
SSL_CTX_free(ctx->ssl_ctx);
|
||||
}
|
||||
#endif // !NO_SSL
|
||||
|
||||
// All threads exited, no sync is needed. Destroy mutex and condvars
|
||||
(void) pthread_mutex_destroy(&ctx->mutex);
|
||||
@ -3667,11 +3752,9 @@ struct mg_context * mg_start(const struct mg_config *config) {
|
||||
|
||||
// NOTE(lsm): order is important here. SSL certificates must
|
||||
// be initialized before listening ports. UID must be set last.
|
||||
if (set_gpass_option(ctx) == MG_ERROR ||
|
||||
#if !defined(NO_SSL)
|
||||
(config->ssl_certificate != NULL && set_ssl_option(ctx) == MG_ERROR) ||
|
||||
#endif // !NO_SSL
|
||||
if (set_ssl_option(ctx) == MG_ERROR ||
|
||||
set_ports_option(ctx) == MG_ERROR ||
|
||||
set_gpass_option(ctx) == MG_ERROR ||
|
||||
#if !defined(_WIN32)
|
||||
set_uid_option(ctx) == MG_ERROR ||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user