コード例 #1
0
ファイル: __init__.py プロジェクト: B-Rich/smart
	def save( self, request ):
		"""Saves the UCS Active Directory Connector configuration

		options:
			LDAP_Host: hostname of the AD server
			LDAP_Base: LDAP base of the AD server
			LDAP_BindDN: LDAP DN to use for authentication
			KerberosDomain: kerberos domain
			PollSleep: time in seconds between polls
			RetryRejected: how many time to retry a synchronisation
			MappingSyncMode: synchronisation mode
			MappingGroupLanguage: language of the AD server

		return: { 'success' : (True|False), 'message' : <details> }
		"""

		self.required_options( request, *map( lambda x: x[ 0 ], Instance.OPTION_MAPPING ) )
		self.guessed_baseDN = None

		try:
			fn = '%s/.htaccess' % DIR_WEB_AD
			fd = open( fn, 'w' )
			fd.write( 'require user %s\n' % self._username )
			fd.close()
			os.chmod( fn, 0644 )
			os.chown( fn, 0, 0 )
		except Exception, e:
			message = _( 'An error occured while saving .htaccess (filename=%(fn)s ; exception=%(exception)s)') % { 'fn': fn, 'exception': e.__class__.__name__ }
			MODULE.process( 'An error occured while saving .htaccess (filename=%(fn)s ; exception=%(exception)s)' % { 'fn': fn, 'exception': e.__class__.__name__ } )
			self.finished( request.id, { 'success' : False, 'message' : message } )
			return
コード例 #2
0
ファイル: __init__.py プロジェクト: B-Rich/smart
		def _thread( request ):
			result = []
			for ldap_dn in request.options:
				if request.flavor == 'users/self':
					ldap_dn = self._user_dn
				module = get_module( request.flavor, ldap_dn )
				if module is None:
					MODULE.process( 'A module for the LDAP DN %s could not be found' % ldap_dn )
					continue
				obj = module.get( ldap_dn )
				if obj:
					props = obj.info
					for passwd in module.password_properties:
						if passwd in props:
							del props[ passwd ]
					props[ '$dn$' ] = obj.dn
					props[ '$options$' ] = {}
					for opt in module.get_options( udm_object = obj ):
						props[ '$options$' ][ opt[ 'id' ] ] = opt[ 'value' ]
					props[ '$policies$' ] = {}
					for policy in obj.policies:
						pol_mod = get_module( None, policy )
						if pol_mod and pol_mod.name:
							props[ '$policies$' ][ pol_mod.name ] = policy
					props[ '$labelObjectType$' ] = module.title;
					result.append( props )
				else:
					MODULE.process( 'The LDAP object for the LDAP DN %s could not be found' % ldap_dn )
			return result
コード例 #3
0
	def process_button(self):
#		if self._first_attempt_button:
#			self._first_attempt_button = False
#			raise UMC_Error(_('First try failed. Try again.'))
		MODULE.process('Generating new secret...')
		newkey_path = "/etc/openvpn/sitetosite.newkey"
		os.popen("openvpn --genkey --secret %s" % newkey_path)
		with open(newkey_path, 'r') as newkey_file:
			newkey=newkey_file.read().replace('\n', '<br />')
		return newkey
コード例 #4
0
ファイル: __init__.py プロジェクト: B-Rich/smart
		def _send_return( thread, result, request ):
			import traceback

			if not isinstance( result, BaseException ):
				MODULE.info( 'sending mail: completed successfully' )
				self.finished( request.id, True )
			else:
				msg = '%s\n%s: %s\n' % ( ''.join( traceback.format_tb( thread.exc_info[ 2 ] ) ), thread.exc_info[ 0 ].__name__, str( thread.exc_info[ 1 ] ) )
				MODULE.process( 'sending mail:An internal error occurred: %s' % msg )
				self.finished( request.id, False, msg, False )
コード例 #5
0
ファイル: __init__.py プロジェクト: B-Rich/smart
	def _check_thread_error( self, thread, result, request ):
		"""Checks if the thread returned an exception. In that case in
		error response is send and the function returns True. Otherwise
		False is returned."""
		if not isinstance( result, BaseException ):
			return False

		msg = '%s\n%s: %s\n' % ( ''.join( traceback.format_tb( thread.exc_info[ 2 ] ) ), thread.exc_info[ 0 ].__name__, str( thread.exc_info[ 1 ] ) )
		MODULE.process( 'An internal error occurred: %s' % msg )
		self.finished( request.id, None, msg, False )
		return True
コード例 #6
0
ファイル: __init__.py プロジェクト: B-Rich/smart
		def _return( pid, status, bufstdout, bufstderr, request, fn ):
			success = True
			if status == 0:
				univention.config_registry.handler_set( [ u'connector/ad/ldap/certificate=%s' % fn ] )
				message = _( 'Certificate has been uploaded successfully.' )
				MODULE.info( 'Certificate has been uploaded successfully. status=%s\nSTDOUT:\n%s\n\nSTDERR:\n%s' % ( status, '\n'.join( bufstdout ), '\n'.join( bufstderr ) ) )
			else:
				success = False
				message = _( 'Certificate upload or conversion failed.' )
				MODULE.process( 'Certificate upload or conversion failed. status=%s\nSTDOUT:\n%s\n\nSTDERR:\n%s' % ( status, '\n'.join( bufstdout ), '\n'.join( bufstderr ) ) )

			self.finished( request.id, [ { 'success' : success, 'message' : message } ] )
コード例 #7
0
ファイル: __init__.py プロジェクト: B-Rich/smart
	def _check_thread_error( self, thread, result, request ):
		"""Checks if the thread returned an exception. In that case in
		error response is send and the function returns True. Otherwise
		False is returned."""
		if not isinstance( result, BaseException ):
			return False

		if isinstance( result, (udm_errors.ldapSizelimitExceeded, udm_errors.ldapTimeout ) ):
			self.finished( request.id, None, result.args[0], success = False, status = MODULE_ERR_COMMAND_FAILED )
			return True

		msg = '%s\n%s: %s\n' % ( ''.join( traceback.format_tb( thread.exc_info[ 2 ] ) ), thread.exc_info[ 0 ].__name__, str( thread.exc_info[ 1 ] ) )
		MODULE.process( 'An internal error occurred: %s' % msg )
		self.finished( request.id, None, msg, False )
		return True
コード例 #8
0
ファイル: __init__.py プロジェクト: B-Rich/smart
	def _copy_certificate( self, request, error_if_missing = False ):
		ssldir = '/etc/univention/ssl/%s' % request.options.get( 'LDAP_Host' )
		try:
			gid_wwwdata = grp.getgrnam('www-data')[2]
		except:
			gid_wwwdata = 0
		if os.path.exists( ssldir ):
			for fn in ( 'private.key', 'cert.pem' ):
				dst = '%s/%s' % (DIR_WEB_AD, fn)
				try:
					shutil.copy2( '%s/%s' % ( ssldir, fn ), dst )
					os.chmod( dst, 0440 )
					os.chown( dst, 0, gid_wwwdata )
				except Exception, e:
					MODULE.process( 'Copying of %s/%s to %s/%s failed (exception=%s)' % ( ssldir, fn, DIR_WEB_AD, fn, str( e.__class__ ) ) )
					raise ConnectorError(  _( 'Copying of %s/%s to %s/%s failed (exception=%s)') % ( ssldir, fn, DIR_WEB_AD, fn, e.__class__.__name__ ) )
コード例 #9
0
ファイル: __init__.py プロジェクト: B-Rich/smart
	def service( self, request ):
		MODULE.info( 'State: options=%s' % request.options )
		self.required_options( request, 'action' )

		self.__update_status()
		action = request.options[ 'action' ]

		MODULE.info( 'State: action=%s  status_running=%s' % ( action, self.status_running ) )

		success = True
		message = None
		if self.status_running and action == 'start':
			message = _( 'Active Directory Connector is already running. Nothing to do.' )
		elif not self.status_running and action == 'stop':
			message =_( 'Active Directory Connector is already stopped. Nothing to do.' )
		elif action not in ( 'start', 'stop' ):
			MODULE.process( 'State: unknown command: action=%s' % action )
			message = _( 'Unknown command ("%s") Please report error to your local administrator' ) % action
			success = False

		if message is not None:
			self.finished( request.id, { 'success' : success, 'message' : message } )
			return

		def _run_it( action ):
			return subprocess.call( ( 'invoke-rc.d', 'univention-ad-connector', action ) )

		def _return( thread, result, request ):
			success = not result
			if result:
				message = _('Switching running state of Active Directory Connector failed.')
				MODULE.info( 'Switching running state of Active Directory Connector failed. exitcode=%s' % result )
			else:
				if request.options.get( 'action' ) == 'start':
					message = _( 'UCS Active Directory Connector has been started.' )
				else:
					message = _( 'UCS Active Directory Connector has been stopped.' )

			self.finished( request.id, { 'success' : success, 'message' : message } )

		cb = notifier.Callback( _return, request )
		func = notifier.Callback( _run_it, action )
		thread = notifier.threads.Simple( 'service', func, cb )
		thread.run()
コード例 #10
0
ファイル: __init__.py プロジェクト: B-Rich/smart
		def _return( pid, status, buffer, request ):
			# dn:
			# namingContexts: DC=ad,DC=univention,DC=de
			# namingContexts: CN=Configuration,DC=ad,DC=univention,DC=de
			# namingContexts: CN=Schema,CN=Configuration,DC=ad,DC=univention,DC=de
			# namingContexts: DC=DomainDnsZones,DC=ad,DC=univention,DC=de
			# namingContexts: DC=ForestDnsZones,DC=ad,DC=univention,DC=de

			self.guessed_baseDN = None
			for line in buffer:
				if line.startswith( 'namingContexts: ' ):
					dn = line.split(': ',1)[1].strip()
					if self.guessed_baseDN is None or len( dn ) < len( self.guessed_baseDN ):
						self.guessed_baseDN = dn

			if self.guessed_baseDN is None:
				self.finished( request.id, { 'success' : False, 'message' : _('The LDAP base of the given Active Directory server could not be determined. Maybe the full-qualified hostname is wrong or unresolvable.' ) } )
				MODULE.process( 'Could not determine baseDN of given ldap server. Maybe FQDN is wrong or unresolvable! FQDN=%s' % request.options[ 'baseDN' ] )
			else:
				self.finished( request.id, { 'success' : True, 'LDAP_Base' : self.guessed_baseDN } )

			MODULE.info( 'Guessed the LDAP base: %s' % self.guessed_baseDN )
コード例 #11
0
 def info_handler(self, info):
     MODULE.process(info)
     self.info = info
コード例 #12
0
    def handle(self, msg):
        # type: (Request) -> None
        """Handles incoming UMCP requests. This function is called only
		when it is a valid UMCP request.

		:param Request msg: the received UMCP request

		The following commands are handled directly and are not passed
		to the custom module code:

		* SET (acls|username|credentials)
		* EXIT
		"""
        from ..error import UMC_Error, NotAcceptable
        self.__time_remaining = self.__timeout
        PROTOCOL.info('Received UMCP %s REQUEST %s' % (msg.command, msg.id))

        resp = Response(msg)
        resp.status = SUCCESS

        if msg.command == 'EXIT':
            shutdown_timeout = 100
            MODULE.info("EXIT: module shutdown in %dms" % shutdown_timeout)
            # shutdown module after one second
            resp.message = 'module %s will shutdown in %dms' % (
                msg.arguments[0], shutdown_timeout)
            self.response(resp)
            notifier.timer_add(shutdown_timeout, self._timed_out)
            return

        if self.__init_etype:
            notifier.timer_add(10000, self._timed_out)
            six.reraise(self.__init_etype, self.__init_exc,
                        self.__init_etraceback)

        if msg.command == 'SET':
            for key, value in msg.options.items():
                if key == 'acls':
                    self.__acls = ACLs(acls=value)
                    self.__handler.acls = self.__acls
                elif key == 'commands':
                    self.__commands.fromJSON(value['commands'])
                elif key == 'username':
                    self.__username = value
                    self.__handler.username = self.__username
                elif key == 'password':
                    self.__password = value
                    self.__handler.password = self.__password
                elif key == 'auth_type':
                    self.__auth_type = value
                    self.__handler.auth_type = self.__auth_type
                elif key == 'credentials':
                    self.__username = value['username']
                    self.__user_dn = value['user_dn']
                    self.__password = value['password']
                    self.__auth_type = value.get('auth_type')
                    self.__handler.username = self.__username
                    self.__handler.user_dn = self.__user_dn
                    self.__handler.password = self.__password
                    self.__handler.auth_type = self.__auth_type
                elif key == 'locale' and value is not None:
                    try:
                        self.__handler.update_language([value])
                    except NotAcceptable:
                        pass  # ignore if the locale doesn't exists, it continues with locale C
                else:
                    raise UMC_Error(status=422)

            # if SET command contains 'acls', commands' and
            # 'credentials' it is the initialization of the module
            # process
            if 'acls' in msg.options and 'commands' in msg.options and 'credentials' in msg.options:
                MODULE.process('Initializing module.')
                try:
                    self.__handler.init()
                except Exception:
                    try:
                        exc_info = sys.exc_info()
                        self.__init_etype, self.__init_exc, self.__init_etraceback = exc_info  # FIXME: do not keep a reference to traceback
                        self.error_handling(msg, 'init', *exc_info)
                    finally:
                        exc_info = None
                    return

            self.response(resp)
            return

        if msg.arguments:
            cmd = msg.arguments[0]
            cmd_obj = self.command_get(cmd)
            if cmd_obj and (not self.__check_acls
                            or self.__acls.is_command_allowed(
                                cmd, options=msg.options, flavor=msg.flavor)):
                self.__active_requests += 1
                self.__handler.execute(cmd_obj.method, msg)
                return
            raise UMC_Error('Not initialized.', status=403)
コード例 #13
0
	def invoke(self, request):
		# ATTENTION!!!!!!!
		# this function has to stay compatible with the very first App Center installations (Dec 2012)
		# if you add new arguments that change the behaviour
		# you should add a new method (see invoke_dry_run) or add a function name (e.g. install-schema)
		# this is necessary because newer app center may talk remotely with older one
		#   that does not understand new arguments and behaves the old way (in case of
		#   dry_run: install application although they were asked to dry_run)
		host = request.options.get('host')
		function = request.options.get('function')
		send_as = function
		if function.startswith('install'):
			function = 'install'
		if function.startswith('update'):
			function = 'update'

		application_id = request.options.get('application')
		Application.all(only_local=True)  # if not yet cached, cache. but use only local inis
		application = Application.find(application_id)
		if application is None:
			raise umcm.UMC_Error(_('Could not find an application for %s') % (application_id,))
		force = request.options.get('force')
		only_dry_run = request.options.get('only_dry_run')
		dont_remote_install = request.options.get('dont_remote_install')
		only_master_packages = send_as.endswith('schema')
		MODULE.process('Try to %s (%s) %s on %s. Force? %r. Only master packages? %r. Prevent installation on other systems? %r. Only dry run? %r.' % (function, send_as, application_id, host, force, only_master_packages, dont_remote_install, only_dry_run))

		# REMOTE invocation!
		if host and host != self.ucr.get('hostname'):
			try:
				client = Client(host, self.username, self.password)
				result = client.umc_command('appcenter/invoke', request.options).result
			except (ConnectionError, HTTPError) as exc:
				MODULE.error('Error during remote appcenter/invoke: %s' % (exc,))
				result = {
					'unreachable': [host],
					'master_unreachable': True,
					'serious_problems': True,
					'software_changes_computed': True,  # not really...
				}
			else:
				if result['can_continue']:
					def _thread_remote(_client, _package_manager):
						with _package_manager.locked(reset_status=True, set_finished=True):
							_package_manager.unlock()   # not really locked locally, but busy, so "with locked()" is appropriate
							Application._query_remote_progress(_client, _package_manager)

					def _finished_remote(thread, result):
						if isinstance(result, BaseException):
							MODULE.warn('Exception during %s %s: %s' % (function, application_id, str(result)))
					thread = notifier.threads.Simple('invoke', notifier.Callback(_thread_remote, client, self.package_manager), _finished_remote)
					thread.run()
			self.finished(request.id, result)
			return

		# make sure that the application can be installed/updated
		can_continue = True
		delayed_can_continue = True
		serious_problems = False
		result = {
			'install': [],
			'remove': [],
			'broken': [],
			'unreachable': [],
			'master_unreachable': False,
			'serious_problems': False,
			'hosts_info': {},
			'problems_with_hosts': False,
			'serious_problems_with_hosts': False,
			'invokation_forbidden_details': {},
			'invokation_warning_details': {},
			'software_changes_computed': False,
		}
		if not application:
			MODULE.process('Application not found: %s' % application_id)
			can_continue = False
		if can_continue and not only_master_packages:
			forbidden, warnings = application.check_invokation(function, self.package_manager)
			if forbidden:
				MODULE.process('Cannot %s %s: %r' % (function, application_id, forbidden))
				result['invokation_forbidden_details'] = forbidden
				can_continue = False
				serious_problems = True
			if warnings:
				MODULE.process('Warning trying to %s %s: %r' % (function, application_id, forbidden))
				result['invokation_warning_details'] = warnings
				if not force:
					# dont stop "immediately".
					#   compute the package changes!
					delayed_can_continue = False
		result['serious_problems'] = serious_problems
		result['can_continue'] = can_continue
		try:
			if can_continue:
				if self._working():
					# make it multi-tab safe (same session many buttons to be clicked)
					raise LockError()
				with self.package_manager.locked(reset_status=True):
					previously_registered_by_dry_run = False
					if can_continue and function in ('install', 'update'):
						remove_component = only_dry_run
						dry_run_result, previously_registered_by_dry_run = application.install_dry_run(self.package_manager, self.component_manager, remove_component=remove_component, username=self._username, password=self.password, only_master_packages=only_master_packages, dont_remote_install=dont_remote_install, function=function, force=force)
						result.update(dry_run_result)
						result['software_changes_computed'] = True
						serious_problems = bool(result['broken'] or result['master_unreachable'] or result['serious_problems_with_hosts'])
						if serious_problems or (not force and (result['unreachable'] or result['install'] or result['remove'] or result['problems_with_hosts'])):
							MODULE.process('Problems encountered or confirmation required. Removing component %s' % application.component_id)
							if not remove_component:
								# component was not removed automatically after dry_run
								if application.candidate:
									# operation on candidate failed. re-register original application
									application.register(self.component_manager, self.package_manager)
								else:
									# operation on self failed. unregister all
									application.unregister_all_and_register(None, self.component_manager, self.package_manager)
							can_continue = False
					elif can_continue and function in ('uninstall',) and not force:
						result['remove'] = application.uninstall_dry_run(self.package_manager)
						result['software_changes_computed'] = True
						can_continue = False
					can_continue = can_continue and delayed_can_continue and not only_dry_run
					result['serious_problems'] = serious_problems
					result['can_continue'] = can_continue

					if can_continue and not only_dry_run:
						def _thread(module, application, function):
							with module.package_manager.locked(set_finished=True):
								with module.package_manager.no_umc_restart(exclude_apache=True):
									if function in ('install', 'update'):
										# dont have to add component: already added during dry_run
										return application.install(module.package_manager, module.component_manager, add_component=only_master_packages, send_as=send_as, username=self._username, password=self.password, only_master_packages=only_master_packages, dont_remote_install=dont_remote_install, previously_registered_by_dry_run=previously_registered_by_dry_run)
									else:
										return application.uninstall(module.package_manager, module.component_manager, self._username, self.password)

						def _finished(thread, result):
							if isinstance(result, BaseException):
								MODULE.warn('Exception during %s %s: %s' % (function, application_id, str(result)))
						thread = notifier.threads.Simple('invoke', notifier.Callback(_thread, self, application, function), _finished)
						thread.run()
					else:
						self.package_manager.set_finished()  # nothing to do, ready to take new commands
			self.finished(request.id, result)
		except LockError:
			# make it thread safe: another process started a package manager
			# this module instance already has a running package manager
			raise umcm.UMC_Error(_('Another package operation is in progress'))
コード例 #14
0
    def __error_handling(self, request, method, etype, exc, etraceback):
        """
		Handle UMC exception.

		As requests are processes by python-notifier in a separate thread, any exception only contains the traceback relative to the notifier thread.
		To make them more usable we want to combine them with the calling part to get a complete stack trace.
		This is complicated by the fact that python-notifier no longer stores the original traceback, as this creates a memory leak.
		Instead only the rendered traceback is stored.

		:param request: The original UMC request.
		:param method: The failed UMC command.
		:param etype: The exception class.
		:param exc: The exception instance.
		:param etraceback: The exception traceback instance; may be None.
		"""
        message = ''
        result = None
        headers = None
        error = None
        trace = etraceback or []
        if isinstance(etraceback, list):
            etraceback = None
        try:
            try:
                self.error_handling(etype, exc, etraceback)
            except:
                raise
            else:
                six.reraise(etype, exc, etraceback)
        except UMC_Error as exc:
            status = exc.status
            result = exc.result
            headers = exc.headers
            message = str(exc)
            if not exc.traceback and exc.include_traceback:
                exc.traceback = traceback.format_exc()
                if isinstance(exc.traceback, bytes):  # Python 2
                    exc.traceback = exc.traceback.decode('utf-8', 'replace')
            error = {
                'command': method,
                'traceback': exc.traceback,
            }
        except:
            status = MODULE_ERR_COMMAND_FAILED
            if etraceback is None:  # Bug #47114: thread.exc_info doesn't contain a traceback object anymore
                tb_str = ''.join(trace + traceback.format_exception_only(
                    *sys.exc_info()[:2]))
            else:
                tb_str = traceback.format_exc()
            if isinstance(tb_str, bytes):  # Python 2
                tb_str = tb_str.decode('utf-8', 'replace')
            error = {
                'command':
                ('%s %s' %
                 (' '.join(request.arguments), '(%s)' %
                  (request.flavor, ) if request.flavor else '')).strip(),
                'traceback':
                tb_str,
            }
            if isinstance(error['command'], bytes):  # Python 2
                error['command'] = error['command'].decode('utf-8', 'replace')
            message = self._(
                'Internal server error during "%(command)s".') % error
        MODULE.process(str(message))
        self.finished(request.id,
                      result,
                      message,
                      status=status,
                      headers=headers,
                      error=error)
コード例 #15
0
			def _step_handler(step):
				MODULE.process('Package manager progress: %.1f' % step)
				progress.current = (step / 100.0) * _nsteps + _step_offset
コード例 #16
0
	def admember_join(self, username, password, ad_server_address, progress):
		progress.title = _('Joining UCS into Active Directory domain')
		progress.total = 100.0
		progress.warnings = []
		overall_success = False
		MODULE.process(progress.title)

		def _progress(steps, msg):
			progress.current = float(steps)
			progress.message = msg
			MODULE.process(msg)
			time.sleep(0.2)

		def _err(exc=None, msg=None):

			exc_str = ''
			if exc is not None:
				exc_str = str(exc) or exc.__doc__  # if no message, take the doc string
				exc_class_name = exc.__class__.__name__
				MODULE.error('Join process failed [%s]: %s' % (exc_class_name, exc_str))

			if msg:
				MODULE.error(msg)
			else:
				msg = _('An unexpected error occurred: %s') % exc_str

			progress.finish_with_result({
				'success': False,
				'error': msg,
				'warnings': progress.warnings,
			})

		ad_domain_info = {}
		try:
			admember.check_server_role()
			ad_domain_info = admember.lookup_adds_dc(ad_server_address)
			ad_server_ip = ad_domain_info['DC IP']

			_progress(5, _('Configuring time synchronization...'))
			admember.time_sync(ad_server_ip)
			admember.set_timeserver(ad_server_ip)

			_progress(10, _('Configuring DNS server...'))
			admember.set_nameserver([ad_server_ip])
			admember.prepare_ucr_settings()

			_progress(15, _('Configuring Kerberos settings...'))
			admember.disable_local_heimdal()
			admember.disable_local_samba4()

			_progress(20, _('Configuring reverse DNS settings...'))
			admember.prepare_dns_reverse_settings(ad_domain_info)

			_progress(25, _('Configuring software components...'))

			_step_offset = 30.0
			_nsteps = 35.0

			def _step_handler(step):
				MODULE.process('Package manager progress: %.1f' % step)
				progress.current = (step / 100.0) * _nsteps + _step_offset

			def _err_handler(err):
				MODULE.warn(err)
				progress.warnings.append(err)

			success = admember.remove_install_univention_samba(info_handler=MODULE.process, error_handler=_err_handler, step_handler=_step_handler)
			if not success:
				raise RuntimeError(_('An error occurred while installing necessary software components.'))

			_progress(65, _('Configuring synchronization from AD...'))
			admember.prepare_connector_settings(username, password, ad_domain_info)
			admember.disable_ssl()

			_progress(70, _('Renaming well known SID objects...'))
			admember.rename_well_known_sid_objects(username, password)

			_progress(75, _('Configuring Administrator account...'))
			admember.prepare_administrator(username, password)

			_progress(80, _('Running Samba join script...'))
			admember.run_samba_join_script(username, password)

			_progress(85, _('Configuring DNS entries...'))
			admember.add_domaincontroller_srv_record_in_ad(ad_server_ip, username, password)
			admember.add_host_record_in_ad(uid=username, bindpw=password, sso=True)

			admember.make_deleted_objects_readable_for_this_machine(username, password)
			admember.synchronize_account_position(ad_domain_info, username, password)

			_progress(90, _('Starting Active Directory connection service...'))
			admember.start_service('univention-ad-connector')

			_progress(95, _('Registering LDAP service entry...'))
			admember.add_admember_service_to_localhost()

			overall_success = True
			_progress(100, _('Join has been finished successfully.'))

		# error handling...
		except admember.invalidUCSServerRole as exc:
			_err(exc, _('The AD member mode can only be configured on a DC master server.'))
		except admember.failedADConnect as exc:
			_err(exc, _('Could not connect to AD Server %s. Please verify that the specified address is correct. (%s)') % (ad_domain_info.get('DC DNS Name'), "admember_join: %s" % (exc,)))
		except admember.domainnameMismatch as exc:
			_err(exc, _('The domain name of the AD Server (%(ad_domain)s) does not match the local UCS domain name (%(ucs_domain)s). For the AD member mode, it is necessary to setup a UCS system with the same domain name as the AD Server.') % {'ad_domain': ad_domain_info["Domain"], 'ucs_domain': ucr['domainname']})
		except admember.connectionFailed as exc:
			_err(exc, _('Could not connect to AD Server %s. Please verify that username and password are correct.') % ad_domain_info.get('DC DNS Name'))
		except admember.failedToSetAdministratorPassword as exc:
			_err(exc, _('Failed to set the password of the UCS Administrator to the Active Directory Administrator password.'))
		except admember.timeSyncronizationFailed as exc:
			_err(exc, _('Could not synchronize the time between the UCS system and the Active Directory domain controller: %s') % exc)
		except RuntimeError as exc:
			_err(exc)
		except Exception as exc:
			# catch all other errors that are unlikely to occur
			_err(exc)
			MODULE.error('Traceback:\n%s' % traceback.format_exc())

		if not overall_success:
			_progress(100, _('Join has been finished with errors.'))
			admember.revert_ucr_settings()
			admember.revert_connector_settings()

		if hasattr(progress, 'result'):
			# some error probably occurred -> return the result in the progress
			return progress.result

		return {'success': success}
コード例 #17
0
    def _install_dry_run_remote(self, app, function, dont_remote_install,
                                force):
        MODULE.process('Invoke install_dry_run_remote')
        self.ucr.load()
        if function.startswith('upgrade'):
            remote_function = 'update-schema'
        else:
            remote_function = 'install-schema'

        master_packages = app.default_packages_master

        # connect to Primary/Backup Nodes
        unreachable = []
        hosts_info = {}
        remote_info = {
            'master_unreachable': False,
            'problems_with_hosts': False,
            'serious_problems_with_hosts': False,
        }
        dry_run_threads = []
        info = get_action('info')
        if master_packages and not dont_remote_install:
            hosts = find_hosts_for_master_packages()

            # checking remote host is I/O heavy, so use threads
            #   "global" variables: unreachable, hosts_info, remote_info

            def _check_remote_host(app_id, host, host_is_master, username,
                                   password, force, remote_function):
                MODULE.process('Starting dry_run for %s on %s' %
                               (app_id, host))
                MODULE.process('%s: Connecting...' % host)
                try:
                    client = Client(host, username, password)
                except (ConnectionError, HTTPError) as exc:
                    MODULE.warn('_check_remote_host: %s: %s' % (host, exc))
                    unreachable.append(host)
                    if host_is_master:
                        remote_info['master_unreachable'] = True
                else:
                    MODULE.process('%s: ... done' % host)
                    host_info = {}
                    MODULE.process('%s: Getting version...' % host)
                    try:
                        host_version = client.umc_command(
                            'appcenter/version', {
                                'version': info.get_compatibility()
                            }).result
                    except Forbidden:
                        # command is not yet known (older app center)
                        MODULE.process('%s: ... forbidden!' % host)
                        host_version = None
                    except (ConnectionError, HTTPError) as exc:
                        MODULE.warn('%s: Could not get appcenter/version: %s' %
                                    (host, exc))
                        raise
                    except Exception as exc:
                        MODULE.error('%s: Exception: %s' % (host, exc))
                        raise
                    MODULE.process('%s: ... done' % host)
                    host_info['compatible_version'] = info.is_compatible(
                        host_version)
                    MODULE.process('%s: Invoking %s ...' %
                                   (host, remote_function))
                    try:
                        host_info['result'] = client.umc_command(
                            'appcenter/invoke_dry_run', {
                                'function': remote_function,
                                'application': app_id,
                                'force': force,
                                'dont_remote_install': True,
                            }).result
                    except Forbidden:
                        # command is not yet known (older app center)
                        MODULE.process('%s: ... forbidden!' % host)
                        host_info['result'] = {
                            'can_continue': False,
                            'serious_problems': False
                        }
                    except (ConnectionError, HTTPError) as exc:
                        MODULE.warn('Could not get appcenter/version: %s' %
                                    (exc, ))
                        raise
                    MODULE.process('%s: ... done' % host)
                    if not host_info['compatible_version'] or not host_info[
                            'result']['can_continue']:
                        remote_info['problems_with_hosts'] = True
                        if host_info['result'][
                                'serious_problems'] or not host_info[
                                    'compatible_version']:
                            remote_info['serious_problems_with_hosts'] = True
                    hosts_info[host] = host_info
                MODULE.process('Finished dry_run for %s on %s' %
                               (app_id, host))

            for host, host_is_master in hosts:
                thread = Thread(target=_check_remote_host,
                                args=(app.id, host, host_is_master,
                                      self.username, self.password, force,
                                      remote_function))
                thread.start()
                dry_run_threads.append(thread)

        result = {}

        for thread in dry_run_threads:
            thread.join()
        MODULE.process('All %d threads finished' % (len(dry_run_threads)))

        result['unreachable'] = unreachable
        result['hosts_info'] = hosts_info
        result.update(remote_info)
        return result
コード例 #18
0
 def info_handler(self, info: str) -> None:
     MODULE.process(info)
     self.info = info
コード例 #19
0
ファイル: __init__.py プロジェクト: spaceone/ucs-school
        def _thread():
            # perform all actions inside a thread...
            # collect files
            progress.component(_('Collecting exam files...'))
            if project:
                project.collect()
            progress.add_steps(10)

            # open a new connection to the master UMC
            master = ucr['ldap/master']
            try:
                client = Client(master)
                client.authenticate_with_machine_account()
            except (ConnectionError, HTTPError) as exc:
                MODULE.error('Could not connect to UMC on %s: %s' %
                             (master, exc))
                raise UMC_Error(
                    _('Could not connect to master server %s.') % (master, ))

            school = SchoolSearchBase.getOU(request.options['room'])

            # unset exam mode for the given computer room
            progress.component(_('Configuring the computer room...'))
            client.umc_command(
                'schoolexam-master/unset-computerroom-exammode',
                dict(
                    roomdn=request.options['room'],
                    school=school,
                )).result
            progress.add_steps(5)

            # delete exam users accounts
            if project:
                # get a list of user accounts in parallel exams
                parallelUsers = dict([
                    (iuser.username, iproject.description)
                    for iproject in util.distribution.Project.list()
                    if iproject.name != project.name
                    for iuser in iproject.recipients
                ])

                progress.component(_('Removing exam accounts'))
                percentPerUser = 25.0 / (1 + len(project.recipients))
                for iuser in project.recipients:
                    progress.info(
                        '%s, %s (%s)' %
                        (iuser.lastname, iuser.firstname, iuser.username))
                    try:
                        if iuser.username not in parallelUsers:
                            # remove first the home directory
                            shutil.rmtree(iuser.unixhome, ignore_errors=True)

                            # remove LDAP user entry
                            client.umc_command(
                                'schoolexam-master/remove-exam-user',
                                dict(
                                    userdn=iuser.dn,
                                    school=school,
                                )).result
                            MODULE.info('Exam user has been removed: %s' %
                                        iuser.dn)
                        else:
                            MODULE.process(
                                'Cannot remove the user account %s as it is registered for the running exam "%s", as well'
                                % (iuser.dn, parallelUsers[iuser.username]))
                    except (ConnectionError, HTTPError) as e:
                        MODULE.warn(
                            'Could not remove exam user account %s: %s' %
                            (iuser.dn, e))

                    # indicate the user has been processed
                    progress.add_steps(percentPerUser)

                progress.add_steps(percentPerUser)
コード例 #20
0
def read_syntax_choices(syn, options={}, module_search_options={}, ldap_connection=None, ldap_position=None):
	syntax_name = syn.name

	choices = getattr(syn, 'choices', [])

	if issubclass(syn.__class__, udm_syntax.UDM_Objects):
		choices = []
		# try to avoid using the slow udm interface
		simple = False
		attr = set()
		if not syn.use_objects:
			attr.update(re.findall(r'%\(([^)]+)\)', syn.key))
			if syn.label:
				attr.update(re.findall(r'%\(([^)]+)\)', syn.label))
			for udm_module in syn.udm_modules:
				module = UDM_Module(udm_module)
				if not module.allows_simple_lookup():
					break
				if module is not None:
					mapping = module.module.mapping
					if not all([mapping.mapName(att) for att in attr]):
						break
			else:
				simple = True
			if not simple:
				MODULE.warn('Syntax %s wants to get optimizations but may not. This is a Bug! We provide a fallback but the syntax will respond much slower than it could!' % syntax_name)

		def extract_key_label(syn, dn, info):
			key = label = None
			if syn.key == 'dn':
				key = dn
			else:
				try:
					key = syn.key % info
				except KeyError:
					pass
			if syn.label == 'dn':
				label = dn
			elif syn.label is None:
				pass
			else:
				try:
					label = syn.label % info
				except KeyError:
					pass
			return key, label
		if not simple:
			def map_choices(obj_list):
				result = []
				for obj in obj_list:
					# first try it without obj.open() (expensive)
					key, label = extract_key_label(syn, obj.dn, obj.info)
					if key is None or label is None:
						obj.open()
						key, label = extract_key_label(syn, obj.dn, obj.info)
						if key is None:
							# ignore the entry as the key is important for a selection, there
							# is no sensible fallback for the key (Bug #26994)
							continue
						if label is None:
							# fallback to the default description as this is just what displayed
							# to the user (Bug #26994)
							label = udm_objects.description(obj)
					result.append((key, label))
				return result

			for udm_module in syn.udm_modules:
				module = UDM_Module(udm_module)
				if module.module is None:
					continue
				filter_s = _create_ldap_filter(syn, options, module)
				if filter_s is not None:
					search_options = {'filter': filter_s}
					search_options.update(module_search_options)
					choices.extend(map_choices(module.search(**search_options)))
		else:
			for udm_module in syn.udm_modules:
				module = UDM_Module(udm_module)
				if module.module is None:
					continue
				filter_s = _create_ldap_filter(syn, options, module)
				if filter_s is not None:
					if filter_s and not filter_s.startswith('('):
						filter_s = '(%s)' % filter_s
					mapping = module.module.mapping
					ldap_attr = [mapping.mapName(att) for att in attr]
					search_options = {'filter': filter_s, 'simple': True}
					search_options.update(module_search_options)
					if ldap_attr:
						search_options['simple_attrs'] = ldap_attr
						result = module.search(**search_options)
						for dn, ldap_map in result:
							info = udm_mapping.mapDict(mapping, ldap_map)
							key, label = extract_key_label(syn, dn, info)
							if key is None:
								continue
							if label is None:
								label = ldap_connection.explodeDn(dn, 1)[0]
							choices.append((key, label))
					else:
						keys = module.search(**search_options)
						if syn.label == 'dn':
							labels = keys
						else:
							labels = [ldap_connection.explodeDn(dn, 1)[0] for dn in keys]
						choices.extend(zip(keys, labels))
	elif issubclass(syn.__class__, udm_syntax.UDM_Attribute):
		choices = []

		def filter_choice(obj):
			# if attributes does not exist or is empty
			return syn.attribute in obj.info and obj.info[syn.attribute]

		def map_choice(obj):
			obj.open()
			MODULE.info('Loading choices from %s: %s' % (obj.dn, obj.info))
			try:
				values = obj.info[syn.attribute]
			except KeyError:
				MODULE.warn('Object has no attribute %r' % (syn.attribute,))
				# this happens for example in PrinterDriverList
				# if the ldap schema is not installed
				# and thus no 'printmodel' attribute is known.
				return []
			if not isinstance(values, (list, tuple)):  # single value
				values = [values]
			if syn.is_complex:
				return [(x[syn.key_index], x[syn.label_index]) for x in values]
			if syn.label_format is not None:
				_choices = []
				for value in values:
					obj.info['$attribute$'] = value
					_choices.append((value, syn.label_format % obj.info))
				return _choices
			return [(x, x) for x in values]

		module = UDM_Module(syn.udm_module)
		if module.module is None:
			return []
		MODULE.info('Found syntax %s with udm_module property' % syntax_name)
		if syn.udm_filter == 'dn':
			choices = map_choice(module.get(options[syn.depends]))
		else:
			filter_s = _create_ldap_filter(syn, options, module)
			if filter_s is not None:
				for element in map(map_choice, filter(filter_choice, module.search(filter=filter_s))):
					for item in element:
						choices.append(item)
	elif issubclass(syn.__class__, udm_syntax.ldapDn) and hasattr(syn, 'searchFilter'):
		try:
			result = ldap_connection.searchDn(filter=syn.searchFilter)
		except udm_errors.base:
			MODULE.process('Failed to initialize syntax class %s' % syntax_name)
			return []
		choices = []
		for dn in result:
			dn_list = ldap_connection.explodeDn(dn)
			choices.append((dn, dn_list[0].split('=', 1)[1]))

	choices = [{'id': x[0], 'label': x[1]} for x in choices]

	if issubclass(syn.__class__, udm_syntax.LDAP_Search):
		options = options.get('options', {})
		try:
			syntax = udm_syntax.LDAP_Search(options['syntax'], options['filter'], options['attributes'], options['base'], options['value'], options['viewonly'], options['empty'], options['empty_end'])
		except KeyError:
			syntax = syn

		if '$dn$' in options:
			filter_mod = get_module(None, options['$dn$'])
			if filter_mod:
				obj = filter_mod.get(options['$dn$'])
				syntax.filter = udm.pattern_replace(syntax.filter, obj)

		syntax._prepare(ldap_connection, syntax.filter)

		choices = []
		for item in syntax.values:
			if syntax.viewonly:
				dn, display_attr = item
			else:
				dn, store_pattern, display_attr = item

			if display_attr:
				# currently we just support one display attribute
				mod_display, display = split_module_attr(display_attr[0])
				module = get_module(mod_display, dn)  # mod_display might be None
			else:
				module = get_module(None, dn)
				display = None
			if not module:
				continue
			obj = module.get(dn)
			if not obj:
				continue

			# find the value to store
			if not syntax.viewonly:
				mod_store, store = split_module_attr(store_pattern)
				if store == 'dn':
					id = dn
				elif store in obj:
					id = obj[store]
				elif store in obj.oldattr and obj.oldattr[store]:
					id = obj.oldattr[store][0]
				else:
					# no valid store object, ignore
					MODULE.warn('LDAP_Search syntax %r: %r is no valid property for object %r - ignoring entry.' % (syntax.name, store, dn))
					continue

			# find the value to display
			if display == 'dn':
				label = dn
			elif display is None:  # if view-only and in case of error
				label = '%s: %s' % (module.title, obj[module.identifies])
			else:
				if display in obj:
					label = obj[display]
				elif display in obj.oldattr and obj.oldattr[display]:
					label = obj.oldattr[display][0]
				else:
					label = 'Unknown attribute %s' % display

			# create list entry
			if syntax.viewonly:
				choices.append({'module': 'udm', 'flavor': module.flavor or 'navigation', 'objectType': module.name, 'id': dn, 'label': label, 'icon': 'udm-%s' % module.name.replace('/', '-')})
			else:
				choices.append({'module': 'udm', 'flavor': module.flavor or 'navigation', 'objectType': module.name, 'id': id, 'label': label, 'icon': 'udm-%s' % module.name.replace('/', '-')})

	# sort choices before inserting / appending some special items
	choices = sorted(choices, key=lambda choice: choice['label'])

	if issubclass(syn.__class__, (udm_syntax.UDM_Objects, udm_syntax.UDM_Attribute)):
		if isinstance(syn.static_values, (tuple, list)):
			for value in syn.static_values:
				choices.insert(0, {'id': value[0], 'label': value[1]})
		if syn.empty_value:
			choices.insert(0, {'id': '', 'label': ''})
	elif issubclass(syn.__class__, udm_syntax.LDAP_Search):
		# then append empty value
		if syntax.addEmptyValue:
			choices.insert(0, {'id': '', 'label': ''})
		elif syntax.appendEmptyValue:
			choices.append({'id': '', 'label': ''})

	return choices
コード例 #21
0
	def init(self):
		self.azure_response = None
		self.adconnection_alias = ucr.get(adconnection_wizard_ucrv) or None
		MODULE.process('adconnection_alias={!r}'.format(self.adconnection_alias))
コード例 #22
0
def run(cmd,
        stepsPerScript,
        info_handler=_dummyFunc,
        error_handler=_dummyFunc,
        critical_handler=_dummyFunc,
        step_handler=_dummyFunc,
        component_handler=_dummyFunc):
    # disable UMC/apache restart
    MODULE.info('disabling UMC and apache server restart')
    subprocess.call(CMD_DISABLE_EXEC)

    try:
        # regular expressions for output parsing
        regError = re.compile('^\* Message:\s*(?P<message>.*)\s*$')
        regJoinScript = re.compile(
            '(Configure|Running)\s+(?P<script>.*)\.inst.*$')
        regInfo = re.compile('^(?P<message>.*?)\s*:?\s*\x1b.*$')

        # call to univention-join
        MODULE.info('calling "%s"' % ' '.join(cmd))
        process = subprocess.Popen(cmd,
                                   shell=False,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE)

        failedJoinScripts = []
        while True:
            # get the next line
            line = process.stdout.readline()
            if not line:
                # no more text from stdout
                break
            MODULE.process(line.strip())

            # parse output... first check for errors
            m = regError.match(line)
            if m:
                message = m.groupdict().get('message')
                error_handler(
                    _("The system join process could not be completed:<br/><br/><i>%s</i><br/><br/> More details can be found in the log file <i>/var/log/univention/join.log</i>.<br/>Please retry after resolving any conflicting issues."
                      ) % message)
                if message.startswith('ssh-login for') or message.startswith(
                        'binddn for'):
                    # invalid credentials or non existent user
                    # do a critical error, the script will stop here
                    critical_handler(True)

                continue

            # check for currently called join script
            m = regJoinScript.match(line)
            if m:
                component_handler(_('Executing join scripts'))
                info_handler(
                    _('Executing join script %s') %
                    m.groupdict().get('script'))
                step_handler(stepsPerScript)
                if 'failed' in line:
                    failedJoinScripts.append(m.groupdict().get('script'))
                continue

            # check for other information
            m = regInfo.match(line)
            if m:
                info_handler(m.groupdict().get('message'))
                step_handler(stepsPerScript / 10)
                continue

        # get all remaining output
        stdout, stderr = process.communicate()
        if stderr:
            # write stderr into the log file
            MODULE.warn('stderr: %s' % stderr)

        success = True
        # check for errors
        if process.returncode != 0:
            # error case
            MODULE.warn('Could not perform system join: %s%s' %
                        (stdout, stderr))
            success = False
        elif failedJoinScripts:
            MODULE.warn(
                'The following join scripts could not be executed: %s' %
                failedJoinScripts)
            error_handler(
                _('Some join scripts could not be executed. More details can be found in the log file <i>/var/log/univention/join.log</i>.<br/>Please retry to execute the join scripts after resolving any conflicting issues.'
                  ))

            success = False
        return success
    finally:
        # make sure that UMC servers and apache can be restarted again
        MODULE.info('enabling UMC and apache server restart')
        subprocess.call(CMD_ENABLE_EXEC)
コード例 #23
0
class Instance(Base, ProgressMixin):
	OPTION_MAPPING = (
		('LDAP_Host', 'connector/ad/ldap/host', ''),
		('LDAP_Base', 'connector/ad/ldap/base', ''),
		('LDAP_BindDN', 'connector/ad/ldap/binddn', ''),
		('KerberosDomain', 'connector/ad/mapping/kerberosdomain', ''),
		('PollSleep', 'connector/ad/poll/sleep', 5),
		('RetryRejected', 'connector/ad/retryrejected', 10),
		('DebugLevel', 'connector/debug/level', 2),
		('DebugFunction', 'connector/debug/function', False),
		('MappingSyncMode', 'connector/ad/mapping/syncmode', 'sync'),
		('MappingGroupLanguage', 'connector/ad/mapping/group/language', 'de')
	)

	def init(self):
		self.__update_status()

	def state(self, request):
		"""Retrieve current status of the Active Directory connection configuration and the service

		options: {}

		return: { 'configured' : (True|False), 'certificate' : (True|False), 'running' : (True|False) }
		"""

		self.__update_status()
		self.finished(request.id, {
			'ssl_enabled': self.status_ssl,
			'password_sync_enabled': self.status_password_sync,
			'running': self.status_running,
			'certificate': self.status_certificate,
			'mode_admember': self.status_mode_admember,
			'mode_adconnector': self.status_mode_adconnector,
			'configured': self.status_mode_adconnector or self.status_mode_admember,
			'server_role': ucr.get('server/role'),
		})

	def load(self, request):
		"""Retrieve current status of the Active Directory connection configuration and the service

		options: {}

		return: { <all AD connector UCR variables> }
		"""

		result = {}
		for option, var, default in Instance.OPTION_MAPPING:
			result[option] = ucr.get(var, default)

		pwd_file = ucr.get('connector/ad/ldap/bindpw')
		result['passwordExists'] = bool(pwd_file and os.path.exists(pwd_file))

		self.finished(request.id, result)

	@sanitize(LDAP_Host=StringSanitizer(required=True))
	def adconnector_save(self, request):
		"""Saves the Active Directory connection configuration

		options:
			Host_IP: IP address of the AD server
			LDAP_Host: hostname of the AD server
			LDAP_Base: LDAP base of the AD server
			LDAP_BindDN: LDAP DN to use for authentication
			KerberosDomain: kerberos domain
			PollSleep: time in seconds between polls
			RetryRejected: how many time to retry a synchronisation
			MappingSyncMode: synchronisation mode
			MappingGroupLanguage: language of the AD server

		return: { 'success' : (True|False), 'message' : <details> }
		"""

		self.required_options(request, 'Host_IP')
		self.required_options(request, *[x[0] for x in Instance.OPTION_MAPPING if x[2] == ''])

		for umckey, ucrkey, default in Instance.OPTION_MAPPING:
			val = request.options.get(umckey, default)
			if val:
				if isinstance(val, bool):
					val = val and 'yes' or 'no'
				MODULE.info('Setting %s=%s' % (ucrkey, val))
				univention.config_registry.handler_set([u'%s=%s' % (ucrkey, val)])

		ucr.load()
		if ucr.get('connector/ad/ldap/ldaps'):
			MODULE.info('Unsetting connector/ad/ldap/ldaps')
			univention.config_registry.handler_unset([u'connector/ad/ldap/ldaps'])
		if ucr.get('connector/ad/ldap/port') == '636':
			MODULE.info('Setting ldap port to 389')
			univention.config_registry.handler_set([u'connector/ad/ldap/port=389'])

		if not request.options.get('LDAP_Password') in (None, '', DO_NOT_CHANGE_PWD):
			fn = ucr.get('connector/ad/ldap/bindpw', FN_BINDPW)
			try:
				fd = open(fn, 'w')
				fd.write(request.options.get('LDAP_Password'))
				fd.close()
				os.chmod(fn, 0600)
				os.chown(fn, 0, 0)
				univention.config_registry.handler_set([u'connector/ad/ldap/bindpw=%s' % fn])
			except Exception, e:
				MODULE.info('Saving bind password failed (filename=%(fn)s ; exception=%(exception)s)' % {'fn': fn, 'exception': str(e.__class__)})
				self.finished(request.id, {'success': False, 'message': _('Saving bind password failed (filename=%(fn)s ; exception=%(exception)s)') % {'fn': fn, 'exception': str(e.__class__)}})
				return

		ssldir = '/etc/univention/ssl/%s' % request.options.get('LDAP_Host')
		if not os.path.exists(ssldir):
			self._create_certificate(request)
			return

		# enter a static host entry such that the AD server's FQDN can be resolved
		univention.config_registry.handler_set([u'hosts/static/%(Host_IP)s=%(LDAP_Host)s' % request.options])

		# check for SSL support on AD side
		if admember.server_supports_ssl(server=request.options.get('LDAP_Host')):
			MODULE.process('Enabling SSL...')
			admember.enable_ssl()
		else:
			MODULE.warn('SSL is not supported')
			admember.disable_ssl()

		# UCR variables are set, and now we can try to guess the language of
		# the AD domain
		ad_lang = guess_ad_domain_language()
		univention.config_registry.handler_set([u'connector/ad/mapping/group/language=%s' % ad_lang])

		self.finished(request.id, {'success': True, 'message': _('Active Directory connection settings have been saved.')})
コード例 #24
0
ファイル: __init__.py プロジェクト: spaceone/ucs-school
    def save_csv(self, request):
        result = {}
        file_id = generate_random()
        school = request.body['school']
        user_type = request.body['type']
        delete_not_mentioned = bool(request.body.get('delete_not_mentioned'))
        user_klass = None
        if user_type == 'student':
            user_klass = CSVStudent
        elif user_type == 'teacher':
            user_klass = CSVTeacher
        elif user_type == 'staff':
            user_klass = CSVStaff
        elif user_type == 'teachersAndStaff':
            user_klass = CSVTeachersAndStaff
        filename = request.options[0]['tmpfile']
        MODULE.process('Processing %s' % filename)
        sniffer = csv.Sniffer()
        with open(filename, 'rb') as f:
            content = f.read()
            # try utf-8 and latin-1
            # if this still fails -> traceback...
            try:
                content = content.decode('utf-8')
            except UnicodeDecodeError:
                content = content.decode('latin-1')
            lines = content.splitlines()
        try:
            first_line = ''
            if lines:
                first_line = lines[0].strip()
                try:
                    MODULE.process('First line is:\n%s' % first_line)
                except TypeError:
                    MODULE.error(
                        'First line is not printable! Wrong CSV format!')
            try:
                # be strict regarding delimiters. I have seen the
                # sniffer returning 'b' as the delimiter in some cases
                dialect = sniffer.sniff(str(content), delimiters=' ,;\t')
                dialect.strict = True
            except csv.Error:
                # Something went wrong. But the sniffer is not exact
                # try it again the hard way: delimiter=, quotechar="
                MODULE.warn(
                    'Error while sniffing csv dialect... fallback to excel')
                dialect = csv.get_dialect('excel')

            # Is the first line the header or already a user?
            # sniffer.has_header(content)
            # is not very acurate. We know how a header looks like...
            has_header = user_klass.is_header(first_line, dialect)
            if has_header:
                MODULE.process('Seems to be a header...')

            num_lines = 0
            with open(filename, 'wb') as f:
                reader = csv.reader(lines, dialect)
                writer = csv.writer(f, dialect)
                csv_columns = []  # Benutzername,Vorname,Irgendwas
                columns = []  # name,firstname,unused2
                first_lines = []
                for line in reader:
                    line = [cell.strip() for cell in line]
                    if not any(line):
                        # empty line
                        continue
                    writer.writerow(line)
                    if not csv_columns:
                        if has_header:
                            csv_columns = line
                            continue
                        else:
                            csv_columns = [
                                'unused%d' % x for x in range(len(line))
                            ]
                    if len(first_lines) < 10:
                        first_lines.append(line)
                    num_lines += 1
                if num_lines == 0:
                    raise csv.Error('Empty!')
                for i, column in enumerate(csv_columns):
                    column_name = user_klass.find_field_name_from_label(
                        column, i)
                    if column_name in columns:
                        column_name = 'unused%d' % i
                    columns.append(column_name)
                MODULE.process('First line translates to columns: %r' %
                               columns)
        except csv.Error as exc:
            MODULE.warn('Malformatted CSV file? %s' % exc)
            result['success'] = False
            # result['message'] = ''
            self.finished(request.id, [result])
        else:
            self.file_map[file_id] = FileInfo(filename, school, user_klass,
                                              dialect, has_header,
                                              delete_not_mentioned)
            result['success'] = True
            result['filename'] = filename
            result['file_id'] = file_id
            result['available_columns'] = user_klass.get_columns_for_assign()
            result['given_columns'] = columns
            result['first_lines'] = first_lines
            result['num_more_lines'] = num_lines - len(first_lines)
            self.finished(request.id, [result])
コード例 #25
0
		def _progress(steps, msg):
			progress.current = float(steps)
			progress.message = msg
			MODULE.process(msg)
			time.sleep(0.2)
コード例 #26
0
def get_master(lo):
    MODULE.process('Searching DC Master')
    return get_hosts(domaincontroller_master, lo)[0].info['fqdn']
コード例 #27
0
    def put(self,
            request,
            ldap_machine_write=None,
            ldap_user_read=None,
            ldap_position=None):
        """Returns the objects for the given IDs

		requests.options = [ { object : ..., options : ... }, ... ]

		return: True|<error message>
		"""

        if request.flavor == 'teacher':
            request.options = request.options[0]['object']
            return self.add_teacher_to_classes(request)

        klass = get_group_class(request)
        for group_from_umc in request.options:
            group_from_umc = group_from_umc['object']
            group_from_umc_dn = group_from_umc['$dn$']
            break

        try:
            group_from_ldap = klass.from_dn(group_from_umc_dn, None,
                                            ldap_machine_write)
        except udm_exceptions.noObject:
            raise UMC_Error('unknown group object')

        old_members = self._filter_members(request, group_from_ldap,
                                           group_from_ldap.users,
                                           ldap_user_read)
        removed_members = set(o['id'] for o in old_members) - set(
            group_from_umc['members'])

        MODULE.info('Modifying group "%s" with members: %s' %
                    (group_from_ldap.dn, group_from_ldap.users))
        MODULE.info('New members: %s' % group_from_umc['members'])
        MODULE.info('Removed members: %s' % (removed_members, ))

        if request.flavor == 'workgroup-admin':
            # do not allow groups to be renamed in order to avoid conflicts with shares
            # grp.name = '%(school)s-%(name)s' % group
            group_from_ldap.description = group_from_umc['description']

        # Workgroup admin view → update teachers, admins, students, (staff)
        # Class view → update only the group's teachers (keep all non teachers)
        # Workgroup teacher view → update only the group's students

        users = []
        # keep specific users from the group
        for userdn in group_from_ldap.users:
            try:
                user = User.from_dn(userdn, None, ldap_machine_write)
            except udm_exceptions.noObject:  # no permissions/is not a user/does not exists → keep the old value
                users.append(userdn)
                continue
            if not user.schools or not set(user.schools) & set(
                [group_from_ldap.school]):
                users.append(userdn)
                continue
            if (request.flavor == 'class'
                    and not user.is_teacher(ldap_machine_write)) or (
                        request.flavor == 'workgroup'
                        and not user.is_student(ldap_machine_write)
                    ) or request.flavor == 'workgroup-admin':
                users.append(userdn)

        # add only certain users to the group
        for userdn in group_from_umc['members']:
            try:
                user = User.from_dn(userdn, None, ldap_machine_write)
            except udm_exceptions.noObject as exc:
                MODULE.error('Not adding not existing user %r to group: %r.' %
                             (userdn, exc))
                continue
            if not user.schools or not set(user.schools) & set(
                [group_from_ldap.school]):
                raise UMC_Error(
                    _('User %s does not belong to school %r.') %
                    (Display.user(user.get_udm_object(ldap_machine_write)),
                     group_from_ldap.school))
            if request.flavor == 'workgroup-admin' and not user.is_student(
                    ldap_machine_write) and not user.is_administrator(
                        ldap_machine_write) and not user.is_staff(
                            ldap_machine_write) and not user.is_teacher(
                                ldap_machine_write):
                raise UMC_Error(
                    _('User %s does not belong to school %r.') %
                    (Display.user(user.get_udm_object(ldap_machine_write)),
                     group_from_ldap.school))
            if request.flavor == 'class' and not user.is_teacher(
                    ldap_machine_write):
                raise UMC_Error(
                    _('User %s is not a teacher.') %
                    (Display.user(user.get_udm_object(ldap_machine_write)), ))
            if request.flavor == 'workgroup' and not user.is_student(
                    ldap_machine_write):
                raise UMC_Error(
                    _('User %s is not a student.') %
                    (Display.user(user.get_udm_object(ldap_machine_write)), ))
            users.append(user.dn)

        group_from_ldap.users = list(set(users) - removed_members)
        try:
            success = group_from_ldap.modify(ldap_machine_write)
            MODULE.info('Modified, group has now members: %s' %
                        (group_from_ldap.users, ))
        except udm_exceptions.base as exc:
            MODULE.process('An error occurred while modifying "%s": %s' %
                           (group_from_umc['$dn$'], exc.message))
            raise UMC_Error(_('Failed to modify group (%s).') % exc.message)

        self.finished(request.id, success)
コード例 #28
0
 def user_dn(self, user_dn):
     self._user_dn = user_dn
     MODULE.process('Setting user LDAP DN %r' % (self._user_dn, ))
コード例 #29
0
 def _check_remote_host(app_id, host, host_is_master, username,
                        password, force, remote_function):
     MODULE.process('Starting dry_run for %s on %s' %
                    (app_id, host))
     MODULE.process('%s: Connecting...' % host)
     try:
         client = Client(host, username, password)
     except (ConnectionError, HTTPError) as exc:
         MODULE.warn('_check_remote_host: %s: %s' % (host, exc))
         unreachable.append(host)
         if host_is_master:
             remote_info['master_unreachable'] = True
     else:
         MODULE.process('%s: ... done' % host)
         host_info = {}
         MODULE.process('%s: Getting version...' % host)
         try:
             host_version = client.umc_command(
                 'appcenter/version', {
                     'version': info.get_compatibility()
                 }).result
         except Forbidden:
             # command is not yet known (older app center)
             MODULE.process('%s: ... forbidden!' % host)
             host_version = None
         except (ConnectionError, HTTPError) as exc:
             MODULE.warn('%s: Could not get appcenter/version: %s' %
                         (host, exc))
             raise
         except Exception as exc:
             MODULE.error('%s: Exception: %s' % (host, exc))
             raise
         MODULE.process('%s: ... done' % host)
         host_info['compatible_version'] = info.is_compatible(
             host_version)
         MODULE.process('%s: Invoking %s ...' %
                        (host, remote_function))
         try:
             host_info['result'] = client.umc_command(
                 'appcenter/invoke_dry_run', {
                     'function': remote_function,
                     'application': app_id,
                     'force': force,
                     'dont_remote_install': True,
                 }).result
         except Forbidden:
             # command is not yet known (older app center)
             MODULE.process('%s: ... forbidden!' % host)
             host_info['result'] = {
                 'can_continue': False,
                 'serious_problems': False
             }
         except (ConnectionError, HTTPError) as exc:
             MODULE.warn('Could not get appcenter/version: %s' %
                         (exc, ))
             raise
         MODULE.process('%s: ... done' % host)
         if not host_info['compatible_version'] or not host_info[
                 'result']['can_continue']:
             remote_info['problems_with_hosts'] = True
             if host_info['result'][
                     'serious_problems'] or not host_info[
                         'compatible_version']:
                 remote_info['serious_problems_with_hosts'] = True
         hosts_info[host] = host_info
     MODULE.process('Finished dry_run for %s on %s' %
                    (app_id, host))
コード例 #30
0
def system_join(username, password, info_handler, error_handler, step_handler):
	# make sure we got the correct server role
	server_role = ucr.get('server/role')
	assert server_role in ('domaincontroller_slave', 'domaincontroller_backup', 'domaincontroller_master')

	# get the number of join scripts
	n_joinscripts = len(glob.glob('/usr/lib/univention-install/*.inst'))
	steps_per_script = 100.0 / n_joinscripts

	# disable UMC/apache restart
	MODULE.info('disabling UMC and apache server restart')
	subprocess.call(CMD_DISABLE_EXEC)

	try:
		with tempfile.NamedTemporaryFile() as password_file:
			password_file.write('%s' % password)
			password_file.flush()

			# regular expressions for output parsing
			error_pattern = re.compile('^\* Message:\s*(?P<message>.*)\s*$')
			joinscript_pattern = re.compile('(Configure|Running)\s+(?P<script>.*)\.inst.*$')
			info_pattern = re.compile('^(?P<message>.*?)\s*:?\s*\x1b.*$')

			# call to univention-join
			process = None
			if server_role == 'domaincontroller_slave':
				# DC slave -> complete re-join
				MODULE.process('Performing system join...')
				process = subprocess.Popen(['/usr/sbin/univention-join', '-dcaccount', username, '-dcpwd', password_file.name], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)
			else:
				# DC backup/master -> only run join scripts
				MODULE.process('Executing join scripts ...')
				process = subprocess.Popen(['/usr/sbin/univention-run-join-scripts', '-dcaccount', username, '-dcpwd', password_file.name], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)

			failed_join_scripts = []
			executed_join_scripts = set()

			def parse(line):
				if not line.strip():
					return
				MODULE.process(repr(line.strip()).strip('"\''))

				# parse output... first check for errors
				m = error_pattern.match(line)
				if m:
					error_handler(_('Software packages have been installed, however, the system join could not be completed: %s. More details can be found in the log file /var/log/univention/join.log. Please retry the join process via the UMC module "Domain join" after resolving any conflicting issues.') % m.groupdict().get('message'))
					return

				# check for currently called join script
				m = joinscript_pattern.match(line)
				if m:
					current_script = m.groupdict().get('script')
					info_handler(_('Executing join script %s') % (current_script,))
					if current_script not in executed_join_scripts:
						executed_join_scripts.add(current_script)
						step_handler(steps_per_script)
					if 'failed' in line:
						failed_join_scripts.append(current_script)
					return

				# check for other information
				m = info_pattern.match(line)
				if m:
					info_handler(m.groupdict().get('message'))
					return

			# make stdout file descriptor of the process non-blocking
			fd = process.stdout.fileno()
			fl = fcntl.fcntl(fd, fcntl.F_GETFL)
			fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)

			unfinished_line = ''
			while True:
				try:
					fd = select.select([process.stdout], [], [])[0][0]
				except IndexError:
					continue  # not ready / no further data
				except select.error as exc:
					if exc.args[0] == errno.EINTR:
						continue
					raise
				# get the next line
				line = fd.read()

				if not line:
					break  # no more text from stdout

				unfinished_line = '' if line.endswith('\n') else '%s%s' % (unfinished_line, line.rsplit('\n', 1)[-1])
				for line in line.splitlines():
					parse(line)
				if unfinished_line:
					parse(unfinished_line)

			# get all remaining output
			stdout, stderr = process.communicate()
			if stderr:
				# write stderr into the log file
				MODULE.warn('stderr from univention-join: %s' % stderr)

			# check for errors
			if process.returncode != 0:
				# error case
				MODULE.warn('Could not perform system join: %s%s' % (stdout, stderr))
				error_handler(_('Software packages have been installed successfully, however, the join process could not be executed. More details can be found in the log file /var/log/univention/join.log. Please retry to join the system via the UMC module "Domain join" after resolving any conflicting issues.'))
			elif failed_join_scripts:
				MODULE.warn('The following join scripts could not be executed: %s' % failed_join_scripts)
				error_handler(_('Software packages have been installed successfully, however, some join scripts could not be executed. More details can be found in the log file /var/log/univention/join.log. Please retry to execute the join scripts via the UMC module "Domain join" after resolving any conflicting issues.'))
	finally:
		# make sure that UMC servers and apache can be restarted again
		MODULE.info('enabling UMC and apache server restart')
		subprocess.call(CMD_ENABLE_EXEC)
コード例 #31
0
 def _thread(obj):
     obj._net_apply_running += 1
     MODULE.process('Applying network settings')
     with util.written_profile(values):
         util.run_networkscrips(demo_mode)
コード例 #32
0
	def install(self, request):
		# get all arguments
		username = request.options.get('username')
		password = request.options.get('password')
		master = request.options.get('master')
		school_ou = request.options.get('schoolOU')
		educational_slave = request.options.get('nameEduServer')
		ou_display_name = request.options.get('OUdisplayname', school_ou)  # use school OU name as fallback
		server_type = request.options.get('server_type')
		setup = request.options.get('setup')
		server_role = ucr.get('server/role')
		joined = os.path.exists('/var/univention-join/joined')

		if self._installation_started:
			raise ValueError('The installation was started twice. This should not have happened.')

		if server_role != 'domaincontroller_slave':
			# use the credentials of the currently authenticated user on a master/backup system
			self.require_password()
			username = self.username
			password = self.password
			master = '%s.%s' % (ucr.get('hostname'), ucr.get('domainname'))
		if server_role == 'domaincontroller_backup':
			master = ucr.get('ldap/master')

		self.original_certificate_file = None

		# check for valid school OU
		if ((setup == 'singlemaster' and server_role == 'domaincontroller_master') or server_role == 'domaincontroller_slave') and not RE_OU.match(school_ou):
			raise SchoolInstallerError(_('The specified school OU is not valid.'))

		# check for valid server role
		if server_role not in ('domaincontroller_master', 'domaincontroller_backup', 'domaincontroller_slave'):
			raise SchoolInstallerError(_('Invalid server role! UCS@school can only be installed on the system roles master domain controller, backup domain controller, or slave domain controller.'))

		if server_role == 'domaincontroller_slave' and not server_type:
			raise SchoolInstallerError(_('Server type has to be set for domain controller slave'))

		if server_role == 'domaincontroller_slave' and server_type == 'administrative' and not educational_slave:
			raise SchoolInstallerError(_('The name of an educational server has to be specified if the system shall be configured as administrative server.'))

		if server_role == 'domaincontroller_slave' and server_type == 'administrative' and educational_slave.lower() == ucr.get('hostname').lower():
			raise SchoolInstallerError(_('The name of the educational server may not be equal to the name of the administrative slave.'))

		if server_role == 'domaincontroller_slave':
			# on slave systems, download the certificate from the master in order
			# to be able to build up secure connections
			self.original_certificate_file = self.retrieve_root_certificate(master)

		if server_role != 'domaincontroller_master':
			# check for a compatible environment on the DC master

			masterinfo = self._umc_master(username, password, master, 'schoolinstaller/get/metainfo')
			school_environment = masterinfo['school_environment']
			master_samba_version = masterinfo['samba']
			if not school_environment:
				raise SchoolInstallerError(_('Please install UCS@school on the master domain controller system. Cannot proceed installation on this system.'))
			if master_samba_version == 3:
				raise SchoolInstallerError(_('This UCS domain uses Samba 3 which is no longer supported by UCS@school. Please update all domain systems to samba 4 to be able to continue.'))
			if server_role == 'domaincontroller_slave' and school_environment != 'multiserver':
				raise SchoolInstallerError(_('The master domain controller is not configured for a UCS@school multi server environment. Cannot proceed installation on this system.'))
			if server_role == 'domaincontroller_backup' and school_environment != setup:
				raise SchoolInstallerError(_('The UCS@school master domain controller needs to be configured similarly to this backup system. Please choose the correct environment type for this system.'))
			if server_role == 'domaincontroller_backup' and not joined:
				raise SchoolInstallerError(_('In order to install UCS@school on a backup domain controller, the system needs to be joined first.'))

		# everything ok, try to acquire the lock for the package installation
		lock_aquired = self.package_manager.lock(raise_on_fail=False)
		if not lock_aquired:
			MODULE.warn('Could not aquire lock for package manager')
			raise SchoolInstallerError(_('Cannot get lock for installation process. Another package manager seems to block the operation.'))

		# see which packages we need to install
		MODULE.process('performing UCS@school installation')
		packages_to_install = []
		installed_samba_version = self.get_samba_version()
		if installed_samba_version == 3:
			raise SchoolInstallerError(_('This UCS domain uses Samba 3 which is no longer supported by UCS@school. Please update all domain systems to samba 4 to be able to continue.'))
		if server_role == 'domaincontroller_slave':
			# slave
			packages_to_install.extend(['univention-samba4', 'univention-s4-connector'])
			if server_type == 'educational':
				packages_to_install.append('ucs-school-slave')
			else:
				packages_to_install.append('ucs-school-nonedu-slave')
		else:  # master or backup
			if setup == 'singlemaster':
				if installed_samba_version:
					pass  # do not install samba a second time
				else:  # otherwise install samba4
					packages_to_install.extend(['univention-samba4', 'univention-s4-connector'])
				packages_to_install.append('ucs-school-singlemaster')
			elif setup == 'multiserver':
				packages_to_install.append('ucs-school-master')
			else:
				raise SchoolInstallerError(_('Invalid UCS@school configuration.'))
		MODULE.info('Packages to be installed: %s' % ', '.join(packages_to_install))

		# reset the current installation progress
		steps = 100  # installation -> 100
		if server_role != 'domaincontroller_backup' and not (server_role == 'domaincontroller_master' and setup == 'multiserver'):
			steps += 10  # create_ou -> 10
		if server_role == 'domaincontroller_slave':
			steps += 10  # move_slave_into_ou -> 10
		steps += 100  # system_join -> 100 steps

		self._installation_started = True
		progress_state = self.progress_state
		progress_state.reset(steps)
		progress_state.component = _('Installation of UCS@school packages')
		self.package_manager.reset_status()

		def _thread(_self, packages):
			MODULE.process('Starting package installation')
			with _self.package_manager.locked(reset_status=True, set_finished=True):
				with _self.package_manager.no_umc_restart(exclude_apache=True):
					_self.package_manager.update()
					if not _self.package_manager.install(*packages):
						raise SchoolInstallerError(_('Failed to install packages.'))

			if server_role != 'domaincontroller_backup' and not (server_role == 'domaincontroller_master' and setup == 'multiserver'):
				# create the school OU (not on backup and not on master w/multi server environment)
				MODULE.info('Starting creation of LDAP school OU structure...')
				progress_state.component = _('Creation of LDAP school structure')
				progress_state.info = ''
				try:
					if server_role == 'domaincontroller_slave':
						_educational_slave = ucr.get('hostname') if server_type == 'educational' else educational_slave
						administrative_slave = None if server_type == 'educational' else ucr.get('hostname')
						create_ou_remote(master, username, password, school_ou, ou_display_name, _educational_slave, administrative_slave)
					elif server_role == 'domaincontroller_master':
						create_ou_local(school_ou, ou_display_name)
				except SchoolInstallerError as exc:
					MODULE.error(str(exc))
					raise SchoolInstallerError(_(
						'The UCS@school software packages have been installed, however, a school OU could not be created and consequently a re-join of the system has not been performed. '
						'Please create a new school OU structure using the UMC module "Add school" on the master and perform a domain join on this machine via the UMC module "Domain join".'
					))

				progress_state.add_steps(10)

			if server_role == 'domaincontroller_slave':
				# make sure that the slave is correctly moved below its OU
				MODULE.info('Trying to move the slave entry in the right OU structure...')
				result = umc(username, password, master, 'schoolwizards/schools/move_dc', {'schooldc': ucr.get('hostname'), 'schoolou': school_ou}, 'schoolwizards/schools').result
				if not result.get('success'):
					MODULE.warn('Could not successfully move the slave DC into its correct OU structure:\n%s' % result.get('message'))
					raise SchoolInstallerError(_('Validating the LDAP school OU structure failed. It seems that the current slave system has already been assigned to a different school or that the specified school OU name is already in use.'))

			# system join on a slave system
			progress_state.component = _('Domain join')
			if server_role == 'domaincontroller_slave':
				progress_state.info = _('Preparing domain join...')
				MODULE.process('Starting system join...')
			else:  # run join scripts on DC backup/master
				progress_state.info = _('Executing join scripts...')
				MODULE.process('Running join scripts...')
			system_join(
				username, password,
				info_handler=self.progress_state.info_handler,
				step_handler=self.progress_state.add_steps,
				error_handler=self.progress_state.error_handler,
			)

		def _finished(thread, result):
			MODULE.info('Finished installation')
			progress_state.finish()
			progress_state.info = _('finished...')
			self._installation_started = None
			if isinstance(result, SchoolInstallerError):
				MODULE.warn('Error during installation: %s' % (result,))
				self.restore_original_certificate()
				progress_state.error_handler(str(result))
			elif isinstance(result, BaseException):
				self.restore_original_certificate()
				msg = ''.join(traceback.format_exception(*thread.exc_info))
				MODULE.error('Exception during installation: %s' % msg)
				progress_state.error_handler(_('An unexpected error occurred during installation: %s') % result)

		thread = notifier.threads.Simple('ucsschool-install', notifier.Callback(_thread, self, packages_to_install), notifier.Callback(_finished))
		thread.run()
		self.finished(request.id, None)
コード例 #33
0
def get_all_backups(lo, ucr=None):
    MODULE.process('Searching DC Backup')
    return [
        host.info['fqdn']
        for host in get_hosts(domaincontroller_backup, lo, ucr)
    ]
コード例 #34
0
def auto_complete_values_for_join(newValues, current_locale=None):
    # try to automatically determine the domain, except on a dcmaster and basesystem
    if newValues[
            'server/role'] != 'domaincontroller_master' and not newValues.get(
                'domainname') and newValues['server/role'] != 'basesystem':
        ucr.load()
        for nameserver in ('nameserver1', 'nameserver2', 'nameserver3'):
            if newValues.get('domainname'):
                break
            newValues['domainname'] = get_ucs_domain(
                newValues.get(nameserver, ucr.get(nameserver)))
        if not newValues['domainname']:
            raise Exception(
                _('Cannot automatically determine the domain. Please specify the server\'s fully qualified domain name.'
                  ))

    # The check "and 'domainname' in newValues" is solely for basesystems
    isAdMember = 'ad/member' in newValues and 'ad/address' in newValues
    if 'windows/domain' not in newValues:
        if isAdMember:
            MODULE.process('Searching for NETBIOS domain in AD')
            for nameserver in ('nameserver1', 'nameserver2', 'nameserver3'):
                ns = newValues.get(nameserver, ucr.get(nameserver))
                if ns:
                    try:
                        ad_domain_info = lookup_adds_dc(
                            newValues.get('ad/address'),
                            ucr={'nameserver1': ns})
                    except failedADConnect:
                        pass
                    else:
                        newValues['windows/domain'] = ad_domain_info[
                            'Netbios Domain']
                        MODULE.process(
                            'Setting NETBIOS domain to AD value: %s' %
                            newValues['windows/domain'])
                        break

    if 'windows/domain' not in newValues and 'domainname' in newValues:
        newValues['windows/domain'] = domain2windowdomain(
            newValues.get('domainname'))
        MODULE.process('Setting NETBIOS domain to default: %s' %
                       newValues['windows/domain'])

    # make sure that AD connector package is installed if AD member mode is chosen
    selectedComponents = set(newValues.get('components', []))
    if isAdMember and newValues['server/role'] == 'domaincontroller_master':
        selectedComponents.add('univention-ad-connector')

    # make sure to install the memberof overlay if it is installed on the DC Master
    if newValues['server/role'] not in ('domaincontroller_master',
                                        'basesystem', 'memberserver'):
        if newValues.pop('install_memberof_overlay', None):
            selectedComponents.add('univention-ldap-overlay-memberof')

    # add lists with all packages that should be removed/installed on the system
    if selectedComponents:
        currentComponents = set()
        for iapp in get_apps():
            if iapp['is_installed']:
                for ipackages in (iapp['default_packages'],
                                  iapp['default_packages_master']):
                    currentComponents = currentComponents.union(ipackages)

        # set of all available software packages
        allComponents = set(['univention-ldap-overlay-memberof'])
        for iapp in get_apps():
            for ipackages in (iapp['default_packages'],
                              iapp['default_packages_master']):
                allComponents = allComponents.union(ipackages)

        # get all packages that shall be removed
        removeComponents = list(allComponents
                                & (currentComponents - selectedComponents))
        newValues['packages_remove'] = ' '.join(removeComponents)

        # get all packages that shall be installed
        installComponents = list(allComponents
                                 & (selectedComponents - currentComponents))
        newValues['packages_install'] = ' '.join(installComponents)

    current_locale = Locale(ucr.get('locale/default', 'en_US.UTF-8:UTF-8'))
    if newValues['server/role'] == 'domaincontroller_master':
        # add newValues for SSL UCR variables
        default_locale = current_locale
        if 'locale/default' in newValues:
            default_locale = Locale(newValues['locale/default'])
        newValues['ssl/state'] = default_locale.territory
        newValues['ssl/locality'] = default_locale.territory
        newValues['ssl/organization'] = newValues.get('organization',
                                                      default_locale.territory)
        newValues['ssl/organizationalunit'] = 'Univention Corporate Server'
        newValues['ssl/email'] = 'ssl@{domainname}'.format(**newValues)

    # make sure that the locale of the current session is also supported
    # ... otherwise the setup scripts will fail after regenerating the
    # locale data (in 20_language/10language) with some strange python
    # exceptions about unsupported locale strings...
    if 'locale' not in newValues:
        newValues['locale'] = newValues.get('locale/default', '')
    forcedLocales = ['en_US.UTF-8:UTF-8', 'de_DE.UTF-8:UTF-8'
                     ]  # we need en_US and de_DE locale as default language
    if current_locale:
        current_locale = '{0}:{1}'.format(str(current_locale),
                                          current_locale.codeset)
        forcedLocales.append(current_locale)
    for ilocale in forcedLocales:
        if ilocale not in newValues['locale']:
            newValues['locale'] = '%s %s' % (newValues['locale'], ilocale)

    return newValues
コード例 #35
0
 def auth_type(self, auth_type):
     MODULE.process('Setting auth type to %r' % (auth_type, ))
     self.__auth_type = auth_type
コード例 #36
0
	def invoke(self, request):
		# ATTENTION!!!!!!!
		# this function has to stay compatible with the very first App Center installations (Dec 2012)
		# if you add new arguments that change the behavior
		# you should add a new method (see invoke_dry_run) or add a function name (e.g. install-schema)
		# this is necessary because newer app center may talk remotely with older one
		#   that does not understand new arguments and behaves the old way (in case of
		#   dry_run: install application although they were asked to dry_run)
		host = request.options.get('host')
		function = request.options.get('function')
		send_as = function
		if function.startswith('install'):
			function = 'install'
		if function.startswith('update'):
			function = 'upgrade'
		if function == 'uninstall':
			function = 'remove'

		app_id = request.options.get('application')
		app = Apps().find(app_id)
		if app is None:
			raise umcm.UMC_Error(_('Could not find an application for %s') % (app_id,))
		force = request.options.get('force')
		values = request.options.get('values')
		only_dry_run = request.options.get('only_dry_run')
		dont_remote_install = request.options.get('dont_remote_install')
		only_master_packages = send_as.endswith('schema')
		MODULE.process('Try to %s (%s) %s on %s. Force? %r. Only master packages? %r. Prevent installation on other systems? %r. Only dry run? %r.' % (function, send_as, app_id, host, force, only_master_packages, dont_remote_install, only_dry_run))

		# REMOTE invocation!
		if host and host != self.ucr.get('hostname'):
			try:
				client = Client(host, self.username, self.password)
				result = client.umc_command('appcenter/invoke', request.options).result
			except (ConnectionError, HTTPError) as exc:
				MODULE.error('Error during remote appcenter/invoke: %s' % (exc,))
				result = {
					'unreachable': [host],
					'master_unreachable': True,
					'serious_problems': True,
					'software_changes_computed': True,  # not really...
				}
			else:
				if result['can_continue']:
					def _thread_remote(_client):
						with self.is_working():
							self._query_remote_progress(_client)

					def _finished_remote(thread, result):
						if isinstance(result, BaseException):
							MODULE.warn('Exception during %s %s: %s' % (function, app_id, str(result)))
					thread = notifier.threads.Simple('invoke', notifier.Callback(_thread_remote, client), _finished_remote)
					thread.run()
			self.finished(request.id, result)
			return

		# make sure that the application can be installed/updated
		action = get_action(function)()
		args = action._build_namespace(app=app, username=self.username, password=self.password, noninteractive=True, skip_checks=['shall_have_enough_ram', 'shall_only_be_installed_in_ad_env_with_password_service', 'must_not_have_concurrent_operation'], send_info=not only_master_packages, set_vars=values, dry_run=True, install_master_packages_remotely=False, only_master_packages=only_master_packages)

		can_continue = True
		delayed_can_continue = True
		serious_problems = False
		result = {
			'install': [],
			'remove': [],
			'broken': [],
			'unreachable': [],
			'master_unreachable': False,
			'serious_problems': False,
			'hosts_info': {},
			'problems_with_hosts': False,
			'serious_problems_with_hosts': False,
			'invokation_forbidden_details': {},
			'invokation_warning_details': {},
			'software_changes_computed': False,
		}
		if not app:
			MODULE.process('Application not found: %s' % app_id)
			can_continue = False
		if can_continue and not only_master_packages:
			if function == 'upgrade':
				app = Apps().find_candidate(app)
			if app is None:
				forbidden, warnings = {'must_have_candidate': False}, {}
			else:
				forbidden, warnings = app.check(function)
			if forbidden:
				MODULE.process('Cannot %s %s: %r' % (function, app_id, forbidden))
				result['invokation_forbidden_details'] = forbidden
				can_continue = False
				serious_problems = True
			if warnings:
				MODULE.process('Warning trying to %s %s: %r' % (function, app_id, forbidden))
				result['invokation_warning_details'] = warnings
				if not force:
					# don't stop "immediately".
					#   compute the package changes!
					delayed_can_continue = False
		result['serious_problems'] = serious_problems
		result['can_continue'] = can_continue
		if can_continue:
			with self.locked():
				if can_continue and function in ('install', 'upgrade'):
					result.update(self._install_dry_run_remote(app, function, dont_remote_install, force))
					serious_problems = bool(result['master_unreachable'] or result['serious_problems_with_hosts'])
					if serious_problems:
						args.dry_run = True
					result.update(action.dry_run(app, args))
					result['software_changes_computed'] = True
					serious_problems = bool(result['broken'] or serious_problems)
					if serious_problems or (not force and (result['unreachable'] or result['install'] or result['remove'] or result['problems_with_hosts'])):
						can_continue = False
				elif can_continue and function in ('remove',) and not force:
					result.update(action.dry_run(app, args))
					result['software_changes_computed'] = True
					can_continue = False
				can_continue = can_continue and delayed_can_continue and not only_dry_run
				result['serious_problems'] = serious_problems
				result['can_continue'] = can_continue

				if can_continue and not only_dry_run:
					def _thread(module, app, function):
						with module.is_working():
							if not dont_remote_install and function != 'remove':
								self._install_master_packages_on_hosts(app, function)
							with module.package_manager.no_umc_restart(exclude_apache=True):
								try:
									args.dry_run = False
									args.install_master_packages_remotely = False
									return action.call_with_namespace(args)
								except AppCenterError as exc:
									raise umcm.UMC_Error(str(exc), result=dict(
										display_feedback=True,
										title='%s %s' % (exc.title, exc.info)))
					def _finished(thread, result):
						if isinstance(result, BaseException):
							MODULE.warn('Exception during %s %s: %s' % (function, app_id, str(result)))
					thread = notifier.threads.Simple('invoke', notifier.Callback(_thread, self, app, function), _finished)
					thread.run()
		self.finished(request.id, result)
コード例 #37
0
	def adconnector_save(self, request):
		"""Saves the Active Directory connection configuration

		options:
			Host_IP: IP address of the AD server
			LDAP_Host: hostname of the AD server
			LDAP_Base: LDAP base of the AD server
			LDAP_BindDN: LDAP DN to use for authentication
			KerberosDomain: kerberos domain
			PollSleep: time in seconds between polls
			RetryRejected: how many time to retry a synchronisation
			MappingSyncMode: synchronisation mode
			MappingGroupLanguage: language of the AD server

		return: { 'success' : (True|False), 'message' : <details> }
		"""

		for umckey, ucrkey, default in Instance.OPTION_MAPPING:
			val = request.options.get(umckey, default)
			if val:
				if isinstance(val, bool):
					val = 'yes' if val else 'no'
				MODULE.info('Setting %s=%s' % (ucrkey, val))
				univention.config_registry.handler_set([u'%s=%s' % (ucrkey, val)])

		ucr.load()
		if ucr.get('connector/ad/ldap/ldaps'):
			MODULE.info('Unsetting connector/ad/ldap/ldaps')
			univention.config_registry.handler_unset([u'connector/ad/ldap/ldaps'])
		if ucr.get('connector/ad/ldap/port') == '636':
			MODULE.info('Setting ldap port to 389')
			univention.config_registry.handler_set([u'connector/ad/ldap/port=389'])

		if not request.options.get('LDAP_Password') in (None, '', DO_NOT_CHANGE_PWD):
			fn = ucr.get('connector/ad/ldap/bindpw', FN_BINDPW)
			try:
				with open(fn, 'w') as fd:
					fd.write(request.options.get('LDAP_Password'))
				os.chmod(fn, 0o600)
				os.chown(fn, 0, 0)
				univention.config_registry.handler_set([u'connector/ad/ldap/bindpw=%s' % fn])
			except Exception as e:
				MODULE.info('Saving bind password failed (filename=%(fn)s ; exception=%(exception)s)' % {'fn': fn, 'exception': str(e.__class__)})
				self.finished(request.id, {'success': False, 'message': _('Saving bind password failed (filename=%(fn)s ; exception=%(exception)s)') % {'fn': fn, 'exception': str(e.__class__)}})
				return

		ssldir = '/etc/univention/ssl/%s' % request.options.get('LDAP_Host')
		if not os.path.exists(ssldir):
			self._create_certificate(request)
			return

		# enter a static host entry such that the AD server's FQDN can be resolved
		univention.config_registry.handler_set([u'hosts/static/%(Host_IP)s=%(LDAP_Host)s' % request.options])

		# check for SSL support on AD side
		if admember.server_supports_ssl(server=request.options.get('LDAP_Host')):
			MODULE.process('Enabling SSL...')
			admember.enable_ssl()
		else:
			MODULE.warn('SSL is not supported')
			admember.disable_ssl()

		# UCR variables are set, and now we can try to guess the language of
		# the AD domain
		ad_lang = guess_ad_domain_language()
		univention.config_registry.handler_set([u'connector/ad/mapping/group/language=%s' % ad_lang])

		self.finished(request.id, {'success': True, 'message': _('Active Directory connection settings have been saved.')})
コード例 #38
0
def get_master(lo):
    MODULE.process('Searching Primary Directory Node')
    return get_hosts(domaincontroller_master, lo)[0].info['fqdn']