[WTF] Use Semaphore and BinarySemaphore instead of dispatch_semaphore_t
[WebKit-https.git] / Source / WebKit / Shared / mac / SecItemShim.cpp
1 /*
2  * Copyright (C) 2011-2018 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "SecItemShim.h"
28
29 #if ENABLE(SEC_ITEM_SHIM)
30
31 #include "BlockingResponseMap.h"
32 #include "ChildProcess.h"
33 #include "SecItemRequestData.h"
34 #include "SecItemResponseData.h"
35 #include "SecItemShimLibrary.h"
36 #include "SecItemShimProxyMessages.h"
37 #include <Security/Security.h>
38 #include <atomic>
39 #include <dlfcn.h>
40 #include <mutex>
41 #include <wtf/ProcessPrivilege.h>
42 #include <wtf/threads/BinarySemaphore.h>
43
44 #if USE(APPLE_INTERNAL_SDK)
45 #include <CFNetwork/CFURLConnectionPriv.h>
46 #else
47 struct _CFNFrameworksStubs {
48     CFIndex version;
49
50     OSStatus (*SecItem_stub_CopyMatching)(CFDictionaryRef query, CFTypeRef *result);
51     OSStatus (*SecItem_stub_Add)(CFDictionaryRef attributes, CFTypeRef *result);
52     OSStatus (*SecItem_stub_Update)(CFDictionaryRef query, CFDictionaryRef attributesToUpdate);
53     OSStatus (*SecItem_stub_Delete)(CFDictionaryRef query);
54 };
55 #endif
56
57 extern "C" void _CFURLConnectionSetFrameworkStubs(const struct _CFNFrameworksStubs* stubs);
58
59 namespace WebKit {
60
61 static ChildProcess* sharedProcess;
62
63 static WorkQueue& workQueue()
64 {
65     static WorkQueue* workQueue;
66     static dispatch_once_t onceToken;
67     dispatch_once(&onceToken, ^{
68         workQueue = &WorkQueue::create("com.apple.WebKit.SecItemShim").leakRef();
69
70     });
71
72     return *workQueue;
73 }
74
75 static std::optional<SecItemResponseData> sendSecItemRequest(SecItemRequestData::Type requestType, CFDictionaryRef query, CFDictionaryRef attributesToMatch = 0)
76 {
77     std::optional<SecItemResponseData> response;
78
79     BinarySemaphore semaphore;
80
81     sharedProcess->parentProcessConnection()->sendWithReply(Messages::SecItemShimProxy::SecItemRequest(SecItemRequestData(requestType, query, attributesToMatch)), 0, workQueue(), [&response, &semaphore](auto reply) {
82         if (reply)
83             response = WTFMove(std::get<0>(*reply));
84
85         semaphore.signal();
86     });
87
88     semaphore.wait();
89
90     return response;
91 }
92
93 static OSStatus webSecItemCopyMatching(CFDictionaryRef query, CFTypeRef* result)
94 {
95     auto response = sendSecItemRequest(SecItemRequestData::CopyMatching, query);
96     if (!response)
97         return errSecInteractionNotAllowed;
98
99     *result = response->resultObject().leakRef();
100     return response->resultCode();
101 }
102
103 static OSStatus webSecItemAdd(CFDictionaryRef query, CFTypeRef* unusedResult)
104 {
105     // Return value of SecItemAdd should be ignored for WebKit use cases. WebKit can't serialize SecKeychainItemRef, so we do not use it.
106     // If someone passes a result value to be populated, the API contract is being violated so we should assert.
107     if (unusedResult) {
108         ASSERT_NOT_REACHED();
109         return errSecParam;
110     }
111
112     auto response = sendSecItemRequest(SecItemRequestData::Add, query);
113     if (!response)
114         return errSecInteractionNotAllowed;
115
116     return response->resultCode();
117 }
118
119 static OSStatus webSecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate)
120 {
121     auto response = sendSecItemRequest(SecItemRequestData::Update, query, attributesToUpdate);
122     if (!response)
123         return errSecInteractionNotAllowed;
124     
125     return response->resultCode();
126 }
127
128 static OSStatus webSecItemDelete(CFDictionaryRef query)
129 {
130     auto response = sendSecItemRequest(SecItemRequestData::Delete, query);
131     if (!response)
132         return errSecInteractionNotAllowed;
133     
134     return response->resultCode();
135 }
136
137 void initializeSecItemShim(ChildProcess& process)
138 {
139     sharedProcess = &process;
140
141 #if PLATFORM(IOS)
142     struct _CFNFrameworksStubs stubs = {
143         .version = 0,
144         .SecItem_stub_CopyMatching = webSecItemCopyMatching,
145         .SecItem_stub_Add = webSecItemAdd,
146         .SecItem_stub_Update = webSecItemUpdate,
147         .SecItem_stub_Delete = webSecItemDelete,
148     };
149
150     _CFURLConnectionSetFrameworkStubs(&stubs);
151 #endif
152
153 #if PLATFORM(MAC)
154     const SecItemShimCallbacks callbacks = {
155         webSecItemCopyMatching,
156         webSecItemAdd,
157         webSecItemUpdate,
158         webSecItemDelete
159     };
160     
161     SecItemShimInitializeFunc func = reinterpret_cast<SecItemShimInitializeFunc>(dlsym(RTLD_DEFAULT, "WebKitSecItemShimInitialize"));
162     func(callbacks);
163 #endif
164 }
165
166 } // namespace WebKit
167
168 #endif // ENABLE(SEC_ITEM_SHIM)