#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# Univention Directory Manager
#
# Copyright 2014-2022 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 sys
import time
import argparse
from ldap.filter import filter_format

import univention.uldap
import univention.admin.uldap
import univention.admin.modules as udm_modules
import univention.config_registry
import univention.debug as ud


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()))
	ud.init('/var/log/univention/lock_expired_accounts.log', ud.FLUSH, ud.NO_FUNCTION)
	ud.set_level(ud.MAIN, ud.ALL)
	ud.set_level(ud.LDAP, ud.ALL)
	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()
			ud.debug(ud.MAIN, ud.PROCESS, '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()
