/** * \brief Transfer money to another account * * Usage: GIVE <dest> <ammount> <reason...> */ void Server_Cmd_GIVE(tClient *Client, char *Args) { char *recipient, *ammount, *reason; int uid, iAmmount; int thisUid; // Parse arguments if( Server_int_ParseArgs(1, Args, &recipient, &ammount, &reason, NULL) ) { sendf(Client->Socket, "407 GIVE takes only 3 arguments\n"); return ; } // Check for authed if( !Client->bIsAuthed ) { sendf(Client->Socket, "401 Not Authenticated\n"); return ; } // Get recipient uid = Bank_GetAcctByName(recipient, 0); if( uid == -1 ) { sendf(Client->Socket, "404 Invalid target user\n"); return ; } // You can't alter an internal account // if( Bank_GetFlags(uid) & USER_FLAG_INTERNAL ) { // sendf(Client->Socket, "404 Invalid target user\n"); // return ; // } // Parse ammount iAmmount = atoi(ammount); if( iAmmount <= 0 ) { sendf(Client->Socket, "407 Invalid Argument, ammount must be > zero\n"); return ; } if( Client->EffectiveUID != -1 ) { thisUid = Client->EffectiveUID; } else { thisUid = Client->UID; } // Do give switch( DispenseGive(Client->UID, thisUid, uid, iAmmount, reason) ) { case 0: sendf(Client->Socket, "200 Give OK\n"); return ; case 2: sendf(Client->Socket, "402 Poor You\n"); return ; default: sendf(Client->Socket, "500 Unknown error\n"); return ; } }
int Bank_CreateAcct(const char *Name) { int ret; ret = Bank_GetAcctByName(Name); if( ret != -1 ) return -1; return Bank_int_AddUser(Name); }
/** * \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 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_USERINFO(tClient *Client, char *Args) { int uid; char *user; // Parse arguments if( Server_int_ParseArgs(0, Args, &user, NULL) ) { sendf(Client->Socket, "407 USER_INFO takes 1 argument\n"); return ; } if( giDebugLevel ) Debug(Client, "User Info '%s'", user); // Get recipient uid = Bank_GetAcctByName(user, 0); if( giDebugLevel >= 2 ) Debug(Client, "uid = %i", uid); if( uid == -1 ) { sendf(Client->Socket, "404 Invalid user\n"); return ; } _SendUserInfo(Client, uid); }
/* * Authenticate a user */ int Bank_GetUserAuth(const char *Salt, const char *Username, const char *Password) { #if USE_LDAP uint8_t hash[20]; uint8_t h[20]; int ofs = strlen(Username) + strlen(Salt); char input[ ofs + 40 + 1]; char tmp[4 + strlen(Username) + 1]; // uid=%s char *passhash; #endif #if 1 // Only here to shut GCC up (until password auth is implemented) if( Salt == NULL ) return -1; if( Password == NULL ) return -1; #endif #if HACK_TPG_NOAUTH if( strcmp(Username, "tpg") == 0 ) return Bank_GetAcctByName("tpg"); #endif #if HACK_ROOT_NOAUTH if( strcmp(Username, "root") == 0 ) { int ret = Bank_GetAcctByName("root"); if( ret == -1 ) return Bank_CreateAcct("root"); return ret; } #endif #if USE_LDAP HexBin(hash, 20, Password); // Build string to hash strcpy(input, Username); strcpy(input, Salt); // TODO: Get user's SHA-1 hash sprintf(tmp, "uid=%s", Username); printf("tmp = '%s'\n", tmp); passhash = ReadLDAPValue(tmp, "userPassword"); if( !passhash ) { return -1; } printf("LDAP hash '%s'\n", passhash); sprintf(input+ofs, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", h[ 0], h[ 1], h[ 2], h[ 3], h[ 4], h[ 5], h[ 6], h[ 7], h[ 8], h[ 9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19] ); // Then create the hash from the provided salt // Compare that with the provided hash # if 1 { int i; printf("Password hash "); for(i=0;i<20;i++) printf("%02x", hash[i]&0xFF); printf("\n"); } # endif #endif return -1; }
/** * \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 ; } }