def __update_status(self): ucr.load() fn = ucr.get('connector/ad/ldap/certificate') self.status_ssl = ucr.is_true('connector/ad/ldap/ssl') self.status_password_sync = ucr.is_true('connector/ad/mapping/user/password/kinit') self.status_certificate = bool(fn and os.path.exists(fn)) self.status_running = self.__is_process_running('*python*univention/connector/ad/main.py*') self.status_mode_admember = admember.is_localhost_in_admember_mode(ucr) self.status_mode_adconnector = admember.is_localhost_in_adconnector_mode(ucr)
def __init__(self): ucr.load() self._is_master = ucr.get('server/role') == 'domaincontroller_master' self._updates_available = ucr.is_true('update/available') self._fqdn = '%s.%s' % (ucr.get('hostname'), ucr.get('domainname')) message = '\n'.join(self._error_msg()) super(LDAP_ServerDown, self).__init__(message, status=503)
def query_maintenance_information(self): ucr.load() if ucr.is_true('license/extended_maintenance/disable_warning'): return {'show_warning': False} version = self.uu.get_ucs_version() try: url = 'http://updates.software-univention.de/download/ucs-maintenance/{}.yaml'.format( version) response = requests.get(url, timeout=10) if not response.ok: response.raise_for_status() status = yaml.load(response.content) if not isinstance(status, dict): raise yaml.YAMLError(repr(status)) # the yaml file contains for maintained either false, true or extended as value. # yaml.load converts true and false into booleans but extended into string. _maintained_status = status.get('maintained') maintenance_extended = _maintained_status == 'extended' show_warning = maintenance_extended or not _maintained_status except yaml.YAMLError as exc: MODULE.error('The YAML format is malformed: %s' % (exc, )) return {'show_warning': False} except requests.exceptions.RequestException as exc: MODULE.error("Querying maintenance information failed: %s" % (exc, )) return {'show_warning': False} return { 'ucs_version': version, 'show_warning': show_warning, 'maintenance_extended': maintenance_extended, 'base_dn': ucr.get('license/base') }
def query_releases(self): """ Returns a list of system releases suitable for the corresponding ComboBox """ # be as current as possible. self.uu.ucr_reinit() ucr.load() appliance_mode = ucr.is_true('server/appliance') available_versions, blocking_components = self.uu.get_all_available_release_updates( ) result = [{ 'id': rel, 'label': 'UCS %s' % (rel, ) } for rel in available_versions] # # appliance_mode=no ; blocking_comp=no → add "latest version" # appliance_mode=no ; blocking_comp=yes → no "latest version" # appliance_mode=yes; blocking_comp=no → add "latest version" # appliance_mode=yes; blocking_comp=yes → add "latest version" # if result and (appliance_mode or not blocking_components): # UniventionUpdater returns available version in ascending order, so # the last returned entry is the one to be flagged as 'latest' if there's # no blocking component. result[-1]['label'] = '%s (%s)' % (result[-1]['label'], _('latest version')) return result
def run(_umc_instance): if util.is_service_active('LDAP'): ucr.load() if not ucr.is_true('ldap/overlay/memberof'): MODULE.error(warning_message) raise Warning(description=warning_message) return
def admember_set_password(self, username, password): ldb_url = ucr.get('connector/ad/ldap/host') ldb_url = 'ldaps://%s' % (ldb_url, ) if ucr.is_true( 'connector/ad/ldap/ldaps') else 'ldap://%s' % (ldb_url, ) try: reset_username = dict(ucr)['ad/reset/username'] with open(dict(ucr)['ad/reset/password']) as fd: reset_password = fd.readline().strip() except (EnvironmentError, KeyError): raise UMC_Error(_( 'The configuration of the password reset service is not complete. The UCR variables "ad/reset/username" and "ad/reset/password" need to be set properly. Please inform an administration.' ), status=500) process = Popen([ 'samba-tool', 'user', 'setpassword', '--username', reset_username, '--password', reset_password, '--filter', filter_format('samaccountname=%s', (username, )), '--newpassword', password, '-H', ldb_url ], stdout=PIPE, stderr=STDOUT) stdouterr = process.communicate()[0] if stdouterr: MODULE.process('samba-tool user setpassword: %s' % (stdouterr, )) if process.returncode: MODULE.error( "admember_set_password(): failed to set password. Return code: %s" % (process.returncode, )) return False return True
def run(_umc_instance): ucr.load() if ucr.is_true('diagnostic/check/disable/59_ldap_server_name') or ucr.get('server/role') != 'memberserver': return ldap_server_name = ucr.get('ldap/server/name') domainname = ucr.get('domainname') lo = univention.uldap.getMachineConnection() master = lo.search(base=ucr.get('ldap/base'), filter='(univentionServerRole=master)', attr=['cn']) try: master_cn = master[0][1].get('cn')[0].decode('UTF-8') except IndexError: raise Critical('Could not find a Primary Directory Node %s' % (master,)) master_fqdn = '.'.join([master_cn, domainname]) if master_fqdn == ldap_server_name: res = lo.searchDn(base=ucr.get('ldap/base'), filter='univentionServerRole=backup') # Case: ldap/server/name is the Primary Directory Node and there are Backup Directory Nodes available. if res: button = [{ 'action': 'deactivate_test', 'label': _('Deactivate test'), }] warn = (_('The primary LDAP Server of this System (UCR ldap/server/name) is set to the Primary Directory Node of this UCS domain (%s).\nSince this environment provides further LDAP Servers, we recommend a different configuration to reduce the load on the Primary Directory Node.\nPlease see {sdb} for further information.') % (master_fqdn,)) raise Warning(warn, buttons=button)
def main(cls): parser = argparse.ArgumentParser( prog='python -m univention.admin.rest.server') parser.add_argument('-d', '--debug', type=int, default=2) args = parser.parse_args() ud.init('stdout', ud.FLUSH, ud.NO_FUNCTION) ud.set_level(ud.MAIN, args.debug) tornado.httpclient.AsyncHTTPClient.configure( 'tornado.curl_httpclient.CurlAsyncHTTPClient') tornado.locale.load_gettext_translations( '/usr/share/locale', 'univention-management-console-module-udm') cls.start_processes() cls.register_signal_handlers() app = tornado.web.Application( [ (r'.*', cls), ], serve_traceback=ucr.is_true( 'directory/manager/rest/show-tracebacks', True), ) app.listen( int(ucr.get('directory/manager/rest/server/port', 9979)), ucr.get('directory/manager/rest/server/address', '127.0.0.1')) ioloop = tornado.ioloop.IOLoop.instance() ioloop.start()
def guess_username(self, lo, date_format): # already provided. use this one if self.name: return self.name # search database hints = [] if self.lastname: hints.append( expression('lastname', escape_filter_chars(self.lastname))) if self.firstname: hints.append( expression('firstname', escape_filter_chars(self.firstname))) if self.birthday: hints.append( expression( 'birthday', escape_filter_chars( unformat_date(self.birthday, date_format)))) if hints: ldap_filter = conjunction('&', hints) udm_obj = self.get_first_udm_obj(lo, str(ldap_filter)) if udm_obj: return udm_obj['username'] # generate a reasonable one firstname = u'' if self.firstname: firstname = u'%s' % (self.firstname.split()[0].lower(), ) lastname = u'' if self.lastname: lastname = u'%s' % (self.lastname.split()[-1].lower()) firstname = self.RE_UID_INVALID.sub('', firstname) lastname = self.RE_UID_INVALID.sub('', lastname) def replace_invalid_chars(u): return re.sub(r'^(?:[^\w]+)?(.*?)(?:[^\w]+)?$', r'\1', u, re.UNICODE) if ucr.is_true( 'ucsschool/csvimport/username/generation/firstname_lastname', False): username = firstname + (u'.' if firstname else u'') + lastname return replace_invalid_chars(username) if firstname: firstname = firstname[:5] + '.' username = firstname + lastname[:5] maxlength = 20 - len( ucr.get('ucsschool/ldap/default/userprefix/exam', 'exam-')) return replace_invalid_chars(username[:maxlength])
def _read_user(self, userstr, ldap_user_read=None): match = self.USER_REGEX.match(userstr) if not match or not userstr: raise AttributeError('invalid key "%s"' % userstr) username = match.groupdict()['username'] if not username: raise AttributeError('username missing: %s' % userstr) lo = ldap_user_read try: userobj = User.get_only_udm_obj( lo, filter_format('uid=%s', (username, ))) if userobj is None: raise noObject(username) user = User.from_udm_obj(userobj, None, lo) except (noObject, MultipleObjectsError): MODULE.info('Unknown user "%s"' % username) dict.__setitem__(self, userstr, UserInfo('', '')) return blacklisted_groups = set([ x.strip().lower() for x in ucr.get( 'ucsschool/umc/computerroom/hide_screenshots/groups', 'Domain Admins').split(',') ]) users_groupmemberships = set( [explode_dn(x, True)[0].lower() for x in userobj['groups']]) MODULE.info('UserMap: %s: hide screenshots for following groups: %s' % ( username, blacklisted_groups, )) MODULE.info('UserMap: %s: user is member of following groups: %s' % ( username, users_groupmemberships, )) hide_screenshot = bool(blacklisted_groups & users_groupmemberships) if ucr.is_true('ucsschool/umc/computerroom/hide_screenshots/teachers', True) and user.is_teacher(lo): MODULE.info('UserMap: %s: is teacher hiding screenshot' % (username, )) hide_screenshot = True MODULE.info('UserMap: %s: hide_screenshot=%r' % (username, hide_screenshot)) dict.__setitem__( self, userstr, UserInfo(user.dn, username, isTeacher=user.is_teacher(lo), hide_screenshot=hide_screenshot))
def run(self, args): # locale must be set before importing UDM! log_init('/dev/stdout', args.debug) language = str(Locale(args.language)) locale.setlocale(locale.LC_MESSAGES, language) os.umask( 0o077) # FIXME: should probably be changed, this is what UMC sets # The UMC-Server and module processes are clearing environment variables os.environ.clear() os.environ['PATH'] = '/bin:/sbin:/usr/bin:/usr/sbin' os.environ['LANG'] = language import univention.admin.modules as udm_modules udm_modules.update() from univention.admin.rest.module import Application application = Application(serve_traceback=ucr.is_true( 'directory/manager/rest/show-tracebacks', True)) server = HTTPServer(application) if args.port: server.bind(args.port) server.start(args.cpus) if args.unix_socket: socket = bind_unix_socket(args.unix_socket) server.add_socket(socket) signal.signal(signal.SIGTERM, partial(self.signal_handler_stop, server)) signal.signal(signal.SIGINT, partial(self.signal_handler_stop, server)) signal.signal(signal.SIGHUP, self.signal_handler_reload) channel = logging.StreamHandler() channel.setFormatter( tornado.log.LogFormatter( fmt= '%(color)s%(asctime)s %(levelname)10s (%(process)9d) :%(end_color)s %(message)s', datefmt='%d.%m.%y %H:%M:%S')) logger = logging.getLogger() logger.setLevel(logging.INFO) logger.addHandler(channel) try: tornado.ioloop.IOLoop.current().start() except (SystemExit, KeyboardInterrupt): raise except: CORE.error(traceback.format_exc()) raise
def _delete_obj(self, request, ldap_user_read=None, ldap_user_write=None, ldap_admin_write=None): # Bug #44641: workaround with security implications! if ucr.is_true('ucsschool/wizards/schoolwizards/workaround/admin-connection'): ldap_user_write = ldap_admin_write ret = [] for obj in iter_objects_in_request(request, ldap_user_write, True): obj.name = obj.get_name_from_dn(obj.old_dn) MODULE.process('Deleting %r' % (obj)) if obj.remove(ldap_user_write): ret.append(True) else: ret.append({'result': {'message': _('"%s" does not exist!') % obj.name}}) return ret
def init(self): if not ucr.is_true("umc/self-service/passwordreset/enabled"): raise UMC_Error(_( 'The password reset service is disabled via configuration registry.' ), status=503) if not IS_SELFSERVICE_MASTER: return self._usersmod = None self.groupmod = None self.db = TokenDB(MODULE) self.conn = self.db.conn atexit.register(self.db.close_db) if not self.db.table_exists(): self.db.create_table() def ucr_try_int(variable, default): try: return int(ucr.get(variable, default)) except ValueError: MODULE.error( 'UCR variables %s is not a number, using default: %s' % (variable, default)) return default self.token_validity_period = ucr_try_int( "umc/self-service/passwordreset/token_validity_period", 3600) self.send_plugins = get_sending_plugins(MODULE.process) self.memcache = pylibmc.Client([MEMCACHED_SOCKET], binary=True) limit_total_minute = ucr_try_int( "umc/self-service/passwordreset/limit/total/minute", 0) limit_total_hour = ucr_try_int( "umc/self-service/passwordreset/limit/total/hour", 0) limit_total_day = ucr_try_int( "umc/self-service/passwordreset/limit/total/day", 0) self.limit_user_minute = ucr_try_int( "umc/self-service/passwordreset/limit/per_user/minute", 0) self.limit_user_hour = ucr_try_int( "umc/self-service/passwordreset/limit/per_user/hour", 0) self.limit_user_day = ucr_try_int( "umc/self-service/passwordreset/limit/per_user/day", 0) self.total_limits = [("t:c_minute", 60, limit_total_minute), ("t:c_hour", 3600, limit_total_hour), ("t:c_day", 86400, limit_total_day)]
def udm_set_password(self, username, password): user = self.get_udm_user(username=username, admin=True) if ucr.is_true('ad/member') and 'synced' in user.get('objectFlag', []): return self.admember_set_password(username, password) try: user["password"] = password user["pwdChangeNextLogin"] = 0 user.modify() return True except (udm_errors.pwToShort, udm_errors.pwQuality) as exc: raise UMC_Error(str(exc)) except udm_errors.pwalreadyused as exc: raise UMC_Error(exc.message) except Exception: MODULE.error( "udm_set_password(): failed to set password: {}".format( traceback.format_exc())) raise
def _modify_obj(self, request, ldap_user_read=None, ldap_user_write=None, ldap_admin_write=None): # Bug #44641: workaround with security implications! if ucr.is_true('ucsschool/wizards/schoolwizards/workaround/admin-connection'): ldap_user_write = ldap_admin_write ret = [] for obj in iter_objects_in_request(request, ldap_user_write, True): MODULE.process('Modifying %r' % (obj)) obj.validate(ldap_user_read) if obj.errors: ret.append({'result': {'message': obj.get_error_msg()}}) continue try: obj.modify(ldap_user_write, validate=False) except uldapBaseException as exc: ret.append({'result': {'message': get_exception_msg(exc)}}) else: ret.append(True) # no changes? who cares? return ret
def run(self, args): # locale must be set before importing UDM! log_init('/dev/stdout', args.debug) language = str(Locale(args.language)) locale.setlocale(locale.LC_MESSAGES, language) os.umask( 0o077) # FIXME: should probably be changed, this is what UMC sets # The UMC-Server and module processes are clearing environment variables os.environ.clear() os.environ['PATH'] = '/bin:/sbin:/usr/bin:/usr/sbin' os.environ['LANG'] = language import univention.admin.modules as udm_modules udm_modules.update() from univention.admin.rest.module import Application application = Application(serve_traceback=ucr.is_true( 'directory/manager/rest/show-tracebacks', True)) server = HTTPServer(application) server.start(args.cpus) if args.port: server.listen(args.port) if args.unix_socket: socket = bind_unix_socket(args.unix_socket) server.add_socket(socket) signal.signal(signal.SIGTERM, partial(self.signal_handler_stop, server)) signal.signal(signal.SIGINT, partial(self.signal_handler_stop, server)) signal.signal(signal.SIGHUP, self.signal_handler_reload) tornado.log.enable_pretty_logging() try: tornado.ioloop.IOLoop.current().start() except (SystemExit, KeyboardInterrupt): raise except: CORE.error(traceback.format_exc()) raise
def delete_user(self, request, ldap_user_read=None, ldap_user_write=None, ldap_admin_write=None): # Bug #44641: workaround with security implications! if ucr.is_true('ucsschool/wizards/schoolwizards/workaround/admin-connection'): ldap_user_write = ldap_admin_write ret = [] for obj_props in request.options: obj_props = obj_props['object'] try: obj = User.from_dn(obj_props['$dn$'], None, ldap_user_write) except noObject: raise UMC_Error(_('The %s %r does not exists or might have been removed in the meanwhile.') % (getattr(User, 'type_name', None) or User.__name__, User.get_name_from_dn(obj_props['$dn$']))) school = obj_props['remove_from_school'] success = obj.remove_from_school(school, ldap_user_write) # obj.old_dn is None when the ucsschool lib has deleted the user after the last school was removed from it if success and obj.old_dn is not None: success = obj.modify(ldap_user_write) if not success: success = {'result': {'message': _('Failed to remove user from school.')}} ret.append(success) return ret
def _create_obj(self, request, ldap_user_read=None, ldap_user_write=None, ldap_admin_write=None): # Bug #44641: workaround with security implications! if ucr.is_true('ucsschool/wizards/schoolwizards/workaround/admin-connection'): ldap_user_write = ldap_admin_write ret = [] for obj in iter_objects_in_request(request, ldap_user_write): MODULE.process('Creating %r' % (obj,)) obj.validate(ldap_user_read) if obj.errors: ret.append({'result': {'message': obj.get_error_msg()}}) MODULE.process('Validation failed %r' % (ret[-1],)) continue try: if obj.create(ldap_user_write, validate=False): ret.append(True) else: ret.append({'result': {'message': _('"%s" already exists!') % obj.name}}) except uldapBaseException as exc: ret.append({'result': {'message': get_exception_msg(exc)}}) MODULE.process('Creation failed %r' % (ret[-1],)) return ret
def _maintenance_information(self) -> Dict[str, Any]: default = {'show_warning': False} if not self.uu: return default ucr.load() if ucr.is_true('license/extended_maintenance/disable_warning'): return default version = self.uu.current_version for _ver, data in self.uu.get_releases(version, version): status = data.get('status', 'unmaintained') maintenance_extended = status == 'extended' show_warning = maintenance_extended or status != 'maintained' return { 'ucs_version': str(version), 'show_warning': show_warning, 'maintenance_extended': maintenance_extended, 'base_dn': ucr.get('license/base'), } return default
def change(self, role, ip, netmask, oldip=None): '''Return a dict with all necessary values for ipchange read from the current status of the system.''' # ignore link local addresses (no DHCP address received) network = ipaddress.IPv4Network(u'%s/%s' % (ip, netmask), False) if network.is_link_local: MODULE.error('Ignore link local address change.') return lo, position = univention.admin.uldap.getAdminConnection() hmodule = univention.admin.modules.get('dns/host_record') cmodule = univention.admin.modules.get('computers/%s' % (role,)) # check if already used res = univention.admin.modules.lookup(hmodule, None, lo, scope='sub', filter=filter_format('aRecord=%s', (ip,))) if res: used_by = [] for i in res: if 'name' in i: used_by.append(i['name']) raise BadRequest('The IP address is already in used by host record(s) for: %s' % ', '.join(used_by)) # do we have a forward zone for this IP address? if oldip and oldip != ip: fmodule = univention.admin.modules.get('dns/forward_zone') for forwardobject in univention.admin.modules.lookup(fmodule, None, lo, scope='sub', superordinate=None, filter=filter_format('(aRecord=%s)', (oldip,))): forwardobject.open() forwardobject['a'].remove(oldip) forwardobject['a'].append(ip) forwardobject.modify() # remove old DNS reverse entries with old IP server = cmodule.object(None, lo, position, self.user_dn) server.open() current_ips = server['ip'] for e in server['dnsEntryZoneReverse']: if e[1] in current_ips: server['dnsEntryZoneReverse'].remove(e) # change IP server['ip'] = ip MODULE.info('Change IP to %s' % (ip,)) server.modify() # do we have a new reverse zone for this IP address? rmodule = univention.admin.modules.get('dns/reverse_zone') parts = network.network_address.exploded.split('.') while parts[-1] == '0': parts.pop() while parts: subnet = '.'.join(parts) parts.pop() filter = filter_format('(subnet=%s)', (subnet,)) reverseobject = univention.admin.modules.lookup(rmodule, None, lo, scope='sub', superordinate=None, filter=filter) if reverseobject: server = cmodule.object(None, lo, position, self.user_dn) server.open() server['dnsEntryZoneReverse'].append([reverseobject[0].dn, ip]) server.modify() break # Change ucs-sso entry # FIXME: this should be done for UCS-in-AD domains as well! ucr.load() sso_fqdn = ucr.get('ucs/server/sso/fqdn') if ucr.is_true('ucs/server/sso/autoregistraton', True): fmodule = univention.admin.modules.get('dns/forward_zone') forwardobjects = univention.admin.modules.lookup(fmodule, None, lo, scope='sub', superordinate=None, filter=None) for forwardobject in forwardobjects: zone = forwardobject.get('zone') if not sso_fqdn.endswith(zone): continue sso_name = sso_fqdn[:-(len(zone) + 1)] for current_ip in current_ips: records = univention.admin.modules.lookup(hmodule, None, lo, scope='sub', superordinate=forwardobject, filter=filter_format('(&(relativeDomainName=%s)(aRecord=%s))', (sso_name, current_ip))) for record in records: record.open() if oldip in record['a']: record['a'].remove(oldip) record['a'].append(ip) record.modify()
def list(filterName=None, userRule=False): '''Returns a list of all existing rules. If name is given, returns only the rule matching the specified name or None. userRule specifies whether all common rules (=False) or only user-specific rules (=True) are listed. If filterName is specified, only rule matching this name is returned as single object (not as list!).''' # iterate over all UCR variables rules = {} for k, v in findUCRVariables(filterName, userRule).iteritems(): imatch = _regFilterNames.match(k) if not imatch: # should not happen continue # get filter name iname = imatch.group('name') # get the rule from our cache irule = rules.get(iname, Rule(iname)) # update the rule with the given property # NOTE: URL black-/whitelists are not supported anymore, only domain lists iproperty = imatch.group('property') if iproperty == 'filtertype': if v not in _filterTypes: irule.type = WHITELIST MODULE.error( 'Unknown filtertype "%s" for rule "%s", using whitelist as default.' % (v, irule)) else: irule.type = _filterTypes[v] elif iproperty == 'priority': try: irule.priority = int(v) except ValueError: irule.priority = 5 MODULE.error( 'Could not parse priority "%s" for rule "%s", using default value "5".' % (v, irule)) elif iproperty == 'wlan': irule.wlan = ucr.is_true(k) elif iproperty == 'domain': # get the index idx = -1 try: idx = int(imatch.group('index')) except ValueError: pass # get list type (blacklisted or whitelisted) listType = _listTypes.get(imatch.group('listType')) # add domain to list of domains irule.addDomain(v, idx, listType) # save the rule back to our cache rules[iname] = irule if filterName: # handle case for filtered search if not len(rules): # no match return None # return single element return rules.items()[0][1] return rules.values()
def __init__(self, **kwargs): ucr.load() self._is_master = ucr.get('server/role') == 'domaincontroller_master' self._updates_available = ucr.is_true('update/available') self._fqdn = '%s.%s' % (ucr.get('hostname'), ucr.get('domainname')) super(UMCError, self).__init__('\n'.join(self._error_msg()), **kwargs)
def _thread(): # make sure that a project with the same name does not exist directory = request.options['directory'] # get absolute path of project file and test for existance fn_test_project = util.distribution.Project.sanitize_project_filename( directory) if os.path.exists(fn_test_project): raise UMC_Error( _('An exam with the name "%s" already exists. Please choose a different name for the exam.' ) % (directory, )) # validate the project data and save project my.project = util.distribution.Project( dict( name=directory, description=request.options['name'], files=request.options.get('files'), sender=sender, )) my.project.validate() my.project.save() # copy files into project directory if self._tmpDir: for ifile in my.project.files: isrc = os.path.join(self._tmpDir, ifile) itarget = os.path.join(my.project.cachedir, ifile) if os.path.exists(isrc): # copy file to cachedir shutil.move(isrc, itarget) os.chown(itarget, 0, 0) # open a new connection to the master UMC try: master = ucr['ldap/master'] 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.') % ucr.get('ldap/master')) # mark the computer room for exam mode progress.component( _('Preparing the computer room for exam mode...')) client.umc_command( 'schoolexam-master/set-computerroom-exammode', dict( school=request.options['school'], roomdn=request.options['room'], )).result # FIXME: no error handling progress.add_steps(5) # read all recipients and fetch all user objects users = [] for idn in request.options['recipients']: ientry = util.distribution.openRecipients(idn, ldap_user_read) if not ientry: continue # recipients can in theory be users or groups members = [] if isinstance(ientry, util.distribution.User): members = [ientry] elif isinstance(ientry, util.distribution.Group): members = ientry.members for entry in members: # ignore exam users user = User.from_dn(entry.dn, None, ldap_user_read) if not user.is_exam_student(ldap_user_read): users.append(entry) # start to create exam user accounts progress.component(_('Preparing exam accounts')) percentPerUser = 25.0 / (1 + len(users)) examUsers = set() student_dns = set() usersReplicated = set() for iuser in users: progress.info( '%s, %s (%s)' % (iuser.lastname, iuser.firstname, iuser.username)) try: ires = client.umc_command( 'schoolexam-master/create-exam-user', dict( school=request.options['school'], userdn=iuser.dn, )).result examuser_dn = ires.get('examuserdn') examUsers.add(examuser_dn) student_dns.add(iuser.dn) MODULE.info('Exam user has been created: %r' % examuser_dn) except (ConnectionError, HTTPError) as exc: MODULE.warn( 'Could not create exam user account for %r: %s' % (iuser.dn, exc)) # indicate the the user has been processed progress.add_steps(percentPerUser) client.umc_command( 'schoolexam-master/add-exam-users-to-groups', dict( users=list(student_dns), school=request.options['school'], )) progress.add_steps(percentPerUser) # wait for the replication of all users to be finished progress.component(_('Preparing user home directories')) recipients = [] # list of User objects for all exam users openAttempts = 30 * 60 # wait max. 30 minutes for replication while (len(examUsers) > len(usersReplicated)) and (openAttempts > 0): openAttempts -= 1 MODULE.info( 'waiting for replication to be finished, %s user objects missing' % (len(examUsers) - len(usersReplicated))) for idn in examUsers - usersReplicated: try: ldap_user_read.get(idn, required=True) except ldap.NO_SUCH_OBJECT: continue # not replicated yet iuser = util.distribution.openRecipients( idn, ldap_user_read) if not iuser: continue # not a users/user object MODULE.info('user has been replicated: %s' % idn) # call hook scripts if 0 != subprocess.call([ '/bin/run-parts', CREATE_USER_POST_HOOK_DIR, '--arg', iuser.username, '--arg', iuser.dn, '--arg', iuser.homedir ]): raise ValueError( 'failed to run hook scripts for user %r' % (iuser.username)) # store User object in list of final recipients recipients.append(iuser) # mark the user as replicated usersReplicated.add(idn) progress.info( '%s, %s (%s)' % (iuser.lastname, iuser.firstname, iuser.username)) progress.add_steps(percentPerUser) # wait a second time.sleep(1) progress.add_steps(percentPerUser) if openAttempts <= 0: MODULE.error( 'replication timeout - %s user objects missing: %r ' % ((len(examUsers) - len(usersReplicated)), (examUsers - usersReplicated))) raise UMC_Error( _('Replication timeout: could not create all exam users')) # update the final list of recipients my.project.recipients = recipients my.project.save() # update local NSS group cache if ucr.is_true('nss/group/cachefile', True): cmd = ['/usr/lib/univention-pam/ldap-group-to-file.py'] if ucr.is_true('nss/group/cachefile/check_member', False): cmd.append('--check_member') MODULE.info('Updating local nss group cache...') if subprocess.call(cmd): MODULE.error('Updating local nss group cache failed: %s' % ' '.join(cmd)) else: MODULE.info( 'Update of local nss group cache finished successfully.' ) # distribute exam files progress.component(_('Distributing exam files')) progress.info('') my.project.distribute() progress.add_steps(20) # prepare room settings via UMCP... # first step: acquire room # second step: adjust room settings progress.component(_('Prepare room settings')) try: user_client = Client(None, self.username, self.password) except (ConnectionError, HTTPError) as exc: MODULE.warn('Authentication failed: %s' % (exc, )) raise UMC_Error(_('Could not connect to local UMC server.')) room = request.options['room'] MODULE.info('Acquire room: %s' % (room, )) user_client.umc_command('computerroom/room/acquire', dict( room=request.options['room'], )).result progress.add_steps(1) MODULE.info('Adjust room settings:\n%s' % '\n'.join( [' %s=%s' % (k, v) for k, v in request.options.iteritems()])) user_client.umc_command( 'computerroom/exam/start', dict( room=room, examDescription=request.options['name'], exam=directory, examEndTime=request.options.get('examEndTime'), )).result progress.add_steps(4) user_client.umc_command( 'computerroom/settings/set', dict( room=room, internetRule=request.options['internetRule'], customRule=request.options.get('customRule'), shareMode=request.options['shareMode'], printMode='default', )).result progress.add_steps(5)
def status(self, request): # TODO: remove unneeded things """One call for all single-value variables.""" result = {} ucr.load() try: result['erratalevel'] = int(ucr.get('version/erratalevel', 0)) except ValueError: result['erratalevel'] = 0 result['appliance_mode'] = ucr.is_true('server/appliance') result['easy_mode'] = ucr.is_true('update/umc/updateprocess/easy', False) result['timestamp'] = int(time()) result['reboot_required'] = ucr.is_true('update/reboot/required', False) try: # be as current as possible. what = 'reinitializing UniventionUpdater' self.uu.ucr_reinit() what = 'getting UCS version' result['ucs_version'] = self.uu.get_ucs_version() # if nothing is returned -> convert to empty string. what = 'querying available release updates' try: result[ 'release_update_available'] = self.uu.release_update_available( errorsto='exception') except RequiredComponentError as exc: result['release_update_available'] = exc.version if result['release_update_available'] is None: result['release_update_available'] = '' what = 'querying update-blocking components' blocking_components = self.uu.get_all_available_release_updates( )[1] result['release_update_blocking_components'] = ' '.join( blocking_components or []) what = "querying availability for easy mode" if result['easy_mode']: # updates/available should reflect the need for an update easy_update_available = ucr.is_true('update/available', False) # but dont rely on ucr! update/available is set during univention-upgrade --check # but when was the last time this was run? # release update easy_update_available = easy_update_available or result[ 'release_update_available'] # if no update seems necessary perform a real (expensive) check nonetheless easy_update_available = easy_update_available or self.uu.component_update_available( ) result['easy_update_available'] = bool(easy_update_available) else: result['easy_update_available'] = False # Component counts are now part of the general 'status' data. what = "counting components" c_count = 0 e_count = 0 for comp in self.uu.get_all_components(): c_count = c_count + 1 if ucr.is_true('repository/online/component/%s' % (comp, ), False): e_count = e_count + 1 result['components'] = c_count result['enabled'] = e_count # HACK: the 'Updates' form polls on the serial file # to refresh itself. Including the serial value # into the form helps us to have a dependent field # that can trigger the refresh of the "Releases" # combobox and the 'package updates available' field. result['serial'] = self._serial_file.timestamp() except Exception as exc: # FIXME: don't catch everything typ = str(type(exc)).strip('<>') msg = '[while %s] [%s] %s' % (what, typ, exc) result['message'] = msg result['status'] = 1 MODULE.error(msg) self.finished(request.id, [result])
def is_singlemaster(self): return ucr.is_true('ucsschool/singlemaster', False)
from univention.config_registry import handler_set import univention.directory.reports as udr from .udm_ldap import ( UDM_Error, UDM_Module, ldap_dn2path, get_module, read_syntax_choices, list_objects, _get_syntax, LDAP_Connection, set_bind_function, container_modules, info_syntax_choices, search_syntax_choices_by_key, UserWithoutDN, ObjectDoesNotExist, SuperordinateDoesNotExist, NoIpLeft, LDAP_AuthenticationFailed ) from .tools import LicenseError, LicenseImport, install_opener, urlopen, dump_license, check_license USE_ASTERISKS = ucr.is_true('directory/manager/web/allow_wildcard_search', True) ADD_ASTERISKS = USE_ASTERISKS and ucr.is_true('directory/manager/web/auto_substring_search', True) _ = Translation('univention-management-console-module-udm').translate def sanitize_func(sanitizer_func): from univention.management.console.modules.decorators import copy_function_meta_data, sanitize def _decorated(function): def _response(self, request): sanitizer_parameters = sanitizer_func(self, request) if isinstance(sanitizer_parameters, dict): sanitizer = sanitize(**sanitizer_parameters) else: # if isinstance(sanitizer_parameters, (list, tuple)): sanitizer = sanitize(*sanitizer_parameters)
def status(self, request: Request) -> None: # TODO: remove unneeded things """One call for all single-value variables.""" result = {} # type: Dict[str, Any] ucr.load() try: result['erratalevel'] = int(ucr.get('version/erratalevel', 0)) except ValueError: result['erratalevel'] = 0 result['appliance_mode'] = ucr.is_true('server/appliance') result['timestamp'] = int(time()) result['reboot_required'] = ucr.is_true('update/reboot/required', False) try: # be as current as possible. what = 'reinitializing UniventionUpdater' self.uu.ucr_reinit() what = 'getting UCS version' result['ucs_version'] = str(self.uu.current_version) # if nothing is returned -> convert to empty string. what = 'querying available release updates' try: ver = self.uu.release_update_available(errorsto='exception') result[ 'release_update_available'] = '' if ver is None else str( ver) except RequiredComponentError as exc: result['release_update_available'] = exc.version what = 'querying update-blocking components' blocking_components = self.uu.get_all_available_release_updates( )[1] or set() # check apps if result['release_update_available']: try: from univention.appcenter.actions import get_action update_check = get_action('update-check') if update_check: blocking_apps = update_check.get_blocking_apps( ucs_version=result['release_update_available']) if blocking_apps: blocking_components.update(set(blocking_apps)) except (ImportError, ValueError): # the new univention.appcenter package is not installed. # Cannot be a dependency as the app center depends on updater... raise UMC_Error( _('Error checking if installed apps are available for next UCS version.' )) result['release_update_blocking_components'] = ' '.join( blocking_components) # Component counts are now part of the general 'status' data. what = "counting components" components = [ bool(comp) for comp in self.uu.get_components(all=True) ] result['components'] = len(components) result['enabled'] = sum(components) # HACK: the 'Updates' form polls on the serial file # to refresh itself. Including the serial value # into the form helps us to have a dependent field # that can trigger the refresh of the "Releases" # combobox and the 'package updates available' field. result['serial'] = self._serial_file.timestamp() except Exception as exc: # FIXME: don't catch everything raise UMC_Error("%s %s %s" % ( _('Error contacting the update server. Please check your proxy or firewall settings, if any. Or it may be a problem with your configured DNS server.' ), _('This is the error message:'), exc, ), traceback=format_exc()) self.finished(request.id, [result])
def _create_disks( self, node_uri, disks, domain_info, profile = None ): drives = [] uri = urlparse.urlsplit( node_uri ) for disk in disks: drive = Disk() # do we create a new disk or just copy data from an already defined drive create_new = disk.get( 'source', None ) is None drive.device = disk[ 'device' ] drive.driver_type = disk[ 'driver_type' ] drive.driver_cache = disk.get('driver_cache', 'default') # set old values of existing drive if not create_new: drive.source = disk[ 'source' ] drive.driver = disk[ 'driver' ] drive.target_bus = disk[ 'target_bus' ] drive.target_dev = disk[ 'target_dev' ] if disk[ 'size' ] is not None: drive.size = MemorySize.str2num( disk[ 'size' ], unit = 'MB' ) else: # when changing the medium of a CDROM we must keep the target drive.target_bus = disk.get( 'target_bus', None ) drive.target_dev = disk.get( 'target_dev', None ) # creating new drive pool_path = self.get_pool_path( node_uri, disk.get( 'pool' ) ) file_pool = self.is_file_pool( node_uri, disk.get( 'pool' ) ) if pool_path: drive.source = os.path.join( pool_path, disk[ 'volumeFilename' ] ) elif not file_pool and disk.get( 'volumeType', Disk.TYPE_BLOCK ) and disk[ 'volumeFilename' ]: drive.source = disk[ 'volumeFilename' ] elif drive.source is None: raise ValueError( _( 'No valid source for disk "%s" found' ) % drive.device ) if file_pool: drive.type = Disk.TYPE_FILE else: drive.type = Disk.TYPE_BLOCK drive.target_bus = 'ide' drive.source = disk[ 'volumeFilename' ] # get default for paravirtual if create_new: if profile is not None: if drive.device == Disk.DEVICE_DISK: driver_pv = getattr( profile, 'pvdisk', False ) elif drive.device == Disk.DEVICE_CDROM: driver_pv = getattr( profile, 'pvcdrom', False ) else: driver_pv = disk.get( 'paravirtual', False ) # by default no paravirtual devices else: driver_pv = disk.get( 'paravirtual', False ) # by default no paravirtual devices MODULE.info( 'Creating a %s drive' % ( driver_pv and 'paravirtual' or 'non-paravirtual' ) ) if drive.device in ( Disk.DEVICE_DISK, Disk.DEVICE_CDROM ): if drive.device == Disk.DEVICE_CDROM: drive.driver_type = 'raw' # ISOs need driver/@type='raw' elif drive.device == Disk.DEVICE_FLOPPY: drive.target_bus = 'fdc' else: raise ValueError('Invalid drive-type "%s"' % drive.device) if uri.scheme.startswith( 'qemu' ): drive.driver = 'qemu' if driver_pv and drive.device != Disk.DEVICE_FLOPPY and drive.type != Disk.TYPE_BLOCK: drive.target_bus = 'virtio' elif disk.get( 'paravirtual', None ) == False and not drive.target_bus: drive.target_bus = 'ide' elif uri.scheme.startswith( 'xen' ): pv_domain = domain_info.os_type == 'xen' if driver_pv and drive.device != Disk.DEVICE_FLOPPY and drive.type != Disk.TYPE_BLOCK: drive.target_bus = 'xen' elif pv_domain and not driver_pv: # explicitly set ide bus drive.target_bus = 'ide' # block devices of para-virtual xen instances must use bus xen if pv_domain and drive.type == Disk.TYPE_BLOCK: drive.target_bus = 'xen' # Since UCS 2.4-2 Xen 3.4.3 contains the blktab2 driver # from Xen 4.0.1 if file_pool: # Use tapdisk2 by default, but not for empty CDROM drives if drive.source is not None and ucr.is_true( 'uvmm/xen/images/tap2', True ): drive.driver = 'tap2' drive.driver_type = 'aio' # if drive.type == 'raw': # drive.driver_type = 'aio' else: drive.driver = 'file' drive.driver_type = None # only raw support else: drive.driver = 'phy' else: raise ValueError( 'Unknown virt-tech "%s"' % node_uri ) if disk[ 'size' ]: drive.size = MemorySize.str2num( disk[ 'size' ], unit = 'MB' ) drives.append( drive ) return drives