#!/usr/bin/python2.6
#
# Univention helper script
# to remove computer with DC objects from Samba 4 and UDM
#
# Copyright 2012-2013 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
# .
from optparse import OptionParser, OptionValueError
import sys, os
from univention import config_registry
import samba
from samba.samdb import SamDB
from samba.auth import system_session
from samba.param import LoadParm
import univention.admin.uldap
import univention.admin.uexceptions as uexceptions
import univention.admin.modules
univention.admin.modules.update()
import univention.admin.objects
import univention.admin.config
import traceback
SAMBA_DIR = '/var/lib/samba'
SAMBA_PRIVATE_DIR = os.path.join(SAMBA_DIR, 'private')
def purge_computer_with_DC_objects(ucr, computername, binddn, bindpw):
lp = LoadParm()
lp.load('/etc/samba/smb.conf')
samdb = SamDB(os.path.join(SAMBA_PRIVATE_DIR, "sam.ldb"), session_info=system_session(lp), lp=lp)
backlink_attribute_list = ["serverReferenceBL", "frsComputerReferenceBL", "msDFSR-ComputerReferenceBL"]
msgs = samdb.search(base=ucr["samba4/ldap/base"], scope=samba.ldb.SCOPE_SUBTREE,
expression="(&(objectClass=computer)(sAMAccountName=%s$))" % computername,
attrs=backlink_attribute_list)
if not msgs:
print "Samba 4 computer account '%s' not found." % (computername,)
sys.exit(1)
answer = raw_input("Really remove %s from Samba 4 and UDM? [y/N]: " % computername)
if not answer.lower() in ('y', 'yes'):
print "Ok, stopping as requested.\n"
sys.exit(2)
answer = raw_input("If you are really sure type YES and hit enter: ")
if not answer == 'YES':
print "The answer was not 'YES', confirmation failed.\n"
sys.exit(1)
else:
print "Ok, continuing as requested.\n"
## remove objects from Samba 4 SAM database
obj = msgs[0]
for backlink_attribute in backlink_attribute_list:
if backlink_attribute in obj:
backlink_object = obj[backlink_attribute][0]
try:
print "Removing %s from SAM database." % (backlink_object,)
samdb.delete(backlink_object, ["tree_delete:0"])
except:
print >>sys.stderr, "Removal of Samba 4 %s objects %s from Samba 4 SAM database failed." % (backlink_attribute, backlink_object,)
print traceback.format_exc()
## Now delete the Samba 4 computer account and sub-objects
## Cannot use tree_delete on isCriticalSystemObject, perform recursive delete like ldbdel code does it:
msgs = samdb.search(base=obj.dn, scope=samba.ldb.SCOPE_SUBTREE,
attrs=["dn"])
obj_dn_list = [obj.dn for obj in msgs]
obj_dn_list.sort(key=len)
obj_dn_list.reverse()
for obj_dn in obj_dn_list:
try:
print "Removing %s from SAM database." % (obj_dn,)
samdb.delete(obj_dn)
except:
print >>sys.stderr, "Removal of Samba 4 computer account object %s from Samba 4 SAM database failed." % (obj_dn,)
print >>sys.stderr, traceback.format_exc()
## Finally, for consistency remove S4 computer object from UDM
try:
lo = univention.admin.uldap.access(host=ucr["ldap/master"], base=ucr["ldap/base"], binddn=binddn, bindpw=bindpw, start_tls=2)
except Exception, e:
print 'authentication error: %s' % str(e)
sys.exit(1)
computer_filter = "(&(objectClass=univentionHost)(uid=%s$))" % computername
result = lo.search(filter=computer_filter, base=ucr["ldap/base"], scope='sub', attr=['univentionObjectType'], unique=1)
if result and len(result)>0 and result[0] and len(result[0])>0 and result[0][0]:
univentionObjectType = result[0][1]['univentionObjectType'][0]
module = univention.admin.modules.get(univentionObjectType)
position = univention.admin.uldap.position(ucr["ldap/base"])
univention.admin.modules.init(lo, position, module)
co = univention.admin.config.config()
filter = univention.admin.filter.expression('name', computername)
objs = module.lookup(co, lo, filter, scope='domain', base=position.getDomain(), unique=1)
if objs:
print "Removing Samba 4 computer account '%s' from Univention Directory Manager" % computername
obj = objs[0]
try:
obj.remove()
except univention.admin.uexceptions.ldapError, e:
print >>sys.stderr, "Removal of UDM computer account %s via UDM failed (univentionObjectType: %s)." % (computername, univentionObjectType,)
sys.exit(1)
if univention.admin.objects.wantsCleanup(obj):
univention.admin.objects.performCleanup(obj)
if __name__ == '__main__':
parser = OptionParser("%prog [options] ")
# parser.add_option("-v", "--verbose", action="store_true")
parser.add_option("--computername", dest="computername", help="Hostname of the Samba computer account to delete")
parser.add_option("-U", "--bind_account", dest="bind_account")
parser.add_option("-P", "--bind_password", dest="bind_password")
opts, args = parser.parse_args()
if not opts.computername:
parser.print_help()
sys.exit(1)
ucr = config_registry.ConfigRegistry()
ucr.load()
if (opts.bind_account and opts.bind_password):
machine_secret = ''
if os.path.exists('/etc/machine.secret'):
with file('/etc/machine.secret') as f:
machine_secret = f.read().rstrip('\n')
else:
print "/etc/machine.secret missing, maybe the system is not joined yet?"
sys.exit(1)
try:
lo = univention.admin.uldap.access(host=ucr["ldap/server/name"], base=ucr["ldap/base"], binddn=ucr["ldap/hostdn"], bindpw=machine_secret, start_tls=0)
except Exception, e:
print 'authentication error: %s' % str(e)
sys.exit(1)
user_searchfilter = "(&(|(&(objectClass=posixAccount)(objectClass=shadowAccount))(objectClass=sambaSamAccount))(uid=%s))" % opts.bind_account
result = lo.searchDn(filter=user_searchfilter, base=ucr["ldap/base"], scope='sub', unique=1)
if result:
binddn = result[0]
else:
print "Cannot determine DN for bind account %s" % opts.bind_account
sys.exit(1)
bindpw = opts.bind_password
elif os.path.exists('/etc/ldap.secret'):
binddn = "cn=admin,%s" % ucr["ldap/base"]
with file('/etc/ldap.secret') as f:
bindpw = f.read().rstrip('\n')
else:
print "On this system the options --bind_account and --bind_password are required."
parser.print_help()
sys.exit(1)
purge_computer_with_DC_objects(ucr, opts.computername, binddn, bindpw)