#!/usr/bin/python2.7
#
# Copyright 2004-2017 Univention GmbH
#
# http://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
# <http://www.gnu.org/licenses/>.

import getopt
import sys
import os
import socket
import copy
import univention.uldap as uuldap
import univention.config_registry

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


class UniventionNagiosLDAP(object):

	def __init__(self, binddn='', bindpwd='', start_tls=2):
		try:
			if binddn:
				self.lo = univention.uldap.access(host=confreg['ldap/master'], port=confreg['ldap/master/port'], base=confreg['ldap/base'], binddn=binddn, bindpw=bindpwd, start_tls=start_tls, decode_ignorelist=[])
			else:
				self.lo = uuldap.getAdminConnection()
		except Exception as e:
			print 'E: cannot connect to ldap server: %s' % str(e)
			sys.exit(1)
		self.dnscache = {}
		self.failedFQDN = {}

	def checkFQDN(self, fqdn):
		try:
			socket.gethostbyname(fqdn)
		except:
			return False
		return True

	def check(self):
		print 'Searching LDAP objects... please wait... ',
		servicednlist = self.lo.searchDn(filter='(objectClass=univentionNagiosServiceClass)')
		print 'done'
		print 'Processing LDAP objects... please wait... ',
		for servicedn in servicednlist:
			fqdnlist = self.lo.getAttr(servicedn, 'univentionNagiosHostname')
			for fqdn in fqdnlist:
				if not self.checkFQDN(fqdn):
					if fqdn not in self.failedFQDN:
						self.failedFQDN[fqdn] = []
					if servicedn not in self.failedFQDN[fqdn]:
						self.failedFQDN[fqdn].append(servicedn)
		print 'done'
		print ''

		if len(self.failedFQDN):
			for key in self.failedFQDN.keys():
				print 'Failed to resolve fqdn %s' % key
				for dn in self.failedFQDN[key]:
					print '   attached to %s' % dn
		else:
			print 'Everything ok.'

	def autofix(self):
		if len(self.failedFQDN):
			print ''
			for key in self.failedFQDN.keys():
				for dn in self.failedFQDN[key]:
					print 'Fixing %s' % dn
					self.removeFQDN(key, dnlist=[dn])

	def removeFQDN(self, fqdn, dnlist=None):
		if not dnlist:
			dnlist = self.lo.searchDn(filter='(&(objectClass=univentionNagiosServiceClass)(univentionNagiosHostname=%s))' % fqdn)
		for dn in dnlist:
			fqdnlist = self.lo.getAttr(dn, 'univentionNagiosHostname')
			oldlist = copy.deepcopy(fqdnlist)
			newlist = [item for item in oldlist if item != fqdn]
			self.lo.modify(dn, [('univentionNagiosHostname', oldlist, newlist)])

	def replaceFQDN(self, oldfqdn, newfqdn, dnlist=None):
		if not dnlist:
			dnlist = self.lo.searchDn(filter='(&(objectClass=univentionNagiosServiceClass)(univentionNagiosHostname=%s))' % oldfqdn)
		for dn in dnlist:
			fqdnlist = self.lo.getAttr(dn, 'univentionNagiosHostname')
			oldlist = copy.deepcopy(fqdnlist)
			newlist = [item for item in oldlist if item != oldfqdn]
			newlist.append(newfqdn)
			print 'Changing %s' % dn
			self.lo.modify(dn, [('univentionNagiosHostname', oldlist, newlist)])


def usage():
	print 'univention-nagios-ldap-tool [-c] [-m -o <oldfqdn> [-n <newfqdn>]]'
	print '  -a             autofix if problem is detected'
	print '  -c             check nagios service objects'
	print '  -m             modify nagios service objects'
	print '  -o <oldfqdn>   fqdn to be replaced or removed'
	print '  -n <newfqdn>   replacement fqdn'
	print '  -D <binddn>    bind DN'
	print '  -w <bindpwd>   bind password'


def main():
	actions = {'check': False,
				'modify': False,
				'autofix': False,
            }
	cfg = {'oldfqdn': None,
			'newfqdn': None,
			'binddn': '',
			'bindpwd': '',
        }

	try:
		(opts, pargs) = getopt.getopt(sys.argv[1:], 'acmo:n:D:w:', ['check', 'modify'])
	except:
		usage()
		sys.exit(0)

	# get command line data
	for opt in opts:
		if opt[0] == '-a':
			actions['autofix'] = True

		if opt[0] == '-c' or opt[0] == '--check':
			actions['check'] = True

		elif opt[0] == '-m' or opt[0] == '--modify':
			actions['modify'] = True

		elif opt[0] == '-o':
			cfg['oldfqdn'] = opt[1]

		elif opt[0] == '-n':
			cfg['newfqdn'] = opt[1]

		elif opt[0] == '-D':
			cfg['binddn'] = opt[1]

		elif opt[0] == '-w':
			cfg['bindpwd'] = opt[1]

	if actions['modify'] and not cfg['oldfqdn']:
		usage()
		sys.exit(1)
	else:
		if not cfg['binddn']:
			if not confreg.get('server/role', '') == 'domaincontroller_master':
				print 'E: please run univention-nagios-ldap-tool as user root on'
				print 'E: domaincontroller_master or specify binddn and bindpwd!'
				sys.exit(2)
			elif os.getuid() != 0:
				print 'E: please run univention-nagios-ldap-tool as user root or'
				print 'E: specify binddn and bindpwd!'
				sys.exit(3)

		unl = UniventionNagiosLDAP(cfg['binddn'], cfg['bindpwd'])

		if actions['check']:
			unl.check()
			if actions['autofix']:
				unl.autofix()

		if actions['modify']:
			if cfg['newfqdn']:
				unl.replaceFQDN(cfg['oldfqdn'], cfg['newfqdn'])
			else:
				unl.removeFQDN(cfg['oldfqdn'])


if __name__ == '__main__':
	main()
