From f4907bc0c23c6c8c389dde3125af89f7b9f163a9 Mon Sep 17 00:00:00 2001 From: valenok <devnull@localhost> Date: Mon, 23 Aug 2010 21:36:35 +0100 Subject: [PATCH] introdused NO_SSL. Explicitely linking against SSL library. --- Makefile | 14 ++-- mongoose.c | 188 +++++++++++++++-------------------------------------- 2 files changed, 62 insertions(+), 140 deletions(-) diff --git a/Makefile b/Makefile index 7e267fb97..793c13104 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,8 @@ all: CFLAGS= -W -Wall -std=c99 -pedantic -Os -fomit-frame-pointer $(COPT) MAC_SHARED= -flat_namespace -bundle -undefined suppress -LINFLAGS= -ldl -pthread $(CFLAGS) +SSLFLAGS= -lssl -lcrypto +LINFLAGS= -ldl -pthread $(SSLFLAGS) $(CFLAGS) LIB= _$(PROG).so linux: @@ -32,16 +33,17 @@ linux: bsd: $(CC) $(CFLAGS) mongoose.c -shared -pthread -s -fpic -fPIC -o $(LIB) - $(CC) $(CFLAGS) mongoose.c main.c -pthread -s -o $(PROG) + $(CC) $(CFLAGS) mongoose.c main.c -pthread -s $(SSLFLAGS) -o $(PROG) mac: - $(CC) $(CFLAGS) $(MAC_SHARED) mongoose.c -pthread -o $(LIB) - $(CC) $(CFLAGS) mongoose.c main.c -pthread -o $(PROG) + $(CC) $(CFLAGS) $(MAC_SHARED) mongoose.c -pthread $(SSLFLAGS) -o $(LIB) + $(CC) $(CFLAGS) mongoose.c main.c -pthread $(SSLFLAGS) -o $(PROG) solaris: gcc $(CFLAGS) mongoose.c -pthread -lnsl \ - -lsocket -s -fpic -fPIC -shared -o $(LIB) - gcc $(CFLAGS) mongoose.c main.c -pthread -lnsl -lsocket -s -o $(PROG) + -lsocket $(SSLFLAGS) -s -fpic -fPIC -shared -o $(LIB) + gcc $(CFLAGS) mongoose.c main.c -pthread -lnsl -lsocket $(SSLFLAGS) \ + -s -o $(PROG) ########################################################################## diff --git a/mongoose.c b/mongoose.c index 66c8b21b0..0fa326f2c 100644 --- a/mongoose.c +++ b/mongoose.c @@ -90,8 +90,6 @@ 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 @@ -174,8 +172,6 @@ typedef struct DIR { #include <dirent.h> #include <dlfcn.h> #include <pthread.h> -#define SSL_LIB "libssl.so" -#define CRYPTO_LIB "libcrypto.so" #define DIRSEP '/' #define IS_DIRSEP_CHAR(c) ((c) == '/') #define O_BINARY 0 @@ -234,76 +230,27 @@ typedef struct ssl_ctx_st SSL_CTX; #define SSL_FILETYPE_PEM 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[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", @@ -344,15 +291,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 @@ -426,13 +373,6 @@ 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) { @@ -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 */ 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 if (fp != NULL) { + } else +#endif // !NO_SSL + if (fp != NULL) { n = fwrite(buf + sent, 1, k, fp); if (ferror(fp)) 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) { int nread; +#if !defined(NO_SSL) if (ssl != NULL) { 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); if (ferror(fp)) nread = -1; @@ -3299,68 +3245,33 @@ static unsigned long ssl_id_callback(void) { 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) { 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 (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()); 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()); return MG_ERROR; } @@ -3448,10 +3359,12 @@ 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); @@ -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.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 && @@ -3574,7 +3488,9 @@ 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 { + } else +#endif // !NO_SSL + { process_new_connection(conn); } @@ -3682,10 +3598,12 @@ 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); @@ -3743,9 +3661,11 @@ 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_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_gpass_option(ctx) == MG_ERROR || #if !defined(_WIN32) set_uid_option(ctx) == MG_ERROR || #endif -- GitLab