View | Details | Raw Unified | Return to bug 46323
Collapse All | Expand All

(-)a/base/univention-lib/python/admember.py (-36 / +46 lines)
 Lines 31-39    Link Here 
31
# <http://www.gnu.org/licenses/>.
31
# <http://www.gnu.org/licenses/>.
32
32
33
from __future__ import print_function
33
from __future__ import print_function
34
import ldb
34
35
import ldap
36
import ldap.sasl
37
import os
35
import os
38
import subprocess
36
import subprocess
39
import locale
37
import locale
 Lines 42-51   import tempfile Link Here 
42
import ipaddr
40
import ipaddr
43
import time
41
import time
44
from datetime import datetime, timedelta
42
from datetime import datetime, timedelta
43
import pipes
44
45
import ldb
46
import ldap
47
import ldap.sasl
48
from ldap.filter import filter_format
45
from samba.dcerpc import nbt, security
49
from samba.dcerpc import nbt, security
46
from samba.ndr import ndr_unpack
50
from samba.ndr import ndr_unpack
47
from samba.net import Net
51
from samba.net import Net
48
from samba.param import LoadParm
52
from samba.param import LoadParm
53
49
import univention.config_registry
54
import univention.config_registry
50
import univention.uldap
55
import univention.uldap
51
import univention.lib.package_manager
56
import univention.lib.package_manager
 Lines 71-76   finally: Link Here 
71
	if orig_path:
76
	if orig_path:
72
		sys.path = orig_path
77
		sys.path = orig_path
73
78
79
74
# Ensure univention debug is initialized
80
# Ensure univention debug is initialized
75
def initialize_debug():
81
def initialize_debug():
76
	# Use a little hack to determine if univention.debug has been initialized
82
	# Use a little hack to determine if univention.debug has been initialized
 Lines 88-93   def initialize_debug(): Link Here 
88
	else:
94
	else:
89
		ud.set_level(ud.MODULE, oldLevel)
95
		ud.set_level(ud.MODULE, oldLevel)
90
96
97
91
class failedToSetService(Exception):
98
class failedToSetService(Exception):
92
99
93
	'''ucs_addServiceToLocalhost failed'''
100
	'''ucs_addServiceToLocalhost failed'''
 Lines 337-343   def check_ad_account(ad_domain_info, username, password, ucr=None): Link Here 
337
344
338
	domain_sid = ndr_unpack(security.dom_sid, res[0][1]["objectSid"][0])
345
	domain_sid = ndr_unpack(security.dom_sid, res[0][1]["objectSid"][0])
339
346
340
	res = lo_ad.search(filter="(sAMAccountName=%s)" % username, attr=["objectSid", "primaryGroupID"])
347
	res = lo_ad.search(filter=filter_format("(sAMAccountName=%s)", [username]), attr=["objectSid", "primaryGroupID"])
341
	if not res or "objectSid" not in res[0][1]:
348
	if not res or "objectSid" not in res[0][1]:
342
		msg = "Determination user SID failed"
349
		msg = "Determination user SID failed"
343
		ud.debug(ud.MODULE, ud.ERROR, msg)
350
		ud.debug(ud.MODULE, ud.ERROR, msg)
 Lines 354-360   def check_ad_account(ad_domain_info, username, password, ucr=None): Link Here 
354
361
355
	user_dn = res[0][0]
362
	user_dn = res[0][0]
356
363
357
	res = lo_ad.search(filter="(sAMAccountName=%s)" % username, base=user_dn, scope="base", attr=["tokenGroups"])
364
	res = lo_ad.search(filter=filter_format("(sAMAccountName=%s)", [username]), base=user_dn, scope="base", attr=["tokenGroups"])
358
	if not res or "tokenGroups" not in res[0][1]:
365
	if not res or "tokenGroups" not in res[0][1]:
359
		msg = "Lookup of AD group memberships for user failed"
366
		msg = "Lookup of AD group memberships for user failed"
360
		ud.debug(ud.MODULE, ud.ERROR, msg)
367
		ud.debug(ud.MODULE, ud.ERROR, msg)
 Lines 380-386   def _sid_of_ucs_sambadomain(lo=None, ucr=None): Link Here 
380
		ucr = univention.config_registry.ConfigRegistry()
387
		ucr = univention.config_registry.ConfigRegistry()
381
		ucr.load()
388
		ucr.load()
382
389
383
	res = lo.search(filter="(&(objectclass=sambadomain)(sambaDomainName=%s))" % ucr.get("windows/domain"), attr=["sambaSID"], unique=True)
390
	res = lo.search(filter=filter_format("(&(objectclass=sambadomain)(sambaDomainName=%s))", [ucr.get("windows/domain")]), attr=["sambaSID"], unique=True)
384
	if not res:
391
	if not res:
385
		ud.debug(ud.MODULE, ud.ERROR, "No UCS LDAP search result for sambaDomainName=%s" % ucr.get("windows/domain"))
392
		ud.debug(ud.MODULE, ud.ERROR, "No UCS LDAP search result for sambaDomainName=%s" % ucr.get("windows/domain"))
386
		raise ldap.NO_SUCH_OBJECT({'desc': 'no object'})
393
		raise ldap.NO_SUCH_OBJECT({'desc': 'no object'})
 Lines 403-409   def _dn_of_udm_domain_admins(lo=None, ucr=None): Link Here 
403
410
404
	ucs_domain_sid = _sid_of_ucs_sambadomain(lo, ucr)
411
	ucs_domain_sid = _sid_of_ucs_sambadomain(lo, ucr)
405
	domain_admins_sid = "%s-%s" % (ucs_domain_sid, security.DOMAIN_RID_ADMINS)
412
	domain_admins_sid = "%s-%s" % (ucs_domain_sid, security.DOMAIN_RID_ADMINS)
406
	res = lo.searchDn(filter="(sambaSID=%s)" % domain_admins_sid, unique=True)
413
	res = lo.searchDn(filter=filter_format("(sambaSID=%s)", [domain_admins_sid]), unique=True)
407
	if not res:
414
	if not res:
408
		ud.debug(ud.MODULE, ud.ERROR, "Failed to determine DN of UCS Domain Admins group")
415
		ud.debug(ud.MODULE, ud.ERROR, "Failed to determine DN of UCS Domain Admins group")
409
		raise ldap.NO_SUCH_OBJECT({'desc': 'no object'})
416
		raise ldap.NO_SUCH_OBJECT({'desc': 'no object'})
 Lines 490-496   def prepare_administrator(username, password, ucr=None): Link Here 
490
497
491
	# First check if account exists in LDAP, otherwise create it:
498
	# First check if account exists in LDAP, otherwise create it:
492
	lo = univention.uldap.getMachineConnection()
499
	lo = univention.uldap.getMachineConnection()
493
	res = lo.search(filter="(&(uid=%s)(objectClass=shadowAccount))" % (username,), attr=["userPassword", "sambaSID"])
500
	res = lo.search(filter=filter_format("(&(uid=%s)(objectClass=shadowAccount))", (username,)), attr=["userPassword", "sambaSID"])
494
	if not res:
501
	if not res:
495
		ud.debug(ud.MODULE, ud.INFO, "No UCS LDAP search result for uid=%s" % username)
502
		ud.debug(ud.MODULE, ud.INFO, "No UCS LDAP search result for uid=%s" % username)
496
		try:
503
		try:
 Lines 536-561   def prepare_administrator(username, password, ucr=None): Link Here 
536
543
537
544
538
def _mapped_ad_dn(ad_dn, ad_ldap_base, ucr=None):
545
def _mapped_ad_dn(ad_dn, ad_ldap_base, ucr=None):
539
	if ad_dn[-len(ad_ldap_base):] != ad_ldap_base:
546
	"""
540
		ud.debug(ud.MODULE, ud.ERROR, "Mapping of AD DN %s failed, base is not %s" % (ad_dn, ad_ldap_base))
547
	>>> _mapped_ad_dn('uid=Administrator + CN=admin,OU=users,CN=univention,Foo=univention,bar=base', 'foo=univention,bar = base', {'ldap/base': 'dc=base'})
548
	'uid=Administrator+cn=admin,ou=users,cn=univention,dc=base'
549
	"""
550
	parent = ad_dn
551
	while parent:
552
		if univention.uldap.access.compare_dn(parent, ad_ldap_base):
553
			break
554
		parent = univention.uldap.parentDn(parent)
555
	else:
556
		ud.debug(ud.MODULE, ud.ERROR, "Mapping of AD DN %r failed, base is not %r" % (ad_dn, ad_ldap_base))
541
		return
557
		return
542
558
543
	if not ucr:
559
	if not ucr:
544
		ucr = univention.config_registry.ConfigRegistry()
560
		ucr = univention.config_registry.ConfigRegistry()
545
		ucr.load()
561
		ucr.load()
546
562
547
	relative_dn = ad_dn[:-len(ad_ldap_base) - 1]
563
	base = ldap.dn.str2dn(ad_ldap_base)
548
	mapped_relative_dn_components = []
564
	dn = [[(attr[0].lower() if attr[0] in ('CN', 'OU') else attr[0], attr[1], attr[2]) for attr in x] for x in ldap.dn.str2dn(ad_dn)[:-len(base)]]
549
	relative_dn_components = relative_dn.split(',')
565
	return ldap.dn.dn2str(dn + ldap.dn.str2dn(ucr.get("ldap/base")))
550
	for rdn in relative_dn_components:
551
		attr, val = rdn.split('=')
552
		if attr in ('CN', 'OU'):
553
			attr = attr.lower()
554
		mapped_rdn = '='.join((attr, val))
555
		mapped_relative_dn_components.append(mapped_rdn)
556
	mapped_relative_dn = ','.join(mapped_relative_dn_components)
557
	mapped_dn = ",".join((mapped_relative_dn, ucr.get("ldap/base")))
558
	return mapped_dn
559
566
560
567
561
def synchronize_account_position(ad_domain_info, username, password, ucr=None):
568
def synchronize_account_position(ad_domain_info, username, password, ucr=None):
 Lines 590-596   def synchronize_account_position(ad_domain_info, username, password, ucr=None): Link Here 
590
	except (ldap.INVALID_CREDENTIALS, ldap.UNWILLING_TO_PERFORM):
597
	except (ldap.INVALID_CREDENTIALS, ldap.UNWILLING_TO_PERFORM):
591
		return False  # Massive failure, but no issue to be raised here.
598
		return False  # Massive failure, but no issue to be raised here.
592
599
593
	res = lo_ad.searchDn(filter="(sAMAccountName=%s)" % username)
600
	res = lo_ad.searchDn(filter=filter_format("(sAMAccountName=%s)", [username]))
594
	if not res:
601
	if not res:
595
		ud.debug(ud.MODULE, ud.ERROR, "Lookup of AD DN for user %s failed" % username)
602
		ud.debug(ud.MODULE, ud.ERROR, "Lookup of AD DN for user %s failed" % username)
596
		return False  # Massive failure, but no issue to be raised here.
603
		return False  # Massive failure, but no issue to be raised here.
 Lines 598-604   def synchronize_account_position(ad_domain_info, username, password, ucr=None): Link Here 
598
605
599
	# Second determine position in UCS LDAP:
606
	# Second determine position in UCS LDAP:
600
	lo = univention.uldap.getMachineConnection()
607
	lo = univention.uldap.getMachineConnection()
601
	res = lo.searchDn(filter="(&(uid=%s)(objectClass=shadowAccount))" % (username,), unique=True)
608
	res = lo.searchDn(filter=filter_format("(&(uid=%s)(objectClass=shadowAccount))", (username,)), unique=True)
602
	if not res:
609
	if not res:
603
		ud.debug(ud.MODULE, ud.ERROR, "No UCS LDAP search result for uid=%s" % username)
610
		ud.debug(ud.MODULE, ud.ERROR, "No UCS LDAP search result for uid=%s" % username)
604
		return False  # Massive failure, but no issue to be raised here.
611
		return False  # Massive failure, but no issue to be raised here.
 Lines 608-614   def synchronize_account_position(ad_domain_info, username, password, ucr=None): Link Here 
608
		return True
615
		return True
609
616
610
	mapped_ad_user_dn = _mapped_ad_dn(ad_user_dn, ad_ldap_base, ucr)
617
	mapped_ad_user_dn = _mapped_ad_dn(ad_user_dn, ad_ldap_base, ucr)
611
	target_position = mapped_ad_user_dn.split(',', 1)[1]
618
	target_position = lo.parentDn(mapped_ad_user_dn)
612
619
613
	cmd = ("univention-directory-manager", "users/user", "move", "--dn", ucs_user_dn, "--position", target_position)
620
	cmd = ("univention-directory-manager", "users/user", "move", "--dn", ucs_user_dn, "--position", target_position)
614
	p1 = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True)
621
	p1 = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True)
 Lines 664-677   def disable_ssl(): Link Here 
664
671
665
def _add_service_to_localhost(service):
672
def _add_service_to_localhost(service):
666
	ud.debug(ud.MODULE, ud.PROCESS, "Adding service %s to localhost" % service)
673
	ud.debug(ud.MODULE, ud.PROCESS, "Adding service %s to localhost" % service)
667
	res = subprocess.call('. /usr/share/univention-lib/ldap.sh; ucs_addServiceToLocalhost "%s"' % service, shell=True)
674
	res = subprocess.call('. /usr/share/univention-lib/ldap.sh; ucs_addServiceToLocalhost %s' % (pipes.quote(service),), shell=True)
668
	if res != 0:
675
	if res != 0:
669
		raise failedToSetService
676
		raise failedToSetService
670
677
671
678
672
def _remove_service_from_localhost(service):
679
def _remove_service_from_localhost(service):
673
	ud.debug(ud.MODULE, ud.PROCESS, "Remove service %s from localhost" % service)
680
	ud.debug(ud.MODULE, ud.PROCESS, "Remove service %s from localhost" % service)
674
	res = subprocess.call('. /usr/share/univention-lib/ldap.sh; ucs_removeServiceFromLocalhost "%s"' % service, shell=True)
681
	res = subprocess.call('. /usr/share/univention-lib/ldap.sh; ucs_removeServiceFromLocalhost %s' % (pipes.quote(service),), shell=True)
675
	if res != 0:
682
	if res != 0:
676
		raise failedToSetService
683
		raise failedToSetService
677
684
 Lines 977-983   def rename_well_known_sid_objects(username, password, ucr=None): Link Here 
977
	ucs_domain_sid = _sid_of_ucs_sambadomain(lo, ucr)
984
	ucs_domain_sid = _sid_of_ucs_sambadomain(lo, ucr)
978
985
979
	domain_admins_sid = "%s-%s" % (ucs_domain_sid, security.DOMAIN_RID_ADMINS)
986
	domain_admins_sid = "%s-%s" % (ucs_domain_sid, security.DOMAIN_RID_ADMINS)
980
	res = lo.search(filter="(&(sambaSID=%s)(objectClass=sambaGroupMapping))" % domain_admins_sid, attr=["cn"], unique=True)
987
	res = lo.search(filter=filter_format("(&(sambaSID=%s)(objectClass=sambaGroupMapping))", [domain_admins_sid]), attr=["cn"], unique=True)
981
	if not res or "cn" not in res[0][1]:
988
	if not res or "cn" not in res[0][1]:
982
		ud.debug(ud.MODULE, ud.ERROR, "Lookup of group name for Domain Admins sid failed")
989
		ud.debug(ud.MODULE, ud.ERROR, "Lookup of group name for Domain Admins sid failed")
983
		domain_admins_name = "Domain Admins"  # sensible guess
990
		domain_admins_name = "Domain Admins"  # sensible guess
 Lines 1001-1007   def rename_well_known_sid_objects(username, password, ucr=None): Link Here 
1001
		raise connectionFailed(msg)
1008
		raise connectionFailed(msg)
1002
1009
1003
	# Finally wait for replication and slapd restart to ensure that new LDAP ACLs are active:
1010
	# Finally wait for replication and slapd restart to ensure that new LDAP ACLs are active:
1004
	res = lo.search(filter="(&(sambaSID=%s)(objectClass=sambaGroupMapping))" % domain_admins_sid, attr=["cn"], unique=True)
1011
	res = lo.search(filter=filter_format("(&(sambaSID=%s)(objectClass=sambaGroupMapping))", [domain_admins_sid]), attr=["cn"], unique=True)
1005
	if not res or "cn" not in res[0][1]:
1012
	if not res or "cn" not in res[0][1]:
1006
		ud.debug(ud.MODULE, ud.ERROR, "Lookup of new group name for Domain Admins sid failed")
1013
		ud.debug(ud.MODULE, ud.ERROR, "Lookup of new group name for Domain Admins sid failed")
1007
		new_domain_admins_name = "Domain Admins"
1014
		new_domain_admins_name = "Domain Admins"
 Lines 1075-1081   def prepare_dns_reverse_settings(ad_domain_info, ucr=None): Link Here 
1075
	except (socket.herror, socket.gaierror) as exc:
1082
	except (socket.herror, socket.gaierror) as exc:
1076
		ud.debug(ud.MODULE, ud.INFO, "Resolving %s failed: %s" % (ad_domain_info['DC IP'], exc.args[1]))
1083
		ud.debug(ud.MODULE, ud.INFO, "Resolving %s failed: %s" % (ad_domain_info['DC IP'], exc.args[1]))
1077
1084
1078
	## Set a hosts/static anyway, to be safe from DNS issues (Bug #38285)
1085
	# Set a hosts/static anyway, to be safe from DNS issues (Bug #38285)
1079
	previous_ucr_set = []
1086
	previous_ucr_set = []
1080
	previous_ucr_unset = []
1087
	previous_ucr_unset = []
1081
1088
 Lines 1097-1102   def prepare_dns_reverse_settings(ad_domain_info, ucr=None): Link Here 
1097
1104
1098
	return (previous_ucr_set, previous_ucr_unset)
1105
	return (previous_ucr_set, previous_ucr_unset)
1099
1106
1107
1100
def prepare_kerberos_ucr_settings(realm=None, ucr=None):
1108
def prepare_kerberos_ucr_settings(realm=None, ucr=None):
1101
	ud.debug(ud.MODULE, ud.PROCESS, "Prepare Kerberos UCR settings")
1109
	ud.debug(ud.MODULE, ud.PROCESS, "Prepare Kerberos UCR settings")
1102
1110
 Lines 1252-1258   def run_samba_join_script(username, password, ucr=None): Link Here 
1252
	ud.debug(ud.MODULE, ud.PROCESS, "Running samba join script")
1260
	ud.debug(ud.MODULE, ud.PROCESS, "Running samba join script")
1253
1261
1254
	lo = univention.uldap.getMachineConnection()
1262
	lo = univention.uldap.getMachineConnection()
1255
	res = lo.searchDn(filter="(&(uid=%s)(objectClass=shadowAccount))" % (username,), unique=True)
1263
	res = lo.searchDn(filter=filter_format("(&(uid=%s)(objectClass=shadowAccount))", (username,)), unique=True)
1256
	if not res:
1264
	if not res:
1257
		ud.debug(ud.MODULE, ud.ERROR, "No UCS LDAP search result for uid=%s" % username)
1265
		ud.debug(ud.MODULE, ud.ERROR, "No UCS LDAP search result for uid=%s" % username)
1258
		raise sambaJoinScriptFailed()
1266
		raise sambaJoinScriptFailed()
 Lines 1283-1291   def add_host_record_in_ad(uid=None, binddn=None, bindpw=None, bindpwdfile=None, Link Here 
1283
	domainname = ucr.get('domainname')
1291
	domainname = ucr.get('domainname')
1284
1292
1285
	if binddn:
1293
	if binddn:
1286
		for i in binddn.split(','):
1294
		uids = [y[1] for x in ldap.dn.str2dn(binddn) for y in x if ('uid' in y)]
1287
			if i.lower().startswith('uid='):
1295
		if uids:
1288
				uid = i.split('=', 1)[1]
1296
			uid = uids[0]
1289
	if bindpwdfile:
1297
	if bindpwdfile:
1290
		create_pwdfile = False
1298
		create_pwdfile = False
1291
		pwdfile = bindpwdfile
1299
		pwdfile = bindpwdfile
 Lines 1328-1334   def add_host_record_in_ad(uid=None, binddn=None, bindpw=None, bindpwdfile=None, Link Here 
1328
		print('%s A record for %s found' % (fqdn, ip))
1336
		print('%s A record for %s found' % (fqdn, ip))
1329
		return True
1337
		return True
1330
1338
1331
	# create host record
1339
	# create host record  # FIXME; missing quoting
1332
	fd = tempfile.NamedTemporaryFile(delete=False)
1340
	fd = tempfile.NamedTemporaryFile(delete=False)
1333
	fd.write('server %s\n' % ad_ip)
1341
	fd.write('server %s\n' % ad_ip)
1334
	fd.write('update add %s 86400 A %s\n' % (fqdn, ip))
1342
	fd.write('update add %s 86400 A %s\n' % (fqdn, ip))
 Lines 1410-1415   def add_domaincontroller_srv_record_in_ad(ad_ip, username, password, ucr=None): Link Here 
1410
		with tempfile.NamedTemporaryFile() as fd, tempfile.NamedTemporaryFile() as fd2:
1418
		with tempfile.NamedTemporaryFile() as fd, tempfile.NamedTemporaryFile() as fd2:
1411
			fd2.write(password)
1419
			fd2.write(password)
1412
			fd2.flush()
1420
			fd2.flush()
1421
			# FIXME: missing quoting
1413
			fd.write('server %s\n' % ad_ip)
1422
			fd.write('server %s\n' % ad_ip)
1414
			fd.write('update delete %s. SRV\n' % (srv_record,))
1423
			fd.write('update delete %s. SRV\n' % (srv_record,))
1415
			fd.write('send\n')
1424
			fd.write('send\n')
 Lines 1424-1429   def add_domaincontroller_srv_record_in_ad(ad_ip, username, password, ucr=None): Link Here 
1424
				ud.debug(ud.MODULE, ud.ERROR, "failed to remove SRV record. Ignoring error.")
1433
				ud.debug(ud.MODULE, ud.ERROR, "failed to remove SRV record. Ignoring error.")
1425
			subprocess.call(['kdestroy'])
1434
			subprocess.call(['kdestroy'])
1426
1435
1436
	# FIXME: missing quoting
1427
	fd = tempfile.NamedTemporaryFile(delete=False)
1437
	fd = tempfile.NamedTemporaryFile(delete=False)
1428
	fd.write('server %s\n' % ad_ip)
1438
	fd.write('server %s\n' % ad_ip)
1429
	fd.write('update add %s. 10800 SRV 0 0 0 %s\n' %
1439
	fd.write('update add %s. 10800 SRV 0 0 0 %s\n' %
 Lines 1454-1460   def add_domaincontroller_srv_record_in_ad(ad_ip, username, password, ucr=None): Link Here 
1454
def get_ucr_variable_from_ucs(host, server, var):
1464
def get_ucr_variable_from_ucs(host, server, var):
1455
	cmd = ['univention-ssh', '/etc/machine.secret']
1465
	cmd = ['univention-ssh', '/etc/machine.secret']
1456
	cmd += ['%s\$@%s' % (host, server)]
1466
	cmd += ['%s\$@%s' % (host, server)]
1457
	cmd += ['/usr/sbin/ucr get %s' % var]
1467
	cmd += ['/usr/sbin/ucr get %s' % (pipes.quote(var),)]
1458
	p1 = subprocess.Popen(cmd, close_fds=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
1468
	p1 = subprocess.Popen(cmd, close_fds=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
1459
	stdout, stderr = p1.communicate()
1469
	stdout, stderr = p1.communicate()
1460
	if p1.returncode:
1470
	if p1.returncode:

Return to bug 46323