f7d32f0dc62e9c0ba8a8d28f029ae22df322413f
[tpg/opendispense2.git] / src / cokebank_basic / main.c
1 /*
2  * OpenDispense 2 
3  * UCC (University [of WA] Computer Club) Electronic Accounting System
4  *
5  * cokebank.c - Coke-Bank management
6  *
7  * This file is licenced under the 3-clause BSD Licence. See the file COPYING
8  * for full details.
9  */
10 #include <stdlib.h>
11 #include <stdint.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <openssl/sha.h>
15 #include "common.h"
16 #if USE_LDAP
17 # include <ldap.h>
18 #endif
19
20 /*
21  * NOTES:
22  * 
23  * http://linuxdevcenter.com/pub/a/linux/2003/08/14/libldap.html
24  * - Using libldap, the LDAP Client Library 
25  * 
26  */
27
28 // === HACKS ===
29 #define HACK_TPG_NOAUTH 1
30 #define HACK_ROOT_NOAUTH        1
31
32 // === PROTOTYPES ===
33 void    Init_Cokebank(const char *Argument);
34  int    Transfer(int SourceUser, int DestUser, int Ammount, const char *Reason);
35  int    GetBalance(int User);
36 char    *GetUserName(int User);
37  int    GetUserID(const char *Username);
38  int    GetMaxID(void);
39  int    GetUserAuth(const char *Salt, const char *Username, const char *PasswordString);
40 #if USE_LDAP
41 char    *ReadLDAPValue(const char *Filter, char *Value);
42 #endif
43 void    HexBin(uint8_t *Dest, int BufSize, const char *Src);
44
45 // === GLOBALS ===
46 FILE    *gBank_LogFile;
47 #if USE_LDAP
48 char    *gsLDAPPath = "ldapi:///";
49 LDAP    *gpLDAP;
50 #endif
51
52 // === CODE ===
53 /**
54  * \brief Load the cokebank database
55  */
56 void Init_Cokebank(const char *Argument)
57 {
58         #if USE_LDAP
59          int    rv;
60         #endif
61         
62         // Open Cokebank
63         gBank_File = fopen(Argument, "rb+");
64         if( !gBank_File ) {
65                 gBank_File = fopen(Argument, "wb+");
66         }
67         if( !gBank_File ) {
68                 perror("Opening coke bank");
69         }
70
71         // Open log file
72         // TODO: Do I need this?
73         gBank_LogFile = fopen("cokebank.log", "a");
74         if( !gBank_LogFile )    gBank_LogFile = stdout;
75
76         // Read in cokebank
77         fseek(gBank_File, 0, SEEK_END);
78         giBank_NumUsers = ftell(gBank_File) / sizeof(gaBank_Users[0]);
79         fseek(gBank_File, 0, SEEK_SET);
80         gaBank_Users = malloc( giBank_NumUsers * sizeof(gaBank_Users[0]) );
81         fread(gaBank_Users, sizeof(gaBank_Users[0]), giBank_NumUsers, gBank_File);
82         
83         #if USE_LDAP
84         // Connect to LDAP
85         rv = ldap_create(&gpLDAP);
86         if(rv) {
87                 fprintf(stderr, "ldap_create: %s\n", ldap_err2string(rv));
88                 exit(1);
89         }
90         rv = ldap_initialize(&gpLDAP, gsLDAPPath);
91         if(rv) {
92                 fprintf(stderr, "ldap_initialize: %s\n", ldap_err2string(rv));
93                 exit(1);
94         }
95         { int ver = LDAP_VERSION3; ldap_set_option(gpLDAP, LDAP_OPT_PROTOCOL_VERSION, &ver); }
96         # if 0
97         rv = ldap_start_tls_s(gpLDAP, NULL, NULL);
98         if(rv) {
99                 fprintf(stderr, "ldap_start_tls_s: %s\n", ldap_err2string(rv));
100                 exit(1);
101         }
102         # endif
103         {
104                 struct berval   cred;
105                 struct berval   *servcred;
106                 cred.bv_val = "secret";
107                 cred.bv_len = 6;
108                 rv = ldap_sasl_bind_s(gpLDAP, "cn=root,dc=ucc,dc=gu,dc=uwa,dc=edu,dc=au",
109                         "", &cred, NULL, NULL, &servcred);
110                 if(rv) {
111                         fprintf(stderr, "ldap_start_tls_s: %s\n", ldap_err2string(rv));
112                         exit(1);
113                 }
114         }
115         #endif
116 }
117
118 /**
119  * \brief Transfers money from one user to another
120  * \param SourceUser    Source user
121  * \param DestUser      Destination user
122  * \param Ammount       Ammount of cents to move from \a SourceUser to \a DestUser
123  * \param Reason        Reason for the transfer (essentially a comment)
124  * \return Boolean failure
125  */
126 int Transfer(int SourceUser, int DestUser, int Ammount, const char *Reason)
127 {
128          int    srcBal = Bank_GetUserBalance(SourceUser);
129          int    dstBal = Bank_GetUserBalance(DestUser);
130         
131         if( srcBal - Ammount < Bank_GetMinAllowedBalance(SourceUser) )
132                 return 1;
133         if( dstBal + Ammount < Bank_GetMinAllowedBalance(DestUser) )
134                 return 1;
135         Bank_AlterUserBalance(DestUser, Ammount);
136         Bank_AlterUserBalance(SourceUser, -Ammount);
137         fprintf(gBank_LogFile, "Transfer %ic #%i{%i} > #%i{%i} [%i, %i] (%s)\n",
138                 Ammount, SourceUser, srcBal, DestUser, dstBal,
139                 srcBal - Ammount, dstBal + Ammount, Reason);
140         return 0;
141 }
142
143 int GetFlags(int User)
144 {
145         return Bank_GetUserFlags(User);
146 }
147
148 int SetFlags(int User, int Mask, int Flags)
149 {
150         return Bank_SetUserFlags(User, Mask, Flags);
151 }
152
153 /**
154  * \brief Get the balance of the passed user
155  */
156 int GetBalance(int User)
157 {
158         return Bank_GetUserBalance(User);
159 }
160
161 /**
162  * \brief Return the name the passed user
163  */
164 char *GetUserName(int User)
165 {
166         return Bank_GetUserName(User);
167 }
168
169 /**
170  * \brief Get the User ID of the named user
171  */
172 int GetUserID(const char *Username)
173 {
174         return Bank_GetUserByName(Username);
175 }
176
177 int CreateUser(const char *Username)
178 {
179          int    ret;
180         
181         ret = Bank_GetUserByName(Username);
182         if( ret != -1 ) return -1;
183         
184         return Bank_AddUser(Username);
185 }
186
187 int GetMaxID(void)
188 {
189         return giBank_NumUsers;
190 }
191
192 /**
193  * \brief Authenticate a user
194  * \return User ID, or -1 if authentication failed
195  */
196 int GetUserAuth(const char *Salt, const char *Username, const char *PasswordString)
197 {
198         #if USE_LDAP
199         uint8_t hash[20];
200         uint8_t h[20];
201          int    ofs = strlen(Username) + strlen(Salt);
202         char    input[ ofs + 40 + 1];
203         char    tmp[4 + strlen(Username) + 1];  // uid=%s
204         char    *passhash;
205         #endif
206         
207         #if HACK_TPG_NOAUTH
208         if( strcmp(Username, "tpg") == 0 )
209                 return GetUserID("tpg");
210         #endif
211         #if HACK_ROOT_NOAUTH
212         if( strcmp(Username, "root") == 0 ) {
213                 int ret = GetUserID("root");
214                 if( ret == -1 )
215                         return CreateUser("root");
216                 return ret;
217         }
218         #endif
219         
220         #if USE_LDAP
221         HexBin(hash, 20, PasswordString);
222         
223         // Build string to hash
224         strcpy(input, Username);
225         strcpy(input, Salt);
226         
227         // TODO: Get user's SHA-1 hash
228         sprintf(tmp, "uid=%s", Username);
229         printf("tmp = '%s'\n", tmp);
230         passhash = ReadLDAPValue(tmp, "userPassword");
231         if( !passhash ) {
232                 return -1;
233         }
234         printf("LDAP hash '%s'\n", passhash);
235         
236         sprintf(input+ofs, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
237                 h[ 0], h[ 1], h[ 2], h[ 3], h[ 4], h[ 5], h[ 6], h[ 7], h[ 8], h[ 9],
238                 h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19]
239                 );
240         // Then create the hash from the provided salt
241         // Compare that with the provided hash
242
243         # if 1
244         {
245                  int    i;
246                 printf("Password hash ");
247                 for(i=0;i<20;i++)
248                         printf("%02x", hash[i]&0xFF);
249                 printf("\n");
250         }
251         # endif
252         
253         #endif
254         
255         return -1;
256 }
257
258 #if USE_LDAP
259 char *ReadLDAPValue(const char *Filter, char *Value)
260 {
261         LDAPMessage     *res, *res2;
262         struct berval **attrValues;
263         char    *attrNames[] = {Value,NULL};
264         char    *ret;
265         struct timeval  timeout;
266          int    rv;
267         
268         timeout.tv_sec = 5;
269         timeout.tv_usec = 0;
270         
271         rv = ldap_search_ext_s(gpLDAP, "", LDAP_SCOPE_BASE, Filter,
272                 attrNames, 0, NULL, NULL, &timeout, 1, &res
273                 );
274         printf("ReadLDAPValue: rv = %i\n", rv);
275         if(rv) {
276                 fprintf(stderr, "LDAP Error reading '%s' with filter '%s'\n%s\n",
277                         Value, Filter,
278                         ldap_err2string(rv)
279                         );
280                 return NULL;
281         }
282         
283         res2 = ldap_first_entry(gpLDAP, res);
284         attrValues = ldap_get_values_len(gpLDAP, res2, Value);
285         
286         ret = strndup(attrValues[0]->bv_val, attrValues[0]->bv_len);
287         
288         ldap_value_free_len(attrValues);
289         
290         
291         return ret;
292 }
293 #endif
294
295 // TODO: Move to another file
296 void HexBin(uint8_t *Dest, int BufSize, const char *Src)
297 {
298          int    i;
299         for( i = 0; i < BufSize; i ++ )
300         {
301                 uint8_t val = 0;
302                 
303                 if('0' <= *Src && *Src <= '9')
304                         val |= (*Src-'0') << 4;
305                 else if('A' <= *Src && *Src <= 'F')
306                         val |= (*Src-'A'+10) << 4;
307                 else if('a' <= *Src && *Src <= 'f')
308                         val |= (*Src-'a'+10) << 4;
309                 else
310                         break;
311                 Src ++;
312                 
313                 if('0' <= *Src && *Src <= '9')
314                         val |= (*Src-'0');
315                 else if('A' <= *Src && *Src <= 'F')
316                         val |= (*Src-'A'+10);
317                 else if('a' <= *Src && *Src <= 'f')
318                         val |= (*Src-'a'+10);
319                 else
320                         break;
321                 Src ++;
322                 
323                 Dest[i] = val;
324         }
325         for( ; i < BufSize; i++ )
326                 Dest[i] = 0;
327 }
328

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