agent: use interface for file permissions
This commit is contained in:
parent
1e0cd2e499
commit
c669a17fa6
|
@ -188,7 +188,7 @@ func TestSetupAgent_RPCUnixSocket_FileExists(t *testing.T) {
|
|||
conf.Addresses.RPC = "unix://" + socketPath
|
||||
|
||||
// Custom mode for socket file
|
||||
conf.UnixSockets = map[string]string{"mode": "0777"}
|
||||
conf.UnixSockets.Perms = "0777"
|
||||
|
||||
shutdownCh := make(chan struct{})
|
||||
defer close(shutdownCh)
|
||||
|
|
|
@ -345,7 +345,27 @@ type Config struct {
|
|||
WatchPlans []*watch.WatchPlan `mapstructure:"-" json:"-"`
|
||||
|
||||
// UnixSockets is a map of socket configuration data
|
||||
UnixSockets map[string]string `mapstructure:"unix_sockets"`
|
||||
UnixSockets UnixSocketConfig `mapstructure:"unix_sockets"`
|
||||
}
|
||||
|
||||
// UnixSocketConfig contains information about a unix socket, and
|
||||
// implements the FilePermissions interface.
|
||||
type UnixSocketConfig struct {
|
||||
Usr string `mapstructure:"user"`
|
||||
Grp string `mapstructure:"group"`
|
||||
Perms string `mapstructure:"mode"`
|
||||
}
|
||||
|
||||
func (u UnixSocketConfig) User() string {
|
||||
return u.Usr
|
||||
}
|
||||
|
||||
func (u UnixSocketConfig) Group() string {
|
||||
return u.Grp
|
||||
}
|
||||
|
||||
func (u UnixSocketConfig) Mode() string {
|
||||
return u.Perms
|
||||
}
|
||||
|
||||
// unixSocketAddr tests if a given address describes a domain socket,
|
||||
|
@ -886,6 +906,15 @@ func MergeConfig(a, b *Config) *Config {
|
|||
if b.DisableAnonymousSignature {
|
||||
result.DisableAnonymousSignature = true
|
||||
}
|
||||
if b.UnixSockets.Usr != "" {
|
||||
result.UnixSockets.Usr = b.UnixSockets.Usr
|
||||
}
|
||||
if b.UnixSockets.Grp != "" {
|
||||
result.UnixSockets.Grp = b.UnixSockets.Grp
|
||||
}
|
||||
if b.UnixSockets.Perms != "" {
|
||||
result.UnixSockets.Perms = b.UnixSockets.Perms
|
||||
}
|
||||
|
||||
if len(b.HTTPAPIResponseHeaders) != 0 {
|
||||
if result.HTTPAPIResponseHeaders == nil {
|
||||
|
@ -896,15 +925,6 @@ func MergeConfig(a, b *Config) *Config {
|
|||
}
|
||||
}
|
||||
|
||||
if len(b.UnixSockets) != 0 {
|
||||
if result.UnixSockets == nil {
|
||||
result.UnixSockets = make(map[string]string)
|
||||
}
|
||||
for field, value := range b.UnixSockets {
|
||||
result.UnixSockets[field] = value
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the start join addresses
|
||||
result.StartJoin = make([]string, 0, len(a.StartJoin)+len(b.StartJoin))
|
||||
result.StartJoin = append(result.StartJoin, a.StartJoin...)
|
||||
|
|
|
@ -595,12 +595,14 @@ func TestDecodeConfig(t *testing.T) {
|
|||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(config.UnixSockets, map[string]string{
|
||||
"user": "500",
|
||||
"group": "500",
|
||||
"mode": "0700",
|
||||
}) {
|
||||
t.Fatalf("bad: %v", config.UnixSockets)
|
||||
if config.UnixSockets.Usr != "500" {
|
||||
t.Fatalf("bad: %#v", config)
|
||||
}
|
||||
if config.UnixSockets.Grp != "500" {
|
||||
t.Fatalf("bad: %#v", config)
|
||||
}
|
||||
if config.UnixSockets.Perms != "0700" {
|
||||
t.Fatalf("bad: %#v", config)
|
||||
}
|
||||
|
||||
// Disable updates
|
||||
|
@ -1013,10 +1015,10 @@ func TestMergeConfig(t *testing.T) {
|
|||
HTTPAPIResponseHeaders: map[string]string{
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
},
|
||||
UnixSockets: map[string]string{
|
||||
"user": "500",
|
||||
"group": "500",
|
||||
"mode": "0700",
|
||||
UnixSockets: UnixSocketConfig{
|
||||
Usr: "500",
|
||||
Grp: "500",
|
||||
Perms: "0700",
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ func TestHTTPServer_UnixSocket(t *testing.T) {
|
|||
|
||||
// Only testing mode, since uid/gid might not be settable
|
||||
// from test environment.
|
||||
c.UnixSockets = map[string]string{"mode": "0777"}
|
||||
c.UnixSockets = UnixSocketConfig{Perms: "0777"}
|
||||
})
|
||||
defer os.RemoveAll(dir)
|
||||
defer srv.Shutdown()
|
||||
|
|
|
@ -100,34 +100,47 @@ func stringHash(s string) string {
|
|||
return fmt.Sprintf("%x", md5.Sum([]byte(s)))
|
||||
}
|
||||
|
||||
// FilePermissions is an interface which allows a struct to set
|
||||
// ownership and permissions easily on a file it describes.
|
||||
type FilePermissions interface {
|
||||
// User returns a user ID or user name
|
||||
User() string
|
||||
|
||||
// Group returns a group ID. Group names are not supported.
|
||||
Group() string
|
||||
|
||||
// Mode returns a string of file mode bits e.g. "0644"
|
||||
Mode() string
|
||||
}
|
||||
|
||||
// setFilePermissions handles configuring ownership and permissions settings
|
||||
// on a given file. It takes a map, which defines the permissions to be set.
|
||||
// All permission/ownership settings are optional. If no user or group is
|
||||
// specified, the current user/group will be used. Mode is optional, and has
|
||||
// no default (the operation is not performed if absent). User may be
|
||||
// specified by name or ID, but group may only be specified by ID.
|
||||
func setFilePermissions(path string, perms map[string]string) error {
|
||||
// on a given file. It takes a path and any struct implementing the
|
||||
// FilePermissions interface. All permission/ownership settings are optional.
|
||||
// If no user or group is specified, the current user/group will be used. Mode
|
||||
// is optional, and has no default (the operation is not performed if absent).
|
||||
// User may be specified by name or ID, but group may only be specified by ID.
|
||||
func setFilePermissions(path string, p FilePermissions) error {
|
||||
var err error
|
||||
uid, gid := os.Getuid(), os.Getgid()
|
||||
|
||||
if _, ok := perms["user"]; ok {
|
||||
if uid, err = strconv.Atoi(perms["user"]); err == nil {
|
||||
if p.User() != "" {
|
||||
if uid, err = strconv.Atoi(p.User()); err == nil {
|
||||
goto GROUP
|
||||
}
|
||||
|
||||
// Try looking up the user by name
|
||||
if u, err := user.Lookup(perms["user"]); err == nil {
|
||||
if u, err := user.Lookup(p.User()); err == nil {
|
||||
uid, _ = strconv.Atoi(u.Uid)
|
||||
goto GROUP
|
||||
}
|
||||
|
||||
return fmt.Errorf("invalid user specified: %v", perms["user"])
|
||||
return fmt.Errorf("invalid user specified: %v", p.User())
|
||||
}
|
||||
|
||||
GROUP:
|
||||
if _, ok := perms["group"]; ok {
|
||||
if gid, err = strconv.Atoi(perms["group"]); err != nil {
|
||||
return fmt.Errorf("invalid group specified: %v", perms["group"])
|
||||
if p.Group() != "" {
|
||||
if gid, err = strconv.Atoi(p.Group()); err != nil {
|
||||
return fmt.Errorf("invalid group specified: %v", p.Group())
|
||||
}
|
||||
}
|
||||
if err := os.Chown(path, uid, gid); err != nil {
|
||||
|
@ -135,10 +148,10 @@ GROUP:
|
|||
uid, gid, path, err)
|
||||
}
|
||||
|
||||
if _, ok := perms["mode"]; ok {
|
||||
mode, err := strconv.ParseUint(perms["mode"], 8, 32)
|
||||
if p.Mode() != "" {
|
||||
mode, err := strconv.ParseUint(p.Mode(), 8, 32)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid mode specified: %v", perms["mode"])
|
||||
return fmt.Errorf("invalid mode specified: %v", p.Mode())
|
||||
}
|
||||
if err := os.Chmod(path, os.FileMode(mode)); err != nil {
|
||||
return fmt.Errorf("failed setting permissions to %d on %q: %s",
|
||||
|
|
|
@ -51,22 +51,22 @@ func TestSetFilePermissions(t *testing.T) {
|
|||
defer os.Remove(path)
|
||||
|
||||
// Bad UID fails
|
||||
if err := setFilePermissions(path, map[string]string{"user": "%"}); err == nil {
|
||||
if err := setFilePermissions(path, UnixSocketConfig{Usr: "%"}); err == nil {
|
||||
t.Fatalf("should fail")
|
||||
}
|
||||
|
||||
// Bad GID fails
|
||||
if err := setFilePermissions(path, map[string]string{"group": "%"}); err == nil {
|
||||
if err := setFilePermissions(path, UnixSocketConfig{Grp: "%"}); err == nil {
|
||||
t.Fatalf("should fail")
|
||||
}
|
||||
|
||||
// Bad mode fails
|
||||
if err := setFilePermissions(path, map[string]string{"mode": "%"}); err == nil {
|
||||
if err := setFilePermissions(path, UnixSocketConfig{Perms: "%"}); err == nil {
|
||||
t.Fatalf("should fail")
|
||||
}
|
||||
|
||||
// Allows omitting user/group/mode
|
||||
if err := setFilePermissions(path, map[string]string{}); err != nil {
|
||||
if err := setFilePermissions(path, UnixSocketConfig{}); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
|
@ -74,7 +74,7 @@ func TestSetFilePermissions(t *testing.T) {
|
|||
if err := os.Chmod(path, 0700); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if err := setFilePermissions(path, map[string]string{}); err != nil {
|
||||
if err := setFilePermissions(path, UnixSocketConfig{}); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
fi, err := os.Stat(path)
|
||||
|
@ -86,7 +86,7 @@ func TestSetFilePermissions(t *testing.T) {
|
|||
}
|
||||
|
||||
// Changes mode if given
|
||||
if err := setFilePermissions(path, map[string]string{"mode": "0777"}); err != nil {
|
||||
if err := setFilePermissions(path, UnixSocketConfig{Perms: "0777"}); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
fi, err = os.Stat(path)
|
||||
|
|
Loading…
Reference in New Issue