1/*
2 * Copyright (c) 2000-2009,2012-2013 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// transition - securityd IPC-to-class-methods transition layer
27//
28// This file contains all server-side MIG implementations for the main
29// securityd protocol ("ucsp"). It dispatches them into the vast object
30// conspiracy that is securityd, anchored in the Server object.
31//
32#include <securityd_client/ss_types.h>
33#include <securityd_client/ucsp.h>
34#include "server.h"
35#include "session.h"
36#include "agentquery.h"
37#include "database.h"
38#include "kcdatabase.h"
39#include "tokendatabase.h"
40#include "kckey.h"
41#include "child.h"
42#include <syslog.h>
43#include <mach/mach_error.h>
44#include <securityd_client/xdr_cssm.h>
45#include <securityd_client/xdr_auth.h>
46#include <securityd_client/xdr_dldb.h>
47#include <security_utilities/logging.h>
48#include <AssertMacros.h>
49
50#include <CoreFoundation/CFNumber.h>
51#include <CoreFoundation/CFDictionary.h>
52#include <CoreFoundation/CFPropertyList.h>
53
54//
55// Bracket Macros
56//
57#define UCSP_ARGS	mach_port_t servicePort, mach_port_t replyPort, \
58	audit_token_t auditToken, CSSM_RETURN *rcode
59
60#define BEGIN_IPCN	*rcode = CSSM_OK; try {
61#define BEGIN_IPC(name)	BEGIN_IPCN RefPointer<Connection> connRef(&Server::connection(replyPort, auditToken)); \
62		Connection &connection __attribute__((unused)) = *connRef; \
63		if (SECURITYD_REQUEST_ENTRY_ENABLED()) { \
64			const char * volatile s = #name; volatile char __attribute__((unused)) pagein = s[0]; \
65			SECURITYD_REQUEST_ENTRY((char *)s, &connection, &connection.process()); \
66		}
67#define END_IPC(base)	END_IPCN(base) Server::requestComplete(*rcode); return KERN_SUCCESS;
68#define END_IPCN(base) 	SECURITYD_REQUEST_RETURN(*rcode); \
69	} \
70	catch (const CommonError &err) { *rcode = CssmError::cssmError(err, CSSM_ ## base ## _BASE_ERROR); } \
71	catch (const std::bad_alloc &) { *rcode = CssmError::merge(CSSM_ERRCODE_MEMORY_ERROR, CSSM_ ## base ## _BASE_ERROR); } \
72	catch (Connection *conn) { *rcode = 0; } \
73	catch (...) { *rcode = CssmError::merge(CSSM_ERRCODE_INTERNAL_ERROR, CSSM_ ## base ## _BASE_ERROR); }
74
75#define BEGIN_IPCS		try {
76#define	END_IPCS(more)	} catch (...) { } \
77						mach_port_deallocate(mach_task_self(), servicePort); more; return KERN_SUCCESS;
78
79#define DATA_IN(base)	void *base, mach_msg_type_number_t base##Length
80#define DATA_OUT(base)	void **base, mach_msg_type_number_t *base##Length
81#define DATA(base)		CssmData(base, base##Length)
82
83#define SSBLOB(Type, name) makeBlob<Type>(DATA(name))
84
85using LowLevelMemoryUtilities::increment;
86using LowLevelMemoryUtilities::difference;
87
88class CopyOutAccessCredentials : public CopyOut {
89public:
90	CopyOutAccessCredentials(void *copy, size_t size) : CopyOut(copy, size + sizeof(CSSM_ACCESS_CREDENTIALS), reinterpret_cast<xdrproc_t>(xdr_CSSM_ACCESS_CREDENTIALS_PTR)) { }
91	operator AccessCredentials *() { return static_cast<AccessCredentials *>(reinterpret_cast<CSSM_ACCESS_CREDENTIALS_PTR>(data())); }
92};
93
94
95class CopyOutEntryAcl : public CopyOut {
96public:
97	CopyOutEntryAcl(void *copy, size_t size) : CopyOut(copy, size + sizeof(CSSM_ACL_ENTRY_PROTOTYPE), reinterpret_cast<xdrproc_t>(xdr_CSSM_ACL_ENTRY_PROTOTYPE_PTR)) { }
98	operator AclEntryPrototype *() { return static_cast<AclEntryPrototype *>(reinterpret_cast<CSSM_ACL_ENTRY_PROTOTYPE_PTR>(data())); }
99};
100
101class CopyOutOwnerAcl : public CopyOut {
102public:
103	CopyOutOwnerAcl(void *copy, size_t size) : CopyOut(copy, size + sizeof(CSSM_ACL_OWNER_PROTOTYPE), reinterpret_cast<xdrproc_t>(xdr_CSSM_ACL_OWNER_PROTOTYPE_PTR)) { }
104	operator AclOwnerPrototype *() { return static_cast<AclOwnerPrototype *>(reinterpret_cast<CSSM_ACL_OWNER_PROTOTYPE_PTR>(data())); }
105};
106
107class CopyOutAclEntryInput : public CopyOut {
108public:
109	CopyOutAclEntryInput(void *copy, size_t size) : CopyOut(copy, size + sizeof(CSSM_ACL_ENTRY_INPUT), reinterpret_cast<xdrproc_t>(xdr_CSSM_ACL_ENTRY_INPUT_PTR)) { }
110	operator AclEntryInput *() { return static_cast<AclEntryInput *>(reinterpret_cast<CSSM_ACL_ENTRY_INPUT_PTR>(data())); }
111};
112
113
114class CopyOutDeriveData : public CopyOut {
115public:
116	CopyOutDeriveData(void *copy, size_t size) : CopyOut(copy, size + sizeof(CSSM_DERIVE_DATA), reinterpret_cast<xdrproc_t>(xdr_CSSM_DERIVE_DATA_PTR)) { }
117	CSSM_DERIVE_DATA * derive_data() { return reinterpret_cast<CSSM_DERIVE_DATA *>(data()); }
118	CSSM_DATA &cssm_data() { return derive_data()->baseData; }
119	CSSM_ALGORITHMS algorithm() { return derive_data()->algorithm; }
120};
121
122
123class CopyOutContext : public CopyOut {
124public:
125	CopyOutContext(void *copy, size_t size) : CopyOut(copy, size + sizeof(CSSM_CONTEXT), reinterpret_cast<xdrproc_t>(xdr_CSSM_CONTEXT_PTR)) { }
126	operator Context *() { return static_cast<Context *>(reinterpret_cast<CSSM_CONTEXT_PTR>(data())); }
127	Context &context() { return *static_cast<Context *>(reinterpret_cast<CSSM_CONTEXT_PTR>(data())); }
128};
129
130class CopyOutKey : public CopyOut {
131public:
132	CopyOutKey(void *copy, size_t size) : CopyOut(copy, size + sizeof(CSSM_KEY), reinterpret_cast<xdrproc_t>(xdr_CSSM_KEY_PTR)) { }
133	operator CssmKey *() { return static_cast<CssmKey *>(reinterpret_cast<CSSM_KEY_PTR>(data())); }
134	CssmKey &key() { return *static_cast<CssmKey *>(reinterpret_cast<CSSM_KEY_PTR>(data())); }
135};
136
137class CopyOutDbRecordAttributes : public CopyOut {
138public:
139	CopyOutDbRecordAttributes(void *copy, size_t size) : CopyOut(copy, size + sizeof(CSSM_DB_RECORD_ATTRIBUTE_DATA), reinterpret_cast<xdrproc_t>(xdr_CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR)) { }
140	CssmDbRecordAttributeData *attribute_data() { return static_cast<CssmDbRecordAttributeData *>(reinterpret_cast<CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR>(data())); }
141};
142
143class CopyOutQuery : public CopyOut {
144public:
145	CopyOutQuery(void *copy, size_t size) : CopyOut(copy, size, reinterpret_cast<xdrproc_t>(xdr_CSSM_QUERY_PTR)) { }
146	operator CssmQuery *() { return static_cast<CssmQuery *>(reinterpret_cast<CSSM_QUERY_PTR>(data())); }
147};
148
149//
150// Take a DATA type RPC argument purportedly representing a Blob of some kind,
151// turn it into a Blob, and fail properly if it's not kosher.
152//
153template <class BlobType>
154const BlobType *makeBlob(const CssmData &blobData, CSSM_RETURN error = CSSM_ERRCODE_INVALID_DATA)
155{
156	if (!blobData.data() || blobData.length() < sizeof(BlobType))
157		CssmError::throwMe(error);
158	const BlobType *blob = static_cast<const BlobType *>(blobData.data());
159	if (blob->totalLength != blobData.length())
160		CssmError::throwMe(error);
161	return blob;
162}
163
164//
165// An OutputData object will take memory allocated within securityd,
166// hand it to the MIG return-output parameters, and schedule it to be released
167// after the MIG reply has been sent. It will also get rid of it in case of
168// error.
169//
170class OutputData : public CssmData {
171public:
172	OutputData(void **outP, mach_msg_type_number_t *outLength)
173		: mData(*outP), mLength(*outLength) { }
174	~OutputData()
175	{ mData = data(); mLength = length(); Server::releaseWhenDone(mData); }
176
177    void operator = (const CssmData &source)
178    { CssmData::operator = (source); }
179
180private:
181	void * &mData;
182	mach_msg_type_number_t &mLength;
183};
184
185//
186// Choose a Database from a choice of two sources, giving preference
187// to persistent stores and to earlier sources.
188//
189Database *pickDb(Database *db1, Database *db2);
190
191static inline Database *dbOf(Key *key)	{ return key ? &key->database() : NULL; }
192
193inline Database *pickDb(Key *k1, Key *k2) { return pickDb(dbOf(k1), dbOf(k2)); }
194inline Database *pickDb(Database *db1, Key *k2) { return pickDb(db1, dbOf(k2)); }
195inline Database *pickDb(Key *k1, Database *db2) { return pickDb(dbOf(k1), db2); }
196
197//
198// Choose a Database from a choice of two sources, giving preference
199// to persistent stores and to earlier sources.
200//
201Database *pickDb(Database *db1, Database *db2)
202{
203	// persistent db1 always wins
204	if (db1 && !db1->transient())
205		return db1;
206
207	// persistent db2 is next choice
208	if (db2 && !db2->transient())
209		return db2;
210
211	// pick any existing transient database
212	if (db1)
213		return db1;
214	if (db2)
215		return db2;
216
217	// none at all. use the canonical transient store
218	return Server::optionalDatabase(noDb);
219}
220
221//
222// Setup/Teardown functions.
223//
224kern_return_t ucsp_server_setup(UCSP_ARGS, mach_port_t taskPort, ClientSetupInfo info, const char *identity)
225{
226	BEGIN_IPCN
227	SECURITYD_REQUEST_ENTRY((char*)"setup", NULL, NULL);
228	Server::active().setupConnection(Server::connectNewProcess, replyPort,
229		taskPort, auditToken, &info);
230	END_IPCN(CSSM)
231	if (*rcode)
232		Syslog::notice("setup(%s) failed rcode=%d", identity ? identity : "<NULL>", *rcode);
233	return KERN_SUCCESS;
234}
235
236
237kern_return_t ucsp_server_setupThread(UCSP_ARGS, mach_port_t taskPort)
238{
239	SECURITYD_REQUEST_ENTRY((char*)"setupThread", NULL, NULL);
240	BEGIN_IPCN
241	Server::active().setupConnection(Server::connectNewThread, replyPort, taskPort, auditToken);
242	END_IPCN(CSSM)
243	if (*rcode)
244		Syslog::notice("setupThread failed rcode=%d", *rcode);
245	return KERN_SUCCESS;
246}
247
248
249kern_return_t ucsp_server_teardown(UCSP_ARGS)
250{
251	BEGIN_IPCN
252	SECURITYD_REQUEST_ENTRY((char*)"teardown", NULL, NULL);
253	Server::active().endConnection(replyPort);
254	END_IPCN(CSSM)
255	return KERN_SUCCESS;
256}
257
258kern_return_t ucsp_server_verifyPrivileged(UCSP_ARGS)
259{
260	BEGIN_IPCN
261	SECURITYD_REQUEST_ENTRY((char*)"verifyPrivileged", NULL, NULL);
262	// doing nothing (we just want securityd's audit credentials returned)
263	END_IPCN(CSSM)
264	return KERN_SUCCESS;
265}
266
267kern_return_t ucsp_server_verifyPrivileged2(UCSP_ARGS, mach_port_t *originPort)
268{
269	BEGIN_IPCN
270	SECURITYD_REQUEST_ENTRY((char*)"verifyPrivileged2", NULL, NULL);
271	// send the port back to the sender to check for a MitM (6986198)
272	*originPort = servicePort;
273	END_IPCN(CSSM)
274	return KERN_SUCCESS;
275}
276
277//
278// Common database operations
279//
280kern_return_t ucsp_server_authenticateDb(UCSP_ARGS, DbHandle db,
281	CSSM_DB_ACCESS_TYPE accessType, DATA_IN(cred))
282{
283	BEGIN_IPC(authenticateDb)
284    secdebug("dl", "authenticateDb");
285	CopyOutAccessCredentials creds(cred, credLength);
286	// ignoring accessType
287    Server::database(db)->authenticate(accessType, creds);
288	END_IPC(DL)
289}
290
291kern_return_t ucsp_server_releaseDb(UCSP_ARGS, DbHandle db)
292{
293	BEGIN_IPC(releaseDb)
294	connection.process().kill(*Server::database(db));
295	END_IPC(DL)
296}
297
298
299kern_return_t ucsp_server_getDbName(UCSP_ARGS, DbHandle db, char name[PATH_MAX])
300{
301	BEGIN_IPC(getDbName)
302	string result = Server::database(db)->dbName();
303	assert(result.length() < PATH_MAX);
304	memcpy(name, result.c_str(), result.length() + 1);
305	END_IPC(DL)
306}
307
308kern_return_t ucsp_server_setDbName(UCSP_ARGS, DbHandle db, const char *name)
309{
310	BEGIN_IPC(setDbName)
311	Server::database(db)->dbName(name);
312	END_IPC(DL)
313}
314
315
316//
317// External database interface
318//
319kern_return_t ucsp_server_openToken(UCSP_ARGS, uint32 ssid, FilePath name,
320	DATA_IN(accessCredentials), DbHandle *db)
321{
322	BEGIN_IPC(openToken)
323	CopyOutAccessCredentials creds(accessCredentials, accessCredentialsLength);
324	*db = (new TokenDatabase(ssid, connection.process(), name, creds))->handle();
325	END_IPC(DL)
326}
327
328kern_return_t ucsp_server_findFirst(UCSP_ARGS, DbHandle db,
329	DATA_IN(inQuery), DATA_IN(inAttributes), DATA_OUT(outAttributes),
330	boolean_t getData, DATA_OUT(data),
331    KeyHandle *hKey, SearchHandle *hSearch, IPCRecordHandle *hRecord)
332{
333	BEGIN_IPC(findFirst)
334	CopyOutQuery query(inQuery, inQueryLength);
335	CopyOutDbRecordAttributes attrs(inAttributes, inAttributesLength);
336
337	RefPointer<Database::Search> search;
338	RefPointer<Database::Record> record;
339	RefPointer<Key> key;
340	CssmData outData;
341	CssmDbRecordAttributeData *outAttrs = NULL; mach_msg_type_number_t outAttrsLength;
342	Server::database(db)->findFirst(*query,
343        attrs.attribute_data(), attrs.length(),
344		getData ? &outData : NULL, key, search, record, outAttrs, outAttrsLength);
345
346	// handle nothing-found case without exceptions
347	if (!record) {
348		*hRecord = noRecord;
349		*hSearch = noSearch;
350		*hKey = noKey;
351	} else {
352		// return handles
353		*hRecord = record->handle();
354		*hSearch = search->handle();
355		*hKey = key ? key->handle() : noKey;
356
357        if (outAttrsLength && outAttrs) {
358            Server::releaseWhenDone(outAttrs); // exception proof it against next line
359            if (!copyin(outAttrs, reinterpret_cast<xdrproc_t> (xdr_CSSM_DB_RECORD_ATTRIBUTE_DATA), outAttributes, outAttributesLength))
360                CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
361            Server::releaseWhenDone(*outAttributes);
362        }
363
364		// return data (temporary fix)
365		if (getData) {
366			Server::releaseWhenDone(outData.data());
367            xdrproc_t encode_proc = reinterpret_cast<xdrproc_t>(xdr_CSSM_NO_KEY_IN_DATA);
368            if (key)
369                encode_proc = reinterpret_cast<xdrproc_t>(xdr_CSSM_KEY_IN_DATA);
370			if (!copyin(&outData, encode_proc, data, dataLength))
371				CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
372			Server::releaseWhenDone(*data);
373		}
374	}
375	END_IPC(DL)
376}
377
378
379kern_return_t ucsp_server_findNext(UCSP_ARGS, SearchHandle hSearch,
380	DATA_IN(inAttributes),
381	DATA_OUT(outAttributes),
382	boolean_t getData, DATA_OUT(data), KeyHandle *hKey,
383	IPCRecordHandle *hRecord)
384{
385	BEGIN_IPC(findNext)
386	CopyOutDbRecordAttributes attrs(inAttributes, inAttributesLength);
387	RefPointer<Database::Search> search =
388		Server::find<Database::Search>(hSearch, CSSMERR_DL_INVALID_RESULTS_HANDLE);
389	RefPointer<Database::Record> record;
390	RefPointer<Key> key;
391	CssmData outData;
392	CssmDbRecordAttributeData *outAttrs = NULL; mach_msg_type_number_t outAttrsLength;
393	search->database().findNext(search, attrs.attribute_data(), attrs.length(),
394		getData ? &outData : NULL, key, record, outAttrs, outAttrsLength);
395
396	// handle nothing-found case without exceptions
397	if (!record) {
398		*hRecord = noRecord;
399		*hKey = noKey;
400	} else {
401		// return handles
402		*hRecord = record->handle();
403		*hKey = key ? key->handle() : noKey;
404
405        if (outAttrsLength && outAttrs) {
406			secdebug("attrmem", "Found attrs: %p of length: %d", outAttrs, outAttrsLength);
407            Server::releaseWhenDone(outAttrs); // exception proof it against next line
408            if (!copyin(outAttrs, reinterpret_cast<xdrproc_t> (xdr_CSSM_DB_RECORD_ATTRIBUTE_DATA), outAttributes, outAttributesLength))
409                CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
410			secdebug("attrmem", "Copied attrs: %p of length: %d", *outAttributes, *outAttributesLength);
411            Server::releaseWhenDone(*outAttributes);
412        }
413
414		// return data (temporary fix)
415		if (getData) {
416			Server::releaseWhenDone(outData.data());
417            xdrproc_t encode_proc = reinterpret_cast<xdrproc_t>(xdr_CSSM_NO_KEY_IN_DATA);
418            if (key)
419                encode_proc = reinterpret_cast<xdrproc_t>(xdr_CSSM_KEY_IN_DATA);
420            if (!copyin(&outData, encode_proc, data, dataLength))
421                CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
422			Server::releaseWhenDone(*data);
423		}
424	}
425	END_IPC(DL)
426}
427
428kern_return_t ucsp_server_findRecordHandle(UCSP_ARGS, IPCRecordHandle hRecord,
429	DATA_IN(inAttributes), DATA_OUT(outAttributes),
430	boolean_t getData, DATA_OUT(data), KeyHandle *hKey)
431{
432	BEGIN_IPC(findRecordHandle)
433	CopyOutDbRecordAttributes attrs(inAttributes, inAttributesLength);
434	RefPointer<Database::Record> record =
435		Server::find<Database::Record>(hRecord, CSSMERR_DL_INVALID_RECORD_UID);
436	RefPointer<Key> key;
437	CssmData outData;
438	CssmDbRecordAttributeData *outAttrs; mach_msg_type_number_t outAttrsLength;
439	record->database().findRecordHandle(record, attrs.attribute_data(), attrs.length(),
440		getData ? &outData : NULL, key, outAttrs, outAttrsLength);
441
442	// return handles
443	*hKey = key ? key->handle() : noKey;
444
445    if (outAttrsLength && outAttrs) {
446        Server::releaseWhenDone(outAttrs); // exception proof it against next line
447        if (!copyin(outAttrs, reinterpret_cast<xdrproc_t> (xdr_CSSM_DB_RECORD_ATTRIBUTE_DATA), outAttributes, outAttributesLength))
448            CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
449        Server::releaseWhenDone(*outAttributes);
450    }
451
452	// return data (temporary fix)
453	if (getData) {
454		/*
455			We can't release this with the usual allocator (which calls free(), since
456			it was VM allocated. Part of the fix for:
457			<rdar://problem/6738709> securityd leaks VM memory during certain smartcard operations
458			will be to call Server::releaseWhenDone below with a new vm allocator param
459		*/
460		Server::releaseWhenDone(outData.data());
461        xdrproc_t encode_proc = reinterpret_cast<xdrproc_t>(xdr_CSSM_NO_KEY_IN_DATA);
462        if (key)
463            encode_proc = reinterpret_cast<xdrproc_t>(xdr_CSSM_KEY_IN_DATA);
464        if (!copyin(&outData, encode_proc, data, dataLength))
465            CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
466        Server::releaseWhenDone(*data);
467	}
468	END_IPC(DL)
469}
470
471kern_return_t ucsp_server_insertRecord(UCSP_ARGS, DbHandle db, CSSM_DB_RECORDTYPE recordType,
472	DATA_IN(inAttributes), DATA_IN(data), IPCRecordHandle *record)
473{
474	BEGIN_IPC(insertRecord)
475	RecordHandle recordHandle;
476	CopyOutDbRecordAttributes attrs(inAttributes, inAttributesLength);
477	Server::database(db)->insertRecord(recordType, attrs.attribute_data(), attrs.length(),
478		DATA(data), recordHandle);
479	*record = recordHandle;
480	END_IPC(DL)
481}
482
483kern_return_t ucsp_server_modifyRecord(UCSP_ARGS, DbHandle db, IPCRecordHandle *hRecord,
484	CSSM_DB_RECORDTYPE recordType, DATA_IN(attributes),
485	boolean_t setData, DATA_IN(data), CSSM_DB_MODIFY_MODE modifyMode)
486{
487	BEGIN_IPC(modifyRecord)
488	CopyOutDbRecordAttributes attrs(attributes, attributesLength);
489	CssmData newData(DATA(data));
490	RefPointer<Database::Record> record =
491		Server::find<Database::Record>(*hRecord, CSSMERR_DL_INVALID_RECORD_UID);
492	Server::database(db)->modifyRecord(recordType, record, attrs.attribute_data(), attrs.length(),
493		setData ? &newData : NULL, modifyMode);
494	// note that the record handle presented to the client never changes here
495	// (we could, but have no reason to - our record handles are just always up to date)
496	END_IPC(DL)
497}
498
499kern_return_t ucsp_server_deleteRecord(UCSP_ARGS, DbHandle db, IPCRecordHandle hRecord)
500{
501	BEGIN_IPC(deleteRecord)
502	Server::database(db)->deleteRecord(
503		Server::find<Database::Record>(hRecord, CSSMERR_DL_INVALID_RECORD_UID));
504	END_IPC(DL)
505}
506
507kern_return_t ucsp_server_releaseSearch(UCSP_ARGS, SearchHandle hSearch)
508{
509	BEGIN_IPC(releaseSearch)
510	RefPointer<Database::Search> search = Server::find<Database::Search>(hSearch, 0);
511	search->database().releaseSearch(*search);
512	END_IPC(DL)
513}
514
515kern_return_t ucsp_server_releaseRecord(UCSP_ARGS, IPCRecordHandle hRecord)
516{
517	BEGIN_IPC(releaseRecord)
518	RefPointer<Database::Record> record = Server::find<Database::Record>(hRecord, 0);
519	record->database().releaseRecord(*record);
520	END_IPC(DL)
521}
522
523
524//
525// Internal database management
526//
527kern_return_t ucsp_server_createDb(UCSP_ARGS, DbHandle *db,
528	DATA_IN(ident), DATA_IN(cred), DATA_IN(owner),
529    DBParameters params)
530{
531	BEGIN_IPC(createDb)
532	CopyOutAccessCredentials creds(cred, credLength);
533	CopyOutEntryAcl owneracl(owner, ownerLength);
534	CopyOut flatident(ident, identLength, reinterpret_cast<xdrproc_t>(xdr_DLDbFlatIdentifierRef));
535	*db = (new KeychainDatabase(*reinterpret_cast<DLDbFlatIdentifier*>(flatident.data()), params, connection.process(), creds, owneracl))->handle();
536	END_IPC(DL)
537}
538
539kern_return_t ucsp_server_recodeDbForSync(UCSP_ARGS, DbHandle dbToClone,
540	DbHandle srcDb, DbHandle *newDb)
541{
542	BEGIN_IPC(recodeDbForSync)
543	RefPointer<KeychainDatabase> srcKC = Server::keychain(srcDb);
544	*newDb = (new KeychainDatabase(*srcKC, connection.process(), dbToClone))->handle();
545	END_IPC(DL)
546}
547
548kern_return_t ucsp_server_authenticateDbsForSync(UCSP_ARGS, DATA_IN(dbHandleArray),
549	DATA_IN(agentData), DbHandle* authenticatedDBHandle)
550{
551	BEGIN_IPC(authenticateDbsForSync)
552	QueryDBBlobSecret query;
553	query.inferHints(connection.process());
554    query.addHint(AGENT_HINT_KCSYNC_DICT, agentData, agentDataLength);
555	CSSM_DATA dbData = DATA(dbHandleArray);
556	uint8 ipcDbHandleArrayCount = *(dbData.Data);
557	DbHandle *ipcDbHandleArray = (DbHandle *)Allocator::standard().malloc(ipcDbHandleArrayCount * sizeof(DbHandle));
558	if ( ipcDbHandleArray == 0 )
559        CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
560	DbHandle *currIPCDbHandleArrayPtr = ipcDbHandleArray;
561	DbHandle *dbHandleArrayPtr = (DbHandle *)(dbData.Data+1);
562	int index;
563	for (index=0; index < ipcDbHandleArrayCount; index++)
564	{
565		*currIPCDbHandleArrayPtr = *dbHandleArrayPtr;
566		Server::keychain(*currIPCDbHandleArrayPtr)->lockDb(); // lock this db if it was unlocked in the past (user could have deleted the kc, resetLogin, etc.)
567		currIPCDbHandleArrayPtr++;
568		dbHandleArrayPtr++;
569	}
570	Server::releaseWhenDone(ipcDbHandleArray);
571	if (query(ipcDbHandleArray, ipcDbHandleArrayCount, authenticatedDBHandle) != SecurityAgent::noReason)
572        CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
573	END_IPC(DL)
574}
575
576kern_return_t ucsp_server_commitDbForSync(UCSP_ARGS, DbHandle srcDb,
577    DbHandle cloneDb, DATA_OUT(blob))
578{
579	BEGIN_IPC(commitDbForSync)
580    RefPointer<KeychainDatabase> srcKC = Server::keychain(srcDb);
581    RefPointer<KeychainDatabase> cloneKC = Server::keychain(cloneDb);
582    srcKC->commitSecretsForSync(*cloneKC);
583
584	// re-encode blob for convenience
585	if (blob && blobLength) {
586		DbBlob *dbBlob = srcKC->blob();
587		*blob = dbBlob;
588		*blobLength = dbBlob->length();
589	} else {
590		secdebug("kcrecode", "No blob can be returned to client");
591	}
592	END_IPC(DL)
593}
594
595kern_return_t ucsp_server_decodeDb(UCSP_ARGS, DbHandle *db,
596    DATA_IN(ident), DATA_IN(cred), DATA_IN(blob))
597{
598	BEGIN_IPC(decodeDb)
599	CopyOutAccessCredentials creds(cred, credLength);
600	CopyOut flatident(ident, identLength, reinterpret_cast<xdrproc_t>(xdr_DLDbFlatIdentifierRef));
601	DLDbFlatIdentifier* flatID = (DLDbFlatIdentifier*) flatident.data();
602	DLDbIdentifier id = *flatID; // invokes a casting operator
603
604	*db = (new KeychainDatabase(id, SSBLOB(DbBlob, blob),
605        connection.process(), creds))->handle();
606	END_IPC(DL)
607}
608
609kern_return_t ucsp_server_encodeDb(UCSP_ARGS, DbHandle db, DATA_OUT(blob))
610{
611	BEGIN_IPC(encodeDb)
612    DbBlob *dbBlob = Server::keychain(db)->blob();	// memory owned by database
613    *blob = dbBlob;
614    *blobLength = dbBlob->length();
615	END_IPC(DL)
616}
617
618kern_return_t ucsp_server_setDbParameters(UCSP_ARGS, DbHandle db, DBParameters params)
619{
620	BEGIN_IPC(setDbParameters)
621	Server::keychain(db)->setParameters(params);
622	END_IPC(DL)
623}
624
625kern_return_t ucsp_server_getDbParameters(UCSP_ARGS, DbHandle db, DBParameters *params)
626{
627	BEGIN_IPC(getDbParameters)
628	Server::keychain(db)->getParameters(*params);
629	END_IPC(DL)
630}
631
632kern_return_t ucsp_server_changePassphrase(UCSP_ARGS, DbHandle db,
633    DATA_IN(cred))
634{
635	BEGIN_IPC(changePassphrase)
636	CopyOutAccessCredentials creds(cred, credLength);
637	Server::keychain(db)->changePassphrase(creds);
638	END_IPC(DL)
639}
640
641kern_return_t ucsp_server_lockAll (UCSP_ARGS, boolean_t)
642{
643	BEGIN_IPC(lockAll)
644	connection.session().processLockAll();
645	END_IPC(DL)
646}
647
648kern_return_t ucsp_server_unlockDb(UCSP_ARGS, DbHandle db)
649{
650	BEGIN_IPC(unlockDb)
651	Server::keychain(db)->unlockDb();
652	END_IPC(DL)
653}
654
655static void check_stash_entitlement(Process & proc)
656{
657    OSStatus status = noErr;
658    CFDictionaryRef code_info = NULL;
659    CFDictionaryRef entitlements = NULL;
660    CFTypeRef value = NULL;
661    bool entitled = false;
662
663    status = SecCodeCopySigningInformation(proc.processCode(), kSecCSRequirementInformation, &code_info);
664    require_noerr(status, done);
665
666    if (CFDictionaryGetValueIfPresent(code_info, kSecCodeInfoEntitlementsDict, &value)) {
667        if (CFGetTypeID(value) == CFDictionaryGetTypeID()) {
668            entitlements = (CFDictionaryRef)value;
669        }
670    }
671    require(entitlements != NULL, done);
672
673    if (CFDictionaryGetValueIfPresent(entitlements, CFSTR("com.apple.private.securityd.stash"), &value)) {
674        if (CFGetTypeID(value) && CFBooleanGetTypeID()) {
675            entitled = CFBooleanGetValue((CFBooleanRef)value);
676        }
677    }
678
679done:
680    if (code_info) {
681        CFRelease(code_info);
682    }
683
684    if (!entitled) {
685        CssmError::throwMe(CSSM_ERRCODE_OS_ACCESS_DENIED);
686    }
687}
688
689kern_return_t ucsp_server_unlockDbWithPassphrase(UCSP_ARGS, DbHandle db, DATA_IN(passphrase))
690{
691	BEGIN_IPC(unlockDbWithPassphrase)
692    Server::keychain(db)->unlockDb(DATA(passphrase));
693	END_IPC(DL)
694}
695
696kern_return_t ucsp_server_stashDb(UCSP_ARGS, DbHandle db)
697{
698    BEGIN_IPC(stashDb)
699    check_stash_entitlement(connection.process());
700    Server::keychain(db)->stashDb();
701    END_IPC(DL)
702}
703
704kern_return_t ucsp_server_stashDbCheck(UCSP_ARGS, DbHandle db)
705{
706    BEGIN_IPC(stashDbCheck)
707    check_stash_entitlement(connection.process());
708    Server::keychain(db)->stashDbCheck();
709    END_IPC(DL)
710}
711
712kern_return_t ucsp_server_isLocked(UCSP_ARGS, DbHandle db, boolean_t *locked)
713{
714    BEGIN_IPC(isLocked)
715    *locked = Server::database(db)->isLocked();
716    END_IPC(DL)
717}
718
719kern_return_t ucsp_server_verifyKeyStorePassphrase(UCSP_ARGS, uint32_t retries)
720{
721    BEGIN_IPC(verifyKeyStorePassphrase)
722    connection.process().session().verifyKeyStorePassphrase(retries);
723    END_IPC(DL)
724}
725
726kern_return_t ucsp_server_changeKeyStorePassphrase(UCSP_ARGS)
727{
728    BEGIN_IPC(verifyKeyStorePassphrase)
729    connection.process().session().changeKeyStorePassphrase();
730    END_IPC(DL)
731}
732
733kern_return_t ucsp_server_resetKeyStorePassphrase(UCSP_ARGS, DATA_IN(passphrase))
734{
735    BEGIN_IPC(verifyKeyStorePassphrase)
736    connection.process().session().resetKeyStorePassphrase(DATA(passphrase));
737    END_IPC(DL)
738}
739
740//
741// Key management
742//
743kern_return_t ucsp_server_encodeKey(UCSP_ARGS, KeyHandle keyh, DATA_OUT(blob),
744    boolean_t wantUid, DATA_OUT(uid))
745{
746	BEGIN_IPC(encodeKey)
747	RefPointer<Key> gKey = Server::key(keyh);
748	if (KeychainKey *key = dynamic_cast<KeychainKey *>(gKey.get())) {
749		KeyBlob *keyBlob = key->blob();	// still owned by key
750		*blob = keyBlob;
751		*blobLength = keyBlob->length();
752		if (wantUid) {	// uid generation is not implemented
753			CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
754		} else {
755			*uidLength = 0;	// do not return this
756		}
757	} else {	// not a KeychainKey
758		CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
759	}
760	END_IPC(CSP)
761}
762
763kern_return_t ucsp_server_decodeKey(UCSP_ARGS, KeyHandle *keyh, DATA_OUT(keyHeader),
764	DbHandle db, DATA_IN(blob))
765{
766	BEGIN_IPC(decodeKey)
767    RefPointer<Key> key = new KeychainKey(*Server::keychain(db), SSBLOB(KeyBlob, blob));
768	CssmKey::Header header;
769    key->returnKey(*keyh, header);
770	if (!copyin(&header, reinterpret_cast<xdrproc_t> (xdr_CSSM_KEYHEADER), keyHeader, keyHeaderLength))
771		CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
772	Server::releaseWhenDone(*keyHeader);
773	END_IPC(CSP)
774}
775
776// keychain synchronization
777kern_return_t ucsp_server_recodeKey(UCSP_ARGS, DbHandle oldDb, KeyHandle keyh,
778	DbHandle newDb, DATA_OUT(newBlob))
779{
780	BEGIN_IPC(recodeKey)
781	// If the old key is passed in as DATA_IN(oldBlob):
782	// RefPointer<KeychainKey> key = new KeychainKey(*Server::keychain(oldDb), SSBLOB(KeyBlob, oldBlob));
783	RefPointer<Key> key = Server::key(keyh);
784	if (KeychainKey *kckey = dynamic_cast<KeychainKey *>(key.get())) {
785		KeyBlob *blob = Server::keychain(newDb)->recodeKey(*kckey);
786		*newBlob = blob;
787		*newBlobLength = blob->length();
788		Server::releaseWhenDone(*newBlob);
789		// @@@  stop leaking blob
790	} else {	// not a KeychainKey
791		CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
792	}
793	END_IPC(CSP)
794}
795
796kern_return_t ucsp_server_releaseKey(UCSP_ARGS, KeyHandle keyh)
797{
798	BEGIN_IPC(releaseKey)
799	RefPointer<Key> key = Server::key(keyh);
800	key->database().releaseKey(*key);
801	END_IPC(CSP)
802}
803
804kern_return_t ucsp_server_queryKeySizeInBits(UCSP_ARGS, KeyHandle keyh, CSSM_KEY_SIZE *length)
805{
806	BEGIN_IPC(queryKeySizeInBits)
807	RefPointer<Key> key = Server::key(keyh);
808	key->database().queryKeySizeInBits(*key, CssmKeySize::overlay(*length));
809	END_IPC(CSP)
810}
811
812kern_return_t ucsp_server_getOutputSize(UCSP_ARGS, DATA_IN(context), KeyHandle keyh,
813    uint32 inputSize, boolean_t encrypt, uint32 *outputSize)
814{
815    BEGIN_IPC(getOutputSize)
816	CopyOutContext ctx(context, contextLength);
817	RefPointer<Key> key = Server::key(keyh);
818    key->database().getOutputSize(*ctx, *key, inputSize, encrypt, *outputSize);
819    END_IPC(CSP)
820}
821
822kern_return_t ucsp_server_getKeyDigest(UCSP_ARGS, KeyHandle key, DATA_OUT(digest))
823{
824	BEGIN_IPC(getKeyDigest)
825	CssmData digestData = Server::key(key)->canonicalDigest();
826	*digest = digestData.data();
827	*digestLength = digestData.length();
828	END_IPC(CSP)
829}
830
831
832//
833// Signatures and MACs
834//
835kern_return_t ucsp_server_generateSignature(UCSP_ARGS, DATA_IN(context), KeyHandle keyh,
836        CSSM_ALGORITHMS signOnlyAlgorithm, DATA_IN(data), DATA_OUT(signature))
837{
838	BEGIN_IPC(generateSignature)
839	CopyOutContext ctx(context, contextLength);
840	RefPointer<Key> key = Server::key(keyh);
841	OutputData sigData(signature, signatureLength);
842	key->database().generateSignature(*ctx, *key, signOnlyAlgorithm,
843		DATA(data), sigData);
844	END_IPC(CSP)
845}
846
847kern_return_t ucsp_server_verifySignature(UCSP_ARGS, DATA_IN(context), KeyHandle keyh,
848		CSSM_ALGORITHMS verifyOnlyAlgorithm, DATA_IN(data), DATA_IN(signature))
849{
850	BEGIN_IPC(verifySignature)
851	CopyOutContext ctx(context, contextLength);
852	RefPointer<Key> key = Server::key(keyh);
853	key->database().verifySignature(*ctx, *key, verifyOnlyAlgorithm,
854		DATA(data), DATA(signature));
855	END_IPC(CSP)
856}
857
858kern_return_t ucsp_server_generateMac(UCSP_ARGS, DATA_IN(context), KeyHandle keyh,
859		DATA_IN(data), DATA_OUT(mac))
860{
861	BEGIN_IPC(generateMac)
862	CopyOutContext ctx(context, contextLength);
863	RefPointer<Key> key = Server::key(keyh);
864	OutputData macData(mac, macLength);
865	key->database().generateMac(*ctx, *key, DATA(data), macData);
866	END_IPC(CSP)
867}
868
869kern_return_t ucsp_server_verifyMac(UCSP_ARGS, DATA_IN(context), KeyHandle keyh,
870		DATA_IN(data), DATA_IN(mac))
871{
872	BEGIN_IPC(verifyMac)
873	CopyOutContext ctx(context, contextLength);
874	RefPointer<Key> key = Server::key(keyh);
875	key->database().verifyMac(*ctx, *key, DATA(data), DATA(mac));
876	END_IPC(CSP)
877}
878
879
880//
881// Encryption/Decryption
882//
883kern_return_t ucsp_server_encrypt(UCSP_ARGS, DATA_IN(context), KeyHandle keyh,
884	DATA_IN(clear), DATA_OUT(cipher))
885{
886	BEGIN_IPC(encrypt)
887	CopyOutContext ctx(context, contextLength);
888	RefPointer<Key> key = Server::key(keyh);
889	OutputData cipherOut(cipher, cipherLength);
890	key->database().encrypt(*ctx, *key, DATA(clear), cipherOut);
891	END_IPC(CSP)
892}
893
894kern_return_t ucsp_server_decrypt(UCSP_ARGS, DATA_IN(context), KeyHandle keyh,
895	DATA_IN(cipher), DATA_OUT(clear))
896{
897	BEGIN_IPC(decrypt)
898	CopyOutContext ctx(context, contextLength);
899	RefPointer<Key> key = Server::key(keyh);
900	OutputData clearOut(clear, clearLength);
901	key->database().decrypt(*ctx, *key, DATA(cipher), clearOut);
902	END_IPC(CSP)
903}
904
905
906//
907// Key generation
908//
909kern_return_t ucsp_server_generateKey(UCSP_ARGS, DbHandle db, DATA_IN(context),
910	DATA_IN(cred), DATA_IN(owner),
911	uint32 usage, uint32 attrs, KeyHandle *newKey, DATA_OUT(keyHeader))
912{
913	BEGIN_IPC(generateKey)
914	CopyOutContext ctx(context, contextLength);
915	CopyOutAccessCredentials creds(cred, credLength);
916
917	CopyOutEntryAcl owneracl(owner, ownerLength);
918	//@@@ preliminary interpretation - will get "type handle"
919	RefPointer<Database> database =
920		Server::optionalDatabase(db, attrs & CSSM_KEYATTR_PERMANENT);
921	RefPointer<Key> key;
922	database->generateKey(*ctx, creds, owneracl, usage, attrs, key);
923	CssmKey::Header newHeader;
924    key->returnKey(*newKey, newHeader);
925
926	if (!copyin(&newHeader, reinterpret_cast<xdrproc_t> (xdr_CSSM_KEYHEADER), keyHeader, keyHeaderLength))
927		CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
928	Server::releaseWhenDone(*keyHeader);
929	END_IPC(CSP)
930}
931
932kern_return_t ucsp_server_generateKeyPair(UCSP_ARGS, DbHandle db, DATA_IN(context),
933	DATA_IN(cred), DATA_IN(owner),
934	uint32 pubUsage, uint32 pubAttrs, uint32 privUsage, uint32 privAttrs,
935	KeyHandle *pubKey, DATA_OUT(pubHeader), KeyHandle *privKey, DATA_OUT(privHeader))
936{
937	BEGIN_IPC(generateKeyPair)
938	CopyOutContext ctx(context, contextLength);
939	CopyOutAccessCredentials creds(cred, credLength);
940	CopyOutEntryAcl owneracl(owner, ownerLength);
941	RefPointer<Database> database =
942		Server::optionalDatabase(db, (privAttrs | pubAttrs) & CSSM_KEYATTR_PERMANENT);
943	RefPointer<Key> pub, priv;
944	database->generateKey(*ctx, creds, owneracl,
945		pubUsage, pubAttrs, privUsage, privAttrs, pub, priv);
946	CssmKey::Header tmpPubHeader, tmpPrivHeader;
947
948    pub->returnKey(*pubKey, tmpPubHeader);
949	if (!copyin(&tmpPubHeader, reinterpret_cast<xdrproc_t> (xdr_CSSM_KEYHEADER), pubHeader, pubHeaderLength))
950		CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
951	Server::releaseWhenDone(*pubHeader);
952
953    priv->returnKey(*privKey, tmpPrivHeader);
954	if (!copyin(&tmpPrivHeader, reinterpret_cast<xdrproc_t> (xdr_CSSM_KEYHEADER), privHeader, privHeaderLength))
955		CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
956	Server::releaseWhenDone(*privHeader);
957
958	END_IPC(CSP)
959}
960
961
962//
963// Key wrapping and unwrapping
964//
965kern_return_t ucsp_server_wrapKey(UCSP_ARGS, DATA_IN(context), KeyHandle hWrappingKey,
966	DATA_IN(cred), KeyHandle hKeyToBeWrapped,
967	DATA_IN(descriptiveData), DATA_OUT(wrappedKeyData))
968{
969	BEGIN_IPC(wrapKey)
970	CssmKey wrappedKey;
971	CopyOutContext ctx(context, contextLength);
972	CopyOutAccessCredentials creds(cred, credLength);
973	RefPointer<Key> subjectKey = Server::key(hKeyToBeWrapped);
974	RefPointer<Key> wrappingKey = Server::optionalKey(hWrappingKey);
975	if ((ctx.context().algorithm() == CSSM_ALGID_NONE && subjectKey->attribute(CSSM_KEYATTR_SENSITIVE))
976		|| !subjectKey->attribute(CSSM_KEYATTR_EXTRACTABLE))
977		CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
978	pickDb(subjectKey, wrappingKey)->wrapKey(*ctx, creds, wrappingKey, *subjectKey, DATA(descriptiveData), wrappedKey);
979	Server::releaseWhenDone(wrappedKey.keyData().data());
980
981	if (!copyin(&wrappedKey, reinterpret_cast<xdrproc_t> (xdr_CSSM_KEY), wrappedKeyData, wrappedKeyDataLength))
982		CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
983
984	Server::releaseWhenDone(*wrappedKeyData);
985	END_IPC(CSP)
986}
987
988kern_return_t ucsp_server_unwrapKey(UCSP_ARGS, DbHandle db, DATA_IN(context),
989	KeyHandle hWrappingKey, DATA_IN(cred), DATA_IN(owner),
990	KeyHandle hPublicKey, DATA_IN(wrappedKeyData),
991	CSSM_KEYUSE usage, CSSM_KEYATTR_FLAGS attrs, DATA_OUT(descriptiveData),
992    KeyHandle *newKey, DATA_OUT(keyHeader)/*CssmKey::Header *newHeader*/)
993{
994	BEGIN_IPC(unwrapKey)
995	CopyOutContext ctx(context, contextLength);
996	CopyOutKey wrappedKey(wrappedKeyData, wrappedKeyDataLength);
997	CopyOutAccessCredentials creds(cred, credLength);
998	CopyOutEntryAcl owneracl(owner, ownerLength);
999	OutputData descriptiveDatas(descriptiveData, descriptiveDataLength);
1000	RefPointer<Key> wrappingKey = Server::optionalKey(hWrappingKey);
1001    RefPointer<Key> unwrappedKey;
1002	pickDb(Server::optionalDatabase(db), wrappingKey)->unwrapKey(*ctx, creds, owneracl,
1003		wrappingKey, Server::optionalKey(hPublicKey),
1004		usage, attrs, wrappedKey.key(), unwrappedKey, descriptiveDatas);
1005
1006	CssmKey::Header newHeader;
1007	unwrappedKey->returnKey(*newKey, newHeader);
1008	if (!copyin(&newHeader, reinterpret_cast<xdrproc_t> (xdr_CSSM_KEYHEADER), keyHeader, keyHeaderLength))
1009		CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
1010	Server::releaseWhenDone(*keyHeader);
1011
1012	END_IPC(CSP)
1013}
1014
1015
1016//
1017// Key derivation.
1018//
1019// Note that the "param" argument can have structure. The walker for the
1020// (artificial) POD CssmDeriveData handles those that are known; if you add
1021// an algorithm with structured param, you need to add a case there.
1022//
1023kern_return_t ucsp_server_deriveKey(UCSP_ARGS, DbHandle db, DATA_IN(context), KeyHandle hKey,
1024	DATA_IN(cred), DATA_IN(owner),
1025    DATA_IN(paramInput), DATA_OUT(paramOutput),
1026	uint32 usage, uint32 attrs, KeyHandle *newKey, DATA_OUT(keyHeader))
1027{
1028	BEGIN_IPC(deriveKey)
1029	CopyOutContext ctx(context, contextLength);
1030	CopyOutAccessCredentials creds(cred, credLength);
1031	CopyOutEntryAcl owneracl(owner, ownerLength);
1032	CopyOutDeriveData deriveParam(paramInput, paramInputLength);
1033	if (deriveParam.algorithm() != ctx.context().algorithm())
1034		CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);	// client layer fault
1035
1036	RefPointer<Database> database =
1037		Server::optionalDatabase(db, attrs & CSSM_KEYATTR_PERMANENT);
1038	RefPointer<Key> key = Server::optionalKey(hKey);
1039	CSSM_DATA param = deriveParam.cssm_data();
1040	RefPointer<Key> derivedKey;
1041	pickDb(Server::optionalDatabase(db, attrs & CSSM_KEYATTR_PERMANENT),
1042		key)->deriveKey(*ctx, key, creds, owneracl, static_cast<CssmData*>(&param), usage, attrs, derivedKey);
1043
1044	CssmKey::Header newHeader;
1045	derivedKey->returnKey(*newKey, newHeader);
1046
1047	if (!copyin(&newHeader, reinterpret_cast<xdrproc_t> (xdr_CSSM_KEYHEADER), keyHeader, keyHeaderLength))
1048		CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
1049	Server::releaseWhenDone(*keyHeader);
1050
1051	if (param.Length) {
1052        if (!param.Data)	// CSP screwed up
1053            CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
1054		OutputData(paramOutput, paramOutputLength) = CssmAutoData(Server::csp().allocator(), param).release();
1055    }
1056	END_IPC(CSP)
1057}
1058
1059
1060//
1061// Random generation
1062//
1063kern_return_t ucsp_server_generateRandom(UCSP_ARGS, uint32 ssid, DATA_IN(context), DATA_OUT(data))
1064{
1065	BEGIN_IPC(generateRandom)
1066	CopyOutContext ctx(context, contextLength);
1067	if (ssid)
1068		CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
1069
1070	// default version (use /dev/random)
1071	Allocator &allocator = Allocator::standard(Allocator::sensitive);
1072	if (size_t bytes = ctx.context().getInt(CSSM_ATTRIBUTE_OUTPUT_SIZE)) {
1073		void *buffer = allocator.malloc(bytes);
1074		Server::active().random(buffer, bytes);
1075		*data = buffer;
1076		*dataLength = bytes;
1077		Server::releaseWhenDone(allocator, buffer);
1078	}
1079	END_IPC(CSP)
1080}
1081
1082
1083//
1084// ACL management.
1085// Watch out for the memory-management tap-dance.
1086//
1087kern_return_t ucsp_server_getOwner(UCSP_ARGS, AclKind kind, KeyHandle key,
1088	DATA_OUT(ownerOut))
1089{
1090	BEGIN_IPC(getOwner)
1091	AclOwnerPrototype owner;
1092	Server::aclBearer(kind, key).getOwner(owner);	// allocates memory in owner
1093	void *owners_data; u_int owners_length;
1094	if (!::copyin(&owner, reinterpret_cast<xdrproc_t>(xdr_CSSM_ACL_OWNER_PROTOTYPE), &owners_data, &owners_length))
1095			CssmError::throwMe(CSSM_ERRCODE_MEMORY_ERROR);
1096
1097	{ ChunkFreeWalker free; walk(free, owner); } // release chunked original
1098	Server::releaseWhenDone(owners_data); // throw flat copy out when done
1099	*ownerOut = owners_data;
1100	*ownerOutLength = owners_length;
1101	END_IPC(CSP)
1102}
1103
1104kern_return_t ucsp_server_setOwner(UCSP_ARGS, AclKind kind, KeyHandle key,
1105	DATA_IN(cred), DATA_IN(owner))
1106{
1107	BEGIN_IPC(setOwner)
1108	CopyOutAccessCredentials creds(cred, credLength);
1109	CopyOutOwnerAcl owneracl(owner, ownerLength);
1110	Server::aclBearer(kind, key).changeOwner(*owneracl, creds);
1111	END_IPC(CSP)
1112}
1113
1114kern_return_t ucsp_server_getAcl(UCSP_ARGS, AclKind kind, KeyHandle key,
1115	boolean_t haveTag, const char *tag,
1116	uint32 *countp, DATA_OUT(acls))
1117{
1118	BEGIN_IPC(getAcl)
1119	uint32 count;
1120	AclEntryInfo *aclList;
1121	Server::aclBearer(kind, key).getAcl(haveTag ? tag : NULL, count, aclList);
1122
1123	CSSM_ACL_ENTRY_INFO_ARRAY aclsArray = { count, aclList };
1124	void *acls_data; u_int acls_length;
1125	if (!::copyin(&aclsArray, reinterpret_cast<xdrproc_t>(xdr_CSSM_ACL_ENTRY_INFO_ARRAY), &acls_data, &acls_length))
1126			CssmError::throwMe(CSSM_ERRCODE_MEMORY_ERROR);
1127
1128	{       // release the chunked memory originals
1129			ChunkFreeWalker free;
1130			for (uint32 n = 0; n < count; n++)
1131					walk(free, aclList[n]);
1132
1133			// release the memory allocated for the list itself when we are done
1134			Allocator::standard().free (aclList);
1135	}
1136
1137
1138	*countp = count; // XXX/cs count becomes part of the blob
1139	*aclsLength = acls_length;
1140	*acls = acls_data;
1141	Server::releaseWhenDone(acls_data);
1142	END_IPC(CSP)
1143}
1144
1145kern_return_t ucsp_server_changeAcl(UCSP_ARGS, AclKind kind, KeyHandle key,
1146	DATA_IN(cred), CSSM_ACL_EDIT_MODE mode, GenericHandle handle,
1147	DATA_IN(acl))
1148{
1149	BEGIN_IPC(changeAcl)
1150	CopyOutAccessCredentials creds(cred, credLength);
1151	CopyOutAclEntryInput entryacl(acl, aclLength);
1152
1153	Server::aclBearer(kind, key).changeAcl(AclEdit(mode, handle, entryacl), creds);
1154	END_IPC(CSP)
1155}
1156
1157
1158//
1159// Login/Logout
1160//
1161kern_return_t ucsp_server_login(UCSP_ARGS, DATA_IN(cred), DATA_IN(name))
1162{
1163	BEGIN_IPC(login)
1164	CopyOutAccessCredentials creds(cred, credLength);
1165	CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
1166	END_IPC(CSP)
1167}
1168
1169kern_return_t ucsp_server_logout(UCSP_ARGS)
1170{
1171	BEGIN_IPC(logout)
1172	CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
1173	END_IPC(CSP)
1174}
1175
1176
1177//
1178// Miscellaneous CSP-related calls
1179//
1180kern_return_t ucsp_server_getStatistics(UCSP_ARGS, uint32 ssid, CSSM_CSP_OPERATIONAL_STATISTICS *statistics)
1181{
1182	BEGIN_IPC(getStatistics)
1183	CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
1184	END_IPC(CSP)
1185}
1186
1187kern_return_t ucsp_server_getTime(UCSP_ARGS, uint32 ssid, CSSM_ALGORITHMS algorithm, DATA_OUT(data))
1188{
1189	BEGIN_IPC(getTime)
1190	CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
1191	END_IPC(CSP)
1192}
1193
1194kern_return_t ucsp_server_getCounter(UCSP_ARGS, uint32 ssid, DATA_OUT(data))
1195{
1196	BEGIN_IPC(getCounter)
1197	CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
1198	END_IPC(CSP)
1199}
1200
1201kern_return_t ucsp_server_selfVerify(UCSP_ARGS, uint32 ssid)
1202{
1203	BEGIN_IPC(selfVerify)
1204	CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
1205	END_IPC(CSP)
1206}
1207
1208
1209//
1210// Passthrough calls (separate for CSP and DL passthroughs)
1211//
1212kern_return_t ucsp_server_cspPassThrough(UCSP_ARGS, uint32 ssid, uint32 id, DATA_IN(context),
1213	KeyHandle hKey, DATA_IN(inData), DATA_OUT(outData))
1214{
1215	BEGIN_IPC(cspPassThrough)
1216	CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
1217	END_IPC(CSP)
1218}
1219
1220kern_return_t ucsp_server_dlPassThrough(UCSP_ARGS, uint32 ssid, uint32 id,
1221	DATA_IN(inData), DATA_OUT(outData))
1222{
1223	BEGIN_IPC(dlPassThrough)
1224	CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
1225	END_IPC(DL)
1226}
1227
1228
1229//
1230// Database key management.
1231// ExtractMasterKey looks vaguely like a key derivation operation, and is in fact
1232// presented by the CSPDL's CSSM layer as such.
1233//
1234kern_return_t ucsp_server_extractMasterKey(UCSP_ARGS, DbHandle db, DATA_IN(context), DbHandle sourceDb,
1235	DATA_IN(cred), DATA_IN(owner),
1236	uint32 usage, uint32 attrs, KeyHandle *newKey, DATA_OUT(keyHeader))
1237{
1238	BEGIN_IPC(extractMasterKey)
1239	CopyOutAccessCredentials creds(cred, credLength);
1240	CopyOutEntryAcl owneracl(owner, ownerLength);
1241	CopyOutContext ctx(context, contextLength);
1242	RefPointer<KeychainDatabase> keychain = Server::keychain(sourceDb);
1243	RefPointer<Key> masterKey = keychain->extractMasterKey(
1244		*Server::optionalDatabase(db, attrs & CSSM_KEYATTR_PERMANENT),
1245		creds, owneracl, usage, attrs);
1246	CssmKey::Header header;
1247	masterKey->returnKey(*newKey, header);
1248	if (!copyin(&header, reinterpret_cast<xdrproc_t> (xdr_CSSM_KEYHEADER), keyHeader, keyHeaderLength))
1249		CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
1250	Server::releaseWhenDone(*keyHeader);
1251	END_IPC(CSP)
1252}
1253
1254
1255//
1256// Authorization subsystem support
1257//
1258kern_return_t ucsp_server_authorizationCreate(UCSP_ARGS,
1259	void *inRights, mach_msg_type_number_t inRightsLength,
1260	uint32 flags,
1261	void *inEnvironment, mach_msg_type_number_t inEnvironmentLength,
1262	AuthorizationBlob *authorization)
1263{
1264	BEGIN_IPC(authorizationCreate)
1265	AuthorizationItemSet *authrights = NULL, *authenvironment = NULL;
1266
1267	if (inRights && !copyout_AuthorizationItemSet(inRights, inRightsLength, &authrights))
1268	{
1269		Syslog::alert("ucsp_server_authorizationCreate(): error converting 'rights' input");
1270		CssmError::throwMe(errAuthorizationInternal); // allocation error probably
1271	}
1272
1273	if (inEnvironment && !copyout_AuthorizationItemSet(inEnvironment, inEnvironmentLength, &authenvironment))
1274	{
1275		free(authrights);
1276		Syslog::alert("ucsp_server_authorizationCreate(): error converting 'environment' input");
1277		CssmError::throwMe(errAuthorizationInternal); // allocation error probably
1278	}
1279
1280	Authorization::AuthItemSet rights(authrights), environment(authenvironment);
1281
1282	*rcode = connection.process().session().authCreate(rights, environment,
1283		flags, *authorization, auditToken);
1284
1285	// @@@ safe-guard against code throw()ing in here
1286
1287	if (authrights)
1288		free(authrights);
1289
1290	if (authenvironment)
1291		free(authenvironment);
1292
1293	END_IPC(CSSM)
1294}
1295
1296kern_return_t ucsp_server_authorizationRelease(UCSP_ARGS,
1297	AuthorizationBlob authorization, uint32 flags)
1298{
1299	BEGIN_IPC(authorizationRelease)
1300	connection.process().session().authFree(authorization, flags);
1301	END_IPC(CSSM)
1302}
1303
1304kern_return_t ucsp_server_authorizationCopyRights(UCSP_ARGS,
1305	AuthorizationBlob authorization,
1306	void *inRights, mach_msg_type_number_t inRightsLength,
1307	uint32 flags,
1308	void *inEnvironment, mach_msg_type_number_t inEnvironmentLength,
1309	void **result, mach_msg_type_number_t *resultLength)
1310{
1311	BEGIN_IPC(authorizationCopyRights)
1312	AuthorizationItemSet *authrights = NULL, *authenvironment = NULL;
1313
1314	if (inRights && !copyout_AuthorizationItemSet(inRights, inRightsLength, &authrights))
1315	{
1316		Syslog::alert("ucsp_server_authorizationCopyRights(): error converting 'rights' input");
1317		CssmError::throwMe(errAuthorizationInternal); // allocation error probably
1318	}
1319	if (inEnvironment && !copyout_AuthorizationItemSet(inEnvironment, inEnvironmentLength, &authenvironment))
1320	{
1321		free(authrights);
1322		Syslog::alert("ucsp_server_authorizationCopyRights(): error converting 'environment' input");
1323		CssmError::throwMe(errAuthorizationInternal); // allocation error probably
1324	}
1325
1326	Authorization::AuthItemSet rights(authrights), environment(authenvironment), grantedRights;
1327	*rcode = Session::authGetRights(authorization, rights, environment, flags, grantedRights);
1328
1329	// @@@ safe-guard against code throw()ing in here
1330
1331	if (authrights)
1332		free(authrights);
1333
1334	if (authenvironment)
1335		free(authenvironment);
1336
1337	if (result && resultLength)
1338	{
1339		AuthorizationItemSet *copyout = grantedRights.copy();
1340		if (!copyin_AuthorizationItemSet(copyout, result, resultLength))
1341		{
1342			free(copyout);
1343            Syslog::alert("ucsp_server_authorizationCopyRights(): error packaging return information");
1344			CssmError::throwMe(errAuthorizationInternal);
1345		}
1346		free(copyout);
1347		Server::releaseWhenDone(*result);
1348	}
1349	END_IPC(CSSM)
1350}
1351
1352kern_return_t ucsp_server_authorizationCopyInfo(UCSP_ARGS,
1353	AuthorizationBlob authorization,
1354	AuthorizationString tag,
1355	void **info, mach_msg_type_number_t *infoLength)
1356{
1357	BEGIN_IPC(authorizationCopyInfo)
1358    Authorization::AuthItemSet infoSet;
1359    *info = NULL;
1360    *infoLength = 0;
1361    *rcode = connection.process().session().authGetInfo(authorization,
1362        tag[0] ? tag : NULL, infoSet);
1363    if (*rcode == noErr)
1364	{
1365		AuthorizationItemSet *copyout = infoSet.copy();
1366		if (!copyin_AuthorizationItemSet(copyout, info, infoLength))
1367		{
1368			free(copyout);
1369            Syslog::alert("ucsp_server_authorizationCopyInfo(): error packaging return information");
1370			CssmError::throwMe(errAuthorizationInternal);
1371		}
1372		free(copyout);
1373        Server::releaseWhenDone(*info);
1374    }
1375    END_IPC(CSSM)
1376}
1377
1378kern_return_t ucsp_server_authorizationExternalize(UCSP_ARGS,
1379	AuthorizationBlob authorization, AuthorizationExternalForm *extForm)
1380{
1381	BEGIN_IPC(authorizationExternalize)
1382	*rcode = connection.process().session().authExternalize(authorization, *extForm);
1383	END_IPC(CSSM)
1384}
1385
1386kern_return_t ucsp_server_authorizationInternalize(UCSP_ARGS,
1387	AuthorizationExternalForm extForm, AuthorizationBlob *authorization)
1388{
1389	BEGIN_IPC(authorizationInternalize)
1390	*rcode = connection.process().session().authInternalize(extForm, *authorization);
1391	END_IPC(CSSM)
1392}
1393
1394
1395//
1396// Session management subsystem
1397//
1398kern_return_t ucsp_server_setSessionUserPrefs(UCSP_ARGS, SecuritySessionId sessionId, DATA_IN(userPrefs))
1399{
1400	BEGIN_IPC(setSessionuserPrefs)
1401	CFRef<CFDataRef> data(CFDataCreate(NULL, (UInt8 *)userPrefs, userPrefsLength));
1402
1403	if (!data)
1404	{
1405		*rcode = errSessionValueNotSet;
1406		return 0;
1407	}
1408
1409	Session::find<DynamicSession>(sessionId).setUserPrefs(data);
1410	*rcode = 0;
1411
1412	END_IPC(CSSM)
1413}
1414
1415
1416//
1417// Notification core subsystem
1418//
1419
1420kern_return_t ucsp_server_postNotification(UCSP_ARGS, uint32 domain, uint32 event,
1421	DATA_IN(data), uint32 sequence)
1422{
1423	BEGIN_IPC(postNotification)
1424		Listener::notify(domain, event, sequence, DATA(data));
1425	END_IPC(CSSM)
1426}
1427
1428
1429//
1430// AuthorizationDB modification
1431//
1432kern_return_t ucsp_server_authorizationdbGet(UCSP_ARGS, const char *rightname, DATA_OUT(rightDefinition))
1433{
1434	BEGIN_IPC(authorizationdbGet)
1435	CFDictionaryRef rightDict;
1436
1437	*rcode = connection.process().session().authorizationdbGet(rightname, &rightDict);
1438
1439	if (!*rcode && rightDict)
1440	{
1441		CFRef<CFDataRef> data(CFPropertyListCreateXMLData (NULL, rightDict));
1442		CFRelease(rightDict);
1443		if (!data)
1444		{
1445			Syslog::alert("ucsp_server_authorizationGet(): unable to make XML version of right definition for '%s'", rightname);
1446			return errAuthorizationInternal;
1447		}
1448
1449		// @@@ copy data to avoid having to do a delayed cfrelease
1450		mach_msg_type_number_t length = CFDataGetLength(data);
1451		void *xmlData = Allocator::standard().malloc(length);
1452		memcpy(xmlData, CFDataGetBytePtr(data), length);
1453		Server::releaseWhenDone(xmlData);
1454
1455		*rightDefinition = xmlData;
1456		*rightDefinitionLength = length;
1457	}
1458	END_IPC(CSSM)
1459}
1460
1461kern_return_t ucsp_server_authorizationdbSet(UCSP_ARGS, AuthorizationBlob authorization, const char *rightname, DATA_IN(rightDefinition))
1462{
1463	BEGIN_IPC(authorizationdbSet)
1464	CFRef<CFDataRef> data(CFDataCreate(NULL, (UInt8 *)rightDefinition, rightDefinitionLength));
1465
1466	if (!data)
1467	{
1468		Syslog::alert("ucsp_server_authorizationSet(): CFDataCreate() error");
1469		return errAuthorizationInternal;
1470	}
1471
1472	CFRef<CFDictionaryRef> rightDefinition(static_cast<CFDictionaryRef>(CFPropertyListCreateFromXMLData(NULL, data, kCFPropertyListImmutable, NULL)));
1473
1474	if (!rightDefinition || (CFGetTypeID(rightDefinition) != CFDictionaryGetTypeID()))
1475	{
1476        Syslog::alert("ucsp_server_authorizationSet(): error converting XML right definition for '%s' to property list", rightname);
1477		return errAuthorizationInternal;
1478	}
1479
1480	*rcode = connection.process().session().authorizationdbSet(authorization, rightname, rightDefinition);
1481
1482	END_IPC(CSSM)
1483}
1484
1485kern_return_t ucsp_server_authorizationdbRemove(UCSP_ARGS, AuthorizationBlob authorization, const char *rightname)
1486{
1487	BEGIN_IPC(authorizationdbRemove)
1488	*rcode = connection.process().session().authorizationdbRemove(authorization, rightname);
1489	END_IPC(CSSM)
1490}
1491
1492
1493//
1494// Miscellaneous administrative functions
1495//
1496kern_return_t ucsp_server_addCodeEquivalence(UCSP_ARGS, DATA_IN(oldHash), DATA_IN(newHash),
1497	const char *name, boolean_t forSystem)
1498{
1499	BEGIN_IPC(addCodeEquivalence)
1500	Server::codeSignatures().addLink(DATA(oldHash), DATA(newHash), name, forSystem);
1501	END_IPC(CSSM)
1502}
1503
1504kern_return_t ucsp_server_removeCodeEquivalence(UCSP_ARGS, DATA_IN(hash),
1505	const char *name, boolean_t forSystem)
1506{
1507	BEGIN_IPC(removeCodeEquivalence)
1508	Server::codeSignatures().removeLink(DATA(hash), name, forSystem);
1509	END_IPC(CSSM)
1510}
1511
1512kern_return_t ucsp_server_setAlternateSystemRoot(UCSP_ARGS, const char *root)
1513{
1514	BEGIN_IPC(setAlternateSystemRoot)
1515#if defined(NDEBUG)
1516	if (connection.process().uid() != 0)
1517		CssmError::throwMe(CSSM_ERRCODE_OS_ACCESS_DENIED);
1518#endif //NDEBUG
1519	Server::codeSignatures().open((string(root) + EQUIVALENCEDBPATH).c_str());
1520	END_IPC(CSSM)
1521}
1522
1523
1524//
1525// Child check-in service.
1526// Note that this isn't using the standard argument pattern.
1527//
1528kern_return_t ucsp_server_childCheckIn(mach_port_t serverPort,
1529	mach_port_t servicePort, mach_port_t taskPort)
1530{
1531	BEGIN_IPCS
1532	ServerChild::checkIn(servicePort, TaskPort(taskPort).pid());
1533	END_IPCS(mach_port_deallocate(mach_task_self(), taskPort))
1534}
1535
1536
1537//
1538// Code Signing Hosting registration.
1539// Note that the Code Signing Proxy facility (implementing the "cshosting"
1540// IPC protocol) is elsewhere.
1541//
1542kern_return_t ucsp_server_registerHosting(UCSP_ARGS, mach_port_t hostingPort, uint32 flags)
1543{
1544	BEGIN_IPC(registerHosting)
1545	connection.process().registerCodeSigning(hostingPort, flags);
1546	END_IPC(CSSM)
1547}
1548
1549kern_return_t ucsp_server_hostingPort(UCSP_ARGS, pid_t hostPid, mach_port_t *hostingPort)
1550{
1551	BEGIN_IPC(hostingPort)
1552	if (RefPointer<Process> process = Server::active().findPid(hostPid))
1553		*hostingPort = process->hostingPort();
1554	else
1555		*hostingPort = MACH_PORT_NULL;
1556	secdebug("hosting", "hosting port for for pid=%d is port %d", hostPid, *hostingPort);
1557	END_IPC(CSSM)
1558}
1559
1560
1561kern_return_t ucsp_server_setGuest(UCSP_ARGS, SecGuestRef guest, SecCSFlags flags)
1562{
1563	BEGIN_IPC(setGuest)
1564	connection.guestRef(guest, flags);
1565	END_IPC(CSSM)
1566}
1567
1568
1569kern_return_t ucsp_server_createGuest(UCSP_ARGS, SecGuestRef host,
1570	uint32_t status, const char *path, DATA_IN(cdhash), DATA_IN(attributes),
1571	SecCSFlags flags, SecGuestRef *newGuest)
1572{
1573	BEGIN_IPC(createGuest)
1574	*newGuest = connection.process().createGuest(host, status, path, DATA(cdhash), DATA(attributes), flags);
1575	END_IPC(CSSM)
1576}
1577
1578kern_return_t ucsp_server_setGuestStatus(UCSP_ARGS, SecGuestRef guest,
1579	uint32_t status, DATA_IN(attributes))
1580{
1581	BEGIN_IPC(setGuestStatus)
1582	connection.process().setGuestStatus(guest, status, DATA(attributes));
1583	END_IPC(CSSM)
1584}
1585
1586kern_return_t ucsp_server_removeGuest(UCSP_ARGS, SecGuestRef host, SecGuestRef guest)
1587{
1588	BEGIN_IPC(removeGuest)
1589	connection.process().removeGuest(host, guest);
1590	END_IPC(CSSM)
1591}
1592
1593kern_return_t ucsp_server_helpCheckLoad(UCSP_ARGS, const char path[PATH_MAX], uint32_t type)
1594{
1595	BEGIN_IPC(helpCheckLoad)
1596	END_IPC(CSSM)
1597}
1598