aboutsummaryrefslogblamecommitdiffstatshomepage
path: root/tunnel/firewall/helpers.go
blob: 237a5f57250e1467ac96d1cf1886ccf6a570d6e8 (plain) (tree)
1
2
3
4
5
6
7
8
9







                                                         
                     
             
            
            

                 
                

                                  

 


                                                                          
                                   




                                              
                                   




                                              
                                   







                                                                                      
                                        



                                                                      
                                        







                                            
                                             

                                  
                                       

         







                                                                                
         
                                                                         
 

                                                                    
                                                              
                       







                                                
                                          


                                                                                                                        


                                                                                 
                                                                                                                                                                     

                                














                                                                

                                
                                                                                               


                                        


                        
                                                       









                                                                  

                                                                           


                                        
                         
 










                                                                  
 
/* SPDX-License-Identifier: MIT
 *
 * Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
 */

package firewall

import (
	"crypto/rand"
	"fmt"
	"io"
	"os"
	"runtime"
	"syscall"
	"unsafe"

	"golang.org/x/sys/windows"
)

func runTransaction(session uintptr, operation wfpObjectInstaller) error {
	err := fwpmTransactionBegin0(session, 0)
	if err != nil {
		return wrapErr(err)
	}

	err = operation(session)
	if err != nil {
		fwpmTransactionAbort0(session)
		return wrapErr(err)
	}

	err = fwpmTransactionCommit0(session)
	if err != nil {
		fwpmTransactionAbort0(session)
		return wrapErr(err)
	}

	return nil
}

func createWtFwpmDisplayData0(name, description string) (*wtFwpmDisplayData0, error) {
	namePtr, err := windows.UTF16PtrFromString(name)
	if err != nil {
		return nil, wrapErr(err)
	}

	descriptionPtr, err := windows.UTF16PtrFromString(description)
	if err != nil {
		return nil, wrapErr(err)
	}

	return &wtFwpmDisplayData0{
		name:        namePtr,
		description: descriptionPtr,
	}, nil
}

func filterWeight(weight uint8) wtFwpValue0 {
	return wtFwpValue0{
		_type: cFWP_UINT8,
		value: uintptr(weight),
	}
}

func wrapErr(err error) error {
	if _, ok := err.(syscall.Errno); !ok {
		return err
	}
	_, file, line, ok := runtime.Caller(1)
	if !ok {
		return fmt.Errorf("Firewall error at unknown location: %v", err)
	}
	return fmt.Errorf("Firewall error at %s:%d: %v", file, line, err)
}

func getCurrentProcessSecurityDescriptor() (*wtFwpByteBlob, error) {
	processToken, err := windows.OpenCurrentProcessToken()
	if err != nil {
		return nil, wrapErr(err)
	}
	defer processToken.Close()
	gs, err := processToken.GetTokenGroups()
	if err != nil {
		return nil, wrapErr(err)
	}
	var sid *windows.SID
	for _, g := range gs.AllGroups() {
		if g.Attributes != windows.SE_GROUP_ENABLED|windows.SE_GROUP_ENABLED_BY_DEFAULT|windows.SE_GROUP_OWNER {
			continue
		}
		// We could be checking != 6, but hopefully Microsoft will update
		// RtlCreateServiceSid to use SHA2, which will then likely bump
		// this up. So instead just roll with a minimum.
		if !g.Sid.IsValid() || g.Sid.IdentifierAuthority() != windows.SECURITY_NT_AUTHORITY || g.Sid.SubAuthorityCount() < 6 || g.Sid.SubAuthority(0) != 80 {
			continue
		}
		sid = g.Sid
		break
	}
	if sid == nil {
		return nil, wrapErr(windows.ERROR_NO_SUCH_GROUP)
	}

	access := &wtExplicitAccess{
		accessPermissions: cFWP_ACTRL_MATCH_FILTER,
		accessMode:        cGRANT_ACCESS,
		trustee: wtTrustee{
			trusteeForm: cTRUSTEE_IS_SID,
			trusteeType: cTRUSTEE_IS_GROUP,
			sid:         sid,
		},
	}
	blob := &wtFwpByteBlob{}
	err = buildSecurityDescriptor(nil, nil, 1, access, 0, nil, nil, &blob.size, &blob.data)
	if err != nil {
		return nil, wrapErr(err)
	}
	return blob, nil
}

func getCurrentProcessAppID() (*wtFwpByteBlob, error) {
	currentFile, err := os.Executable()
	if err != nil {
		return nil, wrapErr(err)
	}

	curFilePtr, err := windows.UTF16PtrFromString(currentFile)
	if err != nil {
		return nil, wrapErr(err)
	}

	var appID *wtFwpByteBlob
	err = fwpmGetAppIdFromFileName0(curFilePtr, unsafe.Pointer(&appID))
	if err != nil {
		return nil, wrapErr(err)
	}
	return appID, nil
}

func randGUID() (windows.GUID, error) {
	guid := windows.GUID{}
	n, err := rand.Read((*[16]byte)(unsafe.Pointer(&guid))[:])
	if err != nil {
		return guid, err
	}
	if n != 16 {
		return guid, io.ErrShortBuffer
	}
	return guid, nil
}