X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=src%2Fcokebank_basic%2Fmain.c;h=0e7956aefcc3e4ffb828b9e5eda3bbf8eb8fb76d;hb=351184b3a2b597193234d09090281b8501f659c6;hp=4a5afb3d3cbe3505f40c3bed0d4b06f5c2ec7da7;hpb=fa5a63b28f0b56be4258b4b08d1f30fc4f08d602;p=tpg%2Fopendispense2.git diff --git a/src/cokebank_basic/main.c b/src/cokebank_basic/main.c index 4a5afb3..0e7956a 100644 --- a/src/cokebank_basic/main.c +++ b/src/cokebank_basic/main.c @@ -3,6 +3,7 @@ * UCC (University [of WA] Computer Club) Electronic Accounting System * * cokebank.c - Coke-Bank management + * > Simple custom database format (uses PAM for usernames) * * This file is licenced under the 3-clause BSD Licence. See the file COPYING * for full details. @@ -33,23 +34,29 @@ #define HACK_TPG_NOAUTH 1 #define HACK_ROOT_NOAUTH 1 +#define indexof(array, ent) (((intptr_t)(ent)-(intptr_t)(array))/sizeof((array)[0])) + +// === TYPES === +struct sAcctIterator +{ + int CurUser; + + int Sort; + + int MinBalance; + int MaxBalance; + + int FlagMask; + int FlagValue; +}; + // === PROTOTYPES === -void Init_Cokebank(const char *Argument); static int Bank_int_ReadDatabase(void); static int Bank_int_WriteEntry(int ID); - int Bank_Transfer(int SourceUser, int DestUser, int Ammount, const char *Reason); - int Bank_CreateUser(const char *Username); - int Bank_GetMaxID(void); - int Bank_GetUserID(const char *Username); - int Bank_GetBalance(int User); - int Bank_GetFlags(int User); - int Bank_SetFlags(int User, int Mask, int Value); int Bank_int_AlterUserBalance(int ID, int Delta); int Bank_int_GetMinAllowedBalance(int ID); int Bank_int_AddUser(const char *Username); -char *Bank_GetUserName(int User); int Bank_int_GetUnixID(const char *Username); - int Bank_GetUserAuth(const char *Salt, const char *Username, const char *PasswordString); #if USE_LDAP char *ReadLDAPValue(const char *Filter, char *Value); #endif @@ -64,12 +71,14 @@ LDAP *gpLDAP; tUser *gaBank_Users; int giBank_NumUsers; FILE *gBank_File; +tUser **gaBank_UsersByName; +tUser **gaBank_UsersByBalance; // === CODE === -/** +/* * \brief Load the cokebank database */ -void Init_Cokebank(const char *Argument) +int Bank_Initialise(const char *Argument) { #if USE_LDAP int rv; @@ -78,7 +87,10 @@ void Init_Cokebank(const char *Argument) // Open Cokebank gBank_File = fopen(Argument, "rb+"); if( !gBank_File ) gBank_File = fopen(Argument, "wb+"); - if( !gBank_File ) perror("Opening coke bank"); + if( !gBank_File ) { + perror("Opening coke bank"); + return -1; + } Bank_int_ReadDatabase(); // Open log file @@ -92,19 +104,19 @@ void Init_Cokebank(const char *Argument) rv = ldap_create(&gpLDAP); if(rv) { fprintf(stderr, "ldap_create: %s\n", ldap_err2string(rv)); - exit(1); + return 1; } rv = ldap_initialize(&gpLDAP, gsLDAPPath); if(rv) { fprintf(stderr, "ldap_initialize: %s\n", ldap_err2string(rv)); - exit(1); + return 1; } { int ver = LDAP_VERSION3; ldap_set_option(gpLDAP, LDAP_OPT_PROTOCOL_VERSION, &ver); } # if 0 rv = ldap_start_tls_s(gpLDAP, NULL, NULL); if(rv) { fprintf(stderr, "ldap_start_tls_s: %s\n", ldap_err2string(rv)); - exit(1); + return 1; } # endif { @@ -116,24 +128,68 @@ void Init_Cokebank(const char *Argument) "", &cred, NULL, NULL, &servcred); if(rv) { fprintf(stderr, "ldap_start_tls_s: %s\n", ldap_err2string(rv)); - exit(1); + return 1; } } #endif + + return 0; +} + +/** + * \brief Name compare function for qsort + */ +static int Bank_int_CompareNames(const void *Ent1, const void *Ent2) +{ + const tUser *user1 = *(const tUser**)Ent1; + const tUser *user2 = *(const tUser**)Ent2; + + return strcmp(user1->Name, user2->Name); +} + +/** + * \brief Name compare function for qsort + */ +static int Bank_int_CompareBalance(const void *Ent1, const void *Ent2) +{ + const tUser *user1 = *(const tUser**)Ent1; + const tUser *user2 = *(const tUser**)Ent2; + + return user1->Balance - user2->Balance; } #if 1 static int Bank_int_ReadDatabase(void) { + int i; if( gaBank_Users ) return 1; // Get size fseek(gBank_File, 0, SEEK_END); - giBank_NumUsers = ftell(gBank_File) / sizeof(gaBank_Users[0]); + giBank_NumUsers = ftell(gBank_File) / sizeof(tFileUser); fseek(gBank_File, 0, SEEK_SET); + + // Allocate structures + gaBank_Users = malloc( giBank_NumUsers * sizeof(tUser) ); + gaBank_UsersByName = malloc( giBank_NumUsers * sizeof(tUser*) ); + gaBank_UsersByBalance = malloc( giBank_NumUsers * sizeof(tUser*) ); // Read data - gaBank_Users = malloc( giBank_NumUsers * sizeof(gaBank_Users[0]) ); - fread(gaBank_Users, sizeof(gaBank_Users[0]), giBank_NumUsers, gBank_File); + for( i = 0; i < giBank_NumUsers; i ++ ) + { + tFileUser fu; + fread(&fu, sizeof(tFileUser), 1, gBank_File); + gaBank_Users[i].Name = NULL; + gaBank_Users[i].UnixID = fu.UnixID; + gaBank_Users[i].Balance = fu.Balance; + gaBank_Users[i].Flags = fu.Flags; + gaBank_Users[i].Name = Bank_GetAcctName(i); + gaBank_UsersByName[i] = &gaBank_Users[i]; // Add to name index + gaBank_UsersByBalance[i] = &gaBank_Users[i]; // Add to balance index + } + + // Sort indexes + qsort(gaBank_UsersByName, giBank_NumUsers, sizeof(tUser*), Bank_int_CompareNames); + qsort(gaBank_UsersByBalance, giBank_NumUsers, sizeof(tUser*), Bank_int_CompareBalance); return 0; } @@ -150,25 +206,30 @@ static int Bank_int_ReadDatabase(void) { fgets(buf, BUFSIZ-1, gBank_File); } - #endif } #endif static int Bank_int_WriteEntry(int ID) { + tFileUser fu; if( ID < 0 || ID >= giBank_NumUsers ) { return -1; } // Commit to file - fseek(gBank_File, ID*sizeof(gaBank_Users[0]), SEEK_SET); - fwrite(&gaBank_Users[ID], sizeof(gaBank_Users[0]), 1, gBank_File); + fseek(gBank_File, ID*sizeof(fu), SEEK_SET); + + fu.UnixID = gaBank_Users[ID].UnixID; + fu.Balance = gaBank_Users[ID].Balance; + fu.Flags = gaBank_Users[ID].Flags; + + fwrite(&fu, sizeof(fu), 1, gBank_File); return 0; } -/** - * \brief Transfers money from one user to another +/* + * Transfers money from one user to another * \param SourceUser Source user * \param DestUser Destination user * \param Ammount Ammount of cents to move from \a SourceUser to \a DestUser @@ -192,28 +253,122 @@ int Bank_Transfer(int SourceUser, int DestUser, int Ammount, const char *Reason) return 0; } -int Bank_CreateUser(const char *Username) +int Bank_CreateAcct(const char *Name) { int ret; - ret = Bank_GetUserID(Username); + ret = Bank_GetAcctByName(Name); if( ret != -1 ) return -1; - return Bank_int_AddUser(Username); + return Bank_int_AddUser(Name); +} + +tAcctIterator *Bank_Iterator(int FlagMask, int FlagValues, int Flags, int MinMaxBalance, time_t LastSeen) +{ + tAcctIterator *ret; + + ret = calloc( 1, sizeof(tAcctIterator) ); + if( !ret ) + return NULL; + ret->MinBalance = INT_MIN; + ret->MaxBalance = INT_MAX; + + ret->FlagMask = FlagMask; + ret->FlagValue = FlagValues & FlagMask; + + if(Flags & BANK_ITFLAG_MINBALANCE) + ret->MinBalance = MinMaxBalance; + if(Flags & BANK_ITFLAG_MAXBALANCE) + ret->MaxBalance = MinMaxBalance; + + ret->Sort = Flags & (BANK_ITFLAG_SORTMASK|BANK_ITFLAG_REVSORT); + + // Shut up GCC + LastSeen = 0; + + //if(Flags & BANK_ITFLAG_SEENBEFORE) + // ret->MinBalance = MinMaxBalance; + //if(Flags & BANK_ITFLAG_SEENAFTER) + // ret->MinBalance = MinMaxBalance; + + return ret; +} + +int Bank_IteratorNext(tAcctIterator *It) +{ + int ret; + + while(It->CurUser < giBank_NumUsers) + { + switch(It->Sort) + { + case BANK_ITFLAG_SORT_NONE: + case BANK_ITFLAG_SORT_NONE | BANK_ITFLAG_REVSORT: + ret = It->CurUser; + break; + case BANK_ITFLAG_SORT_NAME: + ret = indexof(gaBank_Users, gaBank_UsersByName[It->CurUser]); + break; + case BANK_ITFLAG_SORT_NAME | BANK_ITFLAG_REVSORT: + ret = indexof(gaBank_Users, gaBank_UsersByName[giBank_NumUsers-It->CurUser]); + break; + case BANK_ITFLAG_SORT_BAL: + ret = indexof(gaBank_Users, gaBank_UsersByBalance[It->CurUser]); + printf("Sort by balance (ret = %i)\n", ret); + break; + case BANK_ITFLAG_SORT_BAL | BANK_ITFLAG_REVSORT: + ret = indexof(gaBank_Users, gaBank_UsersByBalance[giBank_NumUsers-It->CurUser]); + break; + default: + fprintf(stderr, "BUG: Unsupported sort in Bank_IteratorNext\n"); + return -1; + } + It->CurUser ++; + + if( gaBank_Users[ret].Balance < It->MinBalance ) + continue; + if( gaBank_Users[ret].Balance > It->MaxBalance ) + continue; + if( (gaBank_Users[ret].Flags & It->FlagMask) != It->FlagValue ) + continue; + + return ret; + } + return -1; } -int Bank_GetMaxID(void) +void Bank_DelIterator(tAcctIterator *It) { - return giBank_NumUsers; + free(It); } -/** +/* * \brief Get the User ID of the named user */ -int Bank_GetUserID(const char *Username) -{ +int Bank_GetAcctByName(const char *Username) +{ + #if 0 + int i, size; + i = giBank_NumUsers / 2; + size = giBank_NumUsers; + for(;;) + { + cmp = strcmp(gaBank_UsersByName[i]->Name, Username); + if( cmp == 0 ) + return indexof(gaBank_Users, gaBank_UsersByName[i]; + + // Not found + if( size == 0 ) + return -1; + + if( cmp < 0 ) + i += size; + else + i -= size; + size /= 2; + } + #else int i, uid; - uid = Bank_int_GetUnixID(Username); // Expensive search :( @@ -222,6 +377,7 @@ int Bank_GetUserID(const char *Username) if( gaBank_Users[i].UnixID == uid ) return i; } + #endif return -1; } @@ -241,7 +397,7 @@ int Bank_GetFlags(int ID) // root if( gaBank_Users[ID].UnixID == 0 ) { - gaBank_Users[ID].Flags |= USER_FLAG_WHEEL|USER_FLAG_COKE; + gaBank_Users[ID].Flags |= USER_FLAG_ADMIN|USER_FLAG_COKE; } #if USE_UNIX_GROUPS @@ -268,17 +424,19 @@ int Bank_GetFlags(int ID) } } + #if 0 // Check for additions to the "wheel" group grp = getgrnam("wheel"); if( grp ) { for( i = 0; grp->gr_mem[i]; i ++ ) { if( strcmp(grp->gr_mem[i], pwd->pw_name) == 0 ) { - gaBank_Users[ID].Flags |= USER_FLAG_WHEEL; + gaBank_Users[ID].Flags |= USER_FLAG_ADMIN; break ; } } } + #endif } #endif @@ -329,7 +487,7 @@ int Bank_int_GetMinAllowedBalance(int ID) return INT_MIN; // Wheel is allowed to go to -$100 - if( (flags & USER_FLAG_WHEEL) ) + if( (flags & USER_FLAG_ADMIN) ) return -10000; // Coke is allowed to go to -$20 @@ -340,8 +498,8 @@ int Bank_int_GetMinAllowedBalance(int ID) return 0; } -/** - * \brief Create a new user in our database +/* + * Create a new user in our database */ int Bank_int_AddUser(const char *Username) { @@ -349,15 +507,28 @@ int Bank_int_AddUser(const char *Username) int uid = Bank_int_GetUnixID(Username); // Can has moar space plz? + // - Structures tmp = realloc(gaBank_Users, (giBank_NumUsers+1)*sizeof(gaBank_Users[0])); if( !tmp ) return -1; gaBank_Users = tmp; + // - Name index + tmp = realloc(gaBank_UsersByName, (giBank_NumUsers+1)*sizeof(tUser*)); + if( !tmp ) return -1; + gaBank_UsersByName = tmp; + // - Balance index + tmp = realloc(gaBank_UsersByBalance, (giBank_NumUsers+1)*sizeof(tUser*)); + if( !tmp ) return -1; + gaBank_UsersByBalance = tmp; // Crete new user + gaBank_Users[giBank_NumUsers].Name = NULL; gaBank_Users[giBank_NumUsers].UnixID = uid; gaBank_Users[giBank_NumUsers].Balance = 0; gaBank_Users[giBank_NumUsers].Flags = 0; + gaBank_UsersByName[giBank_NumUsers] = &gaBank_Users[giBank_NumUsers]; + gaBank_UsersByBalance[giBank_NumUsers] = &gaBank_Users[giBank_NumUsers]; + // Set default flags if( strcmp(Username, COKEBANK_DEBT_ACCT) == 0 ) { gaBank_Users[giBank_NumUsers].Flags = USER_FLAG_INTERNAL; } @@ -365,12 +536,20 @@ int Bank_int_AddUser(const char *Username) gaBank_Users[giBank_NumUsers].Flags = USER_FLAG_INTERNAL; } else if( strcmp(Username, "root") == 0 ) { - gaBank_Users[giBank_NumUsers].Flags = USER_FLAG_WHEEL|USER_FLAG_COKE; + gaBank_Users[giBank_NumUsers].Flags = USER_FLAG_ADMIN|USER_FLAG_COKE; } // Increment count giBank_NumUsers ++; + // Get name + gaBank_Users[giBank_NumUsers-1].Name = Bank_GetAcctName(giBank_NumUsers-1); + + // Update indexes + qsort(gaBank_UsersByName, giBank_NumUsers, sizeof(tUser*), Bank_int_CompareNames); + qsort(gaBank_UsersByBalance, giBank_NumUsers, sizeof(tUser*), Bank_int_CompareBalance); + + // Save Bank_int_WriteEntry(giBank_NumUsers - 1); return 0; @@ -380,16 +559,17 @@ int Bank_int_AddUser(const char *Username) // Unix user dependent code // TODO: Modify to keep its own list of usernames // --- -/** - * \brief Return the name the passed user - */ -char *Bank_GetUserName(int ID) +char *Bank_GetAcctName(int ID) { struct passwd *pwd; if( ID < 0 || ID >= giBank_NumUsers ) return NULL; + if( gaBank_Users[ID].Name ) { + return strdup(gaBank_Users[ID].Name); + } + if( gaBank_Users[ID].UnixID == -1 ) return strdup(COKEBANK_SALES_ACCT); @@ -423,11 +603,10 @@ int Bank_int_GetUnixID(const char *Username) } -/** - * \brief Authenticate a user - * \return User ID, or -1 if authentication failed +/* + * Authenticate a user */ -int Bank_GetUserAuth(const char *Salt, const char *Username, const char *PasswordString) +int Bank_GetUserAuth(const char *Salt, const char *Username, const char *Password) { #if USE_LDAP uint8_t hash[20]; @@ -439,28 +618,28 @@ int Bank_GetUserAuth(const char *Salt, const char *Username, const char *Passwor #endif #if 1 - // Only here to shut GCC up (until password auth is implemented + // Only here to shut GCC up (until password auth is implemented) if( Salt == NULL ) return -1; - if( PasswordString == NULL ) + if( Password == NULL ) return -1; #endif #if HACK_TPG_NOAUTH if( strcmp(Username, "tpg") == 0 ) - return Bank_GetUserID("tpg"); + return Bank_GetAcctByName("tpg"); #endif #if HACK_ROOT_NOAUTH if( strcmp(Username, "root") == 0 ) { - int ret = Bank_GetUserID("root"); + int ret = Bank_GetAcctByName("root"); if( ret == -1 ) - return Bank_CreateUser("root"); + return Bank_CreateAcct("root"); return ret; } #endif #if USE_LDAP - HexBin(hash, 20, PasswordString); + HexBin(hash, 20, Password); // Build string to hash strcpy(input, Username);