#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# Univention Directory Manager
#
# Like what you see? Join us!
# https://www.univention.com/about-us/careers/vacancies/
#
# Copyright 2014-2024 Univention GmbH
#
# https://www.univention.de/
#
# All rights reserved.
#
# The source code of this program is made available
# under the terms of the GNU Affero General Public License version 3
# (GNU AGPL V3) as published by the Free Software Foundation.
#
# Binary versions of this program provided by Univention to you as
# well as other copyrighted, protected or trademarked materials like
# Logos, graphics, fonts, specific documentations and configurations,
# cryptographic keys etc. are subject to a license agreement between
# you and Univention and not subject to the GNU AGPL V3.
#
# In the case you use this program under the terms of the GNU AGPL V3,
# the program is provided in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License with the Debian GNU/Linux or Univention distribution in file
# /usr/share/common-licenses/AGPL-3; if not, see
# <https://www.gnu.org/licenses/>.

"""
This script searches for user accounts with expired account that have not
been locked yet. For all found user accounts the posix login will be
disabled.
"""

from __future__ import print_function

import argparse
import sys
import time
from logging import DEBUG, getLogger

from ldap.filter import filter_format

import univention.admin.modules as udm_modules
import univention.admin.uldap
import univention.config_registry
import univention.logging
import univention.uldap


log = getLogger('MAIN')


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("-n", "--dry-run", dest="dry_run", default=False, action="store_true", help="perform only a dry run (disables --quiet)")
    parser.add_argument("-w", "--only-last-week", dest="last_week", default=False, action="store_true", help="check only user accounts that expired within the last 7 days")
    parser.add_argument("-q", "--quiet", dest="verbose", default=True, action="store_false", help="write process messages to logfile only")
    options = parser.parse_args()

    if options.dry_run:
        options.verbose = True

    def print_msg(msg, newline=True):
        if options.verbose:
            if newline:
                print(msg)
            else:
                print(msg, end=' ')

    ucr = univention.config_registry.ConfigRegistry()
    ucr.load()

    if ucr.get('server/role') != 'domaincontroller_master':
        print_msg('ERROR: this script may only be called on a Primary Directory Node')
        sys.exit(1)

    print_msg('Initializing... (%s)' % (time.ctime()))
    univention.logging.basicConfig(filename='/var/log/univention/lock_expired_accounts.log', level=DEBUG)
    if options.last_week:
        print_msg('Checking only accounts that expired in the last 7 days')

    udm_modules.update()
    lo, position = univention.admin.uldap.getAdminConnection()
    udm_modules.init(lo, position, udm_modules.get('users/user'))

    print_msg('Searching for expired user accounts...')

    today = int(time.time() / 24 / 3600)  # time.time() returns the local time
    ldap_filter = filter_format('(shadowExpire<=%s)', (str(today),))
    if options.last_week:
        ldap_filter = filter_format('(&(shadowExpire>=%s)(shadowExpire<=%s))', (str(today - 6), str(today)))
    results = udm_modules.lookup('users/user', None, lo, scope='sub', filter=ldap_filter)

    for entry in results:
        entry.open()
        entry.descriptions['locked'].editable = True
        entry.descriptions['locked'].may_change = True
        if entry['locked'] == '0':
            entry['locked'] = '1'
        else:
            # account is already locked
            continue

        if options.dry_run:
            print_msg('uid=%s expired at %s ... skipped due to dry run (expected modification: locked=%r)' % (entry['username'], entry['userexpiry'], entry['locked']))
        else:
            print_msg('uid=%s expired at %s ...' % (entry['username'], entry['userexpiry']), newline=False)
            entry.modify()
            log.debug('uid=%s expired at %s ... modified (locked=%r)', entry['username'], entry['userexpiry'], entry['locked'])
            print_msg('modified (locked=%r)' % (entry['locked'],))


if __name__ == '__main__':
    main()
