def attach(self, obj, lo): # add univentionPolicyReference if neccessary oc = lo.get(obj.dn, ['objectClass']) if 'univentionPolicyReference' not in oc.get('objectClass', []): try: lo.modify(obj.dn, [('objectClass', '', 'univentionPolicyReference')]) except: logger.warning( 'Objectclass univentionPolicyReference cannot be added to %r', obj) return # add the missing policy pl = lo.get(obj.dn, ['univentionPolicyReference']) logger.info('Attaching %r to %r', self, obj) if self.dn.lower() not in map(lambda x: x.lower(), pl.get('univentionPolicyReference', [])): modlist = [('univentionPolicyReference', '', self.dn)] try: lo.modify(obj.dn, modlist) except: logger.warning('Policy %s cannot be referenced to %r', self, obj) else: logger.info('Already attached!')
def add_domain_controllers(self, lo): logger.info('School.add_domain_controllers(): ou_name=%r', self.name) school_dcs = ucr.get('ucsschool/ldap/default/dcs', 'edukativ').split() for dc in school_dcs: administrative = dc == 'verwaltung' dc_name = self.get_dc_name(administrative=administrative) server = AnyComputer.get_first_udm_obj(lo, 'cn=%s' % escape_filter_chars(dc_name)) logger.info('School.add_domain_controllers(): administrative=%r dc_name=%s self.dc_name=%r server=%r', administrative, dc_name, self.dc_name, server) if not server and not self.dc_name: if administrative: administrative_type = 'administrative' else: administrative_type = 'educational' group_dn = self.get_administrative_group_name(administrative_type, ou_specific=True, as_dn=True) try: hostlist = lo.get(group_dn, ['uniqueMember']).get('uniqueMember', []) except ldap.NO_SUCH_OBJECT: hostlist = [] except Exception, e: logger.error('cannot read %s: %s', group_dn, e) return if hostlist: continue # if at least one DC has control over this OU then jump to next 'school_dcs' item ==> do not create default slave objects self.create_dc_slave(lo, dc_name, administrative=administrative) dhcp_service = self.get_dhcp_service(dc_name) dhcp_service.create(lo) dhcp_service.add_server(dc_name, lo) return True
def _alter_udm_obj(self, udm_obj): super(SchoolComputer, self)._alter_udm_obj(udm_obj) inventory_numbers = self.get_inventory_numbers() if inventory_numbers: udm_obj['inventoryNumber'] = inventory_numbers ipv4_network = self.get_ipv4_network() if ipv4_network: if self._ip_is_set_to_subnet(ipv4_network): logger.info( 'IP was set to subnet. Unsetting it on the computer so that UDM can do some magic: Assign next free IP!' ) udm_obj['ip'] = '' else: udm_obj['ip'] = str(ipv4_network.ip) # set network after ip. Otherwise UDM does not do any # nextIp magic... network = self.get_network() if network: # reset network, so that next line triggers free ip udm_obj.old_network = None try: udm_obj['network'] = network.dn except nextFreeIp: logger.error( 'Tried to set IP automatically, but failed! %r is full', network) raise nextFreeIp( _('There are no free addresses left in the subnet!'))
def move_without_hooks(self, lo, udm_obj, force=False): if udm_obj is None: udm_obj = self.get_udm_object(lo) if udm_obj is None: logger.warning('No UDM object found to move from (%r)', self) return False if self.supports_school() and self.get_school_obj(lo) is None: logger.warn('%r wants to move itself to a not existing school', self) return False logger.info('Moving %r to %r', udm_obj.dn, self) if udm_obj.dn == self.dn: logger.warning('%r wants to move to its own DN!', self) return False if force or self._meta.allow_school_change: try: self.do_move(udm_obj, lo) finally: self.invalidate_cache() self.set_dn(self.dn) else: logger.warning( 'Would like to move %s to %r. But it is not allowed!', udm_obj.dn, self) return False return True
def create_without_hooks(self, lo, validate): if self.exists(lo): return False logger.info('Creating %r', self) if validate: self.validate(lo) if self.errors: raise ValidationError(self.errors.copy()) pos = udm_uldap.position(ucr.get('ldap/base')) container = self.position if not container: logger.error('%r cannot determine a container. Unable to create!', self) return False try: pos.setDn(container) udm_obj = udm_modules.get(self._meta.udm_module).object( None, lo, pos, superordinate=self.get_superordinate(lo)) udm_obj.open() # here is the real logic self.do_create(udm_obj, lo) # get it fresh from the database (needed for udm_obj._exists ...) self.set_dn(self.dn) logger.info('%r successfully created', self) return True finally: self.invalidate_cache()
def do_school_change(self, udm_obj, lo, old_school): try: exam_user = ExamStudent.from_student_dn(lo, old_school, self.old_dn) except noObject as exc: logger.info('No exam user for %r found: %s', self.old_dn, exc) else: logger.info('Removing exam user %r', exam_user.dn) exam_user.remove(lo) super(Student, self).do_school_change(udm_obj, lo, old_school)
def add_host_to_dc_group(self, lo): logger.info('School.add_host_to_dc_group(): ou_name=%r dc_name=%r', self.name, self.dc_name) if self.dc_name: dc = SchoolDCSlave(name=self.dc_name, school=self.name) dc.create(lo) dc_udm_obj = dc.get_udm_object(lo) groups = self.get_administrative_group_name('educational', ou_specific='both', as_dn=True) for grp in groups: if grp not in dc_udm_obj['groups']: dc_udm_obj['groups'].append(grp) dc_udm_obj.modify()
def remove_from_groups_of_school(self, school, lo): for cls in (SchoolClass, WorkGroup, SchoolGroup): for group in cls.get_all( lo, school, filter_format('uniqueMember=%s', (self.dn, ))): try: group.users.remove(self.dn) except ValueError: pass else: logger.info('Removing %r from group %r of school %r.', self.dn, group.dn, school) group.modify(lo)
def create(self, lo, validate=True): logger.info('Creating %r', self) pos = udm_uldap.position(ucr.get('ldap/base')) pos.setDn(self.position) udm_obj = udm_modules.get(self._meta.udm_module).object(None, lo, pos) udm_obj.open() udm_obj['name'] = self.name try: self.do_create(udm_obj, lo) except objectExists as exc: return exc.args[0] else: return udm_obj.dn
def modify_without_hooks(self, lo, validate=True, move_if_necessary=None): logger.info('Modifying %r', self) if move_if_necessary is None: move_if_necessary = self._meta.allow_school_change if validate: self.validate(lo, validate_unlikely_changes=True) if self.errors: raise ValidationError(self.errors.copy()) udm_obj = self.get_udm_object(lo) if not udm_obj: logger.info('%s does not exist!', self.old_dn) return False try: old_attrs = deepcopy(udm_obj.info) self.do_modify(udm_obj, lo) # get it fresh from the database self.set_dn(self.dn) udm_obj = self.get_udm_object(lo) same = old_attrs == udm_obj.info if move_if_necessary: if udm_obj.dn != self.dn: if self.move_without_hooks(lo, udm_obj, force=True): same = False if same: logger.info('%r not modified. Nothing changed', self) else: logger.info('%r successfully modified', self) # return not same return True finally: self.invalidate_cache()
def do_modify(self, udm_obj, lo): self.create_mail_domain(lo) self.password = self.password or None removed_schools = set(udm_obj['school']) - set(self.schools) if removed_schools: # change self.schools back, so schools can be removed by remove_from_school() self.schools = udm_obj['school'] for removed_school in removed_schools: logger.info('Removing %r from school %r...', self, removed_school) if not self.remove_from_school(removed_school, lo): logger.error('Error removing %r from school %r.', self, removed_school) return False mandatory_groups = self.groups_used(lo) for group_dn in udm_obj['groups'][:]: logger.debug('Checking group %s for removal', group_dn) if group_dn not in mandatory_groups: logger.debug('Group not mandatory! Part of a school?') try: school_class = SchoolClass.from_dn(group_dn, None, lo) except noObject: logger.debug('No. Leaving it alone...') continue logger.debug('Yes, part of %s!', school_class.school) if school_class.school not in self.school_classes: continue # if the key isn't set we don't change anything to the groups. to remove the groups it has to be an empty list classes = self.school_classes[school_class.school] remove = school_class.name not in classes and school_class.get_relative_name( ) not in classes if remove: logger.debug('Removing it!') udm_obj['groups'].remove(group_dn) else: logger.debug( 'Leaving it alone: Part of own school and either non-school class or new school classes were not defined at all' ) for group_dn in mandatory_groups: logger.debug('Checking group %s for adding', group_dn) if group_dn not in udm_obj['groups']: logger.debug('Group is not yet part of the user. Adding...') udm_obj['groups'].append(group_dn) return super(User, self).do_modify(udm_obj, lo)
def do_create(self, udm_obj, lo): gid = self.school_group.get_udm_object(lo)['gidNumber'] udm_obj['host'] = self.get_server_fqdn(lo) udm_obj['path'] = self.get_share_path() udm_obj['writeable'] = '1' udm_obj['sambaWriteable'] = '1' udm_obj['sambaBrowseable'] = '1' udm_obj['sambaForceGroup'] = '+%s' % self.name udm_obj['sambaCreateMode'] = '0770' udm_obj['sambaDirectoryMode'] = '0770' udm_obj['owner'] = '0' udm_obj['group'] = gid udm_obj['directorymode'] = '0770' if ucr.is_false('ucsschool/default/share/nfs', True): try: udm_obj.options.remove('nfs') # deactivate NFS except ValueError: pass logger.info('Creating share on "%s"', udm_obj['host']) return super(Share, self).do_create(udm_obj, lo)
def from_udm_obj( cls, udm_obj, school, lo ): # Design fault. school is part of the DN or the ucsschoolSchool attribute. '''Creates a new instance with attributes of the udm_obj. Uses get_class_for_udm_obj() ''' cls.init_udm_module(lo) klass = cls.get_class_for_udm_obj(udm_obj, school) if klass is None: logger.warning( 'UDM object %s does not correspond to a class in UCS school lib!', udm_obj.dn) raise UnknownModel(udm_obj.dn, cls) if klass is not cls: logger.info('UDM object %s is not %s, but actually %s', udm_obj.dn, cls.__name__, klass.__name__) if not issubclass(klass, cls): # security! # ExamStudent must not be converted into Teacher/Student/etc., # SchoolClass must not be converted into ComputerRoom # while Group must be converted into ComputerRoom, etc. and User must be converted into Student, etc. raise WrongModel(udm_obj.dn, klass, cls) return klass.from_udm_obj(udm_obj, school, lo) udm_obj.open() attrs = { 'school': cls.get_school_from_dn(udm_obj.dn) or school } # TODO: is this adjustment okay? for name, attr in cls._attributes.iteritems(): if attr.udm_name: udm_value = udm_obj[attr.udm_name] if udm_value == '': udm_value = None attrs[name] = udm_value obj = cls(**deepcopy(attrs)) obj.set_dn(udm_obj.dn) obj._udm_obj_searched = True obj._udm_obj = udm_obj return obj
def create_dc_slave(self, lo, name, administrative=False): if administrative and not self.shall_create_administrative_objects(): logger.warning('Not creating %s: An administrative DC shall not be created as by UCR variable %r', name, 'ucsschool/ldap/noneducational/create/objects') return False if not self.exists(lo): logger.error('%r does not exist. Cannot create %s', self, name) return False if administrative: groups = self.get_administrative_group_name('administrative', ou_specific='both', as_dn=True) else: groups = self.get_administrative_group_name('educational', ou_specific='both', as_dn=True) logger.debug('DC shall become member of %r', groups) dc = SchoolDCSlave(name=name, school=self.name, groups=groups) if dc.exists(lo): logger.info('%r exists. Setting groups, do not move to %r!', dc, self) # call dc.move() if really necessary to move return dc.modify(lo, move_if_necessary=False) else: existing_host = AnyComputer.get_first_udm_obj(lo, 'cn=%s' % escape_filter_chars(name)) if existing_host: logger.error('Given host name "%s" is already in use and no domaincontroller slave system. Please choose another name.', name) return False return dc.create(lo)
def do_school_change(self, udm_obj, lo, old_school): super(User, self).do_school_change(udm_obj, lo, old_school) school = self.school logger.info('User is part of the following groups: %r', udm_obj['groups']) self.remove_from_groups_of_school(old_school, lo) self._udm_obj_searched = False self.school_classes.pop(old_school, None) udm_obj = self.get_udm_object(lo) udm_obj['primaryGroup'] = self.primary_group_dn(lo) groups = set(udm_obj['groups']) at_least_groups = set(self.groups_used(lo)) if (groups | at_least_groups) != groups: udm_obj['groups'] = list(groups | at_least_groups) subdir = self.get_roleshare_home_subdir() udm_obj['unixhome'] = '/home/' + os.path.join(subdir, self.name) samba_home = self.get_samba_home_path(lo) if samba_home: udm_obj['sambahome'] = samba_home profile_path = self.get_profile_path(lo) if profile_path: udm_obj['profilepath'] = profile_path home_drive = self.get_samba_home_drive() if home_drive is not None: udm_obj['homedrive'] = home_drive script_path = self.get_samba_netlogon_script_path() if script_path is not None: udm_obj['scriptpath'] = script_path if udm_obj['departmentNumber'] == old_school: udm_obj['departmentNumber'] = school if school not in udm_obj['school']: udm_obj['school'].append(school) if old_school in udm_obj['school']: udm_obj['school'].remove(old_school) udm_obj.modify(ignore_license=True)
def remove_without_hooks(self, lo): logger.info('Deleting %r', self) udm_obj = self.get_udm_object(lo) if udm_obj: try: udm_obj.remove(remove_childs=True) udm_objects.performCleanup(udm_obj) self.set_dn(None) logger.info('%r successfully removed', self) return True finally: self.invalidate_cache() logger.info('%r does not exist!', self) return False
def move_without_hooks(self, lo, udm_obj=None, force=False): try: if udm_obj is None: try: udm_obj = self.get_only_udm_obj( lo, 'cn=%s' % escape_filter_chars(self.name)) except MultipleObjectsError: logger.error( 'Found more than one DC Slave with hostname "%s"', self.name) return False if udm_obj is None: logger.error('Cannot find DC Slave with hostname "%s"', self.name) return False old_dn = udm_obj.dn school = self.get_school_obj(lo) group_dn = school.get_administrative_group_name('educational', ou_specific=True, as_dn=True) if group_dn not in udm_obj['groups']: logger.error('%r has no LDAP access to %r', self, school) return False if old_dn == self.dn: logger.info( 'DC Slave "%s" is already located in "%s" - stopping here', self.name, self.school) self.set_dn(old_dn) if self.exists_outside_school(lo): if not force: logger.error('DC Slave "%s" is located in another OU - %s', self.name, udm_obj.dn) logger.error('Use force=True to override') return False if school is None: logger.error( 'Cannot move DC Slave object - School does not exist: %r', school) return False self.modify_without_hooks(lo) if school.class_share_file_server == old_dn: school.class_share_file_server = self.dn if school.home_share_file_server == old_dn: school.home_share_file_server = self.dn school.modify_without_hooks(lo) removed = False # find dhcp server object by checking all dhcp service objects for dhcp_service in AnyDHCPService.get_all(lo, None): for dhcp_server in dhcp_service.get_servers(lo): if dhcp_server.name == self.name and not dhcp_server.dn.endswith( ',%s' % school.dn): dhcp_server.remove(lo) removed = True if removed: own_dhcp_service = school.get_dhcp_service() dhcp_server = DHCPServer(name=self.name, school=self.school, dhcp_service=own_dhcp_service) dhcp_server.create(lo) logger.info('Move complete') logger.warning('The DC Slave has to be rejoined into the domain!') finally: self.invalidate_cache() return True
def do_school_change(self, udm_obj, lo, old_school): logger.info('Going to move %r from school %r to %r', self.old_dn, old_school, self.school)
def get_ipv4_subnet(self): network_str = '%s/%s' % (self.name, self.subnet_mask) try: return ipaddr.IPv4Network(network_str) except ValueError as exc: logger.info('%r is no valid IPv4Network:\n%s', network_str, exc)
def add_server(self, dc_name, lo, force_dhcp_server_move=False): """ Create the given DHCP server within the DHCP service. If the DHCP server object already exists somewhere else within the LDAP tree, it may be moved to the DHCP service. PLEASE NOTE: In multiserver environments an existing DHCP server object is always moved to the current DHCP service. In single server environments the DHCP server object is *ONLY* moved, if the UCR variable dhcpd/ldap/base matches to the current DHCP service. """ from ucsschool.lib.models.school import School # create dhcp-server if not exsistant school = School.cache(self.school) dhcp_server = DHCPServer(name=dc_name, school=school.name, dhcp_service=self) existing_dhcp_server_dn = DHCPServer.find_any_dn_with_name(dc_name, lo) if existing_dhcp_server_dn: logger.info('DHCP server %s exists!', existing_dhcp_server_dn) old_dhcp_server_container = lo.parentDn(existing_dhcp_server_dn) dhcpd_ldap_base = ucr.get('dhcpd/ldap/base', '') # only move if # - forced via kwargs OR # - in multiserver environments OR # - desired dhcp server DN matches with UCR config if force_dhcp_server_move or not ucr.is_true( 'ucsschool/singlemaster', False) or dhcp_server.dn.endswith(',%s' % dhcpd_ldap_base): # move if existing DN does not match with desired DN if existing_dhcp_server_dn != dhcp_server.dn: # move existing dhcp server object to OU/DHCP service logger.info( 'DHCP server %s not in school %r! Removing and creating new one at %s!', existing_dhcp_server_dn, school, dhcp_server.dn) old_superordinate = DHCPServer.find_udm_superordinate( existing_dhcp_server_dn, lo) old_dhcp_server = DHCPServer.from_dn( existing_dhcp_server_dn, None, lo, superordinate=old_superordinate) old_dhcp_server.remove(lo) dhcp_server.create(lo) # copy subnets # find local interfaces interfaces = [] for interface_name in set([ key.split('/')[1] for key in ucr.keys() if key.startswith('interfaces/eth') ]): try: address = ipaddr.IPv4Network('%s/%s' % ( ucr['interfaces/%s/address' % interface_name], ucr['interfaces/%s/netmask' % interface_name], )) interfaces.append(address) except ValueError as exc: logger.info('Skipping invalid interface %s:\n%s', interface_name, exc) subnet_dns = DHCPSubnet.find_all_dns_below_base( old_dhcp_server_container, lo) for subnet_dn in subnet_dns: dhcp_service = DHCPSubnet.find_udm_superordinate(subnet_dn, lo) dhcp_subnet = DHCPSubnet.from_dn(subnet_dn, self.school, lo, superordinate=dhcp_service) subnet = dhcp_subnet.get_ipv4_subnet() if subnet in interfaces: # subnet matches any local subnet logger.info('Creating new DHCPSubnet from %s', subnet_dn) new_dhcp_subnet = DHCPSubnet(**dhcp_subnet.to_dict()) new_dhcp_subnet.dhcp_service = self new_dhcp_subnet.position = new_dhcp_subnet.get_own_container( ) new_dhcp_subnet.set_dn(new_dhcp_subnet.dn) new_dhcp_subnet.create(lo) else: logger.info('Skipping non-local subnet %s', subnet) else: logger.info('No DHCP server named %s found! Creating new one!', dc_name) dhcp_server.create(lo)