CredentialTableController.m   [plain text]

//
// CredentialTableController.m
// GSSTestApp
//
// Created by Love Hörnquist Åstrand on 2014-08-16.
// Copyright (c) 2014 Apple, Inc. All rights reserved.
//

#import "CredentialTableController.h"
#import <GSS/GSS.h>
#import <notify.h>

@interface CredentialTableController ()
@property (assign) CFMutableArrayRef array;
@property (assign) CFMutableDictionaryRef credentials;
@property (assign) int token;
@property (strong) NSMutableSet *notificationObjects;
@end

@implementation CredentialTableController

+ (CredentialTableController *)getGlobalController {
static dispatch_once_t onceToken;
static CredentialTableController *controller = NULL;
dispatch_once(&onceToken, ^{
controller = [[CredentialTableController alloc] init];
});
return controller;
}

- (CredentialTableController *)init {
if ((self = [super init]) == nil)
return nil;

self.array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
self.credentials = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

[self updateCredentials];

self.notificationObjects = [NSMutableSet set];

self.token = NOTIFY_TOKEN_INVALID;
notify_register_dispatch("com.apple.Kerberos.cache.changed", &_token, dispatch_get_main_queue(), ^(int token) {
[self updateCredentials];
});

return self;
}

- (void)dealloc {
notify_cancel(self.token);
CFRelease(_array);
CFRelease(_credentials);
}

- (void)addNotification:(id<GSSCredentialsChangeNotification>)object
{
[self.notificationObjects addObject:object];
}

- (void)removeNotification:(id<GSSCredentialsChangeNotification>)object
{
[self.notificationObjects removeObject:object];
}

- (void)updateCredentials {
OM_uint32 min_stat;
__block bool changeHappned = false;

CFMutableDictionaryRef removedItems = CFDictionaryCreateMutableCopy(NULL, 0, self.credentials);

gss_iter_creds(&min_stat, 0, GSS_KRB5_MECHANISM, ^(gss_OID mechOID, gss_cred_id_t cred) {
CFStringRef nameString = NULL;
gss_name_t name = NULL;
CFUUIDRef uuid;

if (cred == NULL)
return;

uuid = GSSCredentialCopyUUID(cred);
if (uuid == NULL) {
CFRelease(cred);
return;
}

if (CFDictionaryGetValue(self.credentials, uuid)) {
CFDictionaryRemoveValue(removedItems, uuid);
CFRelease(uuid);
CFRelease(cred);
return;
}

name = GSSCredentialCopyName(cred);
if (name) {
nameString = GSSNameCreateDisplayString(name);
CFRelease(name);
}

if (nameString) {
CFDictionarySetValue(self.credentials, uuid, nameString);
CFArrayAppendValue(self.array, uuid);
NSLog(@"adding: %@", nameString);
CFRelease(nameString);
changeHappned = true;
}
CFRelease(uuid);
CFRelease(cred);
});

[(__bridge NSDictionary *)removedItems enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
CFIndex n = CFArrayGetFirstIndexOfValue(self.array, CFRangeMake(0, CFArrayGetCount(self.array)), (__bridge CFUUIDRef)key);
if (n > 0) {
CFArrayRemoveValueAtIndex(self.array, n);
changeHappned = true;
}
}];

CFRelease(removedItems);

if (changeHappned) {
for (id<GSSCredentialsChangeNotification> object in self.notificationObjects) {
[object GSSCredentialChangeNotifification];
}
}
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return CFArrayGetCount(self.array);
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = @"CredentialTableViewCell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

if (cell == nil)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];

CFUUIDRef uuid = (CFUUIDRef)CFArrayGetValueAtIndex(self.array, indexPath.row);
NSString *name = NULL;
if (uuid)
name = CFDictionaryGetValue(self.credentials, uuid);
cell.textLabel.text = name ? name : @"???";

return cell;
}

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {

CFUUIDRef uuid = (CFUUIDRef)CFArrayGetValueAtIndex(self.array, indexPath.row);

OM_uint32 min_stat;
gss_cred_id_t cred = GSSCreateCredentialFromUUID(uuid);
if (cred)
gss_destroy_cred(&min_stat, &cred);

CFDictionaryRemoveValue(self.credentials, uuid);
CFArrayRemoveValueAtIndex(self.array, indexPath.row);

[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}

@end