|
Lines 29-39
Link Here
|
| 29 |
# <http://www.gnu.org/licenses/>. |
29 |
# <http://www.gnu.org/licenses/>. |
| 30 |
|
30 |
|
| 31 |
from __future__ import absolute_import |
31 |
from __future__ import absolute_import |
|
|
32 |
|
| 33 |
import urllib |
| 32 |
import logging |
34 |
import logging |
| 33 |
from optparse import OptionParser |
35 |
from optparse import OptionParser |
|
|
36 |
|
| 37 |
import ldap |
| 38 |
from ldap.filter import filter_format |
| 39 |
|
| 40 |
import univention.uldap |
| 34 |
from univention.admin.uldap import getAdminConnection |
41 |
from univention.admin.uldap import getAdminConnection |
|
|
42 |
from univention.config_registry import ConfigRegistry |
| 35 |
from ucsschool.lib.models.utils import get_stream_handler, get_file_handler |
43 |
from ucsschool.lib.models.utils import get_stream_handler, get_file_handler |
| 36 |
import subprocess |
|
|
| 37 |
|
44 |
|
| 38 |
LOG_FILE = '/var/log/univention/ucsschool-fix-slave-objects.log' |
45 |
LOG_FILE = '/var/log/univention/ucsschool-fix-slave-objects.log' |
| 39 |
LOG_DEBUG_FMT = '%(asctime)s %(levelname)-5s %(funcName)s:%(lineno)d %(message)s' |
46 |
LOG_DEBUG_FMT = '%(asctime)s %(levelname)-5s %(funcName)s:%(lineno)d %(message)s' |
|
Lines 43-56
LOG_DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S'
Link Here
|
| 43 |
logger = logging.getLogger('main') |
50 |
logger = logging.getLogger('main') |
| 44 |
|
51 |
|
| 45 |
|
52 |
|
| 46 |
def fix_slave(lo, slave_dn, slave_attrs, dry_run=True): |
53 |
def get_s4_lo(): |
|
|
54 |
ucr = ConfigRegistry() |
| 55 |
ucr.load() |
| 56 |
tls_mode = 0 if ucr.get('connector/s4/ldap/ssl') == "no" else 2 |
| 57 |
|
| 58 |
protocol = ucr.get('connector/s4/ldap/protocol', 'ldap').lower() |
| 59 |
ldap_host_s4 = ucr.get('connector/s4/ldap/host') |
| 60 |
ldap_port_s4 = int(ucr.get('connector/s4/ldap/port')) |
| 61 |
ldap_base_s4 = ucr.get('connector/s4/ldap/base') |
| 62 |
ldap_binddn_s4 = ucr.get('connector/s4/ldap/binddn') |
| 63 |
ldap_bindpw_s4 = None |
| 64 |
if ucr.get('connector/s4/ldap/bindpw'): |
| 65 |
ldap_bindpw_s4 = open(ucr['connector/s4/ldap/bindpw']).read().strip('\n') |
| 66 |
ldap_certificate_s4 = ucr.get('connector/s4/ldap/certificate') |
| 67 |
if protocol == 'ldapi': |
| 68 |
socket = urllib.quote(ucr.get('connector/s4/ldap/socket', ''), '') |
| 69 |
ldap_uri_s4 = "%s://%s" % (protocol, socket) |
| 70 |
else: |
| 71 |
ldap_uri_s4 = "%s://%s:%d" % (protocol, ldap_host_s4, ldap_port_s4) |
| 72 |
|
| 73 |
lo_s4 = univention.uldap.access(host=ldap_host_s4, port=ldap_port_s4, base=ldap_base_s4, binddn=ldap_binddn_s4, bindpw=ldap_bindpw_s4, start_tls=tls_mode, ca_certfile=ldap_certificate_s4, uri=ldap_uri_s4) |
| 74 |
lo_s4.lo.set_option(ldap.OPT_REFERRALS, 0) |
| 75 |
return lo_s4 |
| 76 |
|
| 77 |
|
| 78 |
def fix_slave(lo, lo_s4, slave_dn, slave_attrs, dry_run=True): |
| 47 |
logger.debug('Checking %r', slave_dn) |
79 |
logger.debug('Checking %r', slave_dn) |
| 48 |
logger.debug('Attributes: %r', slave_attrs) |
80 |
logger.debug('Attributes: %r', slave_attrs) |
| 49 |
roles = slave_attrs.get('ucsschoolRole', []) |
81 |
roles = slave_attrs.get('ucsschoolRole', []) |
| 50 |
object_classes = slave_attrs.get('objectClass', []) |
82 |
object_classes = slave_attrs.get('objectClass', []) |
| 51 |
slave_cn = slave_attrs.get('cn', []) |
83 |
slave_cn = slave_attrs.get('cn', [''])[0] |
| 52 |
slave_s4_dn = '' |
|
|
| 53 |
slave_uAC = '' |
| 54 |
|
84 |
|
| 55 |
mod_role = { |
85 |
mod_role = { |
| 56 |
'old': roles, |
86 |
'old': roles, |
|
Lines 61-98
def fix_slave(lo, slave_dn, slave_attrs, dry_run=True):
Link Here
|
| 61 |
'new': [oc for oc in object_classes if oc not in ('univentionWindows', 'ucsschoolComputer')], |
91 |
'new': [oc for oc in object_classes if oc not in ('univentionWindows', 'ucsschoolComputer')], |
| 62 |
} |
92 |
} |
| 63 |
|
93 |
|
| 64 |
output = subprocess.check_output(['univention-s4search', '--cross-ncs', '(&(cn=%s)(userAccountControl:1.2.840.113556.1.4.803:=4096))' % slave_cn[0]]) |
|
|
| 65 |
for line in output.splitlines(): |
| 66 |
if 'dn:' in line: |
| 67 |
slave_s4_dn = line.split(': ')[1] |
| 68 |
if 'userAccountControl' in line: |
| 69 |
slave_uAC = int(line.split(': ')[1]) |
| 70 |
|
| 71 |
if mod_role['old'] != mod_role['new'] or mod_oc['old'] != mod_oc['new']: |
94 |
if mod_role['old'] != mod_role['new'] or mod_oc['old'] != mod_oc['new']: |
| 72 |
logger.info('Will modify: %s', slave_dn) |
95 |
logger.info('Will modify: %s', slave_dn) |
| 73 |
logger.info('Roles: %r', mod_role) |
96 |
logger.info('Roles: %r', mod_role) |
| 74 |
logger.info('ObjectClass: %r', mod_oc) |
97 |
logger.info('ObjectClass: %r', mod_oc) |
| 75 |
if slave_uAC: |
98 |
if not dry_run: |
| 76 |
new_slave_uAC = int(slave_uAC) - 4096 + 532480 |
|
|
| 77 |
mod_uAC = { |
| 78 |
'old': [slave_uAC], |
| 79 |
'new': [new_slave_uAC], |
| 80 |
} |
| 81 |
logger.info('userAccountControl: %r', mod_uAC) |
| 82 |
if dry_run: |
| 83 |
logger.info('DRY-RUN: skipping modification') |
| 84 |
else: |
| 85 |
lo.modify(slave_dn, ( |
99 |
lo.modify(slave_dn, ( |
| 86 |
('ucsschoolRole', mod_role['old'], mod_role['new']), |
100 |
('ucsschoolRole', mod_role['old'], mod_role['new']), |
| 87 |
('objectClass', mod_oc['old'], mod_oc['new']), |
101 |
('objectClass', mod_oc['old'], mod_oc['new']), |
| 88 |
)) |
102 |
)) |
| 89 |
if slave_s4_dn and slave_uAC: |
103 |
|
| 90 |
# reset userAccountControl from workstation/server (4096) to DC (532480) |
104 |
for slave_s4_dn, slave_s4_attr in lo_s4.search(filter_format('(&(cn=%s)(userAccountControl:1.2.840.113556.1.4.803:=4096))', [slave_cn]), attr=['userAccountControl']): |
| 91 |
mod_str = 'dn: %s\nchangetype: modify\nreplace: userAccountControl\nuserAccountControl: %s\n\n' % (slave_s4_dn, new_slave_uAC) |
105 |
if slave_s4_dn is None: |
| 92 |
p1 = subprocess.Popen(['ldbmodify', '-H', '/var/lib/samba/private/sam.ldb'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, shell=False) |
106 |
continue # referals |
| 93 |
(stdout, stderr) = p1.communicate(mod_str) |
107 |
slave_account_control = int(slave_s4_attr['userAccountControl'][0]) |
| 94 |
if p1.returncode != 0: |
108 |
new_slave_account_control = int(slave_account_control) & ~4096 | 8192 | 524288 |
| 95 |
logger.error('Failed to set userAccountControl for Samba 4 object (%s)\n%s' % (slave_s4_dn, stderr)) |
109 |
if slave_account_control == new_slave_account_control: |
|
|
110 |
continue |
| 111 |
|
| 112 |
mod_account_control = [('userAccountControl', slave_s4_attr['userAccountControl'], [str(new_slave_account_control)])] |
| 113 |
logger.info('userAccountControl: %r', mod_account_control) |
| 114 |
|
| 115 |
# reset userAccountControl from workstation/server (4096) to DC (532480) |
| 116 |
if not dry_run: |
| 117 |
lo_s4.modify(slave_s4_dn, mod_account_control) |
| 118 |
|
| 119 |
if dry_run: |
| 120 |
logger.info('DRY-RUN: skipping modification') |
| 96 |
|
121 |
|
| 97 |
|
122 |
|
| 98 |
def main(): |
123 |
def main(): |
|
Lines 110-121
the wrong object class will be removed and the ucsschoolRole attribute corrected
Link Here
|
| 110 |
|
135 |
|
| 111 |
logger.info('Looking for affected domaincontroller_slave objects...') |
136 |
logger.info('Looking for affected domaincontroller_slave objects...') |
| 112 |
lo, po = getAdminConnection() |
137 |
lo, po = getAdminConnection() |
|
|
138 |
lo_s4 = get_s4_lo() |
| 113 |
slaves = lo.search( |
139 |
slaves = lo.search( |
| 114 |
filter='(univentionObjectType=computers/domaincontroller_slave)', |
140 |
filter='(univentionObjectType=computers/domaincontroller_slave)', |
| 115 |
attr=['objectClass', 'ucsschoolRole', 'cn'] |
141 |
attr=['objectClass', 'ucsschoolRole', 'cn'] |
| 116 |
) |
142 |
) |
| 117 |
for slave_dn, slave_attrs in slaves: |
143 |
for slave_dn, slave_attrs in slaves: |
| 118 |
fix_slave(lo, slave_dn, slave_attrs, dry_run=options.dry_run) |
144 |
fix_slave(lo, lo_s4, slave_dn, slave_attrs, dry_run=options.dry_run) |
| 119 |
|
145 |
|
| 120 |
|
146 |
|
| 121 |
if __name__ == '__main__': |
147 |
if __name__ == '__main__': |