def _check_usersid_join_permissions(self, lo, usersid): allowed_groups = ucr.get('ucsschool/windows/join/groups', 'Domain Admins').split(',') result = lo.searchDn( ldap.filter.filter_format('sambaSID=%s', [usersid])) if not result: raise UMC_Error('SID %s was not found.' % (usersid, )) user_dn = result[0] MODULE.info("Found user with DN %s" % (user_dn, )) result = lo.search(ldap.filter.filter_format('uniqueMember=%s', [user_dn]), attr=['cn']) if not result: raise UMC_Error('No group memberships for SID %s found.' % (usersid, )) for dn, attr in result: if attr.get('cn', [])[0] in allowed_groups: return raise UMC_Error( 'SID %s is not member of one of the following groups: %s. The allowed groups can be modified by setting the UCR variable ucsschool/windows/join/groups.' % (usersid, allowed_groups))
def check_domain(self, username, password, ad_server_address, mode): ad_domain_info = {} try: if mode == 'admember': admember.check_server_role() ad_domain_info = admember.lookup_adds_dc(ad_server_address) ad_server_ip = ad_domain_info['DC IP'] if mode == 'admember': admember.check_domain(ad_domain_info) admember.check_connection(ad_domain_info, username, password) admember.check_ad_account(ad_domain_info, username, password) except admember.invalidUCSServerRole as exc: # check_server_role() MODULE.warn('Failure: %s' % exc) raise UMC_Error( _('The AD member mode can only be configured on a DC master server.' )) except admember.failedADConnect as exc: # lookup_adds_dc() MODULE.warn('Failure: %s' % exc) raise UMC_Error( _('Could not connect to AD Server %s. Please verify that the specified address is correct. (%s)' ) % (ad_server_address, 'check_domain: %s' % (exc, ))) except admember.domainnameMismatch as exc: # check_domain() MODULE.warn('Failure: %s' % exc) raise UMC_Error( _('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.get("Domain"), 'ucs_domain': ucr['domainname'] }) except admember.connectionFailed as exc: # check_connection() MODULE.warn('Failure: %s' % exc) raise UMC_Error( _('Could not connect to AD Server %s. Please verify that username and password are correct. (Details:\n%s)' ) % (ad_domain_info.get('DC DNS Name'), exc)) except admember.notDomainAdminInAD as exc: # check_ad_account() MODULE.warn('Failure: %s' % exc) raise UMC_Error( _('The given user is not member of the Domain Admins group in Active Directory. This is a requirement for the Active Directory domain join.' )) # final info dict that is returned... replace spaces in the keys with '_' MODULE.info('Preparing info dict...') info = dict([(key.replace(' ', '_'), value) for key, value in ad_domain_info.iteritems()]) info['ssl_supported'] = admember.server_supports_ssl(ad_server_ip) # try to get binddn info['LDAP_BindDN'] = get_ad_binddn_from_name(info['LDAP_Base'], ad_server_ip, username, password) MODULE.info(str(info)) return info
def _change_services(self, services, action): error_messages = [] for srv in services: process = subprocess.Popen(('/usr/sbin/service', srv, action), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) output = process.communicate()[0] if process.returncode: try: MODULE.warn('Error during %s of %s: %s' % (action, srv, output.strip())) process = subprocess.Popen( ('/bin/systemctl', 'status', srv), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) output = process.communicate()[0] except EnvironmentError: pass error_messages.append( '%s\n%s' % ({ 'start': _('Starting the service %s failed:'), 'stop': _('Stopping the service %s failed:'), 'restart': _('Restarting the service %s failed:'), }[action] % srv, output.strip())) if error_messages: raise UMC_Error('\n\n'.join(error_messages)) return {'success': True}
def add(self, request): # does the same as put ucr.load() already_set = set(ucr.keys()) & set(v['object']['key'] for v in request.options) if already_set: raise UMC_Error(_('The UCR variable %s is already set.') % ('", "'.join(already_set))) self.put(request)
def remove(self, request): variables = [x for x in [x.get('object') for x in request.options] if x is not None] for var in variables: if self.is_readonly(var): raise UMC_Error(_('The UCR variable %s is read-only and can not be removed!') % (var,)) handler_unset(variables) self.finished(request.id, True)
def _change_start_type(self, service_names, start_type): service_info = ServiceInfo() services = [(service_name, service_info.services[service_name]) for service_name in service_names if service_name in service_info.services] values = ['%s=%s' % (service.get('start_type', '%s/autostart' % (service_name,)), start_type) for service_name, service in services] univention.config_registry.handler_set(values) failed = [x for x in service_names if not service_info.services.get(x)] if failed: raise UMC_Error('%s %s' % (_('Could not change start type of the following services:'), ', '.join(failed)))
def _check_error(self, request, partition_name): # TODO try: fs = fstab.File() mt = mtab.File() except IOError as error: MODULE.error('Could not open %s' % error.filename) raise ValueError(_('Could not open %s') % error.filename) partition = fs.find(spec=partition_name) if partition: mounted_partition = mt.get(partition.spec) if mounted_partition: if 'usrquota' not in mounted_partition.options and 'usrjquota=aquota.user' not in mounted_partition.options: raise UMC_Error(_('The following partition is mounted without quota support: %s') % partition_name) else: raise UMC_Error(_('The following partition is currently not mounted: %s') % partition_name) else: raise UMC_Error(_('No partition found (%s)') % partition_name)
def get(self, request): """get a specific item of self.data""" try: item = self.data[request.options['item']] except IndexError: MODULE.error('A invalid item was accessed.') raise UMC_Error(_('The item %d does not exists.') % (request.options['item'], ), status=400) self.finished(request.id, self.data[item])
def create_windows_computer(self, request, ldap_user_read=None, ldap_admin_write=None, ldap_position=None, search_base=None): if not search_base.school: raise UMC_Error(_('Could not determine schoolOU.')) # Set new position ldap_position.setDn(search_base.computers) self._check_usersid_join_permissions(ldap_user_read, request.options.get('usersid')) # Create the computer account computer = univention.admin.handlers.computers.windows.object( None, ldap_admin_write, position=ldap_position, superordinate=None) computer.open() name = request.options.get('name') if name[-1] == '$': # Samba 3 calls the name in this way name = name[:-1] # In Samba 3 the samba attributes must be set by Samba itself samba3_mode = request.options.get('samba3_mode') if samba3_mode and samba3_mode.lower() in ['true', 'yes']: computer.options = ['posix'] computer['name'] = name password = request.options.get('password') if password: decode_password = request.options.get('decode_password') if decode_password and decode_password.lower() in ['true', 'yes']: # the password is base64 encoded password = base64.decodestring(password) # decode from utf-16le password = password.decode('utf-16le') # and remove the quotes password = password.strip('"') computer['password'] = password computer['description'] = request.options.get('description') try: computer_dn = computer.create() already_exists = False except univention.admin.uexceptions.objectExists as exc: already_exists = True computer_dn = exc.args[0] self.finished(request.id, { 'dn': computer_dn, 'already_exists': already_exists })
def remove(self, request): variables = filter(lambda x: x is not None, map(lambda x: x.get('object'), request.options)) for var in variables: if self.is_readonly(var): raise UMC_Error( _('The UCR variable %s is read-only and can not be removed!' ) % (var, )) handler_unset(variables) self.finished(request.id, True)
def put(self, request): for _var in request.options: var = _var['object'] value = var['value'] or '' key = var['key'] if self.is_readonly(key): raise UMC_Error(_('The UCR variable %s is read-only and can not be changed!') % (key,)) arg = ['%s=%s' % (key.encode(), value.encode())] handler_set(arg) # handle descriptions, type, and categories if 'descriptions' in var or 'type' in var or 'categories' in var: self.__create_variable_info(var) self.finished(request.id, True)
def _thread(request): partition = request.options['partitionDevice'] user = request.options['user'] if isinstance(user, unicode): user = user.encode('utf-8') size_soft = request.options['sizeLimitSoft'] size_hard = request.options['sizeLimitHard'] file_soft = request.options['fileLimitSoft'] file_hard = request.options['fileLimitHard'] self._check_error(request, partition) if tools.setquota(partition, user, tools.byte2block(size_soft), tools.byte2block(size_hard), file_soft, file_hard): raise UMC_Error(_('Failed to modify quota settings for user %(user)s on partition %(partition)s.') % {'user': user, 'partition': partition}) return {'objects': [], 'success': True}
def _enable_ssl_and_test_connection(self, certificate_fname=None): with ucr_rollback(ucr, ['connector/ad/ldap/ssl', 'connector/ad/ldap/certificate']): if certificate_fname: univention.config_registry.handler_set([u'connector/ad/ldap/certificate=%s' % certificate_fname]) server = ucr.get('connector/ad/ldap/host') if server: success = False if admember.server_supports_ssl(server): admember.enable_ssl() try: success = test_connection() except ADNotAvailable: success = False if not success: raise UMC_Error(_('Could not establish an encrypted connection. Either "%r" is not reachable or does not support encryption.') % server) else: MODULE.warn('connector is not configured yet, cannot test connection')
def load(self, request): user, mailbox = getUserAndMailbox(self._user_dn) raise UMC_Error("Es wurde kein Asterisk-Server angelegt!") result = { "phones/interval": user["ringdelay"], "forwarding/number": user.get("forwarding", ""), "mailbox/timeout": user["timeout"], "mailbox": False, } if mailbox: result.update({ "mailbox": True, "mailbox/password": mailbox["password"], "mailbox/email": mailbox["email"], }) self.finished(request.id, result)
def _change_services(self, services, action): error_messages = [] srvs = ServiceInfo() for srv in services: service = srvs.get_service(srv) try: getattr(service, action)() except ServiceError as exc: MODULE.warn('Error during %s of %s: %s' % (action, srv, exc)) error_messages.append( '%s\n%s' % ({ 'start': _('Starting the service %s failed:'), 'stop': _('Stopping the service %s failed:'), 'restart': _('Restarting the service %s failed:'), }[action] % srv, exc)) if error_messages: raise UMC_Error('\n\n'.join(error_messages)) return {'success': True}
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 get(self, request): ucrReg = ConfigRegistry() ucrReg.load() ucrInfo = ConfigRegistryInfo(registered_only=False) # iterate over all requested variables results = [] for key in request.options: info = ucrInfo.get_variable(str(key)) value = ucrReg.get(str(key)) if not info and (value or '' == value): # only the value available results.append({'key': key, 'value': value}) elif info: # info (categories etc.) available info['value'] = value info['key'] = key results.append(info.normalize()) else: # variable not available, request failed raise UMC_Error(_('The UCR variable %(key)s could not be found') % {'key': key}) self.finished(request.id, results)
def iter_objects_in_request(request, lo, require_dn=False): klass = { 'schoolwizards/schools': School, 'schoolwizards/users': User, 'schoolwizards/computers': SchoolComputer, 'schoolwizards/classes': SchoolClass, }[request.flavor] for obj_props in request.options: obj_props = obj_props['object'] for key, value in obj_props.iteritems(): if isinstance(value, basestring): obj_props[key] = value.strip() if issubclass(klass, User): klass = USER_TYPES.get(obj_props.get('type'), User) elif issubclass(klass, SchoolComputer): klass = COMPUTER_TYPES.get(obj_props.get('type'), SchoolComputer) dn = obj_props.get('$dn$') if 'name' not in obj_props: # important for get_school in district_mode! obj_props['name'] = klass.get_name_from_dn(dn) if issubclass(klass, SchoolClass): # workaround to be able to reuse this function everywhere obj_props['name'] = '%s-%s' % (obj_props['school'], obj_props['name']) if require_dn: try: obj = klass.from_dn(dn, obj_props.get('school'), lo) except noObject: raise UMC_Error(_('The %s %r does not exists or might have been removed in the meanwhile.') % (getattr(klass, 'type_name', klass.__name__), obj_props['name'])) for key, value in obj_props.iteritems(): if key in obj._attributes: setattr(obj, key, value) else: obj = klass(**obj_props) if dn: obj.old_dn = dn yield obj
def get_schoolinfo_master(self, school): """ Fetches LDAP information from master about specified OU. This function assumes that the given arguments have already been validated! """ school_name = school try: lo, po = get_machine_connection(write=True) school = School.from_dn(School(name=school_name).dn, None, lo) except noObject: exists = False class_share_server = None home_share_server = None educational_slaves = [] administrative_slaves = [] except ldap.SERVER_DOWN: raise # handled via UMC except ldap.LDAPError as exc: MODULE.warn('LDAP error during receiving school info: %s' % (exc,)) raise UMC_Error(_('The LDAP connection to the master system failed.')) else: exists = True class_share_server = school.class_share_file_server home_share_server = school.home_share_file_server educational_slaves = [SchoolDCSlave.from_dn(dn, None, lo).name for dn in school.educational_servers] administrative_slaves = [SchoolDCSlave.from_dn(dn, None, lo).name for dn in school.administrative_servers] return { 'exists': exists, 'school': school_name, 'classShareServer': class_share_server, 'homeShareServer': home_share_server, 'educational_slaves': educational_slaves, 'administrative_slaves': administrative_slaves, }