checking in some config stuff
This commit is contained in:
parent
4b912a8dae
commit
d3a5f039c1
1
config/TODO
Normal file
1
config/TODO
Normal file
@ -0,0 +1 @@
|
|||||||
|
add default config as struct
|
@ -38,17 +38,20 @@ const (
|
|||||||
var (
|
var (
|
||||||
// sshdModify are values we modify.
|
// sshdModify are values we modify.
|
||||||
sshdModify = [...]string{
|
sshdModify = [...]string{
|
||||||
|
"AuthenticationMethods",
|
||||||
|
"ChallengeResponseAuthentication",
|
||||||
|
"Ciphers",
|
||||||
"HostKey",
|
"HostKey",
|
||||||
"PermitRootLogin",
|
"HostKeyAlgorithms",
|
||||||
"StrictModes",
|
"KexAlgorithms",
|
||||||
"PubkeyAuthentication",
|
"MACs",
|
||||||
"PasswordAuthentication",
|
"PasswordAuthentication",
|
||||||
"PermitEmptyPasswords",
|
"PermitEmptyPasswords",
|
||||||
"ChallengeResponseAuthentication",
|
"PermitRootLogin",
|
||||||
"KexAlgorithms",
|
"PrintLastLog",
|
||||||
"Protocol",
|
"Protocol",
|
||||||
"Ciphers",
|
"PubkeyAuthentication",
|
||||||
"MACs",
|
"StrictModes",
|
||||||
}
|
}
|
||||||
|
|
||||||
// sshModify are values we modify.
|
// sshModify are values we modify.
|
||||||
@ -62,6 +65,10 @@ var (
|
|||||||
"",
|
"",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sshMulti = [...]string{
|
||||||
|
"IdentityFile",
|
||||||
|
}
|
||||||
|
|
||||||
// authMethods are authentication methods that openssh supports.
|
// authMethods are authentication methods that openssh supports.
|
||||||
authMethods = []string{
|
authMethods = []string{
|
||||||
"any",
|
"any",
|
||||||
@ -92,11 +99,13 @@ var (
|
|||||||
// forwardAllows are shared values used by forwarding access control.
|
// forwardAllows are shared values used by forwarding access control.
|
||||||
forwardAllows = []string{"yes", "all", "no", "local", "remote"}
|
forwardAllows = []string{"yes", "all", "no", "local", "remote"}
|
||||||
|
|
||||||
// hostkeyTypes are algorithms/types used for host keys.
|
// keyTypes are algorithms/types used for host keys and client pubkeys.
|
||||||
// The following should generate the same list.
|
// The following should generate the same list.
|
||||||
// ssh -Q HostKeyAlgorithms | sed -re 's/^/"/g' -e 's/$/",/g'
|
// ssh -Q HostKeyAlgorithms | sed -re 's/^/"/g' -e 's/$/",/g'
|
||||||
// ssh -Q HostbasedAcceptedKeyTypes | sed -re 's/^/"/g' -e 's/$/",/g'
|
// ssh -Q HostbasedAcceptedKeyTypes | sed -re 's/^/"/g' -e 's/$/",/g'
|
||||||
hostkeyTypes = []string{
|
// ssh -Q PubkeyAcceptedKeyTypes | sed -re 's/^/"/g' -e 's/$/",/g'
|
||||||
|
// ssh -Q HostbasedKeyTypes | sed -re 's/^/"/g' -e 's/$/",/g'
|
||||||
|
keyTypes = []string{
|
||||||
"ssh-ed25519",
|
"ssh-ed25519",
|
||||||
"ssh-ed25519-cert-v01@openssh.com",
|
"ssh-ed25519-cert-v01@openssh.com",
|
||||||
"sk-ssh-ed25519@openssh.com",
|
"sk-ssh-ed25519@openssh.com",
|
||||||
@ -196,6 +205,21 @@ var (
|
|||||||
"DEBUG3",
|
"DEBUG3",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// logFacilities is a list of valid syslog facilities.
|
||||||
|
logFacilities = []string{
|
||||||
|
"DAEMON",
|
||||||
|
"USER",
|
||||||
|
"AUTH", // default
|
||||||
|
"LOCAL0",
|
||||||
|
"LOCAL1",
|
||||||
|
"LOCAL2",
|
||||||
|
"LOCAL3",
|
||||||
|
"LOCAL4",
|
||||||
|
"LOCAL5",
|
||||||
|
"LOCAL6",
|
||||||
|
"LOCAL7",
|
||||||
|
}
|
||||||
|
|
||||||
// macAlgos is a list of valid MAC (Message Authentication Code) values. "-etm" algos are recommended by upstream.
|
// macAlgos is a list of valid MAC (Message Authentication Code) values. "-etm" algos are recommended by upstream.
|
||||||
// ssh -Q mac | sed -re 's/^/"/g' -e 's/$/",/g'
|
// ssh -Q mac | sed -re 's/^/"/g' -e 's/$/",/g'
|
||||||
macAlgos = []string{
|
macAlgos = []string{
|
||||||
@ -224,6 +248,7 @@ var (
|
|||||||
// Valid keys for sshdMatchCriteria are tracked via field names in SshdMatchRule.
|
// Valid keys for sshdMatchCriteria are tracked via field names in SshdMatchRule.
|
||||||
// Multiple criteria can be specified by e.g. "Match User foo, Host bar.tld"
|
// Multiple criteria can be specified by e.g. "Match User foo, Host bar.tld"
|
||||||
sshdMatchCriteria = []string{
|
sshdMatchCriteria = []string{
|
||||||
|
"Address",
|
||||||
"All",
|
"All",
|
||||||
"User",
|
"User",
|
||||||
"Group",
|
"Group",
|
||||||
@ -231,18 +256,37 @@ var (
|
|||||||
"LocalAddress",
|
"LocalAddress",
|
||||||
"LocalPort",
|
"LocalPort",
|
||||||
"RDomain",
|
"RDomain",
|
||||||
"Address",
|
}
|
||||||
|
|
||||||
|
// sshMatchCriteria is a list of valid criteria that can be used in a Match or Host block.
|
||||||
|
// Valid keys for sshMatchCriteria are tracked via field names in SshMatchRule.
|
||||||
|
// Multiple criteria can be specified by e.g. "Match User foo, Host bar.tld"
|
||||||
|
sshMatchCriteria = []string{
|
||||||
|
"all", // Must appear alone, or immediately after canonical/final.
|
||||||
|
"canonical",
|
||||||
|
"exec", // Requires second argument.
|
||||||
|
"final",
|
||||||
|
"host", // Requires second argument.
|
||||||
|
"localuser", // Requires second argument.
|
||||||
|
"originalhost", // Requires second argument.
|
||||||
|
"user", // Requires second argument.
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// The following are validator maps.
|
// The following are validator maps.
|
||||||
var (
|
var (
|
||||||
// These directives can also begin with "+", "-", or "^", so they need to be stripped off.
|
// These directives can also begin with "+", "-", or "^", so they need to be stripped off.
|
||||||
// TODO: How to do this non-destructively?
|
// TODO: How to do this non-destructively and cleanly?
|
||||||
|
// Currently we just save the struct field's first item with the prefix and strip it in a local var for validating.
|
||||||
sshdStripPre = []string{
|
sshdStripPre = []string{
|
||||||
"HostbasedAcceptedKeyTypes",
|
"HostbasedAcceptedKeyTypes",
|
||||||
"KexAlgorithms",
|
"KexAlgorithms",
|
||||||
}
|
}
|
||||||
|
sshStripPre = []string{
|
||||||
|
"HostbasedKeyTypes",
|
||||||
|
"KexAlgorithms",
|
||||||
|
}
|
||||||
|
|
||||||
// validSshdSingleVals are values that can accept a single string value from a static list.
|
// validSshdSingleVals are values that can accept a single string value from a static list.
|
||||||
validSshdSingleVals = map[string][]string{
|
validSshdSingleVals = map[string][]string{
|
||||||
"AddressFamily": {"any", "inet", "inet6"},
|
"AddressFamily": {"any", "inet", "inet6"},
|
||||||
@ -251,8 +295,13 @@ var (
|
|||||||
"Compression": {"yes", "delayed", "no"}, // "delayed" is legacy, same as "yes".
|
"Compression": {"yes", "delayed", "no"}, // "delayed" is legacy, same as "yes".
|
||||||
"FingerprintHash": {"sha256", "md5"},
|
"FingerprintHash": {"sha256", "md5"},
|
||||||
"GatewayPorts": {"yes", "no", "clientspecified"},
|
"GatewayPorts": {"yes", "no", "clientspecified"},
|
||||||
|
"HostbasedAcceptedKeyTypes": keyTypes,
|
||||||
"IgnoreRHosts": {"yes", "shosts-only", "no"},
|
"IgnoreRHosts": {"yes", "shosts-only", "no"},
|
||||||
"LogLevel": logLevels,
|
"LogLevel": logLevels,
|
||||||
|
"PermitRootLogin": {"yes", "prohibit-password", "forced-commands-only", "no"}, // "without-password" is deprecated.
|
||||||
|
"PermitTunnel": {"yes", "point-to-point", "ethernet", "no"},
|
||||||
|
"PubkeyAuthOptions": {"none", "touch-required"},
|
||||||
|
"SyslogFacility": logFacilities,
|
||||||
}
|
}
|
||||||
|
|
||||||
// validSshdMultiVals are values that can accept multiple values from a static list.
|
// validSshdMultiVals are values that can accept multiple values from a static list.
|
||||||
@ -260,9 +309,28 @@ var (
|
|||||||
"AuthenticationMethods": authMethods,
|
"AuthenticationMethods": authMethods,
|
||||||
"CASignatureAlgorithms": sigAlgos,
|
"CASignatureAlgorithms": sigAlgos,
|
||||||
"Ciphers": ciphers,
|
"Ciphers": ciphers,
|
||||||
"HostbasedAcceptedKeyTypes": hostkeyTypes, // NOTE: Can also begin with "+", "-", or "^"
|
"HostbasedAcceptedKeyTypes": keyTypes,
|
||||||
"HostKeyAlgorithms": hostkeyTypes,
|
"HostKeyAlgorithms": keyTypes,
|
||||||
"KexAlgorithms": kexAlgos, // NOTE: Can also begin with "+", "-", or "^"
|
"KexAlgorithms": kexAlgos,
|
||||||
"MACs": macAlgos,
|
"MACs": macAlgos,
|
||||||
|
"PubkeyAcceptedKeyTypes": keyTypes,
|
||||||
|
}
|
||||||
|
|
||||||
|
// validSshSingleVals are values that can accept a single string value from a static list.
|
||||||
|
validSshSingleVals = map[string][]string{
|
||||||
|
"AddKeysToAgent": {"yes", "ask", "confirm", "no"},
|
||||||
|
"AddressFamily": {"any", "inet", "inet6"},
|
||||||
|
"ControlMaster": {"ask", "yes", "no", "autoask", "auto"},
|
||||||
|
"FingerprintHash": {"sha256", "md5"},
|
||||||
|
}
|
||||||
|
|
||||||
|
// validSshMultiVals are values that can accept multiple values from a static list.
|
||||||
|
validSshMultiVals = map[string][]string{
|
||||||
|
"CASignatureAlgorithms": sigAlgos,
|
||||||
|
"Ciphers": ciphers,
|
||||||
|
"HostbasedKeyTypes": keyTypes,
|
||||||
|
"HostKeyAlgorithms": keyTypes,
|
||||||
|
"KbdInteractiveDevices": {"bsdauth", "pam"},
|
||||||
|
"KexAlgorithms": kexAlgos,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -25,7 +25,7 @@ package config
|
|||||||
*: These values are not in the upstream config but are allowed via the man page (sshd_config(5) and ssh_config(5)).
|
*: These values are not in the upstream config but are allowed via the man page (sshd_config(5) and ssh_config(5)).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// More or less a subset of SshdConf. These are valid keywords for Match blocks in sshd_config.
|
// SshdMatchRule is more or less a subset of SshdConf. These are valid keywords for Match blocks in sshd_config.
|
||||||
type SshdMatchRule struct {
|
type SshdMatchRule struct {
|
||||||
AcceptEnv []string // *
|
AcceptEnv []string // *
|
||||||
AllowAgentForwarding sshBool // .
|
AllowAgentForwarding sshBool // .
|
||||||
@ -49,7 +49,7 @@ type SshdMatchRule struct {
|
|||||||
ForceCommand string // *
|
ForceCommand string // *
|
||||||
GatewayPorts string // .
|
GatewayPorts string // .
|
||||||
GSSAPIAuthentication sshBool // .
|
GSSAPIAuthentication sshBool // .
|
||||||
HostbasedAcceptedKeyTypes []string // *
|
HostbasedAcceptedKeyTypes []string // *+
|
||||||
HostbasedAuthentication sshBool // .
|
HostbasedAuthentication sshBool // .
|
||||||
HostbasedUsesNameFromPacketOnly sshBool // *
|
HostbasedUsesNameFromPacketOnly sshBool // *
|
||||||
IgnoreRhosts string // .
|
IgnoreRhosts string // .
|
||||||
@ -72,10 +72,10 @@ type SshdMatchRule struct {
|
|||||||
PermitUserRC sshBool // *
|
PermitUserRC sshBool // *
|
||||||
PubkeyAcceptedKeyTypes []string // *
|
PubkeyAcceptedKeyTypes []string // *
|
||||||
PubkeyAuthentication sshBool // .+
|
PubkeyAuthentication sshBool // .+
|
||||||
RekeyLimit string // .
|
RekeyLimit []string // .
|
||||||
RevokedKeys string // *
|
RevokedKeys string // *
|
||||||
RDomain string // *
|
RDomain string // *
|
||||||
SetEnv map[string]string // *
|
SetEnv sshEnv // *
|
||||||
// max is 4095, it goes in the config as an octal.
|
// max is 4095, it goes in the config as an octal.
|
||||||
StreamLocalBindMask uint16 // *
|
StreamLocalBindMask uint16 // *
|
||||||
StreamLocalBindUnlink sshBool // *
|
StreamLocalBindUnlink sshBool // *
|
||||||
@ -101,7 +101,7 @@ type SshdConf struct {
|
|||||||
HostCertificate string // *
|
HostCertificate string // *
|
||||||
HostKeyAgent string // *
|
HostKeyAgent string // *
|
||||||
HostKeyAlgorithms []string // +*
|
HostKeyAlgorithms []string // +*
|
||||||
HostKey []string // .
|
HostKey []string // .+
|
||||||
IgnoreUserKnownHosts sshBool // .
|
IgnoreUserKnownHosts sshBool // .
|
||||||
KerberosGetAFSToken sshBool // .
|
KerberosGetAFSToken sshBool // .
|
||||||
KerberosOrLocalPasswd sshBool // .
|
KerberosOrLocalPasswd sshBool // .
|
||||||
@ -114,7 +114,7 @@ type SshdConf struct {
|
|||||||
MaxStartups string // .
|
MaxStartups string // .
|
||||||
PermitUserEnvironment sshBool // .
|
PermitUserEnvironment sshBool // .
|
||||||
PidFile string // .
|
PidFile string // .
|
||||||
Port uint16 // .
|
Port []uint16 // .
|
||||||
PrintLastLog sshBool // .+
|
PrintLastLog sshBool // .+
|
||||||
PrintMotd sshBool // .
|
PrintMotd sshBool // .
|
||||||
Protocol int // +*
|
Protocol int // +*
|
||||||
@ -131,20 +131,86 @@ type SshdConf struct {
|
|||||||
XAuthLocation string // *
|
XAuthLocation string // *
|
||||||
}
|
}
|
||||||
|
|
||||||
// SshConf represents an /etc/ssh/ssh_config (or ~/.ssh/config) file
|
// ListenAddr is a parsed ListenAddress directive.
|
||||||
type SshConf struct {
|
|
||||||
// These are in the default upstream sshd_config so we don't touch them. (Most, if not all, are commented out.)
|
|
||||||
// We just have them here to parse them.
|
|
||||||
Host map[string]string
|
|
||||||
}
|
|
||||||
|
|
||||||
type ListenAddr struct {
|
type ListenAddr struct {
|
||||||
Addr string // hostname|address, hostname:port, IPv4_address:port, or [hostname|address]:port in conf string.
|
Addr string // hostname|address, hostname:port, IPv4_address:port, or [hostname|address]:port in conf string.
|
||||||
Port uint16
|
Port uint16
|
||||||
RDomain string
|
RDomain string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MatchSshd is an sshd_config Match block.
|
||||||
type MatchSshd struct {
|
type MatchSshd struct {
|
||||||
Criteria map[string]string
|
Criteria map[string]string
|
||||||
Rules []SshdMatchRule
|
Rules []SshdMatchRule
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SshMatchRule is more or less a subset of SshConf. These are valid keywords for Match blocks in sshd_config.
|
||||||
|
type SshMatchRule struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// SshConf represents an /etc/ssh/ssh_config (or ~/.ssh/config) file
|
||||||
|
type SshConf struct {
|
||||||
|
AddKeysToAgent string // *
|
||||||
|
AddressFamily string // .
|
||||||
|
BatchMode sshBool // .
|
||||||
|
BindAddress string // *
|
||||||
|
BindInterface string // *
|
||||||
|
CanonicalDomains []string // *
|
||||||
|
CanonicalizeFallbackLocal sshBool // *
|
||||||
|
CanonicalizeHostname sshBool // *
|
||||||
|
CanonicalizeMaxDots uint8 // *
|
||||||
|
CanonicalizePermittedCNAMEs [][2]string // *
|
||||||
|
CASignatureAlgorithms []string // *
|
||||||
|
CertificateFile string // *
|
||||||
|
ChallengeResponseAuthentication sshBool // *
|
||||||
|
CheckHostIP sshBool // .+
|
||||||
|
Ciphers []string // .+
|
||||||
|
ClearAllForwardings sshBool // *
|
||||||
|
Compression sshBool // *
|
||||||
|
ConnectionAttempts uint16 // *
|
||||||
|
ConnectTimeout uint16 // .
|
||||||
|
ControlMaster string // *
|
||||||
|
ControlPath string // *
|
||||||
|
ControlPersist string // *
|
||||||
|
EnableSSHKeysign sshBool // *
|
||||||
|
EscapeChar string // .
|
||||||
|
ExitOnForwardFailure sshBool // *
|
||||||
|
FingerprintHash string // *
|
||||||
|
ForwardAgent string // .
|
||||||
|
ForwardXll sshBool // .
|
||||||
|
ForwardX11Timeout string // .
|
||||||
|
ForwardX11Trusted sshBool // *
|
||||||
|
GatewayPorts sshBool // *
|
||||||
|
GlobalKnownHostsFile []string // *
|
||||||
|
GSSAPIAuthentication sshBool // .
|
||||||
|
GSSAPIDelegateCredentials sshBool // .
|
||||||
|
HashKnownHosts sshBool // *+
|
||||||
|
Host []HostSsh // .
|
||||||
|
HostbasedAuthentication sshBool // .
|
||||||
|
HostbasedKeyTypes []string // *+
|
||||||
|
HostKeyAlgorithms []string // *+
|
||||||
|
HostKeyAlias string // *
|
||||||
|
Hostname string // *
|
||||||
|
IdentitiesOnly sshBool // *
|
||||||
|
IdentityAgent string // *
|
||||||
|
IdentityFile []string // .
|
||||||
|
IgnoreUnknown []string // *
|
||||||
|
Include string // *
|
||||||
|
IPQoS string // *
|
||||||
|
KbdInteractiveAuthentication sshBool // *
|
||||||
|
KbdInteractiveDevices []string // *
|
||||||
|
KexAlgorithms []string // *
|
||||||
|
LocalCommand string // *
|
||||||
|
LocalForward [2]string // *
|
||||||
|
}
|
||||||
|
|
||||||
|
// MatchSsh is an ssh_config Match block.
|
||||||
|
type MatchSsh struct {
|
||||||
|
Criteria map[string]string
|
||||||
|
Rules []SshMatchRule
|
||||||
|
}
|
||||||
|
|
||||||
|
type HostSsh struct {
|
||||||
|
Hostname string
|
||||||
|
Rules []SshMatchRule
|
||||||
|
}
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
`fmt`
|
||||||
|
)
|
||||||
|
|
||||||
type sshBool bool
|
type sshBool bool
|
||||||
|
|
||||||
func (b sshBool) Str() string {
|
func (b sshBool) Str() string {
|
||||||
@ -8,3 +12,13 @@ func (b sshBool) Str() string {
|
|||||||
}
|
}
|
||||||
return "no"
|
return "no"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type sshEnv map[string]string
|
||||||
|
|
||||||
|
func (e sshEnv) Str() string {
|
||||||
|
var s string
|
||||||
|
for k, v := range e {
|
||||||
|
s += fmt.Sprintf("%v=%v", k, v)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
@ -1,34 +1,167 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
`errors`
|
||||||
|
`fmt`
|
||||||
"github.com/oleiade/reflections"
|
`reflect`
|
||||||
"github.com/pkg/errors"
|
`strings`
|
||||||
)
|
)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
func (c *SshdConf) Validate() (bool, error) {
|
// TODO: Match block validation
|
||||||
for k, v := range validSshdSingleVals {
|
|
||||||
realV, err := reflections.GetField(c, k)
|
// Have I mentioned how dumb golang is yet? The following methods share 90% of the same code,
|
||||||
if err != nil {
|
// but ironically delegating that to a separate function is going to be even more of a PITA for now
|
||||||
return false, err
|
// than just maintaining two separate methods.
|
||||||
}
|
// How dumb.
|
||||||
valid := false
|
|
||||||
for _, i := range v {
|
// Validate validates the actual struct of an SshdConf itself, ensuring that certain list fields contain
|
||||||
if i == realV {
|
// valid item(s). It collects all found issues in allErr.
|
||||||
valid = true
|
func (c *SshdConf) Validate() (validConf bool, allErr []error) {
|
||||||
|
// Set the default as true.
|
||||||
|
// We set it on false on first failed validation and keep going.
|
||||||
|
validConf = true
|
||||||
|
fields := reflect.TypeOf(c)
|
||||||
|
values := reflect.ValueOf(c)
|
||||||
|
for i := 0; i < fields.NumField(); i++ {
|
||||||
|
field := fields.Field(i)
|
||||||
|
value := values.Field(i)
|
||||||
|
var validField bool
|
||||||
|
n := field.Name
|
||||||
|
single, isSingle := validSshdSingleVals[n]
|
||||||
|
multi, isMulti := validSshdMultiVals[n]
|
||||||
|
if isSingle {
|
||||||
|
v := value.String()
|
||||||
|
for _, x := range single {
|
||||||
|
if v == x {
|
||||||
|
validField = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !valid {
|
if !validField {
|
||||||
|
validConf = false
|
||||||
e := fmt.Sprintf(
|
e := fmt.Sprintf(
|
||||||
"field %v value %v is not allowed",
|
"field %v: value %v is not allowed; must be ONE of: %v",
|
||||||
k, realV)
|
n, v, single,
|
||||||
return false, errors.New(e)
|
)
|
||||||
|
allErr = append(allErr, errors.New(e))
|
||||||
}
|
}
|
||||||
|
} else if isMulti {
|
||||||
|
// These are all []strings if the field name is in validSshdMultiVals.
|
||||||
|
// But golang is still dumb and has no way of serializing directly, so here comes the hackery.
|
||||||
|
v, ok := value.Interface().([]string)
|
||||||
|
if !ok {
|
||||||
|
validConf = false
|
||||||
|
e := fmt.Sprintf(
|
||||||
|
"field %v: value %v was not able to be parsed as a []string",
|
||||||
|
n, v,
|
||||||
|
)
|
||||||
|
allErr = append(allErr, errors.New(e))
|
||||||
|
}
|
||||||
|
var invalidSlice []string
|
||||||
|
for _, vStr := range v {
|
||||||
|
validItem := false
|
||||||
|
for _, strip := range sshdStripPre {
|
||||||
|
if n == strip {
|
||||||
|
for _, c := range []string{"+", "-", "^"} {
|
||||||
|
vStr = strings.TrimPrefix(vStr, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, nil
|
}
|
||||||
|
}
|
||||||
|
for _, x := range multi {
|
||||||
|
if vStr == x {
|
||||||
|
validItem = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !validItem {
|
||||||
|
invalidSlice = append(invalidSlice, vStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, x := range invalidSlice {
|
||||||
|
e := fmt.Sprintf(
|
||||||
|
"field %v: value item %v is not valid; it must be one or more of %v",
|
||||||
|
n, x, multi,
|
||||||
|
)
|
||||||
|
allErr = append(allErr, errors.New(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return validConf, allErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate validates the actual struct of an SshConf itself, ensuring that certain list fields contain
|
||||||
|
// valid item(s). It collects all found issues in allErr.
|
||||||
|
func (c *SshConf) Validate() (validConf bool, allErr []error) {
|
||||||
|
// Set the default as true.
|
||||||
|
// We set it on false on first failed validation and keep going.
|
||||||
|
validConf = true
|
||||||
|
fields := reflect.TypeOf(c)
|
||||||
|
values := reflect.ValueOf(c)
|
||||||
|
for i := 0; i < fields.NumField(); i++ {
|
||||||
|
field := fields.Field(i)
|
||||||
|
value := values.Field(i)
|
||||||
|
var validField bool
|
||||||
|
n := field.Name
|
||||||
|
single, isSingle := validSshSingleVals[n]
|
||||||
|
multi, isMulti := validSshMultiVals[n]
|
||||||
|
if isSingle {
|
||||||
|
v := value.String()
|
||||||
|
for _, x := range single {
|
||||||
|
if v == x {
|
||||||
|
validField = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !validField {
|
||||||
|
validConf = false
|
||||||
|
e := fmt.Sprintf(
|
||||||
|
"field %v: value %v is not allowed; must be ONE of: %v",
|
||||||
|
n, v, single,
|
||||||
|
)
|
||||||
|
allErr = append(allErr, errors.New(e))
|
||||||
|
}
|
||||||
|
} else if isMulti {
|
||||||
|
// These are all []strings if the field name is in validSshMultiVals.
|
||||||
|
// But golang is still dumb and has no way of serializing directly, so here comes the hackery.
|
||||||
|
v, ok := value.Interface().([]string)
|
||||||
|
if !ok {
|
||||||
|
validConf = false
|
||||||
|
e := fmt.Sprintf(
|
||||||
|
"field %v: value %v was not able to be parsed as a []string",
|
||||||
|
n, v,
|
||||||
|
)
|
||||||
|
allErr = append(allErr, errors.New(e))
|
||||||
|
}
|
||||||
|
var invalidSlice []string
|
||||||
|
for _, vStr := range v {
|
||||||
|
validItem := false
|
||||||
|
for _, strip := range sshStripPre {
|
||||||
|
if n == strip {
|
||||||
|
for _, c := range []string{"+", "-", "^"} {
|
||||||
|
vStr = strings.TrimPrefix(vStr, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, x := range multi {
|
||||||
|
if vStr == x {
|
||||||
|
validItem = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !validItem {
|
||||||
|
invalidSlice = append(invalidSlice, vStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, x := range invalidSlice {
|
||||||
|
e := fmt.Sprintf(
|
||||||
|
"field %v: value item %v is not valid; it must be one or more of %v",
|
||||||
|
n, x, multi,
|
||||||
|
)
|
||||||
|
allErr = append(allErr, errors.New(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return validConf, allErr
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user