From 8c5bba9863ed029b83766d8b4de1195aa38b1f5d Mon Sep 17 00:00:00 2001 From: Jeremy Tan Date: Sun, 20 Oct 2013 22:19:11 +0800 Subject: [PATCH 1/1] Switch to named cookies (mctxkey) --- server/control.c | 2 +- server/fastcgi.c | 77 ++++++++++++++++++++++++++++++++++-------------- server/fastcgi.h | 8 +++-- server/login.c | 6 ++-- 4 files changed, 66 insertions(+), 27 deletions(-) diff --git a/server/control.c b/server/control.c index 6ebaba7..f81ea00 100644 --- a/server/control.c +++ b/server/control.c @@ -197,7 +197,7 @@ void Control_Handler(FCGIContext *context, char *params) { "%s", name); } - FCGI_AcceptJSON(context, "Ok", NULL); + FCGI_AcceptJSON(context, "Ok"); } } diff --git a/server/fastcgi.c b/server/fastcgi.c index 0a6783f..f68bc4f 100644 --- a/server/fastcgi.c +++ b/server/fastcgi.c @@ -33,15 +33,11 @@ * @param context The context to work in * @param params User specified paramters: [actuators, sensors] */ -static void IdentifyHandler(FCGIContext *context, char *params) { +static void IdentifyHandler(FCGIContext *context, char *params) +{ bool ident_sensors = false, ident_actuators = false; - char control_key[CONTROL_KEY_BUFSIZ]; - bool has_control; int i; - snprintf(control_key, CONTROL_KEY_BUFSIZ, "%s", getenv("COOKIE_STRING")); - has_control = FCGI_HasControl(context, control_key); - FCGIValue values[2] = {{"sensors", &ident_sensors, FCGI_BOOL_T}, {"actuators", &ident_actuators, FCGI_BOOL_T}}; if (!FCGI_ParseRequest(context, params, values, 2)) @@ -55,6 +51,8 @@ static void IdentifyHandler(FCGIContext *context, char *params) { clock_getres(CLOCK_MONOTONIC, &t); FCGI_JSONDouble("clock_getres", TIMEVAL_TO_DOUBLE(t)); FCGI_JSONLong("api_version", API_VERSION); + + bool has_control = FCGI_HasControl(context); FCGI_JSONBool("logged_in", has_control); FCGI_JSONPair("user_name", has_control ? context->user_name : ""); @@ -165,11 +163,12 @@ bool FCGI_LockControl(FCGIContext *context, const char * user_name, UserType use * @param key The control key to be validated. * @return TRUE if authorized, FALSE if not. */ -bool FCGI_HasControl(FCGIContext *context, const char *key) { +bool FCGI_HasControl(FCGIContext *context) +{ time_t now = time(NULL); int result = (now - context->control_timestamp) <= CONTROL_TIMEOUT && - key != NULL && context->control_key[0] != '\0' && - !strcmp(context->control_key, key); + context->control_key[0] != '\0' && + !strcmp(context->control_key, context->received_key); if (result) { context->control_timestamp = now; //Update the control_timestamp } @@ -181,12 +180,51 @@ bool FCGI_HasControl(FCGIContext *context, const char *key) { * Revokes the current control key, if present. * @param context The context to work in */ -void FCGI_ReleaseControl(FCGIContext *context) { +void FCGI_ReleaseControl(FCGIContext *context) +{ *(context->control_key) = 0; // Note: context->user_name should *not* be cleared return; } +/** + * Gets the control cookie + * @param buffer A storage buffer of exactly CONTROL_KEY_BUFSIZ length to + store the control key + */ +void FCGI_GetControlCookie(char buffer[CONTROL_KEY_BUFSIZ]) +{ + const char *cookies = getenv("COOKIE_STRING"); + const char *start = strstr(cookies, "mctxkey="); + + if (start != NULL) { + const char *end; + size_t limit = CONTROL_KEY_BUFSIZ; + start += 8; //Ah, magic numbers (the length of mctxkey= - 1) + end = strchr(start, ';'); + if (end != NULL && (end-start) < CONTROL_KEY_BUFSIZ) { + limit = (end-start) + 1; + } + snprintf(buffer, limit, "%s", start); + Log(LOGDEBUG, "buf: %s", buffer); + } else { + *buffer = 0; + } +} + +/** + * Sends the control key to the user as a cookie. + * @param context the context to work in + * @param set Whether to set or unset the control cookie + */ +void FCGI_SendControlCookie(FCGIContext *context, bool set) { + if (set) { + printf("Set-Cookie: mctxkey=%s\r\n", context->control_key); + } else { + printf("Set-Cookie: mctxkey=\r\n"); + } +} + /** * Extracts a key/value pair from a request string. * Note that the input is modified by this function. @@ -347,12 +385,9 @@ void FCGI_BeginJSON(FCGIContext *context, StatusCodes status_code) * @param description A short description. * @param cookie Optional. If given, the cookie field is set to that value. */ -void FCGI_AcceptJSON(FCGIContext *context, const char *description, const char *cookie) +void FCGI_AcceptJSON(FCGIContext *context, const char *description) { printf("Content-type: application/json; charset=utf-8\r\n"); - if (cookie) { - printf("Set-Cookie: %s\r\n", cookie); - } printf("\r\n{\r\n"); printf("\t\"module\" : \"%s\"", context->current_module); FCGI_JSONLong("status", STATUS_OK); @@ -514,17 +549,15 @@ void * FCGI_RequestLoop (void *data) while (FCGI_Accept() >= 0) { ModuleHandler module_handler = NULL; - char module[BUFSIZ], params[BUFSIZ], control_key[CONTROL_KEY_BUFSIZ]; + char module[BUFSIZ], params[BUFSIZ]; //strncpy doesn't zero-truncate properly snprintf(module, BUFSIZ, "%s", getenv("DOCUMENT_URI_LOCAL")); snprintf(params, BUFSIZ, "%s", getenv("QUERY_STRING")); - //Hack to get the nameless cookie only - snprintf(control_key, CONTROL_KEY_BUFSIZ, "%s", getenv("COOKIE_STRING")); - + FCGI_GetControlCookie(context.received_key); Log(LOGDEBUG, "Got request #%d - Module %s, params %s", context.response_number, module, params); - Log(LOGDEBUG, "Control key: %s", control_key); + Log(LOGDEBUG, "Control key: %s", context.received_key); //Remove trailing slashes (if present) from module query @@ -559,10 +592,10 @@ void * FCGI_RequestLoop (void *data) if (module_handler) { - //if (module_handler != Login_Handler && module_handler != IdentifyHandler && module_handler) - if (false) // Testing + if (module_handler != Login_Handler && module_handler != IdentifyHandler && module_handler) + //if (false) // Testing { - if (!FCGI_HasControl(&context, control_key)) + if (!FCGI_HasControl(&context)) { FCGI_RejectJSON(&context, "Please login. Invalid control key."); continue; diff --git a/server/fastcgi.h b/server/fastcgi.h index de02501..5826ece 100644 --- a/server/fastcgi.h +++ b/server/fastcgi.h @@ -50,6 +50,8 @@ typedef struct time_t control_timestamp; /**A SHA-1 hash that is the control key, determining who is logged in**/ char control_key[CONTROL_KEY_BUFSIZ]; + /**The received control key for the current request**/ + char received_key[CONTROL_KEY_BUFSIZ]; /**The IPv4 address of the logged-in user**/ char control_ip[16]; /**Determines if the user is an admin or not**/ @@ -68,11 +70,13 @@ typedef void (*ModuleHandler) (FCGIContext *context, char *params); extern bool FCGI_LockControl(FCGIContext *context, const char * user_name, UserType user_type); extern void FCGI_ReleaseControl(FCGIContext *context); -extern bool FCGI_HasControl(FCGIContext *context, const char *key); +extern bool FCGI_HasControl(FCGIContext *context); +extern void FCGI_GetControlCookie(char buffer[CONTROL_KEY_BUFSIZ]); +extern void FCGI_SendControlCookie(FCGIContext *context, bool set); extern char *FCGI_KeyPair(char *in, const char **key, const char **value); extern bool FCGI_ParseRequest(FCGIContext *context, char *params, FCGIValue values[], size_t count); extern void FCGI_BeginJSON(FCGIContext *context, StatusCodes status_code); -extern void FCGI_AcceptJSON(FCGIContext *context, const char *description, const char *cookie); +extern void FCGI_AcceptJSON(FCGIContext *context, const char *description); extern void FCGI_JSONPair(const char *key, const char *value); extern void FCGI_JSONLong(const char *key, long value); extern void FCGI_JSONDouble(const char *key, double value); diff --git a/server/login.c b/server/login.c index 78e31f9..4d3d7fd 100644 --- a/server/login.c +++ b/server/login.c @@ -170,7 +170,8 @@ int Login_LDAP_Bind(const char * uri, const char * dn, const char * pass) void Logout_Handler(FCGIContext * context, char * params) { FCGI_ReleaseControl(context); - FCGI_AcceptJSON(context, "Logged out", "0"); + FCGI_SendControlCookie(context, false); //Unset the cookie + FCGI_AcceptJSON(context, "Logged out"); } @@ -280,7 +281,8 @@ void Login_Handler(FCGIContext * context, char * params) { FCGI_EscapeText(context->user_name); //Don't break javascript pls // Give the user a cookie - FCGI_AcceptJSON(context, "Logged in", context->control_key); + FCGI_SendControlCookie(context, true); //Send the control key + FCGI_AcceptJSON(context, "Logged in"); Log(LOGDEBUG, "Successful authentication for %s", user); } else -- 2.20.1