]> git.saurik.com Git - apple/security.git/blob - KVSKeychainSyncingProxy/CKDAKSLockMonitor.m
Security-59754.80.3.tar.gz
[apple/security.git] / KVSKeychainSyncingProxy / CKDAKSLockMonitor.m
1 //
2 // CKDAKSLockMonitor.m
3 // Security
4 //
5 // Created by Mitch Adler on 11/2/16.
6 //
7 //
8
9 #import <Foundation/Foundation.h>
10
11 #import "CKDAKSLockMonitor.h"
12
13 #include <utilities/SecCFRelease.h>
14 #include <utilities/SecAKSWrappers.h>
15 #include <utilities/debugging.h>
16
17 #include <notify.h>
18
19 @interface CKDAKSLockMonitor ()
20
21 @property XPCNotificationDispatcher* dispatcher;
22 @property XPCNotificationBlock notificationBlock;
23 @property dispatch_queue_t queue;
24
25 @end
26
27 @implementation CKDAKSLockMonitor
28
29 + (instancetype) monitor {
30 return [[CKDAKSLockMonitor alloc] init];
31 }
32
33 - (instancetype)init {
34 if ((self = [super init])) {
35 XPCNotificationDispatcher* dispatcher = [XPCNotificationDispatcher dispatcher];
36
37 _queue = dispatch_queue_create("CKDAKSLockMonitor", NULL);
38 _locked = true;
39 _unlockedSinceBoot = false;
40
41 /* also use dispatch to make sure */
42 int token = 0;
43 __weak typeof(self) weakSelf = self;
44 notify_register_dispatch(kUserKeybagStateChangeNotification, &token, _queue, ^(int t) {
45 [weakSelf _onqueueRecheck];
46 });
47
48 [self recheck];
49
50 [dispatcher addListener: self];
51 }
52
53 return self;
54 }
55
56 - (void) handleNotification:(const char *)name {
57 if (strcmp(name, kUserKeybagStateChangeNotification) == 0 || strcmp(name, "com.apple.mobile.keybagd.lock_status") == 0) {
58 [self recheck];
59 }
60 }
61
62 - (void) notifyListener {
63 // Take a strong reference:
64 __strong __typeof(self.listener) listener = self.listener;
65
66 if (listener) {
67 if (self.locked) {
68 [listener locked];
69 } else {
70 [listener unlocked];
71 }
72 }
73 }
74
75 - (void)connectTo: (NSObject<CKDLockListener>*) listener {
76 _listener = listener;
77 [self notifyListener];
78 }
79
80 - (void) recheck {
81 dispatch_async(_queue, ^{
82 [self _onqueueRecheck];
83 });
84 }
85
86 - (void) _onqueueRecheck {
87 dispatch_assert_queue(_queue);
88 CFErrorRef aksError = NULL;
89 bool locked = true; // Assume locked if we get an error
90
91 if (!SecAKSGetIsLocked(&locked, &aksError)) {
92 secerror("%@ Got error querying lock state: %@", self, aksError);
93 CFReleaseSafe(aksError);
94 }
95
96 BOOL previousLocked = self.locked;
97 _locked = locked;
98
99 if (!self.locked) {
100 _unlockedSinceBoot = true;
101 }
102
103 if (previousLocked != self.locked) {
104 // recheck might get called from ckdkvsproxy_queue (see 30510390)
105 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
106 [self notifyListener];
107 });
108 }
109 }
110
111 @end