From d539b335e8a7a87dda3da259958bb52183fb760e Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Tue, 5 Mar 2019 02:29:41 +0100 Subject: conf: validate tunnel name --- conf/name.go | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ conf/parser.go | 3 +++ conf/store.go | 18 +++++++++++++++++- 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 conf/name.go (limited to 'conf') diff --git a/conf/name.go b/conf/name.go new file mode 100644 index 00000000..da9928e0 --- /dev/null +++ b/conf/name.go @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. + */ + +package conf + +import ( + "regexp" + "strings" +) + +var reservedNames = []string{ + "CON", "PRN", "AUX", "NUL", + "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", + "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", +} + +const specialChars = "/\\<>:\"|?*\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x00" + +var allowedNameFormat *regexp.Regexp + +func init() { + allowedNameFormat = regexp.MustCompile("^[a-zA-Z0-9_=+.-]{1,32}$") +} + +func isReserved(name string) bool { + if len(name) == 0 { + return false + } + for _, reserved := range reservedNames { + if strings.EqualFold(name, reserved) { + return true + } + } + return false +} + +func hasSpecialChars(name string) bool { + return strings.ContainsAny(name, specialChars) +} + +func TunnelNameIsValid(name string) bool { + // Aside from our own restrictions, let's impose the Windows restrictions first + if isReserved(name) || hasSpecialChars(name) { + return false + } + return allowedNameFormat.MatchString(name) +} diff --git a/conf/parser.go b/conf/parser.go index 3b2ae1b3..b9ceb20e 100644 --- a/conf/parser.go +++ b/conf/parser.go @@ -189,6 +189,9 @@ func (c *Config) maybeAddPeer(p *Peer) { } func FromWgQuick(s string, name string) (*Config, error) { + if !TunnelNameIsValid(name) { + return nil, &ParseError{"Tunnel name is not valid", name} + } lines := strings.Split(s, "\n") parserState := notInASection conf := Config{Name: name} diff --git a/conf/store.go b/conf/store.go index 7c110865..da144a17 100644 --- a/conf/store.go +++ b/conf/store.go @@ -36,7 +36,11 @@ func ListConfigNames() ([]string, error) { if !file.Mode().IsRegular() || file.Mode().Perm()&0444 == 0 { continue } - configs[i] = strings.TrimSuffix(name, configFileSuffix) + name = strings.TrimSuffix(name, configFileSuffix) + if !TunnelNameIsValid(name) { + continue + } + configs[i] = name i++ } return configs[:i], nil @@ -152,10 +156,16 @@ func NameFromPath(path string) (string, error) { } else { name = strings.TrimSuffix(name, configFileUnencryptedSuffix) } + if !TunnelNameIsValid(name) { + return "", errors.New("Tunnel name is not valid") + } return name, nil } func (config *Config) Save() error { + if !TunnelNameIsValid(config.Name) { + return errors.New("Tunnel name is not valid") + } configFileDir, err := resolveConfigFileDir() if err != nil { return err @@ -179,6 +189,9 @@ func (config *Config) Save() error { } func (config *Config) Path() (string, error) { + if !TunnelNameIsValid(config.Name) { + return "", errors.New("Tunnel name is not valid") + } configFileDir, err := resolveConfigFileDir() if err != nil { return "", err @@ -187,6 +200,9 @@ func (config *Config) Path() (string, error) { } func DeleteName(name string) error { + if !TunnelNameIsValid(name) { + return errors.New("Tunnel name is not valid") + } configFileDir, err := resolveConfigFileDir() if err != nil { return err -- cgit v1.2.3-59-g8ed1b