#!/usr/bin/python3
#
# Univention AD connector Machine Password Rotation Script
#
# SPDX-FileCopyrightText: 2023-2025 Univention GmbH
# SPDX-License-Identifier: AGPL-3.0-only

import os
import subprocess
import sys
from datetime import datetime, timedelta

import univention.lib.admember
from univention.config_registry import ucr


def run_postchange():

    # If in ad/member mode change password in AD DC
    # This could run on any server/role
    samba_role = ucr.get('samba/role')
    if samba_role == 'memberserver' and univention.lib.admember.is_localhost_in_admember_mode(ucr=ucr):
        windows_domain = ucr.get('windows/domain', '').upper()
        if not windows_domain:
            sys.stdout.write("ERROR: windows/domain is not set!\n")
            return 1

        with open('/etc/machine.secret') as fd:
            machine_password = fd.read().strip()
        cmd = ['/usr/bin/samba-tool', 'user', 'password']
        cmd.append('--newpassword=%s' % (machine_password))
        cmd.append('-U=%s$' % ucr.get('hostname', '').upper())
        cmd.append('-P')
        process = subprocess.Popen(cmd)
        process.wait()

    return 0


def run_prechange():

    # check time difference against AD DC
    samba_role = ucr.get('samba/role')
    if samba_role == 'memberserver' and univention.lib.admember.is_localhost_in_admember_mode(ucr=ucr):
        windows_domain = ucr.get('windows/domain', '').upper()
        if not windows_domain:
            sys.stdout.write("ERROR: windows/domain is not set!\n")
            return 1

        TIME_FORMAT = "%a %b %d %H:%M:%S %Z %Y"
        tolerance = 180
        info = univention.lib.admember.lookup_adds_dc()
        if 'DC IP' not in info:
            sys.stderr.write('could not find DC IP\n')
            return 1

        env = os.environ.copy()
        env["LC_ALL"] = "C"
        p1 = subprocess.Popen(['rdate', '-p', '-n', info['DC IP']], close_fds=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)
        stdout, stderr = p1.communicate()

        if p1.returncode:
            sys.stderr.write('could not check time in AD DC (%s) - %s\n' % (info['DC IP'], stderr.decode('UTF-8', 'replace')))
            return 1

        local_datetime = datetime.today()
        remote_datetime = datetime.strptime(stdout.decode('UTF-8', 'replace').strip(), TIME_FORMAT)
        delta_t = local_datetime - remote_datetime

        if abs(delta_t) > timedelta(0, tolerance):
            sys.stderr.write('Time difference with AD server (%s) is too big. Cannot change password via samba-tool.\n' % (info['DC IP'],))
            return 1

    return 0


if __name__ == '__main__':
    if len(sys.argv) != 2:
        print("%s [prechange|nochange|postchange]" % sys.argv[0])
    else:
        if sys.argv[1] == "postchange":
            rc = run_postchange()
            sys.exit(rc)
        elif sys.argv[1] == "prechange":
            rc = run_prechange()
            sys.exit(rc)
        else:
            sys.exit(0)
