From 4050f994a406700eff463ef988dac4ab58e502bd Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 16 Feb 2016 07:30:26 +0100 Subject: [PATCH 1/9] fix write_faction_reference, check for f->alive in other places TODO: 1. I added some new TODOs 2. What happens to morale when region owners die? 3. Needs tests --- src/kernel/faction.c | 3 +- src/kernel/group.c | 6 +-- src/kernel/group.test.c | 31 ++++++++++---- src/kernel/save.c | 90 +++++++++++++++++++++++------------------ 4 files changed, 78 insertions(+), 52 deletions(-) diff --git a/src/kernel/faction.c b/src/kernel/faction.c index cf1372950..ac1cf69af 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -333,7 +333,8 @@ variant read_faction_reference(struct storage * store) void write_faction_reference(const faction * f, struct storage *store) { - WRITE_INT(store, (f && f->_alive) ? f->no : 0); + assert(!f || f->_alive); + WRITE_INT(store, f ? f->no : 0); } static faction *dead_factions; diff --git a/src/kernel/group.c b/src/kernel/group.c index 35f7e93a7..9b8b368ad 100755 --- a/src/kernel/group.c +++ b/src/kernel/group.c @@ -203,12 +203,12 @@ void write_groups(struct storage *store, const faction * f) WRITE_INT(store, g->gid); WRITE_STR(store, g->name); for (a = g->allies; a; a = a->next) { - if (a->faction) { + if (a->faction && a->faction->_alive) { write_faction_reference(a->faction, store); WRITE_INT(store, a->status); } } - WRITE_INT(store, 0); + write_faction_reference(NULL, store); a_write(store, g->attribs, g); WRITE_SECTION(store); } @@ -233,7 +233,7 @@ void read_groups(struct storage *store, faction * f) ally *a; variant fid; - READ_INT(store, &fid.i); + fid = read_faction_reference(store); if (fid.i <= 0) break; a = ally_add(pa, findfaction(fid.i)); diff --git a/src/kernel/group.test.c b/src/kernel/group.test.c index 35b25aad5..fa3487cb3 100644 --- a/src/kernel/group.test.c +++ b/src/kernel/group.test.c @@ -5,6 +5,8 @@ #include "faction.h" #include "unit.h" #include "region.h" +#include +#include #include #include #include @@ -22,34 +24,47 @@ static void test_group_readwrite(CuTest * tc) storage store; FILE *F; stream strm; + int i; - F = fopen("test.dat", "w"); + F = fopen("test.dat", "wb"); fstream_init(&strm, F); binstore_init(&store, &strm); test_cleanup(); test_create_world(); f = test_create_faction(0); - g = new_group(f, "test", 42); + g = new_group(f, "NW", 42); + g = new_group(f, "Egoisten", 43); + a_add(&g->attribs, make_key(44)); al = ally_add(&g->allies, f); al->status = HELP_GIVE; write_groups(&store, f); + WRITE_INT(&store, 47); binstore_done(&store); fstream_done(&strm); - F = fopen("test.dat", "r"); + F = fopen("test.dat", "rb"); fstream_init(&strm, F); binstore_init(&store, &strm); f->groups = 0; - free_group(g); read_groups(&store, f); + READ_INT(&store, &i); binstore_done(&store); fstream_done(&strm); + CuAssertIntEquals(tc, 47, i); CuAssertPtrNotNull(tc, f->groups); - CuAssertPtrNotNull(tc, f->groups->allies); - CuAssertPtrEquals(tc, 0, f->groups->allies->next); - CuAssertPtrEquals(tc, f, f->groups->allies->faction); - CuAssertIntEquals(tc, HELP_GIVE, f->groups->allies->status); + CuAssertIntEquals(tc, 42, f->groups->gid); + CuAssertStrEquals(tc, "NW", f->groups->name); + CuAssertPtrNotNull(tc, f->groups->next); + CuAssertIntEquals(tc, 43, f->groups->next->gid); + CuAssertStrEquals(tc, "Egoisten", f->groups->next->name); + CuAssertPtrEquals(tc, 0, f->groups->allies); + g = f->groups->next; + CuAssertPtrNotNull(tc, find_key(g->attribs, 44)); + CuAssertPtrNotNull(tc, g->allies); + CuAssertPtrEquals(tc, 0, g->allies->next); + CuAssertPtrEquals(tc, f, g->allies->faction); + CuAssertIntEquals(tc, HELP_GIVE, g->allies->status); remove("test.dat"); test_cleanup(); } diff --git a/src/kernel/save.c b/src/kernel/save.c index fe8fbd93d..93bd8ffc0 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -454,6 +454,7 @@ void write_alliances(struct gamedata *data) alliance *al = alliances; while (al) { if (al->_leader) { + assert(al->_leader->_alive); WRITE_INT(data->store, al->id); WRITE_STR(data->store, al->name); WRITE_INT(data->store, (int)al->flags); @@ -462,7 +463,7 @@ void write_alliances(struct gamedata *data) } al = al->next; } - WRITE_INT(data->store, 0); + write_faction_reference(NULL, data->store); WRITE_SECTION(data->store); } @@ -535,10 +536,14 @@ static void read_owner(struct gamedata *data, region_owner ** powner) static void write_owner(struct gamedata *data, region_owner * owner) { if (owner) { + faction *f; WRITE_INT(data->store, owner->since_turn); WRITE_INT(data->store, owner->morale_turn); WRITE_INT(data->store, owner->flags); - write_faction_reference(owner->last_owner, data->store); + f = owner->last_owner; + write_faction_reference((f && f->_alive) ? f : NULL, data->store); + // TODO: check that destroyfaction does the right thing. + // TODO: What happens to morale when the owner dies? write_faction_reference(owner->owner, data->store); } else { @@ -612,8 +617,8 @@ unit *read_unit(struct gamedata *data) uhash(u); } - READ_INT(data->store, &n); - f = findfaction(n); + resolve_faction(read_faction_reference(data->store), &f); + assert(f); if (f != u->faction) { u_setfaction(u, f); } @@ -1162,14 +1167,14 @@ faction *readfaction(struct gamedata * data) { ally **sfp; int planes, n; - faction *f; + faction *f = NULL; char name[DISPLAYSIZE]; + variant var; - READ_INT(data->store, &n); - f = findfaction(n); + resolve_faction(var = read_faction_reference(data->store), &f); if (f == NULL) { f = (faction *)calloc(1, sizeof(faction)); - f->no = n; + f->no = var.i; } else { f->allies = NULL; /* mem leak */ @@ -1354,20 +1359,18 @@ void writefaction(struct gamedata *data, const faction * f) WRITE_SECTION(data->store); for (sf = f->allies; sf; sf = sf->next) { - int no; - int status; + faction *fa = sf->faction; - assert(sf->faction); - - no = sf->faction->no; - status = alliedfaction(NULL, f, sf->faction, HELP_ALL); - - if (status != 0) { - WRITE_INT(data->store, no); - WRITE_INT(data->store, sf->status); + assert(fa); + if (fa->_alive) { + int status = alliedfaction(NULL, f, fa, HELP_ALL); + if (status != 0) { + write_faction_reference(fa, data->store); + WRITE_INT(data->store, sf->status); + } } } - WRITE_INT(data->store, 0); + write_faction_reference(NULL, data->store); WRITE_SECTION(data->store); write_groups(data->store, f); write_spellbook(f->spellbook, data->store); @@ -1381,6 +1384,32 @@ static int cb_sb_maxlevel(spellbook_entry *sbe, void *cbdata) { return 0; } +void write_watchers(storage *store, plane *pl) { + watcher *w = pl->watchers; + while (w) { + if (w->faction && w->faction->_alive) { + write_faction_reference(w->faction, store); + WRITE_INT(store, w->mode); + } + w = w->next; + } + write_faction_reference(NULL, store); /* mark the end of the list */ +} + +void read_watchers(storage *store, plane *pl) { + variant fno = read_faction_reference(store); + while (fno.i) { + int n; + watcher *w = (watcher *)malloc(sizeof(watcher)); + ur_add(fno, &w->faction, resolve_faction); + READ_INT(store, &n); + w->mode = (unsigned char)n; + w->next = pl->watchers; + pl->watchers = w; + fno = read_faction_reference(store); + } +} + int readgame(const char *filename, bool backup) { int n, p, nread; @@ -1463,7 +1492,6 @@ int readgame(const char *filename, bool backup) READ_INT(&store, &nread); while (--nread >= 0) { int id; - variant fno; plane *pl; READ_INT(&store, &id); @@ -1500,16 +1528,7 @@ int readgame(const char *filename, bool backup) } } else { - fno = read_faction_reference(&store); - while (fno.i) { - watcher *w = (watcher *)malloc(sizeof(watcher)); - ur_add(fno, &w->faction, resolve_faction); - READ_INT(&store, &n); - w->mode = (unsigned char)n; - w->next = pl->watchers; - pl->watchers = w; - fno = read_faction_reference(&store); - } + read_watchers(&store, pl); } a_read(&store, &pl->attribs, pl); if (pl->id != 1094969858) { // Regatta @@ -1789,7 +1808,6 @@ int writegame(const char *filename) WRITE_SECTION(&store); for (pl = planes; pl; pl = pl->next) { - watcher *w; WRITE_INT(&store, pl->id); WRITE_STR(&store, pl->name); WRITE_INT(&store, pl->minx); @@ -1797,15 +1815,7 @@ int writegame(const char *filename) WRITE_INT(&store, pl->miny); WRITE_INT(&store, pl->maxy); WRITE_INT(&store, pl->flags); - w = pl->watchers; - while (w) { - if (w->faction) { - write_faction_reference(w->faction, &store); - WRITE_INT(&store, w->mode); - } - w = w->next; - } - write_faction_reference(NULL, &store); /* mark the end of the list */ + write_watchers(&store, pl); a_write(&store, pl->attribs, pl); WRITE_SECTION(&store); } From 7fe07439f5863df52af085f96bfc2ed4b17c1765 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 16 Feb 2016 07:30:26 +0100 Subject: [PATCH 2/9] fix write_faction_reference, check for f->alive in other places TODO: 1. I added some new TODOs 2. What happens to morale when region owners die? 3. Needs tests --- crypto | 2 +- share/debian-7_8.supp | 10 ++ share/ubuntu-12_04.supp | 5 + src/battle.c | 10 -- src/bind_faction.c | 2 +- src/bind_unit.c | 4 +- src/buildno.h | 2 +- src/kernel/alliance.test.c | 23 ++++ src/kernel/faction.c | 5 +- src/kernel/faction.test.c | 12 +-- src/kernel/group.c | 4 +- src/kernel/group.h | 2 +- src/kernel/group.test.c | 4 +- src/kernel/plane.c | 11 -- src/kernel/plane.h | 9 +- src/kernel/save.c | 100 +++++++++++------ src/kernel/save.h | 3 + src/kernel/save.test.c | 201 ++++++++++++++++++++++++++++++++++- src/kernel/version.h | 7 +- src/laws.c | 2 +- src/reports.c | 13 --- src/tests.c | 3 +- src/triggers/changefaction.c | 10 +- src/triggers/createunit.c | 28 +++-- src/util/gamedata.test.c | 25 +++++ src/util/password.c | 119 +++++++++++++-------- src/util/password.h | 7 +- src/util/password.test.c | 42 +++++--- tests/write-reports.sh | 2 +- 29 files changed, 495 insertions(+), 172 deletions(-) create mode 100644 src/util/gamedata.test.c diff --git a/crypto b/crypto index e0f9891a9..93dc9200f 160000 --- a/crypto +++ b/crypto @@ -1 +1 @@ -Subproject commit e0f9891a91d69c042f82c1e13e48ab4c7160381d +Subproject commit 93dc9200fa4cb6bfa3883b19f6d33fd416ca43da diff --git a/share/debian-7_8.supp b/share/debian-7_8.supp index 11370ba26..99eefafa4 100644 --- a/share/debian-7_8.supp +++ b/share/debian-7_8.supp @@ -1,3 +1,13 @@ +{ + strcpy.S:197 + Memcheck:Cond + obj:/lib/x86_64-linux-gnu/libc-2.13.so +} +{ + strcpy.S:1106 + Memcheck:Value8 + obj:/lib/x86_64-linux-gnu/libc-2.13.so +} { stpncpy sse3 Memcheck:Cond diff --git a/share/ubuntu-12_04.supp b/share/ubuntu-12_04.supp index 504e4ae2d..bab3287ef 100644 --- a/share/ubuntu-12_04.supp +++ b/share/ubuntu-12_04.supp @@ -1,3 +1,8 @@ +{ + stpncpy in strcpy-sse2-unaligned.S:1659 + Memcheck:Value8 + fun:__stpncpy_sse2_unaligned +} # old zlib version { zlib1g-dev-1:1.2.3.4.dfsg diff --git a/src/battle.c b/src/battle.c index 65b2cff7b..8fb2ec252 100644 --- a/src/battle.c +++ b/src/battle.c @@ -228,21 +228,11 @@ static void message_faction(battle * b, faction * f, struct message *m) void message_all(battle * b, message * m) { bfaction *bf; - plane *p = rplane(b->region); - watcher *w; for (bf = b->factions; bf; bf = bf->next) { assert(bf->faction); message_faction(b, bf->faction, m); } - if (p) - for (w = p->watchers; w; w = w->next) { - for (bf = b->factions; bf; bf = bf->next) - if (bf->faction == w->faction) - break; - if (bf == NULL) - message_faction(b, w->faction, m); - } } static void fbattlerecord(battle * b, faction * f, const char *s) diff --git a/src/bind_faction.c b/src/bind_faction.c index 03a75281a..c6b747416 100644 --- a/src/bind_faction.c +++ b/src/bind_faction.c @@ -392,7 +392,7 @@ static int tolua_faction_set_password(lua_State * L) { faction *self = (faction *)tolua_tousertype(L, 1, 0); const char * passw = tolua_tostring(L, 2, 0); - faction_setpassword(self, password_hash(passw, 0, PASSWORD_DEFAULT)); + faction_setpassword(self, password_encode(passw, PASSWORD_DEFAULT)); return 0; } diff --git a/src/bind_unit.c b/src/bind_unit.c index ed8eb74c3..e0b076710 100755 --- a/src/bind_unit.c +++ b/src/bind_unit.c @@ -153,8 +153,8 @@ static int tolua_unit_get_group(lua_State * L) static int tolua_unit_set_group(lua_State * L) { unit *self = (unit *)tolua_tousertype(L, 1, 0); - int result = join_group(self, tolua_tostring(L, 2, 0)); - lua_pushinteger(L, result); + group *g = join_group(self, tolua_tostring(L, 2, 0)); + lua_pushboolean(L, g!=NULL); return 1; } diff --git a/src/buildno.h b/src/buildno.h index 9727f88eb..3ce9dbfe7 100644 --- a/src/buildno.h +++ b/src/buildno.h @@ -1,3 +1,3 @@ #define VERSION_MAJOR 3 #define VERSION_MINOR 8 -#define VERSION_BUILD 3 +#define VERSION_BUILD 4 diff --git a/src/kernel/alliance.test.c b/src/kernel/alliance.test.c index 98e60e943..1b708b017 100644 --- a/src/kernel/alliance.test.c +++ b/src/kernel/alliance.test.c @@ -4,6 +4,7 @@ #include "alliance.h" #include #include +#include #include @@ -61,9 +62,31 @@ static void test_alliance_join(CuTest *tc) { test_cleanup(); } +static void test_alliance_dead_faction(CuTest *tc) { + faction *f, *f2; + alliance *al; + + test_cleanup(); + f = test_create_faction(0); + f2 = test_create_faction(0); + al = makealliance(42, "Hodor"); + setalliance(f, al); + setalliance(f2, al); + CuAssertPtrEquals(tc, f, alliance_get_leader(al)); + CuAssertIntEquals(tc, 2, ql_length(al->members)); + CuAssertPtrEquals(tc, al, f->alliance); + destroyfaction(&factions); + CuAssertIntEquals(tc, 1, ql_length(al->members)); + CuAssertPtrEquals(tc, f2, alliance_get_leader(al)); + CuAssertPtrEquals(tc, NULL, f->alliance); + CuAssertTrue(tc, !f->_alive); + test_cleanup(); +} + CuSuite *get_alliance_suite(void) { CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_alliance_dead_faction); SUITE_ADD_TEST(suite, test_alliance_make); SUITE_ADD_TEST(suite, test_alliance_join); return suite; diff --git a/src/kernel/faction.c b/src/kernel/faction.c index ac1cf69af..b52879464 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -252,7 +252,7 @@ faction *addfaction(const char *email, const char *password, } if (!password) password = itoa36(rng_int()); - faction_setpassword(f, password_hash(password, 0, PASSWORD_DEFAULT)); + faction_setpassword(f, password_encode(password, PASSWORD_DEFAULT)); ADDMSG(&f->msgs, msg_message("changepasswd", "value", password)); f->alliance_joindate = turn; @@ -567,7 +567,8 @@ void faction_setbanner(faction * self, const char *banner) void faction_setpassword(faction * f, const char *pwhash) { - assert(pwhash && pwhash[0] == '$'); + assert(pwhash); + // && pwhash[0] == '$'); free(f->_password); f->_password = _strdup(pwhash); } diff --git a/src/kernel/faction.test.c b/src/kernel/faction.test.c index 678aaa068..19b4da883 100644 --- a/src/kernel/faction.test.c +++ b/src/kernel/faction.test.c @@ -108,12 +108,12 @@ static void test_addfaction(CuTest *tc) { CuAssertPtrEquals(tc, NULL, (void *)f->ursprung); CuAssertPtrEquals(tc, (void *)factions, (void *)f); CuAssertStrEquals(tc, "test@eressea.de", f->email); - CuAssertIntEquals(tc, true, checkpasswd(f, "hurrdurr")); + CuAssertTrue(tc, checkpasswd(f, "hurrdurr")); CuAssertPtrEquals(tc, (void *)lang, (void *)f->locale); CuAssertIntEquals(tc, 1234, f->subscription); CuAssertIntEquals(tc, 0, f->flags); CuAssertIntEquals(tc, 0, f->age); - CuAssertIntEquals(tc, true, faction_alive(f)); + CuAssertTrue(tc, faction_alive(f)); CuAssertIntEquals(tc, M_GRAY, f->magiegebiet); CuAssertIntEquals(tc, turn, f->lastorders); CuAssertPtrEquals(tc, f, findfaction(f->no)); @@ -124,10 +124,10 @@ static void test_check_passwd(CuTest *tc) { faction *f; f = test_create_faction(0); - faction_setpassword(f, password_hash("password", 0, PASSWORD_DEFAULT)); - CuAssertIntEquals(tc, true, checkpasswd(f, "password")); - CuAssertIntEquals(tc, false, checkpasswd(f, "assword")); - CuAssertIntEquals(tc, false, checkpasswd(f, "PASSWORD")); + faction_setpassword(f, password_encode("password", PASSWORD_DEFAULT)); + CuAssertTrue(tc, checkpasswd(f, "password")); + CuAssertTrue(tc, !checkpasswd(f, "assword")); + CuAssertTrue(tc, !checkpasswd(f, "PASSWORD")); } static void test_get_monsters(CuTest *tc) { diff --git a/src/kernel/group.c b/src/kernel/group.c index 9b8b368ad..fdef2b8b8 100755 --- a/src/kernel/group.c +++ b/src/kernel/group.c @@ -179,7 +179,7 @@ void set_group(struct unit *u, struct group *g) } } -bool join_group(unit * u, const char *name) +group *join_group(unit * u, const char *name) { group *g = NULL; @@ -192,7 +192,7 @@ bool join_group(unit * u, const char *name) } set_group(u, g); - return true; + return g; } void write_groups(struct storage *store, const faction * f) diff --git a/src/kernel/group.h b/src/kernel/group.h index b32bed4c1..145881c00 100755 --- a/src/kernel/group.h +++ b/src/kernel/group.h @@ -36,7 +36,7 @@ extern "C" { } group; extern struct attrib_type at_group; /* attribute for units assigned to a group */ - extern bool join_group(struct unit *u, const char *name); + extern struct group *join_group(struct unit *u, const char *name); extern void set_group(struct unit *u, struct group *g); extern struct group * get_group(const struct unit *u); extern void free_group(struct group *g); diff --git a/src/kernel/group.test.c b/src/kernel/group.test.c index fa3487cb3..7daca2829 100644 --- a/src/kernel/group.test.c +++ b/src/kernel/group.test.c @@ -83,8 +83,8 @@ static void test_group(CuTest * tc) assert(r && f); u = test_create_unit(f, r); assert(u); - CuAssertTrue(tc, join_group(u, "hodor")); - CuAssertPtrNotNull(tc, (g = get_group(u))); + CuAssertPtrNotNull(tc, (g = join_group(u, "hodor"))); + CuAssertPtrEquals(tc, g, get_group(u)); CuAssertStrEquals(tc, "hodor", g->name); CuAssertIntEquals(tc, 1, g->members); set_group(u, 0); diff --git a/src/kernel/plane.c b/src/kernel/plane.c index 32c95f6a8..2542a053d 100644 --- a/src/kernel/plane.c +++ b/src/kernel/plane.c @@ -290,14 +290,3 @@ int read_plane_reference(plane ** pp, struct storage *store) ur_add(id, pp, resolve_plane); return AT_READ_OK; } - -bool is_watcher(const struct plane * p, const struct faction * f) -{ - struct watcher *w; - if (!p) - return false; - w = p->watchers; - while (w && w->faction != f) - w = w->next; - return (w != NULL); -} diff --git a/src/kernel/plane.h b/src/kernel/plane.h index 2426c6a1a..d8ec176a9 100644 --- a/src/kernel/plane.h +++ b/src/kernel/plane.h @@ -23,6 +23,7 @@ extern "C" { #endif struct region; + struct faction; struct plane; struct storage; @@ -43,15 +44,8 @@ extern "C" { #define PFL_NOMONSTERS 16384 /* no monster randenc */ #define PFL_SEESPECIAL 32768 /* far seeing */ - typedef struct watcher { - struct watcher *next; - struct faction *faction; - unsigned char mode; - } watcher; - typedef struct plane { struct plane *next; - struct watcher *watchers; int id; char *name; int minx, maxx, miny, maxy; @@ -76,7 +70,6 @@ extern "C" { struct plane *get_homeplane(void); extern int rel_to_abs(const struct plane *pl, const struct faction *f, int rel, unsigned char index); - extern bool is_watcher(const struct plane *p, const struct faction *f); extern void write_plane_reference(const plane * p, struct storage *store); extern int read_plane_reference(plane ** pp, struct storage *store); extern int plane_width(const plane * pl); diff --git a/src/kernel/save.c b/src/kernel/save.c index 93bd8ffc0..1619b3622 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -544,7 +544,8 @@ static void write_owner(struct gamedata *data, region_owner * owner) write_faction_reference((f && f->_alive) ? f : NULL, data->store); // TODO: check that destroyfaction does the right thing. // TODO: What happens to morale when the owner dies? - write_faction_reference(owner->owner, data->store); + f = owner->owner; + write_faction_reference((f && f->_alive) ? f : NULL, data->store); } else { WRITE_INT(data->store, -1); @@ -766,6 +767,7 @@ void write_unit(struct gamedata *data, const unit * u) const race *irace = u_irace(u); write_unit_reference(u, data->store); + assert(u->faction->_alive); write_faction_reference(u->faction, data->store); WRITE_STR(data->store, u->_name); WRITE_STR(data->store, u->display ? u->display : ""); @@ -1159,6 +1161,58 @@ void write_spellbook(const struct spellbook *book, struct storage *store) WRITE_TOK(store, "end"); } +static char * getpasswd(int fno) { + const char *prefix = itoa36(fno); + size_t len = strlen(prefix); + FILE * F = fopen("passwords.txt", "r"); + char line[80]; + if (F) { + while (!feof(F)) { + fgets(line, sizeof(line), F); + if (line[len]==':' && strncmp(prefix, line, len)==0) { + size_t slen = strlen(line)-1; + assert(line[slen]=='\n'); + line[slen] = 0; + fclose(F); + return _strdup(line+len+1); + } + } + fclose(F); + } + return NULL; +} + +static void read_password(gamedata *data, faction *f) { + char name[128]; + READ_STR(data->store, name, sizeof(name)); + if (data->version == BADCRYPT_VERSION) { + char * pass = getpasswd(f->no); + if (pass) { + faction_setpassword(f, password_encode(pass, PASSWORD_DEFAULT)); + free(pass); // TODO: remove this allocation! + } + else { + free(f->_password); + f->_password = NULL; + } + } + else { + faction_setpassword(f, (data->version >= CRYPT_VERSION) ? name : password_encode(name, PASSWORD_DEFAULT)); + } +} + +void _test_read_password(gamedata *data, faction *f) { + read_password(data, f); +} + +static void write_password(gamedata *data, const faction *f) { + WRITE_TOK(data->store, (const char *)f->_password); +} + +void _test_write_password(gamedata *data, const faction *f) { + write_password(data, f); +} + /** Reads a faction from a file. * This function requires no context, can be called in any state. The * faction may not already exist, however. @@ -1225,8 +1279,7 @@ faction *readfaction(struct gamedata * data) set_email(&f->email, ""); } - READ_STR(data->store, name, sizeof(name)); - faction_setpassword(f, (data->version > CRYPT_VERSION) ? name : password_hash(name, 0, PASSWORD_DEFAULT)); + read_password(data, f); if (data->version < NOOVERRIDE_VERSION) { READ_STR(data->store, 0, 0); } @@ -1313,6 +1366,7 @@ void writefaction(struct gamedata *data, const faction * f) ally *sf; ursprung *ur; + assert(f->_alive); write_faction_reference(f, data->store); WRITE_INT(data->store, f->subscription); #if RELEASE_VERSION >= SPELL_LEVEL_VERSION @@ -1333,7 +1387,7 @@ void writefaction(struct gamedata *data, const faction * f) WRITE_STR(data->store, f->name); WRITE_STR(data->store, f->banner); WRITE_STR(data->store, f->email); - WRITE_TOK(data->store, f->_password); + write_password(data, f); WRITE_TOK(data->store, locale_name(f->locale)); WRITE_INT(data->store, f->lastorders); WRITE_INT(data->store, f->age); @@ -1384,32 +1438,6 @@ static int cb_sb_maxlevel(spellbook_entry *sbe, void *cbdata) { return 0; } -void write_watchers(storage *store, plane *pl) { - watcher *w = pl->watchers; - while (w) { - if (w->faction && w->faction->_alive) { - write_faction_reference(w->faction, store); - WRITE_INT(store, w->mode); - } - w = w->next; - } - write_faction_reference(NULL, store); /* mark the end of the list */ -} - -void read_watchers(storage *store, plane *pl) { - variant fno = read_faction_reference(store); - while (fno.i) { - int n; - watcher *w = (watcher *)malloc(sizeof(watcher)); - ur_add(fno, &w->faction, resolve_faction); - READ_INT(store, &n); - w->mode = (unsigned char)n; - w->next = pl->watchers; - pl->watchers = w; - fno = read_faction_reference(store); - } -} - int readgame(const char *filename, bool backup) { int n, p, nread; @@ -1528,7 +1556,13 @@ int readgame(const char *filename, bool backup) } } else { - read_watchers(&store, pl); + /* WATCHERS - eliminated in February 2016, ca. turn 966 */ + if (gdata.version < CRYPT_VERSION) { + variant fno; + do { + fno = read_faction_reference(&store); + } while (fno.i); + } } a_read(&store, &pl->attribs, pl); if (pl->id != 1094969858) { // Regatta @@ -1815,7 +1849,9 @@ int writegame(const char *filename) WRITE_INT(&store, pl->miny); WRITE_INT(&store, pl->maxy); WRITE_INT(&store, pl->flags); - write_watchers(&store, pl); +#if RELEASE_VERSION < CRYPT_VERSION + write_faction_reference(NULL, &store); /* mark the end of pl->watchers (gone since T966) */ +#endif a_write(&store, pl->attribs, pl); WRITE_SECTION(&store); } diff --git a/src/kernel/save.h b/src/kernel/save.h index ca364fc9c..cedd5befc 100644 --- a/src/kernel/save.h +++ b/src/kernel/save.h @@ -83,6 +83,9 @@ extern "C" { struct gamedata *gamedata_open(const char *filename, const char *mode); void gamedata_close(struct gamedata *data); + /* test-only functions that give access to internal implementation details (BAD) */ + void _test_write_password(struct gamedata *data, const struct faction *f); + void _test_read_password(struct gamedata *data, struct faction *f); #ifdef __cplusplus } #endif diff --git a/src/kernel/save.test.c b/src/kernel/save.test.c index e7f85ad7e..de7f28084 100644 --- a/src/kernel/save.test.c +++ b/src/kernel/save.test.c @@ -3,11 +3,25 @@ #include "save.h" #include "unit.h" +#include "group.h" +#include "ally.h" #include "faction.h" +#include "plane.h" +#include "region.h" #include "version.h" +#include +#include +#include +#include +#include +#include +#include + #include #include +#include + #include static void test_readwrite_data(CuTest * tc) @@ -42,15 +56,17 @@ static void test_readwrite_unit(CuTest * tc) u = test_create_unit(f, r); join_path(datapath(), filename, path, sizeof(path)); - data = gamedata_open(path, "w"); - CuAssertPtrNotNull(tc, data); // TODO: intermittent test + data = gamedata_open(path, "wb"); + CuAssertPtrNotNull(tc, data); + write_unit(data, u); gamedata_close(data); free_gamedata(); f = test_create_faction(0); renumber_faction(f, fno); - data = gamedata_open(path, "r"); + data = gamedata_open(path, "rb"); + CuAssertPtrNotNull(tc, data); u = read_unit(data); gamedata_close(data); @@ -61,10 +77,189 @@ static void test_readwrite_unit(CuTest * tc) test_cleanup(); } +static void test_readwrite_dead_faction_group(CuTest *tc) { + faction *f, *f2; + unit * u; + group *g; + ally *al; + int fno; + + test_cleanup(); + f = test_create_faction(0); + fno = f->no; + CuAssertPtrEquals(tc, f, factions); + CuAssertPtrEquals(tc, 0, f->next); + f2 = test_create_faction(0); + CuAssertPtrEquals(tc, f2, factions->next); + u = test_create_unit(f2, test_create_region(0, 0, 0)); + CuAssertPtrNotNull(tc, u); + g = join_group(u, "group"); + CuAssertPtrNotNull(tc, g); + al = ally_add(&g->allies, f); + CuAssertPtrNotNull(tc, al); + + CuAssertPtrEquals(tc, f, factions); + destroyfaction(&factions); + CuAssertTrue(tc, !f->_alive); + CuAssertPtrEquals(tc, f2, factions); + writegame("test.dat"); + free_gamedata(); + f = f2 = NULL; + readgame("test.dat", false); + CuAssertPtrEquals(tc, 0, findfaction(fno)); + f2 = factions; + CuAssertPtrNotNull(tc, f2); + u = f2->units; + CuAssertPtrNotNull(tc, u); + g = get_group(u); + CuAssertPtrNotNull(tc, g); + CuAssertPtrEquals(tc, 0, g->allies); + test_cleanup(); +} + +static void test_readwrite_dead_faction_regionowner(CuTest *tc) { + faction *f; + region *r; + + test_cleanup(); + config_set("rules.region_owners", "1"); + f = test_create_faction(0); + test_create_unit(f, r = test_create_region(0, 0, 0)); + region_set_owner(r, f, turn); + destroyfaction(&factions); + CuAssertTrue(tc, !f->_alive); + remove_empty_units(); + writegame("test.dat"); + free_gamedata(); + f = NULL; + readgame("test.dat", false); + f = factions; + CuAssertPtrEquals(tc, 0, f); + r = regions; + CuAssertPtrNotNull(tc, r); + CuAssertPtrEquals(tc, 0, region_get_owner(r)); + test_cleanup(); +} + +static void test_readwrite_dead_faction_changefaction(CuTest *tc) { + faction *f, *f2; + region *r; + trigger *tr; + unit * u; + + test_cleanup(); + f = test_create_faction(0); + f2 = test_create_faction(0); + u = test_create_unit(f2, r = test_create_region(0, 0, 0)); + tr = trigger_changefaction(u, f); + add_trigger(&u->attribs, "timer", trigger_timeout(10, tr)); + CuAssertPtrNotNull(tc, a_find(u->attribs, &at_eventhandler)); + destroyfaction(&factions); + CuAssertTrue(tc, !f->_alive); + remove_empty_units(); + writegame("test.dat"); + free_gamedata(); + f = NULL; + readgame("test.dat", false); + f = factions; + CuAssertPtrNotNull(tc, f); + r = regions; + CuAssertPtrNotNull(tc, r); + u = r->units; + CuAssertPtrNotNull(tc, u); + CuAssertPtrEquals(tc, 0, a_find(u->attribs, &at_eventhandler)); + test_cleanup(); +} + +static void test_readwrite_dead_faction_createunit(CuTest *tc) { + faction *f, *f2; + region *r; + trigger *tr; + unit * u; + + test_cleanup(); + f = test_create_faction(0); + f2 = test_create_faction(0); + u = test_create_unit(f2, r = test_create_region(0, 0, 0)); + tr = trigger_createunit(r, f, f->race, 1); + add_trigger(&u->attribs, "timer", trigger_timeout(10, tr)); + CuAssertPtrNotNull(tc, a_find(u->attribs, &at_eventhandler)); + destroyfaction(&factions); + CuAssertTrue(tc, !f->_alive); + remove_empty_units(); + writegame("test.dat"); + free_gamedata(); + f = NULL; + readgame("test.dat", false); + f = factions; + CuAssertPtrNotNull(tc, f); + r = regions; + CuAssertPtrNotNull(tc, r); + u = r->units; + CuAssertPtrNotNull(tc, u); + CuAssertPtrEquals(tc, 0, a_find(u->attribs, &at_eventhandler)); + test_cleanup(); +} + +static void test_read_password(CuTest *tc) { + const char *path = "test.dat"; + gamedata *data; + faction *f; + f = test_create_faction(0); + faction_setpassword(f, password_encode("secret", PASSWORD_DEFAULT)); + data = gamedata_open(path, "wb"); + CuAssertPtrNotNull(tc, data); + _test_write_password(data, f); + gamedata_close(data); + data = gamedata_open(path, "rb"); + CuAssertPtrNotNull(tc, data); + _test_read_password(data, f); + gamedata_close(data); + CuAssertTrue(tc, checkpasswd(f, "secret")); + CuAssertIntEquals(tc, 0, remove(path)); +} + +static void test_read_password_external(CuTest *tc) { + const char *path = "test.dat", *pwfile = "passwords.txt"; + gamedata *data; + faction *f; + FILE * F; + + remove(pwfile); + f = test_create_faction(0); + faction_setpassword(f, password_encode("secret", PASSWORD_DEFAULT)); + CuAssertPtrNotNull(tc, f->_password); + data = gamedata_open(path, "wb"); + CuAssertPtrNotNull(tc, data); + WRITE_TOK(data->store, (const char *)f->_password); + WRITE_TOK(data->store, (const char *)f->_password); + gamedata_close(data); + data = gamedata_open(path, "rb"); + CuAssertPtrNotNull(tc, data); + data->version = BADCRYPT_VERSION; + _test_read_password(data, f); + CuAssertPtrEquals(tc, 0, f->_password); + F = fopen(pwfile, "wt"); + fprintf(F, "%s:secret\n", itoa36(f->no)); + fclose(F); + _test_read_password(data, f); + CuAssertPtrNotNull(tc, f->_password); + gamedata_close(data); + CuAssertTrue(tc, checkpasswd(f, "secret")); + CuAssertIntEquals(tc, 0, remove(path)); + CuAssertIntEquals(tc, 0, remove(pwfile)); +} + CuSuite *get_save_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_readwrite_data); SUITE_ADD_TEST(suite, test_readwrite_unit); + SUITE_ADD_TEST(suite, test_readwrite_dead_faction_createunit); + SUITE_ADD_TEST(suite, test_readwrite_dead_faction_changefaction); + SUITE_ADD_TEST(suite, test_readwrite_dead_faction_regionowner); + DISABLE_TEST(suite, test_readwrite_dead_faction_group); + SUITE_ADD_TEST(suite, test_read_password); + SUITE_ADD_TEST(suite, test_read_password_external); return suite; } diff --git a/src/kernel/version.h b/src/kernel/version.h index c18957530..3ff4e927a 100644 --- a/src/kernel/version.h +++ b/src/kernel/version.h @@ -33,9 +33,10 @@ #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 CRYPT_VERSION 351 /* passwords are encrypted */ -#define RELEASE_VERSION CRYPT_VERSION /* current datafile */ +#define BADCRYPT_VERSION 351 /* passwords are encrypted, poorly */ +#define CRYPT_VERSION 352 /* passwords are encrypted */ +#define RELEASE_VERSION ATTRIBOWNER_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 */ +#define MAX_VERSION BADCRYPT_VERSION /* change this if we can need to read the future datafile, and we can do so */ #define STREAM_VERSION 2 /* internal encoding of binary files */ diff --git a/src/laws.c b/src/laws.c index eb079b8ac..1e1fc33ad 100755 --- a/src/laws.c +++ b/src/laws.c @@ -2172,7 +2172,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, password_hash(pwbuf, 0, PASSWORD_DEFAULT)); + faction_setpassword(u->faction, password_encode(pwbuf, PASSWORD_DEFAULT)); ADDMSG(&u->faction->msgs, msg_message("changepasswd", "value", pwbuf)); return 0; diff --git a/src/reports.c b/src/reports.c index b33f5f1cb..595f92ae3 100644 --- a/src/reports.c +++ b/src/reports.c @@ -1385,17 +1385,9 @@ static void prepare_reports(void) for (r = regions; r; r = r->next) { unit *u; - plane *p = rplane(r); reorder_units(r); - if (p) { - watcher *w = p->watchers; - for (; w; w = w->next) { - faction_add_seen(w->faction, r, w->mode); - } - } - /* Region owner get always the Lighthouse report */ if (bt_lighthouse && config_token("rules.region_owner_pay_building", bt_lighthouse->_name)) { for (b = rbuildings(r); b; b = b->next) { @@ -1464,8 +1456,6 @@ static region *lastregion(faction * f) /* we continue from the best region and look for travelthru etc. */ for (r = f->last->next; r; r = r->next) { - plane *p = rplane(r); - /* search the region for travelthru-attributes: */ if (fval(r, RF_TRAVELUNIT)) { travelthru_map(r, cb_set_last, f); @@ -1474,9 +1464,6 @@ static region *lastregion(faction * f) continue; if (check_leuchtturm(r, f)) f->last = r; - if (p && is_watcher(p, f)) { - f->last = r; - } } return f->last->next; #else diff --git a/src/tests.c b/src/tests.c index b8508b4cc..b52759489 100644 --- a/src/tests.c +++ b/src/tests.c @@ -5,6 +5,7 @@ #include "prefix.h" #include +#include #include #include #include @@ -47,7 +48,7 @@ struct region *test_create_region(int x, int y, const terrain_type *terrain) { region *r = findregion(x, y); if (!r) { - r = new_region(x, y, NULL, 0); + r = new_region(x, y, findplane(x, y), 0); } if (!terrain) { terrain_type *t = get_or_create_terrain("plain"); diff --git a/src/triggers/changefaction.c b/src/triggers/changefaction.c index eb212b769..47eee5874 100644 --- a/src/triggers/changefaction.c +++ b/src/triggers/changefaction.c @@ -79,14 +79,20 @@ static void changefaction_write(const trigger * t, struct storage *store) { changefaction_data *td = (changefaction_data *)t->data.v; write_unit_reference(td->unit, store); - write_faction_reference(td->faction, store); + write_faction_reference(td->faction->_alive ? td->faction : NULL, store); } static int changefaction_read(trigger * t, struct storage *store) { + variant var; changefaction_data *td = (changefaction_data *)t->data.v; read_reference(&td->unit, store, read_unit_reference, resolve_unit); - read_reference(&td->faction, store, read_faction_reference, resolve_faction); + var = read_faction_reference(store); + if (var.i == 0) { + return AT_READ_FAIL; + } + ur_add(var, &td->faction, resolve_faction); + // read_reference(&td->faction, store, read_faction_reference, resolve_faction); return AT_READ_OK; } diff --git a/src/triggers/createunit.c b/src/triggers/createunit.c index 642e598f0..ef79d4300 100644 --- a/src/triggers/createunit.c +++ b/src/triggers/createunit.c @@ -82,7 +82,7 @@ static int createunit_handle(trigger * t, void *data) static void createunit_write(const trigger * t, struct storage *store) { createunit_data *td = (createunit_data *)t->data.v; - write_faction_reference(td->f, store); + write_faction_reference(td->f->_alive ? td->f : NULL, store); write_region_reference(td->r, store); write_race_reference(td->race, store); WRITE_INT(store, td->number); @@ -91,21 +91,27 @@ static void createunit_write(const trigger * t, struct storage *store) static int createunit_read(trigger * t, struct storage *store) { createunit_data *td = (createunit_data *)t->data.v; + variant var; + int result = AT_READ_OK; - int uc = - read_reference(&td->f, store, read_faction_reference, resolve_faction); - int rc = - read_reference(&td->r, store, read_region_reference, + var = read_faction_reference(store); + if (var.i > 0) { + td->f = findfaction(var.i); + if (!td->f) { + ur_add(var, &td->f, resolve_faction); + } + } + else { + result = AT_READ_FAIL; + } + read_reference(&td->r, store, read_region_reference, RESOLVE_REGION(global.data_version)); td->race = (const struct race *)read_race_reference(store).v; - - if (uc == 0 && rc == 0) { - if (!td->f || !td->r) - return AT_READ_FAIL; + if (!td->race) { + result = AT_READ_FAIL; } READ_INT(store, &td->number); - - return AT_READ_OK; + return result; } trigger_type tt_createunit = { diff --git a/src/util/gamedata.test.c b/src/util/gamedata.test.c new file mode 100644 index 000000000..b28066b97 --- /dev/null +++ b/src/util/gamedata.test.c @@ -0,0 +1,25 @@ +#include +#include "gamedata.h" + +#include +#include +#include + +static void test_gamedata(CuTest * tc) +{ + gamedata *data; + data = gamedata_open("test.dat", "wb", 0); + CuAssertPtrNotNull(tc, data); + gamedata_close(data); + data = gamedata_open("test.dat", "rb", 0); + CuAssertPtrNotNull(tc, data); + gamedata_close(data); + CuAssertIntEquals(tc, 0, remove("test.dat")); +} + +CuSuite *get_gamedata_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_gamedata); + return suite; +} diff --git a/src/util/password.c b/src/util/password.c index 271cedf6d..c7850eec8 100644 --- a/src/util/password.c +++ b/src/util/password.c @@ -2,7 +2,9 @@ #include "password.h" #include +#include #include +#include #include #include @@ -25,73 +27,104 @@ } while (0) -char *password_gensalt(void) { - static char salt[SALTLEN + 1]; +char *password_gensalt(char *salt, size_t salt_len) { + size_t buflen = salt_len-1; char *cp = salt; - int buflen = SALTLEN; while (buflen) { unsigned long ul = genrand_int32() & (unsigned long)time(0); - b64_from_24bit((char)(ul & 0xFF), (char)((ul>>8)&0xff), (char)((ul>>16)&0xFF), 4); + b64_from_24bit((char)(ul & 0xFF), (char)((ul >> 8) & 0xff), (char)((ul >> 16) & 0xFF), 4); } - salt[SALTLEN] = 0; + salt[salt_len-1] = 0; return salt; } -static const char * password_hash_i(const char * passwd, const char *salt, int algo, char *result, size_t len) { - assert(passwd); - if (!salt) { - salt = password_gensalt(); - } - if (algo==PASSWORD_PLAIN) { - _snprintf(result, len, "$0$%s$%s", salt, passwd); - } - else if (algo == PASSWORD_MD5) { - return md5_crypt_r(passwd, salt, result, len); - } - else if (algo == PASSWORD_APACHE_MD5) { - apr_md5_encode(passwd, salt, result, len); +static bool password_is_implemented(int algo) { + return algo == PASSWORD_PLAINTEXT || algo == PASSWORD_BCRYPT || algo == PASSWORD_NOCRYPT || algo == PASSWORD_MD5 || algo == PASSWORD_APACHE_MD5; +} + +static const char * password_hash_i(const char * passwd, const char *input, int algo, char *result, size_t len) { + if (algo == PASSWORD_BCRYPT) { + char salt[MAXSALTLEN]; + char setting[40]; + if (!input) { + input = password_gensalt(salt, MAXSALTLEN); + } + if (_crypt_gensalt_blowfish_rn("$2y$", 5, input, strlen(input), setting, sizeof(setting)) == NULL) { + return NULL; + } + if (_crypt_blowfish_rn(passwd, setting, result, len) == NULL) { + return NULL; + } return result; } - else { - return NULL; + else if (algo == PASSWORD_PLAINTEXT) { + _snprintf(result, len, "%s", passwd); + return result; } - return result; + else if (algo == PASSWORD_NOCRYPT) { + _snprintf(result, len, "$0$%s", passwd); + return result; + } + else if (password_is_implemented(algo)) { + char salt[MAXSALTLEN]; + assert(passwd); + if (input) { + const char * dol = strchr(input, '$'); + size_t salt_len; + if (dol) { + assert(dol > input && dol[0] == '$'); + salt_len = dol - input; + } + else { + salt_len = strlen(input); + } + assert(salt_len < MAXSALTLEN); + memcpy(salt, input, salt_len); + salt[salt_len] = 0; + } else { + input = password_gensalt(salt, sizeof(salt)); + } + if (algo == PASSWORD_MD5) { + return md5_crypt_r(passwd, input, result, len); + } + else if (algo == PASSWORD_APACHE_MD5) { + apr_md5_encode(passwd, input, result, len); + return result; + } + } + return NULL; } -const char * password_hash(const char * passwd, const char * salt, int algo) { +const char * password_encode(const char * passwd, int algo) { static char result[64]; // TODO: static result buffers are bad mojo! if (algo < 0) algo = PASSWORD_DEFAULT; - return password_hash_i(passwd, salt, algo, result, sizeof(result)); -} - -static bool password_is_implemented(int algo) { - return algo==PASSWORD_PLAIN || algo==PASSWORD_MD5 || algo==PASSWORD_APACHE_MD5; + return password_hash_i(passwd, 0, algo, result, sizeof(result)); } int password_verify(const char * pwhash, const char * passwd) { - char salt[MAXSALTLEN+1]; char hash[64]; - size_t len; - int algo; + int algo = PASSWORD_PLAINTEXT; char *pos; - const char *dol, *result; + const char *result; assert(passwd); assert(pwhash); - assert(pwhash[0] == '$'); - algo = pwhash[1]; - pos = strchr(pwhash+2, '$'); - assert(pos && pos[0] == '$'); - ++pos; - dol = strchr(pos, '$'); - assert(dol>pos && dol[0] == '$'); - len = dol - pos; - assert(len <= MAXSALTLEN); - strncpy(salt, pos, len); - salt[len] = 0; - result = password_hash_i(passwd, salt, algo, hash, sizeof(hash)); + if (pwhash[0] == '$') { + algo = pwhash[1]; + } if (!password_is_implemented(algo)) { return VERIFY_UNKNOWN; } + if (algo == PASSWORD_PLAINTEXT) { + return (strcmp(passwd, pwhash) == 0) ? VERIFY_OK : VERIFY_FAIL; + } else if (algo == PASSWORD_BCRYPT) { + char sample[200]; + _crypt_blowfish_rn(passwd, pwhash, sample, sizeof(sample)); + return (strcmp(sample, pwhash) == 0) ? VERIFY_OK : VERIFY_FAIL; + } + pos = strchr(pwhash+2, '$'); + assert(pos && pos[0] == '$'); + pos = strchr(pos, '$')+1; + result = password_hash_i(passwd, pos, algo, hash, sizeof(hash)); if (strcmp(pwhash, result) == 0) { return VERIFY_OK; } diff --git a/src/util/password.h b/src/util/password.h index 0bdd9d4ff..fe84716d7 100644 --- a/src/util/password.h +++ b/src/util/password.h @@ -1,15 +1,16 @@ #pragma once -#define PASSWORD_PLAIN '0' +#define PASSWORD_PLAINTEXT 0 +#define PASSWORD_NOCRYPT '0' #define PASSWORD_MD5 '1' #define PASSWORD_BCRYPT '2' // not implemented #define PASSWORD_APACHE_MD5 'a' #define PASSWORD_SHA256 '5' // not implemented #define PASSWORD_SHA512 '6' // not implemented -#define PASSWORD_DEFAULT PASSWORD_APACHE_MD5 +#define PASSWORD_DEFAULT PASSWORD_PLAINTEXT #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, const char *salt, int algo); +const char * password_encode(const char *passwd, int algo); diff --git a/src/util/password.test.c b/src/util/password.test.c index b4f4005da..3df2d2ed8 100644 --- a/src/util/password.test.c +++ b/src/util/password.test.c @@ -1,25 +1,43 @@ #include -#include #include "password.h" +#include +#include static void test_passwords(CuTest *tc) { - const char *hash; + const char *hash, *expect; - hash = password_hash("Hodor", "FqQLkl8g", PASSWORD_APACHE_MD5); + expect = "$apr1$FqQLkl8g$.icQqaDJpim4BVy.Ho5660"; + CuAssertIntEquals(tc, VERIFY_OK, password_verify(expect, "Hodor")); + hash = password_encode("Hodor", PASSWORD_APACHE_MD5); CuAssertPtrNotNull(tc, hash); - CuAssertStrEquals(tc, "$apr1$FqQLkl8g$.icQqaDJpim4BVy.Ho5660", hash); - CuAssertIntEquals(tc, VERIFY_OK, password_verify(hash, "Hodor")); + CuAssertIntEquals(tc, 0, strncmp(hash, expect, 6)); - hash = password_hash("jollygood", "ZouUn04i", PASSWORD_MD5); + expect = "$1$ZouUn04i$yNnT1Oy8azJ5V.UM9ppP5/"; + CuAssertIntEquals(tc, VERIFY_OK, password_verify(expect, "jollygood")); + hash = password_encode("jollygood", PASSWORD_MD5); CuAssertPtrNotNull(tc, hash); - CuAssertStrEquals(tc, "$1$ZouUn04i$yNnT1Oy8azJ5V.UM9ppP5/", hash); - CuAssertIntEquals(tc, VERIFY_OK, password_verify(hash, "jollygood")); + CuAssertIntEquals(tc, 0, strncmp(hash, expect, 3)); - hash = password_hash("password", "hodor", PASSWORD_PLAIN); + expect = "password"; + hash = password_encode("password", PASSWORD_PLAINTEXT); CuAssertPtrNotNull(tc, hash); - CuAssertStrEquals(tc, "$0$hodor$password", hash); - CuAssertIntEquals(tc, VERIFY_OK, password_verify(hash, "password")); - CuAssertIntEquals(tc, VERIFY_FAIL, password_verify(hash, "arseword")); + CuAssertStrEquals(tc, hash, expect); + CuAssertIntEquals(tc, VERIFY_OK, password_verify(expect, "password")); + CuAssertIntEquals(tc, VERIFY_FAIL, password_verify(expect, "arseword")); + + expect = "$0$password"; + hash = password_encode("password", PASSWORD_NOCRYPT); + CuAssertPtrNotNull(tc, hash); + CuAssertStrEquals(tc, hash, expect); + CuAssertIntEquals(tc, VERIFY_OK, password_verify(expect, "password")); + CuAssertIntEquals(tc, VERIFY_FAIL, password_verify(expect, "arseword")); + + expect = "$2y$05$RJ8qAhu.foXyJLdc2eHTLOaK4MDYn3/v4HtOVCq0Plv2yxcrEB7Wm"; + CuAssertIntEquals(tc, VERIFY_OK, password_verify(expect, "Hodor")); + hash = password_encode("Hodor", PASSWORD_BCRYPT); + CuAssertPtrNotNull(tc, hash); + CuAssertIntEquals(tc, 0, strncmp(hash, expect, 7)); + CuAssertIntEquals(tc, VERIFY_UNKNOWN, password_verify("$9$saltyfish$password", "password")); } diff --git a/tests/write-reports.sh b/tests/write-reports.sh index c87059854..2183b17dd 100755 --- a/tests/write-reports.sh +++ b/tests/write-reports.sh @@ -25,7 +25,7 @@ TESTS=../Debug/eressea/test_eressea SERVER=../Debug/eressea/eressea if [ -n "$VALGRIND" ]; then SUPP=../share/ubuntu-12_04.supp -VALGRIND="$VALGRIND --suppressions=$SUPP --error-exitcode=1 --leak-check=no" +VALGRIND="$VALGRIND --track-origins=yes --gen-suppressions=all --suppressions=$SUPP --error-exitcode=1 --leak-check=no" fi echo "running $TESTS" $VALGRIND $TESTS From c823a3b036e0817bbfb258ea767c61cd0c1e4d21 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 16 Feb 2016 09:28:10 +0100 Subject: [PATCH 3/9] handle regions that have no owner --- src/attributes/otherfaction.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/attributes/otherfaction.c b/src/attributes/otherfaction.c index 8e4e7a6af..83196f959 100644 --- a/src/attributes/otherfaction.c +++ b/src/attributes/otherfaction.c @@ -58,7 +58,8 @@ attrib_type at_otherfaction = { struct faction *get_otherfaction(const struct attrib *a) { - return (faction *)(a->data.v); + faction * f = (faction *)(a->data.v); + return (f && f->_alive) ? f : NULL; } struct attrib *make_otherfaction(struct faction *f) From 4f7e1cb80f2e72f5e5c6afb88b7a4c63e63b05a2 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 18 Feb 2016 10:56:43 +0100 Subject: [PATCH 4/9] integration test update. - have a faction that quits, - try to reload the datafile we just wrote. --- tests/data/184.dat | Bin 7632 -> 8216 bytes tests/orders.184 | 12 ++++++++++++ tests/run-turn.sh | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/data/184.dat b/tests/data/184.dat index 734e5a19fd610d5aee2e81843190b8076a84dbb3..78651b2c3f66c0be97c7bc74cf8e0a1ec16e7b94 100644 GIT binary patch delta 806 zcmY+CJ#W)M9LAlrl~6%KLbRw%9ZbdKvwgN>iv_!ho1|%8+SpE_O2~=rI4`ynC(g@l ztymbVER3+Tbzop-XX68uk%BKAf=Cktv6bGked}7p zSK{%_-qFzu(j0{h$u1EBaDqrxD#~!&sijGbg#JPG+e@x`CQTNwCLd*$A6r;{NqN4Ptj8pY3_YiHq`D=?pW%qt~!~zXD9TRdzu1Ml>Bnu7JAy;(jsvzplSg8&~60@ z{e1i0jZ;9Nsbm2P$hF%83D$YeHM`{nI_rv2AW2n+ok2!TDXC982 zisvN*`F<}3kjf}*D5DHTOY6B8rY*$OPu%uA~#CTdJ( zXVhb7D@-a(&-Iy@s5!X>#5KwC$+a*7%1&Z30809l7-n05)YdWSgG{k7O*8{>e}iNb z)2b4)Qzr*9hqJRK Date: Thu, 18 Feb 2016 11:10:49 +0100 Subject: [PATCH 5/9] gcc is picky, fix gcc warnings --- src/kernel/plane.h | 1 + src/kernel/region.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/kernel/plane.h b/src/kernel/plane.h index d8ec176a9..926ffb4e2 100644 --- a/src/kernel/plane.h +++ b/src/kernel/plane.h @@ -22,6 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif + struct faction; struct region; struct faction; struct plane; diff --git a/src/kernel/region.h b/src/kernel/region.h index 5974fd96c..72496193b 100644 --- a/src/kernel/region.h +++ b/src/kernel/region.h @@ -66,6 +66,7 @@ extern "C" { struct message_list; struct rawmaterial; struct item; + struct faction; #define MORALE_TAX_FACTOR 0.005 /* 0.5% tax per point of morale */ #define MORALE_MAX 10 /* Maximum morale allowed */ From be99c02a8214017ba2eae3b04c6599029a0d3036 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 18 Feb 2016 12:31:05 +0100 Subject: [PATCH 6/9] fix valgrind report --- src/triggers/createunit.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/triggers/createunit.c b/src/triggers/createunit.c index ef79d4300..45b67ec3a 100644 --- a/src/triggers/createunit.c +++ b/src/triggers/createunit.c @@ -104,6 +104,7 @@ static int createunit_read(trigger * t, struct storage *store) else { result = AT_READ_FAIL; } + // read_reference(&td->f, store, read_faction_reference, resolve_faction); read_reference(&td->r, store, read_region_reference, RESOLVE_REGION(global.data_version)); td->race = (const struct race *)read_race_reference(store).v; From 77ed6f372228ed72212b15ecb9511216c182815f Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 18 Feb 2016 12:46:14 +0100 Subject: [PATCH 7/9] add missing file --- tests/test-turn.lua | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 tests/test-turn.lua diff --git a/tests/test-turn.lua b/tests/test-turn.lua new file mode 100644 index 000000000..03178b74d --- /dev/null +++ b/tests/test-turn.lua @@ -0,0 +1,5 @@ +dofile('../scripts/run-turn.lua') +turn = get_turn() +eressea.free_game() +print("trying to read data from " .. turn) +eressea.read_game(turn .. ".dat") From 1e4b860a2e0870b8ce652c47cfe502d6efeaebe5 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 19 Feb 2016 18:25:21 +0100 Subject: [PATCH 8/9] some trivial assertions --- src/kernel/faction.c | 1 + src/util/resolve.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/kernel/faction.c b/src/kernel/faction.c index b52879464..f67dbe47a 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -217,6 +217,7 @@ int resolve_faction(variant id, void *address) result = -1; } } + assert(address); *(faction **)address = f; return result; } diff --git a/src/util/resolve.c b/src/util/resolve.c index cee4a9d19..e8dd0c17a 100644 --- a/src/util/resolve.c +++ b/src/util/resolve.c @@ -58,6 +58,7 @@ resolve_fun resolver) void ur_add(variant data, void *ptrptr, resolve_fun fun) { + assert(ptrptr); if (ur_list == NULL) { ur_list = malloc(BLOCKSIZE * sizeof(unresolved)); ur_begin = ur_current = ur_list; @@ -86,6 +87,7 @@ void resolve(void) ur_list = ur; continue; } + assert(ur->ptrptr); ur->resolve(ur->data, ur->ptrptr); ++ur; } From 7807e9e71031bf304f2eca3c47a6b99338ee8ee6 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 22 Feb 2016 21:35:37 +0100 Subject: [PATCH 9/9] fix integration test data file --- src/bind_faction.c | 5 +++-- tests/data/184.dat | Bin 8216 -> 7720 bytes tests/orders.184 | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/bind_faction.c b/src/bind_faction.c index c6b747416..a4302f3c9 100644 --- a/src/bind_faction.c +++ b/src/bind_faction.c @@ -384,8 +384,9 @@ static int tolua_faction_create(lua_State * L) static int tolua_faction_get_password(lua_State * L) { - unused_arg(L); - return 0; + faction *self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->_password); + return 1; } static int tolua_faction_set_password(lua_State * L) diff --git a/tests/data/184.dat b/tests/data/184.dat index 78651b2c3f66c0be97c7bc74cf8e0a1ec16e7b94..d219f92ddd96f5bdd7d9ee4c4e5276bbb1dee895 100644 GIT binary patch delta 197 zcmbQ?u)>Bjj*)?ZiGhKEWg@2$D@#$4iTT9D2v(N7^vtY@i5ipH8TDA0Gg8whCTdP@ zVbo(~F)Q-P2TDw0GGJw?Dk}l8C)Y9Qv$7Z^n}IpMK{B}oSw)irnZsFGO!F;(CTdLn z#tc+rVPIwo;uN!h)cE)qgE${SoXSd{Ob{oZ704;fFHZt--m>bmu$ZJ(O?G69WMwH& W&M*OqzF<=Xax6?MH|w*%lmGzsc{v9F delta 709 zcmY+CJC52w9EW+O*c)sYMVdrOGh@%#21}6=ykH*dk@+#r4kwA+9B{QZBP@9)2Uy!n*PWOA8ICV#rYZ(aj)?Xv(MDMe&Ufh;!5 zWHaiF{N=Rj4Y$?-*#~rfm4AD3mGL@h$WNyd`ka<7aB$+ zCMp63>h{=a#rA8Qf&P?$`VZQ zFWGAgj_e4lRlw_-9%_ohGP4Oc=cRG8DC#Nx`-vSw6bAwCz|^r?@cp;Jj&pGC- zb)dZglWhL^IgViTT3lYzmol?+*?U{G_x_q~yKcJ5&%!kZ5m-&0i>BB!u6xI>T?;Qr t*?V9GXfWr0g~sJf5?L{ZDhN8wzAtx5LvFR$R=0Z52toz@`0(P-?SBRd)`0*3 diff --git a/tests/orders.184 b/tests/orders.184 index eb53b5b51..980993481 100644 --- a/tests/orders.184 +++ b/tests/orders.184 @@ -1,8 +1,8 @@ -ERESSEA 6rLo "4jLm82" +ERESSEA 6rLo "6rLo" EINHEIT 7Lgf NACH NW NW NAECHSTER -ERESSEA w86y "mrqa" +ERESSEA w86y "w86y" EINHEIT uc3u STIRB "mrqa" NAECHSTER