~ubuntu-branches/debian/sid/pytds/sid

« back to all changes in this revision

Viewing changes to pytds/sspi.py

  • Committer: Package Import Robot
  • Author(s): Christopher Hoskin
  • Date: 2017-03-11 20:12:33 UTC
  • Revision ID: package-import@ubuntu.com-20170311201233-voewiramv2n5i4uj
Tags: upstream-1.8.2
ImportĀ upstreamĀ versionĀ 1.8.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import six
 
2
from ctypes import c_ulong, c_ushort, c_void_p, c_ulonglong, POINTER,\
 
3
    Structure, c_wchar_p, WINFUNCTYPE, windll, byref, cast
 
4
 
 
5
 
 
6
class Status(object):
 
7
    SEC_E_OK = 0
 
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
 
27
 
 
28
    @classmethod
 
29
    def getname(cls, value):
 
30
        for name in dir(cls):
 
31
            if name.startswith('SEC_E_') and getattr(cls, name) == value:
 
32
                return name
 
33
        return 'unknown value {0:x}'.format(0x100000000 + value)
 
34
 
 
35
#define SECBUFFER_EMPTY             0   // Undefined, replaced by provider
 
36
#define SECBUFFER_DATA              1   // Packet data
 
37
SECBUFFER_TOKEN = 2
 
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
 
53
 
 
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
 
59
 
 
60
SECBUFFER_VERSION = 0
 
61
 
 
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
 
90
 
 
91
SECURITY_NETWORK_DREP = 0
 
92
SECURITY_NATIVE_DREP = 0x10
 
93
 
 
94
SECPKG_CRED_ATTR_NAMES = 1
 
95
 
 
96
ULONG = c_ulong
 
97
USHORT = c_ushort
 
98
PULONG = POINTER(ULONG)
 
99
PVOID = c_void_p
 
100
TimeStamp = c_ulonglong
 
101
PTimeStamp = POINTER(c_ulonglong)
 
102
PLUID = POINTER(c_ulonglong)
 
103
 
 
104
 
 
105
class SecHandle(Structure):
 
106
    _fields_ = [
 
107
        ('lower', c_void_p),
 
108
        ('upper', c_void_p),
 
109
    ]
 
110
PSecHandle = POINTER(SecHandle)
 
111
CredHandle = SecHandle
 
112
PCredHandle = PSecHandle
 
113
PCtxtHandle = PSecHandle
 
114
 
 
115
 
 
116
class SecBuffer(Structure):
 
117
    _fields_ = [
 
118
        ('cbBuffer', ULONG),
 
119
        ('BufferType', ULONG),
 
120
        ('pvBuffer', PVOID),
 
121
    ]
 
122
PSecBuffer = POINTER(SecBuffer)
 
123
 
 
124
 
 
125
class SecBufferDesc(Structure):
 
126
    _fields_ = [
 
127
        ('ulVersion', ULONG),
 
128
        ('cBuffers', ULONG),
 
129
        ('pBuffers', PSecBuffer),
 
130
    ]
 
131
PSecBufferDesc = POINTER(SecBufferDesc)
 
132
 
 
133
 
 
134
class SEC_WINNT_AUTH_IDENTITY(Structure):
 
135
    _fields_ = [
 
136
        ('User', c_wchar_p),
 
137
        ('UserLength', c_ulong),
 
138
        ('Domain', c_wchar_p),
 
139
        ('DomainLength', c_ulong),
 
140
        ('Password', c_wchar_p),
 
141
        ('PasswordLength', c_ulong),
 
142
        ('Flags', c_ulong),
 
143
        ]
 
144
 
 
145
 
 
146
class SecPkgInfo(Structure):
 
147
    _fields_ = [
 
148
        ('fCapabilities', ULONG),
 
149
        ('wVersion', USHORT),
 
150
        ('wRPCID', USHORT),
 
151
        ('cbMaxToken', ULONG),
 
152
        ('Name', c_wchar_p),
 
153
        ('Comment', c_wchar_p),
 
154
    ]
 
155
PSecPkgInfo = POINTER(SecPkgInfo)
 
156
 
 
157
 
 
158
class SecPkgCredentials_Names(Structure):
 
159
    _fields_ = [('UserName', c_wchar_p)]
 
160
 
 
161
 
 
162
def ret_val(value):
 
163
    if value < 0:
 
164
        raise Exception('SSPI Error {0}'.format(Status.getname(value)))
 
165
    return value
 
166
 
 
167
 
 
168
ENUMERATE_SECURITY_PACKAGES_FN = WINFUNCTYPE(
 
169
    ret_val,
 
170
    POINTER(c_ulong),
 
171
    POINTER(POINTER(SecPkgInfo)))
 
172
 
 
173
ACQUIRE_CREDENTIALS_HANDLE_FN = WINFUNCTYPE(
 
174
    ret_val,
 
175
    c_wchar_p,    # principal
 
176
    c_wchar_p,    # package
 
177
    ULONG,        # fCredentialUse
 
178
    PLUID,        # pvLogonID
 
179
    PVOID,        # pAuthData
 
180
    PVOID,        # pGetKeyFn
 
181
    PVOID,        # pvGetKeyArgument
 
182
    PCredHandle,  # phCredential
 
183
    PTimeStamp    # ptsExpiry
 
184
    )
 
185
FREE_CREDENTIALS_HANDLE_FN = WINFUNCTYPE(ret_val, POINTER(SecHandle))
 
186
INITIALIZE_SECURITY_CONTEXT_FN = WINFUNCTYPE(
 
187
    ret_val,
 
188
    PCredHandle,
 
189
    PCtxtHandle,     # phContext,
 
190
    c_wchar_p,       # pszTargetName,
 
191
    ULONG,           # fContextReq,
 
192
    ULONG,           # Reserved1,
 
193
    ULONG,           # TargetDataRep,
 
194
    PSecBufferDesc,  # pInput,
 
195
    ULONG,           # Reserved2,
 
196
    PCtxtHandle,     # phNewContext,
 
197
    PSecBufferDesc,  # pOutput,
 
198
    PULONG,          # pfContextAttr,
 
199
    PTimeStamp,      # ptsExpiry
 
200
    )
 
201
COMPLETE_AUTH_TOKEN_FN = WINFUNCTYPE(
 
202
    ret_val,
 
203
    PCtxtHandle,     # phContext
 
204
    PSecBufferDesc,  # pToken
 
205
    )
 
206
 
 
207
FREE_CONTEXT_BUFFER_FN = WINFUNCTYPE(ret_val, PVOID)
 
208
 
 
209
QUERY_CREDENTIAL_ATTRIBUTES_FN = WINFUNCTYPE(
 
210
    ret_val,
 
211
    PCredHandle,    # cred
 
212
    ULONG,          # attribute
 
213
    PVOID,          # out buffer
 
214
    )
 
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(
 
224
    ret_val,
 
225
    c_wchar_p,  # package name
 
226
    POINTER(PSecPkgInfo),
 
227
    )
 
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
 
235
 
 
236
 
 
237
class SECURITY_FUNCTION_TABLE(Structure):
 
238
    _fields_ = [
 
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),
 
267
        ]
 
268
 
 
269
_PInitSecurityInterface = WINFUNCTYPE(POINTER(SECURITY_FUNCTION_TABLE))
 
270
InitSecurityInterface = _PInitSecurityInterface(('InitSecurityInterfaceW', windll.secur32))
 
271
 
 
272
sec_fn = InitSecurityInterface()
 
273
if not sec_fn:
 
274
    raise Exception('InitSecurityInterface failed')
 
275
sec_fn = sec_fn.contents
 
276
#sec_mutex = TDS_MUTEX_DEFINE()
 
277
 
 
278
 
 
279
class _SecContext(object):
 
280
    def close(self):
 
281
        if self._handle.lower and self._handle.upper:
 
282
            sec_fn.DeleteSecurityContext(self._handle)
 
283
            self._handle.lower = self._handle.upper = 0
 
284
 
 
285
    def __del__(self):
 
286
        self.close()
 
287
 
 
288
    def complete_auth_token(self, bufs):
 
289
        sec_fn.CompleteAuthToken(
 
290
            byref(self._handle),
 
291
            byref(_make_buffers_desc(bufs)))
 
292
 
 
293
    def next(self,
 
294
             flags,
 
295
             target_name=None,
 
296
             byte_ordering='network',
 
297
             input_buffers=None,
 
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),
 
303
            byref(self._handle),
 
304
            target_name,
 
305
            flags,
 
306
            0,
 
307
            SECURITY_NETWORK_DREP if byte_ordering == 'network' else SECURITY_NATIVE_DREP,
 
308
            byref(input_buffers_desc) if input_buffers_desc else None,
 
309
            0,
 
310
            byref(self._handle),
 
311
            byref(output_buffers_desc) if input_buffers_desc else None,
 
312
            byref(self._attrs),
 
313
            byref(self._ts))
 
314
        result_buffers = []
 
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
 
319
 
 
320
 
 
321
class SspiCredentials(object):
 
322
    def __init__(self, package, use, identity=None):
 
323
        self._handle = SecHandle()
 
324
        self._ts = TimeStamp()
 
325
        sec_fn.AcquireCredentialsHandle(
 
326
            None, package, use,
 
327
            None, byref(identity) if identity and identity.Domain else None,
 
328
            None, None, byref(self._handle), byref(self._ts))
 
329
 
 
330
    def close(self):
 
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
 
335
 
 
336
    def __del__(self):
 
337
        self.close()
 
338
 
 
339
    def query_user_name(self):
 
340
        names = SecPkgCredentials_Names()
 
341
        try:
 
342
            sec_fn.QueryCredentialsAttributes(
 
343
                byref(self._handle),
 
344
                SECPKG_CRED_ATTR_NAMES,
 
345
                byref(names))
 
346
            user_name = six.text_type(names.UserName)
 
347
        finally:
 
348
            p = c_wchar_p.from_buffer(names, SecPkgCredentials_Names.UserName.offset)
 
349
            sec_fn.FreeContextBuffer(p)
 
350
        return user_name
 
351
 
 
352
    def create_context(
 
353
            self,
 
354
            flags,
 
355
            target_name=None,
 
356
            byte_ordering='network',
 
357
            input_buffers=None,
 
358
            output_buffers=None):
 
359
        ctx = _SecContext()
 
360
        ctx._cred = self
 
361
        ctx._handle = SecHandle()
 
362
        ctx._ts = TimeStamp()
 
363
        ctx._attrs = ULONG()
 
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(
 
367
            byref(self._handle),
 
368
            None,
 
369
            target_name,
 
370
            flags,
 
371
            0,
 
372
            SECURITY_NETWORK_DREP if byte_ordering == 'network' else SECURITY_NATIVE_DREP,
 
373
            byref(input_buffers_desc) if input_buffers_desc else None,
 
374
            0,
 
375
            byref(ctx._handle),
 
376
            byref(output_buffers_desc) if output_buffers_desc else None,
 
377
            byref(ctx._attrs),
 
378
            byref(ctx._ts))
 
379
        result_buffers = []
 
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
 
384
 
 
385
 
 
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)
 
396
    return desc
 
397
 
 
398
 
 
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)
 
408
    return identity
 
409
 
 
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)
 
417
#
 
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
 
424
#
 
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
 
432
 
 
433
 
 
434
def enum_security_packages():
 
435
    num = ULONG()
 
436
    infos = POINTER(SecPkgInfo)()
 
437
    status = sec_fn.EnumerateSecurityPackages(byref(num), byref(infos))
 
438
    try:
 
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)]
 
446
    finally:
 
447
        sec_fn.FreeContextBuffer(infos)