Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 23 additions & 54 deletions cli/commands/server/server_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"context"
"fmt"
"net"
"sync"
"net/http"
"net/rpc"
"net/rpc/jsonrpc"
Expand All @@ -29,19 +28,8 @@ import (
// PipeName is the name of the named pipe used for RPC communication.
const PipeName = `\\.\pipe\fresnel_service`

var (
// PreWriteDiskHook allows executing custom setup logic prior to writing a disk.
PreWriteDiskHook = func() error { return nil }
// PostWriteDiskHook allows executing custom teardown logic after writing a disk.
PostWriteDiskHook = func() {}
// StartupHook allows executing custom logic when the server service starts.
StartupHook = func() {}
)

// FresnelService is the RPC service exposed over the named pipe.
type FresnelService struct {
writeMu sync.Mutex
}
type FresnelService struct{}

// WriteRequest represents a request to write an image to disk.
type WriteRequest struct {
Expand All @@ -67,15 +55,6 @@ func (s *FresnelService) WriteDisk(req *WriteRequest, resp *WriteResponse) error
resp.Error = "Access denied: Could not securely identify the calling user."
return nil
}
s.writeMu.Lock()
defer s.writeMu.Unlock()

if err := PreWriteDiskHook(); err != nil {
resp.Error = fmt.Sprintf("pre-write hook error: %v", err)
return nil
}
defer PostWriteDiskHook()

conf, err := config.New(req.Cleanup, req.Warning, req.Eject, req.FFU, req.Update, req.Devices, req.Distro, req.Track, req.ConfTrack, req.SeedServer)
if err != nil {
resp.Error = fmt.Sprintf("config error: %v", err)
Expand All @@ -92,15 +71,14 @@ func (s *FresnelService) WriteDisk(req *WriteRequest, resp *WriteResponse) error

if req.SSOCookie != "" {
tlsClient, err := sso.TLSClient(nil, nil)
if err != nil {
deck.Errorf("TLSClient error: %v", err)
}
if err == nil {
client := &ssoHTTPClient{
cookie: req.SSOCookie,
client: tlsClient,
}
i.SetHTTPClient(client)
} else {
deck.Errorf("TLSClient error: %v", err)
}
}

Expand Down Expand Up @@ -166,8 +144,6 @@ func (m *tokenCodec) Close() error {
func (m *fresnelSvc) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (svcSpecificEC bool, exitCode uint32) {
changes <- svc.Status{State: svc.StartPending}

StartupHook()

service := new(FresnelService)
rpc.Register(service)

Expand All @@ -190,7 +166,26 @@ func (m *fresnelSvc) Execute(args []string, r <-chan svc.ChangeRequest, changes
if err != nil {
return
}
clientToken := getClientToken(conn)
var clientToken windows.Token

// Extract the raw Windows pipe handle using reflection.
fd := getPipeHandle(conn)
if fd != 0 {
runtime.LockOSThread()
// Impersonate the pipe client.
if err := installer.ImpersonateNamedPipeClient(fd); err == nil {
// Grab a copy of their token.
if err := windows.OpenThreadToken(windows.CurrentThread(), windows.TOKEN_ALL_ACCESS, true, &clientToken); err != nil {
deck.Errorf("Failed to open thread token: %v", err)
}
windows.RevertToSelf()
} else {
deck.Errorf("Failed to impersonate pipe client: %v", err)
}
runtime.UnlockOSThread()
} else {
deck.Errorf("Could not extract raw pipe handle from connection")
}
// Serve the RPC connection using our injecting codec.
codec := &tokenCodec{
ServerCodec: jsonrpc.NewServerCodec(conn),
Expand Down Expand Up @@ -240,32 +235,6 @@ func getPipeHandle(conn net.Conn) windows.Handle {
return 0
}

// getClientToken impersonates the connected pipe client to retrieve their Windows token.
func getClientToken(conn net.Conn) windows.Token {
fd := getPipeHandle(conn)
if fd == 0 {
deck.Errorf("Could not extract raw pipe handle from connection")
return 0
}

runtime.LockOSThread()
defer runtime.UnlockOSThread()

if err := installer.ImpersonateNamedPipeClient(fd); err != nil {
deck.Errorf("Failed to impersonate pipe client: %v", err)
return 0
}
defer windows.RevertToSelf()

var clientToken windows.Token
if err := windows.OpenThreadToken(windows.CurrentThread(), windows.TOKEN_ALL_ACCESS, true, &clientToken); err != nil {
deck.Errorf("Failed to open thread token: %v", err)
return 0
}

return clientToken
}

type ssoHTTPClient struct {
cookie string
client *http.Client
Expand Down
3 changes: 2 additions & 1 deletion cli/config/config_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ var (
// IsElevatedCmd injects the command to determine the elevation state of the
// user context.
IsElevatedCmd = isAdmin
funcUSBPermissions = HasWritePermissions

denyWriteRegKey = `SOFTWARE\Policies\Microsoft\Windows\RemovableStorageDevices\{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}`
)
Expand Down Expand Up @@ -68,7 +69,7 @@ func isAdmin() (bool, error) {
}

// HasWritePermissions determines if the local machine is blocked from writing to removable media via policy.
var HasWritePermissions = func() error {
func HasWritePermissions() error {
v, err := registry.GetInteger(denyWriteRegKey, "Deny_Write")
if err != nil && err != registry.ErrNotExist {
return err
Expand Down
Loading