コード例 #1
0
ファイル: NTPPlugin.py プロジェクト: 650elx/middleware
    def verify(self, id, updated_fields, force=False):

        ntp = self.datastore.get_by_id('ntpservers', id)
        if ntp is None:
            raise VerifyException(errno.ENOENT, 'NTP Server with given ID does not exist')

        errors = ValidationException()

        try:
            if 'address' in updated_fields:
                system('ntpdate', '-q', updated_fields['address'])
        except SubprocessException:
            if not force:
                errors.append((
                    'address',
                    errno.EINVAL,
                    'Server could not be reached. Check "Force" to continue regardless.'))

        minpoll = updated_fields.get('minpoll', ntp.get('minpoll'))
        maxpoll = updated_fields.get('maxpoll', ntp.get('maxpoll'))

        if minpoll is not None and maxpoll is not None and not maxpoll > minpoll:
            errors.append(('maxpoll', errno.EINVAL, 'Max Poll should be higher than Min Poll'))

        if errors:
            raise ValidationException(errors)

        return ['system']
コード例 #2
0
    def verify(self, certificate):

        if self.datastore.exists('crypto.certificates', ('name', '=', certificate['name'])):
            raise VerifyException(errno.EEXIST, 'Certificate with given name already exists')

        if certificate['type'] not in ('CERT_EXISTING', 'CA_EXISTING'):
            raise VerifyException(errno.EINVAL, 'Invalid certificate type')

        errors = ValidationException()
        for i in ('country', 'state', 'city', 'organization', 'email', 'common'):
            if i in certificate:
                errors.add((0, i), '{0} is not valid in certificate import'.format(i))
        if errors:
            raise errors

        if certificate['type'] == 'CERT_EXISTING' and (
            'privatekey' not in certificate or
            'passphrase' not in certificate
        ):
            raise VerifyException(
                errno.EINVAL, 'privatekey and passphrase required to import certificate'
            )

        try:
            if 'privatekey' in certificate:
                load_privatekey(certificate['privatekey'], certificate.get('passphrase'))
        except Exception:
            raise VerifyException(errno.EINVAL, 'Invalid passphrase')

        return ['system']
コード例 #3
0
ファイル: DebugPlugin.py プロジェクト: erinix/middleware
 def verify(self, path, logs=True, cores=False):
     errors = ValidationException()
     if path in [None, ''] or path.isspace():
         errors.add((0, 'path'), 'The Path is required', code=errno.EINVAL)
     if errors:
         raise errors
     return []
コード例 #4
0
ファイル: DebugPlugin.py プロジェクト: freenas/middleware
 def verify(self, path):
     errors = ValidationException()
     if path in [None, ''] or path.isspace():
         errors.add((0, 'path'), 'The Path is required', code=errno.EINVAL)
     if errors:
         raise errors
     return ['system']
コード例 #5
0
    def run(self, id, updated_fields):
        service_def = self.datastore.get_by_id('service_definitions', id)
        node = ConfigNode('service.{0}'.format(service_def['name']), self.configstore)
        restart = False
        reload = False
        updated_config = updated_fields.get('config')

        if updated_config is None:
            return

        del updated_config['type']

        if service_def.get('task'):
            enable = updated_config.pop('enable', None)

            try:
                self.verify_subtask(service_def['task'], updated_config)
            except RpcException as err:
                new_err = ValidationException()
                new_err.propagate(err, [0], [1, 'config'])
                raise new_err

            result = self.join_subtasks(self.run_subtask(service_def['task'], updated_config))
            restart = result[0] == 'RESTART'
            reload = result[0] == 'RELOAD'

            if enable is not None:
                node['enable'] = enable
        else:
            node.update(updated_config)

            if service_def.get('etcd-group'):
                self.dispatcher.call_sync('etcd.generation.generate_group', service_def.get('etcd-group'))

            if 'enable' in updated_config:
                # Propagate to dependent services
                for i in service_def.get('dependencies', []):
                    svc_dep = self.datastore.get_by_id('service_definitions', i)
                    self.join_subtasks(self.run_subtask('service.update', i, {
                        'config': {
                            'type': 'service-{0}'.format(svc_dep['name']),
                            'enable': updated_config['enable']
                        }
                    }))

                if service_def.get('auto_enable'):
                    # Consult state of services dependent on us
                    for i in self.datastore.query('service_definitions', ('dependencies', 'in', service_def['name'])):
                        enb = self.configstore.get('service.{0}.enable', i['name'])
                        if enb != updated_config['enable']:
                            del updated_config['enable']
                            break

        self.dispatcher.call_sync('etcd.generation.generate_group', 'services')
        self.dispatcher.call_sync('service.apply_state', service_def['name'], restart, reload, timeout=30)
        self.dispatcher.dispatch_event('service.changed', {
            'operation': 'update',
            'ids': [service_def['id']]
        })
コード例 #6
0
ファイル: RsyncdPlugin.py プロジェクト: freenas/middleware
    def verify(self, rsyncmod):
        errors = ValidationException()

        if re.search(r'[/\]]', rsyncmod['name']):
            errors.add((0, 'name'), 'The name cannot contain slash or a closing square backet.')

        if errors:
            raise errors

        return ['system']
コード例 #7
0
ファイル: UserPlugin.py プロジェクト: abwaters/middleware
    def verify(self, user):
        errors = ValidationException()
        normalize_name(user, 'username')

        for code, message in check_unixname(user['username']):
            errors.add((0, 'username'), message, code=code)

        if self.datastore.exists('users', ('username', '=', user['username'])):
            raise VerifyException(errno.EEXIST, 'User with given name already exists')

        if 'groups' in user and len(user['groups']) > 64:
            errors.add(
                (0, 'groups'),
                'User cannot belong to more than 64 auxiliary groups'
            )

        if user.get('full_name') and ':' in user['full_name']:
            errors.add((0, 'full_name'), 'The character ":" is not allowed')

        if 'email' in user:
            if not EMAIL_REGEX.match(user['email']):
                errors.add(
                    (0, 'email'),
                    "{0} is an invalid email address".format(user['email'])
                )

        if errors:
            raise errors

        return ['system']
コード例 #8
0
    def verify(self, certificate):

        errors = ValidationException()

        if certificate['type'] == 'CERT_INTERNAL':
            if self.datastore.exists('crypto.certificates', ('name', '=', certificate['name'])):
                errors.add((0, 'name'), 'Certificate with given name already exists', code=errno.EEXIST)

            if not self.datastore.exists('crypto.certificates', ('id', '=', certificate['signedby'])):
                errors.add((0, 'signedby'), 'Signing certificate does not exist', code=errno.EEXIST)

            if '"' in certificate['name']:
                errors.add((
                    (0, 'name'),
                    'You cannot issue a certificate with a `"` in its name')
                )

        if certificate['type'] in ('CERT_INTERNAL', 'CA_INTERMEDIATE'):
            if 'signedby' not in certificate or not self.datastore.exists('crypto.certificates', ('id', '=', certificate['signedby'])):
                errors.add((0, 'signedby'), 'Signing Certificate does not exist', code=errno.EEXIST)

        if errors:
            raise errors

        return ['system']
コード例 #9
0
ファイル: UserPlugin.py プロジェクト: freenas/middleware
    def verify(self, group):
        errors = ValidationException()
        normalize_name(group, 'name')

        for code, message in check_unixname(group['name']):
            errors.add((0, 'name'), message, code=code)

        if errors:
            raise errors

        return ['system']
コード例 #10
0
ファイル: IPFSPlugin.py プロジェクト: 650elx/middleware
    def verify(self, ipfs):
        errors = ValidationException()

        if 'path' in ipfs:
            if ipfs['path'] in [None, ''] or ipfs['path'].isspace():
                errors.add((0, path), "The provided path: '{0}' is not valid".format(ipfs['path']))

        if errors:
            raise errors

        return ['system']
コード例 #11
0
    def verify(self, props):
        errors = ValidationException()
        if 'timezone' in props:
            timezones = self.dispatcher.call_sync('system.general.timezones')
            if props['timezone'] not in timezones:
                errors.add((0, 'timezone'), 'Invalid timezone: {0}'.format(props['timezone']))

        if errors:
            raise errors

        return ['system']
コード例 #12
0
ファイル: UserPlugin.py プロジェクト: freenas/middleware
    def verify(self, id, updated_fields):
        errors = ValidationException()
        normalize_name(updated_fields, 'name')

        if 'name' in updated_fields:
            for code, message in check_unixname(updated_fields['name']):
                errors.add((1, 'name'), message, code=code)

        if errors:
            raise errors

        return ['system']
コード例 #13
0
ファイル: AFPPlugin.py プロジェクト: 650elx/middleware
    def verify(self, afp):

        errors = ValidationException()
        dbpath = afp.get('dbpath')
        if dbpath:
            if not os.path.exists(dbpath):
                errors.add((0, 'dbpath'), 'Path does not exist', code=errno.ENOENT)
            elif not os.path.isdir(dbpath):
                errors.add((0, 'dbpath'), 'Path is not a directory')

        if errors:
            raise errors

        return ['system']
コード例 #14
0
    def verify(self, lldp):
        errors = ValidationException()
        node = ConfigNode('service.lldp', self.configstore).__getstate__()
        node.update(lldp)

        # Lazy load pycountry due to extra verbose DEBUG logging
        import pycountry
        if node['country_code'] and node['country_code'] not in pycountry.countries.indices['alpha2']:
            errors.add((0, 'country_code'), 'Invalid ISO-3166 alpha 2 code')

        if errors:
            raise errors

        return ['system']
コード例 #15
0
ファイル: MailPlugin.py プロジェクト: 650elx/middleware
    def verify(self, mail):
        errors = ValidationException()
        node = ConfigNode('mail', self.configstore).__getstate__()

        if mail.get('auth'):
            if not mail.get('user') and not node['user']:
                errors.add((0, 'auth'), 'Mail authorization requires a username')
            if not mail.get('pass') and not node['pass']:
                errors.add((0, 'auth'), 'Mail authorization requires a password')

        if errors:
            raise errors

        return []
コード例 #16
0
ファイル: MailPlugin.py プロジェクト: freenas/middleware
    def verify(self, mail):
        errors = ValidationException()
        node = ConfigNode("mail", self.configstore).__getstate__()

        if mail.get("auth"):
            if not mail.get("user") and not node["user"]:
                errors.add((0, "auth"), "Mail authorization requires a username")
            if not mail.get("pass") and not node["pass"]:
                errors.add((0, "auth"), "Mail authorization requires a password")

        if errors:
            raise errors

        return []
コード例 #17
0
ファイル: TunablePlugin.py プロジェクト: erinix/middleware
    def verify(self, id, updated_fields):

        errors = ValidationException()

        if 'var' in updated_fields and self.datastore.exists(
            'tunables', ('and', [('var', '=', updated_fields['var']), ('id', '!=', id)])
        ):
            errors.add((1, 'var'), 'This variable already exists.', code=errno.EEXIST)

        if 'value' in updated_fields:
            if '"' in updated_fields['value'] or "'" in updated_fields['value']:
                errors.add((1, 'value'), 'Quotes are not allowed')

        if errors:
            raise errors

        return ['system']
コード例 #18
0
    def verify(self, uuid, updated_fields):

        rsyncmod = self.datastore.get_by_id('rsyncd-module', uuid)
        if rsyncmod is None:
            raise VerifyException(errno.ENOENT, 'Rsync module {0} does not exist'.format(uuid))

        rsyncmod.update(updated_fields)

        errors = ValidationException()

        if re.search(r'[/\]]', rsyncmod['name']):
            errors.add((1, 'name'), 'The name cannot contain slash or a closing square backet.')

        if errors:
            raise errors

        return ['system']
コード例 #19
0
ファイル: SMBPlugin.py プロジェクト: 650elx/middleware
    def verify(self, smb):
        errors = ValidationException()
        node = ConfigNode('service.smb', self.configstore).__getstate__()

        netbiosname = smb.get('netbiosname')
        if netbiosname is not None:
            for n in netbiosname:
                if not validate_netbios_name(n):
                    errors.add((0, 'netbiosname'), 'Invalid name {0}'.format(n))
        else:
            netbiosname = node['netbiosname']

        workgroup = smb.get('workgroup')
        if workgroup is not None:
            if not validate_netbios_name(workgroup):
                errors.add((0, 'workgroup'), 'Invalid name')
        else:
            workgroup = node['workgroup']

        if workgroup.lower() in [i.lower() for i in netbiosname]:
            errors.add((0, 'netbiosname'), 'NetBIOS and Workgroup must be unique')

        if errors:
            raise errors

        return ['system']
コード例 #20
0
ファイル: UserPlugin.py プロジェクト: abwaters/middleware
    def verify(self, group):
        errors = ValidationException()
        normalize_name(group, 'name')

        for code, message in check_unixname(group['name']):
            errors.add((0, 'name'), message, code=code)

        if self.datastore.exists('groups', ('name', '=', group['name'])):
            errors.add(
                (0, "name"),
                'Group {0} already exists'.format(group['name']),
                code=errno.EEXIST
            )

        if 'gid' in group and self.datastore.exists('groups', ('gid', '=', group['gid'])):
            errors.add(
                (0, "gid"),
                'Group with GID {0} already exists'.format(group['gid']),
                code=errno.EEXIST
            )

        if errors:
            raise errors

        return ['system']
コード例 #21
0
    def verify(self, id, updated_fields):
        errors = ValidationException()

        if 'name' in updated_fields:
            for code, message in check_unixname(updated_fields['name']):
                errors.add((1, 'name'), message, code=code)

            # Check if there is another group with same name being renamed to
            if self.datastore.exists('groups', ('name', '=', updated_fields['name']), ('id', '!=', id)):
                errors.add(
                    (1, "name"),
                    'Group {0} already exists'.format(updated_fields['name']),
                    code=errno.EEXIST
                )

        if errors:
            raise errors

        return ['system']
コード例 #22
0
ファイル: NTPPlugin.py プロジェクト: 650elx/middleware
    def verify(self, ntp, force=False):
        errors = ValidationException()

        try:
            system('ntpdate', '-q', ntp['address'])
        except SubprocessException:
            if not force:
                errors.add(
                    (0, 'address'),
                    'Server could not be reached. Check "Force" to continue regardless.'
                )

        minpoll = ntp.get('minpoll', 6)
        maxpoll = ntp.get('maxpoll', 10)

        if not maxpoll > minpoll:
            errors.add((0, 'maxpoll'), 'Max Poll should be higher than Min Poll')

        if errors:
            raise errors

        return ['system']
コード例 #23
0
    def verify(self, params):
        errors = ValidationException()

        if self.datastore.get_one('users', ('username', '=', params.get('user'))) is None:
            raise VerifyException(
                errno.ENOENT, 'User {0} does not exist'.format(params.get('user'))
            )

        path = params.get('path')
        rmode = params.get('rsync_mode')
        remote_path = params.get('remote_path')
        remote_host = params.get('remote_host')
        remote_module = params.get('remote_module')

        if path in [None, ''] or path.isspace():
            errors.append(('path', errno.EINVAL, 'The Path is required'))
        elif not os.path.exists(path):
            raise VerifyException(
                errno.ENOENT,
                "The specified path: '{0}'' does not exist".format(params.get('path'))
            )
        if (
            params.get('remote_host') in ['127.0.0.1', 'localhost'] and
            rmode == 'SSH' and
            remote_path is not None and
            not os.path.exists(remote_path)
           ):
            raise VerifyException(
                errno.ENOENT,
                "The specified path: '{0}'' does not exist".format(remote_path)
            )

        if rmode == 'SSH' and (remote_path in [None, ''] or remote_path.isspace()):
            errors.append(('remote_path', errno.EINVAL, 'The Remote Path is required'))
        elif rmode == 'MODULE' and (remote_module in [None, ''] or remote_module.isspace()):
            errors.append(('remote_module', errno.EINVAL, 'The Remote Module is required'))

        if remote_host in [None, ''] or remote_host.isspace():
            errors.append(('remote_host', errno.EINVAL, 'A Remote Host needs to be specified'))
        if errors:
            raise ValidationException(errors)

        return []
コード例 #24
0
ファイル: TunablePlugin.py プロジェクト: erinix/middleware
    def verify(self, tunable):

        errors = ValidationException()

        if '"' in tunable['value'] or "'" in tunable['value']:
            errors.add((1, 'value'), 'Quotes are not allowed')

        if tunable['type'] in ('LOADER', 'RC') and not VAR_LOADER_RC_RE.match(tunable['var']):
            errors.add((1, 'var'), VAR_SYSCTL_FORMAT)
        elif tunable['type'] == 'SYSCTL':
            if not VAR_SYSCTL_RE.match(tunable['var']):
                errors.add((1, 'var'), VAR_LOADER_RC_FORMAT)
            try:
                sysctl.sysctlnametomib(tunable['var'])
            except OSError:
                errors.add((1, 'var'), 'Sysctl variable does not exist')

        if errors:
            raise errors

        return ['system']
コード例 #25
0
    def verify(self, ups):
        errors = ValidationException()
        node = ConfigNode('service.ups', self.configstore).__getstate__()
        node.update(ups)

        if node['mode'] == 'MASTER' and not node['driver_port']:
            errors.add((0, 'driver_port'), 'This field is required')

        if node['mode'] == 'SLAVE' and not node['remote_host']:
            errors.add((0, 'remote_host'), 'This field is required')

        if not re.search(r'^[a-z0-9\.\-_]+$', node['identifier'], re.I):
            errors.add((0, 'identifier'), 'Use alphanumeric characters, ".", "-" and "_"')

        for i in ('monitor_user', 'monitor_password'):
            if re.search(r'[ #]', node[i], re.I):
                errors.add((0, i), 'Spaces or number signs are not allowed')

        if errors:
            raise errors

        return ['system']
コード例 #26
0
    def verify(self, webdav):
        errors = ValidationException()
        node = ConfigNode('service.webdav', self.configstore).__getstate__()
        node.update(webdav)

        if node['http_port'] == node['https_port']:
            errors.add((0, 'http_port'), 'HTTP and HTTPS ports cannot be the same')

        if 'HTTPS' in node['protocol'] and not node['certificate']:
            errors.add((0, 'certificate'), 'SSL protocol specified without choosing a certificate')

        if node['certificate']:
            cert = self.dispatcher.call_sync('crypto.certificate.query', [('id', '=', node['certificate'])])
            if not cert:
                errors.add((0, 'certificate'), 'SSL Certificate not found.')

        if errors:
            raise errors

        return ['system']
コード例 #27
0
    def verify(self, ftp):
        errors = ValidationException()
        node = ConfigNode('service.ftp', self.configstore).__getstate__()
        node.update(ftp)

        pmin = node['passive_ports_min']
        if 'passive_ports_min' in ftp:
            if pmin and (pmin < 1024 or pmin > 65535):
                errors.add((0, 'passive_ports_min'), 'This value must be between 1024 and 65535, inclusive.')

        pmax = node['passive_ports_max']
        if 'passive_ports_max' in ftp:
            if pmax and (pmax < 1024 or pmax > 65535):
                errors.add((0, 'passive_ports_max'), 'This value must be between 1024 and 65535, inclusive.')
            elif pmax and pmin and pmin >= pmax:
                errors.add((0, 'passive_ports_max'),  'This value must be higher than minimum passive port.')

        if node['only_anonymous'] and not node['anonymous_path']:
            errors.add(
                ((0, 'anonymous_path'), errno.EINVAL, 'This field is required for anonymous login.')
            )

        if node['tls'] is True and not node['tls_ssl_certificate']:
            errors.add((0, 'tls_ssl_certificate'), 'TLS specified without certificate.')

        if node['tls_ssl_certificate']:
            cert = self.dispatcher.call_sync('crypto.certificate.query', [('id', '=', node['tls_ssl_certificate'])])
            if not cert:
                errors.add((0, 'tls_ssl_certificate'), 'SSL Certificate not found.')

        if errors:
            raise errors

        return ['system']
コード例 #28
0
    def verify(self, id, updated_fields):

        tunable = self.datastore.get_by_id('tunables', id)
        if tunable is None:
            raise VerifyException(errno.ENOENT, 'Tunable with given ID does not exist')

        errors = ValidationException()

        if 'var' in updated_fields and self.datastore.exists(
            'tunables', ('and', [('var', '=', updated_fields['var']), ('id', '!=', id)])
        ):
            errors.add((1, 'var'), 'This variable already exists.', code=errno.EEXIST)

        if 'value' in updated_fields and '"' in updated_fields['value'] or "'" in updated_fields['value']:
            errors.add((1, 'value'), 'Quotes are not allowed')

        if 'type' in updated_fields:
            if updated_fields['type'] in ('LOADER', 'RC') and not VAR_LOADER_RC_RE.match(tunable['var']):
                errors.add((1, 'var'), VAR_SYSCTL_FORMAT)
            elif updated_fields['type'] == 'SYSCTL':
                if not VAR_SYSCTL_RE.match(tunable['var']):
                    errors.add((1, 'var'), VAR_LOADER_RC_FORMAT)
                try:
                    sysctl.sysctlnametomib(tunable['var'])
                except OSError:
                    errors.add((1, 'var'), 'Sysctl variable does not exist')

        if errors:
            raise errors

        return ['system']
コード例 #29
0
    def run(self, id, updated_fields):
        service_def = self.datastore.get_by_id('service_definitions', id)
        if not service_def:
            raise TaskException(
                errno.ENOENT,
                'Service {0} not found'.format(id)
            )

        if 'config' in updated_fields:
            for x in updated_fields['config']:
                if x == 'type':
                    continue

                if not self.configstore.exists('service.{0}.{1}'.format(service_def['name'], x)):
                    raise TaskException(
                        errno.ENOENT,
                        'Service {0} does not have the following key: {1}'.format(
                            service_def['name'], x))

        node = ConfigNode('service.{0}'.format(service_def['name']), self.configstore)
        restart = False
        reload = False
        updated_config = updated_fields.get('config')
        if updated_config is None:
            return

        enable = not node['enable'].value and updated_config['enable']
        disable = node['enable'].value and not updated_config['enable']
        updated_config.pop('type', None)

        if service_def.get('task'):
            try:
                self.verify_subtask(service_def['task'], updated_config)
            except RpcException as err:
                new_err = ValidationException()
                new_err.propagate(err, [0], [1, 'config'])
                raise new_err

            result = self.run_subtask_sync(service_def['task'], updated_config)
            restart = result == 'RESTART'
            reload = result == 'RELOAD'

            if updated_config.get('enable') is not None:
                node['enable'] = updated_config['enable']
        else:
            node.update(updated_config)

            if service_def.get('etcd-group'):
                self.dispatcher.call_sync('etcd.generation.generate_group', service_def.get('etcd-group'))

            if 'enable' in updated_config:
                # Propagate to dependent services
                for i in service_def.get('dependencies', []):
                    svc_dep = self.datastore.get_by_id('service_definitions', i)
                    self.run_subtask_sync('service.update', i, {
                        'config': {
                            'type': 'service-{0}'.format(svc_dep['name']),
                            'enable': updated_config['enable']
                        }
                    })

                if service_def.get('auto_enable'):
                    # Consult state of services dependent on us
                    for i in self.datastore.query('service_definitions', ('dependencies', 'in', service_def['name'])):
                        enb = self.configstore.get('service.{0}.enable', i['name'])
                        if enb != updated_config['enable']:
                            del updated_config['enable']
                            break

        if 'launchd' in service_def:
            if enable:
                load_job(self.dispatcher, service_def)

            if disable:
                unload_job(self.dispatcher, service_def)

        self.dispatcher.call_sync('etcd.generation.generate_group', 'services')
        self.dispatcher.call_sync('service.apply_state', service_def['name'], restart, reload, timeout=120)
        self.dispatcher.dispatch_event('service.changed', {
            'operation': 'update',
            'ids': [service_def['id']]
        })
コード例 #30
0
ファイル: UserPlugin.py プロジェクト: freenas/middleware
    def verify(self, id, updated_fields):
        errors = ValidationException()
        normalize_name(updated_fields, 'username')

        if updated_fields.get('full_name') and ':' in updated_fields['full_name']:
            errors.add((1, 'full_name'), 'The character ":" is not allowed')

        if 'groups' in updated_fields and len(updated_fields['groups']) > 64:
            errors.add((1, 'groups'), 'User cannot belong to more than 64 auxiliary groups')

        if 'username' in updated_fields:
            for code, message in check_unixname(updated_fields['username']):
                errors.add((1, 'username'), message, code=code)

        if updated_fields.get('email'):
            if not EMAIL_REGEX.match(updated_fields['email']):
                errors.add(
                    (1, 'email'),
                    "{0} is an invalid email address".format(updated_fields['email'])
                )

        if 'home' in updated_fields and updated_fields['home'] not in (None, '/nonexistent'):
            volumes_root = self.dispatcher.call_sync('volume.get_volumes_root')
            updated_fields['home'] = os.path.normpath(updated_fields['home'])
            if not updated_fields['home'].startswith(volumes_root) or updated_fields['home'] == volumes_root:
                errors.add(
                    (1, 'home directory'),
                    "Invalid mountpoint specified for home directory: {0}.\n".format(updated_fields['home']) +
                    "Provide a path within zfs pool or dataset mounted under {0}".format(volumes_root)
                )

        if errors:
            raise errors

        return ['system']