123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267 |
- 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)
- }
|