Commence work on authentication
[matches/MCTX3420.git] / server / login.c
1 /**
2  * @file login.c
3  * @brief Implementation of Login related functionality
4  */
5
6 #define _BSD_SOURCE
7
8 #include "login.h"
9 #include <ctype.h>
10
11 #define LDAP_DEPRECATED 1 // Required to use ldap_simple_bind_s
12 #include <ldap.h>
13
14 #define LDAP_URI "ldaps://ldap.pheme.uwa.edu.au"
15 #define LDAP_DN_BASE "ou=Users,ou=UWA,dc=uwads,dc=uwa,dc=edu,dc=au"     
16
17 /**
18  * Attempt to bind to the LDAP_URI
19  * @param user - The username
20  * @param pass - The password
21  * @returns An error code according to libldap; LDAP_SUCCESS if everything worked
22  */
23 int Login_LDAP_Bind(const char * user, const char * pass)
24 {
25
26
27         Log(LOGINFO, "Username: \"%s\"", user);
28
29         char dn[BUFSIZ]; // Fill with the DN
30
31         const char * user_type = "Students";
32
33         // Staff members have numbers starting in zero
34         if (user[0] == '0') 
35         {
36                 user_type = "Staff";    
37         }
38         
39         if (sprintf(dn, "cn=%s,ou=%s,%s", user, user_type, LDAP_DN_BASE) >= BUFSIZ)
40         {
41                 Log(LOGERR,"DN too long; recompile with increased BUFSIZ");     
42         }
43
44         // Initialise LDAP; prepares to connect to the server
45         LDAP * ld = NULL;
46         int err = ldap_initialize(&ld, LDAP_URI);
47         if (err != LDAP_SUCCESS || ld == NULL)
48         {
49                 Log(LOGERR,"ldap_initialize failed - %s (ld = %p)", ldap_err2string(err), ld);
50                 return err;
51         }
52
53         // Set the LDAP version...
54         int version = LDAP_VERSION3;
55         err = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version); // specify the version
56         if (err != LDAP_SUCCESS)
57         {
58                 Log(LOGERR,"ldap_set_option failed - %s", ldap_err2string(err));
59                 return err;
60         }
61
62         // Attempt to bind using the supplied credentials.
63         // NOTE: ldap_simple_bind_s is "deprecated" in <ldap.h>, but not listed as such in the man pages :S
64         err = ldap_simple_bind_s(ld, dn, pass);
65         if (err != LDAP_SUCCESS)
66         {
67                 Log(LOGERR, "ldap_simple_bind_s failed - %s", ldap_err2string(err));
68         }
69         else
70         {
71                 Log(LOGDEBUG, "Successfully bound to %s with username %s", LDAP_URI, user);
72         }
73
74         err = ldap_unbind_s(ld);
75         if (err != LDAP_SUCCESS)
76         {
77                 Log(LOGERR, "ldap_unbind_s failed - %s", ldap_err2string(err));
78         }
79         return err;
80 }
81
82 /**
83  * Logout
84  * @param context - The context. The key will be cleared.
85  * @param params - Parameter string, UNUSED
86  */
87 void Logout_Handler(FCGIContext * context, char * params)
88 {               
89         FCGI_ReleaseControl(context);
90 }
91
92
93 /**
94  * Handle a Login Request
95  * @param context - The context
96  * @param params - Parameter string, should contain username and password
97  */
98 void Login_Handler(FCGIContext * context, char * params)
99 {
100
101         if (context->control_key[0] != '\0')
102         {
103                 FCGI_RejectJSON(context, "Already logged in");
104                 return;
105         }
106
107         char * user = ""; // The username supplied through CGI
108         char * pass = ""; // The password supplied through CGI
109                                                 //TODO: Make sure these are passed through HTTPS, *not* HTTP .... otherwise people can eavesdrop on the passwords
110
111         FCGIValue values[] = {
112                 {"user", &user, FCGI_REQUIRED(FCGI_STRING_T)},
113                 {"pass", &pass, FCGI_REQUIRED(FCGI_STRING_T)},
114         };
115
116         //enum to avoid the use of magic numbers
117         typedef enum {
118                 USER,
119                 PASS,
120                 LOGOUT
121         } LoginParams;
122
123         // Fill values appropriately
124         if (!FCGI_ParseRequest(context, params, values, sizeof(values)/sizeof(FCGIValue)))
125         {
126                 // Error occured; FCGI_RejectJSON already called
127                 return;
128         }
129
130
131         // Trim leading whitespace (the BUFSIZ check is to make sure incorrectly terminated strings don't cause an infinite loop)
132         int i = 0;
133         for (i = 0; i < BUFSIZ && isspace(user[0]) && user[0] != '\0'; ++i,++user);
134
135         // Truncate string at first non alphanumeric character
136         for (i = 0; i < BUFSIZ && isalnum(user[i]) && user[i] != '\0'; ++i);
137         user[i] = '\0';
138
139         if (strlen(pass) <= 0)
140         {
141                 FCGI_RejectJSON(context, "No password supplied.");
142                 return;
143         }
144
145         // Try to authenticate
146         int err = Login_LDAP_Bind(user, pass);
147
148         // error check  
149         
150         if (err == LDAP_SUCCESS)
151         {
152                 FCGI_LockControl(context, false);
153         }
154         
155
156         FCGI_BeginJSON(context, STATUS_OK);
157         FCGI_JSONPair("user", user);
158         FCGI_JSONPair("login", ldap_err2string(err));
159         FCGI_JSONPair("key", context->control_key);
160         FCGI_EndJSON();
161 }

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