summaryrefslogblamecommitdiff
path: root/src/char/pincode.c
blob: c7d7bce4c31fe599c469a69c03df74dac6fb19cf (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
















                                                           

                                                      

                                                              












                                                                                                               

















                                                                                                                  

                                                 
        






                                                                                                       
        
                                                
                                                







                                                                      
                                  



                                                        
                                                                                







                                                           
                                                            
        
                                                  



                                                  
                                                   






                                                           
                                    
        
                                                  




                                                  
                          













                                                                            
                                                           



















                                                              
                                                        













                                                                                
                                           










                                                                 





                                                                                                                     







                                                                                                                             

                                                                      














                                          
                                          










                                                       
                                     



                                                   
// Copyright (c) Hercules Dev Team, licensed under GNU GPL.
// See the LICENSE file

#include "../common/cbasetypes.h"
#include "../common/mmo.h"
#include "../common/random.h"
#include "../common/showmsg.h"
#include "../common/socket.h"
#include "../common/strlib.h"
#include "char.h"
#include "pincode.h"

#include <stdlib.h>

int enabled = PINCODE_OK;
int changetime = 0;
int maxtry = 3;
int charselect = 0;
unsigned int multiplier = 0x3498, baseSeed = 0x881234;

void pincode_handle ( int fd, struct char_session_data* sd ) {
	bool pass = true;
	
	if( !*pincode->charselect ) {
		struct online_char_data* character;
		if( (character = (struct online_char_data*)idb_get(online_char_db, sd->account_id)) != NULL ) {
			if( character->pincode_passed )
				pass = false;
		}
	}
	
	if( *pincode->enabled && pass ) {

		sd->pincode_pass = false;
		// PIN code system enabled
		if( sd->pincode[0] == '\0' ){
			// No PIN code has been set yet
			pincode->state( fd, sd, PINCODE_NOTSET );
		} else {
			if( !pincode->changetime || !( time(NULL) > (sd->pincode_change+*pincode->changetime) ) ){
				// Ask user for his PIN code
				pincode->state( fd, sd, PINCODE_ASK );
			} else {
				// User hasnt changed his PIN code too long
				pincode->state( fd, sd, PINCODE_EXPIRED );
			}
		}
	} else {
		// PIN code system, disabled
		pincode->state( fd, sd, PINCODE_OK );
	}
}
void pincode_pass(struct char_session_data *sd) {
	struct online_char_data* character;
	
	if( (character = (struct online_char_data*)idb_get(online_char_db, sd->account_id)) != NULL ) {
		character->pincode_passed = true;
	}
	sd->pincode_pass = true;
}
void pincode_check(int fd, struct char_session_data* sd) {
	char pin[4] = "\0\0\0\0";
	
	strncpy(pin, (char*)RFIFOP(fd, 6), 3+1);
	pincode->decrypt(sd->pincode_seed, pin);
	if( pincode->compare( fd, sd, pin ) ){
		pincode->state( fd, sd, PINCODE_OK );
	}
}

int pincode_compare(int fd, struct char_session_data* sd, char* pin) {
	if( strcmp( sd->pincode, pin ) == 0 ){
		sd->pincode_try = 0;
		pincode->pass(sd);
		return 1;
	} else {
		pincode->state( fd, sd, PINCODE_WRONG );
		
		if( *pincode->maxtry && ++sd->pincode_try >= *pincode->maxtry ){
			pincode->error( sd->account_id );
		}
		
		return 0;
	}
}

void pincode_change(int fd, struct char_session_data* sd) {
	char oldpin[4] = "\0\0\0\0", newpin[4] = "\0\0\0\0";
	
	strncpy(oldpin, (char*)RFIFOP(fd,6), 3+1);
	pincode->decrypt(sd->pincode_seed,oldpin);
	if( !pincode->compare( fd, sd, oldpin ) )
		return;
	
	strncpy(newpin, (char*)RFIFOP(fd,10), 3+1);
	pincode->decrypt(sd->pincode_seed,newpin);
	pincode->update( sd->account_id, newpin );
	
	pincode->state( fd, sd, PINCODE_OK );
}

void pincode_setnew(int fd, struct char_session_data* sd) {
	char newpin[4] = "\0\0\0\0";
	
	strncpy(newpin, (char*)RFIFOP(fd,6), 3+1);
	pincode->decrypt(sd->pincode_seed,newpin);
	
	pincode->update( sd->account_id, newpin );
	
	pincode->state( fd, sd, PINCODE_OK );
	pincode->pass(sd);
}

// 0 = disabled / pin is correct
// 1 = ask for pin - client sends 0x8b8
// 2 = create new pin - client sends 0x8ba
// 3 = pin must be changed - client 0x8be
// 4 = create new pin ?? - client sends 0x8ba
// 5 = client shows msgstr(1896)
// 6 = client shows msgstr(1897) Unable to use your KSSN number
// 7 = char select window shows a button - client sends 0x8c5
// 8 = pincode was incorrect
void pincode_sendstate(int fd, struct char_session_data* sd, uint16 state) {
	WFIFOHEAD(fd, 12);
	WFIFOW(fd, 0) = 0x8b9;
	WFIFOL(fd, 2) = sd->pincode_seed = rand() % 0xFFFF;
	WFIFOL(fd, 6) = sd->account_id;
	WFIFOW(fd,10) = state;
	WFIFOSET(fd,12);
}

void pincode_notifyLoginPinUpdate(int account_id, char* pin) {
	WFIFOHEAD(login_fd,11);
	WFIFOW(login_fd,0) = 0x2738;
	WFIFOL(login_fd,2) = account_id;
	strncpy( (char*)WFIFOP(login_fd,6), pin, 5 );
	WFIFOSET(login_fd,11);
}

void pincode_notifyLoginPinError(int account_id) {
	WFIFOHEAD(login_fd,6);
	WFIFOW(login_fd,0) = 0x2739;
	WFIFOL(login_fd,2) = account_id;
	WFIFOSET(login_fd,6);
}

void pincode_decrypt(unsigned int userSeed, char* pin) {
	int i, pos;
	char tab[10] = {0,1,2,3,4,5,6,7,8,9};
	
	for( i = 1; i < 10; i++ ){
		userSeed = *pincode->baseSeed + userSeed * *pincode->multiplier;
		pos = userSeed % (i + 1);
		if( i != pos ){
			tab[i] ^= tab[pos];
			tab[pos] ^= tab[i];
			tab[i] ^= tab[pos];
		}
	}
	
	for( i = 0; i < 4; i++ ){
		pin[i] = tab[pin[i] - '0'];
	}
	
	sprintf(pin, "%d%d%d%d", pin[0], pin[1], pin[2], pin[3]);
}

bool pincode_config_read(char *w1, char *w2) {
	
	while ( true ) {
		
		if ( strcmpi(w1, "pincode_enabled") == 0 ) {
			enabled = atoi(w2);
#ifdef PACKETVER < 20110309
			if( enabled ) {
				ShowWarning("pincode_enabled requires PACKETVER 20110309 or higher. disabling...\n");
				enabled = 0;
			}
#endif
		} else if ( strcmpi(w1, "pincode_changetime") == 0 ) {
			changetime = atoi(w2)*60;
		} else if ( strcmpi(w1, "pincode_maxtry") == 0 ) {
			maxtry = atoi(w2);
			if( maxtry > 3 ) {
				ShowWarning("pincode_maxtry is too high (%d); maximum allowed: 3! capping to 3...\n",maxtry);
				maxtry = 3;
			}
		} else if ( strcmpi(w1, "pincode_charselect") == 0 ) {
			charselect = atoi(w2);
		} else
			return false;
		
		break;
	}
	
	return true;
}

void pincode_defaults(void) {
	pincode = &pincode_s;
	
	pincode->enabled = &enabled;
	pincode->changetime = &changetime;
	pincode->maxtry = &maxtry;
	pincode->charselect = &charselect;
	pincode->multiplier = &multiplier;
	pincode->baseSeed = &baseSeed;
	
	pincode->handle = pincode_handle;
	pincode->decrypt = pincode_decrypt;
	pincode->error = pincode_notifyLoginPinError;
	pincode->update = pincode_notifyLoginPinUpdate;
	pincode->state = pincode_sendstate;
	pincode->new = pincode_setnew;
	pincode->change = pincode_change;
	pincode->compare = pincode_compare;
	pincode->pass = pincode_pass;
	pincode->check = pincode_check;
	pincode->config_read = pincode_config_read;

}