Files
archy/scripts/write-lnd-config.py

64 lines
2.4 KiB
Python

#!/usr/bin/env python3
"""Internal elevated writer: configuration bytes arrive only on stdin.
Use a stable directory descriptor, exclusive temporary file, exact input-length
check and same-directory rename. Never evaluate configuration as a program.
"""
import os
import secrets
import stat
import sys
def write_config(path, expected_length, source):
parent, name = os.path.split(path)
if not parent or not name or name in (".", "..") or expected_length < 0:
raise ValueError("invalid destination")
directory = os.open(parent, os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW)
temporary = ".lnd-config-" + secrets.token_hex(16)
created = False
try:
try:
info = os.stat(name, dir_fd=directory, follow_symlinks=False)
if not stat.S_ISREG(info.st_mode) or stat.S_IMODE(info.st_mode) & 0o7000:
raise ValueError("destination must be an ordinary regular file")
mode = stat.S_IMODE(info.st_mode)
except FileNotFoundError:
info = os.fstat(directory)
mode = 0o600
fd = os.open(temporary, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW,
0o600, dir_fd=directory)
created = True
with os.fdopen(fd, "wb") as output:
remaining = expected_length
while remaining:
chunk = source.read(min(65536, remaining))
if not chunk:
raise ValueError("incomplete input")
output.write(chunk)
remaining -= len(chunk)
if source.read(1):
raise ValueError("excess input")
output.flush()
os.fchown(output.fileno(), info.st_uid, info.st_gid)
os.fchmod(output.fileno(), mode)
os.fsync(output.fileno())
os.replace(temporary, name, src_dir_fd=directory, dst_dir_fd=directory)
created = False
os.fsync(directory)
finally:
if created:
os.unlink(temporary, dir_fd=directory)
os.close(directory)
if __name__ == "__main__":
try:
if len(sys.argv) != 3:
raise ValueError("invalid arguments")
write_config(sys.argv[1], int(sys.argv[2]), sys.stdin.buffer)
except Exception:
# No input contents or parser snippets in privileged process logs.
print("LND configuration write failed", file=sys.stderr)
sys.exit(1)