sspi_windows.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. package mssql
  2. import (
  3. "fmt"
  4. "strings"
  5. "syscall"
  6. "unsafe"
  7. )
  8. var (
  9. secur32_dll = syscall.NewLazyDLL("secur32.dll")
  10. initSecurityInterface = secur32_dll.NewProc("InitSecurityInterfaceW")
  11. sec_fn *SecurityFunctionTable
  12. )
  13. func init() {
  14. ptr, _, _ := initSecurityInterface.Call()
  15. sec_fn = (*SecurityFunctionTable)(unsafe.Pointer(ptr))
  16. }
  17. const (
  18. SEC_E_OK = 0
  19. SECPKG_CRED_OUTBOUND = 2
  20. SEC_WINNT_AUTH_IDENTITY_UNICODE = 2
  21. ISC_REQ_DELEGATE = 0x00000001
  22. ISC_REQ_REPLAY_DETECT = 0x00000004
  23. ISC_REQ_SEQUENCE_DETECT = 0x00000008
  24. ISC_REQ_CONFIDENTIALITY = 0x00000010
  25. ISC_REQ_CONNECTION = 0x00000800
  26. SECURITY_NETWORK_DREP = 0
  27. SEC_I_CONTINUE_NEEDED = 0x00090312
  28. SEC_I_COMPLETE_NEEDED = 0x00090313
  29. SEC_I_COMPLETE_AND_CONTINUE = 0x00090314
  30. SECBUFFER_VERSION = 0
  31. SECBUFFER_TOKEN = 2
  32. NTLMBUF_LEN = 12000
  33. )
  34. const ISC_REQ = ISC_REQ_CONFIDENTIALITY |
  35. ISC_REQ_REPLAY_DETECT |
  36. ISC_REQ_SEQUENCE_DETECT |
  37. ISC_REQ_CONNECTION |
  38. ISC_REQ_DELEGATE
  39. type SecurityFunctionTable struct {
  40. dwVersion uint32
  41. EnumerateSecurityPackages uintptr
  42. QueryCredentialsAttributes uintptr
  43. AcquireCredentialsHandle uintptr
  44. FreeCredentialsHandle uintptr
  45. Reserved2 uintptr
  46. InitializeSecurityContext uintptr
  47. AcceptSecurityContext uintptr
  48. CompleteAuthToken uintptr
  49. DeleteSecurityContext uintptr
  50. ApplyControlToken uintptr
  51. QueryContextAttributes uintptr
  52. ImpersonateSecurityContext uintptr
  53. RevertSecurityContext uintptr
  54. MakeSignature uintptr
  55. VerifySignature uintptr
  56. FreeContextBuffer uintptr
  57. QuerySecurityPackageInfo uintptr
  58. Reserved3 uintptr
  59. Reserved4 uintptr
  60. Reserved5 uintptr
  61. Reserved6 uintptr
  62. Reserved7 uintptr
  63. Reserved8 uintptr
  64. QuerySecurityContextToken uintptr
  65. EncryptMessage uintptr
  66. DecryptMessage uintptr
  67. }
  68. type SEC_WINNT_AUTH_IDENTITY struct {
  69. User *uint16
  70. UserLength uint32
  71. Domain *uint16
  72. DomainLength uint32
  73. Password *uint16
  74. PasswordLength uint32
  75. Flags uint32
  76. }
  77. type TimeStamp struct {
  78. LowPart uint32
  79. HighPart int32
  80. }
  81. type SecHandle struct {
  82. dwLower uintptr
  83. dwUpper uintptr
  84. }
  85. type SecBuffer struct {
  86. cbBuffer uint32
  87. BufferType uint32
  88. pvBuffer *byte
  89. }
  90. type SecBufferDesc struct {
  91. ulVersion uint32
  92. cBuffers uint32
  93. pBuffers *SecBuffer
  94. }
  95. type SSPIAuth struct {
  96. Domain string
  97. UserName string
  98. Password string
  99. Service string
  100. cred SecHandle
  101. ctxt SecHandle
  102. }
  103. func getAuth(user, password, service, workstation string) (Auth, bool) {
  104. if user == "" {
  105. return &SSPIAuth{Service: service}, true
  106. }
  107. if !strings.ContainsRune(user, '\\') {
  108. return nil, false
  109. }
  110. domain_user := strings.SplitN(user, "\\", 2)
  111. return &SSPIAuth{
  112. Domain: domain_user[0],
  113. UserName: domain_user[1],
  114. Password: password,
  115. Service: service,
  116. }, true
  117. }
  118. func (auth *SSPIAuth) InitialBytes() ([]byte, error) {
  119. var identity *SEC_WINNT_AUTH_IDENTITY
  120. if auth.UserName != "" {
  121. identity = &SEC_WINNT_AUTH_IDENTITY{
  122. Flags: SEC_WINNT_AUTH_IDENTITY_UNICODE,
  123. Password: syscall.StringToUTF16Ptr(auth.Password),
  124. PasswordLength: uint32(len(auth.Password)),
  125. Domain: syscall.StringToUTF16Ptr(auth.Domain),
  126. DomainLength: uint32(len(auth.Domain)),
  127. User: syscall.StringToUTF16Ptr(auth.UserName),
  128. UserLength: uint32(len(auth.UserName)),
  129. }
  130. }
  131. var ts TimeStamp
  132. sec_ok, _, _ := syscall.Syscall9(sec_fn.AcquireCredentialsHandle,
  133. 9,
  134. 0,
  135. uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("Negotiate"))),
  136. SECPKG_CRED_OUTBOUND,
  137. 0,
  138. uintptr(unsafe.Pointer(identity)),
  139. 0,
  140. 0,
  141. uintptr(unsafe.Pointer(&auth.cred)),
  142. uintptr(unsafe.Pointer(&ts)))
  143. if sec_ok != SEC_E_OK {
  144. return nil, fmt.Errorf("AcquireCredentialsHandle failed %x", sec_ok)
  145. }
  146. var buf SecBuffer
  147. var desc SecBufferDesc
  148. desc.ulVersion = SECBUFFER_VERSION
  149. desc.cBuffers = 1
  150. desc.pBuffers = &buf
  151. outbuf := make([]byte, NTLMBUF_LEN)
  152. buf.cbBuffer = NTLMBUF_LEN
  153. buf.BufferType = SECBUFFER_TOKEN
  154. buf.pvBuffer = &outbuf[0]
  155. var attrs uint32
  156. sec_ok, _, _ = syscall.Syscall12(sec_fn.InitializeSecurityContext,
  157. 12,
  158. uintptr(unsafe.Pointer(&auth.cred)),
  159. 0,
  160. uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(auth.Service))),
  161. ISC_REQ,
  162. 0,
  163. SECURITY_NETWORK_DREP,
  164. 0,
  165. 0,
  166. uintptr(unsafe.Pointer(&auth.ctxt)),
  167. uintptr(unsafe.Pointer(&desc)),
  168. uintptr(unsafe.Pointer(&attrs)),
  169. uintptr(unsafe.Pointer(&ts)))
  170. if sec_ok == SEC_I_COMPLETE_AND_CONTINUE ||
  171. sec_ok == SEC_I_COMPLETE_NEEDED {
  172. syscall.Syscall6(sec_fn.CompleteAuthToken,
  173. 2,
  174. uintptr(unsafe.Pointer(&auth.ctxt)),
  175. uintptr(unsafe.Pointer(&desc)),
  176. 0, 0, 0, 0)
  177. } else if sec_ok != SEC_E_OK &&
  178. sec_ok != SEC_I_CONTINUE_NEEDED {
  179. syscall.Syscall6(sec_fn.FreeCredentialsHandle,
  180. 1,
  181. uintptr(unsafe.Pointer(&auth.cred)),
  182. 0, 0, 0, 0, 0)
  183. return nil, fmt.Errorf("InitialBytes InitializeSecurityContext failed %x", sec_ok)
  184. }
  185. return outbuf[:buf.cbBuffer], nil
  186. }
  187. func (auth *SSPIAuth) NextBytes(bytes []byte) ([]byte, error) {
  188. var in_buf, out_buf SecBuffer
  189. var in_desc, out_desc SecBufferDesc
  190. in_desc.ulVersion = SECBUFFER_VERSION
  191. in_desc.cBuffers = 1
  192. in_desc.pBuffers = &in_buf
  193. out_desc.ulVersion = SECBUFFER_VERSION
  194. out_desc.cBuffers = 1
  195. out_desc.pBuffers = &out_buf
  196. in_buf.BufferType = SECBUFFER_TOKEN
  197. in_buf.pvBuffer = &bytes[0]
  198. in_buf.cbBuffer = uint32(len(bytes))
  199. outbuf := make([]byte, NTLMBUF_LEN)
  200. out_buf.BufferType = SECBUFFER_TOKEN
  201. out_buf.pvBuffer = &outbuf[0]
  202. out_buf.cbBuffer = NTLMBUF_LEN
  203. var attrs uint32
  204. var ts TimeStamp
  205. sec_ok, _, _ := syscall.Syscall12(sec_fn.InitializeSecurityContext,
  206. 12,
  207. uintptr(unsafe.Pointer(&auth.cred)),
  208. uintptr(unsafe.Pointer(&auth.ctxt)),
  209. uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(auth.Service))),
  210. ISC_REQ,
  211. 0,
  212. SECURITY_NETWORK_DREP,
  213. uintptr(unsafe.Pointer(&in_desc)),
  214. 0,
  215. uintptr(unsafe.Pointer(&auth.ctxt)),
  216. uintptr(unsafe.Pointer(&out_desc)),
  217. uintptr(unsafe.Pointer(&attrs)),
  218. uintptr(unsafe.Pointer(&ts)))
  219. if sec_ok == SEC_I_COMPLETE_AND_CONTINUE ||
  220. sec_ok == SEC_I_COMPLETE_NEEDED {
  221. syscall.Syscall6(sec_fn.CompleteAuthToken,
  222. 2,
  223. uintptr(unsafe.Pointer(&auth.ctxt)),
  224. uintptr(unsafe.Pointer(&out_desc)),
  225. 0, 0, 0, 0)
  226. } else if sec_ok != SEC_E_OK &&
  227. sec_ok != SEC_I_CONTINUE_NEEDED {
  228. return nil, fmt.Errorf("NextBytes InitializeSecurityContext failed %x", sec_ok)
  229. }
  230. return outbuf[:out_buf.cbBuffer], nil
  231. }
  232. func (auth *SSPIAuth) Free() {
  233. syscall.Syscall6(sec_fn.DeleteSecurityContext,
  234. 1,
  235. uintptr(unsafe.Pointer(&auth.ctxt)),
  236. 0, 0, 0, 0, 0)
  237. syscall.Syscall6(sec_fn.FreeCredentialsHandle,
  238. 1,
  239. uintptr(unsafe.Pointer(&auth.cred)),
  240. 0, 0, 0, 0, 0)
  241. }