/** * \brief Set effective user */ void Server_Cmd_SETEUSER(tClient *Client, char *Args) { char *username; int eUserFlags, userFlags; if( Server_int_ParseArgs(0, Args, &username, NULL) ) { sendf(Client->Socket, "407 SETEUSER takes 1 argument\n"); return ; } if( !strlen(Args) ) { sendf(Client->Socket, "407 SETEUSER expects an argument\n"); return ; } // Check authentication if( !Client->bIsAuthed ) { sendf(Client->Socket, "401 Not Authenticated\n"); return ; } // Check user permissions userFlags = Bank_GetFlags(Client->UID); if( !(userFlags & (USER_FLAG_COKE|USER_FLAG_ADMIN)) ) { sendf(Client->Socket, "403 Not in coke\n"); return ; } // Set id Client->EffectiveUID = Bank_GetAcctByName(username, 0); if( Client->EffectiveUID == -1 ) { sendf(Client->Socket, "404 User not found\n"); return ; } // You can't be an internal account (unless you're an admin) if( !(userFlags & USER_FLAG_ADMIN) ) { eUserFlags = Bank_GetFlags(Client->EffectiveUID); if( eUserFlags & USER_FLAG_INTERNAL ) { Client->EffectiveUID = -1; sendf(Client->Socket, "404 User not found\n"); return ; } } // Disabled accounts // - If disabled and the actual user is not an admin (and not root) // return 403 if( (eUserFlags & USER_FLAG_DISABLED) && (Client->UID == 0 || !(userFlags & USER_FLAG_ADMIN)) ) { Client->EffectiveUID = -1; sendf(Client->Socket, "403 Account disabled\n"); return ; } sendf(Client->Socket, "200 User set\n"); }
/** * \brief Authenticate as a user * * Usage: PASS <hash> */ void Server_Cmd_PASS(tClient *Client, char *Args) { char *passhash; int flags; if( Server_int_ParseArgs(0, Args, &passhash, NULL) ) { sendf(Client->Socket, "407 PASS takes 1 argument\n"); return ; } // Pass on to cokebank Client->UID = Bank_GetUserAuth(Client->Salt, Client->Username, passhash); if( Client->UID == -1 ) { sendf(Client->Socket, "401 Auth Failure\n"); return ; } flags = Bank_GetFlags(Client->UID); if( flags & USER_FLAG_DISABLED ) { Client->UID = -1; sendf(Client->Socket, "403 Account Disabled\n"); return ; } if( flags & USER_FLAG_INTERNAL ) { Client->UID = -1; sendf(Client->Socket, "403 Internal account\n"); return ; } Client->bIsAuthed = 1; sendf(Client->Socket, "200 Auth OK\n"); }
void _SendUserInfo(tClient *Client, int UserID) { char *type, *disabled="", *door=""; int flags = Bank_GetFlags(UserID); if( flags & USER_FLAG_INTERNAL ) { type = "internal"; } else if( flags & USER_FLAG_COKE ) { if( flags & USER_FLAG_ADMIN ) type = "coke,admin"; else type = "coke"; } else if( flags & USER_FLAG_ADMIN ) { type = "admin"; } else { type = "user"; } if( flags & USER_FLAG_DISABLED ) disabled = ",disabled"; if( flags & USER_FLAG_DOORGROUP ) door = ",door"; // TODO: User flags/type sendf( Client->Socket, "202 User %s %i %s%s%s\n", Bank_GetAcctName(UserID), Bank_GetBalance(UserID), type, disabled, door ); }
/** * \brief Authenticate as a user without a password * * Usage: AUTOAUTH <user> */ void Server_Cmd_AUTOAUTH(tClient *Client, char *Args) { char *username; int userflags; if( Server_int_ParseArgs(0, Args, &username, NULL) ) { sendf(Client->Socket, "407 AUTOAUTH takes 1 argument\n"); return ; } // Check if trusted if( !Client->bCanAutoAuth ) { if(giDebugLevel) Debug(Client, "Untrusted client attempting to AUTOAUTH"); sendf(Client->Socket, "401 Untrusted\n"); return ; } // Get UID Client->UID = Bank_GetAcctByName( username, 0 ); if( Client->UID < 0 ) { if(giDebugLevel) Debug(Client, "Unknown user '%s'", username); sendf(Client->Socket, "403 Auth Failure\n"); return ; } userflags = Bank_GetFlags(Client->UID); // You can't be an internal account if( userflags & USER_FLAG_INTERNAL ) { if(giDebugLevel) Debug(Client, "Autoauth as '%s', not allowed", username); Client->UID = -1; sendf(Client->Socket, "403 Account is internal\n"); return ; } // Disabled accounts if( userflags & USER_FLAG_DISABLED ) { Client->UID = -1; sendf(Client->Socket, "403 Account disabled\n"); return ; } // Save username if(Client->Username) free(Client->Username); Client->Username = strdup(username); Client->bIsAuthed = 1; if(giDebugLevel) Debug(Client, "Auto authenticated as '%s' (%i)", username, Client->UID); sendf(Client->Socket, "200 Auth OK\n"); }
void Server_Cmd_USERFLAGS(tClient *Client, char *Args) { char *username, *flags, *reason=NULL; int mask=0, value=0; int uid; // Parse arguments if( Server_int_ParseArgs(1, Args, &username, &flags, &reason, NULL) ) { if( !flags ) { sendf(Client->Socket, "407 USER_FLAGS takes at least 2 arguments\n"); return ; } reason = ""; } // Check authentication if( !Client->bIsAuthed ) { sendf(Client->Socket, "401 Not Authenticated\n"); return ; } // Check permissions if( !(Bank_GetFlags(Client->UID) & USER_FLAG_ADMIN) ) { sendf(Client->Socket, "403 Not a coke admin\n"); return ; } // Get UID uid = Bank_GetAcctByName(username, 0); if( uid == -1 ) { sendf(Client->Socket, "404 User '%s' not found\n", username); return ; } // Parse flags if( Server_int_ParseFlags(Client, flags, &mask, &value) ) return ; if( giDebugLevel ) Debug(Client, "Set %i(%s) flags to %x (masked %x)\n", uid, username, mask, value); // Apply flags Bank_SetFlags(uid, mask, value); // Log the change Log_Info("Updated '%s' with flag set '%s' by '%s' - Reason: %s", username, flags, Client->Username, reason); // Return OK sendf(Client->Socket, "200 User Updated\n"); }
void Server_Cmd_SET(tClient *Client, char *Args) { char *user, *ammount, *reason; int uid, iAmmount; // Parse arguments if( Server_int_ParseArgs(1, Args, &user, &ammount, &reason, NULL) ) { sendf(Client->Socket, "407 SET takes 3 arguments\n"); return ; } if( !Client->bIsAuthed ) { sendf(Client->Socket, "401 Not Authenticated\n"); return ; } // Check user permissions if( !(Bank_GetFlags(Client->UID) & USER_FLAG_ADMIN) ) { sendf(Client->Socket, "403 Not an admin\n"); return ; } // Get recipient uid = Bank_GetAcctByName(user, 0); if( uid == -1 ) { sendf(Client->Socket, "404 Invalid user\n"); return ; } // Parse ammount iAmmount = atoi(ammount); if( iAmmount == 0 && ammount[0] != '0' ) { sendf(Client->Socket, "407 Invalid Argument\n"); return ; } int origBalance, rv; // Do give switch( rv = DispenseSet(Client->UID, uid, iAmmount, reason, &origBalance) ) { case 0: sendf(Client->Socket, "200 Add OK (%i)\n", origBalance); return ; default: sendf(Client->Socket, "500 Unknown error (%i)\n", rv); return ; } }
/** * \brief Refund an item to a user * * Usage: REFUND <user> <item id> [<price>] */ void Server_Cmd_REFUND(tClient *Client, char *Args) { tItem *item; int uid, price_override = 0; char *username, *itemname, *price_str; if( Server_int_ParseArgs(0, Args, &username, &itemname, &price_str, NULL) ) { if( !itemname || price_str ) { sendf(Client->Socket, "407 REFUND takes 2 or 3 arguments\n"); return ; } } 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 ; } uid = Bank_GetAcctByName(username, 0); if( uid == -1 ) { sendf(Client->Socket, "404 Unknown user\n"); return ; } item = _GetItemFromString(itemname); if( !item ) { sendf(Client->Socket, "406 Bad Item ID\n"); return ; } if( price_str ) price_override = atoi(price_str); switch( DispenseRefund( Client->UID, uid, item, price_override ) ) { case 0: sendf(Client->Socket, "200 Item Refunded\n"); return ; default: sendf(Client->Socket, "500 Dispense Error\n"); return; } }
void Server_Cmd_UPDATEITEM(tClient *Client, char *Args) { char *itemname, *price_str, *description; int price; tItem *item; if( Server_int_ParseArgs(1, Args, &itemname, &price_str, &description, NULL) ) { sendf(Client->Socket, "407 UPDATE_ITEM takes 3 arguments\n"); return ; } 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 ; } item = _GetItemFromString(itemname); if( !item ) { // TODO: Create item? sendf(Client->Socket, "406 Bad Item ID\n"); return ; } price = atoi(price_str); if( price <= 0 && price_str[0] != '0' ) { sendf(Client->Socket, "407 Invalid price set\n"); } switch( DispenseUpdateItem( Client->UID, item, description, price ) ) { case 0: // Return OK sendf(Client->Socket, "200 Item updated\n"); break; default: break; } }
int Bank_int_GetMinAllowedBalance(int ID) { int flags; if( ID < 0 || ID >= giBank_NumUsers ) return 0; flags = Bank_GetFlags(ID); // Internal accounts have no limit if( (flags & USER_FLAG_INTERNAL) ) return INT_MIN; // Wheel is allowed to go to -$100 if( (flags & USER_FLAG_ADMIN) ) return -10000; // Coke is allowed to go to -$20 if( (flags & USER_FLAG_COKE) ) return -2000; // For everyone else, no negative return 0; }
void Server_Cmd_USERADD(tClient *Client, char *Args) { char *username; // Parse arguments if( Server_int_ParseArgs(0, Args, &username, NULL) ) { sendf(Client->Socket, "407 USER_ADD takes 1 argument\n"); return ; } // Check authentication if( !Client->bIsAuthed ) { sendf(Client->Socket, "401 Not Authenticated\n"); return ; } // Check permissions if( !(Bank_GetFlags(Client->UID) & USER_FLAG_ADMIN) ) { sendf(Client->Socket, "403 Not a coke admin\n"); return ; } // Try to create user if( Bank_CreateAcct(username) == -1 ) { sendf(Client->Socket, "404 User exists\n"); return ; } { char *thisName = Bank_GetAcctName(Client->UID); Log_Info("Account '%s' created by '%s'", username, thisName); free(thisName); } sendf(Client->Socket, "200 User Added\n"); }
/** * \brief Authenticate as a user using the IDENT protocol * * Usage: AUTHIDENT */ void Server_Cmd_AUTHIDENT(tClient *Client, char *Args) { char *username; int userflags; const int ident_timeout = 5; if( Args != NULL && strlen(Args) ) { sendf(Client->Socket, "407 AUTHIDENT takes no arguments\n"); return ; } // Check if trusted if( !Client->bTrustedHost ) { if(giDebugLevel) Debug(Client, "Untrusted client attempting to AUTHIDENT"); sendf(Client->Socket, "401 Untrusted\n"); return ; } // Get username via IDENT username = ident_id(Client->Socket, ident_timeout); if( !username ) { perror("AUTHIDENT - IDENT timed out"); sendf(Client->Socket, "403 Authentication failure: IDENT auth timed out\n"); return ; } // Get UID Client->UID = Bank_GetAcctByName( username, 0 ); if( Client->UID < 0 ) { if(giDebugLevel) Debug(Client, "Unknown user '%s'", username); sendf(Client->Socket, "403 Authentication failure: unknown account\n"); free(username); return ; } userflags = Bank_GetFlags(Client->UID); // You can't be an internal account if( userflags & USER_FLAG_INTERNAL ) { if(giDebugLevel) Debug(Client, "IDENT auth as '%s', not allowed", username); Client->UID = -1; sendf(Client->Socket, "403 Authentication failure: that account is internal\n"); free(username); return ; } // Disabled accounts if( userflags & USER_FLAG_DISABLED ) { Client->UID = -1; sendf(Client->Socket, "403 Authentication failure: account disabled\n"); free(username); return ; } // Save username if(Client->Username) free(Client->Username); Client->Username = strdup(username); Client->bIsAuthed = 1; if(giDebugLevel) Debug(Client, "IDENT authenticated as '%s' (%i)", username, Client->UID); free(username); sendf(Client->Socket, "200 Auth OK\n"); }
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 authenticated? go away! if( !Client->bIsAuthed ) { sendf(Client->Socket, "401 Not Authenticated\n"); return ; } // Get user int uid = Bank_GetAcctByName(username, 0); if( uid == -1 ) { sendf(Client->Socket, "404 User '%s' not found\n", username); return ; } // Check user permissions if( uid != Client->UID && !(Bank_GetFlags(Client->UID) & (USER_FLAG_COKE|USER_FLAG_ADMIN)) ) { sendf(Client->Socket, "403 Not in coke\n"); 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, "201 Pin incorrect\n"); struct sockaddr_storage addr; socklen_t len = sizeof(addr); char ipstr[INET6_ADDRSTRLEN]; getpeername(Client->Socket, (void*)&addr, &len); struct sockaddr_in *s = (struct sockaddr_in *)&addr; inet_ntop(addr.ss_family, &s->sin_addr, ipstr, sizeof(ipstr)); Debug_Notice("Bad pin from %s for %s by %i", ipstr, username, Client->UID); if( backoff < 5) backoff ++; return ; } last_wrong_pin_time = 0; backoff = 1; sendf(Client->Socket, "200 Pin correct\n"); return ; }
void Server_Cmd_ADD(tClient *Client, char *Args) { char *user, *ammount, *reason; int uid, iAmmount; // Parse arguments if( Server_int_ParseArgs(1, Args, &user, &ammount, &reason, NULL) ) { sendf(Client->Socket, "407 ADD takes 3 arguments\n"); return ; } 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 ; } #if !ROOT_CAN_ADD if( strcmp( Client->Username, "root" ) == 0 ) { // Allow adding for new users if( strcmp(reason, "treasurer: new user") != 0 ) { sendf(Client->Socket, "403 Root may not add\n"); return ; } } #endif #if HACK_NO_REFUNDS if( strstr(reason, "refund") != NULL || strstr(reason, "misdispense") != NULL ) { sendf(Client->Socket, "499 Don't use `dispense acct` for refunds, use `dispense refund` (and `dispense -G` to get item IDs)\n"); return ; } #endif // Get recipient uid = Bank_GetAcctByName(user, 0); if( uid == -1 ) { sendf(Client->Socket, "404 Invalid user\n"); return ; } // You can't alter an internal account if( !(Bank_GetFlags(Client->UID) & USER_FLAG_ADMIN) ) { if( Bank_GetFlags(uid) & USER_FLAG_INTERNAL ) { sendf(Client->Socket, "403 Admin only\n"); return ; } // TODO: Maybe disallow changes to disabled? } // Parse ammount iAmmount = atoi(ammount); if( iAmmount == 0 && ammount[0] != '0' ) { sendf(Client->Socket, "407 Invalid Argument\n"); return ; } // Do give switch( DispenseAdd(Client->UID, uid, iAmmount, reason) ) { case 0: sendf(Client->Socket, "200 Add OK\n"); return ; case 2: sendf(Client->Socket, "402 Poor Guy\n"); return ; default: sendf(Client->Socket, "500 Unknown error\n"); return ; } }