Beispiel #1
0
    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
Beispiel #2
0
	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
Beispiel #3
0
	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)
Beispiel #4
0
 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
Beispiel #5
0
    def cache(cls, *args, **kwargs):
        '''Initializes a new instance and caches it for subsequent calls.
		Useful when using School.cache(school_name) a lot in different
		functions, in loops, etc.
		'''
        args = list(args)
        if args:
            kwargs['name'] = args.pop(0)
        if args:
            kwargs['school'] = args.pop(0)
        key = [cls.__name__] + [(k, kwargs[k]) for k in sorted(kwargs)]
        key = tuple(key)
        if key not in cls._cache:
            logger.debug('Initializing %r', key)
            obj = cls(**kwargs)
            cls._cache[key] = obj
        return cls._cache[key]
Beispiel #6
0
    def get_udm_object(self, lo):
        '''Returns the UDM object that corresponds to self.
		If self._meta.name_is_unique it searches for any UDM object
		with self.name.
		If not (which is the default) it searches for self.old_dn or self.dn
		Returns None if no object was found. Caches the result, even None
		If you want to re-search, you need to explicitely set
		self._udm_obj_searched = False
		'''
        self.init_udm_module(lo)
        if self._udm_obj_searched is False or (
                self._udm_obj and self._udm_obj.lo.binddn != lo.binddn):
            dn = self.old_dn or self.dn
            superordinate = self.get_superordinate(lo)
            if dn is None:
                logger.debug('Getting %s UDM object: No DN!',
                             self.__class__.__name__)
                return
            if self._meta.name_is_unique:
                if self.name is None:
                    return None
                udm_name = self._attributes['name'].udm_name
                name = self.get_name_from_dn(dn)
                filter_str = '%s=%s' % (udm_name, escape_filter_chars(name))
                self._udm_obj = self.get_first_udm_obj(lo, filter_str,
                                                       superordinate)
            else:
                logger.debug('Getting %s UDM object by dn: %s',
                             self.__class__.__name__, dn)
                try:
                    self._udm_obj = udm_modules.lookup(
                        self._meta.udm_module,
                        None,
                        lo,
                        scope='base',
                        base=dn,
                        superordinate=superordinate)[0]
                except (noObject, IndexError):
                    self._udm_obj = None
                else:
                    self._udm_obj.open()
            self._udm_obj_searched = True
        return self._udm_obj
Beispiel #7
0
	def from_binddn(cls, lo):
		logger.debug('All local schools: Showing all OUs which DN %s can read.', lo.binddn)
		# get all schools of the user which are present on this server
		user_schools = lo.search(base=lo.binddn, scope='base', attr=['ucsschoolSchool'])[0][1].get('ucsschoolSchool', [])
		if user_schools:
			schools = []
			for ou in user_schools:
				try:
					schools.append(cls.from_dn(cls(name=ou).dn, None, lo))
				except noObject:
					pass
			return cls._filter_local_schools(schools, lo)

		if 'ou=' in lo.binddn:
			# user has no ucsschoolSchool attribute (not migrated yet)
			# we got an OU in the user DN -> school teacher or assistent
			# restrict the visibility to current school
			# (note that there can be schools with a DN such as ou=25g18,ou=25,dc=...)
			school_dn = lo.binddn[lo.binddn.find('ou='):]
			logger.debug('Schools from binddn: Found an OU in the LDAP binddn. Restricting schools to only show %s', school_dn)
			school = cls.from_dn(school_dn, None, lo)
			logger.debug('Schools from binddn: Found school: %r', school)
			return cls._filter_local_schools([school], lo)

		logger.warning('Schools from binddn: Unable to identify OU of this account - showing all local OUs!')
		return School.get_all(lo)
Beispiel #8
0
    def call_hooks(self, hook_time, func_name):
        '''Calls run-parts in
		os.path.join(self.hook_path, '%s_%s_%s.d' % (self._meta.hook_path, func_name, hook_time))
		if self.build_hook_line(hook_time, func_name) returns a non-empty string

		Usage in lib itself:
			hook_time in ['pre', 'post']
			func_name in ['create', 'modify', 'remove']

		In the lib, post-hooks are only called if the corresponding function returns True
		'''
        # verify path
        hook_path = self._meta.hook_path
        path = os.path.join(self.hook_path,
                            '%s_%s_%s.d' % (hook_path, func_name, hook_time))
        if path in self._empty_hook_paths:
            return None
        if not os.path.isdir(path) or not os.listdir(path):
            logger.debug('%s not found or empty.', path)
            self._empty_hook_paths.add(path)
            return None
        logger.debug('%s shall be executed', path)

        dn = None
        if hook_time == 'post':
            dn = self.old_dn

        logger.debug('Building hook line: %r.build_hook_line(%r, %r)', self,
                     hook_time, func_name)
        line = self.build_hook_line(hook_time, func_name)
        if not line:
            logger.debug('No line. Skipping!')
            return None
        line = line.strip() + '\n'

        # create temporary file with data
        with tempfile.NamedTemporaryFile() as tmpfile:
            tmpfile.write(line)
            tmpfile.flush()

            # invoke hook scripts
            # <script> <temporary file> [<ldap dn>]
            command = ['run-parts', path, '--arg', tmpfile.name]
            if dn:
                command.extend(('--arg', dn))

            ret_code = subprocess.call(command)

            return ret_code == 0
Beispiel #9
0
 def do_create(self, udm_obj, lo):
     if not self.schools:
         self.schools = [self.school]
     self.set_default_options(udm_obj)
     self.create_mail_domain(lo)
     password_created = False
     if not self.password:
         logger.debug('No password given. Generating random one')
         old_password = self.password  # None or ''
         self.password = create_passwd(dn=self.dn)
         password_created = True
     udm_obj['primaryGroup'] = self.primary_group_dn(lo)
     udm_obj['groups'] = self.groups_used(lo)
     subdir = self.get_roleshare_home_subdir()
     udm_obj['unixhome'] = '/home/' + os.path.join(subdir, self.name)
     udm_obj['overridePWHistory'] = '1'
     udm_obj['overridePWLength'] = '1'
     if self.disabled is None:
         udm_obj['disabled'] = 'none'
     if 'mailbox' in udm_obj:
         udm_obj['mailbox'] = '/var/spool/%s/' % 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
     success = super(User, self).do_create(udm_obj, lo)
     if password_created:
         # to not show up in host_hooks
         self.password = old_password
     return success
Beispiel #10
0
    def get_all(cls,
                lo,
                school,
                filter_str=None,
                easy_filter=False,
                superordinate=None):
        '''
		Returns a list of all objects that can be found in cls.get_container() with the
		correct udm_module
		If filter_str is given, all udm properties with include_in_default_search are
		queried for that string (so that it should be the value)
		'''
        cls.init_udm_module(lo)
        complete_filter = cls._meta.udm_filter
        if easy_filter:
            filter_from_filter_str = cls.build_easy_filter(filter_str)
        else:
            filter_from_filter_str = filter_str
        if filter_from_filter_str:
            if complete_filter:
                complete_filter = conjunction(
                    '&', [complete_filter, filter_from_filter_str])
            else:
                complete_filter = filter_from_filter_str
        complete_filter = str(complete_filter)
        logger.debug('Getting all %s of %s with filter %r', cls.__name__,
                     school, complete_filter)
        ret = []
        for udm_obj in cls.lookup(lo,
                                  school,
                                  complete_filter,
                                  superordinate=superordinate):
            udm_obj.open()
            try:
                ret.append(cls.from_udm_obj(udm_obj, school, lo))
            except UnknownModel:
                continue
        return ret
Beispiel #11
0
    def from_dn(cls, dn, school, lo, superordinate=None):
        '''Returns a new instance based on the UDM object found at dn
		raises noObject if the udm_module does not match the dn
		or dn is not found
		'''
        cls.init_udm_module(lo)
        if school is None and cls.supports_school():
            school = cls.get_school_from_dn(dn)
            if school is None:
                logger.warn('Unable to guess school from %r', dn)
        try:
            logger.debug('Looking up %s with dn %r', cls.__name__, dn)
            udm_obj = udm_modules.lookup(cls._meta.udm_module,
                                         None,
                                         lo,
                                         filter=cls._meta.udm_filter,
                                         base=dn,
                                         scope='base',
                                         superordinate=superordinate)[0]
        except IndexError:
            # happens when cls._meta.udm_module does not "match" the dn
            raise WrongObjectType(dn, cls)
        return cls.from_udm_obj(udm_obj, school, lo)
Beispiel #12
0
	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)
Beispiel #13
0
    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)
Beispiel #14
0
 def find_all_dns_below_base(cls, dn, lo):
     logger.debug('Searching all univentionDhcpSubnet in %r', dn)
     return lo.searchDn(filter='(objectClass=univentionDhcpSubnet)',
                        base=dn)
Beispiel #15
0
 def invalidate_cache(cls):
     for key in cls._cache.keys():
         if key[0] == cls.__name__:
             logger.debug('Invalidating %r', key)
             cls._cache.pop(key)