forked from github/server
add a new password module
start adding password hashing logic (WIP) does not yet pass all tests
This commit is contained in:
parent
ae0206652e
commit
54d25e91dd
11 changed files with 100 additions and 20 deletions
|
@ -31,6 +31,8 @@ without prior permission by the authors of Eressea.
|
|||
|
||||
#include <util/language.h>
|
||||
#include <util/log.h>
|
||||
#include <util/password.h>
|
||||
|
||||
#include <quicklist.h>
|
||||
|
||||
#include <tolua.h>
|
||||
|
@ -383,7 +385,8 @@ static int tolua_faction_create(lua_State * L)
|
|||
static int tolua_faction_set_password(lua_State * L)
|
||||
{
|
||||
faction *self = (faction *)tolua_tousertype(L, 1, 0);
|
||||
faction_setpassword(self, tolua_tostring(L, 2, 0));
|
||||
const char * passw = tolua_tostring(L, 2, 0);
|
||||
faction_setpassword(self, password_hash(passw));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include <platform.h>
|
||||
#include <kernel/config.h>
|
||||
#include "faction.h"
|
||||
|
||||
#include "alliance.h"
|
||||
#include "ally.h"
|
||||
#include "curse.h"
|
||||
|
@ -46,6 +45,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include <util/language.h>
|
||||
#include <util/log.h>
|
||||
#include <util/parser.h>
|
||||
#include <util/password.h>
|
||||
#include <util/resolve.h>
|
||||
#include <util/rng.h>
|
||||
#include <util/variant.h>
|
||||
|
@ -63,6 +63,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
faction *factions;
|
||||
|
||||
|
@ -252,7 +253,7 @@ faction *addfaction(const char *email, const char *password,
|
|||
}
|
||||
|
||||
if (!password) password = itoa36(rng_int());
|
||||
faction_setpassword(f, password);
|
||||
faction_setpassword(f, password_hash(password));
|
||||
ADDMSG(&f->msgs, msg_message("changepasswd", "value", password));
|
||||
|
||||
f->alliance_joindate = turn;
|
||||
|
@ -313,16 +314,27 @@ unit *addplayer(region * r, faction * f)
|
|||
return u;
|
||||
}
|
||||
|
||||
extern char *sha256_crypt(const char *key, const char *salt);
|
||||
|
||||
const char * mksalt(char *salt, size_t len) {
|
||||
char *dst = salt;
|
||||
int ent = (int)time(0);
|
||||
// FIXME: worst ever salt generation
|
||||
while (dst < salt + len) {
|
||||
*dst++ = itoa36(ent & rng_int())[0];
|
||||
}
|
||||
return salt;
|
||||
}
|
||||
|
||||
bool checkpasswd(const faction * f, const char *passwd)
|
||||
{
|
||||
if (!passwd) return false;
|
||||
if (strcmp(f->_password, passwd)==0) return true;
|
||||
if (unicode_utf8_strcasecmp(f->_password, passwd) == 0) {
|
||||
log_warning("case-sensitive password check failed: %s", factionname(f));
|
||||
return true;
|
||||
|
||||
if (password_verify(f->_password, passwd) == VERIFY_FAIL) {
|
||||
log_warning("password check failed: %s", factionname(f));
|
||||
return false;
|
||||
}
|
||||
log_warning("password check failed: %s", factionname(f));
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
variant read_faction_reference(struct storage * store)
|
||||
|
@ -565,11 +577,11 @@ void faction_setbanner(faction * self, const char *banner)
|
|||
self->banner = _strdup(banner);
|
||||
}
|
||||
|
||||
void faction_setpassword(faction * f, const char *passw)
|
||||
void faction_setpassword(faction * f, const char *pwhash)
|
||||
{
|
||||
assert(passw);
|
||||
assert(pwhash && pwhash[0] == '$');
|
||||
free(f->_password);
|
||||
f->_password = _strdup(passw);
|
||||
f->_password = _strdup(pwhash);
|
||||
}
|
||||
|
||||
bool valid_race(const struct faction *f, const struct race *rc)
|
||||
|
|
|
@ -153,8 +153,7 @@ extern "C" {
|
|||
const char *faction_getemail(const struct faction *self);
|
||||
void faction_setemail(struct faction *self, const char *email);
|
||||
|
||||
// const char *faction_getpassword(const struct faction *self);
|
||||
void faction_setpassword(struct faction *self, const char *password);
|
||||
void faction_setpassword(struct faction *self, const char *pwhash);
|
||||
bool valid_race(const struct faction *f, const struct race *rc);
|
||||
|
||||
void faction_getorigin(const struct faction * f, int id, int *x, int *y);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <kernel/plane.h>
|
||||
#include <kernel/config.h>
|
||||
#include <util/language.h>
|
||||
#include <util/password.h>
|
||||
|
||||
#include "monster.h"
|
||||
#include <CuTest.h>
|
||||
|
@ -123,7 +124,7 @@ static void test_check_passwd(CuTest *tc) {
|
|||
faction *f;
|
||||
|
||||
f = test_create_faction(0);
|
||||
faction_setpassword(f, "password");
|
||||
faction_setpassword(f, password_hash("password"));
|
||||
CuAssertIntEquals(tc, true, checkpasswd(f, "password"));
|
||||
CuAssertIntEquals(tc, true, checkpasswd(f, "PASSWORD"));
|
||||
CuAssertIntEquals(tc, false, checkpasswd(f, "assword"));
|
||||
|
|
|
@ -64,13 +64,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include <util/lists.h>
|
||||
#include <util/log.h>
|
||||
#include <util/parser.h>
|
||||
#include <quicklist.h>
|
||||
#include <util/password.h>
|
||||
#include <util/rand.h>
|
||||
#include <util/resolve.h>
|
||||
#include <util/rng.h>
|
||||
#include <util/umlaut.h>
|
||||
#include <util/unicode.h>
|
||||
|
||||
#include <quicklist.h>
|
||||
#include <stream.h>
|
||||
#include <filestream.h>
|
||||
#include <storage.h>
|
||||
|
@ -1216,7 +1217,7 @@ faction *readfaction(struct gamedata * data)
|
|||
}
|
||||
|
||||
READ_STR(data->store, name, sizeof(name));
|
||||
faction_setpassword(f, name);
|
||||
faction_setpassword(f, (data->version >= CRYPT_VERSION) ? name : password_hash(name));
|
||||
if (data->version < NOOVERRIDE_VERSION) {
|
||||
READ_STR(data->store, 0, 0);
|
||||
}
|
||||
|
|
|
@ -33,8 +33,8 @@
|
|||
#define SPELL_LEVEL_VERSION 348 /* f->max_spelllevel gets stored, not calculated */
|
||||
#define OWNER_3_VERSION 349 /* regions store last owner, not last alliance */
|
||||
#define ATTRIBOWNER_VERSION 350 /* all attrib_type functions know who owns the attribute */
|
||||
|
||||
#define RELEASE_VERSION ATTRIBOWNER_VERSION /* current datafile */
|
||||
#define CRYPT_VERSION 351 /* passwords are encrypted */
|
||||
#define RELEASE_VERSION CRYPT_VERSION /* current datafile */
|
||||
#define MIN_VERSION INTPAK_VERSION /* minimal datafile we support */
|
||||
#define MAX_VERSION RELEASE_VERSION /* change this if we can need to read the future datafile, and we can do so */
|
||||
|
||||
|
|
|
@ -79,6 +79,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include <util/lists.h>
|
||||
#include <util/log.h>
|
||||
#include <util/parser.h>
|
||||
#include <util/password.h>
|
||||
#include <quicklist.h>
|
||||
#include <util/rand.h>
|
||||
#include <util/rng.h>
|
||||
|
@ -2169,7 +2170,7 @@ int password_cmd(unit * u, struct order *ord)
|
|||
cmistake(u, ord, 283, MSG_EVENT);
|
||||
strlcpy(pwbuf, itoa36(rng_int()), sizeof(pwbuf));
|
||||
}
|
||||
faction_setpassword(u->faction, pwbuf);
|
||||
faction_setpassword(u->faction, password_hash(pwbuf));
|
||||
ADDMSG(&u->faction->msgs, msg_message("changepasswd",
|
||||
"value", pwbuf));
|
||||
return 0;
|
||||
|
|
|
@ -3,6 +3,7 @@ project(util C)
|
|||
SET(_TEST_FILES
|
||||
base36.test.c
|
||||
parser.test.c
|
||||
password.test.c
|
||||
attrib.test.c
|
||||
strings.test.c
|
||||
bsdstring.test.c
|
||||
|
@ -28,6 +29,7 @@ log.c
|
|||
message.c
|
||||
nrmessage.c
|
||||
parser.c
|
||||
password.c
|
||||
rand.c
|
||||
resolve.c
|
||||
strings.c
|
||||
|
|
35
src/util/password.c
Normal file
35
src/util/password.c
Normal file
|
@ -0,0 +1,35 @@
|
|||
#include <platform.h>
|
||||
#include "password.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define PASSWORD_PLAIN 0
|
||||
#define PASSWORD_MD5 1
|
||||
#define PASSWORD_SHA256 2
|
||||
#define PASSWORD_BCRYPT 3 // not implemented
|
||||
#define PASSWORD_DEFAULT PASSWORD_PLAIN
|
||||
|
||||
static const char * password_hash_i(const char * passwd, const char *salt, int algo) {
|
||||
static char result[64]; // TODO: static result buffers are bad mojo!
|
||||
assert(passwd);
|
||||
assert(salt);
|
||||
if (algo==PASSWORD_PLAIN) {
|
||||
_snprintf(result, sizeof(result), "$0$%s$%s", salt, passwd);
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const char * password_hash(const char * passwd) {
|
||||
return password_hash_i(passwd, "saltyfish", PASSWORD_DEFAULT);
|
||||
}
|
||||
|
||||
int password_verify(const char * hash, const char * passwd) {
|
||||
assert(hash);
|
||||
assert(passwd);
|
||||
return VERIFY_UNKNOWN;
|
||||
}
|
7
src/util/password.h
Normal file
7
src/util/password.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#define VERIFY_OK 0 // password matches hash
|
||||
#define VERIFY_FAIL 1 // password is wrong
|
||||
#define VERIFY_UNKNOWN 2 // hashing algorithm not supported
|
||||
int password_verify(const char * hash, const char * passwd);
|
||||
const char * password_hash(const char * passwd);
|
19
src/util/password.test.c
Normal file
19
src/util/password.test.c
Normal file
|
@ -0,0 +1,19 @@
|
|||
#include <CuTest.h>
|
||||
#include "password.h"
|
||||
|
||||
static void test_passwords(CuTest *tc) {
|
||||
const char *hash;
|
||||
|
||||
hash = password_hash("password");
|
||||
CuAssertPtrNotNull(tc, hash);
|
||||
CuAssertStrEquals(tc, "$0$saltyfish$password", hash);
|
||||
CuAssertIntEquals(tc, VERIFY_OK, password_verify(hash, "password"));
|
||||
CuAssertIntEquals(tc, VERIFY_FAIL, password_verify(hash, "arseword"));
|
||||
CuAssertIntEquals(tc, VERIFY_UNKNOWN, password_verify("$9$saltyfish$password", "arseword"));
|
||||
}
|
||||
|
||||
CuSuite *get_password_suite(void) {
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_passwords);
|
||||
return suite;
|
||||
}
|
Loading…
Reference in a new issue