* @file fastcgi.c
* @purpose Runs the FCGI request loop to handle web interface requests.
*
- * <stdio.h> should not be included, because these functions are handled by
- * fcgi_stdio.h. If included, it must be included after fcgi_stdio.h.
+ * fcgi_stdio.h must be included before all else so the stdio function
+ * redirection works ok.
*/
#include <fcgi_stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-/*
- But the suggestion was: FunctionName, variable_name (local or member),
- Structure, ENUMVALUE, Extern_FunctionName, g_global
-*/
-
-enum {STATUS_OK = 200, STATUS_BADREQUEST = 400,
- STATUS_UNAUTHORIZED = 401};
-
-typedef void (*ModuleHandler) (void *data, char *params);
+#include "fastcgi.h"
+//#include "common.h"
/**
* Extracts a key/value pair from a request string.
return ptr;
}
-void FCGI_BeginJSON(int status_code, const char *module)
+/**
+ * Begins a response to the client in JSON format.
+ * @param status_code The HTTP status code to be returned.
+ * @param module The name of the module that initiated the response.
+ */
+void FCGI_BeginJSON(StatusCodes status_code, const char *module)
{
switch (status_code) {
case STATUS_OK:
printf("\t\"module\" : \"%s\"", module);
}
+/**
+ * Adds a key/value pair to a JSON response. The response must have already
+ * been initiated by FCGI_BeginJSON. Note that characters are not escaped.
+ * @param key The key of the JSON entry
+ * ¶m value The value associated with the key.
+ */
void FCGI_BuildJSON(const char *key, const char *value)
{
printf(",\r\n\t\"%s\" : \"%s\"", key, value);
}
+/**
+ * Ends a JSON response that was initiated by FCGI_BeginJSON.
+ */
void FCGI_EndJSON()
{
printf("\r\n}\r\n");
}
-static void SensorsHandler(void *data, char *params)
-{
- const char *key, *value;
-
- //Begin a request only when you know the final result
- //E.g whether OK or not.
- FCGI_BeginJSON(STATUS_OK, "sensors");
- while ((params = FCGI_KeyPair(params, &key, &value))) {
- FCGI_BuildJSON(key, value);
- }
- FCGI_EndJSON();
-}
-
+/**
+ * Main FCGI request loop that receives/responds to client requests.
+ * @param data A data field to be passed to the selected module handler.
+ */
void FCGI_RequestLoop (void *data)
{
int count = 0;
if (!strcmp("sensors", module)) {
- module_handler = SensorsHandler;
- } else if (!strcmp("admin", module)) {
- //module_handler = AdminHandlerReplace with pointer to admin handler
+ //module_handler = Handler_Sensors;
+ } else if (!strcmp("actuators", module)) {
+
}
if (module_handler) {
count++;
}
}
-
-int main(int argc, char *argv[]) {
- FCGI_RequestLoop(NULL);
-}
--- /dev/null
+/**
+ * @file fastcgi.h
+ * @purpose Headers for the fastcgi web interface
+ */
+
+#ifndef _FASTCGI_H
+#define _FASTCGI_H
+
+/**HTTP status codes that fcgi module handlers can return**/
+typedef enum StatusCodes {
+ STATUS_OK = 200,
+ STATUS_BADREQUEST = 400,
+ STATUS_UNAUTHORIZED = 401
+} StatusCodes;
+
+typedef void (*ModuleHandler) (void *data, char *params);
+
+extern char *FCGI_KeyPair(char *in, const char **key, const char **value);
+extern void FCGI_BeginJSON(StatusCodes status_code, const char *module);
+extern void FCGI_BuildJSON(const char *key, const char *value);
+extern void FCGI_EndJSON();
+extern void FCGI_RequestLoop (void *data);
+#endif
--- /dev/null
+#include <openssl/sha.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define SALT_LENGTH 20
+
+int ReadBytes(char *str, unsigned char *buffer, size_t buffer_length) {
+ unsigned i, val;
+ if (strlen(str) != buffer_length * 2)
+ return 0;
+ for (i = 0; i < buffer_length; i++) {
+ sscanf(str + i*2, "%2x", &val);
+ buffer[i] = (unsigned char) val;
+ }
+ return 1;
+}
+
+unsigned char *HashPass(const char *pass, unsigned char salt[SALT_LENGTH]) {
+ unsigned char *buffer, *result;
+ size_t pass_length = strlen(pass);
+ size_t buffer_length = pass_length + SALT_LENGTH;
+ buffer = malloc(buffer_length * sizeof(unsigned char));
+ if (!buffer)
+ return NULL;
+
+ memcpy(buffer, pass, pass_length);
+ memcpy(buffer + pass_length, salt, SALT_LENGTH);
+ result = SHA1(buffer, buffer_length, NULL);
+ free(buffer);
+
+ return result;
+}
+
+int WriteUserPass(FILE *fp, const char *user, const char *pass) {
+ unsigned char salt[SALT_LENGTH], *sha1;
+ size_t i;
+
+ FILE *fpr = fopen("/dev/urandom", "r");
+ if (!fpr)
+ return 0;
+ fread(salt, sizeof(unsigned char), SALT_LENGTH, fpr);
+ fclose(fpr);
+
+ if (!fp)
+ return 0;
+
+ sha1 = HashPass(pass, salt);
+ if (!sha1)
+ return 0;
+
+ fprintf(fp, "%s:", user);
+ for (i = 0; i < SALT_LENGTH; i++) {
+ fprintf(fp, "%02x", salt[i]);
+ }
+ fprintf(fp, "$");
+ for (i = 0; i < 20; i++) {
+ fprintf(fp, "%02x", sha1[i]);
+ }
+ fprintf(fp, "\n");
+
+ return 1;
+}
+
+int CheckUserPass(const char *passfile, const char *cuser, const char *cpass) {
+ FILE *fp = fopen(passfile, "r");
+ char buffer[BUFSIZ];
+ int ret = 0;
+ if (!fp)
+ return 0;
+
+ while (fgets(buffer, BUFSIZ, fp)) {
+ char *user, *salt, *hash, *ptr;
+
+ user = buffer;
+ ptr = strchr(buffer, ':');
+ if (ptr) {
+ *ptr++ = 0;
+ salt = ptr;
+ ptr = strchr(ptr, '$');
+ if (ptr) {
+ *ptr++ = 0;
+ hash = ptr;
+ ptr = strchr(ptr, '\n');
+ if (ptr)
+ *ptr = 0;
+
+ if (strlen(hash) != 20 * 2) {
+ printf("Invalid SHA-1 hash: %s\n", hash);
+ continue;
+ } else if (strlen(salt) != SALT_LENGTH * 2) {
+ printf("Invalid salt length: %s\n", salt);
+ continue;
+ } else if (strcmp(user, cuser)) {
+ continue;
+ }
+
+ unsigned char saltbytes[SALT_LENGTH], hashbytes[20];
+ ReadBytes(salt, saltbytes, SALT_LENGTH);
+ ReadBytes(hash, hashbytes, 20);
+ if (!memcmp(HashPass(cpass, saltbytes), hashbytes, 20)) {
+ printf("Matched with user: %s\n", cuser);
+ ret = 1;
+ break;
+ }
+
+ }
+ }
+ }
+
+ fclose(fp);
+ return ret;
+}
+
+int main(int argc, char *argv[]) {
+ if (argc != 4) {
+ printf("Usage: %s user pass fname\n", argv[0]);
+ return 1;
+ }
+
+ FILE *fp = fopen(argv[3], "w");
+
+ if (!WriteUserPass(fp, argv[1], argv[2])) {
+ fprintf(stderr, "Failed to hash: %s:%s\n", argv[1], argv[2]);
+ return 1;
+ }
+ fclose(fp);
+
+ CheckUserPass(argv[3], argv[1], argv[2]);
+ return 0;
+}
--- /dev/null
+#!/bin/bash
+
+USER=www-data
+GROUP=www-data
+HOST=127.0.0.1
+PORT=9005
+
+CGI_NAME=/usr/bin/mctxserv
+CGI_BASENAME=`basename $CGI_NAME`
+PID=/var/run/$CGI_BASENAME.pid
+DAEMON=/usr/bin/spawn-fcgi
+DAEMON_BASENAME=`basename $DAEMON`
+DAEMON_OPTS="-a $HOST -p $PORT -u $USER -g $GROUP -P $PID $CGI_NAME"
+
+#Test if daemon exists
+[ -x "$DAEMON" ] || (echo $DAEMON doesn\'t exist! && exit 1)
+#Test if cgi module exists
+[ -x "$CGI_NAME" ] || (echo $CGI_BASENAME doesn\'t exist! && exit 1)
+
+start() {
+ echo -n "Starting FastCGI Daemon: "
+ start-stop-daemon --start --quiet --pidfile $PID \
+ --exec $DAEMON -- $DAEMON_OPTS > /dev/null
+ RETVAL=$?
+ echo "$CGI_BASENAME."
+}
+stop() {
+ echo -n "Stopping FastCGI Daemon: "
+ start-stop-daemon --stop --quiet --oknodo --retry 30 --pidfile $PID
+ RETVAL=$?
+ echo "$CGI_BASENAME."
+}
+
+case "$1" in
+ start)
+ start
+ ;;
+ stop)
+ stop
+ ;;
+ restart)
+ stop
+ start
+ ;;
+ *)
+ echo "Usage: mctxserv {start|stop|restart}"
+ exit 1
+ ;;
+esac
+exit $RETVAL