| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 | package mssqlimport (	"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_DELEGATEtype 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)}
 |