Crossfire Server, Trunk  R20513
Data Structures | Macros | Typedefs | Functions | Variables
account.c File Reference

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

#include "global.h"
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "object.h"
#include "sproto.h"
#include "output_file.h"
Include dependency graph for account.c:

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...
 

Typedefs

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

Functions

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...
 
socket_structaccount_get_logged_in_init_socket (const char *name)
 This is like the above routine, but checks the init_sockets (account in process of logging in). More...
 
playeraccount_get_logged_in_player (const char *name)
 This checks to see if the account is logged in with a player attached If so, it returns the player object. 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...
 
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...
 

Variables

static account_structaccounts =NULL
 list of all accounts. More...
 
static int accounts_loaded = 0
 Whether the account information was loaded or not. 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.c.

Macro Definition Documentation

#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 105 of file account.c.

Referenced by accounts_load(), and accounts_save().

#define NUM_ACCOUNT_FIELDS   6

Number of fields in the accounts file.

These are colon seperated

Definition at line 63 of file account.c.

Referenced by accounts_load().

Typedef Documentation

Structure that holds account data.

This is basically in game representation of the data store in the file above. Note that there is no field here for the expansion area - if that gets used, then almost certainly the values will be extracted and stored into new fields in this structure, and not just a character that contains the data in an unprocessed form, eg, a int dm field could get added. all char* data here is from strdup_local(), and thus the shared string comparisons/functions should not be used on it.

Function Documentation

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. This is the unencrypted password (password as entered by user)
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 657 of file account.c.

References account_check_string(), check_password(), account_struct::name, newhash(), account_struct::next, account_struct::password, strcasecmp(), and strdup_local.

Referenced by account_password().

Here is the call graph for this function:

Here is the caller graph for this function:

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 368 of file account.c.

References MAX_NAME.

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

Here is the caller graph for this function:

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 308 of file account.c.

References account_struct::name, account_struct::next, and strcasecmp().

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

Here is the call graph for this function:

Here is the caller graph for this function:

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 561 of file account.c.

References account_struct::character_names, account_struct::name, account_struct::next, and account_struct::num_characters.

Referenced by account_add_player_cmd(), and save_player().

Here is the caller graph for this function:

socket_struct* account_get_logged_in_init_socket ( const char *  name)

This is like the above routine, but checks the init_sockets (account in process of logging in).

Parameters
nameaccount name to check against
Returns
index value into init_sockets[] of matching socket, or -1 if no match.

Definition at line 607 of file account.c.

References Socket_Info::allocated_sockets, init_sockets, Ns_Add, socket_info, and strcasecmp().

Referenced by account_is_logged_in(), and account_login_cmd().

Here is the call graph for this function:

Here is the caller graph for this function:

player* account_get_logged_in_player ( const char *  name)

This checks to see if the account is logged in with a player attached If so, it returns the player object.

Parameters
nameaccount name to check against.
Returns
player structure of matching account, or NULL if no match.

Definition at line 586 of file account.c.

References socket_struct::account_name, first_player, pl::next, pl::socket, and strcasecmp().

Referenced by account_is_logged_in(), and account_login_cmd().

Here is the call graph for this function:

Here is the caller graph for this function:

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 542 of file account.c.

References account_struct::character_names, account_struct::name, account_struct::next, and strcasecmp().

Referenced by account_play_cmd(), send_account_players(), and START_TEST().

Here is the call graph for this function:

Here is the caller graph for this function:

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 629 of file account.c.

References account_get_logged_in_init_socket(), and account_get_logged_in_player().

Referenced by account_add_player_cmd().

Here is the call graph for this function:

Here is the caller graph for this function:

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.
2number of characters on this account has reached a maximum.

Definition at line 460 of file account.c.

References account_struct::character_names, MAX_CHARACTERS_PER_ACCOUNT, account_struct::name, account_struct::next, account_struct::num_characters, strcasecmp(), and strdup_local.

Referenced by account_add_player_cmd(), save_player(), and START_TEST().

Here is the call graph for this function:

Here is the caller graph for this function:

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 332 of file account.c.

References check_password(), account_struct::last_login, account_struct::name, account_struct::next, account_struct::password, and strcasecmp().

Referenced by account_login_cmd().

Here is the call graph for this function:

Here is the caller graph for this function:

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 407 of file account.c.

References account_check_string(), account_exists(), accounts, accounts_loaded, account_struct::character_names, account_struct::created, account_struct::last_login, MAX_CHARACTERS_PER_ACCOUNT, account_struct::name, newhash(), account_struct::next, account_struct::num_characters, account_struct::password, and strdup_local.

Referenced by account_new_cmd(), and START_TEST().

Here is the call graph for this function:

Here is the caller graph for this function:

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 496 of file account.c.

References account_struct::character_names, account_struct::name, account_struct::next, account_struct::num_characters, and strcasecmp().

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

Here is the call graph for this function:

Here is the caller graph for this function:

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 246 of file account.c.

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:

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 112 of file account.c.

References accounts_loaded.

Referenced by START_TEST().

Here is the caller graph for this function:

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 121 of file account.c.

References ACCOUNT_FILE, accounts_loaded, account_struct::character_names, account_struct::created, account_struct::last_login, llevError, llevInfo, Settings::localdir, LOG(), MAX_BUF, MAX_CHARACTERS_PER_ACCOUNT, account_struct::name, account_struct::next, NUM_ACCOUNT_FIELDS, account_struct::num_characters, account_struct::password, settings, snprintf, split_string(), strdup_local, and VERY_BIG_BUF.

Referenced by init(), and START_TEST().

Here is the call graph for this function:

Here is the caller graph for this function:

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 267 of file account.c.

References ACCOUNT_FILE, account_write_entry(), accounts_loaded, account_struct::created, Settings::localdir, MAX_BUF, account_struct::next, account_struct::num_characters, of_close(), of_open(), settings, and snprintf.

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

Here is the call graph for this function:

Here is the caller graph for this function:

Variable Documentation

account_struct* accounts =NULL
static

list of all accounts.

Definition at line 91 of file account.c.

Referenced by account_new().

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 99 of file account.c.

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