connection.cpp
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 // 51 Connection::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 secinfo("SecServer", "New client connection %p: %d %d", this, rPort.port(), proc.uid()); 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 // 67 Connection::~Connection() try 68 { 69 mClientPort.deallocate(); 70 secinfo("SecServer", "releasing client connection %p", this); 71 assert(!agentWait); 72 } catch (...) { 73 secerror("SecServer: Error deallocating connection port"); 74 return; 75 } 76 77 // 78 // Set the (last known) guest handle for this connection. 79 // 80 void Connection::guestRef(SecGuestRef newGuest, SecCSFlags flags) 81 { 82 secinfo("SecServer", "Connection %p switches to guest 0x%x", this, newGuest); 83 mGuestRef = newGuest; 84 } 85 86 // 87 // Service request framing. 88 // These are here so "hanging" connection service threads don't fall 89 // into the Big Bad Void as Connections and processes drop out from 90 // under them. 91 // 92 void Connection::beginWork(audit_token_t &auditToken) 93 { 94 // assume the audit token will be valid for the Connection's lifetime 95 // (but no longer) 96 mAuditToken = &auditToken; 97 switch (state) { 98 case idle: 99 state = busy; 100 mOverrideReturn = CSSM_OK; // clear override 101 break; 102 case busy: 103 secinfo("SecServer", "Attempt to re-enter connection %p(port %d)", this, mClientPort.port()); 104 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); //@@@ some state-error code instead? 105 default: 106 assert(false); 107 } 108 } 109 110 void Connection::checkWork() 111 { 112 StLock<Mutex> _(*this); 113 switch (state) { 114 case busy: 115 return; 116 case dying: 117 agentWait = NULL; // obviously we're not waiting on this 118 throw this; 119 default: 120 assert(false); 121 } 122 } 123 124 void Connection::endWork(CSSM_RETURN &rcode) 125 { 126 mAuditToken = NULL; 127 128 switch (state) { 129 case busy: 130 if (mOverrideReturn && rcode == CSSM_OK) 131 rcode = mOverrideReturn; 132 state = idle; 133 return; 134 case dying: 135 secinfo("SecServer", "Connection %p abort resuming", this); 136 return; 137 default: 138 assert(false); 139 return; // placebo 140 } 141 }