From: John Hodge Date: Wed, 11 Jul 2012 14:31:53 +0000 (+0800) Subject: Server - Implimented pins in server code X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=41f3be929beabdc4080b4dbd3626122aac452adb;p=tpg%2Fopendispense2.git Server - Implimented pins in server code --- diff --git a/src/cokebank.h b/src/cokebank.h index c3c7c6f..13d0bb5 100644 --- a/src/cokebank.h +++ b/src/cokebank.h @@ -180,6 +180,21 @@ extern void Bank_DelIterator(tAcctIterator *It); */ extern int Bank_GetUserAuth(const char *Salt, const char *Username, const char *Password); +/** + * \brief Checks the validity of a pin against a username + * \param AcctID Account ID + * \param Pin Integer version of the pin + * \return Boolean correct + */ +extern int Bank_IsPinValid(int AcctID, int Pin); + +/** + * \brief Update a user's pin + * \param AcctID Account ID + * \param NewPin New pin for the account + */ +extern void Bank_SetPin(int AcctID, int NewPin); + /** * \brief Get an account ID from a MIFARE card ID * \param CardID MIFARE card ID diff --git a/src/cokebank_sqlite/main.c b/src/cokebank_sqlite/main.c index 34761b2..464cee3 100644 --- a/src/cokebank_sqlite/main.c +++ b/src/cokebank_sqlite/main.c @@ -63,6 +63,8 @@ struct sAcctIterator // Unused really, just used as a void type int Bank_SetFlags(int AcctID, int Mask, int Value); int Bank_GetBalance(int AcctID); char *Bank_GetAcctName(int AcctID); + int Bank_IsPinValid(int AcctID, int Pin); +void Bank_SetPin(int AcctID, int Pin); sqlite3_stmt *Bank_int_MakeStatemnt(sqlite3 *Database, const char *Query); int Bank_int_QueryNone(sqlite3 *Database, const char *Query, char **ErrorMessage); sqlite3_stmt *Bank_int_QuerySingle(sqlite3 *Database, const char *Query); @@ -354,6 +356,34 @@ int Bank_CreateAcct(const char *Name) return sqlite3_last_insert_rowid(gBank_Database); } +int Bank_IsPinValid(int AcctID, int Pin) +{ + char *query = mkstr("SELECT acct_id FROM accounts WHERE acct_id=%i AND acct_pin=%i LIMIT 1", AcctID, Pin); + sqlite3_stmt *statement = Bank_int_QuerySingle(gBank_Database, query); + free(query); + + if( statement ) { + sqlite3_finalize(statement); + } + + return (statement != NULL); +} + +void Bank_SetPin(int AcctID, int Pin) +{ + char *errmsg; + char *query = mkstr("UPDATE accounts SET acct_pin=%i WHERE acct_id=%i", Pin, AcctID); + int rv = Bank_int_QueryNone(gBank_Database, query, &errmsg); + if( rv != SQLITE_OK ) + { + fprintf(stderr, "Bank_CreateAcct - SQLite Error: '%s'\n", errmsg); + fprintf(stderr, "Query = '%s'\n", query); + sqlite3_free(errmsg); + free(query); + return ; + } + free(query); +} /* * Create an iterator for user accounts */ diff --git a/src/server/main.c b/src/server/main.c index 20520fc..6c2f691 100644 --- a/src/server/main.c +++ b/src/server/main.c @@ -54,6 +54,8 @@ void sigint_handler() void PrintUsage(const char *progname) { fprintf(stderr, "Usage: %s\n", progname); + fprintf(stderr, " -f,--configfile\n"); + fprintf(stderr, " Set the config file path (default `dispsrv.conf')\n"); fprintf(stderr, " -d Set debug level (0 - 2, default 0)\n"); fprintf(stderr, " --[dont-]daemonise\n"); fprintf(stderr, " Run (or explicitly don't run) the server disconnected from the terminal\n"); @@ -83,6 +85,7 @@ int main(int argc, char *argv[]) break; default: // Usage Error + fprintf(stderr, "Unknown option '-%c'\n", arg[1]); PrintUsage(argv[0]); return -1; } @@ -101,6 +104,7 @@ int main(int argc, char *argv[]) } else { // Usage error + fprintf(stderr, "Unknown option '%s'\n", arg); PrintUsage(argv[0]); return -1; } diff --git a/src/server/server.c b/src/server/server.c index 9780058..9bf9eba 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -21,6 +21,7 @@ #include // Signal handling #include // AUTHIDENT #include // time(2) +#include #define DEBUG_TRACE_CLIENT 0 #define HACK_NO_REFUNDS 1 @@ -82,6 +83,8 @@ void _SendUserInfo(tClient *Client, int UserID); void Server_Cmd_USERADD(tClient *Client, char *Args); void Server_Cmd_USERFLAGS(tClient *Client, char *Args); void Server_Cmd_UPDATEITEM(tClient *Client, char *Args); +void Server_Cmd_PINCHECK(tClient *Client, char *Args); +void Server_Cmd_PINSET(tClient *Client, char *Args); // --- Helpers --- void Debug(tClient *Client, const char *Format, ...); int sendf(int Socket, const char *Format, ...); @@ -111,7 +114,9 @@ const struct sClientCommand { {"USER_INFO", Server_Cmd_USERINFO}, {"USER_ADD", Server_Cmd_USERADD}, {"USER_FLAGS", Server_Cmd_USERFLAGS}, - {"UPDATE_ITEM", Server_Cmd_UPDATEITEM} + {"UPDATE_ITEM", Server_Cmd_UPDATEITEM}, + {"PIN_CHECK", Server_Cmd_PINCHECK}, + {"PIN_SET", Server_Cmd_PINSET} }; #define NUM_COMMANDS ((int)(sizeof(gaServer_Commands)/sizeof(gaServer_Commands[0]))) @@ -1540,6 +1545,95 @@ void Server_Cmd_UPDATEITEM(tClient *Client, char *Args) } } +void Server_Cmd_PINCHECK(tClient *Client, char *Args) +{ + char *username, *pinstr; + int pin; + + if( Server_int_ParseArgs(0, Args, &username, &pinstr, NULL) ) { + sendf(Client->Socket, "407 PIN_CHECK takes 2 arguments\n"); + return ; + } + + if( !isdigit(pinstr[0]) || !isdigit(pinstr[1]) || !isdigit(pinstr[2]) || !isdigit(pinstr[3]) || pinstr[4] != '\0' ) { + sendf(Client->Socket, "407 PIN should be four digits\n"); + return ; + } + pin = atoi(pinstr); + + // Not strictly needed, but ensures that randoms don't do brute forcing + if( !Client->bIsAuthed ) { + sendf(Client->Socket, "401 Not Authenticated\n"); + return ; + } + + // Check user permissions + if( !(Bank_GetFlags(Client->UID) & (USER_FLAG_COKE|USER_FLAG_ADMIN)) ) { + sendf(Client->Socket, "403 Not in coke\n"); + return ; + } + + // Get user + int uid = Bank_GetAcctByName(username, 0); + if( uid == -1 ) { + sendf(Client->Socket, "404 User '%s' not found\n", username); + return ; + } + + // Get the pin + static time_t last_wrong_pin_time; + static int backoff = 1; + if( time(NULL) - last_wrong_pin_time < backoff ) { + sendf(Client->Socket, "407 Rate limited (%i seconds remaining)\n", + backoff - (time(NULL) - last_wrong_pin_time)); + return ; + } + last_wrong_pin_time = time(NULL); + if( !Bank_IsPinValid(uid, pin) ) + { + sendf(Client->Socket, "403 Pin incorrect\n"); + if( backoff < 5) + backoff ++; + return ; + } + + last_wrong_pin_time = 0; + backoff = 1; + sendf(Client->Socket, "200 Pin correct\n"); + return ; +} +void Server_Cmd_PINSET(tClient *Client, char *Args) +{ + char *pinstr; + int pin; + + + if( Server_int_ParseArgs(0, Args, &pinstr, NULL) ) { + sendf(Client->Socket, "407 PIN_SET takes 2 arguments\n"); + return ; + } + + if( !isdigit(pinstr[0]) || !isdigit(pinstr[1]) || !isdigit(pinstr[2]) || !isdigit(pinstr[3]) || pinstr[4] != '\0' ) { + sendf(Client->Socket, "407 PIN should be four digits\n"); + return ; + } + pin = atoi(pinstr); + + // Not strictly needed, but ensures that randoms don't do brute forcing + if( !Client->bIsAuthed ) { + sendf(Client->Socket, "401 Not Authenticated\n"); + return ; + } + + int uid = Client->EffectiveUID; + if(uid == -1) + uid = Client->UID; + // Can only pinset yourself (well, the effective user) + Bank_SetPin(uid, pin); + sendf(Client->Socket, "200 Pin updated\n"); + return ; +} + // --- INTERNAL HELPERS --- void Debug(tClient *Client, const char *Format, ...) { @@ -1716,3 +1810,4 @@ int Server_int_ParseFlags(tClient *Client, const char *Str, int *Mask, int *Valu return 0; } +