mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-11-04 00:11:04 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			266 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			266 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package mssql
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"strings"
 | 
						|
	"syscall"
 | 
						|
	"unsafe"
 | 
						|
)
 | 
						|
 | 
						|
var (
 | 
						|
	secur32_dll           = syscall.NewLazyDLL("secur32.dll")
 | 
						|
	initSecurityInterface = secur32_dll.NewProc("InitSecurityInterfaceW")
 | 
						|
	sec_fn                *SecurityFunctionTable
 | 
						|
)
 | 
						|
 | 
						|
func init() {
 | 
						|
	ptr, _, _ := initSecurityInterface.Call()
 | 
						|
	sec_fn = (*SecurityFunctionTable)(unsafe.Pointer(ptr))
 | 
						|
}
 | 
						|
 | 
						|
const (
 | 
						|
	SEC_E_OK                        = 0
 | 
						|
	SECPKG_CRED_OUTBOUND            = 2
 | 
						|
	SEC_WINNT_AUTH_IDENTITY_UNICODE = 2
 | 
						|
	ISC_REQ_DELEGATE                = 0x00000001
 | 
						|
	ISC_REQ_REPLAY_DETECT           = 0x00000004
 | 
						|
	ISC_REQ_SEQUENCE_DETECT         = 0x00000008
 | 
						|
	ISC_REQ_CONFIDENTIALITY         = 0x00000010
 | 
						|
	ISC_REQ_CONNECTION              = 0x00000800
 | 
						|
	SECURITY_NETWORK_DREP           = 0
 | 
						|
	SEC_I_CONTINUE_NEEDED           = 0x00090312
 | 
						|
	SEC_I_COMPLETE_NEEDED           = 0x00090313
 | 
						|
	SEC_I_COMPLETE_AND_CONTINUE     = 0x00090314
 | 
						|
	SECBUFFER_VERSION               = 0
 | 
						|
	SECBUFFER_TOKEN                 = 2
 | 
						|
	NTLMBUF_LEN                     = 12000
 | 
						|
)
 | 
						|
 | 
						|
const ISC_REQ = ISC_REQ_CONFIDENTIALITY |
 | 
						|
	ISC_REQ_REPLAY_DETECT |
 | 
						|
	ISC_REQ_SEQUENCE_DETECT |
 | 
						|
	ISC_REQ_CONNECTION |
 | 
						|
	ISC_REQ_DELEGATE
 | 
						|
 | 
						|
type SecurityFunctionTable struct {
 | 
						|
	dwVersion                  uint32
 | 
						|
	EnumerateSecurityPackages  uintptr
 | 
						|
	QueryCredentialsAttributes uintptr
 | 
						|
	AcquireCredentialsHandle   uintptr
 | 
						|
	FreeCredentialsHandle      uintptr
 | 
						|
	Reserved2                  uintptr
 | 
						|
	InitializeSecurityContext  uintptr
 | 
						|
	AcceptSecurityContext      uintptr
 | 
						|
	CompleteAuthToken          uintptr
 | 
						|
	DeleteSecurityContext      uintptr
 | 
						|
	ApplyControlToken          uintptr
 | 
						|
	QueryContextAttributes     uintptr
 | 
						|
	ImpersonateSecurityContext uintptr
 | 
						|
	RevertSecurityContext      uintptr
 | 
						|
	MakeSignature              uintptr
 | 
						|
	VerifySignature            uintptr
 | 
						|
	FreeContextBuffer          uintptr
 | 
						|
	QuerySecurityPackageInfo   uintptr
 | 
						|
	Reserved3                  uintptr
 | 
						|
	Reserved4                  uintptr
 | 
						|
	Reserved5                  uintptr
 | 
						|
	Reserved6                  uintptr
 | 
						|
	Reserved7                  uintptr
 | 
						|
	Reserved8                  uintptr
 | 
						|
	QuerySecurityContextToken  uintptr
 | 
						|
	EncryptMessage             uintptr
 | 
						|
	DecryptMessage             uintptr
 | 
						|
}
 | 
						|
 | 
						|
type SEC_WINNT_AUTH_IDENTITY struct {
 | 
						|
	User           *uint16
 | 
						|
	UserLength     uint32
 | 
						|
	Domain         *uint16
 | 
						|
	DomainLength   uint32
 | 
						|
	Password       *uint16
 | 
						|
	PasswordLength uint32
 | 
						|
	Flags          uint32
 | 
						|
}
 | 
						|
 | 
						|
type TimeStamp struct {
 | 
						|
	LowPart  uint32
 | 
						|
	HighPart int32
 | 
						|
}
 | 
						|
 | 
						|
type SecHandle struct {
 | 
						|
	dwLower uintptr
 | 
						|
	dwUpper uintptr
 | 
						|
}
 | 
						|
 | 
						|
type SecBuffer struct {
 | 
						|
	cbBuffer   uint32
 | 
						|
	BufferType uint32
 | 
						|
	pvBuffer   *byte
 | 
						|
}
 | 
						|
 | 
						|
type SecBufferDesc struct {
 | 
						|
	ulVersion uint32
 | 
						|
	cBuffers  uint32
 | 
						|
	pBuffers  *SecBuffer
 | 
						|
}
 | 
						|
 | 
						|
type SSPIAuth struct {
 | 
						|
	Domain   string
 | 
						|
	UserName string
 | 
						|
	Password string
 | 
						|
	Service  string
 | 
						|
	cred     SecHandle
 | 
						|
	ctxt     SecHandle
 | 
						|
}
 | 
						|
 | 
						|
func getAuth(user, password, service, workstation string) (auth, bool) {
 | 
						|
	if user == "" {
 | 
						|
		return &SSPIAuth{Service: service}, true
 | 
						|
	}
 | 
						|
	if !strings.ContainsRune(user, '\\') {
 | 
						|
		return nil, false
 | 
						|
	}
 | 
						|
	domain_user := strings.SplitN(user, "\\", 2)
 | 
						|
	return &SSPIAuth{
 | 
						|
		Domain:   domain_user[0],
 | 
						|
		UserName: domain_user[1],
 | 
						|
		Password: password,
 | 
						|
		Service:  service,
 | 
						|
	}, true
 | 
						|
}
 | 
						|
 | 
						|
func (auth *SSPIAuth) InitialBytes() ([]byte, error) {
 | 
						|
	var identity *SEC_WINNT_AUTH_IDENTITY
 | 
						|
	if auth.UserName != "" {
 | 
						|
		identity = &SEC_WINNT_AUTH_IDENTITY{
 | 
						|
			Flags:          SEC_WINNT_AUTH_IDENTITY_UNICODE,
 | 
						|
			Password:       syscall.StringToUTF16Ptr(auth.Password),
 | 
						|
			PasswordLength: uint32(len(auth.Password)),
 | 
						|
			Domain:         syscall.StringToUTF16Ptr(auth.Domain),
 | 
						|
			DomainLength:   uint32(len(auth.Domain)),
 | 
						|
			User:           syscall.StringToUTF16Ptr(auth.UserName),
 | 
						|
			UserLength:     uint32(len(auth.UserName)),
 | 
						|
		}
 | 
						|
	}
 | 
						|
	var ts TimeStamp
 | 
						|
	sec_ok, _, _ := syscall.Syscall9(sec_fn.AcquireCredentialsHandle,
 | 
						|
		9,
 | 
						|
		0,
 | 
						|
		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("Negotiate"))),
 | 
						|
		SECPKG_CRED_OUTBOUND,
 | 
						|
		0,
 | 
						|
		uintptr(unsafe.Pointer(identity)),
 | 
						|
		0,
 | 
						|
		0,
 | 
						|
		uintptr(unsafe.Pointer(&auth.cred)),
 | 
						|
		uintptr(unsafe.Pointer(&ts)))
 | 
						|
	if sec_ok != SEC_E_OK {
 | 
						|
		return nil, fmt.Errorf("AcquireCredentialsHandle failed %x", sec_ok)
 | 
						|
	}
 | 
						|
 | 
						|
	var buf SecBuffer
 | 
						|
	var desc SecBufferDesc
 | 
						|
	desc.ulVersion = SECBUFFER_VERSION
 | 
						|
	desc.cBuffers = 1
 | 
						|
	desc.pBuffers = &buf
 | 
						|
 | 
						|
	outbuf := make([]byte, NTLMBUF_LEN)
 | 
						|
	buf.cbBuffer = NTLMBUF_LEN
 | 
						|
	buf.BufferType = SECBUFFER_TOKEN
 | 
						|
	buf.pvBuffer = &outbuf[0]
 | 
						|
 | 
						|
	var attrs uint32
 | 
						|
	sec_ok, _, _ = syscall.Syscall12(sec_fn.InitializeSecurityContext,
 | 
						|
		12,
 | 
						|
		uintptr(unsafe.Pointer(&auth.cred)),
 | 
						|
		0,
 | 
						|
		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(auth.Service))),
 | 
						|
		ISC_REQ,
 | 
						|
		0,
 | 
						|
		SECURITY_NETWORK_DREP,
 | 
						|
		0,
 | 
						|
		0,
 | 
						|
		uintptr(unsafe.Pointer(&auth.ctxt)),
 | 
						|
		uintptr(unsafe.Pointer(&desc)),
 | 
						|
		uintptr(unsafe.Pointer(&attrs)),
 | 
						|
		uintptr(unsafe.Pointer(&ts)))
 | 
						|
	if sec_ok == SEC_I_COMPLETE_AND_CONTINUE ||
 | 
						|
		sec_ok == SEC_I_COMPLETE_NEEDED {
 | 
						|
		syscall.Syscall6(sec_fn.CompleteAuthToken,
 | 
						|
			2,
 | 
						|
			uintptr(unsafe.Pointer(&auth.ctxt)),
 | 
						|
			uintptr(unsafe.Pointer(&desc)),
 | 
						|
			0, 0, 0, 0)
 | 
						|
	} else if sec_ok != SEC_E_OK &&
 | 
						|
		sec_ok != SEC_I_CONTINUE_NEEDED {
 | 
						|
		syscall.Syscall6(sec_fn.FreeCredentialsHandle,
 | 
						|
			1,
 | 
						|
			uintptr(unsafe.Pointer(&auth.cred)),
 | 
						|
			0, 0, 0, 0, 0)
 | 
						|
		return nil, fmt.Errorf("InitialBytes InitializeSecurityContext failed %x", sec_ok)
 | 
						|
	}
 | 
						|
	return outbuf[:buf.cbBuffer], nil
 | 
						|
}
 | 
						|
 | 
						|
func (auth *SSPIAuth) NextBytes(bytes []byte) ([]byte, error) {
 | 
						|
	var in_buf, out_buf SecBuffer
 | 
						|
	var in_desc, out_desc SecBufferDesc
 | 
						|
 | 
						|
	in_desc.ulVersion = SECBUFFER_VERSION
 | 
						|
	in_desc.cBuffers = 1
 | 
						|
	in_desc.pBuffers = &in_buf
 | 
						|
 | 
						|
	out_desc.ulVersion = SECBUFFER_VERSION
 | 
						|
	out_desc.cBuffers = 1
 | 
						|
	out_desc.pBuffers = &out_buf
 | 
						|
 | 
						|
	in_buf.BufferType = SECBUFFER_TOKEN
 | 
						|
	in_buf.pvBuffer = &bytes[0]
 | 
						|
	in_buf.cbBuffer = uint32(len(bytes))
 | 
						|
 | 
						|
	outbuf := make([]byte, NTLMBUF_LEN)
 | 
						|
	out_buf.BufferType = SECBUFFER_TOKEN
 | 
						|
	out_buf.pvBuffer = &outbuf[0]
 | 
						|
	out_buf.cbBuffer = NTLMBUF_LEN
 | 
						|
 | 
						|
	var attrs uint32
 | 
						|
	var ts TimeStamp
 | 
						|
	sec_ok, _, _ := syscall.Syscall12(sec_fn.InitializeSecurityContext,
 | 
						|
		12,
 | 
						|
		uintptr(unsafe.Pointer(&auth.cred)),
 | 
						|
		uintptr(unsafe.Pointer(&auth.ctxt)),
 | 
						|
		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(auth.Service))),
 | 
						|
		ISC_REQ,
 | 
						|
		0,
 | 
						|
		SECURITY_NETWORK_DREP,
 | 
						|
		uintptr(unsafe.Pointer(&in_desc)),
 | 
						|
		0,
 | 
						|
		uintptr(unsafe.Pointer(&auth.ctxt)),
 | 
						|
		uintptr(unsafe.Pointer(&out_desc)),
 | 
						|
		uintptr(unsafe.Pointer(&attrs)),
 | 
						|
		uintptr(unsafe.Pointer(&ts)))
 | 
						|
	if sec_ok == SEC_I_COMPLETE_AND_CONTINUE ||
 | 
						|
		sec_ok == SEC_I_COMPLETE_NEEDED {
 | 
						|
		syscall.Syscall6(sec_fn.CompleteAuthToken,
 | 
						|
			2,
 | 
						|
			uintptr(unsafe.Pointer(&auth.ctxt)),
 | 
						|
			uintptr(unsafe.Pointer(&out_desc)),
 | 
						|
			0, 0, 0, 0)
 | 
						|
	} else if sec_ok != SEC_E_OK &&
 | 
						|
		sec_ok != SEC_I_CONTINUE_NEEDED {
 | 
						|
		return nil, fmt.Errorf("NextBytes InitializeSecurityContext failed %x", sec_ok)
 | 
						|
	}
 | 
						|
 | 
						|
	return outbuf[:out_buf.cbBuffer], nil
 | 
						|
}
 | 
						|
 | 
						|
func (auth *SSPIAuth) Free() {
 | 
						|
	syscall.Syscall6(sec_fn.DeleteSecurityContext,
 | 
						|
		1,
 | 
						|
		uintptr(unsafe.Pointer(&auth.ctxt)),
 | 
						|
		0, 0, 0, 0, 0)
 | 
						|
	syscall.Syscall6(sec_fn.FreeCredentialsHandle,
 | 
						|
		1,
 | 
						|
		uintptr(unsafe.Pointer(&auth.cred)),
 | 
						|
		0, 0, 0, 0, 0)
 | 
						|
}
 |