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

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