- Environment variables `UID` and `GID`, both defaulting to `1000` - All subprocesses (openvpn, tinyproxy, etc.) run using the UID and GID given - All files are written with an ownership for the UID and GID given - Port forwarded file has also ownership for UID, GID and read permission only
This commit is contained in:
28
internal/alpine/alpine.go
Normal file
28
internal/alpine/alpine.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package alpine
|
||||
|
||||
import (
|
||||
"os/user"
|
||||
|
||||
"github.com/qdm12/golibs/files"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
)
|
||||
|
||||
const logPrefix = "alpine configurator"
|
||||
|
||||
type Configurator interface {
|
||||
CreateUser(username string, uid int) error
|
||||
}
|
||||
|
||||
type configurator struct {
|
||||
fileManager files.FileManager
|
||||
lookupUID func(uid string) (*user.User, error)
|
||||
lookupUser func(username string) (*user.User, error)
|
||||
}
|
||||
|
||||
func NewConfigurator(logger logging.Logger, fileManager files.FileManager) Configurator {
|
||||
return &configurator{
|
||||
fileManager: fileManager,
|
||||
lookupUID: user.LookupId,
|
||||
lookupUser: user.Lookup,
|
||||
}
|
||||
}
|
||||
38
internal/alpine/users.go
Normal file
38
internal/alpine/users.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package alpine
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/user"
|
||||
)
|
||||
|
||||
// CreateUser creates a user in Alpine with the given UID
|
||||
func (c *configurator) CreateUser(username string, uid int) 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)
|
||||
} else if u != nil {
|
||||
if u.Username == username {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("user with ID %d exists with username %q instead of %q", uid, u.Username, username)
|
||||
}
|
||||
u, err = c.lookupUser(username)
|
||||
_, unknownUsername := err.(user.UnknownUserError)
|
||||
if err != nil && !unknownUsername {
|
||||
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", username, u.Uid, uid)
|
||||
}
|
||||
passwd, err := c.fileManager.ReadFile("/etc/passwd")
|
||||
if err != nil {
|
||||
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 nil
|
||||
}
|
||||
15
internal/params/ids.go
Normal file
15
internal/params/ids.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package params
|
||||
|
||||
import (
|
||||
libparams "github.com/qdm12/golibs/params"
|
||||
)
|
||||
|
||||
// GetUID obtains the user ID to use from the environment variable UID
|
||||
func (p *paramsReader) GetUID() (uid int, err error) {
|
||||
return p.envParams.GetEnvIntRange("UID", 0, 65535, libparams.Default("1000"))
|
||||
}
|
||||
|
||||
// GetGID obtains the group ID to use from the environment variable GID
|
||||
func (p *paramsReader) GetGID() (gid int, err error) {
|
||||
return p.envParams.GetEnvIntRange("GID", 0, 65535, libparams.Default("1000"))
|
||||
}
|
||||
@@ -28,6 +28,10 @@ type ParamsReader interface {
|
||||
GetDNSOverTLSPrivateAddresses() (privateAddresses []string)
|
||||
GetDNSOverTLSIPv6() (ipv6 bool, err error)
|
||||
|
||||
// IDs
|
||||
GetUID() (uid int, err error)
|
||||
GetGID() (gid int, err error)
|
||||
|
||||
// Firewall getters
|
||||
GetExtraSubnets() (extraSubnets []net.IPNet, err error)
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ type Configurator interface {
|
||||
encryption models.PIAEncryption, targetIP net.IP) (connections []models.OpenVPNConnection, err error)
|
||||
BuildConf(connections []models.OpenVPNConnection, encryption models.PIAEncryption, verbosity, uid, gid int, root bool, cipher, auth string) (err error)
|
||||
GetPortForward() (port uint16, err error)
|
||||
WritePortForward(filepath models.Filepath, port uint16) (err error)
|
||||
WritePortForward(filepath models.Filepath, port uint16, uid, gid int) (err error)
|
||||
AllowPortForwardFirewall(device models.VPNDevice, port uint16) (err error)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/qdm12/golibs/files"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
)
|
||||
@@ -35,9 +36,13 @@ func (c *configurator) GetPortForward() (port uint16, err error) {
|
||||
return body.Port, nil
|
||||
}
|
||||
|
||||
func (c *configurator) WritePortForward(filepath models.Filepath, port uint16) (err error) {
|
||||
func (c *configurator) WritePortForward(filepath models.Filepath, port uint16, uid, gid int) (err error) {
|
||||
c.logger.Info("%s: Writing forwarded port to %s", logPrefix, filepath)
|
||||
return c.fileManager.WriteLinesToFile(string(filepath), []string{fmt.Sprintf("%d", port)})
|
||||
return c.fileManager.WriteLinesToFile(
|
||||
string(filepath),
|
||||
[]string{fmt.Sprintf("%d", port)},
|
||||
files.Ownership(uid, gid),
|
||||
files.Permissions(400))
|
||||
}
|
||||
|
||||
func (c *configurator) AllowPortForwardFirewall(device models.VPNDevice, port uint16) (err error) {
|
||||
|
||||
@@ -18,6 +18,8 @@ type Settings struct {
|
||||
Firewall Firewall
|
||||
TinyProxy TinyProxy
|
||||
ShadowSocks ShadowSocks
|
||||
UID int
|
||||
GID int
|
||||
}
|
||||
|
||||
func (s *Settings) String() string {
|
||||
@@ -32,6 +34,7 @@ func (s *Settings) String() string {
|
||||
}
|
||||
return strings.Join([]string{
|
||||
"Settings summary below:",
|
||||
fmt.Sprintf("|-- Using UID %d and GID %d", s.UID, s.GID),
|
||||
s.OpenVPN.String(),
|
||||
vpnServiceProvider,
|
||||
s.DNS.String(),
|
||||
@@ -115,5 +118,13 @@ func GetAllSettings(params params.ParamsReader) (settings Settings, err error) {
|
||||
if err != nil {
|
||||
return settings, err
|
||||
}
|
||||
settings.UID, err = params.GetUID()
|
||||
if err != nil {
|
||||
return settings, err
|
||||
}
|
||||
settings.GID, err = params.GetGID()
|
||||
if err != nil {
|
||||
return settings, err
|
||||
}
|
||||
return settings, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user