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/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/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/faction.c b/src/kernel/faction.c index cf1372950..10c614505 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; @@ -566,7 +566,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/save.c b/src/kernel/save.c index 094ce1d78..de6dba3a3 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1155,6 +1155,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. @@ -1221,8 +1273,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); } @@ -1330,7 +1381,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); 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 87658187c..46369bd01 100644 --- a/src/kernel/save.test.c +++ b/src/kernel/save.test.c @@ -14,9 +14,14 @@ #include #include #include +#include +#include + #include #include +#include + #include static void test_readwrite_data(CuTest * tc) @@ -51,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); @@ -195,6 +202,55 @@ static void test_readwrite_dead_faction_createunit(CuTest *tc) { 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(); @@ -204,5 +260,7 @@ CuSuite *get_save_suite(void) 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 257fc5649..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 (3.8.2), plane.watchers are gone (3.8.3) */ -#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/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