From 74f07cbd0ef2a716bd82d46e38c2c1a3381f9456 Mon Sep 17 00:00:00 2001 From: kakwa Date: Wed, 24 Aug 2016 22:13:11 +0200 Subject: [PATCH] big code reorganization: * split the rfc3161 and the http part * add a logger function * add a debugging logger function for the requests * add a specific handler for rfc3161 request --- CMakeLists.txt | 1 + inc/http.h | 1 + inc/rfc3161.h | 40 +++++++++++++- inc/utils.h | 1 + src/cmd/uts-server.c | 1 + src/lib/http.c | 125 +++++++++++++++++++++++++++++++++++++++++++ src/lib/rfc3161.c | 94 +++++++++----------------------- src/lib/utils.c | 19 +++++++ 8 files changed, 212 insertions(+), 70 deletions(-) create mode 100644 inc/http.h create mode 100644 src/lib/http.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 2de104a..4a63424 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ include_directories( add_executable(uts-server src/cmd/uts-server.c src/lib/rfc3161.c + src/lib/http.c src/lib/utils.c src/lib/ini.c ) diff --git a/inc/http.h b/inc/http.h new file mode 100644 index 0000000..d998d73 --- /dev/null +++ b/inc/http.h @@ -0,0 +1 @@ +int http_server_start(); diff --git a/inc/rfc3161.h b/inc/rfc3161.h index d998d73..1ef5af5 100644 --- a/inc/rfc3161.h +++ b/inc/rfc3161.h @@ -1 +1,39 @@ -int http_server_start(); +#include +#include +#include +#include +#include +#include "utils.h" +#include +#include +#include +#include +#include +#include +#include + +/* Name of config entry that defines the OID file. */ +#define ENV_OID_FILE "oid_file" + +static ASN1_OBJECT *txt2obj(const char *oid); +static CONF *load_config_file(const char *configfile); + +/* Reply related functions. */ +static int reply_command(CONF *conf, char *section, char *engine, char *query, + char *passin, char *inkey, const EVP_MD *md, + char *signer, char *chain, const char *policy, + char *in, int token_in, char *out, int token_out, + int text); +static TS_RESP *read_PKCS7(BIO *in_bio); +static TS_RESP *create_response(CONF *conf, const char *section, char *engine, + char *query, char *passin, char *inkey, + const EVP_MD *md, char *signer, char *chain, + const char *policy); +static ASN1_INTEGER *serial_cb(TS_RESP_CTX *ctx, void *data); +static ASN1_INTEGER *next_serial(const char *serialfile); +static int save_ts_serial(const char *serialfile, ASN1_INTEGER *serial); + +#define B_FORMAT_TEXT 0x8000 +#define FORMAT_UNDEF 0 +#define FORMAT_TEXT (1 | B_FORMAT_TEXT) /* Generic text */ +#define FORMAT_ASN1 4 /* ASN.1/DER */ diff --git a/inc/utils.h b/inc/utils.h index 151822e..573af20 100644 --- a/inc/utils.h +++ b/inc/utils.h @@ -1 +1,2 @@ void skeleton_daemon(); +void logger(int priority, char *fmt, ...); diff --git a/src/cmd/uts-server.c b/src/cmd/uts-server.c index d245434..52e38bd 100644 --- a/src/cmd/uts-server.c +++ b/src/cmd/uts-server.c @@ -8,6 +8,7 @@ #include #include "utils.h" #include "rfc3161.h" +#include "http.h" const char *argp_program_version = UTS_VERSION; diff --git a/src/lib/http.c b/src/lib/http.c new file mode 100644 index 0000000..b579314 --- /dev/null +++ b/src/lib/http.c @@ -0,0 +1,125 @@ +/* + * "This product includes software developed by the OpenSSL Project + * * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "utils.h" +#include + +void log_request_debug(const struct mg_request_info *request_info, + int request_id) { + for (int i = 0; i < request_info->num_headers; i++) { + logger(LOG_DEBUG, "Request[%d], Header[%s]: %s\n", request_id, + request_info->http_headers[i].name, + request_info->http_headers[i].value); + } + logger(LOG_DEBUG, "Request[%d], request_method: %s\n", request_id, + request_info->request_method); + logger(LOG_DEBUG, "Request[%d], request_uri: %s\n", request_id, + request_info->request_uri); + logger(LOG_DEBUG, "Request[%d], local_uri: %s\n", request_id, + request_info->local_uri); + logger(LOG_DEBUG, "Request[%d], http_version: %s\n", request_id, + request_info->http_version); + logger(LOG_DEBUG, "Request[%d], query_string: %s\n", request_id, + request_info->query_string); + logger(LOG_DEBUG, "Request[%d], remote_addr: %s\n", request_id, + request_info->remote_addr); + logger(LOG_DEBUG, "Request[%d], is_ssl: %d\n", request_id, + request_info->is_ssl); + logger(LOG_DEBUG, "Request[%d], content_length: %d\n", request_id, + request_info->content_length); + logger(LOG_DEBUG, "Request[%d], remote_port: %d\n", request_id, + request_info->remote_port); +} + +// This function will be called by civetweb on every new request. +static int begin_request_handler(struct mg_connection *conn) { + const struct mg_request_info *request_info = mg_get_request_info(conn); + log_request_debug(request_info, 0); + + mg_printf(conn, + "HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain\r\n" + "Content-Length: 46\r\n" // Always set Content-Length + "\r\n" + "uts-server, a simple RFC 3161 timestamp server"); + + // Returning non-zero tells civetweb that our function has replied to + // the client, and civetweb should not send client any more data. + return 1; +} + +int rfc3161_handler(struct mg_connection *conn, void *context) { + /* Handler may access the request info using mg_get_request_info */ + const struct mg_request_info *request_info = mg_get_request_info(conn); + int ret; + log_request_debug(request_info, 42); + + bool is_tsq = 0; + + for (int i = 0; i < request_info->num_headers; i++) { + const char *h_name = request_info->http_headers[i].name; + const char *h_value = request_info->http_headers[i].value; + if (strcmp(h_name, "Content-Type") == 0 && + strcmp(h_value, "application/timestamp-query") == 0) + is_tsq = 1; + } + + char *content = "\0"; + int content_length = 0; + + // Send HTTP reply to the client + if (is_tsq) { + mg_printf(conn, + "HTTP/1.1 200 OK\r\n" + "Content-Type: application/timestamp-reply\r\n" + "Content-Length: %d\r\n" // Always set Content-Length + "\r\n" + "%s", + content_length, content); + } else { + mg_printf(conn, + "HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain\r\n" + "Content-Length: 46\r\n" // Always set Content-Length + "\r\n" + "uts-server, a simple RFC 3161 timestamp server"); + } + + return 1; +} + +int http_server_start() { + struct mg_context *ctx; + struct mg_callbacks callbacks; + + // List of options. Last element must be NULL. + const char *options[] = {"listening_ports", "8080", NULL}; + + // Prepare callbacks structure. We have only one callback, the rest are + // NULL. + memset(&callbacks, 0, sizeof(callbacks)); + callbacks.begin_request = begin_request_handler; + + // Start the web server. + ctx = mg_start(&callbacks, NULL, options); + mg_set_request_handler(ctx, "/", rfc3161_handler, (void *)NULL); + + // Wait until user hits "enter". Server is running in separate thread. + // Navigating to http://localhost:8080 will invoke begin_request_handler(). + getchar(); + + // Stop the server. + mg_stop(ctx); + + return 0; +} diff --git a/src/lib/rfc3161.c b/src/lib/rfc3161.c index 520cc4d..e9d521f 100644 --- a/src/lib/rfc3161.c +++ b/src/lib/rfc3161.c @@ -11,6 +11,9 @@ #include #include #include +#include +#include "utils.h" +#include #include #include #include @@ -25,11 +28,11 @@ static ASN1_OBJECT *txt2obj(const char *oid); static CONF *load_config_file(const char *configfile); /* Reply related functions. */ -static int reply_command(CONF *conf, char *section, char *engine, - char *query, char *passin, char *inkey, - const EVP_MD *md, char *signer, char *chain, - const char *policy, char *in, int token_in, char *out, - int token_out, int text); +static int reply_command(CONF *conf, char *section, char *engine, char *query, + char *passin, char *inkey, const EVP_MD *md, + char *signer, char *chain, const char *policy, + char *in, int token_in, char *out, int token_out, + int text); static TS_RESP *read_PKCS7(BIO *in_bio); static TS_RESP *create_response(CONF *conf, const char *section, char *engine, char *query, char *passin, char *inkey, @@ -66,55 +69,6 @@ static int save_ts_serial(const char *serialfile, ASN1_INTEGER *serial); } */ -// This function will be called by civetweb on every new request. -static int begin_request_handler(struct mg_connection *conn) { - const struct mg_request_info *request_info = mg_get_request_info(conn); - char content[100]; - - // Prepare the message we're going to send - int content_length = snprintf(content, sizeof(content), - "Hello from civetweb! Remote port: %d", - request_info->remote_port); - - // Send HTTP reply to the client - mg_printf(conn, - "HTTP/1.1 200 OK\r\n" - "Content-Type: application/timestamp-reply\r\n" - "Content-Length: %d\r\n" // Always set Content-Length - "\r\n" - "%s", - content_length, content); - - // Returning non-zero tells civetweb that our function has replied to - // the client, and civetweb should not send client any more data. - return 1; -} - -int http_server_start() { - struct mg_context *ctx; - struct mg_callbacks callbacks; - - // List of options. Last element must be NULL. - const char *options[] = {"listening_ports", "8080", NULL}; - - // Prepare callbacks structure. We have only one callback, the rest are - // NULL. - memset(&callbacks, 0, sizeof(callbacks)); - callbacks.begin_request = begin_request_handler; - - // Start the web server. - ctx = mg_start(&callbacks, NULL, options); - - // Wait until user hits "enter". Server is running in separate thread. - // Navigating to http://localhost:8080 will invoke begin_request_handler(). - getchar(); - - // Stop the server. - mg_stop(ctx); - - return 0; -} - /* * Configuration file-related function definitions. */ @@ -136,7 +90,7 @@ static ASN1_OBJECT *txt2obj(const char *oid) { // const char *p; // //// BIO_printf(bio_err, "Using configuration from %s\n", -///configfile); +/// configfile); // p = NCONF_get_string(conf, NULL, ENV_OID_FILE); // if (p != NULL) { // BIO *oid_bio = BIO_new_file(p, "r"); @@ -158,11 +112,11 @@ static ASN1_OBJECT *txt2obj(const char *oid) { * Reply-related method definitions. */ -static int reply_command(CONF *conf, char *section, char *engine, - char *query, char *passin, char *inkey, - const EVP_MD *md, char *signer, char *chain, - const char *policy, char *in, int token_in, char *out, - int token_out, int text) { +static int reply_command(CONF *conf, char *section, char *engine, char *query, + char *passin, char *inkey, const EVP_MD *md, + char *signer, char *chain, const char *policy, + char *in, int token_in, char *out, int token_out, + int text) { int ret = 0; TS_RESP *response = NULL; BIO *in_bio = NULL; @@ -181,22 +135,23 @@ static int reply_command(CONF *conf, char *section, char *engine, response = d2i_TS_RESP_bio(in_bio, NULL); } } else { - response = create_response(conf, section, engine, query, passin, - inkey, md, signer, chain, policy); + response = create_response(conf, section, engine, query, passin, inkey, + md, signer, chain, policy); // if (response) // BIO_printf(bio_err, "Response has been - //generated.\n"); + // generated.\n"); // else // BIO_printf(bio_err, "Response is not - //generated.\n"); + // generated.\n"); } if (response == NULL) goto end; /* Write response. */ if (text) { - // if ((out_bio = bio_open_default(out, 'w', FORMAT_TEXT)) == - //NULL) + // if ((out_bio = bio_open_default(out, 'w', FORMAT_TEXT)) + //== + // NULL) // goto end; if (token_out) { TS_TST_INFO *tst_info = TS_RESP_get_tst_info(response); @@ -207,8 +162,9 @@ static int reply_command(CONF *conf, char *section, char *engine, goto end; } } else { - // if ((out_bio = bio_open_default(out, 'w', FORMAT_ASN1)) == - //NULL) + // if ((out_bio = bio_open_default(out, 'w', FORMAT_ASN1)) + //== + // NULL) // goto end; if (token_out) { PKCS7 *token = TS_RESP_get_token(response); @@ -363,7 +319,7 @@ static ASN1_INTEGER *next_serial(const char *serialfile) { // BIO_printf(bio_err, "Warning: could not open file %s for //" // "reading, using serial number: 1\n", - //serialfile); + // serialfile); if (!ASN1_INTEGER_set(serial, 1)) goto err; } else { diff --git a/src/lib/utils.c b/src/lib/utils.c index 319ecbc..7b3e61d 100644 --- a/src/lib/utils.c +++ b/src/lib/utils.c @@ -6,6 +6,7 @@ #include #include #include "utils.h" +#include void skeleton_daemon() { pid_t pid; @@ -57,3 +58,21 @@ void skeleton_daemon() { /* Open the log file */ openlog("firstdaemon", LOG_PID, LOG_DAEMON); } + +void logger(int priority, char *fmt, ...) { + FILE *stream; + char *out; + size_t len; + stream = open_memstream(&out, &len); + va_list args; + + va_start(args, fmt); + vfprintf(stream, fmt, args); + va_end(args); + + fflush(stream); + fclose(stream); + printf(out); + syslog(priority, out); + free(out); +}