From be4e13604e52cdc7986b726124d007a664f534b7 Mon Sep 17 00:00:00 2001 From: Sam Moore Date: Mon, 30 Sep 2013 07:34:42 +0000 Subject: [PATCH] Commence work on authentication --- server/Makefile | 4 +- server/fastcgi.c | 50 +++++++-------- server/fastcgi.h | 14 ++++- server/login.c | 161 +++++++++++++++++++++++++++++++++++++++++++++++ server/login.h | 16 +++++ 5 files changed, 214 insertions(+), 31 deletions(-) create mode 100644 server/login.c create mode 100644 server/login.h diff --git a/server/Makefile b/server/Makefile index 929b40d..a87fdcd 100644 --- a/server/Makefile +++ b/server/Makefile @@ -1,8 +1,8 @@ # Makefile for server software CXX = gcc FLAGS = -std=c99 -Wall -pedantic -g -I/usr/include/opencv -I/usr/include/opencv2/highgui -L/usr/lib -LIB = -lfcgi -lssl -lcrypto -lpthread -lm -lopencv_highgui -lopencv_core -lopencv_ml -lopencv_imgproc -OBJ = log.o control.o data.o fastcgi.o main.o sensor.o actuator.o image.o bbb_pin.o bbb_pin_defines.o pin_test.o +LIB = -lfcgi -lssl -lcrypto -lpthread -lm -lopencv_highgui -lopencv_core -lopencv_ml -lopencv_imgproc -lldap +OBJ = log.o control.o data.o fastcgi.o main.o sensor.o actuator.o image.o bbb_pin.o bbb_pin_defines.o pin_test.o login.o RM = rm -f BIN = server diff --git a/server/fastcgi.c b/server/fastcgi.c index 352efe1..0252f78 100644 --- a/server/fastcgi.c +++ b/server/fastcgi.c @@ -17,21 +17,12 @@ #include "options.h" #include "image.h" #include "pin_test.h" +#include "login.h" /**The time period (in seconds) before the control key expires */ #define CONTROL_TIMEOUT 180 -/**Contextual information related to FCGI requests*/ -struct FCGIContext { - /**The time of last valid user access possessing the control key*/ - time_t control_timestamp; - char control_key[41]; - char control_ip[16]; - /**The name of the current module**/ - const char *current_module; - /**For debugging purposes?**/ - int response_number; -}; + /** * Identifies build information and the current API version to the user. @@ -94,7 +85,8 @@ void FCGI_LockControl(FCGIContext *context, bool force) { time_t now = time(NULL); bool expired = now - context->control_timestamp > CONTROL_TIMEOUT; - if (force || !*(context->control_key) || expired) { + if (force || !*(context->control_key) || expired) + { SHA_CTX sha1ctx; unsigned char sha1[20]; int i = rand(); @@ -108,18 +100,6 @@ void FCGI_LockControl(FCGIContext *context, bool force) { for (i = 0; i < 20; i++) sprintf(context->control_key + i * 2, "%02x", sha1[i]); snprintf(context->control_ip, 16, "%s", getenv("REMOTE_ADDR")); - FCGI_BeginJSON(context, STATUS_OK); - FCGI_JSONPair("key", context->control_key); - FCGI_EndJSON(); - } else { - char buf[128]; - strftime(buf, 128, "%H:%M:%S %d-%m-%Y", - localtime(&(context->control_timestamp))); - FCGI_BeginJSON(context, STATUS_UNAUTHORIZED); - FCGI_JSONPair("description", "Another user already has control"); - FCGI_JSONPair("current_user", context->control_ip); - FCGI_JSONPair("when", buf); - FCGI_EndJSON(); } } @@ -461,13 +441,16 @@ void * FCGI_RequestLoop (void *data) while (FCGI_Accept() >= 0) { ModuleHandler module_handler = NULL; - char module[BUFSIZ], params[BUFSIZ]; + char module[BUFSIZ], params[BUFSIZ], hack[BUFSIZ]; //strncpy doesn't zero-truncate properly snprintf(module, BUFSIZ, "%s", getenv("DOCUMENT_URI_LOCAL")); snprintf(params, BUFSIZ, "%s", getenv("QUERY_STRING")); + snprintf(hack, BUFSIZ, "%s", getenv("QUERY_STRING")); Log(LOGDEBUG, "Got request #%d - Module %s, params %s", context.response_number, module, params); + + //Remove trailing slashes (if present) from module query size_t lastchar = strlen(module) - 1; @@ -493,15 +476,26 @@ void * FCGI_RequestLoop (void *data) module_handler = Image_Handler; } else if (!strcmp("pin", module)) { module_handler = Pin_Handler; // *Debug only* pin test module + } else if (!strcmp("bind", module)) { + module_handler = Login_Handler; + } else if (!strcmp("unbind", module)) { + module_handler = Logout_Handler; } context.current_module = module; - if (module_handler) { + context.response_number++; + + + + if (module_handler) + { module_handler(&context, params); - } else { + } + else + { FCGI_RejectJSON(&context, "Unhandled module"); } - context.response_number++; + } diff --git a/server/fastcgi.h b/server/fastcgi.h index 8678a77..74468ae 100644 --- a/server/fastcgi.h +++ b/server/fastcgi.h @@ -39,7 +39,19 @@ typedef struct FCGIValue { unsigned flags; } FCGIValue; -typedef struct FCGIContext FCGIContext; +/**Contextual information related to FCGI requests*/ +typedef struct +{ + /**The time of last valid user access possessing the control key*/ + time_t control_timestamp; + char control_key[41]; + char control_ip[16]; + /**The name of the current module**/ + const char *current_module; + /**For debugging purposes?**/ + int response_number; +} FCGIContext; + typedef void (*ModuleHandler) (FCGIContext *context, char *params); extern void FCGI_LockControl(FCGIContext *context, bool force); diff --git a/server/login.c b/server/login.c new file mode 100644 index 0000000..615be9e --- /dev/null +++ b/server/login.c @@ -0,0 +1,161 @@ +/** + * @file login.c + * @brief Implementation of Login related functionality + */ + +#define _BSD_SOURCE + +#include "login.h" +#include + +#define LDAP_DEPRECATED 1 // Required to use ldap_simple_bind_s +#include + +#define LDAP_URI "ldaps://ldap.pheme.uwa.edu.au" +#define LDAP_DN_BASE "ou=Users,ou=UWA,dc=uwads,dc=uwa,dc=edu,dc=au" + +/** + * Attempt to bind to the LDAP_URI + * @param user - The username + * @param pass - The password + * @returns An error code according to libldap; LDAP_SUCCESS if everything worked + */ +int Login_LDAP_Bind(const char * user, const char * pass) +{ + + + Log(LOGINFO, "Username: \"%s\"", user); + + char dn[BUFSIZ]; // Fill with the DN + + const char * user_type = "Students"; + + // Staff members have numbers starting in zero + if (user[0] == '0') + { + user_type = "Staff"; + } + + if (sprintf(dn, "cn=%s,ou=%s,%s", user, user_type, LDAP_DN_BASE) >= BUFSIZ) + { + Log(LOGERR,"DN too long; recompile with increased BUFSIZ"); + } + + // Initialise LDAP; prepares to connect to the server + LDAP * ld = NULL; + int err = ldap_initialize(&ld, LDAP_URI); + if (err != LDAP_SUCCESS || ld == NULL) + { + Log(LOGERR,"ldap_initialize failed - %s (ld = %p)", ldap_err2string(err), ld); + return err; + } + + // Set the LDAP version... + int version = LDAP_VERSION3; + err = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version); // specify the version + if (err != LDAP_SUCCESS) + { + Log(LOGERR,"ldap_set_option failed - %s", ldap_err2string(err)); + return err; + } + + // Attempt to bind using the supplied credentials. + // NOTE: ldap_simple_bind_s is "deprecated" in , but not listed as such in the man pages :S + err = ldap_simple_bind_s(ld, dn, pass); + if (err != LDAP_SUCCESS) + { + Log(LOGERR, "ldap_simple_bind_s failed - %s", ldap_err2string(err)); + } + else + { + Log(LOGDEBUG, "Successfully bound to %s with username %s", LDAP_URI, user); + } + + err = ldap_unbind_s(ld); + if (err != LDAP_SUCCESS) + { + Log(LOGERR, "ldap_unbind_s failed - %s", ldap_err2string(err)); + } + return err; +} + +/** + * Logout + * @param context - The context. The key will be cleared. + * @param params - Parameter string, UNUSED + */ +void Logout_Handler(FCGIContext * context, char * params) +{ + FCGI_ReleaseControl(context); +} + + +/** + * Handle a Login Request + * @param context - The context + * @param params - Parameter string, should contain username and password + */ +void Login_Handler(FCGIContext * context, char * params) +{ + + if (context->control_key[0] != '\0') + { + FCGI_RejectJSON(context, "Already logged in"); + return; + } + + char * user = ""; // The username supplied through CGI + char * pass = ""; // The password supplied through CGI + //TODO: Make sure these are passed through HTTPS, *not* HTTP .... otherwise people can eavesdrop on the passwords + + FCGIValue values[] = { + {"user", &user, FCGI_REQUIRED(FCGI_STRING_T)}, + {"pass", &pass, FCGI_REQUIRED(FCGI_STRING_T)}, + }; + + //enum to avoid the use of magic numbers + typedef enum { + USER, + PASS, + LOGOUT + } LoginParams; + + // Fill values appropriately + if (!FCGI_ParseRequest(context, params, values, sizeof(values)/sizeof(FCGIValue))) + { + // Error occured; FCGI_RejectJSON already called + return; + } + + + // Trim leading whitespace (the BUFSIZ check is to make sure incorrectly terminated strings don't cause an infinite loop) + int i = 0; + for (i = 0; i < BUFSIZ && isspace(user[0]) && user[0] != '\0'; ++i,++user); + + // Truncate string at first non alphanumeric character + for (i = 0; i < BUFSIZ && isalnum(user[i]) && user[i] != '\0'; ++i); + user[i] = '\0'; + + if (strlen(pass) <= 0) + { + FCGI_RejectJSON(context, "No password supplied."); + return; + } + + // Try to authenticate + int err = Login_LDAP_Bind(user, pass); + + // error check + + if (err == LDAP_SUCCESS) + { + FCGI_LockControl(context, false); + } + + + FCGI_BeginJSON(context, STATUS_OK); + FCGI_JSONPair("user", user); + FCGI_JSONPair("login", ldap_err2string(err)); + FCGI_JSONPair("key", context->control_key); + FCGI_EndJSON(); +} diff --git a/server/login.h b/server/login.h new file mode 100644 index 0000000..8390fb5 --- /dev/null +++ b/server/login.h @@ -0,0 +1,16 @@ +/** + * @file login.h + * @brief Declarations of Login related functions + */ + +#ifndef _LOGIN_H +#define _LOGIN_H + +#include "common.h" + +extern void Login_Handler(FCGIContext * context, char * params); // Handle a login request +extern void Logout_Handler(FCGIContext * context, char * params); // Handle a logout request + +#endif //_LOGIN_H + +//EOF -- 2.20.1