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