X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=server%2Ffastcgi.c;h=a77a3a454109bf6c03abed9a982f533d2e537e9f;hb=e3e7914fe2f59765e5f92371329652a02518928c;hp=f6bea43749c6f78294459c748fce4468845d2727;hpb=a304c5e3c9ef6f145b7e30ebc618e03e749cba95;p=matches%2FMCTX3420.git diff --git a/server/fastcgi.c b/server/fastcgi.c index f6bea43..a77a3a4 100644 --- a/server/fastcgi.c +++ b/server/fastcgi.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include "common.h" #include "sensor.h" @@ -33,7 +35,7 @@ */ static void IdentifyHandler(FCGIContext *context, char *params) { bool ident_sensors = false, ident_actuators = false; - + bool has_control = FCGI_HasControl(context, getenv("COOKIE_STRING")); int i; FCGIValue values[2] = {{"sensors", &ident_sensors, FCGI_BOOL_T}, @@ -45,29 +47,29 @@ static void IdentifyHandler(FCGIContext *context, char *params) { FCGI_JSONPair("description", "MCTX3420 Server API (2013)"); FCGI_JSONPair("build_date", __DATE__ " " __TIME__); FCGI_JSONLong("api_version", API_VERSION); - FCGI_JSONBool("logged_in", FCGI_HasControl(context, getenv("COOKIE_STRING"))); - FCGI_JSONPair("friendly_name", ""); + FCGI_JSONBool("logged_in", has_control); + FCGI_JSONPair("user_name", has_control ? context->user_name : ""); //Sensor and actuator information if (ident_sensors) { FCGI_JSONKey("sensors"); FCGI_JSONValue("{\n\t\t"); - for (i = 0; i < NUMSENSORS; i++) { + for (i = 0; i < g_num_sensors; i++) { if (i > 0) { FCGI_JSONValue(",\n\t\t"); } - FCGI_JSONValue("\"%d\" : \"%s\"", i, g_sensor_names[i]); + FCGI_JSONValue("\"%d\" : \"%s\"", i, Sensor_GetName(i)); } FCGI_JSONValue("\n\t}"); } if (ident_actuators) { FCGI_JSONKey("actuators"); FCGI_JSONValue("{\n\t\t"); - for (i = 0; i < NUMACTUATORS; i++) { + for (i = 0; i < g_num_actuators; i++) { if (i > 0) { FCGI_JSONValue(",\n\t\t"); } - FCGI_JSONValue("\"%d\" : \"%s\"", i, g_actuator_names[i]); + FCGI_JSONValue("\"%d\" : \"%s\"", i, Actuator_GetName(i)); } FCGI_JSONValue("\n\t}"); } @@ -75,34 +77,61 @@ static void IdentifyHandler(FCGIContext *context, char *params) { } /** - * Gives the user a key that determines who has control over - * the system at any one time. The key can be forcibly generated, revoking - * any previous control keys. To be used in conjunction with HTTP - * basic authentication. - * This function will generate a JSON response that indicates success/failure. + * Given an authorised user, attempt to set the control over the system. + * Modifies members in the context structure appropriately if successful. * @param context The context to work in - * @param force Whether to force key generation or not. - */ -void FCGI_LockControl(FCGIContext *context, bool force) { + * @param user_name - Name of the user + * @param user_type - Type of the user, passed after successful authentication + * @return true on success, false otherwise (eg someone else already in control) + */ +bool FCGI_LockControl(FCGIContext *context, const char * user_name, UserType user_type) +{ + // Get current time time_t now = time(NULL); bool expired = now - context->control_timestamp > CONTROL_TIMEOUT; - - if (force || !*(context->control_key) || expired) + + // Can't lock control if: User not actually logged in (sanity), or key is still valid and the user is not an admin + if (user_type == USER_UNAUTH || + (user_type != USER_ADMIN && !expired && *(context->control_key) != '\0')) + return false; + + // Release any existing control (if any) + FCGI_ReleaseControl(context); + + // Set timestamp + context->control_timestamp = now; + + // Generate a SHA1 hash for the user + SHA_CTX sha1ctx; + unsigned char sha1[20]; + int i = rand(); + SHA1_Init(&sha1ctx); + SHA1_Update(&sha1ctx, &now, sizeof(now)); + SHA1_Update(&sha1ctx, &i, sizeof(i)); + SHA1_Final(sha1, &sha1ctx); + for (i = 0; i < sizeof(sha1); i++) + sprintf(context->control_key + i * 2, "%02x", sha1[i]); + + // Set the IP address + snprintf(context->control_ip, 16, "%s", getenv("REMOTE_ADDR")); + // Set the user name + int uname_len = strlen(user_name); + if (snprintf(context->user_name, sizeof(context->user_name), "%s", user_name) < uname_len) + { + Log(LOGERR, "Username at %d characters too long (limit %d)", uname_len, sizeof(context->user_name)); + return false; // :-( + } + // Set the user type + context->user_type = user_type; + // Create directory + if (mkdir(user_name, 0777) != 0 && errno != EEXIST) { - SHA_CTX sha1ctx; - unsigned char sha1[20]; - int i = rand(); - - SHA1_Init(&sha1ctx); - SHA1_Update(&sha1ctx, &now, sizeof(now)); - SHA1_Update(&sha1ctx, &i, sizeof(i)); - SHA1_Final(sha1, &sha1ctx); - - context->control_timestamp = now; - for (i = 0; i < 20; i++) - sprintf(context->control_key + i * 2, "%02x", sha1[i]); - snprintf(context->control_ip, 16, "%s", getenv("REMOTE_ADDR")); + Log(LOGERR, "Couldn't create user directory %s/%s - %s", g_options.root_dir, user_name, strerror(errno)); + return false; // :-( } + + + return true; // :-) } /** @@ -131,8 +160,7 @@ bool FCGI_HasControl(FCGIContext *context, const char *key) { */ void FCGI_ReleaseControl(FCGIContext *context) { *(context->control_key) = 0; - FCGI_BeginJSON(context, STATUS_OK); - FCGI_EndJSON(); + // Note: context->user_name should *not* be cleared return; } @@ -384,7 +412,7 @@ void FCGI_RejectJSONEx(FCGIContext *context, StatusCodes status, const char *des FCGI_BeginJSON(context, status); FCGI_JSONPair("description", description); FCGI_JSONLong("responsenumber", context->response_number); - //FCGI_JSONPair("params", getenv("QUERY_STRING")); + //FCGI_JSONPair("params", getenv("QUERY_STRING")); //A bad idea if contains password but also if contains unescaped stuff FCGI_JSONPair("host", getenv("SERVER_HOSTNAME")); FCGI_JSONPair("user", getenv("REMOTE_USER")); FCGI_JSONPair("ip", getenv("REMOTE_ADDR")); @@ -480,9 +508,6 @@ void * FCGI_RequestLoop (void *data) if (lastchar > 0 && module[lastchar] == '/') module[lastchar] = 0; - //Escape all special characters - FCGI_EscapeText(params); - //Default to the 'identify' module if none specified if (!*module) strcpy(module, "identify"); @@ -510,18 +535,18 @@ void * FCGI_RequestLoop (void *data) if (module_handler) { - if (module_handler != Login_Handler && module_handler != IdentifyHandler) + if (module_handler != Login_Handler && module_handler != IdentifyHandler && module_handler) + //if (false) // Testing { - if (cookie[0] == '\0') - { - FCGI_RejectJSON(&context, "Please login."); - continue; - } if (!FCGI_HasControl(&context, cookie)) { - FCGI_RejectJSON(&context, "Invalid control key."); + FCGI_RejectJSON(&context, "Please login. Invalid control key."); continue; } + + //Escape all special characters. + //Don't escape for login (password may have special chars?) + FCGI_EscapeText(params); } module_handler(&context, params); @@ -530,9 +555,6 @@ void * FCGI_RequestLoop (void *data) { FCGI_RejectJSON(&context, "Unhandled module"); } - - - } Log(LOGDEBUG, "Thread exiting.");