|
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__': |