2 * Copyright (c) 2000-2009,2012-2013 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 // transition - securityd IPC-to-class-methods transition layer
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.
32 #include <securityd_client/ss_types.h>
33 #include <securityd_client/ucsp.h>
36 #include "agentquery.h"
38 #include "kcdatabase.h"
39 #include "tokendatabase.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>
50 #include <CoreFoundation/CFNumber.h>
51 #include <CoreFoundation/CFDictionary.h>
52 #include <CoreFoundation/CFPropertyList.h>
57 #define UCSP_ARGS mach_port_t servicePort, mach_port_t replyPort, \
58 audit_token_t auditToken, CSSM_RETURN *rcode
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()); \
67 #define END_IPC(base) END_IPCN(base) Server::requestComplete(*rcode); return KERN_SUCCESS;
68 #define END_IPCN(base) SECURITYD_REQUEST_RETURN(*rcode); \
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); }
75 #define BEGIN_IPCS try {
76 #define END_IPCS(more) } catch (...) { } \
77 mach_port_deallocate(mach_task_self(), servicePort); more; return KERN_SUCCESS;
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)
83 #define SSBLOB(Type, name) makeBlob<Type>(DATA(name))
85 using LowLevelMemoryUtilities::increment
;
86 using LowLevelMemoryUtilities::difference
;
88 class CopyOutAccessCredentials
: public CopyOut
{
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())); }
95 class CopyOutEntryAcl
: public CopyOut
{
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())); }
101 class CopyOutOwnerAcl
: public CopyOut
{
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())); }
107 class CopyOutAclEntryInput
: public CopyOut
{
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())); }
114 class CopyOutDeriveData
: public CopyOut
{
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
; }
123 class CopyOutContext
: public CopyOut
{
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())); }
130 class CopyOutKey
: public CopyOut
{
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())); }
137 class CopyOutDbRecordAttributes
: public CopyOut
{
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())); }
143 class CopyOutQuery
: public CopyOut
{
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())); }
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.
153 template <class BlobType
>
154 const BlobType
*makeBlob(const CssmData
&blobData
, CSSM_RETURN error
= CSSM_ERRCODE_INVALID_DATA
)
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
);
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
170 class OutputData
: public CssmData
{
172 OutputData(void **outP
, mach_msg_type_number_t
*outLength
)
173 : mData(*outP
), mLength(*outLength
) { }
175 { mData
= data(); mLength
= length(); Server::releaseWhenDone(mData
); }
177 void operator = (const CssmData
&source
)
178 { CssmData::operator = (source
); }
182 mach_msg_type_number_t
&mLength
;
186 // Choose a Database from a choice of two sources, giving preference
187 // to persistent stores and to earlier sources.
189 Database
*pickDb(Database
*db1
, Database
*db2
);
191 static inline Database
*dbOf(Key
*key
) { return key
? &key
->database() : NULL
; }
193 inline Database
*pickDb(Key
*k1
, Key
*k2
) { return pickDb(dbOf(k1
), dbOf(k2
)); }
194 inline Database
*pickDb(Database
*db1
, Key
*k2
) { return pickDb(db1
, dbOf(k2
)); }
195 inline Database
*pickDb(Key
*k1
, Database
*db2
) { return pickDb(dbOf(k1
), db2
); }
198 // Choose a Database from a choice of two sources, giving preference
199 // to persistent stores and to earlier sources.
201 Database
*pickDb(Database
*db1
, Database
*db2
)
203 // persistent db1 always wins
204 if (db1
&& !db1
->transient())
207 // persistent db2 is next choice
208 if (db2
&& !db2
->transient())
211 // pick any existing transient database
217 // none at all. use the canonical transient store
218 return Server::optionalDatabase(noDb
);
222 // Setup/Teardown functions.
224 kern_return_t
ucsp_server_setup(UCSP_ARGS
, mach_port_t taskPort
, ClientSetupInfo info
, const char *identity
)
227 SECURITYD_REQUEST_ENTRY((char*)"setup", NULL
, NULL
);
228 Server::active().setupConnection(Server::connectNewProcess
, replyPort
,
229 taskPort
, auditToken
, &info
);
232 Syslog::notice("setup(%s) failed rcode=%d", identity
? identity
: "<NULL>", *rcode
);
237 kern_return_t
ucsp_server_setupThread(UCSP_ARGS
, mach_port_t taskPort
)
239 SECURITYD_REQUEST_ENTRY((char*)"setupThread", NULL
, NULL
);
241 Server::active().setupConnection(Server::connectNewThread
, replyPort
, taskPort
, auditToken
);
244 Syslog::notice("setupThread failed rcode=%d", *rcode
);
249 kern_return_t
ucsp_server_teardown(UCSP_ARGS
)
252 SECURITYD_REQUEST_ENTRY((char*)"teardown", NULL
, NULL
);
253 Server::active().endConnection(replyPort
);
258 kern_return_t
ucsp_server_verifyPrivileged(UCSP_ARGS
)
261 SECURITYD_REQUEST_ENTRY((char*)"verifyPrivileged", NULL
, NULL
);
262 // doing nothing (we just want securityd's audit credentials returned)
267 kern_return_t
ucsp_server_verifyPrivileged2(UCSP_ARGS
, mach_port_t
*originPort
)
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
;
278 // Common database operations
280 kern_return_t
ucsp_server_authenticateDb(UCSP_ARGS
, DbHandle db
,
281 CSSM_DB_ACCESS_TYPE accessType
, DATA_IN(cred
))
283 BEGIN_IPC(authenticateDb
)
284 secdebug("dl", "authenticateDb");
285 CopyOutAccessCredentials
creds(cred
, credLength
);
286 // ignoring accessType
287 Server::database(db
)->authenticate(accessType
, creds
);
291 kern_return_t
ucsp_server_releaseDb(UCSP_ARGS
, DbHandle db
)
294 connection
.process().kill(*Server::database(db
));
299 kern_return_t
ucsp_server_getDbName(UCSP_ARGS
, DbHandle db
, char name
[PATH_MAX
])
302 string result
= Server::database(db
)->dbName();
303 assert(result
.length() < PATH_MAX
);
304 memcpy(name
, result
.c_str(), result
.length() + 1);
308 kern_return_t
ucsp_server_setDbName(UCSP_ARGS
, DbHandle db
, const char *name
)
311 Server::database(db
)->dbName(name
);
317 // External database interface
319 kern_return_t
ucsp_server_openToken(UCSP_ARGS
, uint32 ssid
, FilePath name
,
320 DATA_IN(accessCredentials
), DbHandle
*db
)
323 CopyOutAccessCredentials
creds(accessCredentials
, accessCredentialsLength
);
324 *db
= (new TokenDatabase(ssid
, connection
.process(), name
, creds
))->handle();
328 kern_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
)
334 CopyOutQuery
query(inQuery
, inQueryLength
);
335 CopyOutDbRecordAttributes
attrs(inAttributes
, inAttributesLength
);
337 RefPointer
<Database::Search
> search
;
338 RefPointer
<Database::Record
> record
;
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
);
346 // handle nothing-found case without exceptions
353 *hRecord
= record
->handle();
354 *hSearch
= search
->handle();
355 *hKey
= key
? key
->handle() : noKey
;
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
);
364 // return data (temporary fix)
366 Server::releaseWhenDone(outData
.data());
367 xdrproc_t encode_proc
= reinterpret_cast<xdrproc_t
>(xdr_CSSM_NO_KEY_IN_DATA
);
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
);
379 kern_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
)
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
;
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
);
396 // handle nothing-found case without exceptions
402 *hRecord
= record
->handle();
403 *hKey
= key
? key
->handle() : noKey
;
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
);
414 // return data (temporary fix)
416 Server::releaseWhenDone(outData
.data());
417 xdrproc_t encode_proc
= reinterpret_cast<xdrproc_t
>(xdr_CSSM_NO_KEY_IN_DATA
);
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
);
428 kern_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
)
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
);
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
);
443 *hKey
= key
? key
->handle() : noKey
;
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
);
452 // return data (temporary fix)
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
460 Server::releaseWhenDone(outData
.data());
461 xdrproc_t encode_proc
= reinterpret_cast<xdrproc_t
>(xdr_CSSM_NO_KEY_IN_DATA
);
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
);
471 kern_return_t
ucsp_server_insertRecord(UCSP_ARGS
, DbHandle db
, CSSM_DB_RECORDTYPE recordType
,
472 DATA_IN(inAttributes
), DATA_IN(data
), IPCRecordHandle
*record
)
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
;
483 kern_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
)
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)
499 kern_return_t
ucsp_server_deleteRecord(UCSP_ARGS
, DbHandle db
, IPCRecordHandle hRecord
)
501 BEGIN_IPC(deleteRecord
)
502 Server::database(db
)->deleteRecord(
503 Server::find
<Database::Record
>(hRecord
, CSSMERR_DL_INVALID_RECORD_UID
));
507 kern_return_t
ucsp_server_releaseSearch(UCSP_ARGS
, SearchHandle hSearch
)
509 BEGIN_IPC(releaseSearch
)
510 RefPointer
<Database::Search
> search
= Server::find
<Database::Search
>(hSearch
, 0);
511 search
->database().releaseSearch(*search
);
515 kern_return_t
ucsp_server_releaseRecord(UCSP_ARGS
, IPCRecordHandle hRecord
)
517 BEGIN_IPC(releaseRecord
)
518 RefPointer
<Database::Record
> record
= Server::find
<Database::Record
>(hRecord
, 0);
519 record
->database().releaseRecord(*record
);
525 // Internal database management
527 kern_return_t
ucsp_server_createDb(UCSP_ARGS
, DbHandle
*db
,
528 DATA_IN(ident
), DATA_IN(cred
), DATA_IN(owner
),
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();
539 kern_return_t
ucsp_server_recodeDbForSync(UCSP_ARGS
, DbHandle dbToClone
,
540 DbHandle srcDb
, DbHandle
*newDb
)
542 BEGIN_IPC(recodeDbForSync
)
543 RefPointer
<KeychainDatabase
> srcKC
= Server::keychain(srcDb
);
544 *newDb
= (new KeychainDatabase(*srcKC
, connection
.process(), dbToClone
))->handle();
548 kern_return_t
ucsp_server_authenticateDbsForSync(UCSP_ARGS
, DATA_IN(dbHandleArray
),
549 DATA_IN(agentData
), DbHandle
* authenticatedDBHandle
)
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);
563 for (index
=0; index
< ipcDbHandleArrayCount
; index
++)
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
++;
570 Server::releaseWhenDone(ipcDbHandleArray
);
571 if (query(ipcDbHandleArray
, ipcDbHandleArrayCount
, authenticatedDBHandle
) != SecurityAgent::noReason
)
572 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
576 kern_return_t
ucsp_server_commitDbForSync(UCSP_ARGS
, DbHandle srcDb
,
577 DbHandle cloneDb
, DATA_OUT(blob
))
579 BEGIN_IPC(commitDbForSync
)
580 RefPointer
<KeychainDatabase
> srcKC
= Server::keychain(srcDb
);
581 RefPointer
<KeychainDatabase
> cloneKC
= Server::keychain(cloneDb
);
582 srcKC
->commitSecretsForSync(*cloneKC
);
584 // re-encode blob for convenience
585 if (blob
&& blobLength
) {
586 DbBlob
*dbBlob
= srcKC
->blob();
588 *blobLength
= dbBlob
->length();
590 secdebug("kcrecode", "No blob can be returned to client");
595 kern_return_t
ucsp_server_decodeDb(UCSP_ARGS
, DbHandle
*db
,
596 DATA_IN(ident
), DATA_IN(cred
), DATA_IN(blob
))
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
604 *db
= (new KeychainDatabase(id
, SSBLOB(DbBlob
, blob
),
605 connection
.process(), creds
))->handle();
609 kern_return_t
ucsp_server_encodeDb(UCSP_ARGS
, DbHandle db
, DATA_OUT(blob
))
612 DbBlob
*dbBlob
= Server::keychain(db
)->blob(); // memory owned by database
614 *blobLength
= dbBlob
->length();
618 kern_return_t
ucsp_server_setDbParameters(UCSP_ARGS
, DbHandle db
, DBParameters params
)
620 BEGIN_IPC(setDbParameters
)
621 Server::keychain(db
)->setParameters(params
);
625 kern_return_t
ucsp_server_getDbParameters(UCSP_ARGS
, DbHandle db
, DBParameters
*params
)
627 BEGIN_IPC(getDbParameters
)
628 Server::keychain(db
)->getParameters(*params
);
632 kern_return_t
ucsp_server_changePassphrase(UCSP_ARGS
, DbHandle db
,
635 BEGIN_IPC(changePassphrase
)
636 CopyOutAccessCredentials
creds(cred
, credLength
);
637 Server::keychain(db
)->changePassphrase(creds
);
641 kern_return_t
ucsp_server_lockAll (UCSP_ARGS
, boolean_t
)
644 connection
.session().processLockAll();
648 kern_return_t
ucsp_server_unlockDb(UCSP_ARGS
, DbHandle db
)
651 Server::keychain(db
)->unlockDb();
655 static void check_stash_entitlement(Process
& proc
)
657 OSStatus status
= noErr
;
658 CFDictionaryRef code_info
= NULL
;
659 CFDictionaryRef entitlements
= NULL
;
660 CFTypeRef value
= NULL
;
661 bool entitled
= false;
663 status
= SecCodeCopySigningInformation(proc
.processCode(), kSecCSRequirementInformation
, &code_info
);
664 require_noerr(status
, done
);
666 if (CFDictionaryGetValueIfPresent(code_info
, kSecCodeInfoEntitlementsDict
, &value
)) {
667 if (CFGetTypeID(value
) == CFDictionaryGetTypeID()) {
668 entitlements
= (CFDictionaryRef
)value
;
671 require(entitlements
!= NULL
, done
);
673 if (CFDictionaryGetValueIfPresent(entitlements
, CFSTR("com.apple.private.securityd.stash"), &value
)) {
674 if (CFGetTypeID(value
) && CFBooleanGetTypeID()) {
675 entitled
= CFBooleanGetValue((CFBooleanRef
)value
);
681 CFRelease(code_info
);
685 CssmError::throwMe(CSSM_ERRCODE_OS_ACCESS_DENIED
);
689 kern_return_t
ucsp_server_unlockDbWithPassphrase(UCSP_ARGS
, DbHandle db
, DATA_IN(passphrase
))
691 BEGIN_IPC(unlockDbWithPassphrase
)
692 Server::keychain(db
)->unlockDb(DATA(passphrase
));
696 kern_return_t
ucsp_server_stashDb(UCSP_ARGS
, DbHandle db
)
699 check_stash_entitlement(connection
.process());
700 Server::keychain(db
)->stashDb();
704 kern_return_t
ucsp_server_stashDbCheck(UCSP_ARGS
, DbHandle db
)
706 BEGIN_IPC(stashDbCheck
)
707 check_stash_entitlement(connection
.process());
708 Server::keychain(db
)->stashDbCheck();
712 kern_return_t
ucsp_server_isLocked(UCSP_ARGS
, DbHandle db
, boolean_t
*locked
)
715 *locked
= Server::database(db
)->isLocked();
719 kern_return_t
ucsp_server_verifyKeyStorePassphrase(UCSP_ARGS
, uint32_t retries
)
721 BEGIN_IPC(verifyKeyStorePassphrase
)
722 connection
.process().session().verifyKeyStorePassphrase(retries
);
726 kern_return_t
ucsp_server_changeKeyStorePassphrase(UCSP_ARGS
)
728 BEGIN_IPC(verifyKeyStorePassphrase
)
729 connection
.process().session().changeKeyStorePassphrase();
733 kern_return_t
ucsp_server_resetKeyStorePassphrase(UCSP_ARGS
, DATA_IN(passphrase
))
735 BEGIN_IPC(verifyKeyStorePassphrase
)
736 connection
.process().session().resetKeyStorePassphrase(DATA(passphrase
));
743 kern_return_t
ucsp_server_encodeKey(UCSP_ARGS
, KeyHandle keyh
, DATA_OUT(blob
),
744 boolean_t wantUid
, DATA_OUT(uid
))
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
751 *blobLength
= keyBlob
->length();
752 if (wantUid
) { // uid generation is not implemented
753 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
755 *uidLength
= 0; // do not return this
757 } else { // not a KeychainKey
758 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
763 kern_return_t
ucsp_server_decodeKey(UCSP_ARGS
, KeyHandle
*keyh
, DATA_OUT(keyHeader
),
764 DbHandle db
, DATA_IN(blob
))
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
);
776 // keychain synchronization
777 kern_return_t
ucsp_server_recodeKey(UCSP_ARGS
, DbHandle oldDb
, KeyHandle keyh
,
778 DbHandle newDb
, DATA_OUT(newBlob
))
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
);
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
);
796 kern_return_t
ucsp_server_releaseKey(UCSP_ARGS
, KeyHandle keyh
)
798 BEGIN_IPC(releaseKey
)
799 RefPointer
<Key
> key
= Server::key(keyh
);
800 key
->database().releaseKey(*key
);
804 kern_return_t
ucsp_server_queryKeySizeInBits(UCSP_ARGS
, KeyHandle keyh
, CSSM_KEY_SIZE
*length
)
806 BEGIN_IPC(queryKeySizeInBits
)
807 RefPointer
<Key
> key
= Server::key(keyh
);
808 key
->database().queryKeySizeInBits(*key
, CssmKeySize::overlay(*length
));
812 kern_return_t
ucsp_server_getOutputSize(UCSP_ARGS
, DATA_IN(context
), KeyHandle keyh
,
813 uint32 inputSize
, boolean_t encrypt
, uint32
*outputSize
)
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
);
822 kern_return_t
ucsp_server_getKeyDigest(UCSP_ARGS
, KeyHandle key
, DATA_OUT(digest
))
824 BEGIN_IPC(getKeyDigest
)
825 CssmData digestData
= Server::key(key
)->canonicalDigest();
826 *digest
= digestData
.data();
827 *digestLength
= digestData
.length();
833 // Signatures and MACs
835 kern_return_t
ucsp_server_generateSignature(UCSP_ARGS
, DATA_IN(context
), KeyHandle keyh
,
836 CSSM_ALGORITHMS signOnlyAlgorithm
, DATA_IN(data
), DATA_OUT(signature
))
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
);
847 kern_return_t
ucsp_server_verifySignature(UCSP_ARGS
, DATA_IN(context
), KeyHandle keyh
,
848 CSSM_ALGORITHMS verifyOnlyAlgorithm
, DATA_IN(data
), DATA_IN(signature
))
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
));
858 kern_return_t
ucsp_server_generateMac(UCSP_ARGS
, DATA_IN(context
), KeyHandle keyh
,
859 DATA_IN(data
), DATA_OUT(mac
))
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
);
869 kern_return_t
ucsp_server_verifyMac(UCSP_ARGS
, DATA_IN(context
), KeyHandle keyh
,
870 DATA_IN(data
), DATA_IN(mac
))
873 CopyOutContext
ctx(context
, contextLength
);
874 RefPointer
<Key
> key
= Server::key(keyh
);
875 key
->database().verifyMac(*ctx
, *key
, DATA(data
), DATA(mac
));
881 // Encryption/Decryption
883 kern_return_t
ucsp_server_encrypt(UCSP_ARGS
, DATA_IN(context
), KeyHandle keyh
,
884 DATA_IN(clear
), DATA_OUT(cipher
))
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
);
894 kern_return_t
ucsp_server_decrypt(UCSP_ARGS
, DATA_IN(context
), KeyHandle keyh
,
895 DATA_IN(cipher
), DATA_OUT(clear
))
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
);
909 kern_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
))
913 BEGIN_IPC(generateKey
)
914 CopyOutContext
ctx(context
, contextLength
);
915 CopyOutAccessCredentials
creds(cred
, credLength
);
917 CopyOutEntryAcl
owneracl(owner
, ownerLength
);
918 //@@@ preliminary interpretation - will get "type handle"
919 RefPointer
<Database
> database
=
920 Server::optionalDatabase(db
, attrs
& CSSM_KEYATTR_PERMANENT
);
922 database
->generateKey(*ctx
, creds
, owneracl
, usage
, attrs
, key
);
923 CssmKey::Header newHeader
;
924 key
->returnKey(*newKey
, newHeader
);
926 if (!copyin(&newHeader
, reinterpret_cast<xdrproc_t
> (xdr_CSSM_KEYHEADER
), keyHeader
, keyHeaderLength
))
927 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR
);
928 Server::releaseWhenDone(*keyHeader
);
932 kern_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
))
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
;
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
);
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
);
963 // Key wrapping and unwrapping
965 kern_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
))
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());
981 if (!copyin(&wrappedKey
, reinterpret_cast<xdrproc_t
> (xdr_CSSM_KEY
), wrappedKeyData
, wrappedKeyDataLength
))
982 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR
);
984 Server::releaseWhenDone(*wrappedKeyData
);
988 kern_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*/)
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
);
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
);
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.
1023 kern_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
))
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
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
*>(¶m
), usage
, attrs
, derivedKey
);
1044 CssmKey::Header newHeader
;
1045 derivedKey
->returnKey(*newKey
, newHeader
);
1047 if (!copyin(&newHeader
, reinterpret_cast<xdrproc_t
> (xdr_CSSM_KEYHEADER
), keyHeader
, keyHeaderLength
))
1048 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR
);
1049 Server::releaseWhenDone(*keyHeader
);
1052 if (!param
.Data
) // CSP screwed up
1053 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
);
1054 OutputData(paramOutput
, paramOutputLength
) = CssmAutoData(Server::csp().allocator(), param
).release();
1061 // Random generation
1063 kern_return_t
ucsp_server_generateRandom(UCSP_ARGS
, uint32 ssid
, DATA_IN(context
), DATA_OUT(data
))
1065 BEGIN_IPC(generateRandom
)
1066 CopyOutContext
ctx(context
, contextLength
);
1068 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
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
);
1076 *dataLength
= bytes
;
1077 Server::releaseWhenDone(allocator
, buffer
);
1085 // Watch out for the memory-management tap-dance.
1087 kern_return_t
ucsp_server_getOwner(UCSP_ARGS
, AclKind kind
, KeyHandle key
,
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
);
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
;
1104 kern_return_t
ucsp_server_setOwner(UCSP_ARGS
, AclKind kind
, KeyHandle key
,
1105 DATA_IN(cred
), DATA_IN(owner
))
1108 CopyOutAccessCredentials
creds(cred
, credLength
);
1109 CopyOutOwnerAcl
owneracl(owner
, ownerLength
);
1110 Server::aclBearer(kind
, key
).changeOwner(*owneracl
, creds
);
1114 kern_return_t
ucsp_server_getAcl(UCSP_ARGS
, AclKind kind
, KeyHandle key
,
1115 boolean_t haveTag
, const char *tag
,
1116 uint32
*countp
, DATA_OUT(acls
))
1120 AclEntryInfo
*aclList
;
1121 Server::aclBearer(kind
, key
).getAcl(haveTag
? tag
: NULL
, count
, aclList
);
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
);
1128 { // release the chunked memory originals
1129 ChunkFreeWalker free
;
1130 for (uint32 n
= 0; n
< count
; n
++)
1131 walk(free
, aclList
[n
]);
1133 // release the memory allocated for the list itself when we are done
1134 Allocator::standard().free (aclList
);
1138 *countp
= count
; // XXX/cs count becomes part of the blob
1139 *aclsLength
= acls_length
;
1141 Server::releaseWhenDone(acls_data
);
1145 kern_return_t
ucsp_server_changeAcl(UCSP_ARGS
, AclKind kind
, KeyHandle key
,
1146 DATA_IN(cred
), CSSM_ACL_EDIT_MODE mode
, GenericHandle handle
,
1149 BEGIN_IPC(changeAcl
)
1150 CopyOutAccessCredentials
creds(cred
, credLength
);
1151 CopyOutAclEntryInput
entryacl(acl
, aclLength
);
1153 Server::aclBearer(kind
, key
).changeAcl(AclEdit(mode
, handle
, entryacl
), creds
);
1161 kern_return_t
ucsp_server_login(UCSP_ARGS
, DATA_IN(cred
), DATA_IN(name
))
1164 CopyOutAccessCredentials
creds(cred
, credLength
);
1165 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
1169 kern_return_t
ucsp_server_logout(UCSP_ARGS
)
1172 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
1178 // Miscellaneous CSP-related calls
1180 kern_return_t
ucsp_server_getStatistics(UCSP_ARGS
, uint32 ssid
, CSSM_CSP_OPERATIONAL_STATISTICS
*statistics
)
1182 BEGIN_IPC(getStatistics
)
1183 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
1187 kern_return_t
ucsp_server_getTime(UCSP_ARGS
, uint32 ssid
, CSSM_ALGORITHMS algorithm
, DATA_OUT(data
))
1190 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
1194 kern_return_t
ucsp_server_getCounter(UCSP_ARGS
, uint32 ssid
, DATA_OUT(data
))
1196 BEGIN_IPC(getCounter
)
1197 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
1201 kern_return_t
ucsp_server_selfVerify(UCSP_ARGS
, uint32 ssid
)
1203 BEGIN_IPC(selfVerify
)
1204 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
1210 // Passthrough calls (separate for CSP and DL passthroughs)
1212 kern_return_t
ucsp_server_cspPassThrough(UCSP_ARGS
, uint32 ssid
, uint32 id
, DATA_IN(context
),
1213 KeyHandle hKey
, DATA_IN(inData
), DATA_OUT(outData
))
1215 BEGIN_IPC(cspPassThrough
)
1216 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
1220 kern_return_t
ucsp_server_dlPassThrough(UCSP_ARGS
, uint32 ssid
, uint32 id
,
1221 DATA_IN(inData
), DATA_OUT(outData
))
1223 BEGIN_IPC(dlPassThrough
)
1224 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
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.
1234 kern_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
))
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
);
1256 // Authorization subsystem support
1258 kern_return_t
ucsp_server_authorizationCreate(UCSP_ARGS
,
1259 void *inRights
, mach_msg_type_number_t inRightsLength
,
1261 void *inEnvironment
, mach_msg_type_number_t inEnvironmentLength
,
1262 AuthorizationBlob
*authorization
)
1264 BEGIN_IPC(authorizationCreate
)
1265 AuthorizationItemSet
*authrights
= NULL
, *authenvironment
= NULL
;
1267 if (inRights
&& !copyout_AuthorizationItemSet(inRights
, inRightsLength
, &authrights
))
1269 Syslog::alert("ucsp_server_authorizationCreate(): error converting 'rights' input");
1270 CssmError::throwMe(errAuthorizationInternal
); // allocation error probably
1273 if (inEnvironment
&& !copyout_AuthorizationItemSet(inEnvironment
, inEnvironmentLength
, &authenvironment
))
1276 Syslog::alert("ucsp_server_authorizationCreate(): error converting 'environment' input");
1277 CssmError::throwMe(errAuthorizationInternal
); // allocation error probably
1280 Authorization::AuthItemSet
rights(authrights
), environment(authenvironment
);
1282 *rcode
= connection
.process().session().authCreate(rights
, environment
,
1283 flags
, *authorization
, auditToken
);
1285 // @@@ safe-guard against code throw()ing in here
1290 if (authenvironment
)
1291 free(authenvironment
);
1296 kern_return_t
ucsp_server_authorizationRelease(UCSP_ARGS
,
1297 AuthorizationBlob authorization
, uint32 flags
)
1299 BEGIN_IPC(authorizationRelease
)
1300 connection
.process().session().authFree(authorization
, flags
);
1304 kern_return_t
ucsp_server_authorizationCopyRights(UCSP_ARGS
,
1305 AuthorizationBlob authorization
,
1306 void *inRights
, mach_msg_type_number_t inRightsLength
,
1308 void *inEnvironment
, mach_msg_type_number_t inEnvironmentLength
,
1309 void **result
, mach_msg_type_number_t
*resultLength
)
1311 BEGIN_IPC(authorizationCopyRights
)
1312 AuthorizationItemSet
*authrights
= NULL
, *authenvironment
= NULL
;
1314 if (inRights
&& !copyout_AuthorizationItemSet(inRights
, inRightsLength
, &authrights
))
1316 Syslog::alert("ucsp_server_authorizationCopyRights(): error converting 'rights' input");
1317 CssmError::throwMe(errAuthorizationInternal
); // allocation error probably
1319 if (inEnvironment
&& !copyout_AuthorizationItemSet(inEnvironment
, inEnvironmentLength
, &authenvironment
))
1322 Syslog::alert("ucsp_server_authorizationCopyRights(): error converting 'environment' input");
1323 CssmError::throwMe(errAuthorizationInternal
); // allocation error probably
1326 Authorization::AuthItemSet
rights(authrights
), environment(authenvironment
), grantedRights
;
1327 *rcode
= Session::authGetRights(authorization
, rights
, environment
, flags
, grantedRights
);
1329 // @@@ safe-guard against code throw()ing in here
1334 if (authenvironment
)
1335 free(authenvironment
);
1337 if (result
&& resultLength
)
1339 AuthorizationItemSet
*copyout
= grantedRights
.copy();
1340 if (!copyin_AuthorizationItemSet(copyout
, result
, resultLength
))
1343 Syslog::alert("ucsp_server_authorizationCopyRights(): error packaging return information");
1344 CssmError::throwMe(errAuthorizationInternal
);
1347 Server::releaseWhenDone(*result
);
1352 kern_return_t
ucsp_server_authorizationCopyInfo(UCSP_ARGS
,
1353 AuthorizationBlob authorization
,
1354 AuthorizationString tag
,
1355 void **info
, mach_msg_type_number_t
*infoLength
)
1357 BEGIN_IPC(authorizationCopyInfo
)
1358 Authorization::AuthItemSet infoSet
;
1361 *rcode
= connection
.process().session().authGetInfo(authorization
,
1362 tag
[0] ? tag
: NULL
, infoSet
);
1363 if (*rcode
== noErr
)
1365 AuthorizationItemSet
*copyout
= infoSet
.copy();
1366 if (!copyin_AuthorizationItemSet(copyout
, info
, infoLength
))
1369 Syslog::alert("ucsp_server_authorizationCopyInfo(): error packaging return information");
1370 CssmError::throwMe(errAuthorizationInternal
);
1373 Server::releaseWhenDone(*info
);
1378 kern_return_t
ucsp_server_authorizationExternalize(UCSP_ARGS
,
1379 AuthorizationBlob authorization
, AuthorizationExternalForm
*extForm
)
1381 BEGIN_IPC(authorizationExternalize
)
1382 *rcode
= connection
.process().session().authExternalize(authorization
, *extForm
);
1386 kern_return_t
ucsp_server_authorizationInternalize(UCSP_ARGS
,
1387 AuthorizationExternalForm extForm
, AuthorizationBlob
*authorization
)
1389 BEGIN_IPC(authorizationInternalize
)
1390 *rcode
= connection
.process().session().authInternalize(extForm
, *authorization
);
1396 // Session management subsystem
1398 kern_return_t
ucsp_server_setSessionUserPrefs(UCSP_ARGS
, SecuritySessionId sessionId
, DATA_IN(userPrefs
))
1400 BEGIN_IPC(setSessionuserPrefs
)
1401 CFRef
<CFDataRef
> data(CFDataCreate(NULL
, (UInt8
*)userPrefs
, userPrefsLength
));
1405 *rcode
= errSessionValueNotSet
;
1409 Session::find
<DynamicSession
>(sessionId
).setUserPrefs(data
);
1417 // Notification core subsystem
1420 kern_return_t
ucsp_server_postNotification(UCSP_ARGS
, uint32 domain
, uint32 event
,
1421 DATA_IN(data
), uint32 sequence
)
1423 BEGIN_IPC(postNotification
)
1424 Listener::notify(domain
, event
, sequence
, DATA(data
));
1430 // AuthorizationDB modification
1432 kern_return_t
ucsp_server_authorizationdbGet(UCSP_ARGS
, const char *rightname
, DATA_OUT(rightDefinition
))
1434 BEGIN_IPC(authorizationdbGet
)
1435 CFDictionaryRef rightDict
;
1437 *rcode
= connection
.process().session().authorizationdbGet(rightname
, &rightDict
);
1439 if (!*rcode
&& rightDict
)
1441 CFRef
<CFDataRef
> data(CFPropertyListCreateXMLData (NULL
, rightDict
));
1442 CFRelease(rightDict
);
1445 Syslog::alert("ucsp_server_authorizationGet(): unable to make XML version of right definition for '%s'", rightname
);
1446 return errAuthorizationInternal
;
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
);
1455 *rightDefinition
= xmlData
;
1456 *rightDefinitionLength
= length
;
1461 kern_return_t
ucsp_server_authorizationdbSet(UCSP_ARGS
, AuthorizationBlob authorization
, const char *rightname
, DATA_IN(rightDefinition
))
1463 BEGIN_IPC(authorizationdbSet
)
1464 CFRef
<CFDataRef
> data(CFDataCreate(NULL
, (UInt8
*)rightDefinition
, rightDefinitionLength
));
1468 Syslog::alert("ucsp_server_authorizationSet(): CFDataCreate() error");
1469 return errAuthorizationInternal
;
1472 CFRef
<CFDictionaryRef
> rightDefinition(static_cast<CFDictionaryRef
>(CFPropertyListCreateFromXMLData(NULL
, data
, kCFPropertyListImmutable
, NULL
)));
1474 if (!rightDefinition
|| (CFGetTypeID(rightDefinition
) != CFDictionaryGetTypeID()))
1476 Syslog::alert("ucsp_server_authorizationSet(): error converting XML right definition for '%s' to property list", rightname
);
1477 return errAuthorizationInternal
;
1480 *rcode
= connection
.process().session().authorizationdbSet(authorization
, rightname
, rightDefinition
);
1485 kern_return_t
ucsp_server_authorizationdbRemove(UCSP_ARGS
, AuthorizationBlob authorization
, const char *rightname
)
1487 BEGIN_IPC(authorizationdbRemove
)
1488 *rcode
= connection
.process().session().authorizationdbRemove(authorization
, rightname
);
1494 // Miscellaneous administrative functions
1496 kern_return_t
ucsp_server_addCodeEquivalence(UCSP_ARGS
, DATA_IN(oldHash
), DATA_IN(newHash
),
1497 const char *name
, boolean_t forSystem
)
1499 BEGIN_IPC(addCodeEquivalence
)
1500 Server::codeSignatures().addLink(DATA(oldHash
), DATA(newHash
), name
, forSystem
);
1504 kern_return_t
ucsp_server_removeCodeEquivalence(UCSP_ARGS
, DATA_IN(hash
),
1505 const char *name
, boolean_t forSystem
)
1507 BEGIN_IPC(removeCodeEquivalence
)
1508 Server::codeSignatures().removeLink(DATA(hash
), name
, forSystem
);
1512 kern_return_t
ucsp_server_setAlternateSystemRoot(UCSP_ARGS
, const char *root
)
1514 BEGIN_IPC(setAlternateSystemRoot
)
1516 if (connection
.process().uid() != 0)
1517 CssmError::throwMe(CSSM_ERRCODE_OS_ACCESS_DENIED
);
1519 Server::codeSignatures().open((string(root
) + EQUIVALENCEDBPATH
).c_str());
1525 // Child check-in service.
1526 // Note that this isn't using the standard argument pattern.
1528 kern_return_t
ucsp_server_childCheckIn(mach_port_t serverPort
,
1529 mach_port_t servicePort
, mach_port_t taskPort
)
1532 ServerChild::checkIn(servicePort
, TaskPort(taskPort
).pid());
1533 END_IPCS(mach_port_deallocate(mach_task_self(), taskPort
))
1538 // Code Signing Hosting registration.
1539 // Note that the Code Signing Proxy facility (implementing the "cshosting"
1540 // IPC protocol) is elsewhere.
1542 kern_return_t
ucsp_server_registerHosting(UCSP_ARGS
, mach_port_t hostingPort
, uint32 flags
)
1544 BEGIN_IPC(registerHosting
)
1545 connection
.process().registerCodeSigning(hostingPort
, flags
);
1549 kern_return_t
ucsp_server_hostingPort(UCSP_ARGS
, pid_t hostPid
, mach_port_t
*hostingPort
)
1551 BEGIN_IPC(hostingPort
)
1552 if (RefPointer
<Process
> process
= Server::active().findPid(hostPid
))
1553 *hostingPort
= process
->hostingPort();
1555 *hostingPort
= MACH_PORT_NULL
;
1556 secdebug("hosting", "hosting port for for pid=%d is port %d", hostPid
, *hostingPort
);
1561 kern_return_t
ucsp_server_setGuest(UCSP_ARGS
, SecGuestRef guest
, SecCSFlags flags
)
1564 connection
.guestRef(guest
, flags
);
1569 kern_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
)
1573 BEGIN_IPC(createGuest
)
1574 *newGuest
= connection
.process().createGuest(host
, status
, path
, DATA(cdhash
), DATA(attributes
), flags
);
1578 kern_return_t
ucsp_server_setGuestStatus(UCSP_ARGS
, SecGuestRef guest
,
1579 uint32_t status
, DATA_IN(attributes
))
1581 BEGIN_IPC(setGuestStatus
)
1582 connection
.process().setGuestStatus(guest
, status
, DATA(attributes
));
1586 kern_return_t
ucsp_server_removeGuest(UCSP_ARGS
, SecGuestRef host
, SecGuestRef guest
)
1588 BEGIN_IPC(removeGuest
)
1589 connection
.process().removeGuest(host
, guest
);
1593 kern_return_t
ucsp_server_helpCheckLoad(UCSP_ARGS
, const char path
[PATH_MAX
], uint32_t type
)
1595 BEGIN_IPC(helpCheckLoad
)