def create_without_hooks(self, lo, validate): district = self.get_district() if district: ou = OU(name=district) ou.position = ucr.get('ldap/base') ou.create(lo, False) # setting class_share_file_server and home_share_file_server: # 1. set to None # 2. create school # 3. (maybe) create file_servers <- that is why this is necessary # 4. set file_servers # 5. modify school saved_class_share_file_server = self.class_share_file_server saved_home_share_file_server = self.home_share_file_server self.class_share_file_server = None self.home_share_file_server = None try: success = super(School, self).create_without_hooks(lo, validate) if not success: logger.warning('Creating %r failed (maybe it already exists?)! Trying to set it up nonetheless', self) self.modify_without_hooks(lo) # In a single server environment the default DHCP container must # be set to the DHCP container in the school ou. Otherwise newly # imported computers have the DHCP objects in the wrong DHCP container if ucr.is_true('ucsschool/singlemaster', False): if not ucr.get('dhcpd/ldap/base'): handler_set(['dhcpd/ldap/base=cn=dhcp,%s' % (self.dn)]) ucr.load() self.create_default_containers(lo) self.create_default_groups(lo) self.add_host_to_dc_group(lo) if not self.add_domain_controllers(lo): return False if self.dc_name_administrative: self.create_dc_slave(lo, self.dc_name_administrative, administrative=True) dhcp_service = self.get_dhcp_service(self.dc_name_administrative) dhcp_service.create(lo) dhcp_service.add_server(self.dc_name_administrative, lo) finally: logger.debug('Resetting share file servers from None to %r and %r', saved_home_share_file_server, saved_class_share_file_server) self.class_share_file_server = saved_class_share_file_server self.home_share_file_server = saved_home_share_file_server self.class_share_file_server = self.get_class_share_file_server(lo) self.home_share_file_server = self.get_home_share_file_server(lo) logger.debug('Now it is %r and %r - %r should be modified accordingly', self.home_share_file_server, self.class_share_file_server, self) self.modify_without_hooks(lo) # if requested, then create dhcp_dns policy that clears univentionDhcpDomainNameServers at OU level # to prevent problems with "wrong" DHCP DNS policy connected to ldap base if ucr.is_true('ucsschool/import/generate/policy/dhcp/dns/clearou', False): policy = DHCPDNSPolicy(name='dhcp-dns-clear', school=self.name, empty_attributes=['univentionDhcpDomainNameServers']) policy.create(lo) policy.attach(self, lo) return success
def create_default_groups(self, lo): # DC groups administrative_group_container = 'cn=ucsschool,cn=groups,%s' % ucr.get('ldap/base') # DC-Edukativnetz # OU%s-DC-Edukativnetz # Member-Edukativnetz # OU%s-Member-Edukativnetz administrative_group_names = self.get_administrative_group_name('educational', domain_controller='both', ou_specific='both') if self.shall_create_administrative_objects(): administrative_group_names.extend(self.get_administrative_group_name('administrative', domain_controller='both', ou_specific='both')) # same with Verwaltungsnetz for administrative_group_name in administrative_group_names: group = BasicGroup.cache(name=administrative_group_name, container=administrative_group_container) group.create(lo) # cn=ouadmins admin_group_container = 'cn=ouadmins,cn=groups,%s' % ucr.get('ldap/base') group = BasicGroup.cache(self.group_name('admins', 'admins-'), container=admin_group_container) group.create(lo) group.add_umc_policy(self.get_umc_policy_dn('admins'), lo) try: udm_obj = group.get_udm_object(lo) except noObject: logger.error('Could not load OU admin group %r for adding "school" value', group.dn) else: admin_option = 'ucsschoolAdministratorGroup' if admin_option not in udm_obj.options: udm_obj.options.append(admin_option) udm_obj['school'] = [self.name] udm_obj.modify() # cn=schueler group = Group.cache(self.group_name('pupils', 'schueler-'), self.name) group.create(lo) group.add_umc_policy(self.get_umc_policy_dn('pupils'), lo) # cn=lehrer group = Group.cache(self.group_name('teachers', 'lehrer-'), self.name) group.create(lo) group.add_umc_policy(self.get_umc_policy_dn('teachers'), lo) # cn=mitarbeiter if self.shall_create_administrative_objects(): group = Group.cache(self.group_name('staff', 'mitarbeiter-'), self.name) group.create(lo) group.add_umc_policy(self.get_umc_policy_dn('staff'), lo) if ucr.is_true('ucsschool/import/attach/policy/default-umc-users', True): # cn=Domain Users %s group = Group.cache("Domain Users %s" % (self.name,), self.name) group.create(lo) group.add_umc_policy("cn=default-umc-users,cn=UMC,cn=policies,%s" % (ucr.get('ldap/base'),), lo)
def create_without_hooks(self, lo, validate): # prepare LDAP: create containers where this basic group lives if necessary container_dn = self.get_own_container()[:-len(ucr.get('ldap/base')) - 1] containers = str2dn(container_dn) super_container_dn = ucr.get('ldap/base') for container_info in reversed(containers): dn_part, cn = container_info[0][0:2] if dn_part.lower() == 'ou': container = OU(name=cn) else: container = Container(name=cn, school='', group_path='1') container.position = super_container_dn super_container_dn = container.create(lo, False) return super(BasicGroup, self).create_without_hooks(lo, validate)
def get_only_udm_obj(cls, lo, filter_str, superordinate=None, base=None): '''Returns the one UDM object of class cls._meta.udm_module that matches a given filter. If more than one is found, a MultipleObjectsError is raised If none is found, None is returned ''' cls.init_udm_module(lo) if cls._meta.udm_filter: filter_str = '(&(%s)(%s))' % (cls._meta.udm_filter, filter_str) logger.debug('Getting %s UDM object by filter: %s', cls.__name__, filter_str) objs = udm_modules.lookup(cls._meta.udm_module, None, lo, scope='sub', base=base or ucr.get('ldap/base'), filter=str(filter_str), superordinate=superordinate) if len(objs) == 0: return None if len(objs) > 1: raise MultipleObjectsError(objs) obj = objs[0] obj.open() return obj
def get_students_groups(self): prefix = ucr.get('ucsschool/ldap/default/groupprefix/pupils', 'schueler-') return [ self.get_group_dn('%s%s' % (prefix, school), school) for school in self.schools ]
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 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 get_staff_groups(self): prefix = ucr.get('ucsschool/ldap/default/groupprefix/staff', 'mitarbeiter-') return [ self.get_group_dn('%s%s' % (prefix, school), school) for school in self.schools ]
def from_student_dn(cls, lo, school, dn): examUserPrefix = ucr.get('ucsschool/ldap/default/userprefix/exam', 'exam-') dn = 'uid=%s%s,%s' % (escape_dn_chars(examUserPrefix), explode_dn(dn, True)[0], cls.get_container(school)) return cls.from_dn(dn, school, lo)
def get_teachers_groups(self): prefix = ucr.get('ucsschool/ldap/default/groupprefix/teachers', 'lehrer-') return [ self.get_group_dn('%s%s' % (prefix, school), school) for school in self.schools ]
def check_configuration(config): if not config.get("sourceUID"): raise InitialisationError("No sourceUID was specified.") if not config["input"].get("type"): raise InitialisationError("No input:type was specified.") if "user_deletion" in config: raise InitialisationError("The 'user_deletion' configuration key is deprecated. Please set 'deletion_grace_period'.") for role in ('default', 'staff', 'student', 'teacher', 'teacher_and_staff'): try: username_max_length = config["username"]["max_length"][role] except KeyError: continue if username_max_length < 4: raise InitialisationError( "Configuration value of username:max_length:{} must be higher than 3.".format(role) ) exam_user_prefix_length = len(ucr.get("ucsschool/ldap/default/userprefix/exam", "exam-")) student_username_max_length = config["username"]["max_length"].get("student", 20 - exam_user_prefix_length) if student_username_max_length > 20 - exam_user_prefix_length: raise InitialisationError( "Configuration value of username:max_length:student must be {} or less.".format(20 - exam_user_prefix_length) ) for role in ('default', 'staff', 'teacher', 'teacher_and_staff'): username_max_length = config["username"]["max_length"].get(role, 20) if username_max_length > 20: raise InitialisationError( "Configuration value of username:max_length:{} must be 20 or less.".format(role) )
def get_all(cls, lo, filter_str=None, easy_filter=False, respect_local_oulist=True): schools = super(School, cls).get_all(lo, school=None, filter_str=filter_str, easy_filter=easy_filter) oulist = ucr.get('ucsschool/local/oulist') if oulist and respect_local_oulist: logger.debug('All Schools: Schools overridden by UCR variable ucsschool/local/oulist') ous = [x.strip() for x in oulist.split(',')] schools = [school for school in schools if school.name in ous] return cls._filter_local_schools(schools, lo)
def find_any_dn_with_name(cls, name, lo): logger.debug('Searching first dhcpServer with cn=%s', name) try: dn = lo.searchDn(filter=filter_format( '(&(objectClass=dhcpServer)(cn=%s))', [name]), base=ucr.get('ldap/base'))[0] except IndexError: dn = None logger.debug('... %r found', dn) return dn
def get_dc_name(self, administrative=False, or_fallback=True): if ucr.is_true('ucsschool/singlemaster', False): return ucr.get('hostname') elif self.dc_name: if administrative: return '%sv' % self.dc_name else: return self.dc_name else: if or_fallback: return self.get_dc_name_fallback(administrative=administrative) else: return None
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 get_samba_home_path(self, lo): school = School.cache(self.school) # if defined then use UCR value ucr_variable = ucr.get('ucsschool/import/set/sambahome') if ucr_variable is not None: samba_home_path = r'\\%s' % ucr_variable.strip('\\') # in single server environments the master is always the fileserver elif ucr.is_true('ucsschool/singlemaster', False): samba_home_path = r'\\%s' % ucr.get('hostname') # if there's a cached result then use it elif school.dn not in self._samba_home_path_cache: samba_home_path = None # get windows home server from OU object school = self.get_school_obj(lo) home_share_file_server = school.home_share_file_server if home_share_file_server: samba_home_path = r'\\%s' % self.get_name_from_dn( home_share_file_server) self._samba_home_path_cache[school.dn] = samba_home_path else: samba_home_path = self._samba_home_path_cache[school.dn] if samba_home_path is not None: return r'%s\%s' % (samba_home_path, self.name)
def get_share_fileserver_dn(self, set_by_self, lo): if set_by_self: set_by_self = self.get_name_from_dn(set_by_self) or set_by_self hostname = set_by_self or self.get_dc_name() if hostname == self.get_dc_name_fallback(): # does not matter if exists or not - dc object will be created later host = SchoolDC(name=hostname, school=self.name) return host.dn host = AnyComputer.get_first_udm_obj(lo, 'cn=%s' % escape_filter_chars(hostname)) if host: return host.dn else: logger.warning('Could not find %s. Using this host as ShareFileServer ("%s").', hostname, ucr.get('hostname')) return ucr.get('ldap/hostdn')
def validate(self, value): super(DCName, self).validate(value) if value: regex = re.compile('^[a-zA-Z0-9](([a-zA-Z0-9-]*)([a-zA-Z0-9]$))?$') if not regex.match(value): raise ValueError(_('Invalid Domain Controller name')) if ucr.is_true('ucsschool/singlemaster', False): if len(value) > 12: raise ValueError( _('A valid NetBIOS hostname can not be longer than 12 characters.' )) if sum([len(value), 1, len(ucr.get('domainname', ''))]) > 63: raise ValueError( _('The length of fully qualified domain name is greater than 63 characters.' ))
def get_profile_path(self, lo): ucr_variable = ucr.get('ucsschool/import/set/serverprofile/path') if ucr_variable is not None: return ucr_variable school = School.cache(self.school) if school.dn not in self._profile_path_cache: profile_path = r'%s\%%USERNAME%%\windows-profiles\default' for computer in AnyComputer.get_all( lo, self.school, 'univentionService=Windows Profile Server'): profile_path = profile_path % (r'\\%s' % computer.name) break else: profile_path = profile_path % '%LOGONSERVER%' self._profile_path_cache[school.dn] = profile_path return self._profile_path_cache[school.dn]
def get_server_fqdn(self, lo): domainname = ucr.get('domainname') school = self.get_school_obj(lo) school_dn = school.dn # fetch serverfqdn from OU result = lo.get(school_dn, ['ucsschoolClassShareFileServer']) if result: server_domain_name = lo.get( result['ucsschoolClassShareFileServer'][0], ['associatedDomain']) if server_domain_name: server_domain_name = server_domain_name['associatedDomain'][0] else: server_domain_name = domainname result = lo.get(result['ucsschoolClassShareFileServer'][0], ['cn']) if result: return '%s.%s' % (result['cn'][0], server_domain_name) # get alternative server (defined at ou object if a dc slave is responsible for more than one ou) ou_attr_ldap_access_write = lo.get(school_dn, ['univentionLDAPAccessWrite']) alternative_server_dn = None if len(ou_attr_ldap_access_write) > 0: alternative_server_dn = ou_attr_ldap_access_write[ 'univentionLDAPAccessWrite'][0] if len(ou_attr_ldap_access_write) > 1: logger.warning( 'more than one corresponding univentionLDAPAccessWrite found at ou=%s', self.school) # build fqdn of alternative server and set serverfqdn if alternative_server_dn: alternative_server_attr = lo.get(alternative_server_dn, ['uid']) if len(alternative_server_attr) > 0: alternative_server_uid = alternative_server_attr['uid'][0] alternative_server_uid = alternative_server_uid.replace( '$', '') if len(alternative_server_uid) > 0: return '%s.%s' % (alternative_server_uid, domainname) # fallback return '%s.%s' % (school.get_dc_name_fallback(), domainname)
def get_administrative_group_name(self, group_type, domain_controller=True, ou_specific=False, as_dn=False): if domain_controller == 'both': return flatten([self.get_administrative_group_name(group_type, True, ou_specific, as_dn), self.get_administrative_group_name(group_type, False, ou_specific, as_dn)]) if ou_specific == 'both': return flatten([self.get_administrative_group_name(group_type, domain_controller, False, as_dn), self.get_administrative_group_name(group_type, domain_controller, True, as_dn)]) if group_type == 'administrative': name = 'Verwaltungsnetz' else: name = 'Edukativnetz' if domain_controller: name = 'DC-%s' % name else: name = 'Member-%s' % name if ou_specific: name = 'OU%s-%s' % (self.name.lower(), name) if as_dn: return 'cn=%s,cn=ucsschool,cn=groups,%s' % (name, ucr.get('ldap/base')) else: return name
def get_container(cls, school=None): from ucsschool.lib.models.school import School if school: return School.cache(school).dn return ucr.get('ldap/base')
def get_container(cls, school=None): return 'cn=domain,cn=mail,%s' % ucr.get('ldap/base')
def cn_name(cls, name, default): ucr_var = 'ucsschool/ldap/default/container/%s' % name return ucr.get(ucr_var, default)
def get_container(cls, school=None): return ucr.get('ldap/base')
def _filter_local_schools(cls, schools, lo): if ucr.get('server/role') in ('domaincontroller_master', 'domaincontroller_backup'): return schools return [school for school in schools if any(ucr.get('ldap/hostdn', '').lower() == x.lower() for x in school.get_administrative_server_names(lo) + school.get_educational_server_names(lo))]
def get_samba_home_drive(self): return ucr.get('ucsschool/import/set/homedrive')
def group_name(self, prefix_var, default_prefix): ucr_var = 'ucsschool/ldap/default/groupprefix/%s' % prefix_var name_part = ucr.get(ucr_var, default_prefix) school_part = self.name.lower() return '%s%s' % (name_part, school_part)
def get_dhcp_service(self, hostname=None): return DHCPService.cache(self.name.lower(), self.name, hostname=hostname, domainname=ucr.get('domainname'))
def get_umc_policy_dn(self, name): # at least the default ones should exist due to the join script return ucr.get('ucsschool/ldap/default/policy/umc/%s' % name, 'cn=ucsschool-umc-%s-default,cn=UMC,cn=policies,%s' % (name, ucr.get('ldap/base')))