mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-12 17:59:06 +02:00
97 lines
3.4 KiB
Go
97 lines
3.4 KiB
Go
//go:build windows
|
|
|
|
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
|
|
"golang.org/x/sys/windows"
|
|
|
|
"github.com/netbirdio/netbird/client/internal/ipcauth"
|
|
)
|
|
|
|
// resolveAllowGroup resolves one --allow-group value to a "sid:<SID>"
|
|
// principal. A value already in SID form, with or without the prefix, is
|
|
// validated and canonicalised; anything else is an account name resolved with
|
|
// LookupAccountName, which goes through LSA and so resolves domain groups on a
|
|
// joined machine as readily as local ones.
|
|
//
|
|
// Both a group and a user account are accepted. The DACL grants a SID without
|
|
// caring which it is, and an administrator restricting the daemon to a single
|
|
// service account should not have to create a group for it.
|
|
func resolveAllowGroup(value string) (ipcauth.Principal, error) {
|
|
principal, typed, err := typedPrincipal(value, ipcauth.KindSID)
|
|
if err != nil {
|
|
return ipcauth.Principal{}, err
|
|
}
|
|
if typed {
|
|
return sidPrincipal(principal.Value)
|
|
}
|
|
|
|
if _, err := windows.StringToSid(value); err == nil {
|
|
return sidPrincipal(value)
|
|
}
|
|
|
|
sid, _, _, err := windows.LookupSID("", value)
|
|
if err != nil {
|
|
return ipcauth.Principal{}, fmt.Errorf("look up account: %w", err)
|
|
}
|
|
return sidPrincipal(sid.String())
|
|
}
|
|
|
|
// checkAllowGroupSet accepts any number of principals: a pipe descriptor holds
|
|
// one ACE per principal.
|
|
func checkAllowGroupSet([]string) error { return nil }
|
|
|
|
// applySocketAccess applies the restriction to a Unix socket, which on Windows
|
|
// it cannot: AF_UNIX sockets there carry no mode, and the daemon has no way to
|
|
// keep another local process off one. Serving it unrestricted would be the
|
|
// fail-open this flag exists to prevent, so a configured restriction is an
|
|
// error instead.
|
|
//
|
|
// The pipe transport is unaffected: its access lives in the security descriptor
|
|
// it is created with, and restrict never routes a named pipe here.
|
|
func applySocketAccess(path string, principals []string) error {
|
|
if len(principals) == 0 {
|
|
return nil
|
|
}
|
|
return fmt.Errorf("cannot restrict the unix socket %s on windows: it carries no access mode, serve the daemon on npipe:// instead", path)
|
|
}
|
|
|
|
// listenUnixPrivate binds a Unix socket. Windows has no umask and no mode on
|
|
// these sockets, so binding is all there is to do; a configured restriction is
|
|
// refused by applySocketAccess before the daemon serves.
|
|
func listenUnixPrivate(address string, _ []string) (net.Listener, error) {
|
|
return net.Listen("unix", address)
|
|
}
|
|
|
|
// allowedPipeSDDL renders the security descriptor for the daemon control pipe.
|
|
// An empty principal list yields the descriptor that lets any local caller
|
|
// connect.
|
|
func allowedPipeSDDL(principals []string) (string, error) {
|
|
sids := make([]string, 0, len(principals))
|
|
for _, value := range principals {
|
|
principal, err := principalOfKind(value, ipcauth.KindSID)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
sids = append(sids, principal.Value)
|
|
}
|
|
return ipcauth.RestrictedPipeSDDL(sids), nil
|
|
}
|
|
|
|
// sidPrincipal validates a SID and renders it in its canonical form, so that
|
|
// two spellings of the same SID produce one principal.
|
|
func sidPrincipal(value string) (ipcauth.Principal, error) {
|
|
sid, err := windows.StringToSid(value)
|
|
if err != nil {
|
|
return ipcauth.Principal{}, fmt.Errorf("parse SID %q: %w", value, err)
|
|
}
|
|
principal, ok := ipcauth.ParsePrincipal(ipcauth.SIDPrincipal(sid.String()))
|
|
if !ok {
|
|
return ipcauth.Principal{}, fmt.Errorf("build sid principal for %q", sid.String())
|
|
}
|
|
return principal, nil
|
|
}
|