Merge pull request #50 from RowanHeinrich/patch-6
authorSam Moore <[email protected]>
Thu, 3 Oct 2013 05:13:21 +0000 (22:13 -0700)
committerSam Moore <[email protected]>
Thu, 3 Oct 2013 05:13:21 +0000 (22:13 -0700)
Create comments

19 files changed:
irc/log
server-configs/nginx/fastcgi_params
server-configs/nginx/sites-enabled/mctxconfig
server/Makefile
server/bbb_pin.c
server/common.h
server/control.c
server/fastcgi.c
server/fastcgi.h
server/image.c
server/log.h
server/login.c [new file with mode: 0644]
server/login.h [new file with mode: 0644]
server/main.c
server/options.h
server/parameters [new file with mode: 0644]
server/run.sh
testing/cookie-test/readme.txt [new file with mode: 0644]
testing/cookie-test/test.c [new file with mode: 0644]

diff --git a/irc/log b/irc/log
index bd5e1ac..fea098f 100644 (file)
--- a/irc/log
+++ b/irc/log
 23:26 < Rowan> sweet, i shall enjoy this gui :)
 23:41 < sam_moore> See you tomorrow
 23:47 < Rowan> yep
+--- Day changed Mon Sep 30 2013
+03:31 -!- Rowan [[email protected]] has quit [Ping timeout]
+10:57 -!- jtanx [[email protected]] has joined #mctxuwa_softdev
+11:10 -!- Rowan [[email protected]] has joined #mctxuwa_softdev
+11:17 < sam_moore> Hi Rowan, do you have anything we should put in the report?
+11:34 -!- Rowan [[email protected]] has quit [Ping timeout]
+11:58 -!- Rowan [[email protected]] has joined #mctxuwa_softdev
+11:59 < Rowan> ill have the outline of all the pages i wanted on git this afternoon
+12:05 < sam_moore> Ok
+12:42 -!- Rowan [[email protected]] has quit [Connection reset by peer]
+12:44 -!- Rowan [[email protected]] has joined #mctxuwa_softdev
+13:33 < Rowan> so far i have a cover page which links to a login page which links to the index page. but theres no styles for them and no security on the login
+14:09 < Rowan> im not sure the files ive added went into sams git. im pretty sure they all forked over to mine. :S
+14:58 -!- Rowan [[email protected]] has quit [Ping timeout]
+15:20 -!- Rowan [[email protected]] has joined #mctxuwa_softdev
+15:57 -!- Rowan [[email protected]] has quit [Ping timeout]
+16:18 -!- Rowan [[email protected]] has joined #mctxuwa_softdev
+16:18 -!- jtanx [[email protected]] has quit [Ping timeout]
+16:31 -!- Rowan [[email protected]] has quit [EOF From client]
+18:20 -!- jtanx [[email protected]] has joined #mctxuwa_softdev
+18:55 -!- MctxBot [[email protected]] has quit [Ping timeout]
+21:18 -!- Rowan [[email protected]] has joined #mctxuwa_softdev
+21:44 -!- jtanx [[email protected]] has quit ["ChatZilla 0.9.90.1 [Firefox 24.0/20130910160258]"]
+22:06 -!- Rowan [[email protected]] has quit [EOF From client]
+--- Day changed Tue Oct 01 2013
+08:50 -!- jtanx [[email protected]] has joined #mctxuwa_softdev
+09:03 -!- jtanx [[email protected]] has quit ["brb"]
+11:04 -!- jtanx [[email protected]] has joined #mctxuwa_softdev
+13:40 < sam_moore> Another option for the login system (a really terrible option that I don't condone on any real world system, but it might just get us marks)
+13:40 < sam_moore> Is to provide some cgi scripts that wrap around "useradd" "userdel" and "usermod"
+13:40 < sam_moore> And have our "Login" function check /etc/shadow
+13:41 < sam_moore> I emailed UWA IT help desk about Pheme anyway
+13:41 < sam_moore> I wonder what they'll make of it...
+13:51 < jtanx> hehe
+13:52 < sam_moore> The more I think about it, the more I think LDAP is the way you'd do this properly though
+13:52 < sam_moore> It basically is a text file
+13:53 < jtanx> yeah
+13:53 < sam_moore> If you started with a text file, you'd quickly find yourself reinventing the wheel and probably converging with what LDAP already does
+13:53 < jtanx> I guess the real problem is that rolling our own solution is not really feasible in the time left, especially if you want to ensure it's at least ok in terms of security
+13:57 < sam_moore> Yes
+14:08 < sam_moore> For reference: http://www.debuntu.org/how-to-set-up-a-ldap-server-and-its-clients/
+14:09 < sam_moore> And http://mindref.blogspot.com.au/2010/12/openldap-create-user.html
+14:09 < sam_moore> (How to set up our own LDAP server)
+14:11 < jtanx> slapd
+14:12 < jtanx> what a weird choice of a name
+14:12 < sam_moore> Haha
+14:15 < jtanx> oh 
+14:15 < jtanx> if you set up an ldap server
+14:15 < jtanx> http://phpldapadmin.sourceforge.net/wiki/index.php/Main_Page
+14:15 < jtanx> get them to manage the ldap database themselves
+14:15 < jtanx> :P
+14:15 < jtanx> to add or remove users
+14:22 < sam_moore> Yeah, that's kind of how ldap was designed
+14:22 < sam_moore> Technically I can probably modify my UWA "pheme" password from a command line using ldappasswd
+14:22 < sam_moore> Unless they use kerberos
+14:23 < sam_moore> (We don't want to start going into kerberos...)
+14:54 < sam_moore> Welp, I've put an LDAP server on my laptop for testing purposes
+14:54 < sam_moore> With an account "snoopy"
+14:55 < sam_moore> Seems to work... now to test it with our software
+14:55 < sam_moore> Hey, maybe we could just put an LDAP server on the BeagleBone and get a GUI LDAP editor
+14:56 < sam_moore> Oh right, you suggested that at 14:15
+14:56 < sam_moore> I like it though
+14:58 < jtanx> yah not too bad
+14:58 < jtanx> say we had an ldap server on the bbb
+14:59 < jtanx> we could even write the password manager in a different language
+14:59 < jtanx> if we wanted to make one
+14:59 < sam_moore> Yeah, exactly
+14:59 < jtanx> because it only has to interact with the ldap database
+14:59 < sam_moore> We shouldn't do that in the FastCGI program
+14:59 < jtanx> yup
+15:00 < sam_moore> I sent an email about it to everyone, suggesting PHP or python CGI to wrap around LDAP
+15:01 < sam_moore> I wonder when this system is going to start being put together though
+15:02 < sam_moore> We'll end up with a server and no hardware to control
+15:02 < jtanx> Looks like it
+15:02 < sam_moore> Those images Justin sent us look nice
+15:02 < jtanx> Yeah they look quite good
+15:07 < sam_moore> With the FastCGI program
+15:07 < sam_moore> Do you think it's better to pass options through the command line
+15:07 < sam_moore> Or have a bunch of #defines that need to get configured?
+15:08 < sam_moore> eg: To specify the LDAP server
+15:08 < sam_moore> (At the moment it's just a #define)
+15:08 < jtanx> hmm
+15:08 < jtanx> It's probably better to pass as a command line
+15:09 < sam_moore> Ok
+15:09 < jtanx> unless we're absolutely sure that the ldap address is fixed
+15:10 < sam_moore> What we can do is write a bash script that sets a bunch of variables
+15:10 < sam_moore> Then run.sh sources that and passes them all as arguments
+15:10 < jtanx> sounds good
+15:35 < sam_moore> What about things like the path to the GPIO and ADC? I figure they should stay as #defines
+15:35 < sam_moore> Since they probably won't be changing
+15:36 < sam_moore> At least not until the next BeagleBone kernel comes out
+15:36 < jtanx> hehe
+15:36 < jtanx> yeah that should stay as defins
+15:36 < jtanx> if the path does change
+15:36 < jtanx> then that probably warrants a recompile anyway since stuff may have changed with how you access it
+15:36 < sam_moore> Ok, should I put all the defines that you might want to adjust on a recompile in the same place?
+15:37 < sam_moore> common.h?
+15:37 < jtanx> what defines do we have right now
+15:37 < jtanx> that may change
+15:39 < sam_moore> Nothing major, I just want it to be flexible
+15:39 < jtanx> hmm
+15:39 < jtanx> even if you did that
+15:39 < jtanx> if you needed to change the define
+15:39 < jtanx> you'd probably be looking at changing hte code anyway
+15:40 < sam_moore> Sure, but that doesn't mean you can't put the defines in an easy to find place
+15:40 < sam_moore> For example, say someone wants to recompile this for a RPi
+15:40 < jtanx> But for stuff like 'where's the pwm path'
+15:40 < sam_moore> Given the trouble we had with pwm path confusion
+15:41 < jtanx> I'd look in the header relevant to pin control
+15:41 < sam_moore> I think it's helpful to make it easy for someone to see what we're doing
+15:41 < sam_moore> I suppose
+15:42 < jtanx> ok I guess it doesn't matter if it goes in common.h or not
+15:42 < sam_moore> Yeah, but I think I agree with you now :P
+15:42 < jtanx> ( I guess this is what ./configure and configure.h are for :P )
+15:51 < sam_moore> Sigh...
+15:51 < sam_moore> I put in a #warning to generate a warning if you tried to compile the software on something that isn't the BeagleBone
+15:51 < sam_moore> ...
+15:51 < sam_moore> And the use of #warning caused a warning
+15:52 < sam_moore> warning: #warning is a GCC extension [enabled by default]
+16:05 < jtanx> :p
+16:08 < jtanx> because of the -pedantic flag
+21:13 -!- jtanx [[email protected]] has quit ["ChatZilla 0.9.90.1 [Firefox 24.0/20130910160258]"]
+21:23 -!- MctxBot [[email protected]] has joined #mctxuwa_softdev
+--- Day changed Wed Oct 02 2013
+17:34 -!- Rowan [[email protected]] has joined #mctxuwa_softdev
+21:54 -!- Rowan [[email protected]] has quit [Ping timeout]
index 51aa692..b5b9858 100644 (file)
@@ -2,6 +2,7 @@ fastcgi_param   QUERY_STRING            $query_string;
 fastcgi_param  REQUEST_METHOD          $request_method;
 fastcgi_param  CONTENT_TYPE            $content_type;
 fastcgi_param  CONTENT_LENGTH          $content_length;
+fastcgi_param  COOKIE_STRING           $http_cookie;
 
 fastcgi_param  SCRIPT_FILENAME         $request_filename;
 fastcgi_param  SCRIPT_NAME             $fastcgi_script_name;
index 1be361a..97e46b6 100644 (file)
@@ -81,13 +81,13 @@ server {
                }
 
                #Program log
-               location ^~ /api/log {
+               location = /api/log {
                        alias /var/log/mctxserv.log;
                        default_type text/plain;
                }
 
                #Program error log
-               location ^~ /api/errorlog {
+               location = /api/errorlog {
                        alias /var/log/mctxserv-error.log;
                        default_type text/plain;
                }
index 929b40d..244490b 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 -lcrypt
+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 4d1276b..7248c5a 100644 (file)
@@ -272,7 +272,7 @@ bool ADC_Export(int pin)
                return true;
        }
 
-       sprintf(g_buffer, "%s/in_voltage%d_raw", g_options.adc_device_path, pin);
+       sprintf(g_buffer, "%s/in_voltage%d_raw", ADC_DEVICE_PATH, pin);
        g_adc[pin].fd_value = open(g_buffer, O_RDONLY);
        if (g_adc[pin].fd_value <0)
        {
@@ -486,4 +486,4 @@ bool ADC_Read(int id, int *value)
 bool True_Stub(void *arg, ...) { return true; }
 bool ADC_Read_Stub(int *val, ...) { *val = 0; return true; }
 bool GPIO_Read_Stub(bool *val, ...) { *val = false; return true; }
-#endif
\ No newline at end of file
+#endif
index 0092598..d4defd9 100644 (file)
@@ -6,18 +6,24 @@
 #ifndef _COMMON_H
 #define _COMMON_H
 
+/** Defines required to allow various C standard functions to be used **/
 #define _POSIX_C_SOURCE 200809L
 #define _BSD_SOURCE
 #define _XOPEN_SOURCE 600
 
 /** Determine if we're running on the BBB **/
 #ifdef __arm__
-#define _BBB
-#endif
+       #define _BBB
+#else
+       //#warning This software was designed for the BeagleBone Black. Some features may not work.
+#endif //__arm__
 
 /** The current API version **/
 #define API_VERSION 0
 
+
+
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdbool.h>
@@ -39,6 +45,9 @@
 #define TIMEVAL_DIFF(tv1, tv2) ((tv1).tv_sec - (tv2).tv_sec + 1e-6 * ((tv1).tv_usec - (tv2).tv_usec))
 
 
+extern bool PathExists(const char * path);
+
+
 
 
 #endif //_COMMON_H
index 5c8a410..4b4a1e6 100644 (file)
@@ -15,7 +15,8 @@ typedef struct ControlData {
 
 ControlData g_controls = {CONTROL_STOP, PTHREAD_MUTEX_INITIALIZER, {0}};
 
-static bool PathExists(const char *path) {
+bool PathExists(const char *path) 
+{
        FILE *fp = fopen(path, "r");
        if (fp) {
                fclose(fp);
@@ -177,4 +178,4 @@ const char * Control_GetModeName() {
  */
 const struct timeval* Control_GetStartTime() {
        return &g_controls.start_time;
-}
\ No newline at end of file
+}
index 352efe1..08c413b 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,17 @@ void * FCGI_RequestLoop (void *data)
        while (FCGI_Accept() >= 0) {
                
                ModuleHandler module_handler = NULL;
-               char module[BUFSIZ], params[BUFSIZ];
+               char module[BUFSIZ], params[BUFSIZ], cookie[BUFSIZ];
                
                //strncpy doesn't zero-truncate properly
                snprintf(module, BUFSIZ, "%s", getenv("DOCUMENT_URI_LOCAL"));
                snprintf(params, BUFSIZ, "%s", getenv("QUERY_STRING"));
+               snprintf(cookie, BUFSIZ, "%s", getenv("COOKIE_STRING"));
 
                Log(LOGDEBUG, "Got request #%d - Module %s, params %s", context.response_number, module, params);
+               Log(LOGDEBUG, "Cookie: %s", cookie);
+
+
                
                //Remove trailing slashes (if present) from module query
                size_t lastchar = strlen(module) - 1;
@@ -493,15 +477,40 @@ 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) 
+               {
+                       if (module_handler != Login_Handler)
+                       {
+                               if (cookie[0] == '\0')
+                               {
+                                       FCGI_RejectJSON(&context, "Please login.");
+                                       continue;
+                               }
+                               if (!FCGI_HasControl(&context, cookie))
+                               {
+                                       FCGI_RejectJSON(&context, "Invalid control key.");
+                                       continue;       
+                               }
+                       }
+
                        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);
index 263ce07..dafe375 100644 (file)
@@ -16,6 +16,18 @@ void Image_Handler(FCGIContext * context, char * params)
 
        IplImage * frame = cvQueryFrame(capture);
        assert(frame != NULL);
+
+//        CvMat stub;
+ //       CvMat * background = cvGetMat(frame, &stub, 0, 0);
+
+//     CvMat *cv8u = cvCreateMat(frame->width, frame->height, CV_8U);
+//     double min, max;
+//     CvPoint a,b;    
+//     cvMinMaxLoc(background, &min, &max, &a, &b, 0);
+       
+//     double ccscale = 255.0/(max-min);
+//     double ccshift = -min;
+       //cvCvtScale(frame, cv8u, ccscale, ccshift);
        CvMat * jpg = cvEncodeImage(".jpg", frame, p);
 
        // Will this work?
index cc038a0..e4fd17f 100644 (file)
@@ -14,7 +14,7 @@
 #define Abort(...) { LogEx(LOGERR, __func__, __FILE__, __LINE__, __VA_ARGS__); return; }
 #define AbortBool(...) { LogEx(LOGERR, __func__, __FILE__, __LINE__, __VA_ARGS__); return false; }
 
-// An enum to make the severity of log messages human readable in code
+/** An enum to make the severity of log messages human readable in code **/
 enum {LOGERR=0, LOGWARN=1, LOGNOTE=2, LOGINFO=3,LOGDEBUG=4};
 
 extern void LogEx(int level, const char * funct, const char * file, int line,  ...); // General function for printing log messages to stderr
diff --git a/server/login.c b/server/login.c
new file mode 100644 (file)
index 0000000..a616af2
--- /dev/null
@@ -0,0 +1,264 @@
+/**
+ * @file login.c
+ * @brief Implementation of Login related functionality
+ */
+
+
+
+
+#include "login.h"
+#include "options.h"
+#include <ctype.h>
+#include <unistd.h>
+
+#define LDAP_DEPRECATED 1 // Required to use ldap_simple_bind_s
+#include <ldap.h>
+
+/**
+ * Attempt to login using a file formatted like /etc/shadow
+ * This is here for horrible hack purposes
+ * @param user - The username
+ * @param pass - The password
+ * @returns True if the login was successful, false otherwise
+ */
+bool Login_Shadow(const char * user, const char * pass, const char * shadow)
+{
+       if (strlen(user) + strlen(pass) >= BUFSIZ-1)
+       {
+               Log(LOGERR, "User/Password too long!\n");
+               return false;
+       }
+
+       FILE * f = fopen(shadow, "r");
+       if (f == NULL)
+       {
+               Log(LOGERR,"Can't open %s - %s\n", shadow, strerror(errno));
+               return false;
+       }
+
+       char buffer[BUFSIZ];
+       int passwd_index = -1;
+
+       while (fgets(buffer, BUFSIZ, f) != NULL) // NOTE: Restrict username+password strings to BUFSIZ... what could possibly go wrong?
+       {
+
+               Log(LOGDEBUG,"Scanning %d: %s", strlen(buffer), buffer);
+       
+               for (int i = 0; i < BUFSIZ-1; ++i)
+               {
+                       if (buffer[i] == ':')
+                       {
+                               buffer[i] = '\0';
+                               passwd_index = i+1;
+                               break;
+                       }
+               }
+
+               if (strcmp(user,buffer) == 0)
+               {
+                       Log(LOGDEBUG,"User matches! %s\n", buffer);
+                       break;
+               } 
+               passwd_index = -1;
+       }
+
+       if (passwd_index <= 0)
+       {
+               Log(LOGDEBUG,"No user found matching %s\n", user);
+               return false;
+       }
+
+       for (int i = passwd_index; i < BUFSIZ-1; ++i)
+       {
+               if (buffer[i] == ':' || buffer[i] == '\n')
+               {
+                       buffer[i] = '\0';
+                       
+               }
+       }
+       
+       // Determine the salt
+       char salt[BUFSIZ];
+       int s = 0; int count = 0;
+       for (int i = passwd_index; i < BUFSIZ-1; ++i)
+       {
+               salt[s++] = buffer[i];
+               if (salt[s] == '$' && ++count >= 3)
+                       break;
+       }
+
+       Log(LOGDEBUG,"Salted Entry: %s\n", buffer+passwd_index);
+       Log(LOGDEBUG,"Salted Attempt: %s\n", crypt(pass, salt));
+       
+       return (strcmp(crypt(pass, salt), buffer+passwd_index) == 0);
+}
+
+/**
+ * Attempt to bind to a LDAP uri
+ * @param uri - The uri
+ * @param dn - The DN
+ * @param pass - The password
+ * @returns An error code according to libldap; LDAP_SUCCESS if everything worked
+ */
+int Login_LDAP_Bind(const char * uri, const char * dn, const char * pass)
+{
+       Log(LOGDEBUG, "Bind to %s with dn %s and pass %s", uri, dn, pass);
+
+       // Initialise LDAP; prepares to connect to the server
+       LDAP * ld = NULL;
+       int err = ldap_initialize(&ld, 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 dn %s", uri, dn);
+       }
+
+       int err2 = ldap_unbind_s(ld);
+       if (err2 != LDAP_SUCCESS)
+       {
+               Log(LOGERR, "ldap_unbind_s failed - %s", ldap_err2string(err2));
+               err = err2;
+       }
+       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';
+
+
+
+       
+       bool authenticated = true;
+       
+       switch (g_options.auth_method)
+       {
+
+               case AUTH_LDAP:
+               {
+                       if (strlen(pass) <= 0)
+                       {
+                               FCGI_RejectJSON(context, "No password supplied.");
+                               return;
+                       }
+
+                       //TODO: Generate the DN in some sane way
+                       char dn[BUFSIZ];
+               
+                       // On a simple LDAP server:
+                       int len = sprintf(dn, "uid=%s,%s", user, g_options.ldap_base_dn);
+       
+                       // At UWA (hooray)
+                       //char * user_type = (user[0] != '0') : "Students" ? "Staff";
+                       //int len = sprintf(dn, "cn=%s,ou=%s", user, user_type, g_options.ldap_dn_base);
+               
+
+                       if (len >= BUFSIZ)
+                       {
+                               FCGI_RejectJSON(context, "DN too long! Recompile with increased BUFSIZ");
+                       }
+               
+                       authenticated = (Login_LDAP_Bind(g_options.auth_uri, dn, pass) == LDAP_SUCCESS);
+                       break;
+               }
+               case AUTH_SHADOW:
+               {
+                       authenticated = Login_Shadow(user, pass, g_options.auth_uri);
+                       break;
+               }
+               default:
+               {
+                       Log(LOGWARN, "No authentication!");
+                       break;
+               }
+       }
+               
+       // error check  
+       
+       if (!authenticated)
+       {
+               FCGI_RejectJSON(context, "Authentication failure.");
+               return;
+       }
+
+       FCGI_LockControl(context, false);
+       
+       // Give the user a cookie
+       FCGI_PrintRaw("Content-type: text\r\n");
+       FCGI_PrintRaw("Set-Cookie: %s\r\n\r\n", context->control_key);
+       
+}
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
index 2ad9dcc..ecdf068 100644 (file)
@@ -28,15 +28,18 @@ Options g_options; // options passed to program through command line arguments
  */
 void ParseArguments(int argc, char ** argv)
 {
-       // horrible horrible hacks
-       g_options.argc = argc;
-       g_options.argv = argv;
+
 
        g_options.program = argv[0]; // program name
        g_options.verbosity = LOGDEBUG; // default log level
        gettimeofday(&(g_options.start_time), NULL); // Start time
-       g_options.adc_device_path = ADC_DEVICE_PATH;
-       Log(LOGDEBUG, "Called as %s with %d arguments.", g_options.program, argc);
+
+
+       g_options.auth_method = AUTH_NONE;  // Don't use authentication
+       g_options.auth_uri = ""; // 
+       g_options.ldap_base_dn = "";
+       
+
 
        for (int i = 1; i < argc; ++i)
        {
@@ -49,18 +52,48 @@ void ParseArguments(int argc, char ** argv)
                if (strlen(argv[i]) > 2)
                        Fatal("Human readable switches are not supported.");
 
+               char * end = NULL;
                switch (argv[i][1])
                {
-                       case 'a':
-                               g_options.adc_device_path = argv[i+1];
-                               Log(LOGINFO, "ADC Device Path: %s", argv[i+1]);
-                               ++i;
+                       // Set program verbosity
+                       case 'v':
+                               g_options.verbosity = strtol(argv[++i], &end, 10);
+                               break;
+                       // Enable/Disable pin test
+                       case 'p':
+                               g_options.enable_pin = !(strtol(argv[++i], &end, 10));
+                               break;
+                       // LDAP URI
+                       case 'A':
+                               g_options.auth_uri = argv[++i];
+                               break;
+                       // LDAP DN
+                       case 'd':
+                               g_options.ldap_base_dn = argv[++i];
                                break;
                        default:
                                Fatal("Unrecognised switch %s", argv[i]);
                                break;
                }
+
+               if (end != NULL && *end != '\0')
+                       Fatal("argv[%d] -%c requires an integer (got \"%s\" instead)", i-1, argv[i-1][0], argv[i]);
        }       
+
+       Log(LOGDEBUG, "Verbosity: %d", g_options.verbosity);
+       Log(LOGDEBUG, "Pin Module Enabled: %d", g_options.enable_pin);
+       Log(LOGDEBUG, "Auth URI: %s", g_options.auth_uri);
+       Log(LOGDEBUG, "LDAP Base DN: %s", g_options.ldap_base_dn);
+
+       if (g_options.auth_uri[0] != '\0')
+       {
+               //HACK...
+               if (PathExists(g_options.auth_uri))
+                       g_options.auth_method = AUTH_SHADOW;
+               else
+                       g_options.auth_method = AUTH_LDAP;
+       }
+       
 }
 
 /**
index 05f7ddf..839bc4d 100644 (file)
@@ -19,13 +19,19 @@ typedef struct
        /** Time at which program exits **/
        struct timeval end_time;
 
-       /** Path to ADC files **/
-       const char * adc_device_path;
+       /** Whether or not to enable the pin_test module **/
+       bool enable_pin;
+       
+       /** URI for authentication **/
+       const char * auth_uri;
 
-       /*** Horrible horrible hack ***/
-       int argc;
-       /*** Horrible horrible hack ***/
-       char ** argv;
+       /** Base DN for LDAP authentication **/
+       const char * ldap_base_dn;
+
+       /** Authentication method **/
+       enum {AUTH_NONE, AUTH_LDAP, AUTH_SHADOW} auth_method;
+
+       
 
 } Options;
 
diff --git a/server/parameters b/server/parameters
new file mode 100644 (file)
index 0000000..9f33848
--- /dev/null
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+# This script sets the options interpreted by the server at runtime.
+# Enclose any settings that have whitespace with "quotation marks".
+
+
+## DO NOT EDIT THESE OPTIONS
+LOGERR=0
+LOGWARN=1
+LOGNOTE=2
+LOGINFO=3
+LOGDEBUG=4
+
+## OPTIONS PASSED TO SERVER
+
+# Set the verbosity of log messages
+verbosity="$LOGDEBUG"
+
+# Set to 1/0 to enable/disable the pin module (gives direct control over GPIO/ADC/PWM)
+pin_test="0"
+
+# Set to the URI to use authentication
+auth_uri="ldap://192.168.1.1"
+#auth_uri="/etc/shadow"
+
+# Set to the dn of the LDAP server
+ldap_base_dn="ou=People,dc=daedalus"
+
+
+## OPTIONS TO BE PASSED TO SERVER; DO NOT EDIT
+parameters="-v $verbosity -p $pin_test -A $auth_uri -d $ldap_base_dn"
index 4318b39..c2bd504 100755 (executable)
Binary files a/server/run.sh and b/server/run.sh differ
diff --git a/testing/cookie-test/readme.txt b/testing/cookie-test/readme.txt
new file mode 100644 (file)
index 0000000..fb52249
--- /dev/null
@@ -0,0 +1,7 @@
+compile with:
+gcc test.c -lfcgi -o test
+
+Run with:
+spawn-fcgi -p9005 -n ./test
+
+nginx must be configured to pass $http_cookie as an evironment variable named COOKIE
\ No newline at end of file
diff --git a/testing/cookie-test/test.c b/testing/cookie-test/test.c
new file mode 100644 (file)
index 0000000..7f88239
--- /dev/null
@@ -0,0 +1,10 @@
+#include <fcgi_stdio.h>
+#include <stdlib.h>
+int main() {
+       while (FCGI_Accept() >= 0) {
+               printf("Content-type: text\r\n");
+               printf("Set-Cookie: name=value with spaces; and a semicolon\r\n");
+               printf("Set-Cookie: name2=value2\r\n\r\n");
+               printf("Cookie:%s\n", getenv("COOKIE_STRING"));
+       }
+}

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