Abstraced updates to the cokebank file to a function
[tpg/opendispense2.git] / src / cokebank_basic / bank.c
1 /*
2  * OpenDispense 2
3  * UCC (University [of WA] Computer Club) Electronic Accounting System
4  * - Cokebank (Basic Version)
5  *
6  * bank.c - Actual bank database
7  *
8  * This file is licenced under the 3-clause BSD Licence. See the file COPYING
9  * for full details.
10  */
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <limits.h>
15 #include <pwd.h>
16 #include <grp.h>
17 #include "common.h"
18
19 #define USE_UNIX_GROUPS 1
20
21 // === PROTOTYPES ===
22 static int      GetUnixID(const char *Username);
23
24 // === GLOBALS ===
25 tUser   *gaBank_Users;
26  int    giBank_NumUsers;
27 FILE    *gBank_File;
28
29 // === CODE ===
30 static int Bank_int_WriteEntry(int ID)
31 {
32         if( ID < 0 || ID >= giBank_NumUsers ) {
33                 return -1;
34         }
35         
36         // Commit to file
37         fseek(gBank_File, ID*sizeof(gaBank_Users[0]), SEEK_SET);
38         fwrite(&gaBank_Users[ID], sizeof(gaBank_Users[0]), 1, gBank_File);
39         
40         return 0;
41 }
42
43 int Bank_GetUserByName(const char *Username)
44 {
45          int    i, uid;
46         
47         uid = GetUnixID(Username);
48         
49         // Expensive search :(
50         for( i = 0; i < giBank_NumUsers; i ++ )
51         {
52                 if( gaBank_Users[i].UnixID == uid )
53                         return i;
54         }
55
56         return -1;
57 }
58
59 int Bank_GetUserBalance(int ID)
60 {
61         if( ID < 0 || ID >= giBank_NumUsers )
62                 return INT_MIN;
63
64         return gaBank_Users[ID].Balance;
65 }
66
67 int Bank_GetUserFlags(int ID)
68 {
69         if( ID < 0 || ID >= giBank_NumUsers )
70                 return -1;
71
72         // root
73         if( gaBank_Users[ID].UnixID == 0 ) {
74                 gaBank_Users[ID].Flags |= USER_FLAG_WHEEL|USER_FLAG_COKE;
75         }
76
77         #if USE_UNIX_GROUPS
78         // TODO: Implement checking the PAM groups and status instead, then
79         // fall back on the database. (and update if there is a difference)
80         if( gaBank_Users[ID].UnixID > 0 )
81         {
82                 struct passwd   *pwd;
83                 struct group    *grp;
84                  int    i;
85                 
86                 // Get username
87                 pwd = getpwuid( gaBank_Users[ID].UnixID );
88                 
89                 // Check for additions to the "coke" group
90                 grp = getgrnam("coke");
91                 if( grp ) {
92                         for( i = 0; grp->gr_mem[i]; i ++ )
93                         {
94                                 if( strcmp(grp->gr_mem[i], pwd->pw_name) == 0 ) {
95                                         gaBank_Users[ID].Flags |= USER_FLAG_COKE;
96                                         break ;
97                                 }
98                         }
99                 }
100                 
101                 // Check for additions to the "wheel" group
102                 grp = getgrnam("wheel");
103                 if( grp ) {
104                         for( i = 0; grp->gr_mem[i]; i ++ )
105                         {
106                                 if( strcmp(grp->gr_mem[i], pwd->pw_name) == 0 ) {
107                                         gaBank_Users[ID].Flags |= USER_FLAG_WHEEL;
108                                         break ;
109                                 }
110                         }
111                 }
112         }
113         #endif
114
115         return gaBank_Users[ID].Flags;
116 }
117
118 int Bank_SetUserFlags(int ID, int Mask, int Value)
119 {
120         // Sanity
121         if( ID < 0 || ID >= giBank_NumUsers )
122                 return -1;
123         
124         // Silently ignore changes to root and meta accounts
125         if( gaBank_Users[ID].UnixID <= 0 )      return 0;
126         
127         gaBank_Users[ID].Flags &= ~Mask;
128         gaBank_Users[ID].Flags |= Value;
129
130         Bank_int_WriteEntry(ID);
131         
132         return 0;
133 }
134
135 int Bank_AlterUserBalance(int ID, int Delta)
136 {
137         // Sanity
138         if( ID < 0 || ID >= giBank_NumUsers )
139                 return -1;
140
141         // Update
142         gaBank_Users[ID].Balance += Delta;
143
144         Bank_int_WriteEntry(ID);
145         
146         return 0;
147 }
148
149 int Bank_GetMinAllowedBalance(int ID)
150 {
151          int    flags;
152         if( ID < 0 || ID >= giBank_NumUsers )
153                 return 0;
154
155         flags = Bank_GetUserFlags(ID);
156
157         // Internal accounts have no limit
158         if( (flags & USER_FLAG_INTERNAL) )
159                 return INT_MIN;
160
161         // Wheel is allowed to go to -$100
162         if( (flags & USER_FLAG_WHEEL) )
163                 return -10000;
164         
165         // Coke is allowed to go to -$20
166         if( (flags & USER_FLAG_COKE) )
167                 return -2000;
168
169         // For everyone else, no negative
170         return 0;
171 }
172
173 /**
174  * \brief Create a new user in our database
175  */
176 int Bank_AddUser(const char *Username)
177 {
178         void    *tmp;
179          int    uid = GetUnixID(Username);
180
181         // Can has moar space plz?
182         tmp = realloc(gaBank_Users, (giBank_NumUsers+1)*sizeof(gaBank_Users[0]));
183         if( !tmp )      return -1;
184         gaBank_Users = tmp;
185
186         // Crete new user
187         gaBank_Users[giBank_NumUsers].UnixID = uid;
188         gaBank_Users[giBank_NumUsers].Balance = 0;
189         gaBank_Users[giBank_NumUsers].Flags = 0;
190         
191         if( strcmp(Username, COKEBANK_DEBT_ACCT) == 0 ) {
192                 gaBank_Users[giBank_NumUsers].Flags = USER_FLAG_INTERNAL;
193         }
194         else if( strcmp(Username, COKEBANK_SALES_ACCT) == 0 ) {
195                 gaBank_Users[giBank_NumUsers].Flags = USER_FLAG_INTERNAL;
196         }
197         else if( strcmp(Username, "root") == 0 ) {
198                 gaBank_Users[giBank_NumUsers].Flags = USER_FLAG_WHEEL|USER_FLAG_COKE;
199         }
200
201         // Increment count
202         giBank_NumUsers ++;
203         
204         Bank_int_WriteEntry(giBank_NumUsers - 1);
205
206         return 0;
207 }
208
209 // ---
210 // Unix user dependent code
211 // TODO: Modify to keep its own list of usernames
212 // ---
213 char *Bank_GetUserName(int ID)
214 {
215         struct passwd   *pwd;
216         
217         if( ID < 0 || ID >= giBank_NumUsers )
218                 return NULL;
219         
220         if( gaBank_Users[ID].UnixID == -1 )
221                 return strdup(COKEBANK_SALES_ACCT);
222
223         if( gaBank_Users[ID].UnixID == -2 )
224                 return strdup(COKEBANK_DEBT_ACCT);
225
226         pwd = getpwuid(gaBank_Users[ID].UnixID);
227         if( !pwd )      return NULL;
228
229         return strdup(pwd->pw_name);
230 }
231
232 static int GetUnixID(const char *Username)
233 {
234          int    uid;
235
236         if( strcmp(Username, COKEBANK_SALES_ACCT) == 0 ) {      // Pseudo account that sales are made into
237                 uid = -1;
238         }
239         else if( strcmp(Username, COKEBANK_DEBT_ACCT) == 0 ) {  // Pseudo acount that money is added from
240                 uid = -2;
241         }
242         else {
243                 struct passwd   *pwd;
244                 // Get user ID
245                 pwd = getpwnam(Username);
246                 if( !pwd )      return -1;
247                 uid = pwd->pw_uid;
248         }
249         return uid;
250 }

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