Work on Authentication System(s)
[matches/MCTX3420.git] / server / login.c
index 615be9e..a616af2 100644 (file)
  * @brief Implementation of Login related functionality
  */
 
-#define _BSD_SOURCE
+
+
 
 #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>
 
-#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
+ * 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 An error code according to libldap; LDAP_SUCCESS if everything worked
+ * @returns True if the login was successful, false otherwise
  */
-int Login_LDAP_Bind(const char * user, const char * pass)
+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;
+       }
 
-       Log(LOGINFO, "Username: \"%s\"", user);
+       char buffer[BUFSIZ];
+       int passwd_index = -1;
 
-       char dn[BUFSIZ]; // Fill with the DN
+       while (fgets(buffer, BUFSIZ, f) != NULL) // NOTE: Restrict username+password strings to BUFSIZ... what could possibly go wrong?
+       {
 
-       const char * user_type = "Students";
+               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;
+                       }
+               }
 
-       // Staff members have numbers starting in zero
-       if (user[0] == '0') 
+               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)
        {
-               user_type = "Staff";    
+               if (buffer[i] == ':' || buffer[i] == '\n')
+               {
+                       buffer[i] = '\0';
+                       
+               }
        }
        
-       if (sprintf(dn, "cn=%s,ou=%s,%s", user, user_type, LDAP_DN_BASE) >= BUFSIZ)
+       // Determine the salt
+       char salt[BUFSIZ];
+       int s = 0; int count = 0;
+       for (int i = passwd_index; i < BUFSIZ-1; ++i)
        {
-               Log(LOGERR,"DN too long; recompile with increased BUFSIZ");     
+               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, LDAP_URI);
+       int err = ldap_initialize(&ld, uri);
        if (err != LDAP_SUCCESS || ld == NULL)
        {
                Log(LOGERR,"ldap_initialize failed - %s (ld = %p)", ldap_err2string(err), ld);
@@ -68,13 +131,14 @@ int Login_LDAP_Bind(const char * user, const char * pass)
        }
        else
        {
-               Log(LOGDEBUG, "Successfully bound to %s with username %s", LDAP_URI, user);
+               Log(LOGDEBUG, "Successfully bound to %s with dn %s", uri, dn);
        }
 
-       err = ldap_unbind_s(ld);
-       if (err != LDAP_SUCCESS)
+       int err2 = ldap_unbind_s(ld);
+       if (err2 != LDAP_SUCCESS)
        {
-               Log(LOGERR, "ldap_unbind_s failed - %s", ldap_err2string(err));
+               Log(LOGERR, "ldap_unbind_s failed - %s", ldap_err2string(err2));
+               err = err2;
        }
        return err;
 }
@@ -100,7 +164,7 @@ void Login_Handler(FCGIContext * context, char * params)
 
        if (context->control_key[0] != '\0')
        {
-               FCGI_RejectJSON(context, "Already logged in");
+               FCGI_RejectJSON(context, "Already logged in.");
                return;
        }
 
@@ -136,26 +200,65 @@ void Login_Handler(FCGIContext * context, char * params)
        for (i = 0; i < BUFSIZ && isalnum(user[i]) && user[i] != '\0'; ++i);
        user[i] = '\0';
 
-       if (strlen(pass) <= 0)
+
+
+       
+       bool authenticated = true;
+       
+       switch (g_options.auth_method)
        {
-               FCGI_RejectJSON(context, "No password supplied.");
-               return;
-       }
 
-       // Try to authenticate
-       int err = Login_LDAP_Bind(user, pass);
+               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 (err == LDAP_SUCCESS)
+       if (!authenticated)
        {
-               FCGI_LockControl(context, false);
+               FCGI_RejectJSON(context, "Authentication failure.");
+               return;
        }
-       
 
-       FCGI_BeginJSON(context, STATUS_OK);
-       FCGI_JSONPair("user", user);
-       FCGI_JSONPair("login", ldap_err2string(err));
-       FCGI_JSONPair("key", context->control_key);
-       FCGI_EndJSON();
+       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);
+       
 }

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