Crossfire Server, Trunk  1.75.0
account.cpp File Reference
#include <set>
#include "global.h"
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "object.h"
#include "sproto.h"
#include "output_file.h"
+ Include dependency graph for account.cpp:

Go to the source code of this file.

Data Structures

struct  account_struct
 Structure that holds account data. More...
 

Macros

#define ACCOUNT_FILE   "accounts"
 Name of the accounts file. More...
 
#define NUM_ACCOUNT_FIELDS   6
 Number of fields in the accounts file. More...
 

Functions

static account_structaccount_alloc ()
 Allocate a new account_struct item. More...
 
int account_change_password (const char *account_name, const char *current_password, const char *new_password)
 Change an account password. More...
 
int account_check_string (const char *str)
 Checks a string to make sure it does not have any invalid characters. More...
 
const char * account_exists (const char *account_name)
 Checks the existing accounts, and see if this account exists. More...
 
const char * account_get_account_for_char (const char *charname)
 This looks at all the accounts and sees if charname is associated with any of them. More...
 
linked_characcount_get_additional_chars (const char *account_name, const Account_Chars *chars, int *count)
 Get a list of character names linked to the specified account which are not listed in chars. More...
 
char ** account_get_players_for_account (const char *account_name)
 Returns an array of strings for the characters on this account - the array is null terminated. More...
 
int account_is_logged_in (const char *name)
 This checkes if an account is logged in. More...
 
int account_link (const char *account_name, const char *player_name)
 Adds a player name to an account. More...
 
int account_login (const char *account_name, const char *account_password)
 Check if the given account exists, and whether the password is correct. More...
 
void account_logout (const char *account_name)
 Remove 'account_name' from the list of logged in accounts. More...
 
int account_new (const char *account_name, const char *account_password)
 Adds an account. More...
 
int account_remove_player (const char *account_name, const char *player_name)
 Removes a player name from an account. More...
 
static void account_write_entry (FILE *fp, account_struct *ac)
 This writes a single account entry to the given filepointer. More...
 
void accounts_clear (void)
 This is used purely by the test harness - by clearing the accounts, it can then verify that the data is added is loaded back into memory properly. More...
 
void accounts_load (void)
 This loads all the account entries into memory. More...
 
void accounts_save (void)
 Save all the account information. More...
 
static int char_in_list (const char *name, const std::vector< Account_Char * > chars)
 Check if a character name is in a list or not. More...
 
static void ensure_available_characters (account_struct *account, int count)
 Ensure an account can handle at least the specified count of character names. More...
 

Variables

static std::vector< account_struct * > accounts
 list of all accounts. More...
 
static int accounts_loaded = 0
 Whether the account information was loaded or not. More...
 
static std::set< std::string > accounts_logged_in = std::set<std::string>()
 Set of accounts names that are currently logged in. More...
 

Detailed Description

This file contains account management logic - creation, deletion, log in verification, as well as associating player files with the account.

The code in this file mostly assumes that the number of account operations will be low - for example, we load up all acounts in a linked list, and save them all out. If we have 10,000 accounts, this would be very slow. But for a few hundred accounts, should be plenty fast on most any hardware.

Likewise, the account structure is not exposed outside this file - this means that account access/updates is done through the account name. This adds some extra overhead in that code has to search the linked list, but for a relatively low number of entries, and relatively infrequent updates, this should not be much of an issue.

Since the accounts file is updated in several places in this file, it is documented here. The file is a list of accounts, one line per account, with fields separted by colons, eg:

Account name:Password:Account last used:Characters (semicolon separated):expansion mwede.nosp@m.l@so.nosp@m.nic.n.nosp@m.et:mypassword:1260686494:Mark;MarkW;:

none of the the fields listed could contain colons, and player names can not contain semicolon, as that is used to separate those. In addition, everything is limited to printable characters. The accounts file is designed to be human readable, even if it is not expected that a human will read it. Passwords are hashed using crypt(3) in traditional mode, unless you're on FreeBSD or Windows in which case passwords are stored in plaintext due to legacy reasons. expansion (last field) is there for possible expansion. There may be desire to store bits of information there. An example might be dm=1. But it is there for expansion.

Definition in file account.cpp.

Macro Definition Documentation

◆ ACCOUNT_FILE

#define ACCOUNT_FILE   "accounts"

Name of the accounts file.

I can not ever see a reason why this name would not work, but may as well still make it easy to change it.

Definition at line 108 of file account.cpp.

◆ NUM_ACCOUNT_FIELDS

#define NUM_ACCOUNT_FIELDS   6

Number of fields in the accounts file.

These are colon separated

Definition at line 67 of file account.cpp.

Function Documentation

◆ account_alloc()

static account_struct* account_alloc ( )
static

Allocate a new account_struct item.

Will fatal() if memory error.

Returns
item, never NULL.

Definition at line 135 of file account.cpp.

References account_struct::created, ensure_available_characters(), fatal(), account_struct::last_login, llevError, LOG(), OUT_OF_MEMORY, and time.

Referenced by account_new(), and accounts_load().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ account_change_password()

int account_change_password ( const char *  account_name,
const char *  current_password,
const char *  new_password 
)

Change an account password.

It does error checking, but the caller might want to do checking before getting here.

Parameters
account_nameaccount name we are changing
current_passwordcurrent password for the account or NULL. This is the unencrypted password (password as entered by user). If NULL, the current password is not checked, suitable for resetting lost passwords.
new_passwordnew password to set, unencrypted.
Return values
0password changed successfully.
1account name, old or new password has invalid character.
2account does not exist.
3current password is invalid.

Definition at line 627 of file account.cpp.

References account_check_string(), accounts, check_password(), newhash(), strcasecmp(), and strdup_local.

Referenced by account_password(), and command_accountpasswd().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ account_check_string()

int account_check_string ( const char *  str)

Checks a string to make sure it does not have any invalid characters.

We are fairly permissive on character here. String must start with alphanumeric String must not contain :;/'[ String can not end if a space This string will get used for file/directory names, but so long as as characters are not included that are not illegal, one can still manipulate the file/directory by putting it in quotes. If one starts to block all characters that may get interperted by shells, a large number of characters now get blocked (|*]()!, etc), and deciding which should be allowed and not just becomes a judgement call, so easier to just allow all and have the user put it in quotes.

Parameters
strstring to check
Returns
0 if ok, 1 if we have an invalid character, 2 if string is too long.

Definition at line 360 of file account.cpp.

References MAX_NAME.

Referenced by account_change_password(), account_new(), account_new_cmd(), account_password(), and create_player_cmd().

+ Here is the caller graph for this function:

◆ account_exists()

const char* account_exists ( const char *  account_name)

Checks the existing accounts, and see if this account exists.

This can also be used to get the official name for the account (eg, as user first entered, so Mark instead of mARk)

Parameters
account_nameaccount name we are looking for.
Returns
returns official name on match, NULL on no match.

Definition at line 296 of file account.cpp.

References accounts, and strcasecmp().

Referenced by account_login_cmd(), account_new(), and account_new_cmd().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ account_get_account_for_char()

const char* account_get_account_for_char ( const char *  charname)

This looks at all the accounts and sees if charname is associated with any of them.

Parameters
charnamecharacter name to check for.
Returns
Account name the character is associated with, NULL if none.

Definition at line 579 of file account.cpp.

References accounts.

Referenced by account_add_player_cmd(), and save_player().

+ Here is the caller graph for this function:

◆ account_get_additional_chars()

linked_char* account_get_additional_chars ( const char *  account_name,
const Account_Chars chars,
int *  count 
)

Get a list of character names linked to the specified account which are not listed in chars.

Parameters
account_nameaccount name.
charsknown character names.
[out]countwill be incremented by the number of items returned. Not initialized before use.
Returns
list of character names not in chars, the caller should free it after use.

Definition at line 550 of file account.cpp.

References accounts, char_in_list(), Account_Chars::chars, linked_char::name, linked_char::next, and strcasecmp().

Referenced by send_account_players().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ account_get_players_for_account()

char** account_get_players_for_account ( const char *  account_name)

Returns an array of strings for the characters on this account - the array is null terminated.

In fact, it just returns the ac->character_names.

Parameters
account_namename of the account to get the players for.
Returns
array of character names for this account. This will return NULL in the case where we can not find the account. It will return an array with the first entry being NULL in the case of a valid account with no characters added. This returned data should not be altered in any way.

Definition at line 519 of file account.cpp.

References accounts, and strcasecmp().

Referenced by account_play_cmd().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ account_is_logged_in()

int account_is_logged_in ( const char *  name)

This checkes if an account is logged in.

It is mainly used because some operations should not be done on logged in accounts (keeping everything synchronized is harder.)

Parameters
namename to look for.
Returns
0 if not logged in, 1 if logged in.

Definition at line 604 of file account.cpp.

References accounts_logged_in, and name.

Referenced by account_add_player_cmd().

+ Here is the caller graph for this function:

◆ account_link()

int account_link ( const char *  account_name,
const char *  player_name 
)

Adds a player name to an account.

Player corresponds to the names used in the pl object, not the person sitting at the computer. This function presumes that the caller has done the work to verify that the player does in fact exist, and does any related work to update the player. What this function does is simply update the account structure.

Parameters
account_namename of the account we are adding this player to.
player_namename of this player.
Return values
0player name added successfully.
1could not find account of that name.

Definition at line 444 of file account.cpp.

References accounts, ensure_available_characters(), strcasecmp(), and strdup_local.

Referenced by account_add_player_cmd(), and save_player().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ account_login()

int account_login ( const char *  account_name,
const char *  account_password 
)

Check if the given account exists, and whether the password is correct.

Note - if we do get a match, we update the last_login value - it is presumed that if someone knows the right accountname/password, that the account is effectively getting logged in.

Parameters
account_nameaccount name we are looking for.
account_passwordpassword for the account. This is the unencrypted password (password as entered by user)
Returns
0 if no match/wrong password, 1 if a match is found and password matches.

Definition at line 318 of file account.cpp.

References account_password(), accounts, accounts_logged_in, check_password(), strcasecmp(), and time.

Referenced by account_login_cmd().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ account_logout()

void account_logout ( const char *  account_name)

Remove 'account_name' from the list of logged in accounts.

Definition at line 337 of file account.cpp.

References accounts_logged_in.

Referenced by free_newsocket().

+ Here is the caller graph for this function:

◆ account_new()

int account_new ( const char *  account_name,
const char *  account_password 
)

Adds an account.

It does error checking, but the caller might want to do checking before getting here.

Parameters
account_nameaccount name we are adding
account_passwordpassword for the account. This is the unencrypted password (password as entered by user)
Return values
0account added successfully.
1name or password has invalid character.
2account already exists.

Definition at line 399 of file account.cpp.

References account_alloc(), account_check_string(), account_exists(), account_password(), accounts, accounts_loaded, account_struct::name, newhash(), account_struct::password, and strdup_local.

Referenced by account_new_cmd().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ account_remove_player()

int account_remove_player ( const char *  account_name,
const char *  player_name 
)

Removes a player name from an account.

Player corresponds to the names used in the pl object, not the person sitting at the computer. This function presumes that the caller has done the work to verify that the player does in fact exist, and does any related work to update the player. What this function does is simply update the account structure.

Parameters
account_namename of the account we are removing this player from.
player_namename of this player.
Return values
0player name removed successfully.
1could not find account of that name.
2player of this name not on account.

Definition at line 474 of file account.cpp.

References accounts, and strcasecmp().

Referenced by account_add_player_cmd(), key_confirm_quit(), and kill_player_permadeath().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ account_write_entry()

static void account_write_entry ( FILE *  fp,
account_struct ac 
)
static

This writes a single account entry to the given filepointer.

it is used both when saving all accounts, or if we just need to append a new account to the end of the file.

Parameters
fpfile pointer to write to.
acaccount structure to write out.

Definition at line 234 of file account.cpp.

References account_struct::character_names, account_struct::created, account_struct::last_login, account_struct::name, account_struct::num_characters, and account_struct::password.

Referenced by accounts_save().

+ Here is the caller graph for this function:

◆ accounts_clear()

void accounts_clear ( void  )

This is used purely by the test harness - by clearing the accounts, it can then verify that the data is added is loaded back into memory properly.

As such, we don't worry about memory cleanup, etc.

Definition at line 152 of file account.cpp.

References accounts, and accounts_loaded.

◆ accounts_load()

void accounts_load ( void  )

This loads all the account entries into memory.

It is presumed to only be called once during the program startup.

Definition at line 161 of file account.cpp.

References account_alloc(), ACCOUNT_FILE, accounts, accounts_loaded, buf, bufferreader_destroy(), bufferreader_init_from_file(), bufferreader_next_line(), account_struct::character_names, account_struct::created, ensure_available_characters(), fields, account_struct::last_login, llevError, llevInfo, Settings::localdir, LOG(), MAX_BUF, account_struct::name, NUM_ACCOUNT_FIELDS, account_struct::num_characters, account_struct::password, settings, split_string(), and strdup_local.

Referenced by init().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ accounts_save()

void accounts_save ( void  )

Save all the account information.

Since the data is stored in a flat file, if an update is needed for an account, the only way to save updates is to save all the data - there isn't an easy way to just add another player name for an account.

Definition at line 255 of file account.cpp.

References ACCOUNT_FILE, account_write_entry(), accounts, accounts_loaded, Settings::localdir, MAX_BUF, of_close(), of_open(), settings, and time.

Referenced by account_new_cmd(), cleanup(), and do_specials().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ char_in_list()

static int char_in_list ( const char *  name,
const std::vector< Account_Char * >  chars 
)
static

Check if a character name is in a list or not.

Parameters
namecharacter name to check.
charslist of names to check.
Returns
0 if not in the list, non-zero else.

Definition at line 533 of file account.cpp.

References name.

Referenced by account_get_additional_chars().

+ Here is the caller graph for this function:

◆ ensure_available_characters()

static void ensure_available_characters ( account_struct account,
int  count 
)
static

Ensure an account can handle at least the specified count of character names.

Parameters
accountaccount to check.
countnumber of names to handle.

Definition at line 115 of file account.cpp.

References account_struct::allocated_characters, account_struct::character_names, fatal(), llevError, LOG(), and OUT_OF_MEMORY.

Referenced by account_alloc(), account_link(), and accounts_load().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ accounts

◆ accounts_loaded

int accounts_loaded = 0
static

Whether the account information was loaded or not.

Because accounts_save() is called in cleanup(), we don't want programs using this library to erase the server's account information, since it is NOT loaded by default.

Definition at line 102 of file account.cpp.

Referenced by account_new(), accounts_clear(), accounts_load(), and accounts_save().

◆ accounts_logged_in

std::set<std::string> accounts_logged_in = std::set<std::string>()
static

Set of accounts names that are currently logged in.

Definition at line 55 of file account.cpp.

Referenced by account_is_logged_in(), account_login(), and account_logout().