2
from ctypes import c_ulong, c_ushort, c_void_p, c_ulonglong, POINTER,\
3
Structure, c_wchar_p, WINFUNCTYPE, windll, byref, cast
8
SEC_I_CONTINUE_NEEDED = 0x00090312
9
SEC_I_COMPLETE_AND_CONTINUE = 0x00090314
10
SEC_I_INCOMPLETE_CREDENTIALS = 0x00090320
11
SEC_E_INSUFFICIENT_MEMORY = 0x80090300 - 0x100000000
12
SEC_E_INVALID_HANDLE = 0x80090301 - 0x100000000
13
SEC_E_UNSUPPORTED_FUNCTION = 0x80090302 - 0x100000000
14
SEC_E_INTERNAL_ERROR = 0x80090304 - 0x100000000
15
SEC_E_SECPKG_NOT_FOUND = 0x80090305 - 0x100000000
16
SEC_E_NOT_OWNER = 0x80090306 - 0x100000000
17
SEC_E_INVALID_TOKEN = 0x80090308 - 0x100000000
18
SEC_E_NO_IMPERSONATION = 0x8009030B - 0x100000000
19
SEC_E_LOGON_DENIED = 0x8009030C - 0x100000000
20
SEC_E_UNKNOWN_CREDENTIALS = 0x8009030D - 0x100000000
21
SEC_E_NO_CREDENTIALS = 0x8009030E - 0x100000000
22
SEC_E_OUT_OF_SEQUENCE = 0x80090310 - 0x100000000
23
SEC_E_NO_AUTHENTICATING_AUTHORITY = 0x80090311 - 0x100000000
24
SEC_E_BUFFER_TOO_SMALL = 0x80090321 - 0x100000000
25
SEC_E_WRONG_PRINCIPAL = 0x80090322 - 0x100000000
26
SEC_E_ALGORITHM_MISMATCH = 0x80090331 - 0x100000000
29
def getname(cls, value):
31
if name.startswith('SEC_E_') and getattr(cls, name) == value:
33
return 'unknown value {0:x}'.format(0x100000000 + value)
35
#define SECBUFFER_EMPTY 0 // Undefined, replaced by provider
36
#define SECBUFFER_DATA 1 // Packet data
38
#define SECBUFFER_PKG_PARAMS 3 // Package specific parameters
39
#define SECBUFFER_MISSING 4 // Missing Data indicator
40
#define SECBUFFER_EXTRA 5 // Extra data
41
#define SECBUFFER_STREAM_TRAILER 6 // Security Trailer
42
#define SECBUFFER_STREAM_HEADER 7 // Security Header
43
#define SECBUFFER_NEGOTIATION_INFO 8 // Hints from the negotiation pkg
44
#define SECBUFFER_PADDING 9 // non-data padding
45
#define SECBUFFER_STREAM 10 // whole encrypted message
46
#define SECBUFFER_MECHLIST 11
47
#define SECBUFFER_MECHLIST_SIGNATURE 12
48
#define SECBUFFER_TARGET 13 // obsolete
49
#define SECBUFFER_CHANNEL_BINDINGS 14
50
#define SECBUFFER_CHANGE_PASS_RESPONSE 15
51
#define SECBUFFER_TARGET_HOST 16
52
#define SECBUFFER_ALERT 17
54
SECPKG_CRED_INBOUND = 0x00000001
55
SECPKG_CRED_OUTBOUND = 0x00000002
56
SECPKG_CRED_BOTH = 0x00000003
57
SECPKG_CRED_DEFAULT = 0x00000004
58
SECPKG_CRED_RESERVED = 0xF0000000
62
#define ISC_REQ_DELEGATE 0x00000001
63
#define ISC_REQ_MUTUAL_AUTH 0x00000002
64
ISC_REQ_REPLAY_DETECT = 4
65
#define ISC_REQ_SEQUENCE_DETECT 0x00000008
66
ISC_REQ_CONFIDENTIALITY = 0x10
67
ISC_REQ_USE_SESSION_KEY = 0x00000020
68
ISC_REQ_PROMPT_FOR_CREDS = 0x00000040
69
ISC_REQ_USE_SUPPLIED_CREDS = 0x00000080
70
ISC_REQ_ALLOCATE_MEMORY = 0x00000100
71
ISC_REQ_USE_DCE_STYLE = 0x00000200
72
ISC_REQ_DATAGRAM = 0x00000400
73
ISC_REQ_CONNECTION = 0x00000800
74
#define ISC_REQ_CALL_LEVEL 0x00001000
75
#define ISC_REQ_FRAGMENT_SUPPLIED 0x00002000
76
#define ISC_REQ_EXTENDED_ERROR 0x00004000
77
#define ISC_REQ_STREAM 0x00008000
78
#define ISC_REQ_INTEGRITY 0x00010000
79
#define ISC_REQ_IDENTIFY 0x00020000
80
#define ISC_REQ_NULL_SESSION 0x00040000
81
#define ISC_REQ_MANUAL_CRED_VALIDATION 0x00080000
82
#define ISC_REQ_RESERVED1 0x00100000
83
#define ISC_REQ_FRAGMENT_TO_FIT 0x00200000
84
#// This exists only in Windows Vista and greater
85
#define ISC_REQ_FORWARD_CREDENTIALS 0x00400000
86
#define ISC_REQ_NO_INTEGRITY 0x00800000 // honored only by SPNEGO
87
#define ISC_REQ_USE_HTTP_STYLE 0x01000000
88
#define ISC_REQ_UNVERIFIED_TARGET_NAME 0x20000000
89
#define ISC_REQ_CONFIDENTIALITY_ONLY 0x40000000 // honored by SPNEGO/Kerberos
91
SECURITY_NETWORK_DREP = 0
92
SECURITY_NATIVE_DREP = 0x10
94
SECPKG_CRED_ATTR_NAMES = 1
98
PULONG = POINTER(ULONG)
100
TimeStamp = c_ulonglong
101
PTimeStamp = POINTER(c_ulonglong)
102
PLUID = POINTER(c_ulonglong)
105
class SecHandle(Structure):
110
PSecHandle = POINTER(SecHandle)
111
CredHandle = SecHandle
112
PCredHandle = PSecHandle
113
PCtxtHandle = PSecHandle
116
class SecBuffer(Structure):
119
('BufferType', ULONG),
122
PSecBuffer = POINTER(SecBuffer)
125
class SecBufferDesc(Structure):
127
('ulVersion', ULONG),
129
('pBuffers', PSecBuffer),
131
PSecBufferDesc = POINTER(SecBufferDesc)
134
class SEC_WINNT_AUTH_IDENTITY(Structure):
137
('UserLength', c_ulong),
138
('Domain', c_wchar_p),
139
('DomainLength', c_ulong),
140
('Password', c_wchar_p),
141
('PasswordLength', c_ulong),
146
class SecPkgInfo(Structure):
148
('fCapabilities', ULONG),
149
('wVersion', USHORT),
151
('cbMaxToken', ULONG),
153
('Comment', c_wchar_p),
155
PSecPkgInfo = POINTER(SecPkgInfo)
158
class SecPkgCredentials_Names(Structure):
159
_fields_ = [('UserName', c_wchar_p)]
164
raise Exception('SSPI Error {0}'.format(Status.getname(value)))
168
ENUMERATE_SECURITY_PACKAGES_FN = WINFUNCTYPE(
171
POINTER(POINTER(SecPkgInfo)))
173
ACQUIRE_CREDENTIALS_HANDLE_FN = WINFUNCTYPE(
175
c_wchar_p, # principal
177
ULONG, # fCredentialUse
181
PVOID, # pvGetKeyArgument
182
PCredHandle, # phCredential
183
PTimeStamp # ptsExpiry
185
FREE_CREDENTIALS_HANDLE_FN = WINFUNCTYPE(ret_val, POINTER(SecHandle))
186
INITIALIZE_SECURITY_CONTEXT_FN = WINFUNCTYPE(
189
PCtxtHandle, # phContext,
190
c_wchar_p, # pszTargetName,
191
ULONG, # fContextReq,
193
ULONG, # TargetDataRep,
194
PSecBufferDesc, # pInput,
196
PCtxtHandle, # phNewContext,
197
PSecBufferDesc, # pOutput,
198
PULONG, # pfContextAttr,
199
PTimeStamp, # ptsExpiry
201
COMPLETE_AUTH_TOKEN_FN = WINFUNCTYPE(
203
PCtxtHandle, # phContext
204
PSecBufferDesc, # pToken
207
FREE_CONTEXT_BUFFER_FN = WINFUNCTYPE(ret_val, PVOID)
209
QUERY_CREDENTIAL_ATTRIBUTES_FN = WINFUNCTYPE(
215
ACCEPT_SECURITY_CONTEXT_FN = PVOID
216
DELETE_SECURITY_CONTEXT_FN = WINFUNCTYPE(ret_val, PCtxtHandle)
217
APPLY_CONTROL_TOKEN_FN = PVOID
218
QUERY_CONTEXT_ATTRIBUTES_FN = PVOID
219
IMPERSONATE_SECURITY_CONTEXT_FN = PVOID
220
REVERT_SECURITY_CONTEXT_FN = PVOID
221
MAKE_SIGNATURE_FN = PVOID
222
VERIFY_SIGNATURE_FN = PVOID
223
QUERY_SECURITY_PACKAGE_INFO_FN = WINFUNCTYPE(
225
c_wchar_p, # package name
226
POINTER(PSecPkgInfo),
228
EXPORT_SECURITY_CONTEXT_FN = PVOID
229
IMPORT_SECURITY_CONTEXT_FN = PVOID
230
ADD_CREDENTIALS_FN = PVOID
231
QUERY_SECURITY_CONTEXT_TOKEN_FN = PVOID
232
ENCRYPT_MESSAGE_FN = PVOID
233
DECRYPT_MESSAGE_FN = PVOID
234
SET_CONTEXT_ATTRIBUTES_FN = PVOID
237
class SECURITY_FUNCTION_TABLE(Structure):
239
('dwVersion', c_ulong),
240
('EnumerateSecurityPackages', ENUMERATE_SECURITY_PACKAGES_FN),
241
('QueryCredentialsAttributes', QUERY_CREDENTIAL_ATTRIBUTES_FN),
242
('AcquireCredentialsHandle', ACQUIRE_CREDENTIALS_HANDLE_FN),
243
('FreeCredentialsHandle', FREE_CREDENTIALS_HANDLE_FN),
244
('Reserved2', c_void_p),
245
('InitializeSecurityContext', INITIALIZE_SECURITY_CONTEXT_FN),
246
('AcceptSecurityContext', ACCEPT_SECURITY_CONTEXT_FN),
247
('CompleteAuthToken', COMPLETE_AUTH_TOKEN_FN),
248
('DeleteSecurityContext', DELETE_SECURITY_CONTEXT_FN),
249
('ApplyControlToken', APPLY_CONTROL_TOKEN_FN),
250
('QueryContextAttributes', QUERY_CONTEXT_ATTRIBUTES_FN),
251
('ImpersonateSecurityContext', IMPERSONATE_SECURITY_CONTEXT_FN),
252
('RevertSecurityContext', REVERT_SECURITY_CONTEXT_FN),
253
('MakeSignature', MAKE_SIGNATURE_FN),
254
('VerifySignature', VERIFY_SIGNATURE_FN),
255
('FreeContextBuffer', FREE_CONTEXT_BUFFER_FN),
256
('QuerySecurityPackageInfo', QUERY_SECURITY_PACKAGE_INFO_FN),
257
('Reserved3', c_void_p),
258
('Reserved4', c_void_p),
259
('ExportSecurityContext', EXPORT_SECURITY_CONTEXT_FN),
260
('ImportSecurityContext', IMPORT_SECURITY_CONTEXT_FN),
261
('AddCredentials', ADD_CREDENTIALS_FN),
262
('Reserved8', c_void_p),
263
('QuerySecurityContextToken', QUERY_SECURITY_CONTEXT_TOKEN_FN),
264
('EncryptMessage', ENCRYPT_MESSAGE_FN),
265
('DecryptMessage', DECRYPT_MESSAGE_FN),
266
('SetContextAttributes', SET_CONTEXT_ATTRIBUTES_FN),
269
_PInitSecurityInterface = WINFUNCTYPE(POINTER(SECURITY_FUNCTION_TABLE))
270
InitSecurityInterface = _PInitSecurityInterface(('InitSecurityInterfaceW', windll.secur32))
272
sec_fn = InitSecurityInterface()
274
raise Exception('InitSecurityInterface failed')
275
sec_fn = sec_fn.contents
276
#sec_mutex = TDS_MUTEX_DEFINE()
279
class _SecContext(object):
281
if self._handle.lower and self._handle.upper:
282
sec_fn.DeleteSecurityContext(self._handle)
283
self._handle.lower = self._handle.upper = 0
288
def complete_auth_token(self, bufs):
289
sec_fn.CompleteAuthToken(
291
byref(_make_buffers_desc(bufs)))
296
byte_ordering='network',
298
output_buffers=None):
299
input_buffers_desc = _make_buffers_desc(input_buffers) if input_buffers else None
300
output_buffers_desc = _make_buffers_desc(output_buffers) if output_buffers else None
301
status = sec_fn.InitializeSecurityContext(
302
byref(self._cred._handle),
307
SECURITY_NETWORK_DREP if byte_ordering == 'network' else SECURITY_NATIVE_DREP,
308
byref(input_buffers_desc) if input_buffers_desc else None,
311
byref(output_buffers_desc) if input_buffers_desc else None,
315
for i, (type, buf) in enumerate(output_buffers):
316
buf = buf[:output_buffers_desc.pBuffers[i].cbBuffer]
317
result_buffers.append((type, buf))
318
return status, result_buffers
321
class SspiCredentials(object):
322
def __init__(self, package, use, identity=None):
323
self._handle = SecHandle()
324
self._ts = TimeStamp()
325
sec_fn.AcquireCredentialsHandle(
327
None, byref(identity) if identity and identity.Domain else None,
328
None, None, byref(self._handle), byref(self._ts))
331
if self._handle.lower or self._handle.upper:
332
sec_fn.FreeCredentialsHandle(byref(self._handle))
333
self._handle.lower = 0
334
self._handle.upper = 0
339
def query_user_name(self):
340
names = SecPkgCredentials_Names()
342
sec_fn.QueryCredentialsAttributes(
344
SECPKG_CRED_ATTR_NAMES,
346
user_name = six.text_type(names.UserName)
348
p = c_wchar_p.from_buffer(names, SecPkgCredentials_Names.UserName.offset)
349
sec_fn.FreeContextBuffer(p)
356
byte_ordering='network',
358
output_buffers=None):
361
ctx._handle = SecHandle()
362
ctx._ts = TimeStamp()
364
input_buffers_desc = _make_buffers_desc(input_buffers) if input_buffers else None
365
output_buffers_desc = _make_buffers_desc(output_buffers) if output_buffers else None
366
status = sec_fn.InitializeSecurityContext(
372
SECURITY_NETWORK_DREP if byte_ordering == 'network' else SECURITY_NATIVE_DREP,
373
byref(input_buffers_desc) if input_buffers_desc else None,
376
byref(output_buffers_desc) if output_buffers_desc else None,
380
for i, (type, buf) in enumerate(output_buffers):
381
buf = buf[:output_buffers_desc.pBuffers[i].cbBuffer]
382
result_buffers.append((type, buf))
383
return ctx, status, result_buffers
386
def _make_buffers_desc(buffers):
387
desc = SecBufferDesc()
388
desc.ulVersion = SECBUFFER_VERSION
389
bufs_array = (SecBuffer * len(buffers))()
390
for i, (type, buf) in enumerate(buffers):
391
bufs_array[i].BufferType = type
392
bufs_array[i].cbBuffer = len(buf)
393
bufs_array[i].pvBuffer = cast(buf, PVOID)
394
desc.pBuffers = bufs_array
395
desc.cBuffers = len(buffers)
399
def make_winnt_identity(domain, user_name, password):
400
identity = SEC_WINNT_AUTH_IDENTITY()
401
identity.Flags = 2 # SEC_WINNT_AUTH_IDENTITY_UNICODE
402
identity.Password = password
403
identity.PasswordLength = len(password)
404
identity.Domain = domain
405
identity.DomainLength = len(domain)
406
identity.User = user_name
407
identity.UserLength = len(user_name)
410
#class SspiSecBuffer(object):
411
# def __init__(self, type, buflen=4096):
412
# self._buf = create_string_buffer(int(buflen))
413
# self._desc = SecBuffer()
414
# self._desc.cbBuffer = buflen
415
# self._desc.BufferType = type
416
# self._desc.pvBuffer = cast(self._buf, PVOID)
418
#class SspiSecBuffers(object):
419
# def __init__(self):
420
# self._desc = SecBufferDesc()
421
# self._desc.ulVersion = SECBUFFER_VERSION
422
# self._descrs = (SecBuffer * 8)()
423
# self._desc.pBuffers = self._descrs
425
# def append(self, buf):
426
# if len(self._descrs) <= self._desc.cBuffers:
427
# newdescrs = (SecBuffer * (len(self._descrs) * 2))(*self._descrs)
428
# self._descrs = newdescrs
429
# self._desc.pBuffers = newdescrs
430
# self._descrs[self._desc.cBuffers] = buf._desc
431
# self._desc.cBuffers += 1
434
def enum_security_packages():
436
infos = POINTER(SecPkgInfo)()
437
status = sec_fn.EnumerateSecurityPackages(byref(num), byref(infos))
439
return [{'caps': infos[i].fCapabilities,
440
'version': infos[i].wVersion,
441
'rpcid': infos[i].wRPCID,
442
'max_token': infos[i].cbMaxToken,
443
'name': infos[i].Name,
444
'comment': infos[i].Comment,
445
} for i in range(num.value)]
447
sec_fn.FreeContextBuffer(infos)