1212from ._nl_support import _GetACP
1313from ._common import _PyBytes_FromStringAndSize
1414
15+ # values to ref and make sure that they will not go away
16+ _keep_alive = WeakKeyDictionary ()
1517
1618ffi .cdef ("""
1719
5254 LPCWSTR Filter, DWORD Flags, DWORD *Count, PCREDENTIAL **Credential);
5355""" )
5456
55- _keep_alive = WeakKeyDictionary ()
56-
57-
58- SUPPORTED_CREDKEYS = set ((
59- u'Type' , u'TargetName' , u'Persist' ,
60- u'UserName' , u'Comment' , u'CredentialBlob' ))
61-
6257
6358def make_unicode (password ):
6459 """ Convert the input string to unicode.
@@ -70,48 +65,101 @@ def make_unicode(password):
7065 code_page = _GetACP ()
7166 return password .decode (encoding = str (code_page ), errors = 'strict' )
7267
68+ class _FILETIME (object ):
69+
70+ def __call__ (self ):
71+ return ffi .new ("PFILETIME" )[0 ]
72+
73+ @classmethod
74+ def fromdict (cls , filetime ):
75+ factory = cls ()
76+ c_filetime = factory ()
77+ c_filetime .dwLowDateTime = filetime ['dwLowDateTime' ]
78+ c_filetime .dwHighDateTime = filetime ['dwHighDateTime' ]
79+ return c_filetime
80+
7381
7482class _CREDENTIAL (object ):
7583
7684 def __call__ (self ):
7785 return ffi .new ("PCREDENTIAL" )[0 ]
7886
7987 @classmethod
80- def fromdict (cls , credential , flag = 0 ):
81- unsupported = set (credential .keys ()) - SUPPORTED_CREDKEYS
82- if len (unsupported ):
83- raise ValueError ("Unsupported keys: {0}" .format (unsupported ))
84- if flag != 0 :
85- raise ValueError ("flag != 0 not yet supported" )
86-
88+ def fromdict (cls , credential , flags = 0 ):
8789 factory = cls ()
88- c_creds = factory ()
89- # values to ref and make sure that they will not go away
90- values = []
90+ c_credential = factory ()
91+ values = [] # values to ref and make sure that they will not go away
9192 for key , value in credential .items ():
92- if key == u'CredentialBlob' :
93- blob = make_unicode (value )
94- blob_data = ffi .new ('wchar_t[]' , blob )
95- # new adds a NULL at the end that we do not want.
96- c_creds .CredentialBlobSize = \
97- ffi .sizeof (blob_data ) - ffi .sizeof ('wchar_t' )
98- c_creds .CredentialBlob = ffi .cast ('LPBYTE' , blob_data )
99- values .append (blob_data )
100- elif key in (u'Type' , u'Persist' ):
101- setattr (c_creds , key , value )
102- elif value is None :
103- setattr (c_creds , key , ffi .NULL )
104- else :
105- blob = make_unicode (value )
106- pblob = ffi .new ('wchar_t[]' , blob )
107- values .append (pblob )
108- setattr (c_creds , key , ffi .cast ('LPTSTR' , pblob ))
109- # keep values alive until c_creds goes away.
110- _keep_alive [c_creds ] = tuple (values )
111- return c_creds
93+ if key == 'CredentialBlob' :
94+ blob = ffi .new ('wchar_t[]' , value )
95+ c_credential .CredentialBlob = ffi .cast ('LPBYTE' , blob )
96+ c_credential .CredentialBlobSize = ffi .sizeof (blob ) - ffi .sizeof ('wchar_t' ) # noqa
97+ values .append (blob )
98+ elif key == 'Attributes' :
99+ count = len (value )
100+ if count == 0 :
101+ continue
102+ elif count > 1 :
103+ raise ValueError ('Multiple attributes are not supported' )
104+ c_attribute = CREDENTIAL_ATTRIBUTE .fromdict (value [0 ])
105+ c_credential .Attributes = PCREDENTIAL_ATTRIBUTE (c_attribute )
106+ c_credential .AttributeCount = count
107+ values .append (c_attribute )
108+ elif key in ('Type' , 'Persist' , 'Flags' ):
109+ setattr (c_credential , key , value )
110+ elif key in ('TargetName' , 'Comment' , 'TargetAlias' , 'UserName' ):
111+ if value is None :
112+ setattr (c_credential , key , ffi .NULL )
113+ else :
114+ blob_pointer = ffi .new ('wchar_t[]' , value )
115+ setattr (c_credential , key , ffi .cast ('LPWSTR' , blob_pointer ))
116+ values .append (blob_pointer )
117+
118+ # keep values alive until c_credential goes away.
119+ _keep_alive [c_credential ] = tuple (values )
120+ return c_credential
121+
122+
123+ class _CREDENTIAL_ATTRIBUTE (object ):
124+
125+ def __call__ (self ):
126+ return ffi .new ("PCREDENTIAL_ATTRIBUTE" )[0 ]
127+
128+ @classmethod
129+ def fromdict (cls , attribute , flags = 0 ):
130+ factory = cls ()
131+ c_attribute = factory ()
132+ c_attribute .Flags = attribute .get ('Flags' , flags )
133+ keyword = attribute .get ('Keyword' , None )
134+ if keyword is None :
135+ c_attribute .Keyword = ffi .NULL
136+ else :
137+ blob_pointer = ffi .new ('wchar_t[]' , keyword )
138+ c_attribute .Keyword = ffi .cast ('LPWSTR' , blob_pointer )
139+ value = attribute ['Value' ]
140+ if len (value ) == 0 :
141+ data , size = ffi .NULL , 0
142+ elif is_text (value ):
143+ blob = ffi .new ('wchar_t[]' , value )
144+ _keep_alive [c_attribute ] = blob
145+ data = ffi .cast ('LPBYTE' , blob )
146+ size = ffi .sizeof (blob ) - ffi .sizeof ('wchar_t' ) # noqa
147+ else :
148+ data = ffi .new ('BYTE[]' , value )
149+ size = ffi .sizeof (blob_pointer ) - ffi .sizeof ('BYTE' )
150+ _keep_alive [c_attribute ] = data
151+ c_attribute .Value = data
152+ c_attribute .ValueSize = size
153+ return c_attribute
112154
113155
114156CREDENTIAL = _CREDENTIAL ()
157+ CREDENTIAL_ATTRIBUTE = _CREDENTIAL_ATTRIBUTE ()
158+ FILETIME = _FILETIME ()
159+
160+
161+ def PFILETIME (value = None ):
162+ return ffi .new ("PFILETIME" , ffi .NULL if value is None else value )
115163
116164
117165def PCREDENTIAL (value = None ):
@@ -126,47 +174,79 @@ def PPPCREDENTIAL(value=None):
126174 return ffi .new ("PCREDENTIAL**" , ffi .NULL if value is None else value )
127175
128176
129- def credential2dict (pc_creds ):
130- credentials = {}
131- for key in SUPPORTED_CREDKEYS :
132- if key == u'CredentialBlob' :
177+ def PCREDENTIAL_ATTRIBUTE (value = None ):
178+ return ffi .new (
179+ "PCREDENTIAL_ATTRIBUTE" , ffi .NULL if value is None else value )
180+
181+
182+ def credential_attribute2dict (c_attribute ):
183+ attribute = {}
184+ keyword = c_attribute .Keyword
185+ if keyword == ffi .NULL :
186+ attribute ['Keyword' ] = None
187+ else :
188+ attribute ['Keyword' ] = ffi .string (keyword )
189+ attribute ['Flags' ] = c_attribute .Flags
190+ size = c_attribute .ValueSize
191+ if size > 0 :
192+ value = _PyBytes_FromStringAndSize (c_attribute .Value , size )
193+ attribute ['Value' ] = value
194+ return attribute
195+
196+
197+ def credential2dict (c_credential ):
198+ credential = {}
199+ for key in dir (c_credential ):
200+ if key == 'CredentialBlob' :
133201 data = _PyBytes_FromStringAndSize (
134- pc_creds .CredentialBlob , pc_creds .CredentialBlobSize )
135- elif key in (u'Type' , u'Persist' ):
136- data = int (getattr (pc_creds , key ))
137- else :
138- string_pointer = getattr (pc_creds , key )
202+ c_credential .CredentialBlob , c_credential .CredentialBlobSize )
203+ elif key == 'Attributes' :
204+ attributes = []
205+ count = c_credential .AttributeCount
206+ c_attributes = c_credential .Attributes
207+ for index in range (count ):
208+ attribute = credential_attribute2dict (c_attributes [index ])
209+ attributes .append (attribute )
210+ data = tuple (attributes )
211+ elif key == 'LastWritten' :
212+ data = c_credential .LastWritten
213+ elif key in ('Type' , 'Persist' , 'Flags' ):
214+ data = int (getattr (c_credential , key ))
215+ elif key in ('TargetName' , 'Comment' , 'TargetAlias' , 'UserName' ):
216+ string_pointer = getattr (c_credential , key )
139217 if string_pointer == ffi .NULL :
140218 data = None
141219 else :
142220 data = ffi .string (string_pointer )
143- credentials [key ] = data
144- return credentials
221+ else :
222+ continue
223+ credential [key ] = data
224+ return credential
145225
146226
147227def _CredRead (TargetName , Type , Flags , ppCredential ):
148228 target = make_unicode (TargetName )
149229 return check_false (
150230 dlls .advapi32 .CredReadW (target , Type , Flags , ppCredential ),
151- u 'CredRead' )
231+ 'CredRead' )
152232
153233
154234def _CredWrite (Credential , Flags ):
155235 return check_false (
156- dlls .advapi32 .CredWriteW (Credential , Flags ), u 'CredWrite' )
236+ dlls .advapi32 .CredWriteW (Credential , Flags ), 'CredWrite' )
157237
158238
159239def _CredDelete (TargetName , Type , Flags ):
160240 return check_false (
161241 dlls .advapi32 .CredDeleteW (
162- make_unicode (TargetName ), Type , Flags ), u 'CredDelete' )
242+ make_unicode (TargetName ), Type , Flags ), 'CredDelete' )
163243
164244
165245def _CredEnumerate (Filter , Flags , Count , pppCredential ):
166246 filter = make_unicode (Filter ) if Filter is not None else ffi .NULL
167247 return check_false (
168248 dlls .advapi32 .CredEnumerateW (filter , Flags , Count , pppCredential ),
169- u 'CredEnumerate' )
249+ 'CredEnumerate' )
170250
171251
172252_CredFree = dlls .advapi32 .CredFree
0 commit comments