mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-27 06:49:07 +01:00
Add an optional --allow-group flag restricting the daemon sockets to a group
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
//go:build windows
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// accountName returns the name the local system knows a SID by.
|
||||
func accountName(sid string) (string, error) {
|
||||
parsed, err := windows.StringToSid(sid)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
account, domain, _, err := parsed.LookupAccount("")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if domain == "" {
|
||||
return account, nil
|
||||
}
|
||||
return domain + `\` + account, nil
|
||||
}
|
||||
|
||||
// sidAdministrators is BUILTIN\Administrators, a group present on every
|
||||
// Windows install, localised name and all.
|
||||
const sidAdministrators = "S-1-5-32-544"
|
||||
|
||||
// testAllowGroupPrincipal is a principal that resolves on any Windows host.
|
||||
const testAllowGroupPrincipal = "sid:" + sidAdministrators
|
||||
|
||||
func TestResolveAllowGroup_SID(t *testing.T) {
|
||||
for _, value := range []string{sidAdministrators, "sid:" + sidAdministrators, strings.ToLower(sidAdministrators)} {
|
||||
t.Run(value, func(t *testing.T) {
|
||||
principal, err := resolveAllowGroup(value)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "sid:"+sidAdministrators, principal)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveAllowGroup_ByName(t *testing.T) {
|
||||
// The well-known SID resolves to whatever the account is called in this
|
||||
// install's language, and that name must resolve back to the same SID.
|
||||
name, err := accountName(sidAdministrators)
|
||||
require.NoError(t, err)
|
||||
|
||||
principal, err := resolveAllowGroup(name)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "sid:"+sidAdministrators, principal)
|
||||
}
|
||||
|
||||
func TestResolveAllowGroup_Rejects(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
value string
|
||||
}{
|
||||
{name: "unix principal", value: "gid:0"},
|
||||
{name: "unknown kind", value: "user:alice"},
|
||||
{name: "malformed SID", value: "sid:S-1-not-a-sid"},
|
||||
{name: "unknown account", value: "no-such-account-08b1f0c4"},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
_, err := resolveAllowGroup(tc.value)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// A pipe descriptor holds one ACE per principal, so any number is enforceable.
|
||||
func TestCheckAllowGroupSet_AcceptsAny(t *testing.T) {
|
||||
assert.NoError(t, checkAllowGroupSet(nil))
|
||||
assert.NoError(t, checkAllowGroupSet([]string{"sid:" + sidAdministrators, "sid:S-1-5-18"}))
|
||||
}
|
||||
|
||||
func TestAllowedPipeSDDL(t *testing.T) {
|
||||
t.Run("no principals leaves the pipe open", func(t *testing.T) {
|
||||
sddl, err := allowedPipeSDDL(nil)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, sddl, "(A;;GA;;;WD)", "an unconfigured pipe stays open to every local caller")
|
||||
})
|
||||
|
||||
t.Run("a principal replaces the Everyone ACE", func(t *testing.T) {
|
||||
sddl, err := allowedPipeSDDL([]string{"sid:S-1-5-21-1-2-3-1001"})
|
||||
require.NoError(t, err)
|
||||
assert.NotContains(t, sddl, "(A;;GA;;;WD)")
|
||||
assert.Contains(t, sddl, "(A;;GA;;;S-1-5-21-1-2-3-1001)")
|
||||
assert.Contains(t, sddl, "(A;;GA;;;SY)", "LocalSystem runs the daemon")
|
||||
assert.Contains(t, sddl, "(A;;GA;;;BA)", "an elevated caller is never locked out")
|
||||
assert.True(t, strings.HasPrefix(sddl, "D:P"), "the DACL must stay protected: %s", sddl)
|
||||
})
|
||||
|
||||
t.Run("a principal of another platform is refused", func(t *testing.T) {
|
||||
_, err := allowedPipeSDDL([]string{"gid:0"})
|
||||
require.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
// TestListenNamedPipe_RestrictedDescriptor covers the descriptor reaching the
|
||||
// listener, which is the only part of the restriction that cannot be asserted
|
||||
// from allowedPipeSDDL alone.
|
||||
func TestListenNamedPipe_RestrictedDescriptor(t *testing.T) {
|
||||
listener, path, err := listenNamedPipe("netbird-test-"+t.Name(), []string{"sid:" + sidAdministrators})
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { assert.NoError(t, listener.Close()) })
|
||||
assert.NotEmpty(t, path)
|
||||
}
|
||||
Reference in New Issue
Block a user