Commence work on authentication
authorSam Moore <[email protected]>
Mon, 30 Sep 2013 07:34:42 +0000 (07:34 +0000)
committerSam Moore <[email protected]>
Mon, 30 Sep 2013 07:34:42 +0000 (07:34 +0000)
server/Makefile
server/fastcgi.c
server/fastcgi.h
server/login.c [new file with mode: 0644]
server/login.h [new file with mode: 0644]

index 929b40d..a87fdcd 100644 (file)
@@ -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
index 352efe1..0252f78 100644 (file)
 #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++;
+               
 
                
        }
index 8678a77..74468ae 100644 (file)
@@ -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 (file)
index 0000000..615be9e
--- /dev/null
@@ -0,0 +1,161 @@
+/**
+ * @file login.c
+ * @brief Implementation of Login related functionality
+ */
+
+#define _BSD_SOURCE
+
+#include "login.h"
+#include <ctype.h>
+
+#define LDAP_DEPRECATED 1 // Required to use ldap_simple_bind_s
+#include <ldap.h>
+
+#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 <ldap.h>, 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 (file)
index 0000000..8390fb5
--- /dev/null
@@ -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

UCC git Repository :: git.ucc.asn.au