2 * Copyright (c) 2000-2009,2012-2013,2016 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"
40 #include "acl_keychain.h"
44 #include <mach/mach_error.h>
45 #include "SecRandom.h"
46 #include <securityd_client/xdr_cssm.h>
47 #include <securityd_client/xdr_auth.h>
48 #include <securityd_client/xdr_dldb.h>
49 #include <security_utilities/logging.h>
50 #include <security_utilities/casts.h>
51 #include <Security/AuthorizationTagsPriv.h>
52 #include <AssertMacros.h>
53 #include <security_utilities/errors.h>
54 #include <Security/SecEntitlements.h>
56 #include <CoreFoundation/CFNumber.h>
57 #include <CoreFoundation/CFDictionary.h>
58 #include <CoreFoundation/CFPropertyList.h>
63 #define UCSP_ARGS mach_port_t servicePort, mach_port_t replyPort, \
64 audit_token_t auditToken, CSSM_RETURN *rcode
66 #define BEGIN_IPCN *rcode = CSSM_OK; try {
67 #define BEGIN_IPC(name) BEGIN_IPCN RefPointer<Connection> connRef(&Server::connection(replyPort, auditToken)); \
68 Connection &connection __attribute__((unused)) = *connRef; \
69 secinfo("SecServer", "request entry " #name " (pid:%d session:%d)", connection.process().pid(), connection.session().sessionId());
71 #define END_IPC(base) END_IPCN(base) Server::requestComplete(*rcode); return KERN_SUCCESS;
72 #define END_IPCN(base) secinfo("SecServer", "request return: %d", *(rcode)); \
74 catch (const CommonError &err) { *rcode = CssmError::cssmError(err, CSSM_ ## base ## _BASE_ERROR); } \
75 catch (const std::bad_alloc &) { *rcode = CssmError::merge(CSSM_ERRCODE_MEMORY_ERROR, CSSM_ ## base ## _BASE_ERROR); } \
76 catch (Connection *conn) { *rcode = 0; } \
77 catch (...) { *rcode = CssmError::merge(CSSM_ERRCODE_INTERNAL_ERROR, CSSM_ ## base ## _BASE_ERROR); }
79 #define BEGIN_IPCS try {
80 #define END_IPCS(more) } catch (...) { } \
81 mach_port_deallocate(mach_task_self(), servicePort); more; return KERN_SUCCESS;
83 #define DATA_IN(base) void *base, mach_msg_type_number_t base##Length
84 #define DATA_OUT(base) void **base, mach_msg_type_number_t *base##Length
85 #define DATA(base) CssmData(base, base##Length)
87 #define SSBLOB(Type, name) makeBlob<Type>(DATA(name))
89 using LowLevelMemoryUtilities::increment
;
90 using LowLevelMemoryUtilities::difference
;
92 class CopyOutAccessCredentials
: public CopyOut
{
94 CopyOutAccessCredentials(void *copy
, size_t size
) : CopyOut(copy
, size
+ sizeof(CSSM_ACCESS_CREDENTIALS
), reinterpret_cast<xdrproc_t
>(xdr_CSSM_ACCESS_CREDENTIALS_PTR
)) { }
95 operator AccessCredentials
*() { return static_cast<AccessCredentials
*>(reinterpret_cast<CSSM_ACCESS_CREDENTIALS_PTR
>(data())); }
99 class CopyOutEntryAcl
: public CopyOut
{
101 CopyOutEntryAcl(void *copy
, size_t size
) : CopyOut(copy
, size
+ sizeof(CSSM_ACL_ENTRY_PROTOTYPE
), reinterpret_cast<xdrproc_t
>(xdr_CSSM_ACL_ENTRY_PROTOTYPE_PTR
)) { }
102 operator AclEntryPrototype
*() { return static_cast<AclEntryPrototype
*>(reinterpret_cast<CSSM_ACL_ENTRY_PROTOTYPE_PTR
>(data())); }
105 class CopyOutOwnerAcl
: public CopyOut
{
107 CopyOutOwnerAcl(void *copy
, size_t size
) : CopyOut(copy
, size
+ sizeof(CSSM_ACL_OWNER_PROTOTYPE
), reinterpret_cast<xdrproc_t
>(xdr_CSSM_ACL_OWNER_PROTOTYPE_PTR
)) { }
108 operator AclOwnerPrototype
*() { return static_cast<AclOwnerPrototype
*>(reinterpret_cast<CSSM_ACL_OWNER_PROTOTYPE_PTR
>(data())); }
111 class CopyOutAclEntryInput
: public CopyOut
{
113 CopyOutAclEntryInput(void *copy
, size_t size
) : CopyOut(copy
, size
+ sizeof(CSSM_ACL_ENTRY_INPUT
), reinterpret_cast<xdrproc_t
>(xdr_CSSM_ACL_ENTRY_INPUT_PTR
)) { }
114 operator AclEntryInput
*() { return static_cast<AclEntryInput
*>(reinterpret_cast<CSSM_ACL_ENTRY_INPUT_PTR
>(data())); }
118 class CopyOutDeriveData
: public CopyOut
{
120 CopyOutDeriveData(void *copy
, size_t size
) : CopyOut(copy
, size
+ sizeof(CSSM_DERIVE_DATA
), reinterpret_cast<xdrproc_t
>(xdr_CSSM_DERIVE_DATA_PTR
)) { }
121 CSSM_DERIVE_DATA
* derive_data() { return reinterpret_cast<CSSM_DERIVE_DATA
*>(data()); }
122 CSSM_DATA
&cssm_data() { return derive_data()->baseData
; }
123 CSSM_ALGORITHMS
algorithm() { return derive_data()->algorithm
; }
127 class CopyOutContext
: public CopyOut
{
129 CopyOutContext(void *copy
, size_t size
) : CopyOut(copy
, size
+ sizeof(CSSM_CONTEXT
), reinterpret_cast<xdrproc_t
>(xdr_CSSM_CONTEXT_PTR
)) { }
130 operator Context
*() { return static_cast<Context
*>(reinterpret_cast<CSSM_CONTEXT_PTR
>(data())); }
131 Context
&context() { return *static_cast<Context
*>(reinterpret_cast<CSSM_CONTEXT_PTR
>(data())); }
134 class CopyOutKey
: public CopyOut
{
136 CopyOutKey(void *copy
, size_t size
) : CopyOut(copy
, size
+ sizeof(CSSM_KEY
), reinterpret_cast<xdrproc_t
>(xdr_CSSM_KEY_PTR
)) { }
137 operator CssmKey
*() { return static_cast<CssmKey
*>(reinterpret_cast<CSSM_KEY_PTR
>(data())); }
138 CssmKey
&key() { return *static_cast<CssmKey
*>(reinterpret_cast<CSSM_KEY_PTR
>(data())); }
141 class CopyOutDbRecordAttributes
: public CopyOut
{
143 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
)) { }
144 CssmDbRecordAttributeData
*attribute_data() { return static_cast<CssmDbRecordAttributeData
*>(reinterpret_cast<CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR
>(data())); }
147 class CopyOutQuery
: public CopyOut
{
149 CopyOutQuery(void *copy
, size_t size
) : CopyOut(copy
, size
, reinterpret_cast<xdrproc_t
>(xdr_CSSM_QUERY_PTR
)) { }
150 operator CssmQuery
*() { return static_cast<CssmQuery
*>(reinterpret_cast<CSSM_QUERY_PTR
>(data())); }
154 // Take a DATA type RPC argument purportedly representing a Blob of some kind,
155 // turn it into a Blob, and fail properly if it's not kosher.
157 template <class BlobType
>
158 const BlobType
*makeBlob(const CssmData
&blobData
, CSSM_RETURN error
= CSSM_ERRCODE_INVALID_DATA
)
160 if (!blobData
.data() || blobData
.length() < sizeof(BlobType
))
161 CssmError::throwMe(error
);
162 const BlobType
*blob
= static_cast<const BlobType
*>(blobData
.data());
163 if (blob
->totalLength
!= blobData
.length())
164 CssmError::throwMe(error
);
169 // An OutputData object will take memory allocated within securityd,
170 // hand it to the MIG return-output parameters, and schedule it to be released
171 // after the MIG reply has been sent. It will also get rid of it in case of
174 class OutputData
: public CssmData
{
176 OutputData(void **outP
, mach_msg_type_number_t
*outLength
)
177 : mData(*outP
), mLength(*outLength
) { }
179 { mData
= data(); mLength
= int_cast
<size_t, mach_msg_type_number_t
>(length()); Server::releaseWhenDone(mData
); }
181 void operator = (const CssmData
&source
)
182 { CssmData::operator = (source
); }
186 mach_msg_type_number_t
&mLength
;
190 // Choose a Database from a choice of two sources, giving preference
191 // to persistent stores and to earlier sources.
193 Database
*pickDb(Database
*db1
, Database
*db2
);
195 static inline Database
*dbOf(Key
*key
) { return key
? &key
->database() : NULL
; }
197 inline Database
*pickDb(Key
*k1
, Key
*k2
) { return pickDb(dbOf(k1
), dbOf(k2
)); }
198 inline Database
*pickDb(Database
*db1
, Key
*k2
) { return pickDb(db1
, dbOf(k2
)); }
199 inline Database
*pickDb(Key
*k1
, Database
*db2
) { return pickDb(dbOf(k1
), db2
); }
202 // Choose a Database from a choice of two sources, giving preference
203 // to persistent stores and to earlier sources.
205 Database
*pickDb(Database
*db1
, Database
*db2
)
207 // persistent db1 always wins
208 if (db1
&& !db1
->transient())
211 // persistent db2 is next choice
212 if (db2
&& !db2
->transient())
215 // pick any existing transient database
221 // none at all. use the canonical transient store
222 return Server::optionalDatabase(noDb
);
225 static void checkPathLength(char const *str
) {
226 if (strlen(str
) >= PATH_MAX
) {
227 secerror("SecServer: path too long");
228 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR
);
233 // Setup/Teardown functions.
236 #pragma clang diagnostic push
237 #pragma clang diagnostic ignored "-Wmissing-prototypes"
239 kern_return_t
ucsp_server_setup(UCSP_ARGS
, mach_port_t taskPort
, ClientSetupInfo info
, const char *identity
)
242 secinfo("SecServer", "request entry: setup");
243 Server::active().setupConnection(Server::connectNewProcess
, replyPort
,
244 taskPort
, auditToken
, &info
);
247 Syslog::notice("setup(%s) failed rcode=%d", identity
? identity
: "<NULL>", *rcode
);
248 mach_port_deallocate(mach_task_self(), taskPort
);
253 kern_return_t
ucsp_server_setupThread(UCSP_ARGS
, mach_port_t taskPort
)
255 secinfo("SecServer", "request entry: setupThread");
257 Server::active().setupConnection(Server::connectNewThread
, replyPort
, taskPort
, auditToken
);
260 Syslog::notice("setupThread failed rcode=%d", *rcode
);
261 mach_port_deallocate(mach_task_self(), taskPort
);
265 kern_return_t
ucsp_server_verifyPrivileged(UCSP_ARGS
)
268 secinfo("SecServer", "request entry: verifyPrivileged");
269 // doing nothing (we just want securityd's audit credentials returned)
274 kern_return_t
ucsp_server_verifyPrivileged2(UCSP_ARGS
, mach_port_t
*originPort
)
278 secinfo("SecServer", "request entry: verifyPrivileged2");
279 // send the port back to the sender to check for a MitM (6986198)
280 *originPort
= servicePort
;
286 // Common database operations
288 kern_return_t
ucsp_server_authenticateDb(UCSP_ARGS
, DbHandle db
,
289 CSSM_DB_ACCESS_TYPE accessType
, DATA_IN(cred
))
291 BEGIN_IPC(authenticateDb
)
292 secinfo("dl", "authenticateDb");
293 CopyOutAccessCredentials
creds(cred
, credLength
);
294 // ignoring accessType
295 Server::database(db
)->authenticate(accessType
, creds
);
299 kern_return_t
ucsp_server_releaseDb(UCSP_ARGS
, DbHandle db
)
302 connection
.process().kill(*Server::database(db
));
307 kern_return_t
ucsp_server_getDbName(UCSP_ARGS
, DbHandle db
, char name
[PATH_MAX
])
310 string result
= Server::database(db
)->dbName();
311 checkPathLength(result
.c_str());
312 memcpy(name
, result
.c_str(), result
.length() + 1);
316 kern_return_t
ucsp_server_setDbName(UCSP_ARGS
, DbHandle db
, const char *name
)
319 checkPathLength(name
);
320 Server::database(db
)->dbName(name
);
326 // External database interface
328 kern_return_t
ucsp_server_openToken(UCSP_ARGS
, uint32 ssid
, FilePath name
,
329 DATA_IN(accessCredentials
), DbHandle
*db
)
332 CopyOutAccessCredentials
creds(accessCredentials
, accessCredentialsLength
);
333 // The static analyzer is not a fan of this "create object, send handle to foreign process" model. Tell it not to worry.
334 #ifndef __clang_analyzer__
335 *db
= (new TokenDatabase(ssid
, connection
.process(), name
, creds
))->handle();
340 kern_return_t
ucsp_server_findFirst(UCSP_ARGS
, DbHandle db
,
341 DATA_IN(inQuery
), DATA_IN(inAttributes
), DATA_OUT(outAttributes
),
342 boolean_t getData
, DATA_OUT(data
),
343 KeyHandle
*hKey
, SearchHandle
*hSearch
, IPCRecordHandle
*hRecord
)
346 CopyOutQuery
query(inQuery
, inQueryLength
);
347 CopyOutDbRecordAttributes
attrs(inAttributes
, inAttributesLength
);
349 RefPointer
<Database::Search
> search
;
350 RefPointer
<Database::Record
> record
;
353 CssmDbRecordAttributeData
*outAttrs
= NULL
; mach_msg_type_number_t outAttrsLength
;
354 Server::database(db
)->findFirst(*query
,
355 attrs
.attribute_data(), attrs
.length(),
356 getData
? &outData
: NULL
, key
, search
, record
, outAttrs
, outAttrsLength
);
358 // handle nothing-found case without exceptions
365 *hRecord
= record
->handle();
366 *hSearch
= search
->handle();
367 *hKey
= key
? key
->handle() : noKey
;
369 if (outAttrsLength
&& outAttrs
) {
370 Server::releaseWhenDone(outAttrs
); // exception proof it against next line
371 if (!copyin(outAttrs
, reinterpret_cast<xdrproc_t
> (xdr_CSSM_DB_RECORD_ATTRIBUTE_DATA
), outAttributes
, outAttributesLength
))
372 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR
);
373 Server::releaseWhenDone(*outAttributes
);
376 // return data (temporary fix)
378 Server::releaseWhenDone(outData
.data());
379 xdrproc_t encode_proc
= reinterpret_cast<xdrproc_t
>(xdr_CSSM_NO_KEY_IN_DATA
);
381 encode_proc
= reinterpret_cast<xdrproc_t
>(xdr_CSSM_KEY_IN_DATA
);
382 if (!copyin(&outData
, encode_proc
, data
, dataLength
))
383 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR
);
384 Server::releaseWhenDone(*data
);
391 kern_return_t
ucsp_server_findNext(UCSP_ARGS
, SearchHandle hSearch
,
392 DATA_IN(inAttributes
),
393 DATA_OUT(outAttributes
),
394 boolean_t getData
, DATA_OUT(data
), KeyHandle
*hKey
,
395 IPCRecordHandle
*hRecord
)
398 CopyOutDbRecordAttributes
attrs(inAttributes
, inAttributesLength
);
399 RefPointer
<Database::Search
> search
=
400 Server::find
<Database::Search
>(hSearch
, CSSMERR_DL_INVALID_RESULTS_HANDLE
);
401 RefPointer
<Database::Record
> record
;
404 CssmDbRecordAttributeData
*outAttrs
= NULL
; mach_msg_type_number_t outAttrsLength
;
405 search
->database().findNext(search
, attrs
.attribute_data(), attrs
.length(),
406 getData
? &outData
: NULL
, key
, record
, outAttrs
, outAttrsLength
);
408 // handle nothing-found case without exceptions
414 *hRecord
= record
->handle();
415 *hKey
= key
? key
->handle() : noKey
;
417 if (outAttrsLength
&& outAttrs
) {
418 secinfo("attrmem", "Found attrs: %p of length: %d", outAttrs
, outAttrsLength
);
419 Server::releaseWhenDone(outAttrs
); // exception proof it against next line
420 if (!copyin(outAttrs
, reinterpret_cast<xdrproc_t
> (xdr_CSSM_DB_RECORD_ATTRIBUTE_DATA
), outAttributes
, outAttributesLength
))
421 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR
);
422 secinfo("attrmem", "Copied attrs: %p of length: %d", *outAttributes
, *outAttributesLength
);
423 Server::releaseWhenDone(*outAttributes
);
426 // return data (temporary fix)
428 Server::releaseWhenDone(outData
.data());
429 xdrproc_t encode_proc
= reinterpret_cast<xdrproc_t
>(xdr_CSSM_NO_KEY_IN_DATA
);
431 encode_proc
= reinterpret_cast<xdrproc_t
>(xdr_CSSM_KEY_IN_DATA
);
432 if (!copyin(&outData
, encode_proc
, data
, dataLength
))
433 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR
);
434 Server::releaseWhenDone(*data
);
440 kern_return_t
ucsp_server_findRecordHandle(UCSP_ARGS
, IPCRecordHandle hRecord
,
441 DATA_IN(inAttributes
), DATA_OUT(outAttributes
),
442 boolean_t getData
, DATA_OUT(data
), KeyHandle
*hKey
)
444 BEGIN_IPC(findRecordHandle
)
445 CopyOutDbRecordAttributes
attrs(inAttributes
, inAttributesLength
);
446 RefPointer
<Database::Record
> record
=
447 Server::find
<Database::Record
>(hRecord
, CSSMERR_DL_INVALID_RECORD_UID
);
450 CssmDbRecordAttributeData
*outAttrs
; mach_msg_type_number_t outAttrsLength
;
451 record
->database().findRecordHandle(record
, attrs
.attribute_data(), attrs
.length(),
452 getData
? &outData
: NULL
, key
, outAttrs
, outAttrsLength
);
455 *hKey
= key
? key
->handle() : noKey
;
457 if (outAttrsLength
&& outAttrs
) {
458 Server::releaseWhenDone(outAttrs
); // exception proof it against next line
459 if (!copyin(outAttrs
, reinterpret_cast<xdrproc_t
> (xdr_CSSM_DB_RECORD_ATTRIBUTE_DATA
), outAttributes
, outAttributesLength
))
460 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR
);
461 Server::releaseWhenDone(*outAttributes
);
464 // return data (temporary fix)
467 We can't release this with the usual allocator (which calls free(), since
468 it was VM allocated. Part of the fix for:
469 <rdar://problem/6738709> securityd leaks VM memory during certain smartcard operations
470 will be to call Server::releaseWhenDone below with a new vm allocator param
472 Server::releaseWhenDone(outData
.data());
473 xdrproc_t encode_proc
= reinterpret_cast<xdrproc_t
>(xdr_CSSM_NO_KEY_IN_DATA
);
475 encode_proc
= reinterpret_cast<xdrproc_t
>(xdr_CSSM_KEY_IN_DATA
);
476 if (!copyin(&outData
, encode_proc
, data
, dataLength
))
477 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR
);
478 Server::releaseWhenDone(*data
);
483 kern_return_t
ucsp_server_insertRecord(UCSP_ARGS
, DbHandle db
, CSSM_DB_RECORDTYPE recordType
,
484 DATA_IN(inAttributes
), DATA_IN(data
), IPCRecordHandle
*record
)
486 BEGIN_IPC(insertRecord
)
487 RecordHandle recordHandle
;
488 CopyOutDbRecordAttributes
attrs(inAttributes
, inAttributesLength
);
489 Server::database(db
)->insertRecord(recordType
, attrs
.attribute_data(), attrs
.length(),
490 DATA(data
), recordHandle
);
491 *record
= recordHandle
;
495 kern_return_t
ucsp_server_modifyRecord(UCSP_ARGS
, DbHandle db
, IPCRecordHandle
*hRecord
,
496 CSSM_DB_RECORDTYPE recordType
, DATA_IN(attributes
),
497 boolean_t setData
, DATA_IN(data
), CSSM_DB_MODIFY_MODE modifyMode
)
499 BEGIN_IPC(modifyRecord
)
500 CopyOutDbRecordAttributes
attrs(attributes
, attributesLength
);
501 CssmData
newData(DATA(data
));
502 RefPointer
<Database::Record
> record
=
503 Server::find
<Database::Record
>(*hRecord
, CSSMERR_DL_INVALID_RECORD_UID
);
504 Server::database(db
)->modifyRecord(recordType
, record
, attrs
.attribute_data(), attrs
.length(),
505 setData
? &newData
: NULL
, modifyMode
);
506 // note that the record handle presented to the client never changes here
507 // (we could, but have no reason to - our record handles are just always up to date)
511 kern_return_t
ucsp_server_deleteRecord(UCSP_ARGS
, DbHandle db
, IPCRecordHandle hRecord
)
513 BEGIN_IPC(deleteRecord
)
514 Server::database(db
)->deleteRecord(
515 Server::find
<Database::Record
>(hRecord
, CSSMERR_DL_INVALID_RECORD_UID
));
519 kern_return_t
ucsp_server_releaseSearch(UCSP_ARGS
, SearchHandle hSearch
)
521 BEGIN_IPC(releaseSearch
)
522 RefPointer
<Database::Search
> search
= Server::find
<Database::Search
>(hSearch
, 0);
523 search
->database().releaseSearch(*search
);
527 kern_return_t
ucsp_server_releaseRecord(UCSP_ARGS
, IPCRecordHandle hRecord
)
529 BEGIN_IPC(releaseRecord
)
530 RefPointer
<Database::Record
> record
= Server::find
<Database::Record
>(hRecord
, 0);
531 record
->database().releaseRecord(*record
);
537 // Internal database management
539 kern_return_t
ucsp_server_createDb(UCSP_ARGS
, DbHandle
*db
,
540 DATA_IN(ident
), DATA_IN(cred
), DATA_IN(owner
),
544 CopyOutAccessCredentials
creds(cred
, credLength
);
545 CopyOutEntryAcl
owneracl(owner
, ownerLength
);
546 CopyOut
flatident(ident
, identLength
, reinterpret_cast<xdrproc_t
>(xdr_DLDbFlatIdentifierRef
));
547 checkPathLength((*reinterpret_cast<DLDbFlatIdentifier
*>(flatident
.data())).name
);
548 #ifndef __clang_analyzer__
549 *db
= (new KeychainDatabase(*reinterpret_cast<DLDbFlatIdentifier
*>(flatident
.data()), params
, connection
.process(), creds
, owneracl
))->handle();
554 kern_return_t
ucsp_server_cloneDb(UCSP_ARGS
, DbHandle srcDb
, DATA_IN(ident
), DbHandle
*newDb
) {
557 secnotice("integrity", "cloning a db");
559 CopyOut
flatident(ident
, identLength
, reinterpret_cast<xdrproc_t
>(xdr_DLDbFlatIdentifierRef
));
561 checkPathLength((*reinterpret_cast<DLDbFlatIdentifier
*>(flatident
.data())).name
);
563 RefPointer
<KeychainDatabase
> srcKC
= Server::keychain(srcDb
);
564 secnotice("integrity", "cloning db %d", srcKC
->handle());
566 #ifndef __clang_analyzer__
567 KeychainDatabase
* newKC
= new KeychainDatabase(*reinterpret_cast<DLDbFlatIdentifier
*>(flatident
.data()), *srcKC
, connection
.process());
568 secnotice("integrity", "returning db %d", newKC
->handle());
569 *newDb
= newKC
->handle();
575 kern_return_t
ucsp_server_recodeDbForSync(UCSP_ARGS
, DbHandle dbToClone
,
576 DbHandle srcDb
, DbHandle
*newDb
)
578 BEGIN_IPC(recodeDbForSync
)
579 RefPointer
<KeychainDatabase
> srcKC
= Server::keychain(srcDb
);
580 #ifndef __clang_analyzer__
581 *newDb
= (new KeychainDatabase(*srcKC
, connection
.process(), dbToClone
))->handle();
586 kern_return_t
ucsp_server_recodeDbToVersion(UCSP_ARGS
, uint32 newVersion
, DbHandle srcDb
, DbHandle
*newDb
)
588 BEGIN_IPC(recodeDbToVersion
)
589 RefPointer
<KeychainDatabase
> srcKC
= Server::keychain(srcDb
);
591 // You can only recode an unlocked keychain, so let's make sure.
592 srcKC
->unlockDb(false);
594 KeychainDatabase
* newKC
= new KeychainDatabase(newVersion
, *srcKC
, connection
.process());
595 if(newKC
->blob()->version() != newVersion
) {
596 CssmError::throwMe(CSSM_ERRCODE_INCOMPATIBLE_VERSION
);
599 *newDb
= newKC
->handle();
604 kern_return_t
ucsp_server_recodeFinished(UCSP_ARGS
, DbHandle db
)
606 BEGIN_IPC(recodeDbToVersion
)
607 Server::keychain(db
)->recodeFinished();
612 kern_return_t
ucsp_server_authenticateDbsForSync(UCSP_ARGS
, DATA_IN(dbHandleArray
),
613 DATA_IN(agentData
), DbHandle
* authenticatedDBHandle
)
615 BEGIN_IPC(authenticateDbsForSync
)
616 QueryDBBlobSecret query
;
617 query
.inferHints(connection
.process());
618 query
.addHint(AGENT_HINT_KCSYNC_DICT
, agentData
, agentDataLength
);
619 CSSM_DATA dbData
= DATA(dbHandleArray
);
620 uint8 ipcDbHandleArrayCount
= *(dbData
.Data
);
621 DbHandle
*ipcDbHandleArray
= (DbHandle
*)Allocator::standard().malloc(ipcDbHandleArrayCount
* sizeof(DbHandle
));
622 if ( ipcDbHandleArray
== 0 )
623 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR
);
624 DbHandle
*currIPCDbHandleArrayPtr
= ipcDbHandleArray
;
625 DbHandle
*dbHandleArrayPtr
= (DbHandle
*)(dbData
.Data
+1);
627 for (index
=0; index
< ipcDbHandleArrayCount
; index
++)
629 *currIPCDbHandleArrayPtr
= *dbHandleArrayPtr
;
630 Server::keychain(*currIPCDbHandleArrayPtr
)->lockDb(); // lock this db if it was unlocked in the past (user could have deleted the kc, resetLogin, etc.)
631 currIPCDbHandleArrayPtr
++;
634 Server::releaseWhenDone(ipcDbHandleArray
);
635 if (query(ipcDbHandleArray
, ipcDbHandleArrayCount
, authenticatedDBHandle
) != SecurityAgent::noReason
)
636 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
640 kern_return_t
ucsp_server_commitDbForSync(UCSP_ARGS
, DbHandle srcDb
,
641 DbHandle cloneDb
, DATA_OUT(blob
))
643 BEGIN_IPC(commitDbForSync
)
644 RefPointer
<KeychainDatabase
> srcKC
= Server::keychain(srcDb
);
645 RefPointer
<KeychainDatabase
> cloneKC
= Server::keychain(cloneDb
);
646 srcKC
->commitSecretsForSync(*cloneKC
);
648 // re-encode blob for convenience
649 if (blob
&& blobLength
) {
650 DbBlob
*dbBlob
= srcKC
->blob();
652 *blobLength
= dbBlob
->length();
654 secinfo("kcrecode", "No blob can be returned to client");
659 kern_return_t
ucsp_server_decodeDb(UCSP_ARGS
, DbHandle
*db
,
660 DATA_IN(ident
), DATA_IN(cred
), DATA_IN(blob
))
663 CopyOutAccessCredentials
creds(cred
, credLength
);
664 CopyOut
flatident(ident
, identLength
, reinterpret_cast<xdrproc_t
>(xdr_DLDbFlatIdentifierRef
));
665 DLDbFlatIdentifier
* flatID
= (DLDbFlatIdentifier
*) flatident
.data();
666 DLDbIdentifier id
= *flatID
; // invokes a casting operator
668 checkPathLength(id
.dbName());
670 #ifndef __clang_analyzer__
671 *db
= (new KeychainDatabase(id
, SSBLOB(DbBlob
, blob
),
672 connection
.process(), creds
))->handle();
677 kern_return_t
ucsp_server_encodeDb(UCSP_ARGS
, DbHandle db
, DATA_OUT(blob
))
680 DbBlob
*dbBlob
= Server::keychain(db
)->blob(); // memory owned by database
682 *blobLength
= dbBlob
->length();
686 kern_return_t
ucsp_server_setDbParameters(UCSP_ARGS
, DbHandle db
, DBParameters params
)
688 BEGIN_IPC(setDbParameters
)
689 Server::keychain(db
)->setParameters(params
);
693 kern_return_t
ucsp_server_getDbParameters(UCSP_ARGS
, DbHandle db
, DBParameters
*params
)
695 BEGIN_IPC(getDbParameters
)
696 Server::keychain(db
)->getParameters(*params
);
700 kern_return_t
ucsp_server_changePassphrase(UCSP_ARGS
, DbHandle db
,
703 BEGIN_IPC(changePassphrase
)
704 CopyOutAccessCredentials
creds(cred
, credLength
);
705 Server::keychain(db
)->changePassphrase(creds
);
709 kern_return_t
ucsp_server_lockAll (UCSP_ARGS
, boolean_t
)
712 connection
.session().processLockAll();
716 kern_return_t
ucsp_server_unlockDb(UCSP_ARGS
, DbHandle db
)
719 Server::keychain(db
)->unlockDb(true);
723 static void check_stash_entitlement(Process
& proc
)
725 OSStatus status
= noErr
;
726 CFDictionaryRef code_info
= NULL
;
727 CFDictionaryRef entitlements
= NULL
;
728 CFTypeRef value
= NULL
;
729 bool entitled
= false;
731 status
= proc
.copySigningInfo(kSecCSRequirementInformation
, &code_info
);
732 require_noerr(status
, done
);
734 if (CFDictionaryGetValueIfPresent(code_info
, kSecCodeInfoEntitlementsDict
, &value
)) {
735 if (CFGetTypeID(value
) == CFDictionaryGetTypeID()) {
736 entitlements
= (CFDictionaryRef
)value
;
739 require(entitlements
!= NULL
, done
);
741 if (CFDictionaryGetValueIfPresent(entitlements
, kSecEntitlementPrivateStash
, &value
)) {
742 if (CFGetTypeID(value
) && CFBooleanGetTypeID()) {
743 entitled
= CFBooleanGetValue((CFBooleanRef
)value
);
749 CFRelease(code_info
);
753 CssmError::throwMe(CSSM_ERRCODE_OS_ACCESS_DENIED
);
757 kern_return_t
ucsp_server_unlockDbWithPassphrase(UCSP_ARGS
, DbHandle db
, DATA_IN(passphrase
))
759 BEGIN_IPC(unlockDbWithPassphrase
)
760 Server::keychain(db
)->unlockDb(DATA(passphrase
), true);
764 kern_return_t
ucsp_server_stashDb(UCSP_ARGS
, DbHandle db
)
767 check_stash_entitlement(connection
.process());
768 Server::keychain(db
)->stashDb();
772 kern_return_t
ucsp_server_stashDbCheck(UCSP_ARGS
, DbHandle db
)
774 BEGIN_IPC(stashDbCheck
)
775 check_stash_entitlement(connection
.process());
776 Server::keychain(db
)->stashDbCheck();
780 kern_return_t
ucsp_server_isLocked(UCSP_ARGS
, DbHandle db
, boolean_t
*locked
)
783 // Must hold the DB's common's lock to safely determine if it's locked. Locking is a mess in there.
784 StLock
<Mutex
> _(Server::database(db
)->common());
785 *locked
= Server::database(db
)->isLocked();
789 kern_return_t
ucsp_server_verifyKeyStorePassphrase(UCSP_ARGS
, uint32_t retries
)
791 BEGIN_IPC(verifyKeyStorePassphrase
)
792 connection
.process().session().verifyKeyStorePassphrase(retries
);
796 kern_return_t
ucsp_server_changeKeyStorePassphrase(UCSP_ARGS
)
798 BEGIN_IPC(verifyKeyStorePassphrase
)
799 connection
.process().session().changeKeyStorePassphrase();
803 kern_return_t
ucsp_server_resetKeyStorePassphrase(UCSP_ARGS
, DATA_IN(passphrase
))
805 BEGIN_IPC(verifyKeyStorePassphrase
)
806 connection
.process().session().resetKeyStorePassphrase(DATA(passphrase
));
813 kern_return_t
ucsp_server_encodeKey(UCSP_ARGS
, KeyHandle keyh
, DATA_OUT(blob
),
814 boolean_t wantUid
, DATA_OUT(uid
))
817 RefPointer
<Key
> gKey
= Server::key(keyh
);
818 if (KeychainKey
*key
= dynamic_cast<KeychainKey
*>(gKey
.get())) {
819 KeyBlob
*keyBlob
= key
->blob(); // still owned by key
821 *blobLength
= keyBlob
->length();
822 if (wantUid
) { // uid generation is not implemented
823 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
825 *uidLength
= 0; // do not return this
827 } else { // not a KeychainKey
828 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
833 kern_return_t
ucsp_server_decodeKey(UCSP_ARGS
, KeyHandle
*keyh
, DATA_OUT(keyHeader
),
834 DbHandle db
, DATA_IN(blob
))
837 RefPointer
<Key
> key
= new KeychainKey(*Server::keychain(db
), SSBLOB(KeyBlob
, blob
));
838 CssmKey::Header header
;
839 key
->returnKey(*keyh
, header
);
840 if (!copyin(&header
, reinterpret_cast<xdrproc_t
> (xdr_CSSM_KEYHEADER
), keyHeader
, keyHeaderLength
))
841 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR
);
842 Server::releaseWhenDone(*keyHeader
);
846 // keychain synchronization
847 kern_return_t
ucsp_server_recodeKey(UCSP_ARGS
, DbHandle oldDb
, KeyHandle keyh
,
848 DbHandle newDb
, DATA_OUT(newBlob
))
851 // If the old key is passed in as DATA_IN(oldBlob):
852 // RefPointer<KeychainKey> key = new KeychainKey(*Server::keychain(oldDb), SSBLOB(KeyBlob, oldBlob));
853 RefPointer
<Key
> key
= Server::key(keyh
);
854 if (KeychainKey
*kckey
= dynamic_cast<KeychainKey
*>(key
.get())) {
855 KeyBlob
*blob
= Server::keychain(newDb
)->recodeKey(*kckey
);
857 *newBlobLength
= blob
->length();
858 Server::releaseWhenDone(*newBlob
);
859 // @@@ stop leaking blob
860 } else { // not a KeychainKey
861 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
866 kern_return_t
ucsp_server_releaseKey(UCSP_ARGS
, KeyHandle keyh
)
868 BEGIN_IPC(releaseKey
)
869 RefPointer
<Key
> key
= Server::key(keyh
);
870 key
->database().releaseKey(*key
);
874 kern_return_t
ucsp_server_queryKeySizeInBits(UCSP_ARGS
, KeyHandle keyh
, CSSM_KEY_SIZE
*length
)
876 BEGIN_IPC(queryKeySizeInBits
)
877 RefPointer
<Key
> key
= Server::key(keyh
);
878 key
->database().queryKeySizeInBits(*key
, CssmKeySize::overlay(*length
));
882 kern_return_t
ucsp_server_getOutputSize(UCSP_ARGS
, DATA_IN(context
), KeyHandle keyh
,
883 uint32 inputSize
, boolean_t encrypt
, uint32
*outputSize
)
885 BEGIN_IPC(getOutputSize
)
886 CopyOutContext
ctx(context
, contextLength
);
887 RefPointer
<Key
> key
= Server::key(keyh
);
888 key
->database().getOutputSize(*ctx
, *key
, inputSize
, encrypt
, *outputSize
);
892 kern_return_t
ucsp_server_getKeyDigest(UCSP_ARGS
, KeyHandle key
, DATA_OUT(digest
))
894 BEGIN_IPC(getKeyDigest
)
895 CssmData digestData
= Server::key(key
)->canonicalDigest();
896 *digest
= digestData
.data();
897 *digestLength
= int_cast
<size_t, mach_msg_type_number_t
>(digestData
.length());
903 // Signatures and MACs
905 kern_return_t
ucsp_server_generateSignature(UCSP_ARGS
, DATA_IN(context
), KeyHandle keyh
,
906 CSSM_ALGORITHMS signOnlyAlgorithm
, DATA_IN(data
), DATA_OUT(signature
))
908 BEGIN_IPC(generateSignature
)
909 CopyOutContext
ctx(context
, contextLength
);
910 RefPointer
<Key
> key
= Server::key(keyh
);
911 OutputData
sigData(signature
, signatureLength
);
912 key
->database().generateSignature(*ctx
, *key
, signOnlyAlgorithm
,
913 DATA(data
), sigData
);
917 kern_return_t
ucsp_server_verifySignature(UCSP_ARGS
, DATA_IN(context
), KeyHandle keyh
,
918 CSSM_ALGORITHMS verifyOnlyAlgorithm
, DATA_IN(data
), DATA_IN(signature
))
920 BEGIN_IPC(verifySignature
)
921 CopyOutContext
ctx(context
, contextLength
);
922 RefPointer
<Key
> key
= Server::key(keyh
);
923 key
->database().verifySignature(*ctx
, *key
, verifyOnlyAlgorithm
,
924 DATA(data
), DATA(signature
));
928 kern_return_t
ucsp_server_generateMac(UCSP_ARGS
, DATA_IN(context
), KeyHandle keyh
,
929 DATA_IN(data
), DATA_OUT(mac
))
931 BEGIN_IPC(generateMac
)
932 CopyOutContext
ctx(context
, contextLength
);
933 RefPointer
<Key
> key
= Server::key(keyh
);
934 OutputData
macData(mac
, macLength
);
935 key
->database().generateMac(*ctx
, *key
, DATA(data
), macData
);
939 kern_return_t
ucsp_server_verifyMac(UCSP_ARGS
, DATA_IN(context
), KeyHandle keyh
,
940 DATA_IN(data
), DATA_IN(mac
))
943 CopyOutContext
ctx(context
, contextLength
);
944 RefPointer
<Key
> key
= Server::key(keyh
);
945 key
->database().verifyMac(*ctx
, *key
, DATA(data
), DATA(mac
));
951 // Encryption/Decryption
953 kern_return_t
ucsp_server_encrypt(UCSP_ARGS
, DATA_IN(context
), KeyHandle keyh
,
954 DATA_IN(clear
), DATA_OUT(cipher
))
957 CopyOutContext
ctx(context
, contextLength
);
958 RefPointer
<Key
> key
= Server::key(keyh
);
959 OutputData
cipherOut(cipher
, cipherLength
);
960 key
->database().encrypt(*ctx
, *key
, DATA(clear
), cipherOut
);
964 kern_return_t
ucsp_server_decrypt(UCSP_ARGS
, DATA_IN(context
), KeyHandle keyh
,
965 DATA_IN(cipher
), DATA_OUT(clear
))
968 CopyOutContext
ctx(context
, contextLength
);
969 RefPointer
<Key
> key
= Server::key(keyh
);
970 OutputData
clearOut(clear
, clearLength
);
971 key
->database().decrypt(*ctx
, *key
, DATA(cipher
), clearOut
);
979 kern_return_t
ucsp_server_generateKey(UCSP_ARGS
, DbHandle db
, DATA_IN(context
),
980 DATA_IN(cred
), DATA_IN(owner
),
981 uint32 usage
, uint32 attrs
, KeyHandle
*newKey
, DATA_OUT(keyHeader
))
983 BEGIN_IPC(generateKey
)
984 CopyOutContext
ctx(context
, contextLength
);
985 CopyOutAccessCredentials
creds(cred
, credLength
);
987 CopyOutEntryAcl
owneracl(owner
, ownerLength
);
988 //@@@ preliminary interpretation - will get "type handle"
989 RefPointer
<Database
> database
=
990 Server::optionalDatabase(db
, attrs
& CSSM_KEYATTR_PERMANENT
);
992 database
->generateKey(*ctx
, creds
, owneracl
, usage
, attrs
, key
);
993 CssmKey::Header newHeader
;
994 key
->returnKey(*newKey
, newHeader
);
996 if (!copyin(&newHeader
, reinterpret_cast<xdrproc_t
> (xdr_CSSM_KEYHEADER
), keyHeader
, keyHeaderLength
))
997 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR
);
998 Server::releaseWhenDone(*keyHeader
);
1002 kern_return_t
ucsp_server_generateKeyPair(UCSP_ARGS
, DbHandle db
, DATA_IN(context
),
1003 DATA_IN(cred
), DATA_IN(owner
),
1004 uint32 pubUsage
, uint32 pubAttrs
, uint32 privUsage
, uint32 privAttrs
,
1005 KeyHandle
*pubKey
, DATA_OUT(pubHeader
), KeyHandle
*privKey
, DATA_OUT(privHeader
))
1007 BEGIN_IPC(generateKeyPair
)
1008 CopyOutContext
ctx(context
, contextLength
);
1009 CopyOutAccessCredentials
creds(cred
, credLength
);
1010 CopyOutEntryAcl
owneracl(owner
, ownerLength
);
1011 RefPointer
<Database
> database
=
1012 Server::optionalDatabase(db
, (privAttrs
| pubAttrs
) & CSSM_KEYATTR_PERMANENT
);
1013 RefPointer
<Key
> pub
, priv
;
1014 database
->generateKey(*ctx
, creds
, owneracl
,
1015 pubUsage
, pubAttrs
, privUsage
, privAttrs
, pub
, priv
);
1016 CssmKey::Header tmpPubHeader
, tmpPrivHeader
;
1018 pub
->returnKey(*pubKey
, tmpPubHeader
);
1019 if (!copyin(&tmpPubHeader
, reinterpret_cast<xdrproc_t
> (xdr_CSSM_KEYHEADER
), pubHeader
, pubHeaderLength
))
1020 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR
);
1021 Server::releaseWhenDone(*pubHeader
);
1023 priv
->returnKey(*privKey
, tmpPrivHeader
);
1024 if (!copyin(&tmpPrivHeader
, reinterpret_cast<xdrproc_t
> (xdr_CSSM_KEYHEADER
), privHeader
, privHeaderLength
))
1025 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR
);
1026 Server::releaseWhenDone(*privHeader
);
1033 // Key wrapping and unwrapping
1035 kern_return_t
ucsp_server_wrapKey(UCSP_ARGS
, DATA_IN(context
), KeyHandle hWrappingKey
,
1036 DATA_IN(cred
), KeyHandle hKeyToBeWrapped
,
1037 DATA_IN(descriptiveData
), DATA_OUT(wrappedKeyData
))
1041 CopyOutContext
ctx(context
, contextLength
);
1042 CopyOutAccessCredentials
creds(cred
, credLength
);
1043 RefPointer
<Key
> subjectKey
= Server::key(hKeyToBeWrapped
);
1044 RefPointer
<Key
> wrappingKey
= Server::optionalKey(hWrappingKey
);
1045 if ((ctx
.context().algorithm() == CSSM_ALGID_NONE
&& subjectKey
->attribute(CSSM_KEYATTR_SENSITIVE
))
1046 || !subjectKey
->attribute(CSSM_KEYATTR_EXTRACTABLE
))
1047 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
);
1048 pickDb(subjectKey
, wrappingKey
)->wrapKey(*ctx
, creds
, wrappingKey
, *subjectKey
, DATA(descriptiveData
), wrappedKey
);
1049 Server::releaseWhenDone(wrappedKey
.keyData().data());
1051 if (!copyin(&wrappedKey
, reinterpret_cast<xdrproc_t
> (xdr_CSSM_KEY
), wrappedKeyData
, wrappedKeyDataLength
))
1052 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR
);
1054 Server::releaseWhenDone(*wrappedKeyData
);
1058 kern_return_t
ucsp_server_unwrapKey(UCSP_ARGS
, DbHandle db
, DATA_IN(context
),
1059 KeyHandle hWrappingKey
, DATA_IN(cred
), DATA_IN(owner
),
1060 KeyHandle hPublicKey
, DATA_IN(wrappedKeyData
),
1061 CSSM_KEYUSE usage
, CSSM_KEYATTR_FLAGS attrs
, DATA_OUT(descriptiveData
),
1062 KeyHandle
*newKey
, DATA_OUT(keyHeader
)/*CssmKey::Header *newHeader*/)
1064 BEGIN_IPC(unwrapKey
)
1065 CopyOutContext
ctx(context
, contextLength
);
1066 CopyOutKey
wrappedKey(wrappedKeyData
, wrappedKeyDataLength
);
1067 CopyOutAccessCredentials
creds(cred
, credLength
);
1068 CopyOutEntryAcl
owneracl(owner
, ownerLength
);
1069 OutputData
descriptiveDatas(descriptiveData
, descriptiveDataLength
);
1070 RefPointer
<Key
> wrappingKey
= Server::optionalKey(hWrappingKey
);
1071 RefPointer
<Key
> unwrappedKey
;
1072 pickDb(Server::optionalDatabase(db
), wrappingKey
)->unwrapKey(*ctx
, creds
, owneracl
,
1073 wrappingKey
, Server::optionalKey(hPublicKey
),
1074 usage
, attrs
, wrappedKey
.key(), unwrappedKey
, descriptiveDatas
);
1076 CssmKey::Header newHeader
;
1077 unwrappedKey
->returnKey(*newKey
, newHeader
);
1078 if (!copyin(&newHeader
, reinterpret_cast<xdrproc_t
> (xdr_CSSM_KEYHEADER
), keyHeader
, keyHeaderLength
))
1079 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR
);
1080 Server::releaseWhenDone(*keyHeader
);
1089 // Note that the "param" argument can have structure. The walker for the
1090 // (artificial) POD CssmDeriveData handles those that are known; if you add
1091 // an algorithm with structured param, you need to add a case there.
1093 kern_return_t
ucsp_server_deriveKey(UCSP_ARGS
, DbHandle db
, DATA_IN(context
), KeyHandle hKey
,
1094 DATA_IN(cred
), DATA_IN(owner
),
1095 DATA_IN(paramInput
), DATA_OUT(paramOutput
),
1096 uint32 usage
, uint32 attrs
, KeyHandle
*newKey
, DATA_OUT(keyHeader
))
1098 BEGIN_IPC(deriveKey
)
1099 CopyOutContext
ctx(context
, contextLength
);
1100 CopyOutAccessCredentials
creds(cred
, credLength
);
1101 CopyOutEntryAcl
owneracl(owner
, ownerLength
);
1102 CopyOutDeriveData
deriveParam(paramInput
, paramInputLength
);
1103 if (deriveParam
.algorithm() != ctx
.context().algorithm())
1104 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR
); // client layer fault
1106 RefPointer
<Database
> database
=
1107 Server::optionalDatabase(db
, attrs
& CSSM_KEYATTR_PERMANENT
);
1108 RefPointer
<Key
> key
= Server::optionalKey(hKey
);
1109 CSSM_DATA param
= deriveParam
.cssm_data();
1110 RefPointer
<Key
> derivedKey
;
1111 pickDb(Server::optionalDatabase(db
, attrs
& CSSM_KEYATTR_PERMANENT
),
1112 key
)->deriveKey(*ctx
, key
, creds
, owneracl
, static_cast<CssmData
*>(¶m
), usage
, attrs
, derivedKey
);
1114 CssmKey::Header newHeader
;
1115 derivedKey
->returnKey(*newKey
, newHeader
);
1117 if (!copyin(&newHeader
, reinterpret_cast<xdrproc_t
> (xdr_CSSM_KEYHEADER
), keyHeader
, keyHeaderLength
))
1118 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR
);
1119 Server::releaseWhenDone(*keyHeader
);
1122 if (!param
.Data
) // CSP screwed up
1123 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
);
1124 OutputData(paramOutput
, paramOutputLength
) = CssmAutoData(Server::csp().allocator(), param
).release();
1131 // Watch out for the memory-management tap-dance.
1133 kern_return_t
ucsp_server_getOwner(UCSP_ARGS
, AclKind kind
, KeyHandle key
,
1137 AclOwnerPrototype owner
;
1138 Server::aclBearer(kind
, key
).getOwner(owner
); // allocates memory in owner
1139 void *owners_data
; u_int owners_length
;
1140 if (!::copyin(&owner
, reinterpret_cast<xdrproc_t
>(xdr_CSSM_ACL_OWNER_PROTOTYPE
), &owners_data
, &owners_length
))
1141 CssmError::throwMe(CSSM_ERRCODE_MEMORY_ERROR
);
1143 { ChunkFreeWalker free
; walk(free
, owner
); } // release chunked original
1144 Server::releaseWhenDone(owners_data
); // throw flat copy out when done
1145 *ownerOut
= owners_data
;
1146 *ownerOutLength
= owners_length
;
1150 kern_return_t
ucsp_server_setOwner(UCSP_ARGS
, AclKind kind
, KeyHandle key
,
1151 DATA_IN(cred
), DATA_IN(owner
))
1154 CopyOutAccessCredentials
creds(cred
, credLength
);
1155 CopyOutOwnerAcl
owneracl(owner
, ownerLength
);
1156 Server::aclBearer(kind
, key
).changeOwner(*owneracl
, creds
);
1160 kern_return_t
ucsp_server_getAcl(UCSP_ARGS
, AclKind kind
, KeyHandle key
,
1161 boolean_t haveTag
, const char *tag
,
1162 uint32
*countp
, DATA_OUT(acls
))
1166 AclEntryInfo
*aclList
;
1168 AclSource
& aclRef
= Server::aclBearer(kind
, key
);
1169 secinfo("SecAccess", "getting the ACL for handle %d [%d] (%p)", key
, (uint32_t) kind
, &aclRef
);
1170 aclRef
.getAcl(haveTag
? tag
: NULL
, count
, aclList
);
1172 CSSM_ACL_ENTRY_INFO_ARRAY aclsArray
= { count
, aclList
};
1173 void *acls_data
; u_int acls_length
;
1174 if (!::copyin(&aclsArray
, reinterpret_cast<xdrproc_t
>(xdr_CSSM_ACL_ENTRY_INFO_ARRAY
), &acls_data
, &acls_length
))
1175 CssmError::throwMe(CSSM_ERRCODE_MEMORY_ERROR
);
1177 { // release the chunked memory originals
1178 ChunkFreeWalker free
;
1179 for (uint32 n
= 0; n
< count
; n
++)
1180 walk(free
, aclList
[n
]);
1182 // release the memory allocated for the list itself when we are done
1183 Allocator::standard().free (aclList
);
1187 *countp
= count
; // XXX/cs count becomes part of the blob
1188 *aclsLength
= acls_length
;
1190 Server::releaseWhenDone(acls_data
);
1194 kern_return_t
ucsp_server_changeAcl(UCSP_ARGS
, AclKind kind
, KeyHandle key
,
1195 DATA_IN(cred
), CSSM_ACL_EDIT_MODE mode
, GenericHandle handle
,
1198 BEGIN_IPC(changeAcl
)
1199 CopyOutAccessCredentials
creds(cred
, credLength
);
1200 CopyOutAclEntryInput
entryacl(acl
, aclLength
);
1202 AclSource
& aclRef
= Server::aclBearer(kind
, key
);
1203 secinfo("SecAccess", "changing the ACL for handle %d [%d] (%p)", key
, (uint32_t) kind
, &aclRef
);
1204 aclRef
.changeAcl(AclEdit(mode
, handle
, entryacl
), creds
);
1213 kern_return_t
ucsp_server_login(UCSP_ARGS
, DATA_IN(cred
), DATA_IN(name
))
1216 CopyOutAccessCredentials
creds(cred
, credLength
);
1217 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
1221 kern_return_t
ucsp_server_logout(UCSP_ARGS
)
1224 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
1230 // Miscellaneous CSP-related calls
1232 kern_return_t
ucsp_server_getStatistics(UCSP_ARGS
, uint32 ssid
, CSSM_CSP_OPERATIONAL_STATISTICS
*statistics
)
1234 BEGIN_IPC(getStatistics
)
1235 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
1239 kern_return_t
ucsp_server_getTime(UCSP_ARGS
, uint32 ssid
, CSSM_ALGORITHMS algorithm
, DATA_OUT(data
))
1242 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
1246 kern_return_t
ucsp_server_getCounter(UCSP_ARGS
, uint32 ssid
, DATA_OUT(data
))
1248 BEGIN_IPC(getCounter
)
1249 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
1253 kern_return_t
ucsp_server_selfVerify(UCSP_ARGS
, uint32 ssid
)
1255 BEGIN_IPC(selfVerify
)
1256 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
1262 // Passthrough calls (separate for CSP and DL passthroughs)
1264 kern_return_t
ucsp_server_cspPassThrough(UCSP_ARGS
, uint32 ssid
, uint32 id
, DATA_IN(context
),
1265 KeyHandle hKey
, DATA_IN(inData
), DATA_OUT(outData
))
1267 BEGIN_IPC(cspPassThrough
)
1268 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
1272 kern_return_t
ucsp_server_dlPassThrough(UCSP_ARGS
, uint32 ssid
, uint32 id
,
1273 DATA_IN(inData
), DATA_OUT(outData
))
1275 BEGIN_IPC(dlPassThrough
)
1276 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
1282 // Database key management.
1283 // ExtractMasterKey looks vaguely like a key derivation operation, and is in fact
1284 // presented by the CSPDL's CSSM layer as such.
1286 kern_return_t
ucsp_server_extractMasterKey(UCSP_ARGS
, DbHandle db
, DATA_IN(context
), DbHandle sourceDb
,
1287 DATA_IN(cred
), DATA_IN(owner
),
1288 uint32 usage
, uint32 attrs
, KeyHandle
*newKey
, DATA_OUT(keyHeader
))
1290 BEGIN_IPC(extractMasterKey
)
1291 CopyOutAccessCredentials
creds(cred
, credLength
);
1292 CopyOutEntryAcl
owneracl(owner
, ownerLength
);
1293 CopyOutContext
ctx(context
, contextLength
);
1294 RefPointer
<KeychainDatabase
> keychain
= Server::keychain(sourceDb
);
1295 RefPointer
<Key
> masterKey
= keychain
->extractMasterKey(
1296 *Server::optionalDatabase(db
, attrs
& CSSM_KEYATTR_PERMANENT
),
1297 creds
, owneracl
, usage
, attrs
);
1298 CssmKey::Header header
;
1299 masterKey
->returnKey(*newKey
, header
);
1300 if (!copyin(&header
, reinterpret_cast<xdrproc_t
> (xdr_CSSM_KEYHEADER
), keyHeader
, keyHeaderLength
))
1301 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR
);
1302 Server::releaseWhenDone(*keyHeader
);
1308 // Notification core subsystem
1311 kern_return_t
ucsp_server_postNotification(UCSP_ARGS
, uint32 domain
, uint32 event
,
1312 DATA_IN(data
), uint32 sequence
)
1314 BEGIN_IPC(postNotification
)
1315 Listener::notify(domain
, event
, sequence
, DATA(data
), auditToken
);
1321 // Child check-in service.
1322 // Note that this isn't using the standard argument pattern.
1324 kern_return_t
ucsp_server_childCheckIn(audit_token_t auditToken
, mach_port_t serverPort
,
1325 mach_port_t servicePort
, mach_port_t taskPort
)
1328 ServerChild::checkIn(servicePort
, audit_token_to_pid(auditToken
));
1329 // Will be NULL from newer frameworks, but mach_port_deallocate doesn't seem to mind
1330 END_IPCS(mach_port_deallocate(mach_task_self(), taskPort
))
1335 // Testing-related RPCs
1337 kern_return_t
ucsp_server_getUserPromptAttempts(UCSP_ARGS
, uint32
* attempts
)
1339 BEGIN_IPC(keychainPromptAttempts
)
1341 *attempts
= KeychainPromptAclSubject::getPromptAttempts() + KeychainDatabase::getInteractiveUnlockAttempts();
1346 #pragma clang diagnostic pop