]> git.saurik.com Git - apple/security.git/blob - OSX/authd/PreloginUserDb.m
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / authd / PreloginUserDb.m
1 //
2 // PreloginUserDb.m
3 // authd
4 //
5 // Copyright © 2019 Apple. All rights reserved.
6 //
7
8 #import <Foundation/Foundation.h>
9 #import <libgen.h>
10 #import <APFS/APFS.h>
11 #import <DiskManagement/DiskManagement.h>
12 #import "PreloginUserDb.h"
13 #import <LocalAuthentication/LAContext+Private.h>
14 #import <SoftLinking/SoftLinking.h>
15 #import "debugging.h"
16 #import <Security/Authorization.h>
17 #import <Security/AuthorizationTagsPriv.h>
18 #import <libaks_filevault.h>
19
20 AUTHD_DEFINE_LOG
21
22 SOFT_LINK_FRAMEWORK(Frameworks, LocalAuthentication)
23 SOFT_LINK_FRAMEWORK(PrivateFrameworks, DiskManagement)
24 SOFT_LINK_FRAMEWORK(Frameworks, DiskArbitration)
25 SOFT_LINK_FRAMEWORK(PrivateFrameworks, APFS)
26
27 SOFT_LINK_CLASS(LocalAuthentication, LAContext)
28 SOFT_LINK_CLASS(DiskManagement, DMManager)
29 SOFT_LINK_CLASS(DiskManagement, DMAPFS)
30 SOFT_LINK_FUNCTION(APFS, APFSVolumeGetUnlockRecord, soft_APFSVolumeGetUnlockRecord, errno_t, (const char *disk, uuid_t wrecUUID, CFDataRef *data), (disk, wrecUUID, data))
31 SOFT_LINK_FUNCTION(DiskArbitration, DADiskMount, soft_DADiskMount, void, ( DADiskRef disk, CFURLRef __nullable path, DADiskMountOptions options, DADiskMountCallback __nullable callback, void * __nullable context), (disk, path, options, callback, context ))
32 SOFT_LINK_FUNCTION(DiskArbitration, DADiskUnmount, soft_DADiskUnmount, void, ( DADiskRef disk, DADiskUnmountOptions options, DADiskUnmountCallback __nullable callback, void * __nullable context), (disk, options, callback, context ))
33 SOFT_LINK_FUNCTION(DiskArbitration, DADissenterGetStatusString, soft_DADissenterGetStatusString, CFStringRef __nullable, ( DADissenterRef dissenter ), ( dissenter ))
34 SOFT_LINK_FUNCTION(DiskManagement, DMUnlocalizedTechnicalErrorString, soft_DMUnlocalizedTechnicalErrorString, NSString *, ( DMDiskErrorType inError ), ( inError ))
35 SOFT_LINK_FUNCTION(DiskArbitration, DASessionCreate, soft_DASessionCreate, DASessionRef __nullable, ( CFAllocatorRef __nullable allocator ), ( allocator ))
36 SOFT_LINK_FUNCTION(DiskArbitration, DADissenterGetStatus, soft_DADissenterGetStatus, DAReturn, ( DADissenterRef dissenter ), ( dissenter ))
37 SOFT_LINK_FUNCTION(DiskArbitration, DASessionSetDispatchQueue, soft_DASessionSetDispatchQueue, void, ( DASessionRef session, dispatch_queue_t __nullable queue ), ( session, queue ))
38
39 static NSString *kVekItemName = @"SecureAccessToken";
40 static NSString *kGUIDItemName = @"GeneratedUID";
41 static NSString *kAuthenticationAuthority = @"AuthenticationAuthority";
42 static NSString *kIsAdmintemName = @"Admin";
43 static NSString *kSCUnlockDataItemName = @"FVTokenSecret";
44 static NSString *kSCEnforcementItemName = @"SmartCardEnforcement";
45 static NSString *kSCUacItemName = @"userAccountControl";
46
47 static NSString *kLongNameItemName = @"RealName";
48 static NSString *kUidItemName = @"UID";
49 static NSString *kVekFile = @"%@/%@/var/db/secureaccesstoken.plist";
50 static NSString *kUsersFile = @"%@/%@/var/db/AllUsersInfo.plist";
51
52 static NSString *kUsersGUID = @"UserIdent";
53 static NSString *kUsersNameSection = @"UserNamesData";
54 static NSString *kUsersSection = @"CryptoUsers";
55
56
57 @interface PreloginUserDb : NSObject
58
59 - (instancetype)init;
60
61 - (BOOL) loadWithError:(NSError **)error;
62
63 - (NSArray<NSDictionary *> *) users;
64 - (NSArray<NSDictionary *> *) users:(NSString *)volumeUuid;
65
66 @end
67
68 typedef void (^AIRDBDACommonCompletionHandler)(DADissenterRef dissenter);
69 static void _commonDACompletionCallback(DADiskRef disk, DADissenterRef dissenter, void *context)
70 {
71 AIRDBDACommonCompletionHandler handler = (__bridge AIRDBDACommonCompletionHandler)context;
72 handler(dissenter);
73 }
74
75 @implementation PreloginUserDb {
76 DMManager *_diskMgr;
77 id _daSession;
78 NSMutableDictionary<NSString*, NSMutableArray*> *_dbDataDict; // NSDictionary indexed by volume UUID (NSString*)
79 NSMutableDictionary<NSString*, NSString*> *_dbVolumeGroupMap;
80 dispatch_queue_t _queue;
81 }
82
83 - (instancetype)init
84 {
85 if ((self = [super init])) {
86 _queue = dispatch_queue_create("com.apple.PLUDB", DISPATCH_QUEUE_SERIAL);
87 if (!_queue) {
88 os_log_error(AUTHD_LOG, "Failed to create queue");
89 return nil;
90 }
91
92 _diskMgr = [[getDMManagerClass() alloc] init];
93 if (!_diskMgr) {
94 os_log_error(AUTHD_LOG, "Failed to get DM");
95 return nil;
96 }
97
98 _daSession = (__bridge_transfer id)soft_DASessionCreate(kCFAllocatorDefault);
99 if (!_daSession) {
100 os_log_error(AUTHD_LOG, "Failed to get DA");
101 return nil;
102 }
103
104 soft_DASessionSetDispatchQueue((__bridge DASessionRef _Nullable)_daSession, _queue);
105 [_diskMgr setDefaultDASession:(__bridge DASessionRef _Nullable)(_daSession)];
106 }
107 return self;
108 }
109
110 - (BOOL)loadWithError:(NSError **)err
111 {
112 // get all preboot volumes
113 NSArray* prebootVolumes = [self allPrebootVolumes];
114 if (prebootVolumes.count == 0) {
115 os_log_error(AUTHD_LOG, "Failed to get preboot volumes for Prelogin userDB");
116 if (err) {
117 *err = [NSError errorWithDomain:@"com.apple.authorization" code:-1000 userInfo:@{ NSLocalizedDescriptionKey : @"Failed to get preboot volumes for Prelogin userDB"}];
118 }
119 return NO;
120 }
121
122 NSUUID *uuid = [self currentRecoveryVolumeUUID];
123 os_log_info(AUTHD_LOG, "Current Recovery Volume UUID: %{public}@", uuid);
124
125 _dbDataDict = [NSMutableDictionary new];
126 _dbVolumeGroupMap = [NSMutableDictionary new];
127 [self processPrebootVolumes:prebootVolumes currentRecoveryVolumeUUID:uuid];
128
129 if (_dbDataDict.count == 0 && uuid != nil) {
130 os_log(AUTHD_LOG, "No admins found. Try to load all preboot partitions");
131 _dbDataDict = [NSMutableDictionary new];
132 [self processPrebootVolumes:prebootVolumes currentRecoveryVolumeUUID:nil]; // load admins from ALL preboot partitions
133 }
134
135 if (err) {
136 *err = nil;
137 }
138 return YES;
139 }
140
141 - (NSArray<NSDictionary *> *)users
142 {
143 return [self users:nil];
144 }
145
146 - (NSArray<NSDictionary *> *) users:(NSString *)requestedUuid
147 {
148 if (!_dbDataDict.allValues) {
149 return nil;
150 }
151 if (requestedUuid && !_dbDataDict[requestedUuid]) {
152 NSString *realUuid = _dbVolumeGroupMap[requestedUuid];
153 if (!realUuid) {
154 os_log_info(AUTHD_LOG, "Requested volume %{public}@ was not found and is not volumeGroup", requestedUuid);
155 NSArray *keys = [_dbVolumeGroupMap allKeysForObject:requestedUuid];
156 for(NSString *uuid in keys) {
157 if (_dbDataDict[uuid]) {
158 realUuid = uuid;
159 break;
160 }
161 }
162 if (!realUuid) {
163 os_log_info(AUTHD_LOG, "Requested volumeGroup %{public}@ was not found", requestedUuid);
164 return nil; // no users for requested partition and no mapping for VolumeGroup or vice versa
165 }
166 }
167 os_log_info(AUTHD_LOG, "Requested volume %{public}@ has no users, trying volume %{public}@", requestedUuid, realUuid);
168 requestedUuid = realUuid;
169 }
170
171 NSMutableArray *allUsers = [NSMutableArray new];
172 for (NSString *uuid in _dbDataDict) {
173 if (requestedUuid && ![requestedUuid isEqualToString:uuid]) {
174 os_log_info(AUTHD_LOG, "Requested volume %{public}@ so ignoring volume %{public}@", requestedUuid, uuid);
175 continue;
176 }
177 [allUsers addObjectsFromArray:_dbDataDict[uuid]];
178 }
179 return allUsers;
180 }
181 #pragma mark - Private Methods
182
183 - (void)processPrebootVolumes:(NSArray*)prebootVolumes currentRecoveryVolumeUUID:(NSUUID *)currentRecoveryVolumeUUID
184 {
185 // process each preboot volume
186 for (id prebootVolume in prebootVolumes) {
187
188 // mount the preboot volume. If it fails it could be already mounted. Try to get mountPoint anyway.
189 Boolean mounted = [self mountPrebootVolume:prebootVolume];
190
191 // get a mount point of the preboot volume
192 NSString* mountPoint = [self mountPointForPrebootVolume:prebootVolume];
193 if (!mountPoint) {
194 continue;
195 }
196
197 // process the preboot volume
198 NSDirectoryEnumerator *dirEnumerator = [[NSFileManager defaultManager] enumeratorAtURL:[NSURL fileURLWithPath:mountPoint isDirectory:YES] includingPropertiesForKeys:nil options:NSDirectoryEnumerationSkipsSubdirectoryDescendants errorHandler:nil];
199 for (NSURL *url in dirEnumerator) {
200 BOOL isDir = NO;
201 [[NSFileManager defaultManager] fileExistsAtPath:url.path isDirectory:&isDir];
202 if (!isDir) {
203 os_log_info(AUTHD_LOG, "Skipping file %{public}@ (not a directory)", url.path);
204 continue;
205 }
206
207 NSUUID* volumeUUID = [[NSUUID alloc] initWithUUIDString:url.lastPathComponent]; // the dir has the name as UUID
208 if (!volumeUUID) {
209 os_log_info(AUTHD_LOG, "Ignoring folder %{public}@ (not UUID)", url);
210 continue;
211 }
212
213 if (currentRecoveryVolumeUUID && ![currentRecoveryVolumeUUID isEqualTo:volumeUUID]) {
214 os_log_info(AUTHD_LOG, "The preboot volume skipped: %{public}@ (not the currentRecoveryVolumeUUID %{public}@)", url, currentRecoveryVolumeUUID);
215 continue;
216 }
217
218 [self processVolumeData:volumeUUID mountPoint:mountPoint];
219 }
220
221 // unmount the preboot volume
222 if (mounted) {
223 [self unmountPrebootVolume:prebootVolume];
224 }
225 }
226 }
227
228 #define kEFISystemVolumeUUIDVariableName "SystemVolumeUUID"
229 - (NSUUID *)currentRecoveryVolumeUUID
230 {
231 NSData *data;
232 NSString * const LANVRAMNamespaceStartupManager = @"5EEB160F-45FB-4CE9-B4E3-610359ABF6F8";
233
234 NSString *key = [NSString stringWithFormat:@"%@:%@", LANVRAMNamespaceStartupManager, @kEFISystemVolumeUUIDVariableName];
235
236 io_registry_entry_t match = IORegistryEntryFromPath(kIOMasterPortDefault, "IODeviceTree:/options");
237 if (match) {
238 CFTypeRef entry = IORegistryEntryCreateCFProperty(match, (__bridge CFStringRef)key, kCFAllocatorDefault, 0);
239 IOObjectRelease(match);
240
241 if (entry)
242 {
243 if (CFGetTypeID(entry) == CFDataGetTypeID())
244 data = CFBridgingRelease(entry);
245 else
246 CFRelease(entry);
247 }
248 }
249 os_log_info(AUTHD_LOG, "Current boot volume: %{public}@", data);
250
251 if (data) {
252 return [[NSUUID alloc] initWithUUIDBytes:data.bytes];
253 } else {
254 return nil;
255 }
256 }
257
258 - (NSArray *)allPrebootVolumes
259 {
260 NSMutableArray* result = [NSMutableArray new];
261
262 DMAPFS* dmAPFS = [[getDMAPFSClass() alloc] initWithManager:_diskMgr];
263
264 for (id tmp in _diskMgr.disks) {
265 DADiskRef diskRef = (__bridge DADiskRef)(tmp);
266 os_log_info(AUTHD_LOG, "Found disk %{public}@", diskRef);
267
268 BOOL preboot;
269 DMDiskErrorType diskErr = [dmAPFS isPrebootVolume:diskRef prebootRole:&preboot];
270 if (diskErr) {
271 os_log(AUTHD_LOG, "Failed to determine preboot state for %{public}@: %{public}@", diskRef, soft_DMUnlocalizedTechnicalErrorString(diskErr));
272 continue;
273 }
274 if (!preboot) {
275 os_log_info(AUTHD_LOG, "Not a preboot volume: %{public}@", diskRef);
276 continue;
277 }
278
279 id prebootVolume = CFBridgingRelease([_diskMgr copyBooterDiskForDisk:diskRef error:&diskErr]);
280 if (prebootVolume) {
281 os_log_info(AUTHD_LOG, "Found APFS preboot %{public}@", prebootVolume);
282 [result addObject:prebootVolume];
283 } else {
284 os_log_error(AUTHD_LOG, "Failed to copy preboot for disk %{public}@, err: %{public}@", diskRef, soft_DMUnlocalizedTechnicalErrorString(diskErr));
285 }
286 }
287
288 return result;
289 }
290
291 - (BOOL)mountPrebootVolume:(id)preboot
292 {
293 __block BOOL success = NO;
294 dispatch_semaphore_t sem = dispatch_semaphore_create(0);
295 AIRDBDACommonCompletionHandler completionHandler = ^(DADissenterRef dissenter) {
296 success = (dissenter == NULL);
297 if (dissenter != NULL) {
298 os_log(AUTHD_LOG, "Failed to mount preboot volume %{public}@ (status: 0x%x, reason: \"%{public}@\").", preboot, soft_DADissenterGetStatus(dissenter), soft_DADissenterGetStatusString(dissenter));
299 }
300 dispatch_semaphore_signal(sem);
301 };
302 soft_DADiskMount((__bridge DADiskRef _Nonnull)(preboot), NULL, kDADiskMountOptionDefault, _commonDACompletionCallback, (__bridge void * _Nullable)(completionHandler));
303 dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
304 return success;
305 }
306
307 - (NSString *)mountPointForPrebootVolume:(id)preboot
308 {
309 DMDiskErrorType diskErr;
310 NSString* result = [_diskMgr mountPointForDisk:(__bridge DADiskRef _Nonnull)(preboot) error:&diskErr];
311 if (result) {
312 os_log_info(AUTHD_LOG, "Mounted preboot partition %{public}@ at %{public}@", preboot, result);
313 } else {
314 os_log_error(AUTHD_LOG, "Failed to get preboot mount point: %{public}@", soft_DMUnlocalizedTechnicalErrorString(diskErr));
315 }
316 return result;
317 }
318
319 - (void)unmountPrebootVolume:(id)preboot
320 {
321 soft_DADiskUnmount((__bridge DADiskRef _Nonnull)(preboot), kDADiskUnmountOptionDefault, nil, nil);
322 os_log_info(AUTHD_LOG, "Preboot partition unmounted: %{public}@", preboot);
323 }
324
325 - (NSString *)deviceNodeForVolumeWithUUID:(NSUUID *)volumeUuid diskRef:(DADiskRef *)diskRef
326 {
327 DMDiskErrorType diskErr;
328 DADiskRef localDiskRef = [_diskMgr copyDiskForVolumeUUID:volumeUuid.UUIDString error:&diskErr];
329 if (!localDiskRef) {
330 os_log_error(AUTHD_LOG, "Failed to find disk with volume %{public}@: %{public}@", volumeUuid, soft_DMUnlocalizedTechnicalErrorString(diskErr));
331 return nil;
332 }
333 if (diskRef) {
334 *diskRef = localDiskRef;
335 CFRetain(*diskRef);
336 }
337 os_log_info(AUTHD_LOG, "Found disk %{public}@ with volume UUID %{public}@", localDiskRef, volumeUuid);
338 NSString* deviceNode = [self deviceNodeForDisk:localDiskRef];
339 CFRelease(localDiskRef);
340 return deviceNode;
341 }
342
343 - (NSString *)deviceNodeForDisk:(DADiskRef)diskRef
344 {
345 DMDiskErrorType diskErr;
346 NSString *deviceNode = [_diskMgr deviceNodeForDisk:diskRef error:&diskErr];
347 if (!deviceNode) {
348 os_log_error(AUTHD_LOG, "Failed to find device node for disk %{public}@: %{public}@", diskRef, soft_DMUnlocalizedTechnicalErrorString(diskErr));
349 return nil;
350 }
351 os_log_info(AUTHD_LOG, "Device node found: %{public}@", deviceNode);
352 return deviceNode;
353 }
354
355 - (NSData *)loadVEKforVolumeWithUUID:(NSUUID *)volumeUuid mountPoint:(NSString *)mountPoint
356 {
357 NSString *vekPath = [NSString stringWithFormat:kVekFile, mountPoint, volumeUuid.UUIDString];
358 NSDictionary *vekDict = [NSDictionary dictionaryWithContentsOfFile:vekPath];
359 NSData *vek = vekDict[kVekItemName];
360 if (!vek) {
361 os_log_error(AUTHD_LOG, "Failed to load DiskToken from %{public}@", vekPath);
362 return nil;
363 }
364 os_log_info(AUTHD_LOG, "Loaded DiskToken from %{public}@", vekPath);
365
366 return vek;
367 }
368
369 - (NSData *)loadKEKforUuid:(NSString *)userUuid deviceNode:(NSString *)deviceNode
370 {
371 NSUUID *nsUuid = [[NSUUID alloc] initWithUUIDString:userUuid];
372 uuid_t uuid;
373 [nsUuid getUUIDBytes:uuid];
374 CFDataRef dataCF;
375 errno_t err = soft_APFSVolumeGetUnlockRecord(deviceNode.UTF8String, uuid, &dataCF);
376 if(err != 0) {
377 os_log_error(AUTHD_LOG, "Failed to find SecureToken on device node %{public}@ and UUID %{public}@ (%d)", deviceNode, userUuid, err);
378 return nil;
379 }
380 os_log_info(AUTHD_LOG, "Loaded SecureToken from device node %{public}@", deviceNode);
381
382 NSData *kek = CFBridgingRelease(dataCF);
383 return kek;
384 }
385
386 - (NSDictionary *)loadUserDatabaseForVolumeUUID:(NSUUID *)volumeUuid mountPoint:(NSString *)mountPoint
387 {
388 NSString *usersPath = [NSString stringWithFormat:kUsersFile, mountPoint, volumeUuid.UUIDString];
389 NSDictionary *users = [NSDictionary dictionaryWithContentsOfFile:usersPath];
390 if (users.count == 0) {
391 os_log_error(AUTHD_LOG, "Failed to find user records in file %{public}@", usersPath);
392 return nil;
393 }
394 os_log_debug(AUTHD_LOG, "Loaded %lu user records from file %{public}@", (unsigned long)users.count, usersPath);
395 return users;
396 }
397
398 - (void)processVolumeData:(NSUUID *)volumeUuid mountPoint:(NSString *)mountPoint
399 {
400 os_log_info(AUTHD_LOG, "Processing volume data: %{public}@", volumeUuid);
401 NSData *vek = [self loadVEKforVolumeWithUUID:volumeUuid mountPoint:mountPoint];
402 if (!vek) {
403 return;
404 }
405
406 DADiskRef cfDiskRef = NULL;
407 NSString* deviceNode = [self deviceNodeForVolumeWithUUID:volumeUuid diskRef:&cfDiskRef];
408 id diskRef = CFBridgingRelease(cfDiskRef);
409 if (!deviceNode) {
410 return;
411 }
412 NSString *volumeGroupUuid;
413 DMAPFS* dmAPFS = [[getDMAPFSClass() alloc] initWithManager:_diskMgr];
414 DMDiskErrorType diskErr = [dmAPFS volumeGroupForVolume:(__bridge DADiskRef _Nonnull)(diskRef) id:&volumeGroupUuid];
415 if (diskErr != kDiskErrorNoError || volumeGroupUuid == nil) {
416 os_log_error(AUTHD_LOG, "Error %d while trying to get volume group for %{public}@", diskErr, volumeUuid);
417 } else {
418 if ([volumeUuid.UUIDString isEqualTo:volumeGroupUuid]) {
419 NSArray *systemVolumeDisks = nil;
420 diskErr = [dmAPFS disksForVolumeGroup:volumeGroupUuid volumeDisks:nil systemVolumeDisks:&systemVolumeDisks dataVolumeDisks:nil userVolumeDisks:nil container:nil];
421 if (diskErr != kDiskErrorNoError || systemVolumeDisks == nil) {
422 os_log_error(AUTHD_LOG, "Error %d while trying to get volume group disks for %{public}@", diskErr, volumeGroupUuid);
423 } else {
424 // There should be only one systemVolume, but the API returns an array so we'll process as many as it wants to give us
425 for (id tmp in systemVolumeDisks) {
426 DADiskRef systemVolumeDiskRef = (__bridge DADiskRef)(tmp);
427 NSString *systemVolumeUuid = nil;
428 diskErr = [dmAPFS volumeUUIDForVolume:systemVolumeDiskRef UUID:&systemVolumeUuid];
429 if (diskErr != kDiskErrorNoError || systemVolumeUuid == nil) {
430 os_log_error(AUTHD_LOG, "Error %d while trying to get volume uuid disks for some system volumes of group %{public}@", diskErr, volumeGroupUuid);
431 } else {
432 os_log(AUTHD_LOG, "Volume %{public}@ belongs to the group %{public}@", systemVolumeUuid, volumeGroupUuid);
433 _dbVolumeGroupMap[systemVolumeUuid] = volumeGroupUuid;
434 }
435 }
436 }
437 }
438 }
439
440 NSDictionary *users = [self loadUserDatabaseForVolumeUUID:volumeUuid mountPoint:mountPoint];
441 for (NSString *userName in users) {
442 NSDictionary *userData = users[userName];
443 os_log_debug(AUTHD_LOG, "Processing user: %{public}@", userData);
444 NSString *userGuid = userData[kGUIDItemName];
445 if (userGuid == nil) {
446 os_log_error(AUTHD_LOG, "Failed to find GUID for user %{public}@", userName);
447 continue;
448 }
449 NSData* kek = [self loadKEKforUuid:userGuid deviceNode:deviceNode];
450 if (!kek) {
451 os_log_error(AUTHD_LOG, "Failed to find SecureToken for user %{public}@", userName);
452 continue;
453 }
454
455 NSArray *aauthority = userData[kAuthenticationAuthority];
456 NSMutableDictionary *dict = @{}.mutableCopy;
457 if (aauthority) {
458 dict[@PLUDB_SCPAIR] = aauthority;
459 os_log_debug(AUTHD_LOG, "Using authority: %{public}@", aauthority);
460 }
461
462 Boolean owner;
463 struct aks_fv_param_s params = {};
464 aks_fv_blob_state_s verifier_state = {};
465 struct aks_fv_data_s kekData = { .data = (void *)kek.bytes, .len = kek.length };
466
467 int res = aks_fv_get_blob_state(&params, &kekData, &verifier_state);
468 if (res) {
469 os_log_error(AUTHD_LOG, "Blob state failed: %x", res);
470 owner = NO;
471 } else {
472 owner = ((verifier_state.flags & aks_fv_state_is_owner) == aks_fv_state_is_owner);
473 }
474
475 dict[@PLUDB_USERNAME] = userName;
476 dict[@PLUDB_GUID] = userGuid;
477 dict[@PLUDB_ADMIN] = userData[kIsAdmintemName];
478 dict[@PLUDB_KEK] = kek;
479 dict[@PLUDB_VEK] = vek;
480 dict[@PLUDB_DNODE] = deviceNode;
481 dict[@PLUDB_OWNER] = @(owner);
482
483 if ([userData.allKeys containsObject:kSCUnlockDataItemName]) {
484 dict[@PLUDB_SCUNLOCK_DATA] = userData[kSCUnlockDataItemName];
485 }
486 if ([userData.allKeys containsObject:kSCEnforcementItemName]) {
487 dict[@PLUDB_SCUNLOCK_DATA] = userData[kSCEnforcementItemName];
488 }
489 if ([userData.allKeys containsObject:kSCUnlockDataItemName]) {
490 dict[@PLUDB_SCUNLOCK_DATA] = userData[kSCUnlockDataItemName];
491 }
492 if ([userData.allKeys containsObject:kSCUacItemName]) {
493 dict[@PLUDB_SCUAC] = userData[kSCUacItemName];
494 }
495 if ([userData.allKeys containsObject:kLongNameItemName]) {
496 dict[@PLUDB_LUSERNAME] = userData[kLongNameItemName];
497 }
498
499 NSMutableArray *array = _dbDataDict[volumeUuid.UUIDString];
500 if (array == nil) {
501 array = [NSMutableArray new];
502 if (!array) {
503 os_log_error(AUTHD_LOG, "Failed to create users array");
504 return;
505 }
506 _dbDataDict[volumeUuid.UUIDString] = array;
507 }
508
509 os_log_info(AUTHD_LOG, "Prelogin UserDB added entry: %{public}@", dict);
510 [array addObject:dict];
511 }
512 }
513
514 @end
515
516 OSStatus preloginudb_copy_userdb(const char *uuid, UInt32 flags, CFArrayRef *output)
517 {
518 if (!output) {
519 return errAuthorizationBadAddress;
520 }
521 static PreloginUserDb *database;
522 static OSStatus loadError = errAuthorizationSuccess;
523 static dispatch_once_t onceToken;
524
525 dispatch_once(&onceToken, ^{
526
527 os_log_info(AUTHD_LOG, "Going to load User DB");
528
529 database = [[PreloginUserDb alloc] init];
530 if (!database) {
531 loadError = errAuthorizationInvalidSet;
532 } else {
533 NSError *error;
534 if ([database loadWithError:&error]) {
535 loadError = (int)error.code;
536 }
537 }
538 });
539
540 if (loadError) {
541 return loadError;
542 }
543
544 os_log_debug(AUTHD_LOG, "Processing user db for volume %{public}s with flags %d", uuid, flags);
545
546 *output = CFBridgingRetain([database users:uuid ? [NSString stringWithUTF8String:uuid] : nil]);
547 return errAuthorizationSuccess;
548 }