Exemple #1
0
class PasswordChangeForm(SetPasswordForm):
    """
    A form that lets a user change his/her password by entering
    their old password.
    """
    old_password = forms.CharField(label=_("Old password"), widget=forms.PasswordInput)
Exemple #2
0
    def __init__(self, *args, **kwargs):
        super(InterfacesForm, self).__init__(*args, **kwargs)

        self._carp = False
        _n = notifier()
        if not _n.is_freenas() and _n.failover_licensed():
            from freenasUI.failover.utils import node_label_field
            self._carp = True
            node_label_field(
                _n.failover_node(),
                self.fields['int_ipv4address'],
                self.fields['int_ipv4address_b'],
            )

        if not self._carp:
            del self.fields['int_vip']
            del self.fields['int_vhid']
            del self.fields['int_critical']
            del self.fields['int_group']
            del self.fields['int_ipv4address_b']

        self.fields['int_interface'].choices = choices.NICChoices()
        self.fields['int_dhcp'].widget.attrs['onChange'] = (
            'javascript:toggleGeneric("id_int_dhcp", ["id_int_ipv4address", '
            '"id_int_ipv4address_b", "id_int_v4netmaskbit"]);')
        self.fields['int_ipv6auto'].widget.attrs['onChange'] = (
            'javascript:toggleGeneric("id_int_ipv6auto", '
            '["id_int_ipv6address", "id_int_v6netmaskbit"]);')
        if 'int_critical' in self.fields:
            self.fields['int_critical'].widget.attrs['onChange'] = (
                'javascript:toggleGeneric("id_int_critical", '
                '["id_int_group"], true);')
        dhcp = False
        ipv6auto = False
        if self.data:
            if self.data.get("int_dhcp"):
                dhcp = True
            if self.data.get("int_ipv6auto"):
                ipv6auto = True
        elif self.instance.id:
            if self.instance.int_dhcp:
                dhcp = True
            if self.instance.int_ipv6auto:
                ipv6auto = True
        if dhcp:
            if 'int_ipv4address' in self.fields:
                self.fields['int_ipv4address'].widget.attrs['disabled'] = (
                    'disabled')
            if 'int_ipv4address_b' in self.fields:
                self.fields['int_ipv4address_b'].widget.attrs['disabled'] = (
                    'disabled')
            self.fields['int_v4netmaskbit'].widget.attrs['disabled'] = (
                'disabled')
        if ipv6auto:
            self.fields['int_ipv6address'].widget.attrs['disabled'] = (
                'disabled')
            self.fields['int_v6netmaskbit'].widget.attrs['disabled'] = (
                'disabled')

        if self.instance.id:
            if 'int_group' in self.fields and not self.instance.int_critical:
                self.fields['int_group'].widget.attrs['disabled'] = (
                    'disabled')
            self.fields['int_interface'] = forms.CharField(
                label=self.fields['int_interface'].label,
                initial=self.instance.int_interface,
                widget=forms.TextInput(attrs={
                    'readonly':
                    True,
                    'class': ('dijitDisabled dijitTextBoxDisabled'
                              ' dijitValidationTextBoxDisabled'),
                }, ))
Exemple #3
0
class LDAPForm(ModelForm):

    ldap_netbiosname_a = forms.CharField(
        max_length=120,
        label=_("NetBIOS name"),
    )
    ldap_netbiosname_b = forms.CharField(
        max_length=120,
        label=_("NetBIOS name"),
        required=False,
    )
    ldap_netbiosalias = forms.CharField(
        max_length=120,
        label=_("NetBIOS alias"),
        required=False,
    )

    advanced_fields = [
        'ldap_anonbind', 'ldap_usersuffix', 'ldap_groupsuffix',
        'ldap_passwordsuffix', 'ldap_machinesuffix', 'ldap_sudosuffix',
        'ldap_netbiosname_a', 'ldap_netbiosname_b', 'ldap_netbiosalias',
        'ldap_kerberos_realm', 'ldap_kerberos_principal', 'ldap_ssl',
        'ldap_certificate', 'ldap_timeout', 'ldap_dns_timeout',
        'ldap_idmap_backend', 'ldap_has_samba_schema',
        'ldap_auxiliary_parameters', 'ldap_schema'
    ]

    class Meta:
        fields = '__all__'
        exclude = ['ldap_idmap_backend_type']

        model = models.LDAP
        widgets = {
            'ldap_bindpw': forms.widgets.PasswordInput(render_value=False),
        }

    def __init__(self, *args, **kwargs):
        super(LDAPForm, self).__init__(*args, **kwargs)
        self.fields["ldap_enable"].widget.attrs["onChange"] = (
            "ldap_mutex_toggle();")
        self.cifs = CIFS.objects.latest('id')
        if self.cifs:
            self.fields[
                'ldap_netbiosname_a'].initial = self.cifs.cifs_srv_netbiosname
            self.fields[
                'ldap_netbiosname_b'].initial = self.cifs.cifs_srv_netbiosname_b
            self.fields[
                'ldap_netbiosalias'].initial = self.cifs.cifs_srv_netbiosalias
        _n = notifier()
        if not _n.is_freenas():
            if _n.failover_licensed():
                from freenasUI.failover.utils import node_label_field
                node_label_field(
                    _n.failover_node(),
                    self.fields['ldap_netbiosname_a'],
                    self.fields['ldap_netbiosname_b'],
                )
            else:
                del self.fields['ldap_netbiosname_b']
        else:
            del self.fields['ldap_netbiosname_b']

    def check_for_samba_schema(self):
        self.clean_bindpw()

        cdata = self.cleaned_data
        binddn = cdata.get("ldap_binddn")
        bindpw = cdata.get("ldap_bindpw")
        basedn = cdata.get("ldap_basedn")
        hostname = cdata.get("ldap_hostname")

        certfile = None
        ssl = cdata.get("ldap_ssl")
        if ssl in ('start_tls', 'on'):
            certificate = cdata["ldap_certificate"]
            certfile = get_certificateauthority_path(certificate)

        fl = FreeNAS_LDAP(host=hostname,
                          binddn=binddn,
                          bindpw=bindpw,
                          basedn=basedn,
                          certfile=certfile,
                          ssl=ssl)

        if fl.has_samba_schema():
            self.instance.ldap_has_samba_schema = True
        else:
            self.instance.ldap_has_samba_schema = False

    def clean_ldap_netbiosname_a(self):
        netbiosname = self.cleaned_data.get("ldap_netbiosname_a")
        try:
            validate_netbios_name(netbiosname)
        except Exception as e:
            raise forms.ValidationError(e)
        return netbiosname

    def clean_ldap_netbiosname_b(self):
        netbiosname_a = self.cleaned_data.get("ldap_netbiosname_a")
        netbiosname = self.cleaned_data.get("ldap_netbiosname_b")
        if not netbiosname:
            return netbiosname
        if netbiosname_a and netbiosname_a == netbiosname:
            raise forms.ValidationError(
                _('NetBIOS cannot be the same as the first.'))
        try:
            validate_netbios_name(netbiosname)
        except Exception as e:
            raise forms.ValidationError(e)
        return netbiosname

    def clean_ldap_netbiosalias(self):
        netbiosalias = self.cleaned_data.get("ldap_netbiosalias")
        if netbiosalias:
            try:
                validate_netbios_name(netbiosalias)
            except Exception as e:
                raise forms.ValidationError(e)
        return netbiosalias

    def clean(self):
        cdata = self.cleaned_data
        if not cdata.get("ldap_bindpw"):
            cdata["ldap_bindpw"] = self.instance.ldap_bindpw

        binddn = cdata.get("ldap_binddn")
        bindpw = cdata.get("ldap_bindpw")
        basedn = cdata.get("ldap_basedn")
        hostname = cdata.get("ldap_hostname")
        ssl = cdata.get("ldap_ssl")

        certfile = None
        if ssl in ('start_tls', 'on'):
            certificate = cdata["ldap_certificate"]
            if not certificate:
                raise forms.ValidationError(
                    "SSL/TLS specified without certificate")
            else:
                certfile = get_certificateauthority_path(certificate)

        port = 389
        if ssl == "on":
            port = 636
        if hostname:
            parts = hostname.split(':')
            hostname = parts[0]
            if len(parts) > 1:
                port = int(parts[1])

        if cdata.get("ldap_enable") is False:
            return cdata

        # self.check_for_samba_schema()
        try:
            FreeNAS_LDAP.validate_credentials(hostname,
                                              binddn=binddn,
                                              bindpw=bindpw,
                                              basedn=basedn,
                                              port=port,
                                              certfile=certfile,
                                              ssl=ssl)
        except LDAPError as e:
            log.debug("LDAPError: type = %s", type(e))

            error = []
            try:
                error.append(e.args[0]['info'])
                error.append(e.args[0]['desc'])
                error = ', '.join(error)

            except:
                error = str(e)

            raise forms.ValidationError("{0}".format(error))

        except Exception as e:
            log.debug("LDAPError: type = %s", type(e))
            raise forms.ValidationError("{0}".format(str(e)))

        return cdata

    def save(self):
        enable = self.cleaned_data.get("ldap_enable")

        started = notifier().started("ldap")
        obj = super(LDAPForm, self).save()
        self.cifs.cifs_srv_netbiosname = self.cleaned_data.get(
            "ldap_netbiosname_a")
        self.cifs.cifs_srv_netbiosname_b = self.cleaned_data.get(
            "ldap_netbiosname_b")
        self.cifs.cifs_srv_netbiosalias = self.cleaned_data.get(
            "ldap_netbiosalias")
        self.cifs.save()

        if enable:
            if started is True:
                started = notifier().restart(
                    "ldap",
                    timeout=_fs().directoryservice.ldap.timeout.restart)
            if started is False:
                started = notifier().start(
                    "ldap", timeout=_fs().directoryservice.ldap.timeout.start)
            if started is False:
                self.instance.ldap_enable = False
                super(LDAPForm, self).save()
                raise MiddlewareError(_("LDAP failed to reload."))
        else:
            if started is True:
                started = notifier().stop(
                    "ldap", timeout=_fs().directoryservice.ldap.timeout.stop)

        return obj

    def done(self, request, events):
        events.append("refreshById('tab_LDAP')")
        super(LDAPForm, self).done(request, events)
Exemple #4
0
class EmailForm(ModelForm):
    em_pass1 = forms.CharField(
        label=_("Password"),
        widget=forms.PasswordInput,
        required=False)
    em_pass2 = forms.CharField(
        label=_("Password confirmation"),
        widget=forms.PasswordInput,
        help_text=_("Enter the same password as above, for verification."),
        required=False)

    class Meta:
        model = models.Email
        exclude = ('em_pass',)

    def __init__(self, *args, **kwargs):
        super(EmailForm, self).__init__(*args, **kwargs)
        try:
            self.fields['em_pass1'].initial = self.instance.em_pass
            self.fields['em_pass2'].initial = self.instance.em_pass
        except:
            pass
        self.fields['em_smtp'].widget.attrs['onChange'] = (
            'toggleGeneric("id_em_smtp", ["id_em_pass1", "id_em_pass2", '
            '"id_em_user"], true);'
        )
        ro = True

        if len(self.data) > 0:
            if self.data.get("em_smtp", None) == "on":
                ro = False
        else:
            if self.instance.em_smtp is True:
                ro = False
        if ro:
            self.fields['em_user'].widget.attrs['disabled'] = 'disabled'
            self.fields['em_pass1'].widget.attrs['disabled'] = 'disabled'
            self.fields['em_pass2'].widget.attrs['disabled'] = 'disabled'

    def clean_em_user(self):
        if (
            self.cleaned_data['em_smtp'] is True and
            self.cleaned_data['em_user'] == ""
        ):
            raise forms.ValidationError(_("This field is required"))
        return self.cleaned_data['em_user']

    def clean_em_pass1(self):
        if (
            self.cleaned_data['em_smtp'] is True and
            self.cleaned_data['em_pass1'] == ""
        ):
            if self.instance.em_pass:
                return self.instance.em_pass
            raise forms.ValidationError(_("This field is required"))
        return self.cleaned_data['em_pass1']

    def clean_em_pass2(self):
        if (
            self.cleaned_data['em_smtp'] is True and
            self.cleaned_data.get('em_pass2', "") == ""
        ):
            if self.instance.em_pass:
                return self.instance.em_pass
            raise forms.ValidationError(_("This field is required"))
        pass1 = self.cleaned_data.get("em_pass1", "")
        pass2 = self.cleaned_data.get("em_pass2", "")
        if pass1 != pass2:
            raise forms.ValidationError(
                _("The two password fields didn't match.")
            )
        return pass2

    def save(self, commit=True):
        email = super(EmailForm, self).save(commit=False)
        if commit:
            email.em_pass = self.cleaned_data['em_pass2']
            email.save()
        return email
Exemple #5
0
class FirmwareUploadForm(Form):
    firmware = FileField(label=_("New image to be installed"), required=True)
    sha256 = forms.CharField(
        label=_("SHA256 sum for the image"),
        required=True
    )
Exemple #6
0
class JailMountPointForm(ModelForm):

    create = forms.BooleanField(
        label=('Create directory'),
        required=False,
        initial=True,
        help_text=_('Create destination directory if it does not exist'),
    )

    mounted = forms.BooleanField(
        label=_("Mounted?"),
        required=False,
        initial=True,
    )

    # Do not remove: used in javascript side
    mpjc_path = forms.CharField(required=False)

    class Meta:
        fields = '__all__'
        model = JailMountPoint
        widgets = {
            'source':
            forms.widgets.TextInput(
                attrs={
                    'data-dojo-type': 'freeadmin.form.PathSelector',
                }),
            'destination':
            forms.widgets.TextInput(
                attrs={
                    'data-dojo-type': 'freeadmin.form.PathSelector',
                }),
        }

    def clean_source(self):
        src = self.cleaned_data.get("source")
        src = os.path.abspath(src.strip().replace("..", ""))
        return src

    def clean_destination(self):
        dest = self.cleaned_data.get("destination")
        dest = os.path.abspath(dest.strip().replace("..", ""))
        if not re.search(r'^/[a-zA-Z0-9][a-zA-Z0-9_/\-:. ]*$', dest):
            raise forms.ValidationError(
                _("Destination must begin with an "
                  "alphanumeric character and may only contain "
                  "\"-\", \"_\", \":\", \" \" and \".\"."))

        if not self.jail:
            jail = self.cleaned_data.get("jail")
            if jail:
                self.jail = Jails.objects.get(jail_host=jail)

        if not self.jail:
            raise forms.ValidationError(
                _("This shouldn't happen, but the jail could not be found"))

        self._full = "%s/%s%s" % (self.jc.jc_path, self.jail.jail_host, dest)

        if len(self._full) > 88:
            raise forms.ValidationError(
                _("The full path cannot exceed 88 characters"))

        return dest

    def __init__(self, *args, **kwargs):
        self.jail = None
        if kwargs and 'jail' in kwargs:
            self.jail = kwargs.pop('jail')

        super(JailMountPointForm, self).__init__(*args, **kwargs)

        self._full = None

        if kwargs and 'instance' in kwargs:
            self.instance = kwargs.pop('instance')
            if not self.jail and self.instance.id:
                try:
                    self.jail = Jails.objects.filter(
                        jail_host=self.instance.jail)[0]
                except:
                    pass

        self.jc = JailsConfiguration.objects.order_by("-id")[0]
        self.fields['jail'] = forms.ChoiceField(
            label=_("Jail"),
            choices=(),
            widget=forms.Select(attrs={'class': 'required'}),
        )
        if self.jail:
            self.fields['jail'].initial = self.jail.jail_host
            self.fields['jail'].widget.attrs['readonly'] = True
            jail_path = "%s/%s" % (self.jc.jc_path, self.jail.jail_host)
            self.fields['destination'].widget.attrs['root'] = jail_path

        try:
            clean_path_execbit(self.jc.jc_path)
        except forms.ValidationError, e:
            self.errors['__all__'] = self.error_class(e.messages)

        pjlist = []
        try:
            wlist = Warden().cached_list()
        except:
            wlist = []

        for wj in wlist:
            pjlist.append(wj[WARDEN_KEY_HOST])

        self.fields['jail'].choices = [('', '')] + [(pj, pj) for pj in pjlist]
        self.fields['jail'].widget.attrs['onChange'] = (
            'addStorageJailChange(this);')

        self.fields['mpjc_path'].widget = forms.widgets.HiddenInput()
        self.fields['mpjc_path'].initial = self.jc.jc_path

        if self.instance.id:
            self.fields['mounted'].initial = self.instance.mounted
        else:
            self.fields['mounted'].widget = forms.widgets.HiddenInput()
Exemple #7
0
class IPMIForm(Form):
    # Max password length via IPMI v2.0 is 20 chars. We only support IPMI
    # v2.0+ compliant boards thus far.
    ipmi_password1 = forms.CharField(
        label=_("Password"),
        max_length=20,
        widget=forms.PasswordInput,
        required=False
    )
    ipmi_password2 = forms.CharField(
        label=_("Password confirmation"),
        max_length=20,
        widget=forms.PasswordInput,
        help_text=_("Enter the same password as above, for verification."),
        required=False
    )
    dhcp = forms.BooleanField(
        label=_("DHCP"),
        required=False,
    )
    ipv4address = IP4AddressFormField(
        initial='',
        required=False,
        label=_("IPv4 Address"),
    )
    ipv4netmaskbit = forms.ChoiceField(
        choices=choices.v4NetmaskBitList,
        required=False,
        label=_("IPv4 Netmask"),
    )
    ipv4gw = IP4AddressFormField(
        initial='',
        required=False,
        label=_("IPv4 Default Gateway"),
    )
    vlanid = forms.IntegerField(
        label=_("VLAN ID"),
        required=False,
        widget=forms.widgets.TextInput(),
    )

    def __init__(self, *args, **kwargs):
        super(IPMIForm, self).__init__(*args, **kwargs)
        self.fields['dhcp'].widget.attrs['onChange'] = (
            'javascript:toggleGeneric('
            '"id_dhcp", ["id_ipv4address", "id_ipv4netmaskbit"]);'
        )

        channels = []
        _n = notifier()
        for i in range(1, 17):
            try:
                data = _n.ipmi_get_lan(channel=i)
            except:
                continue

            if not data:
                continue

            channels.append((i, i))

        self.fields['channel'] = forms.ChoiceField(
            choices=channels,
            label=_('Channel'),
        )
        self.fields.keyOrder.remove('channel')
        self.fields.keyOrder.insert(0, 'channel')

    def clean_ipmi_password2(self):
        ipmi_password1 = self.cleaned_data.get("ipmi_password1", "")
        ipmi_password2 = self.cleaned_data["ipmi_password2"]
        if ipmi_password1 != ipmi_password2:
            raise forms.ValidationError(
                _("The two password fields didn't match.")
            )
        return ipmi_password2

    def clean_ipv4netmaskbit(self):
        try:
            cidr = int(self.cleaned_data.get("ipv4netmaskbit"))
        except ValueError:
            return None
        bits = 0xffffffff ^ (1 << 32 - cidr) - 1
        return socket.inet_ntoa(pack('>I', bits))

    def clean_ipv4address(self):
        ipv4 = self.cleaned_data.get('ipv4address')
        if ipv4:
            ipv4 = str(ipv4)
        return ipv4

    def clean_ipv4gw(self):
        ipv4 = self.cleaned_data.get('ipv4gw')
        if ipv4:
            ipv4 = str(ipv4)
        return ipv4
Exemple #8
0
class SNMPForm(MiddlewareModelForm, ModelForm):

    middleware_attr_prefix = "snmp_"
    middleware_attr_schema = "snmp"
    middleware_exclude_fields = ["v3_password2", "v3_privpassphrase2"]
    middleware_plugin = "snmp"
    is_singletone = True

    snmp_v3_password2 = forms.CharField(
        max_length=40,
        label=_("Confirm Password"),
        widget=forms.widgets.PasswordInput(render_value=True),
        required=False,
    )

    snmp_v3_privpassphrase2 = forms.CharField(
        max_length=40,
        label=_("Confirm Privacy Passphrase"),
        widget=forms.widgets.PasswordInput(render_value=True),
        required=False,
    )

    class Meta:
        fields = '__all__'
        model = models.SNMP
        widgets = {
            'snmp_v3_password': forms.widgets.PasswordInput(render_value=True),
            'snmp_v3_privpassphrase': forms.widgets.PasswordInput(
                render_value=True
            ),
        }

    def __init__(self, *args, **kwargs):
        super(SNMPForm, self).__init__(*args, **kwargs)
        self.fields['snmp_v3'].widget.attrs['onChange'] = (
            'toggleGeneric("id_snmp_v3", ["id_snmp_v3_password", '
            '"id_snmp_v3_password2", "id_snmp_v3_username", '
            '"id_snmp_v3_authtype", "id_snmp_v3_privproto", '
            '"id_snmp_v3_privpassphrase", "id_snmp_v3_privpassphrase2"],true);'
        )
        if self.instance.id and not self.instance.snmp_v3:
            self.fields['snmp_v3_password'].widget.attrs['disabled'] = (
                'disabled'
            )
            self.fields['snmp_v3_password2'].widget.attrs['disabled'] = (
                'disabled'
            )
            self.fields['snmp_v3_authtype'].widget.attrs['disabled'] = (
                'disabled'
            )
            self.fields['snmp_v3_username'].widget.attrs['disabled'] = (
                'disabled'
            )
            self.fields['snmp_v3_privproto'].widget.attrs['disabled'] = (
                'disabled'
            )
            self.fields['snmp_v3_privpassphrase'].widget.attrs['disabled'] = (
                'disabled'
            )
            self.fields['snmp_v3_privpassphrase2'].widget.attrs['disabled'] = (
                'disabled'
            )
        if self.instance.id:
            self.fields['snmp_v3_password2'].initial = self.instance.snmp_v3_password
            self.fields['snmp_v3_privpassphrase2'].initial = self.instance.snmp_v3_privpassphrase

    def clean_snmp_v3_password2(self):
        password1 = self.cleaned_data.get("snmp_v3_password")
        password2 = self.cleaned_data.get("snmp_v3_password2")
        if not password1:
            return password2
        if password1 != password2:
            raise forms.ValidationError(
                _("The two password fields didn't match.")
            )
        return password2

    def clean_snmp_v3_privpassphrase2(self):
        passphrase1 = self.cleaned_data.get("snmp_v3_privpassphrase")
        passphrase2 = self.cleaned_data.get("snmp_v3_privpassphrase2")
        if not passphrase1:
            return passphrase2
        if passphrase1 != passphrase2:
            raise forms.ValidationError(
                _("The two password fields didn't match.")
            )
        return passphrase2
Exemple #9
0
class iSCSITargetAuthCredentialForm(MiddlewareModelForm, ModelForm):
    middleware_attr_prefix = "iscsi_target_auth_"
    middleware_attr_schema = "services.iscsi_targetauthcredential"
    middleware_plugin = "iscsi.auth"
    is_singletone = False

    iscsi_target_auth_secret2 = forms.CharField(
        label=_("Secret (Confirm)"),
        widget=forms.PasswordInput(render_value=True),
        help_text=_("Enter the same secret above for verification.")
    )
    iscsi_target_auth_peersecret2 = forms.CharField(
        label=_("Peer Secret (Confirm)"),
        widget=forms.PasswordInput(render_value=True),
        help_text=_("Enter the same secret above for verification."),
        required=False,
    )

    class Meta:
        fields = '__all__'
        model = models.iSCSITargetAuthCredential
        widgets = {
            'iscsi_target_auth_secret': forms.PasswordInput(render_value=True),
            'iscsi_target_auth_peersecret': forms.PasswordInput(
                render_value=True
            ),
        }

    def __init__(self, *args, **kwargs):
        super(iSCSITargetAuthCredentialForm, self).__init__(*args, **kwargs)
        if self._api:
            del self.fields['iscsi_target_auth_secret2']
            del self.fields['iscsi_target_auth_peersecret2']
        else:
            key_order(self, 3, 'iscsi_target_auth_secret2', instance=True)
            key_order(self, 6, 'iscsi_target_auth_peersecret2', instance=True)

            ins = kwargs.get("instance", None)
            if ins:
                self.fields['iscsi_target_auth_secret2'].initial = (
                    self.instance.iscsi_target_auth_secret)
                self.fields['iscsi_target_auth_peersecret2'].initial = (
                    self.instance.iscsi_target_auth_peersecret)

    def _clean_secret_common(self, secretprefix):
        secret1 = self.cleaned_data.get(secretprefix, "")
        secret2 = self.cleaned_data[("%s2" % secretprefix)]
        if secret1 != secret2:
            raise forms.ValidationError(_("Secret does not match"))
        return secret2

    def clean_iscsi_target_auth_secret2(self):
        return self._clean_secret_common("iscsi_target_auth_secret")

    def clean_iscsi_target_auth_peersecret2(self):
        return self._clean_secret_common("iscsi_target_auth_peersecret")

    def middleware_clean(self, data):
        data.pop('secret2', None)
        data.pop('peersecret2', None)
        return data
Exemple #10
0
class WebDAVForm(MiddlewareModelForm, ModelForm):
    middleware_attr_prefix = 'webdav_'
    middleware_attr_schema = 'webdav'
    middleware_exclude_fields = ['password2']
    middleware_plugin = 'webdav'
    is_singletone = True

    webdav_password2 = forms.CharField(
        max_length=120,
        label=_("Confirm WebDAV Password"),
        widget=forms.widgets.PasswordInput(),
        required=False,
    )

    class Meta:
        fields = (
            'webdav_protocol', 'webdav_tcpport', 'webdav_tcpportssl',
            'webdav_certssl', 'webdav_htauth', 'webdav_password'
        )
        model = models.WebDAV
        widgets = {
            'webdav_tcpport': forms.widgets.TextInput(),
            'webdav_tcpportssl': forms.widgets.TextInput(),
            'webdav_password': forms.widgets.PasswordInput(),
        }

    def __init__(self, *args, **kwargs):
        super(WebDAVForm, self).__init__(*args, **kwargs)
        if self.instance.webdav_password:
            self.fields['webdav_password'].required = False
            self.fields['webdav_password2'].required = False
        if self._api is True:
            del self.fields['webdav_password2']
        self.fields['webdav_protocol'].widget.attrs['onChange'] = (
            "webdavprotocolToggle();"
        )
        self.fields['webdav_htauth'].widget.attrs['onChange'] = (
            "webdavhtauthToggle();"
        )

    def clean(self):
        cdata = self.cleaned_data

        if self._api is not True and cdata.get("webdav_password") != cdata.get("webdav_password2"):
            self._errors["webdav_password"] = self.error_class(
                [_("The two password fields didn't match.")]
            )
        elif not cdata.get("webdav_password"):
            cdata['webdav_password'] = self.instance.webdav_password
        if not cdata.get("webdav_tcpport"):
            cdata['webdav_tcpport'] = self.instance.webdav_tcpport
        if not cdata.get("webdav_tcpportssl"):
            cdata['webdav_tcpportssl'] = self.instance.webdav_tcpportssl

        return cdata

    def middleware_clean(self, data):
        data['protocol'] = data['protocol'].upper()
        data['htauth'] = data['htauth'].upper()

        return data
Exemple #11
0
class S3Form(MiddlewareModelForm, ModelForm):

    middleware_attr_prefix = "s3_"
    middleware_attr_schema = "s3"
    middleware_exclude_fields = ('secret_key2', )
    middleware_plugin = "s3"
    is_singletone = True
    middleware_attr_map = {
        'storage_path': 's3_disks'
    }

    s3_bindip = forms.ChoiceField(
        label=models.S3._meta.get_field("s3_bindip").verbose_name,
        help_text=models.S3._meta.get_field("s3_bindip").help_text,
        widget=forms.widgets.FilteringSelect(),
        required=False,
        choices=(),
    )
    s3_secret_key2 = forms.CharField(
        max_length=128,
        label=_("Confirm S3 Key"),
        widget=forms.widgets.PasswordInput(render_value=True),
        required=False,
    )

    class Meta:
        fields = '__all__'
        widgets = {
            's3_secret_key': forms.widgets.PasswordInput(render_value=True),
            's3_bindport': forms.widgets.TextInput(),
        }
        model = models.S3

    def __init__(self, *args, **kwargs):
        super(S3Form, self).__init__(*args, **kwargs)
        key_order(self, 1, 's3_bindip', instance=True)
        key_order(self, 2, 's3_bindport', instance=True)
        key_order(self, 3, 's3_access_key', instance=True)
        key_order(self, 4, 's3_secret_key', instance=True)
        key_order(self, 5, 's3_secret_key2', instance=True)
        key_order(self, 6, 's3_disks', instance=True)
        key_order(self, 7, 's3_certificate', instance=True)
        key_order(self, 8, 's3_mode', instance=True)
        key_order(self, 9, 's3_browser', instance=True)

        self.fields['s3_bindip'].choices = [('0.0.0.0', '0.0.0.0')] + list(choices.IPChoices())
        if self.instance.id and self.instance.s3_bindip:
            bindips = []
            for ip in self.instance.s3_bindip:
                bindips.append(ip.encode('utf-8'))

            self.fields['s3_bindip'].initial = (bindips)
        else:
            self.fields['s3_bindip'].initial = ('')

        if self.instance.id:
            self.fields['s3_secret_key2'].initial = self.instance.s3_secret_key
        if self._api is True:
            del self.fields['s3_secret_key2']

        self.fields['s3_mode'].widget = forms.widgets.HiddenInput()

    def clean_s3_secret_key2(self):
        s3_secret_key1 = self.cleaned_data.get("s3_secret_key")
        s3_secret_key2 = self.cleaned_data.get("s3_secret_key2")
        if s3_secret_key1 != s3_secret_key2:
            raise forms.ValidationError(
                _("The two password fields didn't match.")
            )
        return s3_secret_key2

    def clean(self):
        cdata = self.cleaned_data
        if not cdata.get("s3_secret_key"):
            cdata["s3_secret_key"] = self.instance.s3_secret_key
        return cdata

    def middleware_clean(self, data):
        if 'disks' in data:
            data['storage_path'] = data.pop('disks')
        data.pop('mode', None)
        return data
Exemple #12
0
class LicenseUpdateForm(Form):

    license = forms.CharField(
        label=_('License'),
        widget=forms.widgets.Textarea,
    )
Exemple #13
0
class ActiveDirectoryForm(MiddlewareModelForm, ModelForm):
    middleware_attr_prefix = 'ad_'
    middleware_attr_schema = 'ad'
    middleware_plugin = 'activedirectory'
    is_singletone = True

    ad_netbiosname = forms.CharField(
        max_length=120,
        label=_("NetBIOS name"),
    )
    ad_netbiosname_b = forms.CharField(
        max_length=120,
        label=_("NetBIOS name"),
    )
    ad_netbiosalias = forms.CharField(
        max_length=120,
        label=_("NetBIOS alias"),
        required=False,
    )
    ad_kerberos_principal = forms.ChoiceField(
        label=models.ActiveDirectory._meta.get_field(
            'ad_kerberos_principal').verbose_name,
        required=False,
        choices=choices.KERBEROS_PRINCIPAL_CHOICES(),
        help_text=
        _("Kerberos principal to use for AD-related UI and middleware operations. "
          "Populated with exiting  principals from the system keytab. "
          "A keytab entry is generated for the the Active Directory Machine Account "
          "The account name for the server is the server netbios name appended with a '$' "
          "Bind credentails are automatically cleared after the has is joined to Active "
          "Directory. Later operations are perfomed by the AD machine account, which has "
          "restricted privileges in the AD domain."),
        initial='')

    advanced_fields = [
        'ad_netbiosname', 'ad_netbiosname_b', 'ad_netbiosalias', 'ad_ssl',
        'ad_certificate', 'ad_verbose_logging', 'ad_allow_trusted_doms',
        'ad_use_default_domain', 'ad_createcomputer', 'ad_allow_dns_updates',
        'ad_disable_freenas_cache', 'ad_site', 'ad_kerberos_realm',
        'ad_kerberos_principal', 'ad_nss_info', 'ad_timeout', 'ad_dns_timeout',
        'ad_idmap_backend', 'ad_ldap_sasl_wrapping'
    ]

    class Meta:
        fields = '__all__'
        exclude = ['ad_idmap_backend_type', 'ad_userdn', 'ad_groupdn']

        model = models.ActiveDirectory
        widgets = {
            'ad_bindpw': forms.widgets.PasswordInput(render_value=False),
        }

    def __init__(self, *args, **kwargs):
        super(ActiveDirectoryForm, self).__init__(*args, **kwargs)
        with client as c:
            ad = c.call('activedirectory.config')

            self.fields['ad_netbiosname'].initial = ad['netbiosname']
            if 'netbiosname_b' in ad:
                self.fields['ad_netbiosname_b'].initial = ad['netbiosname_b']
            else:
                del self.fields['ad_netbiosname_b']

    def save(self):
        try:
            super(ActiveDirectoryForm, self).save()
        except Exception as e:
            raise MiddlewareError(e)

    def middleware_clean(self, data):
        for key in ['certificate', 'nss_info', 'kerberos_realm']:
            if not data[key]:
                data.pop(key)

        for key in ['ssl', 'idmap_backend', 'nss_info', 'ldap_sasl_wrapping']:
            if key in data and data[key] is not None:
                data[key] = data[key].upper()

        data['netbiosalias'] = data['netbiosalias'].split()
        if data['kerberos_principal'] == '---------':
            data['kerberos_principal'] = ''

        return data
Exemple #14
0
class NullMountPointForm(ModelForm):

    mounted = forms.BooleanField(
        label=_("Mounted?"),
        required=False,
        initial=True,
    )

    # Do not remove: used in javascript side
    mpjc_path = forms.CharField(required=False)

    class Meta:
        model = NullMountPoint
        widgets = {
            'source':
            forms.widgets.TextInput(
                attrs={
                    'data-dojo-type': 'freeadmin.form.PathSelector',
                }),
            'destination':
            forms.widgets.TextInput(
                attrs={
                    'data-dojo-type': 'freeadmin.form.PathSelector',
                }),
        }

    def clean_source(self):
        src = self.cleaned_data.get("source")
        src = os.path.abspath(src.strip().replace("..", ""))
        return src

    def clean_destination(self):
        dest = self.cleaned_data.get("destination")
        dest = os.path.abspath(dest.strip().replace("..", ""))

        if not self.jail:
            jail = self.cleaned_data.get("jail")
            if jail:
                self.jail = Jails.objects.get(jail_host=jail)

        if not self.jail:
            raise forms.ValidationError(
                _("This shouldn't happen, but the jail could not be found"))

        full = "%s/%s%s" % (self.jc.jc_path, self.jail.jail_host, dest)

        if len(full) > 88:
            raise forms.ValidationError(
                _("The full path cannot exceed 88 characters"))
        return dest

    def __init__(self, *args, **kwargs):
        self.jail = None
        if kwargs and 'jail' in kwargs:
            self.jail = kwargs.pop('jail')

        super(NullMountPointForm, self).__init__(*args, **kwargs)

        if kwargs and 'instance' in kwargs:
            self.instance = kwargs.pop('instance')
            if not self.jail:
                self.jail = Jails.objects.filter(
                    jail_host=self.instance.jail)[0]

        self.jc = JailsConfiguration.objects.order_by("-id")[0]
        self.fields['jail'] = forms.ChoiceField(
            label=_("Jail"),
            choices=(),
            widget=forms.Select(attrs={'class': 'required'}),
        )
        if self.jail:
            self.fields['jail'].initial = self.jail.jail_host

        try:
            clean_path_execbit(self.jc.jc_path)
        except forms.ValidationError, e:
            self.errors['__all__'] = self.error_class(e.messages)

        pjlist = []
        try:
            wlist = Warden().list()
        except:
            wlist = []

        for wj in wlist:
            pjlist.append(wj[WARDEN_KEY_HOST])

        self.fields['jail'].choices = [(pj, pj) for pj in pjlist]
        self.fields['jail'].widget.attrs['onChange'] = (
            'addStorageJailChange(this);')
        jail_path = "%s/%s" % (self.jc.jc_path, self.jail.jail_host)
        self.fields['destination'].widget.attrs['root'] = jail_path

        self.fields['mpjc_path'].widget = forms.widgets.HiddenInput()
        self.fields['mpjc_path'].initial = self.jc.jc_path

        if self.instance.id:
            self.fields['mounted'].initial = self.instance.mounted
        else:
            self.fields['mounted'].widget = forms.widgets.HiddenInput()
Exemple #15
0
class bsdUsersForm(ModelForm):

    bsdusr_username = forms.CharField(label=_("Username"), max_length=16)
    bsdusr_password = forms.CharField(label=_("Password"),
                                      widget=forms.PasswordInput,
                                      required=False)
    bsdusr_password2 = forms.CharField(
        label=_("Password confirmation"),
        widget=forms.PasswordInput,
        help_text=_("Enter the same password as above, for verification."),
        required=False)
    bsdusr_group = forms.ModelChoiceField(
        label=_("Primary Group"),
        queryset=models.bsdGroups.objects.all(),
        required=False)
    bsdusr_creategroup = forms.BooleanField(
        label=_("Create a new primary group for the user"),
        required=False,
        initial=True)
    bsdusr_sshpubkey = forms.CharField(label=_("SSH Public Key"),
                                       widget=forms.Textarea,
                                       required=False)
    bsdusr_mode = UnixPermissionField(label=_('Home Directory Mode'),
                                      initial='755',
                                      required=False)
    bsdusr_to_group = SelectMultipleField(label=_('Auxiliary groups'),
                                          choices=(),
                                          required=False)

    advanced_fields = ['bsdusr_mode']
    middleware_attr_map = {
        'groups': 'bsdusr_to_group',
        'group_create': 'bsdusr_creategroup',
        'home_mode': 'bsdusr_home',
    }
    middleware_attr_prefix = 'bsdusr_'

    class Meta:
        model = models.bsdUsers
        widgets = {
            'bsdusr_uid': forms.widgets.ValidationTextInput(),
        }
        exclude = (
            'bsdusr_unixhash',
            'bsdusr_smbhash',
            'bsdusr_group',
        )
        fields = (
            'bsdusr_uid',
            'bsdusr_username',
            'bsdusr_creategroup',
            'bsdusr_home',
            'bsdusr_mode',
            'bsdusr_shell',
            'bsdusr_full_name',
            'bsdusr_email',
            'bsdusr_password',
            'bsdusr_password2',
            'bsdusr_password_disabled',
            'bsdusr_locked',
            'bsdusr_sudo',
            'bsdusr_microsoft_account',
            'bsdusr_sshpubkey',
            'bsdusr_to_group',
        )

    def __init__(self, *args, **kwargs):
        #FIXME: Workaround for DOJO not showing select with blank values
        if len(args) > 0 and isinstance(args[0], QueryDict):
            new = args[0].copy()
            if new.get('bsdusr_group', None) == '-----':
                new['bsdusr_group'] = ''
            args = (new, ) + args[1:]
        super(bsdUsersForm, self).__init__(*args, **kwargs)
        key_order(self, 3, 'bsdusr_group', instance=True)
        if self._api is True:
            del self.fields['bsdusr_password2']
        self.fields['bsdusr_to_group'].choices = [
            (x.id, x.bsdgrp_group) for x in models.bsdGroups.objects.all()
        ]
        self.fields['bsdusr_password_disabled'].widget.attrs['onChange'] = (
            'javascript:toggleGeneric("id_bsdusr_password_disabled", '
            '["id_bsdusr_locked", "id_bsdusr_sudo"], false);')
        self.fields['bsdusr_locked'].widget.attrs['onChange'] = (
            'javascript:toggleGeneric("id_bsdusr_locked", '
            '["id_bsdusr_password_disabled"], false);')
        self.fields['bsdusr_sudo'].widget.attrs['onChange'] = (
            'javascript:toggleGeneric("id_bsdusr_sudo", '
            '["id_bsdusr_password_disabled"], false);')

        if not self.instance.id:
            try:
                with client as c:
                    self.fields['bsdusr_uid'].initial = c.call(
                        'user.get_next_uid')
            except Exception:
                pass
            self.fields['bsdusr_home'].label = _('Create Home Directory In')
            self.fields['bsdusr_creategroup'].widget.attrs['onChange'] = (
                'javascript:toggleGeneric("id_bsdusr_creategroup", '
                '["id_bsdusr_group"], false);')
            self.fields['bsdusr_group'].widget.attrs['maxHeight'] = 200
            self.fields['bsdusr_group'].widget.attrs['disabled'] = 'disabled'
            self.fields['bsdusr_group'].choices = (
                ('-----', '-----'), ) + tuple(
                    [x for x in self.fields['bsdusr_group'].choices][1:])
            self.fields['bsdusr_group'].required = False
            self.bsdusr_home_saved = '/nonexistent'

        elif self.instance.id:
            self.fields['bsdusr_to_group'].initial = [
                x.bsdgrpmember_group.id
                for x in models.bsdGroupMembership.objects.filter(
                    bsdgrpmember_user=self.instance.id)
            ]

            del self.fields['bsdusr_creategroup']
            self.fields['bsdusr_group'].initial = self.instance.bsdusr_group
            self.advanced_fields = []
            self.bsdusr_home_saved = self.instance.bsdusr_home
            key_order(self, len(self.fields) - 1, 'bsdusr_mode', instance=True)
            self.fields['bsdusr_username'].widget.attrs['readonly'] = True
            self.fields['bsdusr_username'].widget.attrs['class'] = (
                'dijitDisabled dijitTextBoxDisabled '
                'dijitValidationTextBoxDisabled')
            if os.path.exists(self.instance.bsdusr_home):
                mode = os.stat(self.instance.bsdusr_home).st_mode & 0o777
                self.fields['bsdusr_mode'].initial = oct(mode)[2:]
            if self.instance.bsdusr_builtin:
                self.fields['bsdusr_uid'].widget.attrs['readonly'] = True
                self.fields['bsdusr_uid'].widget.attrs['class'] = (
                    'dijitDisabled dijitTextBoxDisabled '
                    'dijitValidationTextBoxDisabled')
                self.fields['bsdusr_group'].widget.attrs['readonly'] = True
                self.fields['bsdusr_group'].widget.attrs['class'] = (
                    'dijitDisabled dijitSelectDisabled')
                self.fields['bsdusr_home'].widget.attrs['readonly'] = True
                self.fields['bsdusr_home'].widget.attrs['class'] = (
                    'dijitDisabled dijitTextBoxDisabled '
                    'dijitValidationTextBoxDisabled')
                self.fields['bsdusr_mode'].widget.attrs['disabled'] = True
                self.fields['bsdusr_mode'].required = False
            if self.instance.bsdusr_locked or self.instance.bsdusr_sudo:
                self.fields['bsdusr_password_disabled'].widget.attrs[
                    'disabled'] = True
            if self.instance.bsdusr_password_disabled is True:
                self.fields['bsdusr_locked'].widget.attrs['disabled'] = True
                self.fields['bsdusr_sudo'].widget.attrs['disabled'] = True
            self.fields['bsdusr_sshpubkey'].initial = (
                self.instance.bsdusr_sshpubkey)

    def clean_bsdusr_password2(self):
        bsdusr_password = self.cleaned_data.get("bsdusr_password", "")
        bsdusr_password2 = self.cleaned_data["bsdusr_password2"]
        if bsdusr_password and bsdusr_password != bsdusr_password2:
            raise forms.ValidationError(
                _("The two password fields didn't match."))
        return bsdusr_password2

    def clean_bsdusr_home(self):
        home = self.cleaned_data['bsdusr_home']
        user_home = self.instance.bsdusr_home

        if self.instance.bsdusr_builtin:
            return self.instance.bsdusr_home
        if home is not None:
            if home == '/nonexistent':
                return home

            if home.startswith('/mnt/'):
                bsdusr_username = self.cleaned_data.get('bsdusr_username', '')
                volumes = [
                    '/mnt/{}'.format(volume.vol_name)
                    for volume in Volume.objects.all()
                ]

                if self.instance.id and home != user_home:
                    if len(zfs.list_datasets(path=user_home)) > 0 and \
                            (len(zfs.list_datasets(path=home)) > 0 and home.startswith(user_home + '/')):
                        raise forms.ValidationError(
                            _("A dataset inside the home dataset "
                              "cannot be used as a home directory."))

                if home in volumes:
                    raise forms.ValidationError(
                        _("Volume root directories cannot be used as user home directories."
                          ))

                if home.endswith(bsdusr_username):
                    return home

                if not self.instance.id:
                    home = "%s/%s" % (home.rstrip('/'), bsdusr_username)

                if not self.instance.id and not home.endswith(bsdusr_username):
                    raise forms.ValidationError(
                        _('Home directory must end with username'))

                return home

    def clean_bsdusr_mode(self):
        mode = self.cleaned_data.get('bsdusr_mode')
        if not self.instance.id and not mode:
            return '755'
        return mode or None

    def clean_bsdusr_sshpubkey(self):
        ssh = self.cleaned_data.get('bsdusr_sshpubkey', '')
        ssh = ssh.strip(' ').strip('\n')
        ssh = re.sub(r'[ ]{2,}', ' ', ssh, re.M)
        ssh = re.sub(r'\n{2,}', '\n', ssh, re.M)
        old = ssh
        while True:
            ssh = re.sub(r'(\S{20,})\n(\S{20,})', '\\1\\2', ssh, re.M)
            if ssh == old:
                break
            old = ssh
        return ssh

    def save(self, *args, **kwargs):
        data = self.cleaned_data.copy()

        # Convert attributes to new middleware API
        for k in list(data.keys()):
            if k.startswith('bsdusr_'):
                data[k[len('bsdusr_'):]] = data.pop(k)

        if self.instance.id is None:
            args = ['user.create']
            data['group_create'] = data.pop('creategroup', False)
        else:
            args = ['user.update', self.instance.id]
            # If password is blank, do not send it to middleware
            if not data.get('password'):
                data.pop('password', None)

        data.pop('password2', None)
        data['home_mode'] = data.pop('mode')
        if not data.get('email'):
            data['email'] = None
        if not data.get('home_mode'):
            data.pop('home_mode')
        if data['group']:
            data['group'] = data['group'].id
        else:
            data.pop('group')
        data['groups'] = [int(group) for group in data.pop('to_group', [])]

        if self.instance.bsdusr_builtin:
            data.pop('home', None)
            data.pop('home_mode', None)
            data.pop('uid', None)
            data.pop('username', None)
            data.pop('group', None)

        with client as c:
            pk = c.call(*args, data)

        self.instance = models.bsdUsers.objects.get(pk=pk)
        return self.instance

    def delete(self, **kwargs):
        data = {
            'delete_group': False if self.data.get('nodelgroup') else True,
        }
        with client as c:
            c.call('user.delete', self.instance.id, data)
Exemple #16
0
class bsdUsersForm(ModelForm, bsdUserGroupMixin):
    """
    # Yanked from django/contrib/auth/
    A form that creates a user, with no privileges,
    from the given username and password.
    """
    bsdusr_username = forms.CharField(
        label=_("Username"),
        max_length=16)
    bsdusr_password = forms.CharField(
        label=_("Password"),
        widget=forms.PasswordInput,
        required=False)
    bsdusr_password2 = forms.CharField(
        label=_("Password confirmation"),
        widget=forms.PasswordInput,
        help_text=_("Enter the same password as above, for verification."),
        required=False)
    bsdusr_group = forms.ModelChoiceField(
        label=_("Primary Group"),
        queryset=models.bsdGroups.objects.all(),
        required=False)
    bsdusr_shell = forms.ChoiceField(
        label=_("Shell"),
        initial=u'/bin/csh',
        choices=())
    bsdusr_creategroup = forms.BooleanField(
        label=_("Create a new primary group for the user"),
        required=False,
        initial=True)
    bsdusr_sshpubkey = forms.CharField(
        label=_("SSH Public Key"),
        widget=forms.Textarea,
        max_length=8192,
        required=False)
    bsdusr_mode = UnixPermissionField(
        label=_('Home Directory Mode'),
        initial='755',
        required=False)
    bsdusr_to_group = FilteredSelectField(
        label=_('Auxiliary groups'),
        choices=(),
        required=False)
    advanced_fields = ['bsdusr_mode']

    class Meta:
        model = models.bsdUsers
        widgets = {
            'bsdusr_uid': forms.widgets.ValidationTextInput(),
        }
        exclude = (
            'bsdusr_unixhash',
            'bsdusr_smbhash',
            'bsdusr_group',
        )
        fields = (
            'bsdusr_uid',
            'bsdusr_username',
            'bsdusr_creategroup',
            'bsdusr_home',
            'bsdusr_mode',
            'bsdusr_shell',
            'bsdusr_full_name',
            'bsdusr_email',
            'bsdusr_password',
            'bsdusr_password2',
            'bsdusr_password_disabled',
            'bsdusr_locked',
            'bsdusr_sshpubkey',
            'bsdusr_to_group',
        )

    def __init__(self, *args, **kwargs):
        #FIXME: Workaround for DOJO not showing select with blank values
        if len(args) > 0 and isinstance(args[0], QueryDict):
            new = args[0].copy()
            if new.get('bsdusr_group', None) == '-----':
                new['bsdusr_group'] = ''
            args = (new,) + args[1:]
        super(bsdUsersForm, self).__init__(*args, **kwargs)
        self.fields.keyOrder.remove('bsdusr_group')
        self.fields.keyOrder.insert(3, 'bsdusr_group')
        if self._api is True:
            del self.fields['bsdusr_password2']
        self.fields['bsdusr_shell'].choices = self._populate_shell_choices()
        self.fields['bsdusr_shell'].choices.sort()
        self.fields['bsdusr_to_group'].choices = [
            (x.id, x.bsdgrp_group) for x in models.bsdGroups.objects.all()
        ]
        self.fields['bsdusr_password_disabled'].widget.attrs['onChange'] = (
            'javascript:toggleGeneric("id_bsdusr_password_disabled", '
            '["id_bsdusr_locked"], false);')
        self.fields['bsdusr_locked'].widget.attrs['onChange'] = (
            'javascript:toggleGeneric("id_bsdusr_locked", '
            '["id_bsdusr_password_disabled"], false);')

        if not self.instance.id:
            self.fields['bsdusr_uid'].initial = notifier().user_getnextuid()
            self.fields['bsdusr_creategroup'].widget.attrs['onChange'] = (
                'javascript:toggleGeneric("id_bsdusr_creategroup", '
                '["id_bsdusr_group"], false);')
            self.fields['bsdusr_group'].widget.attrs['maxHeight'] = 200
            self.fields['bsdusr_group'].widget.attrs['disabled'] = 'disabled'
            self.fields['bsdusr_group'].choices = (
                ('-----', '-----'),
            ) + tuple(
                [x for x in self.fields['bsdusr_group'].choices][1:]
            )
            self.fields['bsdusr_group'].required = False

        elif self.instance.id:
            del self.fields['bsdusr_to_group']
            del self.fields['bsdusr_password']
            if self._api is False:
                del self.fields['bsdusr_password2']
            del self.fields['bsdusr_creategroup']
            self.fields['bsdusr_group'].initial = self.instance.bsdusr_group
            self.advanced_fields = []
            self.fields.keyOrder.remove('bsdusr_mode')
            self.fields.keyOrder.insert(
                len(self.fields.keyOrder) - 1,
                'bsdusr_mode',
            )
            self.fields['bsdusr_username'].widget.attrs['readonly'] = True
            self.fields['bsdusr_username'].widget.attrs['class'] = (
                'dijitDisabled dijitTextBoxDisabled '
                'dijitValidationTextBoxDisabled')
            if os.path.exists(self.instance.bsdusr_home):
                mode = os.stat(self.instance.bsdusr_home).st_mode & 0o777
                self.fields['bsdusr_mode'].initial = oct(mode)
            if self.instance.bsdusr_builtin:
                self.fields['bsdusr_uid'].widget.attrs['readonly'] = True
                self.fields['bsdusr_uid'].widget.attrs['class'] = (
                    'dijitDisabled dijitTextBoxDisabled '
                    'dijitValidationTextBoxDisabled'
                )
                self.fields['bsdusr_group'].widget.attrs['readonly'] = True
                self.fields['bsdusr_group'].widget.attrs['class'] = (
                    'dijitDisabled dijitSelectDisabled')
                self.fields['bsdusr_home'].widget.attrs['readonly'] = True
                self.fields['bsdusr_home'].widget.attrs['class'] = (
                    'dijitDisabled dijitTextBoxDisabled '
                    'dijitValidationTextBoxDisabled'
                )
                self.fields['bsdusr_mode'].widget.attrs['disabled'] = True
                self.fields['bsdusr_mode'].required = False
            try:
                self.fields['bsdusr_sshpubkey'].initial = open(
                    '%s/.ssh/authorized_keys' % (
                        self.instance.bsdusr_home,
                    )
                ).read()
            except:
                self.fields['bsdusr_sshpubkey'].initial = ''

    def clean_bsdusr_username(self):
        if self.instance.id is None:
            bsdusr_username = self.cleaned_data["bsdusr_username"]
            self.pw_checkname(bsdusr_username)
            try:
                models.bsdUsers.objects.get(bsdusr_username=bsdusr_username)
            except models.bsdUsers.DoesNotExist:
                return bsdusr_username
            raise forms.ValidationError(
                _("A user with that username already exists.")
            )
        else:
            return self.instance.bsdusr_username

    def clean_bsdusr_uid(self):
        if self.instance.id and self.instance.bsdusr_builtin:
            return self.instance.bsdusr_uid
        else:
            return self.cleaned_data.get("bsdusr_uid")

    def clean_bsdusr_group(self):
        if self.instance.id and self.instance.bsdusr_builtin:
            return self.instance.bsdusr_group
        else:
            create = self.cleaned_data.get("bsdusr_creategroup")
            group = self.cleaned_data.get("bsdusr_group")
            if not group and not create:
                raise forms.ValidationError(_("This field is required"))
            return group

    def clean_bsdusr_password2(self):
        bsdusr_password = self.cleaned_data.get("bsdusr_password", "")
        bsdusr_password2 = self.cleaned_data["bsdusr_password2"]
        if bsdusr_password != bsdusr_password2:
            raise forms.ValidationError(
                _("The two password fields didn't match.")
            )
        return bsdusr_password2

    def clean_bsdusr_home(self):
        home = self.cleaned_data['bsdusr_home']
        if home is not None:
            if ':' in home:
                raise forms.ValidationError(
                    _("Home directory cannot contain colons")
                )
            if home.startswith(u'/mnt/') or home == u'/nonexistent':
                return home
        raise forms.ValidationError(
            _('Home directory has to start with /mnt/ or be /nonexistent')
        )

    def clean_bsdusr_mode(self):
        mode = self.cleaned_data.get('bsdusr_mode')
        if not self.instance.id and not mode:
            return '755'
        return mode

    def clean_bsdusr_sshpubkey(self):
        ssh = self.cleaned_data.get('bsdusr_sshpubkey', '')
        ssh = ssh.strip(' ').strip('\n')
        ssh = re.sub(r'[ ]{2,}', ' ', ssh, re.M)
        ssh = re.sub(r'\n{2,}', '\n', ssh, re.M)
        old = ssh
        while True:
            ssh = re.sub(r'(\S{10,})\n(\S{10,})', '\\1\\2', ssh, re.M)
            if ssh == old:
                break
            old = ssh
        return ssh

    def clean_bsdusr_full_name(self):
        name = self.cleaned_data["bsdusr_full_name"]
        self.pw_checkfullname(name)
        return name

    def clean_bsdusr_to_group(self):
        v = self.cleaned_data.get("bsdusr_to_group")
        if len(v) > 64:
            raise forms.ValidationError(
                _("A user cannot belong to more than 64 auxiliary groups"))
        return v

    def clean(self):
        cleaned_data = self.cleaned_data

        password_disable = cleaned_data["bsdusr_password_disabled"] = (
            cleaned_data.get("bsdusr_password_disabled", False)
        )
        bsdusr_home = cleaned_data.get('bsdusr_home', '')
        if (
            bsdusr_home and cleaned_data.get('bsdusr_sshpubkey') and
            not bsdusr_home.startswith(u'/mnt/')
        ):
            del cleaned_data['bsdusr_sshpubkey']
            self._errors['bsdusr_sshpubkey'] = self.error_class([
                _("Home directory is not writable, leave this blank")])
        if self.instance.id is None:
            FIELDS = ['bsdusr_password', 'bsdusr_password2']
            if password_disable:
                for field in FIELDS:
                    if field in cleaned_data and cleaned_data.get(field) != '':
                        self._errors[field] = self.error_class([
                            _("Password is disabled, leave this blank")])
                        del cleaned_data[field]
            else:
                for field in FIELDS:
                    if field in cleaned_data and cleaned_data.get(field) == '':
                        self._errors[field] = self.error_class([
                            _("This field is required.")])
                        del cleaned_data[field]

        return cleaned_data

    def save(self, commit=True):
        _notifier = notifier()
        if self.instance.id is None:
            group = self.cleaned_data['bsdusr_group']
            if group is None:
                try:
                    gid = models.bsdGroups.objects.get(
                        bsdgrp_group=self.cleaned_data['bsdusr_username']
                    ).bsdgrp_gid
                except:
                    gid = -1
            else:
                gid = group.bsdgrp_gid
            uid, gid, unixhash, smbhash = _notifier.user_create(
                username=str(self.cleaned_data['bsdusr_username']),
                fullname=self.cleaned_data['bsdusr_full_name'].encode(
                    'utf8', 'ignore'
                ).replace(':', ''),
                password=self.cleaned_data['bsdusr_password'].encode(
                    'utf8', 'ignore'
                ),
                uid=self.cleaned_data['bsdusr_uid'],
                gid=gid,
                shell=str(self.cleaned_data['bsdusr_shell']),
                homedir=str(self.cleaned_data['bsdusr_home']),
                homedir_mode=int(
                    self.cleaned_data.get('bsdusr_mode', '755'),
                    8
                ),
                password_disabled=self.cleaned_data.get(
                    'bsdusr_password_disabled', False
                ),
            )
            bsduser = super(bsdUsersForm, self).save(commit=False)
            try:
                grp = models.bsdGroups.objects.get(bsdgrp_gid=gid)
            except models.bsdGroups.DoesNotExist:
                grp = models.bsdGroups(
                    bsdgrp_gid=gid,
                    bsdgrp_group=self.cleaned_data['bsdusr_username'],
                    bsdgrp_builtin=False,
                )
                grp.save()
            bsduser.bsdusr_group = grp
            bsduser.bsdusr_uid = uid
            bsduser.bsdusr_shell = self.cleaned_data['bsdusr_shell']
            bsduser.bsdusr_unixhash = unixhash
            bsduser.bsdusr_smbhash = smbhash
            bsduser.bsdusr_builtin = False
            bsduser.save()

            models.bsdGroupMembership.objects.filter(
                bsdgrpmember_user=bsduser).delete()
            groupid_list = self.cleaned_data['bsdusr_to_group']
            for groupid in groupid_list:
                group = models.bsdGroups.objects.get(id=groupid)
                m = models.bsdGroupMembership(
                    bsdgrpmember_group=group,
                    bsdgrpmember_user=bsduser)
                m.save()
        else:
            bsduser = super(bsdUsersForm, self).save(commit=False)
        _notifier.reload("user")
        bsdusr_sshpubkey = self.cleaned_data.get('bsdusr_sshpubkey')
        if bsdusr_sshpubkey:
            _notifier.save_pubkey(
                bsduser.bsdusr_home,
                bsdusr_sshpubkey,
                bsduser.bsdusr_username,
                bsduser.bsdusr_group.bsdgrp_group)
        return bsduser
Exemple #17
0
class bsdUsersForm(ModelForm, bsdUserGroupMixin):

    bsdusr_username = forms.CharField(
        label=_("Username"),
        max_length=16)
    bsdusr_password = forms.CharField(
        label=_("Password"),
        widget=forms.PasswordInput,
        required=False)
    bsdusr_password2 = forms.CharField(
        label=_("Password confirmation"),
        widget=forms.PasswordInput,
        help_text=_("Enter the same password as above, for verification."),
        required=False)
    bsdusr_group = forms.ModelChoiceField(
        label=_("Primary Group"),
        queryset=models.bsdGroups.objects.all(),
        required=False)
    bsdusr_shell = forms.ChoiceField(
        label=_("Shell"),
        initial=u'/bin/csh',
        choices=())
    bsdusr_creategroup = forms.BooleanField(
        label=_("Create a new primary group for the user"),
        required=False,
        initial=True)
    bsdusr_sshpubkey = forms.CharField(
        label=_("SSH Public Key"),
        widget=forms.Textarea,
        required=False)
    bsdusr_mode = UnixPermissionField(
        label=_('Home Directory Mode'),
        initial='755',
        required=False)
    bsdusr_to_group = SelectMultipleField(
        label=_('Auxiliary groups'),
        choices=(),
        required=False)
    advanced_fields = ['bsdusr_mode']

    class Meta:
        model = models.bsdUsers
        widgets = {
            'bsdusr_uid': forms.widgets.ValidationTextInput(),
        }
        exclude = (
            'bsdusr_unixhash',
            'bsdusr_smbhash',
            'bsdusr_group',
        )
        fields = (
            'bsdusr_uid',
            'bsdusr_username',
            'bsdusr_creategroup',
            'bsdusr_home',
            'bsdusr_mode',
            'bsdusr_shell',
            'bsdusr_full_name',
            'bsdusr_email',
            'bsdusr_password',
            'bsdusr_password2',
            'bsdusr_password_disabled',
            'bsdusr_locked',
            'bsdusr_sudo',
            'bsdusr_microsoft_account',
            'bsdusr_sshpubkey',
            'bsdusr_to_group',
        )

    def __init__(self, *args, **kwargs):
        #FIXME: Workaround for DOJO not showing select with blank values
        if len(args) > 0 and isinstance(args[0], QueryDict):
            new = args[0].copy()
            if new.get('bsdusr_group', None) == '-----':
                new['bsdusr_group'] = ''
            args = (new,) + args[1:]
        super(bsdUsersForm, self).__init__(*args, **kwargs)
        self.fields.keyOrder.remove('bsdusr_group')
        self.fields.keyOrder.insert(3, 'bsdusr_group')
        if self._api is True:
            del self.fields['bsdusr_password2']
        self.fields['bsdusr_shell'].choices = self._populate_shell_choices()
        self.fields['bsdusr_shell'].choices.sort()
        self.fields['bsdusr_to_group'].choices = [
            (x.id, x.bsdgrp_group)
            for x in models.bsdGroups.objects.all()
        ]
        self.fields['bsdusr_password_disabled'].widget.attrs['onChange'] = (
            'javascript:toggleGeneric("id_bsdusr_password_disabled", '
            '["id_bsdusr_locked", "id_bsdusr_sudo"], false);')
        self.fields['bsdusr_locked'].widget.attrs['onChange'] = (
            'javascript:toggleGeneric("id_bsdusr_locked", '
            '["id_bsdusr_password_disabled"], false);')
        self.fields['bsdusr_sudo'].widget.attrs['onChange'] = (
            'javascript:toggleGeneric("id_bsdusr_sudo", '
            '["id_bsdusr_password_disabled"], false);')

        if not self.instance.id:
            try:
                self.fields['bsdusr_uid'].initial = notifier().user_getnextuid()
            except:
                pass
            self.fields['bsdusr_home'].label = _('Create Home Directory In')
            self.fields['bsdusr_creategroup'].widget.attrs['onChange'] = (
                'javascript:toggleGeneric("id_bsdusr_creategroup", '
                '["id_bsdusr_group"], false);')
            self.fields['bsdusr_group'].widget.attrs['maxHeight'] = 200
            self.fields['bsdusr_group'].widget.attrs['disabled'] = 'disabled'
            self.fields['bsdusr_group'].choices = (
                ('-----', '-----'),
            ) + tuple(
                [x for x in self.fields['bsdusr_group'].choices][1:]
            )
            self.fields['bsdusr_group'].required = False
            self.bsdusr_home_saved = u'/nonexistent'
            self.bsdusr_home_copy = False

        elif self.instance.id:
            self.fields['bsdusr_to_group'].initial = [
                x.bsdgrpmember_group.id
                for x in models.bsdGroupMembership.objects.filter(
                    bsdgrpmember_user=self.instance.id
                )
            ]

            del self.fields['bsdusr_creategroup']
            self.fields['bsdusr_group'].initial = self.instance.bsdusr_group
            self.advanced_fields = []
            self.bsdusr_home_saved = self.instance.bsdusr_home
            self.bsdusr_home_copy = False
            self.fields.keyOrder.remove('bsdusr_mode')
            self.fields.keyOrder.insert(
                len(self.fields.keyOrder) - 1,
                'bsdusr_mode',
            )
            self.fields['bsdusr_username'].widget.attrs['readonly'] = True
            self.fields['bsdusr_username'].widget.attrs['class'] = (
                'dijitDisabled dijitTextBoxDisabled '
                'dijitValidationTextBoxDisabled')
            if os.path.exists(self.instance.bsdusr_home):
                mode = os.stat(self.instance.bsdusr_home).st_mode & 0o777
                self.fields['bsdusr_mode'].initial = oct(mode)
            if self.instance.bsdusr_builtin:
                self.fields['bsdusr_uid'].widget.attrs['readonly'] = True
                self.fields['bsdusr_uid'].widget.attrs['class'] = (
                    'dijitDisabled dijitTextBoxDisabled '
                    'dijitValidationTextBoxDisabled'
                )
                self.fields['bsdusr_group'].widget.attrs['readonly'] = True
                self.fields['bsdusr_group'].widget.attrs['class'] = (
                    'dijitDisabled dijitSelectDisabled')
                self.fields['bsdusr_home'].widget.attrs['readonly'] = True
                self.fields['bsdusr_home'].widget.attrs['class'] = (
                    'dijitDisabled dijitTextBoxDisabled '
                    'dijitValidationTextBoxDisabled'
                )
                self.fields['bsdusr_mode'].widget.attrs['disabled'] = True
                self.fields['bsdusr_mode'].required = False
            if self.instance.bsdusr_locked or self.instance.bsdusr_sudo:
                self.fields['bsdusr_password_disabled'].widget.attrs[
                    'disabled'
                ] = True
            if self.instance.bsdusr_password_disabled is True:
                self.fields['bsdusr_locked'].widget.attrs['disabled'] = True
                self.fields['bsdusr_sudo'].widget.attrs['disabled'] = True
            self.fields['bsdusr_sshpubkey'].initial = (
                self.instance.bsdusr_sshpubkey
            )

    def clean_bsdusr_username(self):
        if self.instance.id is None:
            bsdusr_username = self.cleaned_data["bsdusr_username"]
            self.pw_checkname(bsdusr_username)
            try:
                models.bsdUsers.objects.get(bsdusr_username=bsdusr_username)
            except models.bsdUsers.DoesNotExist:
                return bsdusr_username
            raise forms.ValidationError(
                _("A user with that username already exists.")
            )
        else:
            return self.instance.bsdusr_username

    def clean_bsdusr_uid(self):
        if self.instance.id and self.instance.bsdusr_builtin:
            return self.instance.bsdusr_uid
        else:
            return self.cleaned_data.get("bsdusr_uid")

    def clean_bsdusr_group(self):
        if self.instance.id and self.instance.bsdusr_builtin:
            return self.instance.bsdusr_group
        else:
            create = self.cleaned_data.get("bsdusr_creategroup")
            group = self.cleaned_data.get("bsdusr_group")
            if not group and not create:
                raise forms.ValidationError(_("This field is required"))
            return group

    def clean_bsdusr_password(self):
        bsdusr_password = self.cleaned_data.get('bsdusr_password')
        # See bug #4098
        if bsdusr_password and '?' in bsdusr_password:
            raise forms.ValidationError(_(
                'Passwords containing a question mark (?) are currently not '
                'allowed due to problems with SMB.'
            ))
        return bsdusr_password

    def clean_bsdusr_password2(self):
        bsdusr_password = self.cleaned_data.get("bsdusr_password", "")
        bsdusr_password2 = self.cleaned_data["bsdusr_password2"]
        if bsdusr_password and bsdusr_password != bsdusr_password2:
            raise forms.ValidationError(
                _("The two password fields didn't match.")
            )
        return bsdusr_password2

    def clean_bsdusr_home(self):
        home = self.cleaned_data['bsdusr_home']
        if self.instance.id and self.instance.bsdusr_uid == 0:
            return self.instance.bsdusr_home
        elif home is not None:
            if ':' in home:
                raise forms.ValidationError(
                    _("Home directory cannot contain colons")
                )

            if home == u'/nonexistent':
                return home

            if home.startswith(u'/mnt/'):
                bsdusr_username = self.cleaned_data.get('bsdusr_username', '')
                saved_home = self.bsdusr_home_saved

                if home.endswith(bsdusr_username):
                    if home != saved_home:
                        self.bsdusr_home_copy = True
                    return home

                if not self.instance.id:
                    home = "%s/%s" % (home.rstrip('/'), bsdusr_username)

                if not self.instance.id and not home.endswith(bsdusr_username):
                    raise forms.ValidationError(
                        _('Home directory must end with username')
                    )

                if home != saved_home:
                    self.bsdusr_home_copy = True

                return home

        raise forms.ValidationError(
            _('Home directory has to start with /mnt/ or be /nonexistent')
        )

    def clean_bsdusr_mode(self):
        mode = self.cleaned_data.get('bsdusr_mode')
        if not self.instance.id and not mode:
            return '755'
        return mode

    def clean_bsdusr_sshpubkey(self):
        ssh = self.cleaned_data.get('bsdusr_sshpubkey', '')
        ssh = ssh.strip(' ').strip('\n')
        ssh = re.sub(r'[ ]{2,}', ' ', ssh, re.M)
        ssh = re.sub(r'\n{2,}', '\n', ssh, re.M)
        old = ssh
        while True:
            ssh = re.sub(r'(\S{15,})\n(\S{15,})', '\\1\\2', ssh, re.M)
            if ssh == old:
                break
            old = ssh
        return ssh

    def clean_bsdusr_full_name(self):
        name = self.cleaned_data["bsdusr_full_name"]
        self.pw_checkfullname(name)
        return name

    def clean_bsdusr_to_group(self):
        v = self.cleaned_data.get("bsdusr_to_group")
        if len(v) > 64:
            raise forms.ValidationError(
                _("A user cannot belong to more than 64 auxiliary groups"))
        return v

    def clean(self):
        cleaned_data = self.cleaned_data

        password_disable = cleaned_data["bsdusr_password_disabled"] = (
            cleaned_data.get("bsdusr_password_disabled", False)
        )
        bsdusr_home = cleaned_data.get('bsdusr_home', '')
        if (
            bsdusr_home and cleaned_data.get('bsdusr_sshpubkey') and
            (
                not bsdusr_home.startswith(u'/mnt/') and (
                    self.instance.id is None or
                    (self.instance.id and self.instance.bsdusr_uid != 0)
                )
            )
        ):
            del cleaned_data['bsdusr_sshpubkey']
            self._errors['bsdusr_sshpubkey'] = self.error_class([
                _("Home directory is not writable, leave this blank")])
        if self.instance.id is None:
            FIELDS = ['bsdusr_password', 'bsdusr_password2']
            if password_disable:
                for field in FIELDS:
                    if field in cleaned_data and cleaned_data.get(field) != '':
                        self._errors[field] = self.error_class([
                            _("Password is disabled, leave this blank")])
                        del cleaned_data[field]
            else:
                for field in FIELDS:
                    if field in cleaned_data and cleaned_data.get(field) == '':
                        self._errors[field] = self.error_class([
                            _("This field is required.")])
                        del cleaned_data[field]

        return cleaned_data

    def save(self, commit=True):
        _notifier = notifier()
        if self.instance.id is None:
            group = self.cleaned_data['bsdusr_group']
            if group is None:
                try:
                    gid = models.bsdGroups.objects.get(
                        bsdgrp_group=self.cleaned_data['bsdusr_username']
                    ).bsdgrp_gid
                except:
                    gid = -1
            else:
                gid = group.bsdgrp_gid
            uid, gid, unixhash, smbhash = _notifier.user_create(
                username=self.cleaned_data['bsdusr_username'].encode(
                    'utf8', 'ignore'
                ),
                fullname=self.cleaned_data['bsdusr_full_name'].encode(
                    'utf8', 'ignore'
                ).replace(':', ''),
                password=self.cleaned_data['bsdusr_password'].encode(
                    'utf8', 'ignore'
                ),
                uid=self.cleaned_data['bsdusr_uid'],
                gid=gid,
                shell=str(self.cleaned_data['bsdusr_shell']),
                homedir=str(self.cleaned_data['bsdusr_home']),
                homedir_mode=int(
                    self.cleaned_data.get('bsdusr_mode', '755'),
                    8
                ),
                password_disabled=self.cleaned_data.get(
                    'bsdusr_password_disabled', False
                ),
            )
            bsduser = super(bsdUsersForm, self).save(commit=False)
            try:
                grp = models.bsdGroups.objects.get(bsdgrp_gid=gid)
            except models.bsdGroups.DoesNotExist:
                grp = models.bsdGroups(
                    bsdgrp_gid=gid,
                    bsdgrp_group=self.cleaned_data['bsdusr_username'],
                    bsdgrp_builtin=False,
                )
                grp.save()
            bsduser.bsdusr_group = grp
            bsduser.bsdusr_uid = uid
            bsduser.bsdusr_shell = self.cleaned_data['bsdusr_shell']
            bsduser.bsdusr_unixhash = unixhash
            bsduser.bsdusr_smbhash = smbhash
            bsduser.bsdusr_builtin = False
            bsduser.save()

        else:
            bsduser = super(bsdUsersForm, self).save(commit=False)
            bsduser.bsdusr_group = self.cleaned_data['bsdusr_group']
            bsduser.save()

            #
            # Check if updating password
            #
            bsdusr_password = self.cleaned_data.get("bsdusr_password", "")
            if self._api is True:
                bsdusr_password2 = bsdusr_password
            else:
                bsdusr_password2 = self.cleaned_data["bsdusr_password2"]
            if bsdusr_password and (bsdusr_password == bsdusr_password2):
                unixhash, smbhash = _notifier.user_changepassword(
                    username=bsduser.bsdusr_username.encode('utf8'),
                    password=bsdusr_password.encode('utf8'),
                )
                bsduser.bsdusr_unixhash = unixhash
                bsduser.bsdusr_smbhash = smbhash
                bsduser.save()

            homedir_mode = self.cleaned_data.get('bsdusr_mode')
            if (
                not bsduser.bsdusr_builtin and homedir_mode is not None and
                os.path.exists(bsduser.bsdusr_home)
            ):
                try:
                    homedir_mode = int(homedir_mode, 8)
                    os.chmod(bsduser.bsdusr_home, homedir_mode)
                except:
                    log.warn('Failed to set homedir mode', exc_info=True)

        #
        # Check if updating group membership
        #
        models.bsdGroupMembership.objects.filter(
            bsdgrpmember_user=bsduser
        ).delete()
        groupid_list = self.cleaned_data['bsdusr_to_group']
        for groupid in groupid_list:
            group = models.bsdGroups.objects.get(id=groupid)
            m = models.bsdGroupMembership(
                bsdgrpmember_group=group,
                bsdgrpmember_user=bsduser)
            m.save()

        _notifier.reload("user")
        if self.bsdusr_home_copy:
            p = pipeopen("su - %s -c '/bin/cp -a %s/* %s/'" % (
                self.cleaned_data['bsdusr_username'],
                self.bsdusr_home_saved,
                self.cleaned_data['bsdusr_home']
            ))
            p.communicate()

        bsdusr_sshpubkey = self.cleaned_data.get('bsdusr_sshpubkey')
        if bsdusr_sshpubkey:
            _notifier.save_pubkey(
                bsduser.bsdusr_home,
                bsdusr_sshpubkey,
                bsduser.bsdusr_username,
                bsduser.bsdusr_group.bsdgrp_group)
        else:
            _notifier.delete_pubkey(bsduser.bsdusr_home)
        return bsduser

    def delete(self, **kwargs):
        if self.data.get('nodelgroup'):
            kwargs['delete_group'] = False
        else:
            kwargs['delete_group'] = True
        super(bsdUsersForm, self).delete(**kwargs)
Exemple #18
0
class CloudSyncForm(ModelForm):

    attributes = forms.CharField(
        widget=CloudSyncWidget(),
        label=_('Provider'),
    )
    bwlimit = forms.CharField(
        label=_('Bandwidth limit'),
        help_text=
        _('Either single bandwidth limit or bandwidth limit schedule in rclone format.<br />'
          'Example: "08:00,512 12:00,10M 13:00,512 18:00,30M 23:00,off".<br />'
          'Default unit is kilobytes.'))
    exclude = forms.CharField(
        label=_('Exclude'),
        help_text=
        _('Newline-separated list of files and directories to exclude from sync.<br />'
          'See https://rclone.org/filtering/ for more details on --exclude option.'
          ),
        widget=forms.Textarea(),
    )

    class Meta:
        exclude = ('credential', 'args')
        fields = '__all__'
        model = models.CloudSync
        widgets = {
            'minute':
            CronMultiple(attrs={
                'numChoices': 60,
                'label': _("minute")
            }),
            'hour':
            CronMultiple(attrs={
                'numChoices': 24,
                'label': _("hour")
            }),
            'daymonth':
            CronMultiple(attrs={
                'numChoices': 31,
                'start': 1,
                'label': _("day of month"),
            }),
            'dayweek':
            forms.CheckboxSelectMultiple(choices=choices.WEEKDAYS_CHOICES),
            'month':
            forms.CheckboxSelectMultiple(choices=choices.MONTHS_CHOICES),
        }

    def __init__(self, *args, **kwargs):
        if "instance" in kwargs:
            kwargs.setdefault("initial", {})
            try:
                kwargs["initial"]["encryption_password"] = notifier(
                ).pwenc_decrypt(kwargs["instance"].encryption_password)
            except Exception:
                pass
            try:
                kwargs["initial"]["encryption_salt"] = notifier(
                ).pwenc_decrypt(kwargs["instance"].encryption_salt)
            except Exception:
                pass

            if len(kwargs["instance"].bwlimit
                   ) == 1 and kwargs["instance"].bwlimit[0]["time"] == "00:00":
                kwargs["initial"]["bwlimit"] = humanize_size_rclone(
                    kwargs["instance"].bwlimit[0]['bandwidth'])
            else:
                kwargs["initial"]["bwlimit"] = " ".join([
                    f"{limit['time']},{humanize_size_rclone(limit['bandwidth']) if limit['bandwidth'] else 'off'}"
                    for limit in kwargs["instance"].bwlimit
                ])

            kwargs["initial"]["exclude"] = "\n".join(
                kwargs["instance"].exclude)

        super(CloudSyncForm, self).__init__(*args, **kwargs)
        key_order(self, 2, 'attributes', instance=True)
        mchoicefield(self, 'month', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
        mchoicefield(self, 'dayweek', [1, 2, 3, 4, 5, 6, 7])
        if self.instance.id:
            self.fields['attributes'].initial = {
                'credential': self.instance.credential.id,
            }
            self.fields['attributes'].initial.update(self.instance.attributes)

        self.fields['direction'].widget.attrs['onChange'] = (
            "cloudSyncDirectionToggle();")

    def clean_attributes(self):
        attributes = self.cleaned_data.get('attributes')
        try:
            attributes = json.loads(attributes)
        except ValueError:
            raise forms.ValidationError(_('Invalid provider details.'))

        credential = attributes.get('credential')
        if not credential:
            raise forms.ValidationError(_('This field is required.'))
        qs = CloudCredentials.objects.filter(id=credential)
        if not qs.exists():
            raise forms.ValidationError(_('Invalid credential.'))

        return attributes

    def clean_month(self):
        m = self.data.getlist('month')
        if len(m) == 12:
            return '*'
        m = ','.join(m)
        return m

    def clean_dayweek(self):
        w = self.data.getlist('dayweek')
        if w == '*':
            return w
        if len(w) == 7:
            return '*'
        w = ','.join(w)
        return w

    def clean_bwlimit(self):
        v = self.cleaned_data.get('bwlimit')
        if "," not in v:
            v = f"00:00,{v}"

        bwlimit = []
        for t in v.split():
            try:
                time_, bandwidth = t.split(",", 1)
            except ValueError:
                raise forms.ValidationError(_('Invalid value: %r') % t)

            try:
                h, m = time_.split(":", 1)
            except ValueError:
                raise forms.ValidationError(_('Invalid time: %r') % time_)

            try:
                time(int(h), int(m))
            except ValueError:
                raise forms.ValidationError(_('Invalid time: %r') % time_)

            if bandwidth == "off":
                bandwidth = None
            else:
                try:
                    bandwidth = int(bandwidth) * 1024
                except ValueError:
                    try:
                        bandwidth = int(bandwidth[:-1]) * {
                            "b": 1,
                            "k": 1024,
                            "M": 1024 * 1024,
                            "G": 1024 * 1024 * 1024
                        }[bandwidth[-1]]
                    except (KeyError, ValueError):
                        raise forms.ValidationError(
                            _('Invalid bandwidth: %r') % bandwidth)

            bwlimit.append({
                "time": time_,
                "bandwidth": bandwidth,
            })

        for a, b in zip(bwlimit, bwlimit[1:]):
            if a["time"] >= b["time"]:
                raise forms.ValidationError(
                    _('Invalid time order: %s, %s') % (a["time"], b["time"]))

        return bwlimit

    def clean_exclude(self):
        return list(
            filter(
                None,
                map(lambda s: s.strip(),
                    self.cleaned_data.get('exclude').split('\n'))))

    def save(self, **kwargs):
        with client as c:
            cdata = self.cleaned_data
            cdata['credentials'] = cdata['attributes'].pop('credential')
            cdata['schedule'] = {
                'minute': cdata.pop('minute'),
                'hour': cdata.pop('hour'),
                'dom': cdata.pop('daymonth'),
                'month': cdata.pop('month'),
                'dow': cdata.pop('dayweek')
            }
            if self.instance.id:
                c.call('cloudsync.update', self.instance.id, cdata)
            else:
                self.instance = models.CloudSync.objects.get(
                    pk=c.call('cloudsync.create', cdata)['id'])
        return self.instance

    def delete(self, **kwargs):
        with client as c:
            c.call('cloudsync.delete', self.instance.id)
Exemple #19
0
class DeviceForm(ModelForm):

    CDROM_path = PathField(
        label=_('CD-ROM (ISO)'),
        required=False,
        dirsonly=False,
    )
    DISK_zvol = forms.ChoiceField(
        label=_('ZVol'),
        required=False,
    )
    DISK_mode = forms.ChoiceField(
        label=_('Mode'),
        choices=choices.VM_DISKMODETYPES,
        required=False,
        initial='AHCI',
    )
    DISK_raw = PathField(
        label=_('Raw File'),
        required=False,
        dirsonly=False,
    )
    DISK_raw_boot = forms.BooleanField(
        label=_('Disk boot'),
        widget=forms.widgets.HiddenInput(),
        required=False,
        initial=False,
    )
    ROOT_password = forms.CharField(
        label=_('Password'),
        max_length=50,
        widget=forms.widgets.HiddenInput(),
        required=False,
        help_text=_("Set the password for the rancher user."),
    )
    DISK_sectorsize = forms.IntegerField(
        label=_('Disk sectorsize'),
        required=False,
        initial=0,
        help_text=_(
            "Sector size of the emulated disk in bytes. Both logical and physical sector size are set to this value."
            "If 0, a sector size is not set."),
    )
    DISK_raw_size = forms.CharField(
        label=_('Disk size'),
        widget=forms.widgets.HiddenInput(),
        required=False,
        initial=0,
        validators=[
            RegexValidator(
                "^(\d*)\s?([M|G|T]?)$",
                "Enter M, G, or T after the value to use megabytes, gigabytes or terabytes."
                " When no suffix letter is entered, the units default to gigabytes."
            )
        ],
        help_text=
        _("Resize the existing raw disk. Enter 0 to use the disk with the current size."
          ),
    )
    NIC_type = forms.ChoiceField(
        label=_('Adapter Type'),
        choices=choices.VM_NICTYPES,
        required=False,
        initial='E1000',
    )
    NIC_attach = forms.ChoiceField(
        label=_('NIC to attach'),
        choices=choices.NICChoices(exclude_configured=False),
        required=False,
    )
    NIC_mac = forms.CharField(
        label=_('MAC Address'),
        required=False,
        help_text=
        _("Specify the adapter MAC Address or leave empty to be auto generated."
          ),
        validators=[
            RegexValidator("^([0-9a-fA-F]{2}([::]?|$)){6}$",
                           "Invalid MAC format.")
        ],
        initial='00:a0:98:FF:FF:FF',
    )
    VNC_resolution = forms.ChoiceField(
        label=_('Resolution'),
        choices=choices.VNC_RESOLUTION,
        required=False,
        initial='1024x768',
    )
    VNC_port = forms.CharField(
        label=_('VNC port'),
        required=False,
        help_text=_("Specify the VNC port or set to 0 for auto."),
        validators=[RegexValidator("^[0-9]*$", "Only integers are accepted")],
        initial=0,
    )
    VNC_bind = forms.ChoiceField(
        label=_('Bind to'),
        choices=(),
        required=False,
    )
    VNC_wait = forms.BooleanField(
        label=_('Wait to boot'),
        required=False,
    )
    VNC_password = forms.CharField(
        label=_('Password'),
        max_length=8,
        widget=forms.PasswordInput(render_value=True, ),
        required=False,
        help_text=_("The VNC password authentication."
                    "Maximum password length is 8 characters."))
    VNC_web = forms.BooleanField(
        label=_('VNC Web'),
        required=False,
    )

    class Meta:
        fields = '__all__'
        model = models.Device

    def __init__(self, *args, **kwargs):
        super(DeviceForm, self).__init__(*args, **kwargs)
        self.fields['dtype'].widget.attrs['onChange'] = ("deviceTypeToggle();")

        self.fields['VNC_bind'].choices = self.ipv4_list()

        diskchoices = {}
        _n = notifier()
        used_zvol = []
        for volume in Volume.objects.filter():
            zvols = _n.list_zfs_vols(volume.vol_name, sort='name')
            for zvol, attrs in zvols.items():
                if "zvol/" + zvol not in used_zvol:
                    diskchoices["zvol/" + zvol] = "%s (%s)" % (
                        zvol, humanize_size(attrs['volsize']))
        self.fields['DISK_zvol'].choices = diskchoices.items()

        if self.instance.id:
            if self.instance.dtype == 'CDROM':
                self.fields[
                    'CDROM_path'].initial = self.instance.attributes.get(
                        'path', '')
            elif self.instance.dtype == 'DISK':
                self.fields[
                    'DISK_zvol'].initial = self.instance.attributes.get(
                        'path', '').replace('/dev/', '')
                self.fields[
                    'DISK_mode'].initial = self.instance.attributes.get('type')
                self.fields[
                    'DISK_sectorsize'].initial = self.instance.attributes.get(
                        'sectorsize', 0)
            elif self.instance.dtype == 'RAW':
                self.fields['DISK_raw'].initial = self.instance.attributes.get(
                    'path', '')
                self.fields[
                    'DISK_mode'].initial = self.instance.attributes.get('type')
                self.fields[
                    'DISK_sectorsize'].initial = self.instance.attributes.get(
                        'sectorsize', 0)

                if self.instance.vm.vm_type == 'Container Provider':
                    self.fields['DISK_raw_boot'].widget = forms.CheckboxInput()
                    self.fields['DISK_raw_size'].widget = forms.TextInput()
                    self.fields['ROOT_password'].widget = forms.PasswordInput(
                        render_value=True, )

                self.fields[
                    'DISK_raw_boot'].initial = self.instance.attributes.get(
                        'boot', False)
                self.fields[
                    'DISK_raw_size'].initial = self.instance.attributes.get(
                        'size', '')
                self.fields[
                    'ROOT_password'].initial = self.instance.attributes.get(
                        'rootpwd', '')
            elif self.instance.dtype == 'NIC':
                self.fields['NIC_type'].initial = self.instance.attributes.get(
                    'type')
                self.fields['NIC_mac'].initial = self.instance.attributes.get(
                    'mac')
                self.fields[
                    'NIC_attach'].initial = self.instance.attributes.get(
                        'nic_attach')
            elif self.instance.dtype == 'VNC':
                vnc_port = self.instance.attributes.get('vnc_port')
                vnc_port = 0 if vnc_port is None else vnc_port

                self.fields['VNC_wait'].initial = self.instance.attributes.get(
                    'wait')
                self.fields['VNC_port'].initial = vnc_port
                self.fields[
                    'VNC_resolution'].initial = self.instance.attributes.get(
                        'vnc_resolution')
                self.fields['VNC_bind'].initial = self.instance.attributes.get(
                    'vnc_bind')
                self.fields[
                    'VNC_password'].initial = self.instance.attributes.get(
                        'vnc_password')
                self.fields['VNC_web'].initial = self.instance.attributes.get(
                    'vnc_web')

    def ipv4_list(self):
        choices = ()
        with client as c:
            ipv4_addresses = c.call('interfaces.ipv4_in_use')
        for ipv4_addr in ipv4_addresses:
            choices = choices + ((ipv4_addr, ipv4_addr), )
        return choices

    def clean(self):
        vm = self.cleaned_data.get('vm')
        vnc_port = self.cleaned_data.get('VNC_port')
        new_vnc_port = 5900
        if vm and vnc_port == '0':
            new_vnc_port = new_vnc_port + int(vm.id)
            self.cleaned_data['VNC_port'] = str(new_vnc_port)

        return self.cleaned_data

    def is_container(self, vm_type):
        if vm_type == 'Container Provider':
            return True
        else:
            return False

    def save(self, *args, **kwargs):
        vm = self.cleaned_data.get('vm')
        kwargs['commit'] = False
        obj = super(DeviceForm, self).save(*args, **kwargs)

        if self.cleaned_data['dtype'] == 'DISK':
            obj.attributes = {
                'path': '/dev/' + self.cleaned_data['DISK_zvol'],
                'type': self.cleaned_data['DISK_mode'],
                'sectorsize': self.cleaned_data['DISK_sectorsize'],
            }
        elif self.cleaned_data['dtype'] == 'RAW':
            if self.is_container(vm.vm_type):
                if self.cleaned_data['DISK_mode'] == 'VIRTIO':
                    self._errors['dtype'] = self.error_class(
                        [_('Containers require AHCI mode.')])
            obj.attributes = {
                'path': self.cleaned_data['DISK_raw'],
                'type': self.cleaned_data['DISK_mode'],
                'sectorsize': self.cleaned_data['DISK_sectorsize'],
                'boot': self.cleaned_data['DISK_raw_boot'],
                'size': self.cleaned_data['DISK_raw_size'],
                'rootpwd': self.cleaned_data['ROOT_password'],
            }
        elif self.cleaned_data['dtype'] == 'CDROM':
            cdrom_path = self.cleaned_data['CDROM_path']
            if cdrom_path:
                obj.attributes = {
                    'path': cdrom_path,
                }
            else:
                self._errors['CDROM_path'] = self.error_class(
                    [_('Please choose an ISO file.')])
        elif self.cleaned_data['dtype'] == 'NIC':
            obj.attributes = {
                'type': self.cleaned_data['NIC_type'],
                'mac': self.cleaned_data['NIC_mac'],
                'nic_attach': self.cleaned_data['NIC_attach'],
            }
        elif self.cleaned_data['dtype'] == 'VNC':
            if vm.bootloader == 'UEFI' and self.is_container(
                    vm.vm_type) is False:
                obj.attributes = {
                    'wait': self.cleaned_data['VNC_wait'],
                    'vnc_port': self.cleaned_data['VNC_port'],
                    'vnc_resolution': self.cleaned_data['VNC_resolution'],
                    'vnc_bind': self.cleaned_data['VNC_bind'],
                    'vnc_password': self.cleaned_data['VNC_password'],
                    'vnc_web': self.cleaned_data['VNC_web'],
                }
            else:
                self._errors['dtype'] = self.error_class(
                    [_('VNC only works with UEFI VMs')])
                self.cleaned_data.pop('VNC_port', None)
                self.cleaned_data.pop('VNC_wait', None)
                self.cleaned_data.pop('VNC_resolution', None)
                self.cleaned_data.pop('VNC_bind', None)
                self.cleaned_data.pop('VNC_password', None)
                self.cleaned_data.pop('VNC_web', None)
                return obj

        obj.save()
        return obj
Exemple #20
0
class VMForm(ModelForm):

    root_password = forms.CharField(
        label=_("Root Password"),
        widget=forms.PasswordInput(render_value=True),
        required=False,
    )
    path = PathField(
        label=_("Docker Disk File"),
        dirsonly=False,
        filesonly=False,
    )
    size = forms.IntegerField(
        label=_("Size of Docker Disk File (GiB)"),
        initial=2,
        required=False,
    )

    class Meta:
        fields = '__all__'
        model = models.VM

    def __init__(self, *args, **kwargs):
        super(VMForm, self).__init__(*args, **kwargs)
        if self.instance.id:
            for i in ('vm_type', 'root_password', 'path', 'size'):
                del self.fields[i]
            if self.instance.vm_type != 'Bhyve':
                del self.fields['bootloader']
        else:
            self.fields['vm_type'].widget.attrs['onChange'] = (
                "vmTypeToggle();")
            key_order(self, 0, 'vm_type', instance=True)

    def clean_name(self):
        name = self.cleaned_data.get('name')
        if name:
            name = name.replace(' ', '')
        return name

    def clean_root_password(self):
        vm_type = self.cleaned_data.get('vm_type')
        root_password = self.cleaned_data.get('root_password')
        if vm_type != 'Bhyve' and not root_password:
            raise forms.ValidationError(_('This field is required.'))
        return root_password

    def clean_path(self):
        vm_type = self.cleaned_data.get('vm_type')
        path = self.cleaned_data.get('path')
        if vm_type != 'Bhyve':
            if path and os.path.exists(path):
                raise forms.ValidationError(_('File must not exist.'))
            elif not path:
                raise forms.ValidationError(_('File path is required.'))
        return path

    def clean_size(self):
        vm_type = self.cleaned_data.get('vm_type')
        size = self.cleaned_data.get('size')
        if vm_type != 'Bhyve' and not size:
            raise forms.ValidationError(_('This field is required.'))
        return size

    def save(self, **kwargs):
        with client as c:
            cdata = self.cleaned_data

            # Container boot load is GRUB
            if self.instance.vm_type == 'Container Provider':
                cdata['bootloader'] = 'GRUB'

            if self.instance.id:
                c.call('vm.update', self.instance.id, cdata)
            else:
                if cdata['vm_type'] == 'Container Provider':
                    cdata['devices'] = [
                        {
                            'dtype': 'NIC',
                            'attributes': {
                                'type': 'E1000'
                            }
                        },
                        {
                            'dtype': 'RAW',
                            'attributes': {
                                'path': cdata.pop('path'),
                                'type': 'AHCI',
                                'sectorsize': 0,
                                'size': cdata.pop('size'),
                                'exists': False,
                            }
                        },
                    ]
                    cdata.pop('vm_type')
                    cdata.pop('bootloader')
                    cdata['type'] = 'RancherOS'
                    return c.call('vm.create_container', cdata)

                cdata.pop('root_password')
                cdata.pop('path')
                cdata.pop('size')

                if cdata['bootloader'] == 'UEFI' and cdata[
                        'vm_type'] == 'Bhyve':
                    cdata['devices'] = [
                        {
                            'dtype': 'NIC',
                            'attributes': {
                                'type': 'E1000'
                            }
                        },
                        {
                            'dtype': 'VNC',
                            'attributes': {
                                'wait': False,
                                'vnc_web': False
                            }
                        },
                    ]
                else:
                    cdata['devices'] = [
                        {
                            'dtype': 'NIC',
                            'attributes': {
                                'type': 'E1000'
                            }
                        },
                    ]
                self.instance = models.VM.objects.get(
                    pk=c.call('vm.create', cdata))
        return self.instance

    def delete(self, **kwargs):
        with client as c:
            c.call('vm.delete', self.instance.id)
Exemple #21
0
class DeviceForm(ModelForm):

    CDROM_path = PathField(
        label=_('CD-ROM (ISO)'),
        required=False,
        dirsonly=False,
    )
    DISK_zvol = forms.ChoiceField(
        label=_('ZVol'),
        required=False,
    )
    DISK_mode = forms.ChoiceField(
        label=_('Mode'),
        choices=choices.VM_DISKMODETYPES,
        required=False,
        initial='AHCI',
    )
    DISK_raw = PathField(
        label=_('Raw File'),
        required=False,
        dirsonly=False,
    )
    NIC_type = forms.ChoiceField(
        label=_('Adapter Type'),
        choices=choices.VM_NICTYPES,
        required=False,
        initial='E1000',
    )
    NIC_attach = forms.ChoiceField(
        label=_('Nic to attach'),
        choices=choices.NICChoices(exclude_configured=False),
        required=False,
    )
    NIC_mac = forms.CharField(
        label=_('Mac Address'),
        required=False,
        help_text=
        _("You can specify the adapter MAC Address or let it be auto generated."
          ),
        validators=[
            RegexValidator("^([0-9a-fA-F]{2}([::]?|$)){6}$",
                           "Invalid MAC format.")
        ],
        initial='00:a0:98:FF:FF:FF',
    )
    VNC_resolution = forms.ChoiceField(
        label=_('Resolution'),
        choices=choices.VNC_RESOLUTION,
        required=False,
        initial='1024x768',
    )
    VNC_port = forms.CharField(
        label=_('VNC port'),
        required=False,
        help_text=_("You can specify the VNC port or 0 for auto."),
        validators=[RegexValidator("^[0-9]*$", "Only integer is accepted")],
        initial=0,
    )
    VNC_bind = forms.ChoiceField(label=_('Bind to'),
                                 choices=(),
                                 required=False,
                                 initial='0.0.0.0')
    VNC_wait = forms.BooleanField(
        label=_('Wait to boot'),
        required=False,
    )

    class Meta:
        fields = '__all__'
        model = models.Device

    def __init__(self, *args, **kwargs):
        super(DeviceForm, self).__init__(*args, **kwargs)
        self.fields['dtype'].widget.attrs['onChange'] = ("deviceTypeToggle();")
        self.fields['VNC_bind'].choices = self.ipv4_list()

        diskchoices = {}
        _n = notifier()
        used_zvol = []
        for volume in Volume.objects.filter():
            zvols = _n.list_zfs_vols(volume.vol_name, sort='name')
            for zvol, attrs in zvols.items():
                if "zvol/" + zvol not in used_zvol:
                    diskchoices["zvol/" + zvol] = "%s (%s)" % (
                        zvol, humanize_size(attrs['volsize']))
        self.fields['DISK_zvol'].choices = diskchoices.items()

        if self.instance.id:
            if self.instance.dtype == 'CDROM':
                self.fields[
                    'CDROM_path'].initial = self.instance.attributes.get(
                        'path', '')
            elif self.instance.dtype == 'DISK':
                self.fields[
                    'DISK_zvol'].initial = self.instance.attributes.get(
                        'path', '').replace('/dev/', '')
                self.fields[
                    'DISK_mode'].initial = self.instance.attributes.get('type')
            elif self.instance.dtype == "RAW":
                self.fields['DISK_raw'].initial = self.instance.attributes.get(
                    'path', '')
                self.fields[
                    'DISK_mode'].initial = self.instance.attributes.get('type')
            elif self.instance.dtype == 'NIC':
                self.fields['NIC_type'].initial = self.instance.attributes.get(
                    'type')
                self.fields['NIC_mac'].initial = self.instance.attributes.get(
                    'mac')
                self.fields[
                    'NIC_attach'].initial = self.instance.attributes.get(
                        'nic_attach')
            elif self.instance.dtype == 'VNC':
                vnc_port = self.instance.attributes.get('vnc_port')
                vnc_port = 0 if vnc_port is None else vnc_port

                self.fields['VNC_wait'].initial = self.instance.attributes.get(
                    'wait')
                self.fields['VNC_port'].initial = vnc_port
                self.fields[
                    'VNC_resolution'].initial = self.instance.attributes.get(
                        'vnc_resolution')
                self.fields['VNC_bind'].initial = self.instance.attributes.get(
                    'vnc_bind')

    def ipv4_list(self):
        choices = (('0.0.0.0', '0.0.0.0'), )
        with client as c:
            ipv4_addresses = c.call('interfaces.ipv4_in_use')
        for ipv4_addr in ipv4_addresses:
            choices = choices + ((ipv4_addr, ipv4_addr), )
        return choices

    def clean(self):
        vm = self.cleaned_data.get('vm')
        vnc_port = self.cleaned_data.get('VNC_port')
        new_vnc_port = 5900
        if vm and vnc_port == '0':
            new_vnc_port = new_vnc_port + int(vm.id)
            self.cleaned_data['VNC_port'] = str(new_vnc_port)

        return self.cleaned_data

    def save(self, *args, **kwargs):
        vm = self.cleaned_data.get('vm')
        kwargs['commit'] = False
        obj = super(DeviceForm, self).save(*args, **kwargs)
        if self.cleaned_data['dtype'] == 'DISK':
            obj.attributes = {
                'path': '/dev/' + self.cleaned_data['DISK_zvol'],
                'type': self.cleaned_data['DISK_mode'],
            }
        elif self.cleaned_data['dtype'] == 'RAW':
            obj.attributes = {
                'path': self.cleaned_data['DISK_raw'],
                'type': self.cleaned_data['DISK_mode'],
            }
        elif self.cleaned_data['dtype'] == 'CDROM':
            cdrom_path = self.cleaned_data['CDROM_path']
            if cdrom_path:
                obj.attributes = {
                    'path': cdrom_path,
                }
            else:
                self._errors['CDROM_path'] = self.error_class(
                    [_('Please choose an ISO file.')])
        elif self.cleaned_data['dtype'] == 'NIC':
            obj.attributes = {
                'type': self.cleaned_data['NIC_type'],
                'mac': self.cleaned_data['NIC_mac'],
                'nic_attach': self.cleaned_data['NIC_attach'],
            }
        elif self.cleaned_data['dtype'] == 'VNC':
            if vm.bootloader == 'UEFI':
                obj.attributes = {
                    'wait': self.cleaned_data['VNC_wait'],
                    'vnc_port': self.cleaned_data['VNC_port'],
                    'vnc_resolution': self.cleaned_data['VNC_resolution'],
                    'vnc_bind': self.cleaned_data['VNC_bind'],
                }
            else:
                self._errors['dtype'] = self.error_class(
                    [_('VNC is only allowed for UEFI')])
                self.cleaned_data.pop('VNC_port', None)
                self.cleaned_data.pop('VNC_wait', None)
                self.cleaned_data.pop('VNC_resolution', None)
                self.cleaned_data.pop('VNC_bind', None)
                return obj

        obj.save()
        return obj
Exemple #22
0
    def __init__(self, *args, **kwargs):
        super(InterfacesForm, self).__init__(*args, **kwargs)
        self.fields['int_interface'].choices = choices.NICChoices()
        self.fields['int_dhcp'].widget.attrs['onChange'] = (
            'javascript:toggleGeneric("id_int_dhcp", ["id_int_ipv4address", '
            '"id_int_v4netmaskbit"]);')
        self.fields['int_ipv6auto'].widget.attrs['onChange'] = (
            'javascript:toggleGeneric("id_int_ipv6auto", '
            '["id_int_ipv6address", "id_int_v6netmaskbit"]);')
        dhcp = False
        ipv6auto = False
        if self.data:
            if self.data.get("int_dhcp"):
                dhcp = True
            if self.data.get("int_ipv6auto"):
                ipv6auto = True
        elif self.instance.id:
            if self.instance.int_dhcp:
                dhcp = True
            if self.instance.int_ipv6auto:
                ipv6auto = True
        if dhcp:
            self.fields['int_ipv4address'].widget.attrs['disabled'] = (
                'disabled')
            self.fields['int_v4netmaskbit'].widget.attrs['disabled'] = (
                'disabled')
        if ipv6auto:
            self.fields['int_ipv6address'].widget.attrs['disabled'] = (
                'disabled')
            self.fields['int_v6netmaskbit'].widget.attrs['disabled'] = (
                'disabled')

        if self.instance.id:
            if self.instance.int_interface.startswith('carp'):
                self.fields['int_v4netmaskbit'].widget.attrs['readonly'] = True
                self.fields['int_v4netmaskbit'].widget.attrs['class'] = (
                    'dijitDisabled dijitSelectDisabled')
                self.fields['int_v4netmaskbit'].initial = '32'
                self.instance.int_v4netmaskbit = '32'
            self.fields['int_interface'] = \
                forms.CharField(
                    label=self.fields['int_interface'].label,
                    initial=self.instance.int_interface,
                    widget=forms.TextInput(
                        attrs={
                            'readonly': True,
                            'class': (
                                'dijitDisabled dijitTextBoxDisabled'
                                ' dijitValidationTextBoxDisabled'
                            ),
                        },
                    )
                )
        else:
            # In case there is a CARP instance but no Interfaces instance
            if hasattr(notifier, 'failover_status'):
                from freenasUI.failover.models import CARP
                int_interfaces = [
                    o.int_interface for o in models.Interfaces.objects.all()
                ]
                for o in CARP.objects.all():
                    if o.carp_name not in int_interfaces:
                        self.fields['int_interface'].choices += [
                            (o.carp_name, o.carp_name),
                        ]
Exemple #23
0
class SSLForm(ModelForm):
    ssl_passphrase2 = forms.CharField(
        max_length=120,
        label=_("Confirm Passphrase"),
        widget=forms.widgets.PasswordInput(),
        required=False,
    )

    class Meta:
        fields = '__all__'
        model = models.SSL
        widgets = {
            'ssl_passphrase': forms.widgets.PasswordInput(render_value=False),
        }

    def __init__(self, *args, **kwargs):
        super(SSLForm, self).__init__(*args, **kwargs)
        self.fields.keyOrder = [
            'ssl_org',
            'ssl_unit',
            'ssl_email',
            'ssl_city',
            'ssl_state',
            'ssl_country',
            'ssl_common',
            'ssl_passphrase',
            'ssl_passphrase2',
            'ssl_certfile',
        ]
        if self.instance.ssl_passphrase:
            self.fields['ssl_passphrase'].required = False

    def clean_ssl_passphrase2(self):
        passphrase1 = self.cleaned_data.get("ssl_passphrase")
        passphrase2 = self.cleaned_data.get("ssl_passphrase2")
        if passphrase1 != passphrase2:
            raise forms.ValidationError(
                _("The two passphrase fields didn't match.")
            )
        return passphrase2

    def get_x509_modulus(self, x509_file_path):
        if not x509_file_path:
            return None

        proc = subprocess.Popen([
            "/usr/bin/openssl",
            "x509",
            "-noout",
            "-modulus",
            "-in", x509_file_path,
        ], stdout=subprocess.PIPE, stderr=subprocess.PIPE)

        modulus, err = proc.communicate()
        if proc.returncode != 0:
            return None

        return modulus.strip()

    def get_key_modulus(self, key_file_path, type='rsa'):
        if not key_file_path:
            return None

        proc = subprocess.Popen([
            "/usr/bin/openssl",
            type,
            "-noout",
            "-modulus",
            "-in", key_file_path,
        ], stdout=subprocess.PIPE, stderr=subprocess.PIPE)

        modulus, err = proc.communicate()
        if proc.returncode != 0:
            return None

        return modulus.strip()

    def clean_ssl_certfile(self):
        certfile = self.cleaned_data.get("ssl_certfile")
        if not certfile:
            return None
        reg = re.search(
            r'(-----BEGIN ([DR]SA) PRIVATE KEY-----.*?'
            r'-----END \2 PRIVATE KEY-----)',
            certfile,
            re.M | re.S
        )
        if not reg:
            raise forms.ValidationError(
                _("RSA or DSA private key not found")
            )
        priv = reg.group()

        priv_file = tempfile.mktemp(dir='/tmp/')
        with open(priv_file, 'w') as f:
            f.write(priv)

        keytype = None
        reg = re.search(r'-----BEGIN ([DR]SA) PRIVATE KEY-----', priv)
        if reg:
            keytype = reg.group(1).lower()

        modulus1 = self.get_key_modulus(priv_file, keytype)
        os.unlink(priv_file)
        if not modulus1:
            raise forms.ValidationError(
                _("RSA or DSA private key is not valid"))

        reg = re.findall(
            r'(-----BEGIN CERTIFICATE-----.*?'
            r'-----END CERTIFICATE-----)',
            certfile,
            re.M | re.S
        )

        verified = False
        for cert in reg:
            x509_file = tempfile.mktemp(dir='/tmp')
            with open(x509_file, 'w') as f:
                f.write(cert)

            modulus2 = self.get_x509_modulus(x509_file)
            os.unlink(x509_file)
            if modulus1 == modulus2:
                verified = True
                break

        if not verified:
            raise forms.ValidationError(
                _("The modulus of certificate and key must match")
            )

        return certfile

    def clean(self):
        cdata = self.cleaned_data
        if not cdata.get("ssl_passphrase2"):
            cdata['ssl_passphrase'] = cdata['ssl_passphrase2']
        return cdata

    def save(self):
        super(SSLForm, self).save()
        notifier().start_ssl("nginx")
Exemple #24
0
class NT4Form(ModelForm):
    nt4_adminpw2 = forms.CharField(
        max_length=50,
        label=_("Confirm Administrator Password"),
        widget=forms.widgets.PasswordInput(),
        required=False,
    )

    advanced_fields = ['nt4_use_default_domain', 'nt4_idmap_backend']

    class Meta:
        model = models.NT4
        widgets = {
            'nt4_adminpw': forms.widgets.PasswordInput(render_value=False),
        }
        fields = [
            'nt4_dcname', 'nt4_netbiosname', 'nt4_workgroup', 'nt4_adminname',
            'nt4_adminpw', 'nt4_adminpw2', 'nt4_use_default_domain',
            'nt4_idmap_backend', 'nt4_enable'
        ]

    def __init__(self, *args, **kwargs):
        super(NT4Form, self).__init__(*args, **kwargs)
        if self.instance.nt4_adminpw:
            self.fields['nt4_adminpw'].required = False
        if self._api is True:
            del self.fields['nt4_adminpw2']

        self.instance._original_nt4_idmap_backend = \
            self.instance.nt4_idmap_backend

        self.fields["nt4_enable"].widget.attrs["onChange"] = (
            "nt4_mutex_toggle();")

    def clean_nt4_adminpw2(self):
        password1 = self.cleaned_data.get("nt4_adminpw")
        password2 = self.cleaned_data.get("nt4_adminpw2")
        if password1 != password2:
            raise forms.ValidationError(
                _("The two password fields didn't match."))
        return password2

    def clean_nt4_idmap_backend(self):
        nt4_idmap_backend = self.cleaned_data.get("nt4_idmap_backend")
        if not nt4_idmap_backend:
            nt4_idmap_backend = None
        return nt4_idmap_backend

    def clean_nt4_netbiosname(self):
        netbiosname = self.cleaned_data.get("nt4_netbiosname")
        try:
            validate_netbios_names(netbiosname)
        except Exception as e:
            raise forms.ValidationError(_("netbiosname: %s" % e))
        return netbiosname

    def clean_nt4_workgroup(self):
        workgroup = self.cleaned_data.get("nt4_workgroup")
        try:
            validate_netbios_name(workgroup)
        except Exception as e:
            raise forms.ValidationError(_("workgroup: %s" % e))
        return workgroup

    def clean(self):
        cdata = self.cleaned_data
        if not cdata.get("nt4_adminpw"):
            cdata['nt4_adminpw'] = self.instance.nt4_adminpw
        return cdata

    def save(self):
        enable = self.cleaned_data.get("nt4_enable")
        started = notifier().started("nt4")
        if enable:
            if started is True:
                started = notifier().restart("nt4")
            if started is False:
                started = notifier().start("nt4")
            if started is False:
                self.instance.ad_enable = False
                super(NT4Form, self).save()
                raise ServiceFailed("nt4", _("NT4 failed to reload."))
        else:
            if started is True:
                started = notifier().stop("nt4")

        obj = super(NT4Form, self).save()
        return obj
Exemple #25
0
class IPMIForm(Form):
    # Max password length via IPMI v2.0 is 20 chars. We only support IPMI
    # v2.0+ compliant boards thus far.
    ipmi_password1 = forms.CharField(label=_("Password"),
                                     max_length=20,
                                     widget=forms.PasswordInput,
                                     required=False)
    ipmi_password2 = forms.CharField(
        label=_("Password confirmation"),
        max_length=20,
        widget=forms.PasswordInput,
        help_text=_("Enter the same password as above, for verification."),
        required=False)
    dhcp = forms.BooleanField(
        label=_("DHCP"),
        required=False,
    )
    ipv4address = IP4AddressFormField(
        initial='',
        required=False,
        label=_("IPv4 Address"),
    )
    ipv4netmaskbit = forms.ChoiceField(
        choices=choices.v4NetmaskBitList,
        required=False,
        label=_("IPv4 Netmask"),
    )
    ipv4gw = IP4AddressFormField(
        initial='',
        required=False,
        label=_("IPv4 Default Gateway"),
    )
    vlanid = forms.IntegerField(
        label=_("VLAN ID"),
        required=False,
        widget=forms.widgets.TextInput(),
    )

    def __init__(self, *args, **kwargs):
        self.remote = kwargs.pop('remote', None)
        self.initial_fail = False
        with client as c:
            if self.remote:
                try:
                    data = c.call('failover.call_remote', 'ipmi.query',
                                  [[('channel', '=', 1)]])
                except Exception:
                    self.initial_fail = True
                    data = None
            else:
                data = c.call('ipmi.query', [('channel', '=', 1)])
            if data:
                data = data[0]
                num, cidr = struct.unpack('>I',
                                          socket.inet_aton(
                                              data['netmask']))[0], 0
                while num > 0:
                    num = num << 1 & 0xffffffff
                    cidr += 1
                kwargs['initial'] = {
                    'dhcp': data['dhcp'],
                    'ipv4address': data.get('ipaddress'),
                    'ipv4gw': data.get('gateway'),
                    'ipv4netmaskbit': str(cidr),
                    'vlanid': data.get('vlan'),
                }

        super(IPMIForm, self).__init__(*args, **kwargs)
        self.fields['dhcp'].widget.attrs['onChange'] = (
            'javascript:toggleGeneric('
            '"id_dhcp", ["id_ipv4address", "id_ipv4netmaskbit"]);')

        with client as c:
            channels = list(map(lambda i: (i, i), c.call('ipmi.channels')))

        self.fields['channel'] = forms.ChoiceField(
            choices=channels,
            label=_('Channel'),
        )
        key_order(self, 0, 'channel', instance=True)

    def clean_ipmi_password2(self):
        ipmi_password1 = self.cleaned_data.get("ipmi_password1", "")
        ipmi_password2 = self.cleaned_data["ipmi_password2"]
        if ipmi_password1 != ipmi_password2:
            raise forms.ValidationError(
                _("The two password fields didn't match."))
        return ipmi_password2

    def clean_ipv4netmaskbit(self):
        try:
            cidr = int(self.cleaned_data.get("ipv4netmaskbit"))
        except ValueError:
            return None
        bits = 0xffffffff ^ (1 << 32 - cidr) - 1
        return socket.inet_ntoa(pack('>I', bits))

    def clean_ipv4address(self):
        ipv4 = self.cleaned_data.get('ipv4address')
        if ipv4:
            ipv4 = str(ipv4)
        return ipv4

    def clean_ipv4gw(self):
        ipv4 = self.cleaned_data.get('ipv4gw')
        if ipv4:
            ipv4 = str(ipv4)
        return ipv4

    def save(self):
        data = {
            'dhcp': self.cleaned_data.get('dhcp'),
            'ipaddress': self.cleaned_data.get('ipv4address'),
            'netmask': self.cleaned_data.get('ipv4netmaskbit'),
            'gateway': self.cleaned_data.get('ipv4gw'),
            'password': self.cleaned_data.get('ipmi_password2'),
        }
        vlan = self.cleaned_data.get('vlanid')
        if vlan:
            data['vlan'] = vlan
        channel = self.cleaned_data.get('channel')
        with client as c:
            if self.remote:
                return c.call('failover.call_remote', 'ipmi.update',
                              [channel, data])
            else:
                return c.call('ipmi.update', channel, data)
Exemple #26
0
class CloudSyncForm(ModelForm):

    attributes = forms.CharField(
        widget=CloudSyncWidget(),
        label=_('Provider'),
    )

    class Meta:
        exclude = ('credential', )
        fields = '__all__'
        model = models.CloudSync
        widgets = {
            'minute':
            CronMultiple(attrs={
                'numChoices': 60,
                'label': _("minute")
            }),
            'hour':
            CronMultiple(attrs={
                'numChoices': 24,
                'label': _("hour")
            }),
            'daymonth':
            CronMultiple(attrs={
                'numChoices': 31,
                'start': 1,
                'label': _("day of month"),
            }),
            'dayweek':
            forms.CheckboxSelectMultiple(choices=choices.WEEKDAYS_CHOICES),
            'month':
            forms.CheckboxSelectMultiple(choices=choices.MONTHS_CHOICES),
        }

    def __init__(self, *args, **kwargs):
        super(CloudSyncForm, self).__init__(*args, **kwargs)
        key_order(self, 2, 'attributes', instance=True)
        mchoicefield(self, 'month', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
        mchoicefield(self, 'dayweek', [1, 2, 3, 4, 5, 6, 7])
        if self.instance.id:
            self.fields['attributes'].initial = {
                'credential': self.instance.credential.id,
            }
            self.fields['attributes'].initial.update(self.instance.attributes)

    def clean_attributes(self):
        attributes = self.cleaned_data.get('attributes')
        try:
            attributes = json.loads(attributes)
        except ValueError:
            raise forms.ValidationError(_('Invalid provider details.'))

        credential = attributes.get('credential')
        if not credential:
            raise forms.ValidationError(_('This field is required.'))
        qs = CloudCredentials.objects.filter(id=credential)
        if not qs.exists():
            raise forms.ValidationError(_('Invalid credential.'))

        if not attributes.get('bucket'):
            raise forms.ValidationError(_('Bucket is required.'))

        direction = self.cleaned_data.get('direction')
        folder = attributes.get('folder')
        if direction == 'PULL' and folder and folder != '/':
            if folder.startswith('/'):
                folder = folder[1:]
            with client as c:
                # TODO: make it provider agnostic
                if not c.call('backup.s3.ls', credential, attributes['bucket'],
                              folder):
                    raise forms.ValidationError(
                        _('Folder "%s" does not exist.') % folder)

        return attributes

    def clean_month(self):
        m = self.data.getlist('month')
        if len(m) == 12:
            return '*'
        m = ','.join(m)
        return m

    def clean_dayweek(self):
        w = self.data.getlist('dayweek')
        if w == '*':
            return w
        if len(w) == 7:
            return '*'
        w = ','.join(w)
        return w

    def save(self, **kwargs):
        with client as c:
            cdata = self.cleaned_data
            cdata['credential'] = cdata['attributes'].pop('credential')
            if self.instance.id:
                c.call('backup.update', self.instance.id, cdata)
                pk = self.instance.id
            else:
                pk = c.call('backup.create', cdata)
        return models.CloudSync.objects.get(pk=pk)

    def delete(self, **kwargs):
        with client as c:
            c.call('backup.delete', self.instance.id)
Exemple #27
0
class ActiveDirectoryForm(ModelForm):

    ad_netbiosname_a = forms.CharField(
        max_length=120,
        label=_("NetBIOS name"),
    )
    ad_netbiosname_b = forms.CharField(
        max_length=120,
        label=_("NetBIOS name"),
        required=False,
    )
    ad_netbiosalias = forms.CharField(
        max_length=120,
        label=_("NetBIOS alias"),
        required=False,
    )

    advanced_fields = [
        'ad_netbiosname_a', 'ad_netbiosname_b', 'ad_netbiosalias', 'ad_ssl',
        'ad_certificate', 'ad_verbose_logging', 'ad_unix_extensions',
        'ad_allow_trusted_doms', 'ad_use_default_domain',
        'ad_allow_dns_updates', 'ad_disable_freenas_cache', 'ad_userdn',
        'ad_groupdn', 'ad_site', 'ad_dcname', 'ad_gcname', 'ad_kerberos_realm',
        'ad_kerberos_principal', 'ad_nss_info', 'ad_timeout', 'ad_dns_timeout',
        'ad_idmap_backend', 'ad_ldap_sasl_wrapping'
    ]

    class Meta:
        fields = '__all__'
        exclude = ['ad_idmap_backend_type']

        model = models.ActiveDirectory
        widgets = {
            'ad_bindpw': forms.widgets.PasswordInput(render_value=False),
        }

    def __original_save(self):
        for name in ('ad_domainname', 'ad_allow_trusted_doms',
                     'ad_use_default_domain', 'ad_unix_extensions',
                     'ad_verbose_logging', 'ad_bindname', 'ad_bindpw'):
            setattr(self.instance, "_original_%s" % name,
                    getattr(self.instance, name))
        for name in (
                'cifs_srv_netbiosname',
                'cifs_srv_netbiosname_b',
                'cifs_srv_netbiosalias',
        ):
            setattr(
                self.cifs,
                "_original_%s" % name,
                getattr(self.cifs, name),
            )

    def __original_changed(self):
        if (self.instance._original_ad_domainname !=
                self.instance.ad_domainname
                or self.cifs._original_cifs_srv_netbiosname !=
                self.cifs.cifs_srv_netbiosname
                or self.cifs._original_cifs_srv_netbiosname_b !=
                self.cifs.cifs_srv_netbiosname_b
                or self.cifs._original_cifs_srv_netbiosalias !=
                self.cifs.cifs_srv_netbiosalias
                or self.instance._original_ad_allow_trusted_doms !=
                self.instance.ad_allow_trusted_doms
                or self.instance._original_ad_use_default_domain !=
                self.instance.ad_use_default_domain
                or self.instance._original_ad_unix_extensions !=
                self.instance.ad_unix_extensions
                or self.instance._original_ad_verbose_logging !=
                self.instance.ad_verbose_logging
                or self.instance._original_ad_bindname !=
                self.instance.ad_bindname or
                self.instance._original_ad_bindpw != self.instance.ad_bindpw):
            return True
        return False

    def __init__(self, *args, **kwargs):
        super(ActiveDirectoryForm, self).__init__(*args, **kwargs)
        if self.instance.ad_bindpw:
            self.fields['ad_bindpw'].required = False
        self.cifs = CIFS.objects.latest('id')
        self.__original_save()

        self.fields["ad_idmap_backend"].widget.attrs["onChange"] = (
            "activedirectory_idmap_check();")

        self.fields["ad_enable"].widget.attrs["onChange"] = (
            "activedirectory_mutex_toggle();")
        if self.cifs:
            self.fields[
                'ad_netbiosname_a'].initial = self.cifs.cifs_srv_netbiosname
            self.fields[
                'ad_netbiosname_b'].initial = self.cifs.cifs_srv_netbiosname_b
            self.fields[
                'ad_netbiosalias'].initial = self.cifs.cifs_srv_netbiosalias
        _n = notifier()
        if not _n.is_freenas():
            if _n.failover_licensed():
                from freenasUI.failover.utils import node_label_field
                node_label_field(
                    _n.failover_node(),
                    self.fields['ad_netbiosname_a'],
                    self.fields['ad_netbiosname_b'],
                )
            else:
                del self.fields['ad_netbiosname_b']
        else:
            del self.fields['ad_netbiosname_b']

    def get_dcport(self):
        ad_dcname = self.cleaned_data.get('ad_dcname')
        ad_dcport = 389

        ad_ssl = self.cleaned_data.get('ad_ssl')
        if ad_ssl == 'on':
            ad_dcport = 636

        if not ad_dcname:
            return ad_dcport

        parts = ad_dcname.split(':')
        if len(parts) > 1 and parts[1].isdigit():
            ad_dcport = int(parts[1])

        return ad_dcport

    def clean_ad_dcname(self):
        ad_dcname = self.cleaned_data.get('ad_dcname')
        ad_dcport = self.get_dcport()

        if not ad_dcname:
            return None

        parts = ad_dcname.split(':')
        ad_dcname = parts[0]

        errors = []
        try:
            ret = FreeNAS_ActiveDirectory.port_is_listening(host=ad_dcname,
                                                            port=ad_dcport,
                                                            errors=errors)

            if ret is False:
                raise Exception('Invalid Host/Port: %s' % errors[0])

        except Exception as e:
            raise forms.ValidationError('%s.' % e)

        return self.cleaned_data.get('ad_dcname')

    def get_gcport(self):
        ad_gcname = self.cleaned_data.get('ad_gcname')
        ad_gcport = 3268

        ad_ssl = self.cleaned_data.get('ad_ssl')
        if ad_ssl == 'on':
            ad_gcport = 3269

        if not ad_gcname:
            return ad_gcport

        parts = ad_gcname.split(':')
        if len(parts) > 1 and parts[1].isdigit():
            ad_gcport = int(parts[1])

        return ad_gcport

    def clean_ad_gcname(self):
        ad_gcname = self.cleaned_data.get('ad_gcname')
        ad_gcport = self.get_gcport()

        if not ad_gcname:
            return None

        parts = ad_gcname.split(':')
        ad_gcname = parts[0]

        errors = []
        try:
            ret = FreeNAS_ActiveDirectory.port_is_listening(host=ad_gcname,
                                                            port=ad_gcport,
                                                            errors=errors)

            if ret is False:
                raise Exception('Invalid Host/Port: %s' % errors[0])

        except Exception as e:
            raise forms.ValidationError('%s.' % e)

        return self.cleaned_data.get('ad_gcname')

    def clean_ad_netbiosname_a(self):
        netbiosname = self.cleaned_data.get("ad_netbiosname_a")
        try:
            validate_netbios_name(netbiosname)
        except Exception as e:
            raise forms.ValidationError(e)
        return netbiosname

    def clean_ad_netbiosname_b(self):
        netbiosname_a = self.cleaned_data.get("ad_netbiosname_a")
        netbiosname = self.cleaned_data.get("ad_netbiosname_b")
        if not netbiosname:
            return netbiosname
        if netbiosname_a and netbiosname_a == netbiosname:
            raise forms.ValidationError(
                _('NetBIOS cannot be the same as the first.'))
        try:
            validate_netbios_name(netbiosname)
        except Exception as e:
            raise forms.ValidationError(e)
        return netbiosname

    def clean_ad_netbiosalias(self):
        netbiosalias = self.cleaned_data.get("ad_netbiosalias")
        if netbiosalias:
            try:
                validate_netbios_name(netbiosalias)
            except Exception as e:
                raise forms.ValidationError(e)
        return netbiosalias

    def clean(self):
        cdata = self.cleaned_data
        domain = cdata.get("ad_domainname")
        bindname = cdata.get("ad_bindname")
        binddn = "%s@%s" % (bindname, domain)
        bindpw = cdata.get("ad_bindpw")
        site = cdata.get("ad_site")
        netbiosname = cdata.get("ad_netbiosname_a")
        netbiosname_b = cdata.get("ad_netbiosname_b")
        ssl = cdata.get("ad_ssl")
        certificate = cdata["ad_certificate"]
        ad_kerberos_principal = cdata["ad_kerberos_principal"]
        workgroup = None

        if certificate:
            certificate = certificate.get_certificate_path()

        args = {
            'domain': domain,
            'site': site,
            'ssl': ssl,
            'certfile': certificate
        }

        if not cdata.get("ad_bindpw"):
            bindpw = self.instance.ad_bindpw
            cdata['ad_bindpw'] = bindpw

        if cdata.get("ad_enable") is False:
            return cdata

        if not ad_kerberos_principal:
            if not bindname:
                raise forms.ValidationError("No domain account name specified")
            if not bindpw:
                raise forms.ValidationError(
                    "No domain account password specified")

            try:
                FreeNAS_ActiveDirectory.validate_credentials(
                    domain,
                    site=site,
                    ssl=ssl,
                    certfile=certificate,
                    binddn=binddn,
                    bindpw=bindpw)

            except LDAPError as e:
                log.debug("LDAPError: type = %s", type(e))

                error = []
                try:
                    error.append(e.args[0]['info'])
                    error.append(e.args[0]['desc'])
                    error = ', '.join(error)

                except:
                    error = str(e)

                raise forms.ValidationError("{0}".format(error))

            except Exception as e:
                log.debug("Exception: type = %s", type(e))
                raise forms.ValidationError('{0}.'.format(str(e)))

            args['binddn'] = binddn
            args['bindpw'] = bindpw

        else:
            args['keytab_principal'] = ad_kerberos_principal.principal_name
            args['keytab_file'] = '/etc/krb5.keytab'

        try:
            workgroup = FreeNAS_ActiveDirectory.get_workgroup_name(**args)
        except Exception as e:
            raise forms.ValidationError(e)

        if workgroup:
            if compare_netbios_names(netbiosname, workgroup, None):
                raise forms.ValidationError(
                    _("The NetBIOS name cannot be the same as the workgroup name!"
                      ))
            if netbiosname_b:
                if compare_netbios_names(netbiosname_b, workgroup, None):
                    raise forms.ValidationError(
                        _("The NetBIOS name cannot be the same as the workgroup "
                          "name!"))

        else:
            log.warn("Unable to determine workgroup name")

        if ssl in ("off", None):
            return cdata

        if not certificate:
            raise forms.ValidationError(
                "SSL/TLS specified without certificate")

        return cdata

    def save(self):
        enable = self.cleaned_data.get("ad_enable")
        enable_monitoring = self.cleaned_data.get("ad_enable_monitor")
        monit_frequency = self.cleaned_data.get("ad_monitor_frequency")
        monit_retry = self.cleaned_data.get("ad_recover_retry")
        fqdn = self.cleaned_data.get("ad_domainname")
        sm = None

        if self.__original_changed():
            notifier().clear_activedirectory_config()

        started = notifier().started(
            "activedirectory",
            timeout=_fs().directoryservice.activedirectory.timeout.started)
        obj = super(ActiveDirectoryForm, self).save()

        try:
            utils.get_idmap_object(obj.ds_type, obj.id, obj.ad_idmap_backend)
        except ObjectDoesNotExist:
            log.debug(
                'IDMAP backend {} entry does not exist, creating one.'.format(
                    obj.ad_idmap_backend))
            utils.get_idmap(obj.ds_type, obj.id, obj.ad_idmap_backend)

        self.cifs.cifs_srv_netbiosname = self.cleaned_data.get(
            "ad_netbiosname_a")
        self.cifs.cifs_srv_netbiosname_b = self.cleaned_data.get(
            "ad_netbiosname_b")
        self.cifs.cifs_srv_netbiosalias = self.cleaned_data.get(
            "ad_netbiosalias")
        self.cifs.save()

        if enable:
            if started is True:
                timeout = _fs(
                ).directoryservice.activedirectory.timeout.restart
                try:
                    started = notifier().restart("activedirectory",
                                                 timeout=timeout)
                except Exception as e:
                    raise MiddlewareError(
                        _("Active Directory restart timed out after %d seconds."
                          % timeout), )

            if started is False:
                timeout = _fs().directoryservice.activedirectory.timeout.start
                try:
                    started = notifier().start("activedirectory",
                                               timeout=timeout)
                except Exception as e:
                    raise MiddlewareError(
                        _("Active Directory start timed out after %d seconds."
                          % timeout), )
            if started is False:
                self.instance.ad_enable = False
                super(ActiveDirectoryForm, self).save()
                raise MiddlewareError(
                    _("Active Directory failed to reload."), )
        else:
            if started is True:
                timeout = _fs().directoryservice.activedirectory.timeout.stop
                try:
                    started = notifier().stop("activedirectory",
                                              timeout=timeout)
                except Exception as e:
                    raise MiddlewareError(
                        _("Active Directory stop timed out after %d seconds." %
                          timeout), )

        sm_name = 'activedirectory'
        try:
            sm = ServiceMonitor.objects.get(sm_name=sm_name)
        except Exception as e:
            log.debug("XXX: Unable to find ServiceMonitor: %s", e)
            pass

        #
        # Ports can be specified in the UI but there doesn't appear to be a way to
        # override them via SRV records. This should be fixed.
        #
        dcport = self.get_dcport()
        # gcport = self.get_gcport()

        if not sm:
            try:
                log.debug(
                    "XXX: fqdn=%s dcport=%s frequency=%s retry=%s enable=%s",
                    fqdn, dcport, monit_frequency, monit_retry,
                    enable_monitoring)

                sm = ServiceMonitor.objects.create(
                    sm_name=sm_name,
                    sm_host=fqdn,
                    sm_port=dcport,
                    sm_frequency=monit_frequency,
                    sm_retry=monit_retry,
                    sm_enable=enable_monitoring)
            except Exception as e:
                log.debug("XXX: Unable to create ServiceMonitor: %s", e)
                raise MiddlewareError(
                    _("Unable to create ServiceMonitor: %s" % e), )

        else:
            sm.sm_name = sm_name
            if fqdn != sm.sm_host:
                sm.sm_host = fqdn
            if dcport != sm.sm_port:
                sm.sm_port = dcport
            if monit_frequency != sm.sm_frequency:
                sm.sm_frequency = monit_frequency
            if monit_retry != sm.sm_retry:
                sm.sm_retry = monit_retry
            if enable_monitoring != sm.sm_enable:
                sm.sm_enable = enable_monitoring

            try:
                sm.save(force_update=True)
            except Exception as e:
                log.debug("XXX: Unable to create ServiceMonitor: %s", e)
                raise MiddlewareError(
                    _("Unable to save ServiceMonitor: %s" % e), )

        with client as c:
            if enable_monitoring and enable:
                log.debug(
                    "[ServiceMonitoring] Add %s service, frequency: %d, retry: %d"
                    % ('activedirectory', monit_frequency, monit_retry))
                c.call('servicemonitor.restart')
            else:
                log.debug(
                    "[ServiceMonitoring] Remove %s service, frequency: %d, retry: %d"
                    % ('activedirectory', monit_frequency, monit_retry))
                c.call('servicemonitor.restart')

        return obj
Exemple #28
0
class AFP_ShareForm(ModelForm):

    afp_sharepw2 = forms.CharField(
        max_length=50,
        label=_("Confirm Share Password"),
        widget=forms.widgets.PasswordInput(render_value=False),
        required=False,
    )

    class Meta:
        model = models.AFP_Share
        widgets = {
            'afp_sharepw': forms.widgets.PasswordInput(render_value=False),
        }

    def __init__(self, *args, **kwargs):
        super(AFP_ShareForm, self).__init__(*args, **kwargs)
        self.fields['afp_upriv'].widget.attrs['onChange'] = (
            'javascript:toggleGeneric("id_afp_upriv", ["id_afp_fperm", '
            '"id_afp_dperm"], true);')
        self.fields['afp_fperm'] = UnixPermissionField(
            label=self.fields['afp_fperm'].label,
            initial=self.fields['afp_fperm'].initial,
            required=False,
        )
        self.fields['afp_dperm'] = UnixPermissionField(
            label=self.fields['afp_dperm'].label,
            initial=self.fields['afp_dperm'].initial,
            required=False,
        )
        if self.instance.id:
            self.fields['afp_sharepw2'].initial = self.instance.afp_sharepw
            if self.instance.afp_sharepw:
                self.fields['afp_deletepw'] = forms.BooleanField(
                    label=_("Delete password"),
                    initial=False,
                    required=False,
                )
                self.fields.keyOrder.remove('afp_deletepw')
                self.fields.keyOrder.insert(5, 'afp_deletepw')
            if not self.instance.afp_upriv:
                self.fields['afp_fperm'].widget.attrs['disabled'] = 'true'
                self.fields['afp_dperm'].widget.attrs['disabled'] = 'true'
            else:
                self.fields['afp_fperm'].widget.attrs['disabled'] = 'false'
                self.fields['afp_dperm'].widget.attrs['disabled'] = 'false'

    def clean_afp_sharepw2(self):
        password1 = self.cleaned_data.get("afp_sharepw")
        password2 = self.cleaned_data.get("afp_sharepw2")
        if password1 != password2:
            raise forms.ValidationError(
                _("The two password fields didn't match."))
        return password2

    def clean(self):
        cdata = self.cleaned_data
        if not cdata.get("afp_sharepw") and not cdata.get("afp_deletepw"):
            cdata['afp_sharepw'] = self.instance.afp_sharepw
        return cdata

    def save(self):
        ret = super(AFP_ShareForm, self).save()
        notifier().reload("afp")
        return ret

    def done(self, request, events):
        if not services.objects.get(srv_service='afp').srv_enable:
            events.append('ask_service("afp")')
Exemple #29
0
class DeviceForm(ModelForm):

    CDROM_path = PathField(
        label=_('CD-ROM (ISO)'),
        required=False,
        dirsonly=False,
    )
    DISK_zvol = forms.ChoiceField(
        label=_('ZVol'),
        required=False,
    )
    DISK_mode = forms.ChoiceField(
        label=_('Mode'),
        choices=(
            ('AHCI', _('AHCI')),
            ('VIRTIO', _('VirtIO')),
        ),
        required=False,
        initial='AHCI',
    )
    NIC_type = forms.ChoiceField(
        label=_('Adapter Type'),
        choices=(
            ('E1000', _('Intel e82545 (e1000)')),
            ('VIRTIO', _('VirtIO')),
        ),
        required=False,
        initial='E1000',
    )
    VNC_port = forms.CharField(
        label=_('VNC port'),
        required=False,
        initial=0,
        help_text=_("You can specify the VNC port or 0 for auto."),
        validators=[RegexValidator("^[0-9]*$", "Only integer is accepted")],
    )
    VNC_wait = forms.BooleanField(
        label=_('Wait to boot'),
        required=False,
    )

    class Meta:
        fields = '__all__'
        model = models.Device

    def __init__(self, *args, **kwargs):
        super(DeviceForm, self).__init__(*args, **kwargs)
        self.fields['dtype'].widget.attrs['onChange'] = ("deviceTypeToggle();")

        diskchoices = {}
        _n = notifier()
        used_zvol = []
        for volume in Volume.objects.filter():
            zvols = _n.list_zfs_vols(volume.vol_name, sort='name')
            for zvol, attrs in zvols.items():
                if "zvol/" + zvol not in used_zvol:
                    diskchoices["zvol/" + zvol] = "%s (%s)" % (
                        zvol, humanize_size(attrs['volsize']))
        self.fields['DISK_zvol'].choices = diskchoices.items()

        if self.instance.id:
            if self.instance.dtype == 'CDROM':
                self.fields[
                    'CDROM_path'].initial = self.instance.attributes.get(
                        'path', '')
            elif self.instance.dtype == 'DISK':
                self.fields[
                    'DISK_zvol'].initial = self.instance.attributes.get(
                        'path', '').replace('/dev/', '')
                self.fields[
                    'DISK_mode'].initial = self.instance.attributes.get('type')
            elif self.instance.dtype == 'NIC':
                self.fields['NIC_type'].initial = self.instance.attributes.get(
                    'type')
            elif self.instance.dtype == 'VNC':
                self.fields['VNC_wait'].initial = self.instance.attributes.get(
                    'wait')
                self.fields['VNC_port'].initial = self.instance.attributes.get(
                    'vnc_port')

    def clean(self):
        vm = self.cleaned_data.get('vm')
        vnc_port = self.cleaned_data.get('VNC_port')
        new_vnc_port = 5900
        if vm and vnc_port == '0':
            new_vnc_port = new_vnc_port + int(vm.id)
            self.cleaned_data['VNC_port'] = str(new_vnc_port)

        return self.cleaned_data

    def save(self, *args, **kwargs):
        vm = self.cleaned_data.get('vm')
        kwargs['commit'] = False
        obj = super(DeviceForm, self).save(*args, **kwargs)
        if self.cleaned_data['dtype'] == 'DISK':
            obj.attributes = {
                'path': '/dev/' + self.cleaned_data['DISK_zvol'],
                'type': self.cleaned_data['DISK_mode'],
            }
        elif self.cleaned_data['dtype'] == 'CDROM':
            obj.attributes = {
                'path': self.cleaned_data['CDROM_path'],
            }
        elif self.cleaned_data['dtype'] == 'NIC':
            obj.attributes = {
                'type': self.cleaned_data['NIC_type'],
            }
        elif self.cleaned_data['dtype'] == 'VNC':
            if vm.bootloader == 'UEFI':
                obj.attributes = {
                    'wait': self.cleaned_data['VNC_wait'],
                    'vnc_port': self.cleaned_data['VNC_port'],
                }
            else:
                self._errors['dtype'] = self.error_class(
                    [_('VNC is only allowed for UEFI')])
                self.cleaned_data.pop('VNC_port', None)
                self.cleaned_data.pop('VNC_wait', None)
                return obj

        obj.save()
        return obj
Exemple #30
0
class ActiveDirectoryForm(ModelForm):

    ad_netbiosname_a = forms.CharField(
        max_length=120,
        label=_("NetBIOS name"),
    )
    ad_netbiosname_b = forms.CharField(
        max_length=120,
        label=_("NetBIOS name"),
        required=False,
    )
    ad_netbiosalias = forms.CharField(
        max_length=120,
        label=_("NetBIOS alias"),
        required=False,
    )

    advanced_fields = [
        'ad_netbiosname_a', 'ad_netbiosname_b', 'ad_netbiosalias', 'ad_ssl',
        'ad_certificate', 'ad_verbose_logging', 'ad_unix_extensions',
        'ad_allow_trusted_doms', 'ad_use_default_domain',
        'ad_allow_dns_updates', 'ad_disable_freenas_cache', 'ad_userdn',
        'ad_groupdn', 'ad_site', 'ad_dcname', 'ad_gcname', 'ad_kerberos_realm',
        'ad_kerberos_principal', 'ad_nss_info', 'ad_timeout', 'ad_dns_timeout',
        'ad_idmap_backend', 'ad_ldap_sasl_wrapping'
    ]

    class Meta:
        fields = '__all__'
        exclude = ['ad_idmap_backend_type']

        model = models.ActiveDirectory
        widgets = {
            'ad_bindpw': forms.widgets.PasswordInput(render_value=False),
        }

    def __original_save(self):
        for name in ('ad_domainname', 'ad_allow_trusted_doms',
                     'ad_use_default_domain', 'ad_unix_extensions',
                     'ad_verbose_logging', 'ad_bindname', 'ad_bindpw'):
            setattr(self.instance, "_original_%s" % name,
                    getattr(self.instance, name))
        for name in (
                'cifs_srv_netbiosname',
                'cifs_srv_netbiosname_b',
                'cifs_srv_netbiosalias',
        ):
            setattr(
                self.cifs,
                "_original_%s" % name,
                getattr(self.cifs, name),
            )

    def __original_changed(self):
        if (self.instance._original_ad_domainname !=
                self.instance.ad_domainname
                or self.cifs._original_cifs_srv_netbiosname !=
                self.cifs.cifs_srv_netbiosname
                or self.cifs._original_cifs_srv_netbiosname_b !=
                self.cifs.cifs_srv_netbiosname_b
                or self.cifs._original_cifs_srv_netbiosalias !=
                self.cifs.cifs_srv_netbiosalias
                or self.instance._original_ad_allow_trusted_doms !=
                self.instance.ad_allow_trusted_doms
                or self.instance._original_ad_use_default_domain !=
                self.instance.ad_use_default_domain
                or self.instance._original_ad_unix_extensions !=
                self.instance.ad_unix_extensions
                or self.instance._original_ad_verbose_logging !=
                self.instance.ad_verbose_logging
                or self.instance._original_ad_bindname !=
                self.instance.ad_bindname or
                self.instance._original_ad_bindpw != self.instance.ad_bindpw):
            return True
        return False

    def __init__(self, *args, **kwargs):
        super(ActiveDirectoryForm, self).__init__(*args, **kwargs)
        if self.instance.ad_bindpw:
            self.fields['ad_bindpw'].required = False
        self.cifs = CIFS.objects.latest('id')
        self.__original_save()

        self.fields["ad_idmap_backend"].widget.attrs["onChange"] = (
            "activedirectory_idmap_check();")

        self.fields["ad_enable"].widget.attrs["onChange"] = (
            "activedirectory_mutex_toggle();")
        if self.cifs:
            self.fields[
                'ad_netbiosname_a'].initial = self.cifs.cifs_srv_netbiosname
            self.fields[
                'ad_netbiosname_b'].initial = self.cifs.cifs_srv_netbiosname_b
            self.fields[
                'ad_netbiosalias'].initial = self.cifs.cifs_srv_netbiosalias
        _n = notifier()
        if not _n.is_freenas():
            if _n.failover_licensed():
                from freenasUI.failover.utils import node_label_field
                node_label_field(
                    _n.failover_node(),
                    self.fields['ad_netbiosname_a'],
                    self.fields['ad_netbiosname_b'],
                )
            else:
                del self.fields['ad_netbiosname_b']
        else:
            del self.fields['ad_netbiosname_b']

    def clean_ad_dcname(self):
        ad_dcname = self.cleaned_data.get('ad_dcname')
        ad_dcport = 389

        ad_ssl = self.cleaned_data.get('ad_ssl')
        if ad_ssl == 'on':
            ad_dcport = 636

        if not ad_dcname:
            return None

        parts = ad_dcname.split(':')
        ad_dcname = parts[0]
        if len(parts) > 1 and parts[1].isdigit():
            ad_dcport = long(parts[1])

        errors = []
        try:
            ret = FreeNAS_ActiveDirectory.port_is_listening(host=ad_dcname,
                                                            port=ad_dcport,
                                                            errors=errors)

            if ret is False:
                raise Exception('Invalid Host/Port: %s' % errors[0])

        except Exception as e:
            raise forms.ValidationError('%s.' % e)

        return self.cleaned_data.get('ad_dcname')

    def clean_ad_gcname(self):
        ad_gcname = self.cleaned_data.get('ad_gcname')
        ad_gcport = 3268

        ad_ssl = self.cleaned_data.get('ad_ssl')
        if ad_ssl == 'on':
            ad_gcport = 3269

        if not ad_gcname:
            return None

        parts = ad_gcname.split(':')
        ad_gcname = parts[0]
        if len(parts) > 1 and parts[1].isdigit():
            ad_gcport = long(parts[1])

        errors = []
        try:
            ret = FreeNAS_ActiveDirectory.port_is_listening(host=ad_gcname,
                                                            port=ad_gcport,
                                                            errors=errors)

            if ret is False:
                raise Exception('Invalid Host/Port: %s' % errors[0])

        except Exception as e:
            raise forms.ValidationError('%s.' % e)

        return self.cleaned_data.get('ad_gcname')

    def clean_ad_netbiosname_a(self):
        netbiosname = self.cleaned_data.get("ad_netbiosname_a")
        try:
            validate_netbios_name(netbiosname)
        except Exception as e:
            raise forms.ValidationError(e)
        return netbiosname

    def clean_ad_netbiosname_b(self):
        netbiosname_a = self.cleaned_data.get("ad_netbiosname_a")
        netbiosname = self.cleaned_data.get("ad_netbiosname_b")
        if not netbiosname:
            return netbiosname
        if netbiosname_a and netbiosname_a == netbiosname:
            raise forms.ValidationError(
                _('NetBIOS cannot be the same as the first.'))
        try:
            validate_netbios_name(netbiosname)
        except Exception as e:
            raise forms.ValidationError(e)
        return netbiosname

    def clean_ad_netbiosalias(self):
        netbiosalias = self.cleaned_data.get("ad_netbiosalias")
        if netbiosalias:
            try:
                validate_netbios_name(netbiosalias)
            except Exception as e:
                raise forms.ValidationError(e)
        return netbiosalias

    def clean(self):
        cdata = self.cleaned_data
        domain = cdata.get("ad_domainname")
        bindname = cdata.get("ad_bindname")
        binddn = "%s@%s" % (bindname, domain)
        bindpw = cdata.get("ad_bindpw")
        site = cdata.get("ad_site")
        netbiosname = cdata.get("ad_netbiosname_a")
        netbiosname_b = cdata.get("ad_netbiosname_b")
        ssl = cdata.get("ad_ssl")
        certificate = cdata["ad_certificate"]
        ad_kerberos_principal = cdata["ad_kerberos_principal"]
        workgroup = None

        if certificate:
            certificate = certificate.get_certificate_path()

        args = {
            'domain': domain,
            'site': site,
            'ssl': ssl,
            'certfile': certificate
        }

        if not cdata.get("ad_bindpw"):
            bindpw = self.instance.ad_bindpw
            cdata['ad_bindpw'] = bindpw

        if cdata.get("ad_enable") is False:
            return cdata

        if not ad_kerberos_principal:
            if not bindname:
                raise forms.ValidationError("No domain account name specified")
            if not bindpw:
                raise forms.ValidationError(
                    "No domain account password specified")

            try:
                FreeNAS_ActiveDirectory.validate_credentials(
                    domain,
                    site=site,
                    ssl=ssl,
                    certfile=certificate,
                    binddn=binddn,
                    bindpw=bindpw)
            except LDAPError as e:
                # LDAPError is dumb, it returns a list with one element for goodness knows what reason
                e = e[0]
                error = []
                desc = e.get('desc')
                info = e.get('info')
                if desc:
                    error.append(desc)
                if info:
                    error.append(info)

                if error:
                    error = ', '.join(error)
                else:
                    error = str(e)

                raise forms.ValidationError("{0}".format(error))
            except Exception as e:
                raise forms.ValidationError('{0}.'.format(str(e)))

            args['binddn'] = binddn
            args['bindpw'] = bindpw

        else:
            args['keytab_principal'] = ad_kerberos_principal.principal_name
            args['keytab_file'] = '/etc/krb5.keytab'

        try:
            workgroup = FreeNAS_ActiveDirectory.get_workgroup_name(**args)
        except Exception as e:
            raise forms.ValidationError(e)

        if workgroup:
            if compare_netbios_names(netbiosname, workgroup, None):
                raise forms.ValidationError(
                    _("The NetBIOS name cannot be the same as the workgroup name!"
                      ))
            if netbiosname_b:
                if compare_netbios_names(netbiosname_b, workgroup, None):
                    raise forms.ValidationError(
                        _("The NetBIOS name cannot be the same as the workgroup "
                          "name!"))

        else:
            log.warn("Unable to determine workgroup name")

        if ssl in ("off", None):
            return cdata

        if not certificate:
            raise forms.ValidationError(
                "SSL/TLS specified without certificate")

        return cdata

    def save(self):
        enable = self.cleaned_data.get("ad_enable")
        if self.__original_changed():
            notifier()._clear_activedirectory_config()

        started = notifier().started("activedirectory")
        obj = super(ActiveDirectoryForm, self).save()
        self.cifs.cifs_srv_netbiosname = self.cleaned_data.get(
            "ad_netbiosname_a")
        self.cifs.cifs_srv_netbiosname_b = self.cleaned_data.get(
            "ad_netbiosname_b")
        self.cifs.cifs_srv_netbiosalias = self.cleaned_data.get(
            "ad_netbiosalias")
        self.cifs.save()

        if enable:
            if started is True:
                started = notifier().restart("activedirectory")
            if started is False:
                started = notifier().start("activedirectory")
            if started is False:
                self.instance.ad_enable = False
                super(ActiveDirectoryForm, self).save()
                raise ServiceFailed(
                    "activedirectory",
                    _("Active Directory failed to reload."),
                )
        else:
            if started is True:
                started = notifier().stop("activedirectory")
        return obj