Skip to content

Commit

Permalink
Fix #34 KeePass: socket connection failed when used in parallel
Browse files Browse the repository at this point in the history
  • Loading branch information
viczem committed Nov 9, 2022
1 parent ac84c3c commit 107fb09
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 13 deletions.
2 changes: 1 addition & 1 deletion galaxy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace: viczem
name: keepass

# The version of the collection. Must be compatible with semantic versioning
version: 0.7.1
version: 0.7.2

# The path to the Markdown (.md) readme file. This path is relative to the root of the collection
readme: README.md
Expand Down
42 changes: 30 additions & 12 deletions plugins/lookup/keepass.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import argparse
import getpass
import hashlib
import fcntl
import os
import re
import socket
Expand All @@ -21,7 +22,7 @@
DOCUMENTATION = """
lookup: keepass
author: Victor Zemtsov <viczem.dev@gmail.com>
version_added: '0.7.1'
version_added: '0.7.2'
short_description: Fetching data from KeePass file
description:
- This lookup returns a value of a property of a KeePass entry
Expand Down Expand Up @@ -88,7 +89,9 @@ def run(self, terms, variables=None, **kwargs):
socket_path = _keepass_socket_path(var_dbx)
lock_file_ = socket_path + ".lock"

if not os.path.isfile(lock_file_):
try:
os.open(lock_file_, os.O_RDWR)
except FileNotFoundError:
cmd = [
"/usr/bin/env",
"python3",
Expand Down Expand Up @@ -189,7 +192,6 @@ def _keepass_socket(kdbx, kdbx_key, sock_path, ttl=60, kdbx_password=None):
"""
tmp_files = []
try:
os.umask(0o177)
with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s:
s.bind(sock_path)
s.listen(1)
Expand Down Expand Up @@ -240,6 +242,9 @@ def _keepass_socket(kdbx, kdbx_key, sock_path, ttl=60, kdbx_password=None):
else:
conn.send(_resp("password", 1))
break
elif cmd == "password":
conn.send(_resp("password", 0))
break

# CMD: fetch
# Read data from decrypted KeePass file
Expand Down Expand Up @@ -404,6 +409,20 @@ def _keepass_socket_path(dbx_path):
return "%s/ansible-keepass-%s.sock" % (tempdir, suffix[:8])


def lock(kdbx_sock_path):
fd = os.open(kdbx_sock_path + ".lock", os.O_RDWR | os.O_CREAT | os.O_TRUNC)

try:
# The LOCK_EX means that only one process can hold the lock
# The LOCK_NB means that the fcntl.flock() is not blocking
# https://docs.python.org/3/library/fcntl.html#fcntl.flock
fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
except (IOError, OSError):
return None

return fd


if __name__ == "__main__":
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument("kdbx", type=str)
Expand All @@ -413,24 +432,23 @@ def _keepass_socket_path(dbx_path):
arg_parser.add_argument("--ask-pass", action="store_true")
args = arg_parser.parse_args()

kdbx = os.path.realpath(os.path.expanduser(os.path.expandvars(args.kdbx)))
arg_kdbx = os.path.realpath(os.path.expanduser(os.path.expandvars(args.kdbx)))
if args.key:
key = os.path.realpath(os.path.expanduser(os.path.expandvars(args.key)))
arg_key = os.path.realpath(os.path.expanduser(os.path.expandvars(args.key)))
else:
key = None
arg_key = None

if args.kdbx_sock:
kdbx_sock = args.kdbx_sock
arg_kdbx_sock = args.kdbx_sock
else:
kdbx_sock = _keepass_socket_path(kdbx)
arg_kdbx_sock = _keepass_socket_path(arg_kdbx)

password = None
if args.ask_pass:
password = getpass.getpass("Password: ")
if isinstance(password, bytes):
password = password.decode(sys.stdin.encoding)

lock_file = kdbx_sock + ".lock"
if not os.path.isfile(lock_file):
open(lock_file, "a").close()
_keepass_socket(kdbx, key, kdbx_sock, args.ttl, password)
os.umask(0o177)
if lock(arg_kdbx_sock):
_keepass_socket(arg_kdbx, arg_key, arg_kdbx_sock, args.ttl, password)

0 comments on commit 107fb09

Please sign in to comment.