├── LICENSE
├── README.md
├── images
├── t2s-1.png
├── t2s-2.png
└── t2s-3.png
├── touch2sudo.xcodeproj
├── project.pbxproj
└── project.xcworkspace
│ └── contents.xcworkspacedata
└── touch2sudo
└── main.m
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2019, NVIDIA Corporation
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | * Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | # touch2sudo
6 |
7 |
8 |
9 |
10 |
11 | `touch2sudo` is a standalone program if executed authenticates the user either through Touch ID or password. A successful authentication (confirmation) is signaled by a zero exit status from touch2sudo program.
12 | To authenticate sudo commands, we configure touch2sudo as `SSH_ASKPASS` confirmation program, invoked by ssh-agent.
13 |
14 | Infact this program can be used for any application that requires user authentication on Mac
15 |
16 | ## Mac configuration
17 |
18 | *Fingerprint authentication is done locally on Mac, but it acts as a gating mechanism for remote sudo authentication.*
19 |
20 | If you haven't setup Touch ID, you can find the instructions from Apple [here](https://support.apple.com/en-us/HT207054)
21 |
22 | ## touch2sudo installation
23 |
24 | You have two options:
25 | * Install `touch2sudo` binary using `brew` (OR)
26 | * Build from source
27 |
28 | ### Install using brew
29 |
30 | ```sh
31 | brew tap prbinu/touch2sudo
32 | brew install touch2sudo
33 | ```
34 |
35 | ### Build from source
36 |
37 | ```sh
38 | git clone https://github.com/prbinu/touch2sudo
39 | ```
40 |
41 | **Steps**
42 |
43 | 1. Open `touch2sudo.xcodeproj` file using [Xcode](https://developer.apple.com/xcode/)
44 |
45 | 2. Build: (*Product -> Build*) If the build is successful, you may see this dialog:
46 |
47 |
48 |
49 |
50 |
51 |
52 | 3. Archive: (*Product -> Archive -> Distribute Content -> Build Products -> Next -> Save*) Save the archive folder. The touch2sudo executable will be in the `/Product/usr/local/bin` path.
53 |
54 | 4. Install: Copy `touch2sudo` binary to `/usr/local/bin`
55 |
56 | 5. Run: `touch2sudo`
57 |
58 |
59 | ## Configure ssh-agent with touch2sudo
60 |
61 | Generate a new SSH key pair for sudo:
62 |
63 | ```sh
64 | $ ssh-keygen -t rsa -b 2048
65 | Generating public/private rsa key pair.
66 | Enter file in which to save the key (/Users/binu/.ssh/id_rsa): /Users/binu/.ssh/id_rsa_sudo
67 | Enter passphrase (empty for no passphrase):
68 | Enter same passphrase again:
69 | Your identification has been saved in /Users/binu/.ssh/id_rsa_sudo.
70 | Your public key has been saved in /Users/binu/.ssh/id_rsa_sudo.pub.
71 | The key fingerprint is:
72 | SHA256:6Vf0p0iUzQaiXqjQlUU+BYeTGiQqzUeC7z7iBNg7alE binu@localhostThe key's randomart image is:
73 | + - -[RSA 2048] - - +
74 | | .. o.o+=++ |
75 | | .o = oo+++ = |
76 | | ..= o oo+.+ + |
77 | |.. E.o o.o + o |
78 | |o o. . S o . .|
79 | | o .. . o . o |
80 | | =. . . . . |
81 | | +..o . |
82 | |o… . |
83 | + - - [SHA256] - - -+
84 | ```
85 |
86 | Start `ssh-agent`
87 |
88 | ```sh
89 | $ export SSH_ASKPASS=/usr/local/bin/touch2sudo
90 | $ export DISPLAY=0
91 | $ eval $(ssh-agent)
92 | Agent pid 51863
93 |
94 | $ ssh-add -L
95 | The agent has no identities.
96 |
97 | $ env | grep SSH
98 | SSH_AGENT_PID=51863
99 | SSH_AUTH_SOCK=/var/folders/hm/x1_38yz53td1jty5xgs39dxm2lm58d/T//ssh-JssXsflTuHrC/agent.51862
100 | SSH_ASKPASS=/usr/local/bin/touch2sudo
101 |
102 | $ ssh-add -c id_rsa_sudo
103 | Identity added: id_rsa_sudo (binu-sudo@binu.local)
104 | The user must confirm each use of the key
105 | ```
106 |
107 | To make it work, on remote server you need to configure `pam-ssh-agent-auth` - a PAM module that does SSH key authentication for sudo.
108 | pam-ssh-agent-auth is based on SSH *agent-forwarding* feature that allow the PAM module to authenticate sudo command using key cached in ssh-agent running on your workstation (Mac).
109 |
110 | **SSH Agent Forwarding Security**
111 | To avoid exposure of other keys in your local ssh-agent to the connecting host, you may a use a seperate SSH key (for sudo) with a dedicated `ssh-agent` for agent-forwarding. Use [`ForwardAgent`](https://man.openbsd.org/ssh_config#ForwardAgent) option to pass the path/env-var of this sudo ssh-agent.
112 |
113 | For the complete information on end to end setup, refer:
114 | https://medium.com/@prbinu/touch2sudo-enable-remote-sudo-two-factor-authentication-using-mac-touch-id-df638b7da594
115 |
116 |
--------------------------------------------------------------------------------
/images/t2s-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prbinu/touch2sudo/11f643e34cd90b3764e0b34269449f5d682e5acd/images/t2s-1.png
--------------------------------------------------------------------------------
/images/t2s-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prbinu/touch2sudo/11f643e34cd90b3764e0b34269449f5d682e5acd/images/t2s-2.png
--------------------------------------------------------------------------------
/images/t2s-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prbinu/touch2sudo/11f643e34cd90b3764e0b34269449f5d682e5acd/images/t2s-3.png
--------------------------------------------------------------------------------
/touch2sudo.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 2FC7505721D95A1E007B32AC /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FC7505621D95A1E007B32AC /* main.m */; };
11 | /* End PBXBuildFile section */
12 |
13 | /* Begin PBXCopyFilesBuildPhase section */
14 | 2FC7505121D95A1E007B32AC /* CopyFiles */ = {
15 | isa = PBXCopyFilesBuildPhase;
16 | buildActionMask = 2147483647;
17 | dstPath = /usr/share/man/man1/;
18 | dstSubfolderSpec = 0;
19 | files = (
20 | );
21 | runOnlyForDeploymentPostprocessing = 1;
22 | };
23 | /* End PBXCopyFilesBuildPhase section */
24 |
25 | /* Begin PBXFileReference section */
26 | 2FC7505321D95A1E007B32AC /* touch2sudo */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = touch2sudo; sourceTree = BUILT_PRODUCTS_DIR; };
27 | 2FC7505621D95A1E007B32AC /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
28 | /* End PBXFileReference section */
29 |
30 | /* Begin PBXFrameworksBuildPhase section */
31 | 2FC7505021D95A1E007B32AC /* Frameworks */ = {
32 | isa = PBXFrameworksBuildPhase;
33 | buildActionMask = 2147483647;
34 | files = (
35 | );
36 | runOnlyForDeploymentPostprocessing = 0;
37 | };
38 | /* End PBXFrameworksBuildPhase section */
39 |
40 | /* Begin PBXGroup section */
41 | 2FC7504A21D95A1E007B32AC = {
42 | isa = PBXGroup;
43 | children = (
44 | 2FC7505521D95A1E007B32AC /* touch2sudo */,
45 | 2FC7505421D95A1E007B32AC /* Products */,
46 | );
47 | sourceTree = "";
48 | };
49 | 2FC7505421D95A1E007B32AC /* Products */ = {
50 | isa = PBXGroup;
51 | children = (
52 | 2FC7505321D95A1E007B32AC /* touch2sudo */,
53 | );
54 | name = Products;
55 | sourceTree = "";
56 | };
57 | 2FC7505521D95A1E007B32AC /* touch2sudo */ = {
58 | isa = PBXGroup;
59 | children = (
60 | 2FC7505621D95A1E007B32AC /* main.m */,
61 | );
62 | path = touch2sudo;
63 | sourceTree = "";
64 | };
65 | /* End PBXGroup section */
66 |
67 | /* Begin PBXNativeTarget section */
68 | 2FC7505221D95A1E007B32AC /* touch2sudo */ = {
69 | isa = PBXNativeTarget;
70 | buildConfigurationList = 2FC7505A21D95A1E007B32AC /* Build configuration list for PBXNativeTarget "touch2sudo" */;
71 | buildPhases = (
72 | 2FC7504F21D95A1E007B32AC /* Sources */,
73 | 2FC7505021D95A1E007B32AC /* Frameworks */,
74 | 2FC7505121D95A1E007B32AC /* CopyFiles */,
75 | );
76 | buildRules = (
77 | );
78 | dependencies = (
79 | );
80 | name = touch2sudo;
81 | productName = touch2sudo;
82 | productReference = 2FC7505321D95A1E007B32AC /* touch2sudo */;
83 | productType = "com.apple.product-type.tool";
84 | };
85 | /* End PBXNativeTarget section */
86 |
87 | /* Begin PBXProject section */
88 | 2FC7504B21D95A1E007B32AC /* Project object */ = {
89 | isa = PBXProject;
90 | attributes = {
91 | LastUpgradeCheck = 1010;
92 | ORGANIZATIONNAME = "Binu Ramakrishnan";
93 | TargetAttributes = {
94 | 2FC7505221D95A1E007B32AC = {
95 | CreatedOnToolsVersion = 10.1;
96 | };
97 | };
98 | };
99 | buildConfigurationList = 2FC7504E21D95A1E007B32AC /* Build configuration list for PBXProject "touch2sudo" */;
100 | compatibilityVersion = "Xcode 9.3";
101 | developmentRegion = en;
102 | hasScannedForEncodings = 0;
103 | knownRegions = (
104 | en,
105 | );
106 | mainGroup = 2FC7504A21D95A1E007B32AC;
107 | productRefGroup = 2FC7505421D95A1E007B32AC /* Products */;
108 | projectDirPath = "";
109 | projectRoot = "";
110 | targets = (
111 | 2FC7505221D95A1E007B32AC /* touch2sudo */,
112 | );
113 | };
114 | /* End PBXProject section */
115 |
116 | /* Begin PBXSourcesBuildPhase section */
117 | 2FC7504F21D95A1E007B32AC /* Sources */ = {
118 | isa = PBXSourcesBuildPhase;
119 | buildActionMask = 2147483647;
120 | files = (
121 | 2FC7505721D95A1E007B32AC /* main.m in Sources */,
122 | );
123 | runOnlyForDeploymentPostprocessing = 0;
124 | };
125 | /* End PBXSourcesBuildPhase section */
126 |
127 | /* Begin XCBuildConfiguration section */
128 | 2FC7505821D95A1E007B32AC /* Debug */ = {
129 | isa = XCBuildConfiguration;
130 | buildSettings = {
131 | ALWAYS_SEARCH_USER_PATHS = NO;
132 | CLANG_ANALYZER_NONNULL = YES;
133 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
134 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
135 | CLANG_CXX_LIBRARY = "libc++";
136 | CLANG_ENABLE_MODULES = YES;
137 | CLANG_ENABLE_OBJC_ARC = YES;
138 | CLANG_ENABLE_OBJC_WEAK = YES;
139 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
140 | CLANG_WARN_BOOL_CONVERSION = YES;
141 | CLANG_WARN_COMMA = YES;
142 | CLANG_WARN_CONSTANT_CONVERSION = YES;
143 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
144 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
145 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
146 | CLANG_WARN_EMPTY_BODY = YES;
147 | CLANG_WARN_ENUM_CONVERSION = YES;
148 | CLANG_WARN_INFINITE_RECURSION = YES;
149 | CLANG_WARN_INT_CONVERSION = YES;
150 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
151 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
152 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
153 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
154 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
155 | CLANG_WARN_STRICT_PROTOTYPES = YES;
156 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
157 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
158 | CLANG_WARN_UNREACHABLE_CODE = YES;
159 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
160 | CODE_SIGN_IDENTITY = "-";
161 | COPY_PHASE_STRIP = NO;
162 | DEBUG_INFORMATION_FORMAT = dwarf;
163 | ENABLE_STRICT_OBJC_MSGSEND = YES;
164 | ENABLE_TESTABILITY = YES;
165 | GCC_C_LANGUAGE_STANDARD = gnu11;
166 | GCC_DYNAMIC_NO_PIC = NO;
167 | GCC_NO_COMMON_BLOCKS = YES;
168 | GCC_OPTIMIZATION_LEVEL = 0;
169 | GCC_PREPROCESSOR_DEFINITIONS = (
170 | "DEBUG=1",
171 | "$(inherited)",
172 | );
173 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
174 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
175 | GCC_WARN_UNDECLARED_SELECTOR = YES;
176 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
177 | GCC_WARN_UNUSED_FUNCTION = YES;
178 | GCC_WARN_UNUSED_VARIABLE = YES;
179 | MACOSX_DEPLOYMENT_TARGET = 10.13;
180 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
181 | MTL_FAST_MATH = YES;
182 | ONLY_ACTIVE_ARCH = YES;
183 | SDKROOT = macosx;
184 | };
185 | name = Debug;
186 | };
187 | 2FC7505921D95A1E007B32AC /* Release */ = {
188 | isa = XCBuildConfiguration;
189 | buildSettings = {
190 | ALWAYS_SEARCH_USER_PATHS = NO;
191 | CLANG_ANALYZER_NONNULL = YES;
192 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
193 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
194 | CLANG_CXX_LIBRARY = "libc++";
195 | CLANG_ENABLE_MODULES = YES;
196 | CLANG_ENABLE_OBJC_ARC = YES;
197 | CLANG_ENABLE_OBJC_WEAK = YES;
198 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
199 | CLANG_WARN_BOOL_CONVERSION = YES;
200 | CLANG_WARN_COMMA = YES;
201 | CLANG_WARN_CONSTANT_CONVERSION = YES;
202 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
203 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
204 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
205 | CLANG_WARN_EMPTY_BODY = YES;
206 | CLANG_WARN_ENUM_CONVERSION = YES;
207 | CLANG_WARN_INFINITE_RECURSION = YES;
208 | CLANG_WARN_INT_CONVERSION = YES;
209 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
210 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
211 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
212 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
213 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
214 | CLANG_WARN_STRICT_PROTOTYPES = YES;
215 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
216 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
217 | CLANG_WARN_UNREACHABLE_CODE = YES;
218 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
219 | CODE_SIGN_IDENTITY = "-";
220 | COPY_PHASE_STRIP = NO;
221 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
222 | ENABLE_NS_ASSERTIONS = NO;
223 | ENABLE_STRICT_OBJC_MSGSEND = YES;
224 | GCC_C_LANGUAGE_STANDARD = gnu11;
225 | GCC_NO_COMMON_BLOCKS = YES;
226 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
227 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
228 | GCC_WARN_UNDECLARED_SELECTOR = YES;
229 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
230 | GCC_WARN_UNUSED_FUNCTION = YES;
231 | GCC_WARN_UNUSED_VARIABLE = YES;
232 | MACOSX_DEPLOYMENT_TARGET = 10.13;
233 | MTL_ENABLE_DEBUG_INFO = NO;
234 | MTL_FAST_MATH = YES;
235 | SDKROOT = macosx;
236 | };
237 | name = Release;
238 | };
239 | 2FC7505B21D95A1E007B32AC /* Debug */ = {
240 | isa = XCBuildConfiguration;
241 | buildSettings = {
242 | CODE_SIGN_STYLE = Automatic;
243 | PRODUCT_NAME = "$(TARGET_NAME)";
244 | };
245 | name = Debug;
246 | };
247 | 2FC7505C21D95A1E007B32AC /* Release */ = {
248 | isa = XCBuildConfiguration;
249 | buildSettings = {
250 | CODE_SIGN_STYLE = Automatic;
251 | PRODUCT_NAME = "$(TARGET_NAME)";
252 | };
253 | name = Release;
254 | };
255 | /* End XCBuildConfiguration section */
256 |
257 | /* Begin XCConfigurationList section */
258 | 2FC7504E21D95A1E007B32AC /* Build configuration list for PBXProject "touch2sudo" */ = {
259 | isa = XCConfigurationList;
260 | buildConfigurations = (
261 | 2FC7505821D95A1E007B32AC /* Debug */,
262 | 2FC7505921D95A1E007B32AC /* Release */,
263 | );
264 | defaultConfigurationIsVisible = 0;
265 | defaultConfigurationName = Release;
266 | };
267 | 2FC7505A21D95A1E007B32AC /* Build configuration list for PBXNativeTarget "touch2sudo" */ = {
268 | isa = XCConfigurationList;
269 | buildConfigurations = (
270 | 2FC7505B21D95A1E007B32AC /* Debug */,
271 | 2FC7505C21D95A1E007B32AC /* Release */,
272 | );
273 | defaultConfigurationIsVisible = 0;
274 | defaultConfigurationName = Release;
275 | };
276 | /* End XCConfigurationList section */
277 | };
278 | rootObject = 2FC7504B21D95A1E007B32AC /* Project object */;
279 | }
280 |
--------------------------------------------------------------------------------
/touch2sudo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/touch2sudo/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // touch2sudo
4 | //
5 | // Created by Binu Ramakrishnan on 12/30/18.
6 | // Copyright (c) 2018 NVIDIA CORPORATION. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import
12 |
13 | int main(int argc, const char * argv[]) {
14 | @autoreleasepool {
15 |
16 | if ((argc == 2) && (strncmp(argv[1], "-h", strlen("-h")) == 0)) {
17 | printf("Usage: touch2sudo -reason \n");
18 | printf(" -reason The app-provided reason for requesting authentication,\n");
19 | printf(" which displays in the authentication dialog presented to the user\n");
20 | printf(" -h Help!\n");
21 | return 1;
22 | }
23 | NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
24 | NSString *reason = ([standardDefaults stringForKey:@"reason"] != NULL) ?
25 | [standardDefaults stringForKey:@"reason"]: @"perform an action that requires authentication";
26 |
27 | // SSH_ASKPASS format
28 | if (([standardDefaults stringForKey:@"reason"] == NULL) && (argc == 2)) {
29 | NSString *arg = [NSString stringWithUTF8String: argv[1]];
30 | NSArray *listItems = [arg componentsSeparatedByString:@"Key fingerprint "];
31 | if ((listItems.count == 2) && ([listItems[1] hasPrefix:@"SHA256:"])) {
32 | reason = [reason stringByAppendingString:@"\n\n"];
33 | reason = [reason stringByAppendingString:listItems[0]];
34 | reason = [reason stringByAppendingString:@"\n\nKey fingerprint: "];
35 | reason = [reason stringByAppendingString:listItems[1]];
36 | }
37 | }
38 |
39 | __block int result = 1;
40 | LAContext *context = [[LAContext alloc] init];
41 | dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
42 | [context evaluatePolicy: kLAPolicyDeviceOwnerAuthentication localizedReason: reason
43 | reply:^(BOOL success, NSError * _Nullable error) {
44 | if (success) {
45 | result = 0;
46 | }
47 | else {
48 | NSLog(@"%s\n", error.localizedDescription.UTF8String);
49 | result = 1;
50 | }
51 |
52 | dispatch_semaphore_signal(semaphore);
53 | }];
54 |
55 | dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
56 | return result;
57 | }
58 | }
59 |
60 |
--------------------------------------------------------------------------------