1/* 2 * Copyright (c) 2000-2009 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// 26// connection - manage connections to clients. 27// 28// Note that Connection objects correspond to client process threads, and are 29// thus inherently single-threaded. It is physically impossible for multiple 30// requests to come in for the same Connection, unless the client side is 31// illegally messing with the IPC protocol (for which we check below). 32// It is still necessary to take the object lock for a Connection because there 33// are times when we want to manipulate a busy Connection from another securityd 34// thread (say, in response to a DPN). 35// 36#include "connection.h" 37#include "key.h" 38#include "server.h" 39#include "session.h" 40#include <security_cdsa_client/keyclient.h> 41#include <security_cdsa_client/genkey.h> 42#include <security_cdsa_client/wrapkey.h> 43#include <security_cdsa_client/signclient.h> 44#include <security_cdsa_client/macclient.h> 45#include <security_cdsa_client/cryptoclient.h> 46 47 48// 49// Construct a Connection object. 50// 51Connection::Connection(Process &proc, Port rPort) 52 : mClientPort(rPort), mGuestRef(kSecNoGuest), state(idle), agentWait(NULL) 53{ 54 parent(proc); 55 56 // bump the send-rights count on the reply port so we keep the right after replying 57 mClientPort.modRefs(MACH_PORT_RIGHT_SEND, +1); 58 59 SECURITYD_CLIENT_CONNECTION_NEW(this, rPort, &proc); 60} 61 62 63// 64// When a Connection's destructor executes, the connection must already have been 65// terminated. All we have to do here is clean up a bit. 66// 67Connection::~Connection() 68{ 69 SECURITYD_CLIENT_CONNECTION_RELEASE(this); 70 assert(!agentWait); 71} 72 73 74// 75// Set the (last known) guest handle for this connection. 76// 77void Connection::guestRef(SecGuestRef newGuest, SecCSFlags flags) 78{ 79 secdebug("SS", "Connection %p switches to guest 0x%x", this, newGuest); 80 mGuestRef = newGuest; 81} 82 83 84// 85// Terminate a Connection normally. 86// This is assumed to be properly sequenced, so no thread races are possible. 87// 88void Connection::terminate() 89{ 90 // cleanly discard port rights 91 assert(state == idle); 92 mClientPort.modRefs(MACH_PORT_RIGHT_SEND, -1); // discard surplus send right 93 assert(mClientPort.getRefs(MACH_PORT_RIGHT_SEND) == 1); // one left for final reply 94 secdebug("SS", "Connection %p terminated", this); 95} 96 97 98// 99// Abort a Connection. 100// This may be called from thread A while thread B is working a request for the Connection, 101// so we must be careful. 102// 103void Connection::abort(bool keepReplyPort) 104{ 105 StLock<Mutex> _(*this); 106 if (!keepReplyPort) 107 mClientPort.destroy(); // dead as a doornail already 108 switch (state) { 109 case idle: 110 secdebug("SS", "Connection %p aborted", this); 111 break; 112 case busy: 113 state = dying; // shoot me soon, please 114 if (agentWait) 115 agentWait->disconnect(); 116 secdebug("SS", "Connection %p abort deferred (busy)", this); 117 break; 118 default: 119 assert(false); // impossible (we hope) 120 break; 121 } 122} 123 124 125// 126// Service request framing. 127// These are here so "hanging" connection service threads don't fall 128// into the Big Bad Void as Connections and processes drop out from 129// under them. 130// 131void Connection::beginWork(audit_token_t &auditToken) 132{ 133 // assume the audit token will be valid for the Connection's lifetime 134 // (but no longer) 135 mAuditToken = &auditToken; 136 switch (state) { 137 case idle: 138 state = busy; 139 mOverrideReturn = CSSM_OK; // clear override 140 break; 141 case busy: 142 secdebug("SS", "Attempt to re-enter connection %p(port %d)", this, mClientPort.port()); 143 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); //@@@ some state-error code instead? 144 default: 145 assert(false); 146 } 147} 148 149void Connection::checkWork() 150{ 151 StLock<Mutex> _(*this); 152 switch (state) { 153 case busy: 154 return; 155 case dying: 156 agentWait = NULL; // obviously we're not waiting on this 157 throw this; 158 default: 159 assert(false); 160 } 161} 162 163void Connection::endWork(CSSM_RETURN &rcode) 164{ 165 mAuditToken = NULL; 166 167 switch (state) { 168 case busy: 169 if (mOverrideReturn && rcode == CSSM_OK) 170 rcode = mOverrideReturn; 171 state = idle; 172 return; 173 case dying: 174 secdebug("SS", "Connection %p abort resuming", this); 175 return; 176 default: 177 assert(false); 178 return; // placebo 179 } 180} 181