FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
SFHFKeychainUtils Class Reference
Inheritance diagram for SFHFKeychainUtils:
Collaboration diagram for SFHFKeychainUtils:

Class Methods

(NSString *) + getPasswordForUsername:andServerName:error:
 
(BOOL) + storeUsername:andPassword:forServerName:updateExisting:error:
 
(BOOL) + deleteItemForUsername:andServerName:error:
 

Detailed Description

Definition at line 32 of file SFHFKeychainUtils.h.

Method Documentation

◆ deleteItemForUsername:andServerName:error:

+ (BOOL) deleteItemForUsername: (NSString *)  username
andServerName: (NSString *)  serverName
error: (NSError **)  error 

Definition at line 33 of file SFHFKeychainUtils.m.

460 :(NSString *)username
461 andServerName:(NSString *)serverName
462 error:(NSError **)error
463{
464 if (!username || !serverName)
465 {
466 if (error != nil)
467 {
468 *error = [NSError errorWithDomain:SFHFKeychainUtilsErrorDomain code:-2000 userInfo:nil];
469 }
470 return NO;
471 }
472
473 if (error != nil)
474 {
475 *error = nil;
476 }
477
478 NSArray *keys =
479 [[[NSArray alloc] initWithObjects:(NSString *)kSecClass, kSecAttrAccount, kSecAttrService,
480 kSecReturnAttributes, nil] autorelease];
481 NSArray *objects =
482 [[[NSArray alloc] initWithObjects:(NSString *)kSecClassGenericPassword, username,
483 serverName, kCFBooleanTrue, nil] autorelease];
484
485 NSDictionary *query = [[[NSDictionary alloc] initWithObjects:objects forKeys:keys] autorelease];
486
487 OSStatus status = SecItemDelete((CFDictionaryRef)query);
488
489 if (error != nil && status != noErr)
490 {
491 *error = [NSError errorWithDomain:SFHFKeychainUtilsErrorDomain code:status userInfo:nil];
492
493 return NO;
494 }
495
496 return YES;
497}

◆ getPasswordForUsername:andServerName:error:

+ (NSString *) getPasswordForUsername: (NSString *)  username
andServerName: (NSString *)  serverName
error: (NSError **)  error 

Definition at line 33 of file SFHFKeychainUtils.m.

228 :(NSString *)username
229 andServerName:(NSString *)serverName
230 error:(NSError **)error
231{
232 if (!username || !serverName)
233 {
234 if (error != nil)
235 {
236 *error = [NSError errorWithDomain:SFHFKeychainUtilsErrorDomain code:-2000 userInfo:nil];
237 }
238 return nil;
239 }
240
241 if (error != nil)
242 {
243 *error = nil;
244 }
245
246 // Set up a query dictionary with the base query attributes: item type (generic), username, and
247 // service
248
249 NSArray *keys = [[[NSArray alloc]
250 initWithObjects:(NSString *)kSecClass, kSecAttrAccount, kSecAttrService, nil] autorelease];
251 NSArray *objects = [[[NSArray alloc] initWithObjects:(NSString *)kSecClassGenericPassword,
252 username, serverName, nil] autorelease];
253
254 NSMutableDictionary *query = [[[NSMutableDictionary alloc] initWithObjects:objects
255 forKeys:keys] autorelease];
256
257 // First do a query for attributes, in case we already have a Keychain item with no password
258 // data set. One likely way such an incorrect item could have come about is due to the previous
259 // (incorrect) version of this code (which set the password as a generic attribute instead of
260 // password data).
261
262 NSDictionary *attributeResult = NULL;
263 NSMutableDictionary *attributeQuery = [query mutableCopy];
264 [attributeQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnAttributes];
265 OSStatus status =
266 SecItemCopyMatching((CFDictionaryRef)attributeQuery, (CFTypeRef *)&attributeResult);
267
268 [attributeResult release];
269 [attributeQuery release];
270
271 if (status != noErr)
272 {
273 // No existing item found--simply return nil for the password
274 if (error != nil && status != errSecItemNotFound)
275 {
276 // Only return an error if a real exception happened--not simply for "not found."
277 *error = [NSError errorWithDomain:SFHFKeychainUtilsErrorDomain
278 code:status
279 userInfo:nil];
280 }
281
282 return nil;
283 }
284
285 // We have an existing item, now query for the password data associated with it.
286
287 NSData *resultData = nil;
288 NSMutableDictionary *passwordQuery = [query mutableCopy];
289 [passwordQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
290
291 status = SecItemCopyMatching((CFDictionaryRef)passwordQuery, (CFTypeRef *)&resultData);
292
293 [resultData autorelease];
294 [passwordQuery release];
295
296 if (status != noErr)
297 {
298 if (status == errSecItemNotFound)
299 {
300 // We found attributes for the item previously, but no password now, so return a special
301 // error. Users of this API will probably want to detect this error and prompt the user
302 // to re-enter their credentials. When you attempt to store the re-entered credentials
303 // using storeUsername:andPassword:forServiceName:updateExisting:error
304 // the old, incorrect entry will be deleted and a new one with a properly encrypted
305 // password will be added.
306 if (error != nil)
307 {
308 *error = [NSError errorWithDomain:SFHFKeychainUtilsErrorDomain
309 code:-1999
310 userInfo:nil];
311 }
312 }
313 else
314 {
315 // Something else went wrong. Simply return the normal Keychain API error code.
316 if (error != nil)
317 {
318 *error = [NSError errorWithDomain:SFHFKeychainUtilsErrorDomain
319 code:status
320 userInfo:nil];
321 }
322 }
323
324 return nil;
325 }
326
327 NSString *password = nil;
328
329 if (resultData)
330 {
331 password = [[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding];
332 }
333 else
334 {
335 // There is an existing item, but we weren't able to get password data for it for some
336 // reason, Possibly as a result of an item being incorrectly entered by the previous code.
337 // Set the -1999 error so the code above us can prompt the user again.
338 if (error != nil)
339 {
340 *error = [NSError errorWithDomain:SFHFKeychainUtilsErrorDomain code:-1999 userInfo:nil];
341 }
342 }
343
344 return [password autorelease];
345}

◆ storeUsername:andPassword:forServerName:updateExisting:error:

+ (BOOL) storeUsername: (NSString *)  username
andPassword: (NSString *)  password
forServerName: (NSString *)  serverName
updateExisting: (BOOL)  updateExisting
error: (NSError **)  error 

Definition at line 33 of file SFHFKeychainUtils.m.

347 :(NSString *)username
348 andPassword:(NSString *)password
349 forServerName:(NSString *)serverName
350 updateExisting:(BOOL)updateExisting
351 error:(NSError **)error
352{
353 if (!username || !password || !serverName)
354 {
355 if (error != nil)
356 {
357 *error = [NSError errorWithDomain:SFHFKeychainUtilsErrorDomain code:-2000 userInfo:nil];
358 }
359 return NO;
360 }
361
362 // See if we already have a password entered for these credentials.
363 NSError *getError = nil;
364 NSString *existingPassword = [SFHFKeychainUtils getPasswordForUsername:username
365 andServerName:serverName
366 error:&getError];
367
368 if ([getError code] == -1999)
369 {
370 // There is an existing entry without a password properly stored (possibly as a result of
371 // the previous incorrect version of this code. Delete the existing item before moving on
372 // entering a correct one.
373
374 getError = nil;
375
376 [self deleteItemForUsername:username andServerName:serverName error:&getError];
377
378 if ([getError code] != noErr)
379 {
380 if (error != nil)
381 {
382 *error = getError;
383 }
384 return NO;
385 }
386 }
387 else if ([getError code] != noErr)
388 {
389 if (error != nil)
390 {
391 *error = getError;
392 }
393 return NO;
394 }
395
396 if (error != nil)
397 {
398 *error = nil;
399 }
400
401 OSStatus status = noErr;
402
403 if (existingPassword)
404 {
405 // We have an existing, properly entered item with a password.
406 // Update the existing item.
407
408 if (![existingPassword isEqualToString:password] && updateExisting)
409 {
410 // Only update if we're allowed to update existing. If not, simply do nothing.
411
412 NSArray *keys =
413 [[[NSArray alloc] initWithObjects:(NSString *)kSecClass, kSecAttrService,
414 kSecAttrLabel, kSecAttrAccount, nil] autorelease];
415
416 NSArray *objects =
417 [[[NSArray alloc] initWithObjects:(NSString *)kSecClassGenericPassword, serverName,
418 serverName, username, nil] autorelease];
419
420 NSDictionary *query = [[[NSDictionary alloc] initWithObjects:objects
421 forKeys:keys] autorelease];
422
423 status = SecItemUpdate(
424 (CFDictionaryRef)query,
425 (CFDictionaryRef)[NSDictionary
426 dictionaryWithObject:[password dataUsingEncoding:NSUTF8StringEncoding]
427 forKey:(NSString *)kSecValueData]);
428 }
429 }
430 else
431 {
432 // No existing entry (or an existing, improperly entered, and therefore now
433 // deleted, entry). Create a new entry.
434
435 NSArray *keys =
436 [[[NSArray alloc] initWithObjects:(NSString *)kSecClass, kSecAttrService, kSecAttrLabel,
437 kSecAttrAccount, kSecValueData, nil] autorelease];
438
439 NSArray *objects = [[[NSArray alloc]
440 initWithObjects:(NSString *)kSecClassGenericPassword, serverName, serverName, username,
441 [password dataUsingEncoding:NSUTF8StringEncoding], nil] autorelease];
442
443 NSDictionary *query = [[[NSDictionary alloc] initWithObjects:objects
444 forKeys:keys] autorelease];
445
446 status = SecItemAdd((CFDictionaryRef)query, NULL);
447 }
448
449 if (error != nil && status != noErr)
450 {
451 // Something went wrong with adding the new item. Return the Keychain error code.
452 *error = [NSError errorWithDomain:SFHFKeychainUtilsErrorDomain code:status userInfo:nil];
453
454 return NO;
455 }
456
457 return YES;
458}

The documentation for this class was generated from the following files: