Re-use username for UID if it exists

This commit is contained in:
Quentin McGaw
2020-12-27 00:36:39 +00:00
parent 38e713fea2
commit 2dc674559e
19 changed files with 52 additions and 48 deletions

View File

@@ -118,7 +118,8 @@ func _main(background context.Context, args []string) int { //nolint:gocognit,go
// Should never change
uid, gid := allSettings.System.UID, allSettings.System.GID
err = alpineConf.CreateUser("nonrootuser", uid)
const defaultUsername = "nonrootuser"
nonRootUsername, err := alpineConf.CreateUser(defaultUsername, uid)
if err != nil {
logger.Error(err)
return 1
@@ -217,7 +218,7 @@ func _main(background context.Context, args []string) int { //nolint:gocognit,go
go collectStreamLines(ctx, streamMerger, logger, signalTunnelReady)
openvpnLooper := openvpn.NewLooper(allSettings.OpenVPN, uid, gid, allServers,
openvpnLooper := openvpn.NewLooper(allSettings.OpenVPN, nonRootUsername, uid, gid, allServers,
ovpnConf, firewallConf, routingConf, logger, httpClient, fileManager, streamMerger, cancel)
wg.Add(1)
// wait for restartOpenvpn
@@ -229,7 +230,7 @@ func _main(background context.Context, args []string) int { //nolint:gocognit,go
// wait for updaterLooper.Restart() or its ticket launched with RunRestartTicker
go updaterLooper.Run(ctx, wg)
unboundLooper := dns.NewLooper(dnsConf, allSettings.DNS, logger, streamMerger, uid, gid)
unboundLooper := dns.NewLooper(dnsConf, allSettings.DNS, logger, streamMerger, nonRootUsername, uid, gid)
wg.Add(1)
// wait for unboundLooper.Restart or its ticker launched with RunRestartTicker
go unboundLooper.Run(ctx, wg, signalDNSReady)

View File

@@ -7,7 +7,7 @@ import (
)
type Configurator interface {
CreateUser(username string, uid int) error
CreateUser(username string, uid int) (createdUsername string, err error)
}
type configurator struct {

View File

@@ -6,34 +6,34 @@ import (
)
// CreateUser creates a user in Alpine with the given UID.
func (c *configurator) CreateUser(username string, uid int) error {
func (c *configurator) CreateUser(username string, uid int) (createdUsername string, err error) {
UIDStr := fmt.Sprintf("%d", uid)
u, err := c.lookupUID(UIDStr)
_, unknownUID := err.(user.UnknownUserIdError)
if err != nil && !unknownUID {
return fmt.Errorf("cannot create user: %w", err)
return "", fmt.Errorf("cannot create user: %w", err)
} else if u != nil {
if u.Username == username {
return nil
return "", nil
}
return fmt.Errorf("user with ID %d exists with username %q instead of %q", uid, u.Username, username)
return u.Username, nil
}
u, err = c.lookupUser(username)
_, unknownUsername := err.(user.UnknownUserError)
if err != nil && !unknownUsername {
return fmt.Errorf("cannot create user: %w", err)
return "", fmt.Errorf("cannot create user: %w", err)
} else if u != nil {
return fmt.Errorf("cannot create user: user with name %s already exists for ID %s instead of %d",
return "", fmt.Errorf("cannot create user: user with name %s already exists for ID %s instead of %d",
username, u.Uid, uid)
}
passwd, err := c.fileManager.ReadFile("/etc/passwd")
if err != nil {
return fmt.Errorf("cannot create user: %w", err)
return "", fmt.Errorf("cannot create user: %w", err)
}
passwd = append(passwd, []byte(fmt.Sprintf("%s:x:%d:::/dev/null:/sbin/nologin\n", username, uid))...)
if err := c.fileManager.WriteToFile("/etc/passwd", passwd); err != nil {
return fmt.Errorf("cannot create user: %w", err)
return "", fmt.Errorf("cannot create user: %w", err)
}
return nil
return username, nil
}

View File

@@ -71,8 +71,7 @@ func OpenvpnConfig() error {
lines := providerConf.BuildConf(
connection,
allSettings.OpenVPN.Verbosity,
allSettings.System.UID,
allSettings.System.GID,
"nonroortuser",
allSettings.OpenVPN.Root,
allSettings.OpenVPN.Cipher,
allSettings.OpenVPN.Auth,

View File

@@ -14,9 +14,10 @@ import (
"github.com/qdm12/golibs/network"
)
func (c *configurator) MakeUnboundConf(ctx context.Context, settings settings.DNS, uid, gid int) (err error) {
func (c *configurator) MakeUnboundConf(ctx context.Context, settings settings.DNS,
username string, uid, gid int) (err error) {
c.logger.Info("generating Unbound configuration")
lines, warnings := generateUnboundConf(ctx, settings, c.client, c.logger)
lines, warnings := generateUnboundConf(ctx, settings, username, c.client, c.logger)
for _, warning := range warnings {
c.logger.Warn(warning)
}
@@ -28,7 +29,7 @@ func (c *configurator) MakeUnboundConf(ctx context.Context, settings settings.DN
}
// MakeUnboundConf generates an Unbound configuration from the user provided settings.
func generateUnboundConf(ctx context.Context, settings settings.DNS,
func generateUnboundConf(ctx context.Context, settings settings.DNS, username string,
client network.Client, logger logging.Logger) (
lines []string, warnings []error) {
doIPv6 := "no"
@@ -69,7 +70,7 @@ func generateUnboundConf(ctx context.Context, settings settings.DNS,
"interface": "0.0.0.0",
"port": "53",
// Other
"username": "\"nonrootuser\"",
"username": fmt.Sprintf("%q", username),
}
// Block lists

View File

@@ -41,7 +41,7 @@ func Test_generateUnboundConf(t *testing.T) {
logger := mock_logging.NewMockLogger(mockCtrl)
logger.EXPECT().Info("%d hostnames blocked overall", 2).Times(1)
logger.EXPECT().Info("%d IP addresses blocked overall", 3).Times(1)
lines, warnings := generateUnboundConf(ctx, settings, client, logger)
lines, warnings := generateUnboundConf(ctx, settings, "nonrootuser", client, logger)
require.Len(t, warnings, 0)
expected := `
server:

View File

@@ -15,7 +15,7 @@ import (
type Configurator interface {
DownloadRootHints(ctx context.Context, uid, gid int) error
DownloadRootKey(ctx context.Context, uid, gid int) error
MakeUnboundConf(ctx context.Context, settings settings.DNS, uid, gid int) (err error)
MakeUnboundConf(ctx context.Context, settings settings.DNS, username string, uid, gid int) (err error)
UseDNSInternally(IP net.IP)
UseDNSSystemWide(ip net.IP, keepNameserver bool) error
Start(ctx context.Context, logLevel uint8) (stdout io.ReadCloser, waitFn func() error, err error)

View File

@@ -27,6 +27,7 @@ type looper struct {
conf Configurator
logger logging.Logger
streamMerger command.StreamMerger
username string
uid int
gid int
loopLock sync.Mutex
@@ -40,7 +41,7 @@ type looper struct {
}
func NewLooper(conf Configurator, settings settings.DNS, logger logging.Logger,
streamMerger command.StreamMerger, uid, gid int) Looper {
streamMerger command.StreamMerger, username string, uid, gid int) Looper {
return &looper{
state: state{
status: constants.Stopped,
@@ -48,6 +49,7 @@ func NewLooper(conf Configurator, settings settings.DNS, logger logging.Logger,
},
conf: conf,
logger: logger.WithPrefix("dns over tls: "),
username: username,
uid: uid,
gid: gid,
streamMerger: streamMerger,
@@ -292,7 +294,7 @@ func (l *looper) updateFiles(ctx context.Context) (err error) {
return err
}
settings := l.GetSettings()
if err := l.conf.MakeUnboundConf(ctx, settings, l.uid, l.gid); err != nil {
if err := l.conf.MakeUnboundConf(ctx, settings, l.username, l.uid, l.gid); err != nil {
return err
}
return nil

View File

@@ -33,8 +33,9 @@ type Looper interface {
type looper struct {
state state
// Fixed parameters
uid int
gid int
username string
uid int
gid int
// Configurators
conf Configurator
fw firewall.Configurator
@@ -54,7 +55,7 @@ type looper struct {
}
func NewLooper(settings settings.OpenVPN,
uid, gid int, allServers models.AllServers,
username string, uid, gid int, allServers models.AllServers,
conf Configurator, fw firewall.Configurator, routing routing.Routing,
logger logging.Logger, client *http.Client, fileManager files.FileManager,
streamMerger command.StreamMerger, cancel context.CancelFunc) Looper {
@@ -64,6 +65,7 @@ func NewLooper(settings settings.OpenVPN,
settings: settings,
allServers: allServers,
},
username: username,
uid: uid,
gid: gid,
conf: conf,
@@ -107,8 +109,7 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) {
lines := providerConf.BuildConf(
connection,
settings.Verbosity,
l.uid,
l.gid,
l.username,
settings.Root,
settings.Cipher,
settings.Auth,

View File

@@ -62,8 +62,8 @@ func (c *cyberghost) GetOpenVPNConnection(selection models.ServerSelection) (
return pickRandomConnection(connections, c.randSource), nil
}
func (c *cyberghost) BuildConf(connection models.OpenVPNConnection, verbosity,
uid, gid int, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
func (c *cyberghost) BuildConf(connection models.OpenVPNConnection, verbosity int,
username string, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
if len(cipher) == 0 {
cipher = aes256cbc
}
@@ -105,7 +105,7 @@ func (c *cyberghost) BuildConf(connection models.OpenVPNConnection, verbosity,
lines = append(lines, "ncp-ciphers AES-256-GCM:AES-256-CBC:AES-128-GCM")
}
if !root {
lines = append(lines, "user nonrootuser")
lines = append(lines, "user "+username)
}
lines = append(lines, []string{
"<ca>",

View File

@@ -73,7 +73,7 @@ func (m *mullvad) GetOpenVPNConnection(selection models.ServerSelection) (
}
func (m *mullvad) BuildConf(connection models.OpenVPNConnection,
verbosity, uid, gid int, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
verbosity int, username string, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
if len(cipher) == 0 {
cipher = aes256cbc
}
@@ -114,7 +114,7 @@ func (m *mullvad) BuildConf(connection models.OpenVPNConnection,
lines = append(lines, `pull-filter ignore "ifconfig-ipv6"`)
}
if !root {
lines = append(lines, "user nonrootuser")
lines = append(lines, "user "+username)
}
lines = append(lines, []string{
"<ca>",

View File

@@ -78,7 +78,7 @@ func (n *nordvpn) GetOpenVPNConnection(selection models.ServerSelection) (
return pickRandomConnection(connections, n.randSource), nil
}
func (n *nordvpn) BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int, root bool,
func (n *nordvpn) BuildConf(connection models.OpenVPNConnection, verbosity int, username string, root bool,
cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
if len(cipher) == 0 {
cipher = aes256cbc
@@ -121,7 +121,7 @@ func (n *nordvpn) BuildConf(connection models.OpenVPNConnection, verbosity, uid,
fmt.Sprintf("auth %s", auth),
}
if !root {
lines = append(lines, "user nonrootuser")
lines = append(lines, "user "+username)
}
lines = append(lines, []string{
"<ca>",

View File

@@ -109,7 +109,7 @@ func (p *pia) GetOpenVPNConnection(selection models.ServerSelection) (
return connection, nil
}
func (p *pia) BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int, root bool,
func (p *pia) BuildConf(connection models.OpenVPNConnection, verbosity int, username string, root bool,
cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
var X509CRL, certificate string
var defaultCipher, defaultAuth string
@@ -161,7 +161,7 @@ func (p *pia) BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid
lines = append(lines, "ncp-disable")
}
if !root {
lines = append(lines, "user nonrootuser")
lines = append(lines, "user "+username)
}
lines = append(lines, []string{
"<crl-verify>",

View File

@@ -70,7 +70,7 @@ func (s *privado) GetOpenVPNConnection(selection models.ServerSelection) (
return pickRandomConnection(connections, s.randSource), nil
}
func (s *privado) BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int, root bool,
func (s *privado) BuildConf(connection models.OpenVPNConnection, verbosity int, username string, root bool,
cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
if len(cipher) == 0 {
cipher = aes256cbc
@@ -104,7 +104,7 @@ func (s *privado) BuildConf(connection models.OpenVPNConnection, verbosity, uid,
fmt.Sprintf("auth %s", auth),
}
if !root {
lines = append(lines, "user nonrootuser")
lines = append(lines, "user "+username)
}
lines = append(lines, []string{
"<ca>",

View File

@@ -15,7 +15,7 @@ import (
// Provider contains methods to read and modify the openvpn configuration to connect as a client.
type Provider interface {
GetOpenVPNConnection(selection models.ServerSelection) (connection models.OpenVPNConnection, err error)
BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int,
BuildConf(connection models.OpenVPNConnection, verbosity int, username string,
root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string)
PortForward(ctx context.Context, client *http.Client,
fileManager files.FileManager, pfLogger logging.Logger, gateway net.IP, fw firewall.Configurator,

View File

@@ -72,7 +72,7 @@ func (p *purevpn) GetOpenVPNConnection(selection models.ServerSelection) (
return pickRandomConnection(connections, p.randSource), nil
}
func (p *purevpn) BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int, root bool,
func (p *purevpn) BuildConf(connection models.OpenVPNConnection, verbosity int, username string, root bool,
cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
if len(cipher) == 0 {
cipher = aes256cbc
@@ -108,7 +108,7 @@ func (p *purevpn) BuildConf(connection models.OpenVPNConnection, verbosity, uid,
fmt.Sprintf("cipher %s", cipher),
}
if !root {
lines = append(lines, "user nonrootuser")
lines = append(lines, "user "+username)
}
lines = append(lines, []string{
"<ca>",

View File

@@ -73,7 +73,7 @@ func (s *surfshark) GetOpenVPNConnection(selection models.ServerSelection) (
return pickRandomConnection(connections, s.randSource), nil
}
func (s *surfshark) BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int, root bool,
func (s *surfshark) BuildConf(connection models.OpenVPNConnection, verbosity int, username string, root bool,
cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
if len(cipher) == 0 {
cipher = aes256cbc
@@ -117,7 +117,7 @@ func (s *surfshark) BuildConf(connection models.OpenVPNConnection, verbosity, ui
fmt.Sprintf("auth %s", auth),
}
if !root {
lines = append(lines, "user nonrootuser")
lines = append(lines, "user "+username)
}
lines = append(lines, []string{
"<ca>",

View File

@@ -69,7 +69,7 @@ func (v *vyprvpn) GetOpenVPNConnection(selection models.ServerSelection) (
return pickRandomConnection(connections, v.randSource), nil
}
func (v *vyprvpn) BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int,
func (v *vyprvpn) BuildConf(connection models.OpenVPNConnection, verbosity int, username string,
root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
if len(cipher) == 0 {
cipher = aes256cbc
@@ -106,7 +106,7 @@ func (v *vyprvpn) BuildConf(connection models.OpenVPNConnection, verbosity, uid,
fmt.Sprintf("auth %s", auth),
}
if !root {
lines = append(lines, "user nonrootuser")
lines = append(lines, "user "+username)
}
lines = append(lines, []string{
"<ca>",

View File

@@ -72,7 +72,7 @@ func (w *windscribe) GetOpenVPNConnection(selection models.ServerSelection) (con
return pickRandomConnection(connections, w.randSource), nil
}
func (w *windscribe) BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int,
func (w *windscribe) BuildConf(connection models.OpenVPNConnection, verbosity int, username string,
root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
if len(cipher) == 0 {
cipher = aes256cbc
@@ -111,7 +111,7 @@ func (w *windscribe) BuildConf(connection models.OpenVPNConnection, verbosity, u
lines = append(lines, "ncp-ciphers AES-256-GCM:AES-256-CBC:AES-128-GCM")
}
if !root {
lines = append(lines, "user nonrootuser")
lines = append(lines, "user "+username)
}
lines = append(lines, []string{
"<ca>",