Merge branch 'master' of https://github.com/szmoore/MCTX3420 into users
authorJeremy Tan <[email protected]>
Sat, 26 Oct 2013 01:39:56 +0000 (09:39 +0800)
committerJeremy Tan <[email protected]>
Sat, 26 Oct 2013 01:39:56 +0000 (09:39 +0800)
Conflicts:
server/fastcgi.c
server/parameters

1  2 
.gitignore
server/login.c
server/main.c

diff --combined .gitignore
@@@ -2,6 -2,8 +2,8 @@@
  *.o
  *.exe
  *.dll
+ *.a
+ *.lib
  
  .DS_Store
  .DS_Store?
@@@ -17,5 -19,3 +19,5 @@@ server/win3
  **/nbproject/private/
  
  *jquery-ui*
 +
 +*password*
diff --combined server/login.c
   */
  
  
 -
 -
 -#include "login.h"
 +#include "common.h"
  #include "options.h"
  #include <ctype.h>
  #include <unistd.h>
  
 +// LDAP stuff
  #define LDAP_DEPRECATED 1 // Required to use ldap_simple_bind_s
  #include <ldap.h>
  
 +// MySQL stuff
 +#undef _GNU_SOURCE // HACK to silence compiler warning on redefinition in my_global.h
 +#include <my_global.h>
 +#include <mysql.h>
 +
 +
 +
 +
 +
 +/**
 + * Attempt to login by searching a MySQL database
 + * @param user - Username
 + * @param pass - Password
 + * @param db_host - Host running the DataBase
 + * @param db_user - User to search the database as
 + * @param db_pass - Password for the database user
 + * @param db_name - Name of the database to use
 + * @param db_table - Table to search in
 + * @returns Privelage level of the user or USER_UNAUTH for failure to authenticate
 + */
 +UserType Login_MySQL(const char * user, const char * pass, 
 +      const char * db_host, const char * db_user, const char * db_pass, const char * db_name, const char * db_table)
 +{
 +      MYSQL * con = mysql_init(NULL);
 +      if (con == NULL)
 +      {
 +              Log(LOGERR, "mysql_init failed - %s", mysql_error(con));
 +              return USER_UNAUTH;
 +      }
 +
 +      if (mysql_real_connect(con, db_host, db_user, db_pass, NULL, 0, NULL, 0) == NULL)
 +      {
 +              Log(LOGERR, "mysql_real_connect failed - %s", mysql_error(con));
 +              mysql_close(con);
 +              return USER_UNAUTH;
 +      }
 +
 +      char buffer[BUFSIZ];
 +
 +      // Select the database
 +      sprintf(buffer, "USE %s;", db_name);
 +      if (mysql_query(con, buffer))
 +      {
 +              Log(LOGERR, "mysql_query failed - %s", mysql_error(con));
 +              mysql_close(con);
 +              return USER_UNAUTH;
 +      }
 +
 +      // Search for the user
 +      sprintf(buffer, "SELECT password FROM %s WHERE user_name = \"%s\";", db_table, user);
 +      if (mysql_query(con, buffer))
 +      {
 +              Log(LOGERR, "mysql_query failed - %s", mysql_error(con));
 +              mysql_close(con);
 +              return USER_UNAUTH;
 +      }
 +      
 +      // Process the result
 +      MYSQL_RES * result = mysql_store_result(con);
 +      if (result == NULL)
 +      {
 +              Log(LOGERR, "mysql_store_result failed - %s", mysql_error(con));
 +              mysql_close(con);
 +              return USER_UNAUTH;
 +      }
 +
 +      int num_fields = mysql_num_fields(result);
 +      if (num_fields != 1)
 +      {
 +              Log(LOGERR, "The database may be corrupt; %d fields found, expected %d", num_fields, 1);
 +              mysql_close(con);
 +              return USER_UNAUTH;
 +      }
 +
 +      UserType user_type = USER_UNAUTH;
 +      MYSQL_ROW row;
 +
 +      // Get first row
 +      if ((row = mysql_fetch_row(result)))
 +      {
 +              if (strcmp(crypt(pass, row[0]), row[0]) == 0)
 +              {
 +                      user_type = USER_NORMAL;
 +              }
 +
 +              // There should only be one row. Through a hissy fit if we see any more.
 +              if ((row = mysql_fetch_row(result)))
 +              {
 +                      Log(LOGERR, "Too many rows found.");
 +                      user_type = USER_UNAUTH;
 +              }
 +      }
 +      else
 +      {
 +              Log(LOGERR, "No user matching %s", user);
 +      }
 +
 +      //TODO: Handle administrator users somehow better than this
 +      // UserCake stores the permission level in a seperate table to the username/password, which is annoying
 +      if (user_type != USER_UNAUTH && strcmp(user, "admin") == 0)
 +      {
 +              user_type = USER_ADMIN;
 +      }
 +      mysql_free_result(result);
 +      mysql_close(con);
 +      return user_type;
 +}
 +
  /**
   * Attempt to login using a file formatted like /etc/shadow
   * This is here... because all better options have been exhausted
   * @param user - The username
   * @param pass - The password
 + * @param shadow - The file to use
   * @returns Privelage level of the user or USER_UNAUTH for failure to authenticate
   */
  UserType Login_Shadow(const char * user, const char * pass, const char * shadow)
@@@ -286,7 -178,10 +286,10 @@@ void Logout_Handler(FCGIContext * conte
  /**
   * Handle a Login Request
   * @param context - The context
-  * @param params - Parameter string, should contain username and password
+  * @param params - Parameter string, should contain username and password.
+  *                               NOTE: Care should be taken when using params, as it is
+  *                               completely unescaped. Do not log or use it without
+  *                 suitable escaping.
   */
  void Login_Handler(FCGIContext * context, char * params)
  {
  
                case AUTH_LDAP:
                {
-                       if (strlen(pass) <= 0)
+                       if (*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);
 +                      //int len = sprintf(dn, "uid=%s,%s", user, g_options.auth_options);
        
                        // At UWA (hooray)
                        char * user_group = "Students";
                        if (user[0] == '0')
                                user_group = "Staff";
 -                      int len = sprintf(dn, "cn=%s,ou=%s,%s", user, user_group, g_options.ldap_base_dn);
 +                      int len = sprintf(dn, "cn=%s,ou=%s,%s", user, user_group, g_options.auth_options);
                
  
                        if (len >= BUFSIZ)
                        user_type = Login_Shadow(user, pass, g_options.auth_uri);
                        break;
                }
 +              case AUTH_MYSQL:
 +              {
 +                      //WARNING: C string manipulation code approaching!
 +                      // Non reentrent; uses strsep and modifies g_options.auth_options
 +                      // If problems happen, try strdup first ...
 +                      static char * db_opts[] = {"root", "", "users", "uc_users"};
 +                      static bool db_init_opts = false;
 +                      if (!db_init_opts)
 +                      {
 +                              db_init_opts = true;
 +                              db_opts[0] = (char*)g_options.auth_options;
 +                              for (int i = 1; i < sizeof(db_opts)/sizeof(char*); ++i)
 +                              {
 +                                      char * def = db_opts[i];
 +                                      db_opts[i] = db_opts[i-1];
 +
 +                                      strsep(db_opts+i, ",");
 +                                      if (db_opts[i] == NULL)
 +                                      {
 +                                              db_opts[i] = def;
 +                                              break;
 +                                      }
 +                              }                       
 +                              //Log(LOGDEBUG, "MySQL: user %s pass %s name %s table %s", db_opts[0], db_opts[1], db_opts[2], db_opts[3]);     
 +                      }
 +
 +                      user_type = Login_MySQL(user, pass, g_options.auth_uri, db_opts[0],db_opts[1], db_opts[2], db_opts[3]);
 +                      break;
 +              }
                default:
                {
                        Log(LOGWARN, "No authentication!");
diff --combined server/main.c
@@@ -47,7 -47,7 +47,7 @@@ void ParseArguments(int argc, char ** a
  
        g_options.auth_method = AUTH_NONE;  // Don't use authentication
        g_options.auth_uri = ""; // 
 -      g_options.ldap_base_dn = "";
 +      g_options.auth_options = "";
        g_options.experiment_dir = ".";
        
        for (int i = 1; i < argc; ++i)
                        case 'p':
                                g_options.enable_pin = !(strtol(argv[++i], &end, 10));
                                break;
 -                      // LDAP URI
 +                      // Authentication URI and options
                        case 'A':
                                g_options.auth_uri = argv[++i];
                                break;
 -                      // LDAP DN
 -                      case 'd':
 -                              g_options.ldap_base_dn = argv[++i];
 -                              break;
                        case 'e':
                        // Experiments directory
                                g_options.experiment_dir = argv[++i];
                        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);
 -      //Log(LOGDEBUG, "Root directory: %s", g_options.root_dir);
 -      Log(LOGDEBUG, "Experiment directory: %s", g_options.experiment_dir);
 +
  
        if (!DirExists(g_options.experiment_dir))
        {
  
        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;
 +              // Get the options part of the URI if it exists
 +              char * c = (char*)g_options.auth_uri;
 +              while (*(++c) != '\0' && *c != '#');
 +              
 +              if (*(c++) == '#')
 +              {
 +                      *(c-1) = '\0';
 +                      g_options.auth_options = c;
 +              }
 +
 +              // Use the first part of the URI to identify the protocol:
 +              c = (char*)g_options.auth_uri;
 +              while (*(++c) != '\0' && *c != ':');
 +
 +              if (*c == '\0') // No ':' means no protocol; use plaintext file
 +              {
 +                      g_options.auth_method = AUTH_SHADOW;                    
 +              }
 +              else if (*c == ':' && *(c+1) == '/' && *(c+2) == '/')
 +              {
 +                      
 +                      *c = '\0';
 +                      if (strcmp(g_options.auth_uri, "ldap") == 0 || strcmp(g_options.auth_uri, "ldaps") == 0)
 +                      {
 +                              *c = ':'; // LDAP URI's require the prodocol as part of the string
 +                              g_options.auth_method = AUTH_LDAP;
 +                      }
 +                      else if (strcmp(g_options.auth_uri, "mysql") == 0)
 +                      {
 +                              g_options.auth_uri = c+3; // MySQL doesn't (just a hostname)
 +                              g_options.auth_method = AUTH_MYSQL;
 +                      }
 +                      else
 +                      {
 +                              Fatal("Unsupported authentication method %s", g_options.auth_uri);
 +                      }
 +              }
 +      }
 +      else
 +      {
 +              Log(LOGWARN, "No authentication method.");
        }
 +
 +      Log(LOGDEBUG, "Verbosity: %d", g_options.verbosity);
 +      Log(LOGDEBUG, "Pin Module Enabled: %d", g_options.enable_pin);
 +      Log(LOGDEBUG, "Auth method: %d", g_options.auth_method);
 +      Log(LOGDEBUG, "Auth URI: %s", g_options.auth_uri);
 +      Log(LOGDEBUG, "Auth Options: %s", g_options.auth_options);
 +      //Log(LOGDEBUG, "Root directory: %s", g_options.root_dir);
 +      Log(LOGDEBUG, "Experiment directory: %s", g_options.experiment_dir);
 +
 +
        
  }
  
@@@ -160,7 -123,7 +160,7 @@@ void Cleanup(
  {
        Log(LOGDEBUG, "Begin cleanup.");
        Sensor_Cleanup();
-       //Actuator_Cleanup();
+       Actuator_Cleanup();
        Log(LOGDEBUG, "Finish cleanup.");
  }
  
@@@ -236,23 -199,22 +236,22 @@@ int main(int argc, char ** argv
  
        
  
-       Sensor_Init();
-       Actuator_Init();
        Pin_Init();
        
        // Try and start things
        
-       const char *ret;
-       if ((ret = Control_SetMode(CONTROL_START, "test")) != NULL)
-               Fatal("Control_SetMode failed with '%s'", ret);
+       //const char *ret;
+       //if ((ret = Control_SetMode(CONTROL_START, "test")) != NULL)
+       //      Fatal("Control_SetMode failed with '%s'", ret);
        
  
        // run request thread in the main thread
        FCGI_RequestLoop(NULL);
  
        
-       if ((ret = Control_SetMode(CONTROL_STOP, "test")) != NULL)
-               Fatal("Control_SetMode failed with '%s'", ret);
+       Control_SetMode(CONTROL_STOP, NULL);
+       //if ((ret = Control_SetMode(CONTROL_STOP, "test")) != NULL)
+       //      Fatal("Control_SetMode failed with '%s'", ret);
        
        //Sensor_StopAll();
        //Actuator_StopAll();

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