From 5a1c96bd936da8b330d5bd2392c34ba58659caa4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 27 Sep 2018 16:57:39 +0200 Subject: [PATCH 1/3] make python password checks use the database and bcrypt --- process/checkpasswd.py | 13 +++-- process/epasswd.py | 111 +++++++++++++++++++++++++------------- process/process-orders.py | 6 ++- process/sendreport.sh | 6 ++- 4 files changed, 92 insertions(+), 44 deletions(-) diff --git a/process/checkpasswd.py b/process/checkpasswd.py index f797dcfde..dd4924b32 100755 --- a/process/checkpasswd.py +++ b/process/checkpasswd.py @@ -6,14 +6,19 @@ from epasswd import EPasswd if len(sys.argv)<4: sys.exit(-2) -passfile=sys.argv[1] +filename=sys.argv[1] myfaction=sys.argv[2] mypasswd=sys.argv[3] -if mypasswd[0]=='"': - mypasswd=mypasswd[1:len(mypasswd)-1] +if mypasswd[0] == '"': + mypasswd = mypasswd.strip('"') + +pw_data = EPasswd() +try: + pw_data.load_database(filename) +except: + pw_data.load_file(filename) -pw_data=EPasswd(passfile) if pw_data.fac_exists(myfaction): if pw_data.check(myfaction, mypasswd): sys.exit(0) diff --git a/process/epasswd.py b/process/epasswd.py index aa3d79fa6..4798967a9 100755 --- a/process/epasswd.py +++ b/process/epasswd.py @@ -4,47 +4,82 @@ from string import split from string import strip from string import lower import subprocess +import bcrypt +import sqlite3 + +def baseconvert(n, base): + """convert positive decimal integer n to equivalent in another base (2-36)""" + + digits = "0123456789abcdefghijkLmnopqrstuvwxyz" + + try: + n = int(n) + base = int(base) + except: + return "" + + if n < 0 or base < 2 or base > 36: + return "" + + s = "" + while True: + r = n % base + s = digits[r] + s + n = n / base + if n == 0: + break + + return s class EPasswd: - def _check_apr1(self, pwhash, pw): - spl = split(pwhash, '$') - salt = spl[2] - hash = subprocess.check_output(['openssl', 'passwd', '-apr1', '-salt', salt, pw]).decode('utf-8').strip() - return hash==pwhash + def __init__(self): + self.data = {} - def __init__(self, file): - self.data = {} - try: - fp = open(file,"r") - except: - fp = None - if fp != None: - while True: - line = fp.readline() - if not line: break - line = strip(line) - [id, email, passwd] = split(line, ":")[0:3] - lc_id = lower(id) - self.data[lc_id] = {} - self.data[lc_id]["id"] = id - self.data[lc_id]["email"] = email - self.data[lc_id]["passwd"] = passwd - fp.close() + def set_data(no, email, passwd): + lc_id = lower(no) + self.data[lc_id] = {} + self.data[lc_id]["id"] = no + self.data[lc_id]["email"] = email + self.data[lc_id]["passwd"] = passwd - def check(self, id, passwd): - pw = self.get_passwd(id) - if pw[0:6]=='$apr1$': - return self._check_apr1(pw, passwd) - return pw == passwd + def load_database(self, file): + conn = sqlite3.connect(file) + c = conn.cursor() + c.execute('SELECT MAX(turn) FROM factions') + args = c.fetchone() + for row in c.execute('SELECT no, email, password FROM factions WHERE turn=?', args): + (no, email, passwd) = row + self.set_data(baseconvert(no, 36), email, passwd) + conn.close() - def get_passwd(self, id): - return self.data[lower(id)]["passwd"] - - def get_email(self, id): - return self.data[lower(id)]["email"] - - def get_canon_id(self, id): - return self.data[lower(id)]["id"] + def load_file(self, file): + try: + fp = open(file,"r") + except: + fp = None + if fp != None: + while True: + line = fp.readline() + if not line: break + line = strip(line) + [id, email, passwd] = split(line, ":")[0:3] + self.set_data(id, email, passwd) + fp.close() - def fac_exists(self, id): - return self.data.has_key(lower(id)) + def check(self, id, passwd): + pw = self.get_passwd(id) + if pw[0:4]=='$2a$' or pw[0:4]=='$2y$': + return bcrypt.checkpw(passwd, pw) + return pw == passwd + + def get_passwd(self, id): + return self.data[lower(id)]["passwd"] + + def get_email(self, id): + return self.data[lower(id)]["email"] + + def get_canon_id(self, id): + return self.data[lower(id)]["id"] + + def fac_exists(self, id): + return self.data.has_key(lower(id)) diff --git a/process/process-orders.py b/process/process-orders.py index 8ed5e8625..3c741bfeb 100755 --- a/process/process-orders.py +++ b/process/process-orders.py @@ -128,7 +128,11 @@ def echeck(filename, locale, rules): return mail #print "reading password file..." -pw_data = EPasswd(os.path.join(game_dir,"passwd")) +pw_data = EPasswd() +try: + pw_data.load_database(os.path.join(game_dir,"eressea.db")) +except: + pw_data.load_file(os.path.join(game_dir,"passwd")) #print "reading orders.queue..." # move the queue file to a save space while locking it: diff --git a/process/sendreport.sh b/process/sendreport.sh index d98ed505e..d8fe79d47 100755 --- a/process/sendreport.sh +++ b/process/sendreport.sh @@ -30,7 +30,11 @@ LOCKFILE="$ERESSEA/.report.lock" echo "$(date):report:$GAME:$EMAIL:$FACTION:$PASSWD" >> "$ERESSEA/request.log" cd "$ERESSEA" || exit -checkpasswd.py "game-$GAME/passwd" "$FACTION" "$PASSWD" || reply "Das Passwort fuer die Partei $FACTION ist ungueltig" +PWFILE="game-$GAME/eressea.db" +if [ ! -e "$PWFILE" ]; then + PWFILE="game-$GAME/passwd" +fi +checkpasswd.py "$PWFILE" "$FACTION" "$PASSWD" || reply "Das Passwort fuer die Partei $FACTION ist ungueltig" cd "$ERESSEA/game-$GAME/reports" || exit if [ ! -e "${FACTION}.sh" ]; then From 88f0504f48572b721f766fe0cd344ac670bb06e3 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 27 Sep 2018 17:08:04 +0200 Subject: [PATCH 2/3] no such file sendpasswd.py (and no suppor for feature possible) --- process/procmail/rules | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/process/procmail/rules b/process/procmail/rules index 32626fe56..7c70c84bb 100644 --- a/process/procmail/rules +++ b/process/procmail/rules @@ -2,26 +2,6 @@ ## Eressea Reportversand ## -:0:server.lock -* ^Subject:.*ERE.*2.*PASSWOR.* -| sendpassword.py $HOME/eressea/game-2/passwd - -:0:server.lock -* ^Subject:.*ERE.*3.*PASSWOR.* -| sendpassword.py $HOME/eressea/game-3/passwd - -:0:server.lock -* ^Subject:.*ERE.*4.*PASSWOR.* -| sendpassword.py $HOME/eressea/game-4/passwd - -:0:server.lock -* ^Subject:.*ERE.*PASSWOR.* -| sendpassword.py $HOME/eressea/game-2/passwd - -:0:server.lock -* ^Subject:.*E3.*PASSWOR.* -| sendpassword.py $HOME/eressea/game-3/passwd - :0:server.lock * ^Subject:.*ERE.*2.*REPORT \/.* * !From: .*eressea.*@eressea.de From 4a6957378683831f7768d1ed9425c42953fb78f6 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 30 Sep 2018 13:36:34 +0200 Subject: [PATCH 3/3] change database selection, fix in-memory db --- s/cmake-init | 35 ++++++++++++++++++++++++++++++++++- src/CMakeLists.txt | 3 +++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/s/cmake-init b/s/cmake-init index 781db1ea7..eea222334 100755 --- a/s/cmake-init +++ b/s/cmake-init @@ -1,13 +1,46 @@ #!/bin/sh -ERESSEA_DB=db +ERESSEA_DB=memory pkg-config --exists sqlite3 && ERESSEA_DB=sqlite + +GETOPT=getopt +GETOPT_LONG=1 + +if [ "Darwin" = "$(uname)" ] ; then + if [ -x "/usr/local/opt/gnu-getopt/bin/getopt" ] ; then + GETOPT="/usr/local/opt/gnu-getopt/bin/getopt" + else + GETOPT_LONG=0 + fi +fi + +if [ $GETOPT_LONG -eq 1 ]; then + options=$(${GETOPT} -o d: -l db: -- "$@") +else # assume GNU getopt (long arguments) + options=$(${GETOPT} d: "$@") +fi + # Parse command line arguments +eval set -- "$options" +until [ -z "$1" ] ; do + case $1 in + -d|--db) + ERESSEA_DB=$2 + shift + ;; + --) shift; break;; + (-*) echo "$0: error - unrecognized option $1" 1>&2; exit 1;; + (*) break;; + esac + shift +done while [ ! -z "$1" ] ; do if [ "$1" = "--with-db" ] ; then ERESSEA_DB=db elif [ "$1" = "--with-sqlite" ] ; then ERESSEA_DB=sqlite +elif [ "$1" = "--with-memory" ] ; then +ERESSEA_DB=memory fi shift 1 done diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eacc879e5..8a7edbcc4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -179,6 +179,9 @@ endif() add_library(version STATIC ${VERSION_SRC}) add_library(game ${ERESSEA_SRC}) + +#add_executable(checker ${CHECK_SRC}) + add_executable(eressea ${SERVER_SRC}) if (IWYU_PATH) set_property(TARGET eressea PROPERTY C_INCLUDE_WHAT_YOU_USE ${IWYU_PATH})