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