1/*
2 * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24//
25//  SecAKSWrappers.c
26//  utilities
27//
28
29#include <utilities/SecAKSWrappers.h>
30#include <utilities/SecCFWrappers.h>
31
32#if TARGET_IPHONE_SIMULATOR
33#  define change_notification "com.apple.will.never.happen"
34#elif TARGET_OS_IPHONE
35#  include <MobileKeyBag/MobileKeyBag.h>
36#  define change_notification kMobileKeyBagLockStatusNotificationID
37#elif TARGET_OS_MAC
38#  include <AppleKeyStoreEvents.h>
39#  define change_notification kAppleKeyStoreLockStatusNotificationID
40#else
41#  error "unsupported target platform"
42#endif
43
44const char * const kUserKeybagStateChangeNotification = change_notification;
45
46bool SecAKSDoWhileUserBagLocked(CFErrorRef *error, dispatch_block_t action)
47{
48#if TARGET_IPHONE_SIMULATOR
49    action();
50    return true;
51#else
52    // Acquire lock assertion, ref count?
53
54    __block kern_return_t status = kIOReturnSuccess;
55    static dispatch_once_t queue_once;
56    static dispatch_queue_t assertion_queue;
57
58#if TARGET_OS_MAC && !TARGET_OS_EMBEDDED                            // OS X
59    AKSAssertionType_t lockAssertType = kAKSAssertTypeOther;
60    keybag_handle_t keybagHandle = session_keybag_handle;
61#else                                                               // iOS, but not simulator
62    AKSAssertionType_t lockAssertType = kAKSAssertTypeProfile;      // Profile supports timeouts, but only available on iOS
63    keybag_handle_t keybagHandle = device_keybag_handle;
64#endif
65
66    dispatch_once(&queue_once, ^{
67        assertion_queue = dispatch_queue_create("AKS Lock Assertion Queue", NULL);
68    });
69
70    static uint32_t count = 0;
71
72    dispatch_sync(assertion_queue, ^{
73        if (count == 0) {
74            uint64_t timeout = 60ull;
75            secnotice("lockassertions", "Requesting lock assertion for %lld seconds", timeout);
76            status = aks_assert_hold(keybagHandle, lockAssertType, timeout);
77        }
78
79        if (status == kIOReturnSuccess)
80            ++count;
81    });
82
83    if (status == kIOReturnSuccess) {
84        action();
85        dispatch_sync(assertion_queue, ^{
86            if (count && (--count == 0)) {
87                secnotice("lockassertions", "Dropping lock assertion");
88                status = aks_assert_drop(keybagHandle, lockAssertType);
89            }
90        });
91    }
92    return SecKernError(status, error, CFSTR("Kern return error"));
93#endif  /* !TARGET_IPHONE_SIMULATOR */
94}
95