* @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;
+ }
+ char buffer[BUFSIZ];
+ int passwd_index = -1;
- Log(LOGINFO, "Username: \"%s\"", user);
+ while (fgets(buffer, BUFSIZ, f) != NULL) // NOTE: Restrict username+password strings to BUFSIZ... what could possibly go wrong?
+ {
- char dn[BUFSIZ]; // Fill with the DN
+ 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;
+ }
+ }
- const char * user_type = "Students";
+ if (strcmp(user,buffer) == 0)
+ {
+ Log(LOGDEBUG,"User matches! %s\n", buffer);
+ break;
+ }
+ passwd_index = -1;
+ }
- // Staff members have numbers starting in zero
- if (user[0] == '0')
+ if (passwd_index <= 0)
{
- user_type = "Staff";
+ 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';
+
+ }
}
- 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);
}
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;
}
if (context->control_key[0] != '\0')
{
- FCGI_RejectJSON(context, "Already logged in");
+ 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
+ char * user; // The username supplied through CGI
+ char * pass; // The password supplied through CGI
FCGIValue values[] = {
{"user", &user, FCGI_REQUIRED(FCGI_STRING_T)},
return;
}
-
- // Trim leading whitespace (the BUFSIZ check is to make sure incorrectly terminated strings don't cause an infinite loop)
+ // Trim leading whitespace
int i = 0;
- for (i = 0; i < BUFSIZ && isspace(user[0]) && user[0] != '\0'; ++i,++user);
+ for (i = 0; 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);
+ for (i = 0; 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);
+ FCGI_PrintRaw("Logged in");
}