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)
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'), }, ))
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)
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
class FirmwareUploadForm(Form): firmware = FileField(label=_("New image to be installed"), required=True) sha256 = forms.CharField( label=_("SHA256 sum for the image"), required=True )
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()
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
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
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
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
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
class LicenseUpdateForm(Form): license = forms.CharField( label=_('License'), widget=forms.widgets.Textarea, )
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
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()
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)
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
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)
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)
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
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)
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
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), ]
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")
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
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)
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)
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
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")')
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
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