1/* 2 * Copyright (C) 2011, 2013 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 "SecItemShimMessages.h" 37#include "SecItemShimProxyMessages.h" 38#include <Security/Security.h> 39#include <atomic> 40#include <dlfcn.h> 41#include <mutex> 42#include <wtf/NeverDestroyed.h> 43 44#if __has_include(<CFNetwork/CFURLConnectionPriv.h>) 45#include <CFNetwork/CFURLConnectionPriv.h> 46#else 47struct _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 57extern "C" void _CFURLConnectionSetFrameworkStubs(const struct _CFNFrameworksStubs* stubs); 58 59namespace WebKit { 60 61static BlockingResponseMap<SecItemResponseData>& responseMap() 62{ 63 static std::once_flag onceFlag; 64 static LazyNeverDestroyed<BlockingResponseMap<SecItemResponseData>> responseMap; 65 66 std::call_once(onceFlag, []{ 67 responseMap.construct(); 68 }); 69 70 return responseMap; 71} 72 73static ChildProcess* sharedProcess; 74 75SecItemShim& SecItemShim::shared() 76{ 77 static SecItemShim* shim; 78 static dispatch_once_t once; 79 dispatch_once(&once, ^{ 80 shim = adoptRef(new SecItemShim).leakRef(); 81 }); 82 83 return *shim; 84} 85 86SecItemShim::SecItemShim() 87 : m_queue(WorkQueue::create("com.apple.WebKit.SecItemShim")) 88{ 89} 90 91static uint64_t generateSecItemRequestID() 92{ 93 static std::atomic<int64_t> uniqueSecItemRequestID; 94 return ++uniqueSecItemRequestID; 95} 96 97static std::unique_ptr<SecItemResponseData> sendSecItemRequest(SecItemRequestData::Type requestType, CFDictionaryRef query, CFDictionaryRef attributesToMatch = 0) 98{ 99 uint64_t requestID = generateSecItemRequestID(); 100 if (!sharedProcess->parentProcessConnection()->send(Messages::SecItemShimProxy::SecItemRequest(requestID, SecItemRequestData(requestType, query, attributesToMatch)), 0)) 101 return nullptr; 102 103 return responseMap().waitForResponse(requestID); 104} 105 106static OSStatus webSecItemCopyMatching(CFDictionaryRef query, CFTypeRef* result) 107{ 108 std::unique_ptr<SecItemResponseData> response = sendSecItemRequest(SecItemRequestData::CopyMatching, query); 109 if (!response) 110 return errSecInteractionNotAllowed; 111 112 *result = response->resultObject().leakRef(); 113 return response->resultCode(); 114} 115 116static OSStatus webSecItemAdd(CFDictionaryRef query, CFTypeRef* result) 117{ 118 std::unique_ptr<SecItemResponseData> response = sendSecItemRequest(SecItemRequestData::Add, query); 119 if (!response) 120 return errSecInteractionNotAllowed; 121 122 if (result) 123 *result = response->resultObject().leakRef(); 124 return response->resultCode(); 125} 126 127static OSStatus webSecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate) 128{ 129 std::unique_ptr<SecItemResponseData> response = sendSecItemRequest(SecItemRequestData::Update, query, attributesToUpdate); 130 if (!response) 131 return errSecInteractionNotAllowed; 132 133 return response->resultCode(); 134} 135 136static OSStatus webSecItemDelete(CFDictionaryRef query) 137{ 138 std::unique_ptr<SecItemResponseData> response = sendSecItemRequest(SecItemRequestData::Delete, query); 139 if (!response) 140 return errSecInteractionNotAllowed; 141 142 return response->resultCode(); 143} 144 145void SecItemShim::secItemResponse(uint64_t requestID, const SecItemResponseData& response) 146{ 147 responseMap().didReceiveResponse(requestID, std::make_unique<SecItemResponseData>(response)); 148} 149 150void SecItemShim::initialize(ChildProcess* process) 151{ 152 sharedProcess = process; 153 154#if PLATFORM(IOS) 155 struct _CFNFrameworksStubs stubs = { 156 .version = 0, 157 .SecItem_stub_CopyMatching = webSecItemCopyMatching, 158 .SecItem_stub_Add = webSecItemAdd, 159 .SecItem_stub_Update = webSecItemUpdate, 160 .SecItem_stub_Delete = webSecItemDelete, 161 }; 162 163 _CFURLConnectionSetFrameworkStubs(&stubs); 164#endif 165 166#if PLATFORM(MAC) 167 const SecItemShimCallbacks callbacks = { 168 webSecItemCopyMatching, 169 webSecItemAdd, 170 webSecItemUpdate, 171 webSecItemDelete 172 }; 173 174 SecItemShimInitializeFunc func = reinterpret_cast<SecItemShimInitializeFunc>(dlsym(RTLD_DEFAULT, "WebKitSecItemShimInitialize")); 175 func(callbacks); 176#endif 177} 178 179void SecItemShim::initializeConnection(IPC::Connection* connection) 180{ 181 connection->addWorkQueueMessageReceiver(Messages::SecItemShim::messageReceiverName(), m_queue.get(), this); 182} 183 184} // namespace WebKit 185 186#endif // ENABLE(SEC_ITEM_SHIM) 187