mirror of https://github.com/gogits/gogs.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
266 lines
6.8 KiB
266 lines
6.8 KiB
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) |
|
}
|
|
|