net/dns, paths, util/winutil: change net/dns/windowsManager NRPT management to support more than 50 domains.

AFAICT this isn't documented on MSDN, but based on the issue referenced below,
NRPT rules are not working when a rule specifies > 50 domains.

This patch modifies our NRPT rule generator to split the list of domains
into chunks as necessary, and write a separate rule for each chunk.

For compatibility reasons, we continue to use the hard-coded rule ID, but
as additional rules are required, we generate new GUIDs. Those GUIDs are
stored under the Tailscale registry path so that we know which rules are ours.

I made some changes to winutils to add additional helper functions in support
of both the code and its test: I added additional registry accessors, and also
moved some token accessors from paths to util/winutil.

Fixes https://github.com/tailscale/coral/issues/63

Signed-off-by: Aaron Klotz <aaron@tailscale.com>
This commit is contained in:
Aaron Klotz
2022-05-25 15:51:54 -06:00
parent c16271fb46
commit b005b79236
6 changed files with 466 additions and 131 deletions

View File

@@ -8,67 +8,11 @@ import (
"os"
"path/filepath"
"strings"
"unsafe"
"golang.org/x/sys/windows"
"tailscale.com/util/winutil"
)
func getTokenInfo(token windows.Token, infoClass uint32) ([]byte, error) {
var desiredLen uint32
err := windows.GetTokenInformation(token, infoClass, nil, 0, &desiredLen)
if err != nil && err != windows.ERROR_INSUFFICIENT_BUFFER {
return nil, err
}
buf := make([]byte, desiredLen)
actualLen := desiredLen
err = windows.GetTokenInformation(token, infoClass, &buf[0], desiredLen, &actualLen)
return buf, err
}
func getTokenUserInfo(token windows.Token) (*windows.Tokenuser, error) {
buf, err := getTokenInfo(token, windows.TokenUser)
if err != nil {
return nil, err
}
return (*windows.Tokenuser)(unsafe.Pointer(&buf[0])), nil
}
func getTokenPrimaryGroupInfo(token windows.Token) (*windows.Tokenprimarygroup, error) {
buf, err := getTokenInfo(token, windows.TokenPrimaryGroup)
if err != nil {
return nil, err
}
return (*windows.Tokenprimarygroup)(unsafe.Pointer(&buf[0])), nil
}
type userSids struct {
User *windows.SID
PrimaryGroup *windows.SID
}
func getCurrentUserSids() (*userSids, error) {
token, err := windows.OpenCurrentProcessToken()
if err != nil {
return nil, err
}
defer token.Close()
userInfo, err := getTokenUserInfo(token)
if err != nil {
return nil, err
}
primaryGroup, err := getTokenPrimaryGroupInfo(token)
if err != nil {
return nil, err
}
return &userSids{userInfo.User.Sid, primaryGroup.PrimaryGroup}, nil
}
// ensureStateDirPerms applies a restrictive ACL to the directory specified by dirPath.
// It sets the following security attributes on the directory:
// Owner: The user for the current process;
@@ -93,7 +37,7 @@ func ensureStateDirPerms(dirPath string) error {
}
// We need the info for our current user as SIDs
sids, err := getCurrentUserSids()
sids, err := winutil.GetCurrentUserSIDs()
if err != nil {
return err
}