|
@@ -90,8 +90,6 @@ typedef long off_t;
|
|
|
|
|
|
#define ERRNO GetLastError()
|
|
#define ERRNO GetLastError()
|
|
#define NO_SOCKLEN_T
|
|
#define NO_SOCKLEN_T
|
|
-#define SSL_LIB "ssleay32.dll"
|
|
|
|
-#define CRYPTO_LIB "libeay32.dll"
|
|
|
|
#define DIRSEP '\\'
|
|
#define DIRSEP '\\'
|
|
#define IS_DIRSEP_CHAR(c) ((c) == '/' || (c) == '\\')
|
|
#define IS_DIRSEP_CHAR(c) ((c) == '/' || (c) == '\\')
|
|
#define O_NONBLOCK 0
|
|
#define O_NONBLOCK 0
|
|
@@ -174,8 +172,6 @@ typedef struct DIR {
|
|
#include <dirent.h>
|
|
#include <dirent.h>
|
|
#include <dlfcn.h>
|
|
#include <dlfcn.h>
|
|
#include <pthread.h>
|
|
#include <pthread.h>
|
|
-#define SSL_LIB "libssl.so"
|
|
|
|
-#define CRYPTO_LIB "libcrypto.so"
|
|
|
|
#define DIRSEP '/'
|
|
#define DIRSEP '/'
|
|
#define IS_DIRSEP_CHAR(c) ((c) == '/')
|
|
#define IS_DIRSEP_CHAR(c) ((c) == '/')
|
|
#define O_BINARY 0
|
|
#define O_BINARY 0
|
|
@@ -234,76 +230,27 @@ typedef struct ssl_ctx_st SSL_CTX;
|
|
#define SSL_FILETYPE_PEM 1
|
|
#define SSL_FILETYPE_PEM 1
|
|
#define CRYPTO_LOCK 1
|
|
#define CRYPTO_LOCK 1
|
|
|
|
|
|
-// 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}
|
|
|
|
-};
|
|
|
|
|
|
+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));
|
|
|
|
|
|
static const char *month_names[] = {
|
|
static const char *month_names[] = {
|
|
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
|
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
|
@@ -344,15 +291,15 @@ struct socket {
|
|
};
|
|
};
|
|
|
|
|
|
struct mg_context {
|
|
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
|
|
const struct mg_config *config; // Mongoose configuration
|
|
|
|
|
|
struct socket *listening_sockets;
|
|
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
|
|
struct socket queue[20]; // Accepted sockets
|
|
int sq_head; // Head of the socket queue
|
|
int sq_head; // Head of the socket queue
|
|
@@ -426,13 +373,6 @@ static void cry(struct mg_connection *conn, const char *fmt, ...) {
|
|
conn->request_info.log_message = NULL;
|
|
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
|
|
// Return fake connection structure. Used for logging, if connection
|
|
// is not applicable at the moment of logging.
|
|
// is not applicable at the moment of logging.
|
|
static struct mg_connection *fc(struct mg_context *ctx) {
|
|
static struct mg_connection *fc(struct mg_context *ctx) {
|
|
@@ -1180,9 +1120,12 @@ static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf,
|
|
/* How many bytes we send in this iteration */
|
|
/* How many bytes we send in this iteration */
|
|
k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent);
|
|
k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent);
|
|
|
|
|
|
|
|
+#if !defined(NO_SSL)
|
|
if (ssl != NULL) {
|
|
if (ssl != NULL) {
|
|
n = SSL_write(ssl, buf + sent, k);
|
|
n = SSL_write(ssl, buf + sent, k);
|
|
- } else if (fp != NULL) {
|
|
|
|
|
|
+ } else
|
|
|
|
+#endif // !NO_SSL
|
|
|
|
+ if (fp != NULL) {
|
|
n = fwrite(buf + sent, 1, k, fp);
|
|
n = fwrite(buf + sent, 1, k, fp);
|
|
if (ferror(fp))
|
|
if (ferror(fp))
|
|
n = -1;
|
|
n = -1;
|
|
@@ -1204,9 +1147,12 @@ 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) {
|
|
static int pull(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int len) {
|
|
int nread;
|
|
int nread;
|
|
|
|
|
|
|
|
+#if !defined(NO_SSL)
|
|
if (ssl != NULL) {
|
|
if (ssl != NULL) {
|
|
nread = SSL_read(ssl, buf, len);
|
|
nread = SSL_read(ssl, buf, len);
|
|
- } else if (fp != NULL) {
|
|
|
|
|
|
+ } else
|
|
|
|
+#endif // !NO_SSL
|
|
|
|
+ if (fp != NULL) {
|
|
nread = fread(buf, 1, (size_t) len, fp);
|
|
nread = fread(buf, 1, (size_t) len, fp);
|
|
if (ferror(fp))
|
|
if (ferror(fp))
|
|
nread = -1;
|
|
nread = -1;
|
|
@@ -3299,68 +3245,33 @@ static unsigned long ssl_id_callback(void) {
|
|
return (unsigned long) pthread_self();
|
|
return (unsigned long) pthread_self();
|
|
}
|
|
}
|
|
|
|
|
|
-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;
|
|
|
|
|
|
+// 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);
|
|
}
|
|
}
|
|
|
|
|
|
-// Dynamically load SSL library. Set up ctx->ssl_ctx pointer.
|
|
|
|
static enum mg_error_t set_ssl_option(struct mg_context *ctx) {
|
|
static enum mg_error_t set_ssl_option(struct mg_context *ctx) {
|
|
SSL_CTX *CTX;
|
|
SSL_CTX *CTX;
|
|
int i, size;
|
|
int i, size;
|
|
const char *pem = ctx->config->ssl_certificate;
|
|
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
|
|
// Initialize SSL crap
|
|
SSL_library_init();
|
|
SSL_library_init();
|
|
SSL_load_error_strings();
|
|
SSL_load_error_strings();
|
|
|
|
|
|
if ((CTX = SSL_CTX_new(SSLv23_server_method())) == NULL) {
|
|
if ((CTX = SSL_CTX_new(SSLv23_server_method())) == NULL) {
|
|
cry(fc(ctx), "SSL_CTX_new error: %s", ssl_error());
|
|
cry(fc(ctx), "SSL_CTX_new error: %s", ssl_error());
|
|
|
|
+ return MG_ERROR;
|
|
} else if (ctx->config->ssl_password_handler != NULL) {
|
|
} else if (ctx->config->ssl_password_handler != NULL) {
|
|
SSL_CTX_set_default_passwd_cb(CTX, ctx->config->ssl_password_handler);
|
|
SSL_CTX_set_default_passwd_cb(CTX, ctx->config->ssl_password_handler);
|
|
}
|
|
}
|
|
|
|
|
|
- if (CTX != NULL && SSL_CTX_use_certificate_file(CTX, pem,
|
|
|
|
- SSL_FILETYPE_PEM) == 0) {
|
|
|
|
|
|
+ if (SSL_CTX_use_certificate_file(CTX, pem, SSL_FILETYPE_PEM) == 0) {
|
|
cry(fc(ctx), "%s: cannot open %s: %s", __func__, pem, ssl_error());
|
|
cry(fc(ctx), "%s: cannot open %s: %s", __func__, pem, ssl_error());
|
|
return MG_ERROR;
|
|
return MG_ERROR;
|
|
- } else if (CTX != NULL && SSL_CTX_use_PrivateKey_file(CTX, pem,
|
|
|
|
- SSL_FILETYPE_PEM) == 0) {
|
|
|
|
|
|
+ } else if (SSL_CTX_use_PrivateKey_file(CTX, pem, SSL_FILETYPE_PEM) == 0) {
|
|
cry(fc(ctx), "%s: cannot open %s: %s", NULL, pem, ssl_error());
|
|
cry(fc(ctx), "%s: cannot open %s: %s", NULL, pem, ssl_error());
|
|
return MG_ERROR;
|
|
return MG_ERROR;
|
|
}
|
|
}
|
|
@@ -3448,10 +3359,12 @@ static void close_socket_gracefully(SOCKET sock) {
|
|
}
|
|
}
|
|
|
|
|
|
static void close_connection(struct mg_connection *conn) {
|
|
static void close_connection(struct mg_connection *conn) {
|
|
|
|
+#if !defined(NO_SSL)
|
|
if (conn->ssl) {
|
|
if (conn->ssl) {
|
|
SSL_free(conn->ssl);
|
|
SSL_free(conn->ssl);
|
|
conn->ssl = NULL;
|
|
conn->ssl = NULL;
|
|
}
|
|
}
|
|
|
|
+#endif // !NO_SSL
|
|
|
|
|
|
if (conn->client.sock != INVALID_SOCKET) {
|
|
if (conn->client.sock != INVALID_SOCKET) {
|
|
close_socket_gracefully(conn->client.sock);
|
|
close_socket_gracefully(conn->client.sock);
|
|
@@ -3567,6 +3480,7 @@ static void worker_thread(struct mg_context *ctx) {
|
|
conn->request_info.remote_ip = ntohl(conn->request_info.remote_ip);
|
|
conn->request_info.remote_ip = ntohl(conn->request_info.remote_ip);
|
|
conn->request_info.is_ssl = conn->client.is_ssl;
|
|
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) {
|
|
if (conn->client.is_ssl && (conn->ssl = SSL_new(ctx->ssl_ctx)) == NULL) {
|
|
cry(conn, "%s: SSL_new: %s", __func__, ssl_error());
|
|
cry(conn, "%s: SSL_new: %s", __func__, ssl_error());
|
|
} else if (conn->client.is_ssl &&
|
|
} else if (conn->client.is_ssl &&
|
|
@@ -3574,7 +3488,9 @@ static void worker_thread(struct mg_context *ctx) {
|
|
cry(conn, "%s: SSL_set_fd: %s", __func__, ssl_error());
|
|
cry(conn, "%s: SSL_set_fd: %s", __func__, ssl_error());
|
|
} else if (conn->client.is_ssl && SSL_accept(conn->ssl) != 1) {
|
|
} else if (conn->client.is_ssl && SSL_accept(conn->ssl) != 1) {
|
|
cry(conn, "%s: SSL handshake error: %s", __func__, ssl_error());
|
|
cry(conn, "%s: SSL handshake error: %s", __func__, ssl_error());
|
|
- } else {
|
|
|
|
|
|
+ } else
|
|
|
|
+#endif // !NO_SSL
|
|
|
|
+ {
|
|
process_new_connection(conn);
|
|
process_new_connection(conn);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -3682,10 +3598,12 @@ static void master_thread(struct mg_context *ctx) {
|
|
}
|
|
}
|
|
(void) pthread_mutex_unlock(&ctx->mutex);
|
|
(void) pthread_mutex_unlock(&ctx->mutex);
|
|
|
|
|
|
|
|
+#if !defined(NO_SSL)
|
|
// Deallocate SSL context
|
|
// Deallocate SSL context
|
|
if (ctx->ssl_ctx != NULL) {
|
|
if (ctx->ssl_ctx != NULL) {
|
|
SSL_CTX_free(ctx->ssl_ctx);
|
|
SSL_CTX_free(ctx->ssl_ctx);
|
|
}
|
|
}
|
|
|
|
+#endif // !NO_SSL
|
|
|
|
|
|
// All threads exited, no sync is needed. Destroy mutex and condvars
|
|
// All threads exited, no sync is needed. Destroy mutex and condvars
|
|
(void) pthread_mutex_destroy(&ctx->mutex);
|
|
(void) pthread_mutex_destroy(&ctx->mutex);
|
|
@@ -3743,9 +3661,11 @@ struct mg_context * mg_start(const struct mg_config *config) {
|
|
|
|
|
|
// NOTE(lsm): order is important here. SSL certificates must
|
|
// NOTE(lsm): order is important here. SSL certificates must
|
|
// be initialized before listening ports. UID must be set last.
|
|
// be initialized before listening ports. UID must be set last.
|
|
- if (set_ssl_option(ctx) == MG_ERROR ||
|
|
|
|
|
|
+ if (set_gpass_option(ctx) == MG_ERROR ||
|
|
|
|
+#if !defined(NO_SSL)
|
|
|
|
+ (config->ssl_certificate != NULL && set_ssl_option(ctx) == MG_ERROR) ||
|
|
|
|
+#endif // !NO_SSL
|
|
set_ports_option(ctx) == MG_ERROR ||
|
|
set_ports_option(ctx) == MG_ERROR ||
|
|
- set_gpass_option(ctx) == MG_ERROR ||
|
|
|
|
#if !defined(_WIN32)
|
|
#if !defined(_WIN32)
|
|
set_uid_option(ctx) == MG_ERROR ||
|
|
set_uid_option(ctx) == MG_ERROR ||
|
|
#endif
|
|
#endif
|