# # (C) Copyright 2015 Enthought, Inc., Austin, TX # All right reserved. # # This file is open source software distributed according to the terms in # LICENSE.txt # from __future__ import absolute_import from weakref import WeakKeyDictionary from win32ctypes.core.compat import is_text from ._util import ffi, check_zero, dlls from ._nl_support import _GetACP from ._common import _PyBytes_FromStringAndSize ffi.cdef(""" typedef struct _FILETIME { DWORD dwLowDateTime; DWORD dwHighDateTime; } FILETIME, *PFILETIME; typedef struct _CREDENTIAL_ATTRIBUTE { LPWSTR Keyword; DWORD Flags; DWORD ValueSize; LPBYTE Value; } CREDENTIAL_ATTRIBUTE, *PCREDENTIAL_ATTRIBUTE; typedef struct _CREDENTIAL { DWORD Flags; DWORD Type; LPWSTR TargetName; LPWSTR Comment; FILETIME LastWritten; DWORD CredentialBlobSize; LPBYTE CredentialBlob; DWORD Persist; DWORD AttributeCount; PCREDENTIAL_ATTRIBUTE Attributes; LPWSTR TargetAlias; LPWSTR UserName; } CREDENTIAL, *PCREDENTIAL; BOOL WINAPI CredReadW( LPCWSTR TargetName, DWORD Type, DWORD Flags, PCREDENTIAL *Credential); BOOL WINAPI CredWriteW(PCREDENTIAL Credential, DWORD); VOID WINAPI CredFree(PVOID Buffer); BOOL WINAPI CredDeleteW(LPCWSTR TargetName, DWORD Type, DWORD Flags); """) _keep_alive = WeakKeyDictionary() SUPPORTED_CREDKEYS = set(( u'Type', u'TargetName', u'Persist', u'UserName', u'Comment', u'CredentialBlob')) def make_unicode(password): """ Convert the input string to unicode. """ if is_text(password): return password else: code_page = _GetACP() return password.decode(encoding=str(code_page), errors='strict') class _CREDENTIAL(object): def __call__(self): return ffi.new("PCREDENTIAL")[0] @classmethod def fromdict(cls, credential, flag=0): unsupported = set(credential.keys()) - SUPPORTED_CREDKEYS if len(unsupported): raise ValueError("Unsupported keys: {0}".format(unsupported)) if flag != 0: raise ValueError("flag != 0 not yet supported") factory = cls() c_creds = factory() # values to ref and make sure that they will not go away values = [] for key in SUPPORTED_CREDKEYS: if key in credential: if key == u'CredentialBlob': blob = make_unicode(credential['CredentialBlob']) blob_data = ffi.new('wchar_t[]', blob) # new adds a NULL at the end that we do not want. c_creds.CredentialBlobSize = \ ffi.sizeof(blob_data) - ffi.sizeof('wchar_t') c_creds.CredentialBlob = ffi.cast('LPBYTE', blob_data) values.append(blob_data) elif key in (u'Type', u'Persist'): setattr(c_creds, key, credential[key]) else: blob = make_unicode(credential[key]) value = ffi.new('wchar_t[]', blob) values.append(value) setattr(c_creds, key, ffi.cast('LPTSTR', value)) # keep values alive until c_creds goes away. _keep_alive[c_creds] = tuple(values) return c_creds CREDENTIAL = _CREDENTIAL() def PCREDENTIAL(value=None): return ffi.new("PCREDENTIAL", ffi.NULL if value is None else value) def PPCREDENTIAL(value=None): return ffi.new("PCREDENTIAL*", ffi.NULL if value is None else value) def credential2dict(pc_creds): credentials = {} for key in SUPPORTED_CREDKEYS: if key == u'CredentialBlob': data = _PyBytes_FromStringAndSize( pc_creds.CredentialBlob, pc_creds.CredentialBlobSize) elif key in (u'Type', u'Persist'): data = int(getattr(pc_creds, key)) else: string_pointer = getattr(pc_creds, key) if string_pointer == ffi.NULL: data = u'' else: data = ffi.string(string_pointer) credentials[key] = data return credentials def _CredRead(TargetName, Type, Flags, ppCredential): target = make_unicode(TargetName) value = check_zero( dlls.advapi32.CredReadW(target, Type, Flags, ppCredential), u'CredRead') return value def _CredWrite(Credential, Flags): return check_zero( dlls.advapi32.CredWriteW(Credential, Flags), u'CredWrite') def _CredDelete(TargetName, Type, Flags): return check_zero( dlls.advapi32.CredDeleteW( make_unicode(TargetName), Type, Flags), u'CredDelete') _CredFree = dlls.advapi32.CredFree