]> git.saurik.com Git - apple/security.git/blob - securityd/src/transition.cpp
Security-58286.51.6.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 // Must hold the DB's common's lock to safely determine if it's locked. Locking is a mess in there.
776 StLock<Mutex> _(Server::database(db)->common());
777 *locked = Server::database(db)->isLocked();
778 END_IPC(DL)
779 }
780
781 kern_return_t ucsp_server_verifyKeyStorePassphrase(UCSP_ARGS, uint32_t retries)
782 {
783 BEGIN_IPC(verifyKeyStorePassphrase)
784 connection.process().session().verifyKeyStorePassphrase(retries);
785 END_IPC(DL)
786 }
787
788 kern_return_t ucsp_server_changeKeyStorePassphrase(UCSP_ARGS)
789 {
790 BEGIN_IPC(verifyKeyStorePassphrase)
791 connection.process().session().changeKeyStorePassphrase();
792 END_IPC(DL)
793 }
794
795 kern_return_t ucsp_server_resetKeyStorePassphrase(UCSP_ARGS, DATA_IN(passphrase))
796 {
797 BEGIN_IPC(verifyKeyStorePassphrase)
798 connection.process().session().resetKeyStorePassphrase(DATA(passphrase));
799 END_IPC(DL)
800 }
801
802 //
803 // Key management
804 //
805 kern_return_t ucsp_server_encodeKey(UCSP_ARGS, KeyHandle keyh, DATA_OUT(blob),
806 boolean_t wantUid, DATA_OUT(uid))
807 {
808 BEGIN_IPC(encodeKey)
809 RefPointer<Key> gKey = Server::key(keyh);
810 if (KeychainKey *key = dynamic_cast<KeychainKey *>(gKey.get())) {
811 KeyBlob *keyBlob = key->blob(); // still owned by key
812 *blob = keyBlob;
813 *blobLength = keyBlob->length();
814 if (wantUid) { // uid generation is not implemented
815 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
816 } else {
817 *uidLength = 0; // do not return this
818 }
819 } else { // not a KeychainKey
820 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
821 }
822 END_IPC(CSP)
823 }
824
825 kern_return_t ucsp_server_decodeKey(UCSP_ARGS, KeyHandle *keyh, DATA_OUT(keyHeader),
826 DbHandle db, DATA_IN(blob))
827 {
828 BEGIN_IPC(decodeKey)
829 RefPointer<Key> key = new KeychainKey(*Server::keychain(db), SSBLOB(KeyBlob, blob));
830 CssmKey::Header header;
831 key->returnKey(*keyh, header);
832 if (!copyin(&header, reinterpret_cast<xdrproc_t> (xdr_CSSM_KEYHEADER), keyHeader, keyHeaderLength))
833 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
834 Server::releaseWhenDone(*keyHeader);
835 END_IPC(CSP)
836 }
837
838 // keychain synchronization
839 kern_return_t ucsp_server_recodeKey(UCSP_ARGS, DbHandle oldDb, KeyHandle keyh,
840 DbHandle newDb, DATA_OUT(newBlob))
841 {
842 BEGIN_IPC(recodeKey)
843 // If the old key is passed in as DATA_IN(oldBlob):
844 // RefPointer<KeychainKey> key = new KeychainKey(*Server::keychain(oldDb), SSBLOB(KeyBlob, oldBlob));
845 RefPointer<Key> key = Server::key(keyh);
846 if (KeychainKey *kckey = dynamic_cast<KeychainKey *>(key.get())) {
847 KeyBlob *blob = Server::keychain(newDb)->recodeKey(*kckey);
848 *newBlob = blob;
849 *newBlobLength = blob->length();
850 Server::releaseWhenDone(*newBlob);
851 // @@@ stop leaking blob
852 } else { // not a KeychainKey
853 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
854 }
855 END_IPC(CSP)
856 }
857
858 kern_return_t ucsp_server_releaseKey(UCSP_ARGS, KeyHandle keyh)
859 {
860 BEGIN_IPC(releaseKey)
861 RefPointer<Key> key = Server::key(keyh);
862 key->database().releaseKey(*key);
863 END_IPC(CSP)
864 }
865
866 kern_return_t ucsp_server_queryKeySizeInBits(UCSP_ARGS, KeyHandle keyh, CSSM_KEY_SIZE *length)
867 {
868 BEGIN_IPC(queryKeySizeInBits)
869 RefPointer<Key> key = Server::key(keyh);
870 key->database().queryKeySizeInBits(*key, CssmKeySize::overlay(*length));
871 END_IPC(CSP)
872 }
873
874 kern_return_t ucsp_server_getOutputSize(UCSP_ARGS, DATA_IN(context), KeyHandle keyh,
875 uint32 inputSize, boolean_t encrypt, uint32 *outputSize)
876 {
877 BEGIN_IPC(getOutputSize)
878 CopyOutContext ctx(context, contextLength);
879 RefPointer<Key> key = Server::key(keyh);
880 key->database().getOutputSize(*ctx, *key, inputSize, encrypt, *outputSize);
881 END_IPC(CSP)
882 }
883
884 kern_return_t ucsp_server_getKeyDigest(UCSP_ARGS, KeyHandle key, DATA_OUT(digest))
885 {
886 BEGIN_IPC(getKeyDigest)
887 CssmData digestData = Server::key(key)->canonicalDigest();
888 *digest = digestData.data();
889 *digestLength = int_cast<size_t, mach_msg_type_number_t>(digestData.length());
890 END_IPC(CSP)
891 }
892
893
894 //
895 // Signatures and MACs
896 //
897 kern_return_t ucsp_server_generateSignature(UCSP_ARGS, DATA_IN(context), KeyHandle keyh,
898 CSSM_ALGORITHMS signOnlyAlgorithm, DATA_IN(data), DATA_OUT(signature))
899 {
900 BEGIN_IPC(generateSignature)
901 CopyOutContext ctx(context, contextLength);
902 RefPointer<Key> key = Server::key(keyh);
903 OutputData sigData(signature, signatureLength);
904 key->database().generateSignature(*ctx, *key, signOnlyAlgorithm,
905 DATA(data), sigData);
906 END_IPC(CSP)
907 }
908
909 kern_return_t ucsp_server_verifySignature(UCSP_ARGS, DATA_IN(context), KeyHandle keyh,
910 CSSM_ALGORITHMS verifyOnlyAlgorithm, DATA_IN(data), DATA_IN(signature))
911 {
912 BEGIN_IPC(verifySignature)
913 CopyOutContext ctx(context, contextLength);
914 RefPointer<Key> key = Server::key(keyh);
915 key->database().verifySignature(*ctx, *key, verifyOnlyAlgorithm,
916 DATA(data), DATA(signature));
917 END_IPC(CSP)
918 }
919
920 kern_return_t ucsp_server_generateMac(UCSP_ARGS, DATA_IN(context), KeyHandle keyh,
921 DATA_IN(data), DATA_OUT(mac))
922 {
923 BEGIN_IPC(generateMac)
924 CopyOutContext ctx(context, contextLength);
925 RefPointer<Key> key = Server::key(keyh);
926 OutputData macData(mac, macLength);
927 key->database().generateMac(*ctx, *key, DATA(data), macData);
928 END_IPC(CSP)
929 }
930
931 kern_return_t ucsp_server_verifyMac(UCSP_ARGS, DATA_IN(context), KeyHandle keyh,
932 DATA_IN(data), DATA_IN(mac))
933 {
934 BEGIN_IPC(verifyMac)
935 CopyOutContext ctx(context, contextLength);
936 RefPointer<Key> key = Server::key(keyh);
937 key->database().verifyMac(*ctx, *key, DATA(data), DATA(mac));
938 END_IPC(CSP)
939 }
940
941
942 //
943 // Encryption/Decryption
944 //
945 kern_return_t ucsp_server_encrypt(UCSP_ARGS, DATA_IN(context), KeyHandle keyh,
946 DATA_IN(clear), DATA_OUT(cipher))
947 {
948 BEGIN_IPC(encrypt)
949 CopyOutContext ctx(context, contextLength);
950 RefPointer<Key> key = Server::key(keyh);
951 OutputData cipherOut(cipher, cipherLength);
952 key->database().encrypt(*ctx, *key, DATA(clear), cipherOut);
953 END_IPC(CSP)
954 }
955
956 kern_return_t ucsp_server_decrypt(UCSP_ARGS, DATA_IN(context), KeyHandle keyh,
957 DATA_IN(cipher), DATA_OUT(clear))
958 {
959 BEGIN_IPC(decrypt)
960 CopyOutContext ctx(context, contextLength);
961 RefPointer<Key> key = Server::key(keyh);
962 OutputData clearOut(clear, clearLength);
963 key->database().decrypt(*ctx, *key, DATA(cipher), clearOut);
964 END_IPC(CSP)
965 }
966
967
968 //
969 // Key generation
970 //
971 kern_return_t ucsp_server_generateKey(UCSP_ARGS, DbHandle db, DATA_IN(context),
972 DATA_IN(cred), DATA_IN(owner),
973 uint32 usage, uint32 attrs, KeyHandle *newKey, DATA_OUT(keyHeader))
974 {
975 BEGIN_IPC(generateKey)
976 CopyOutContext ctx(context, contextLength);
977 CopyOutAccessCredentials creds(cred, credLength);
978
979 CopyOutEntryAcl owneracl(owner, ownerLength);
980 //@@@ preliminary interpretation - will get "type handle"
981 RefPointer<Database> database =
982 Server::optionalDatabase(db, attrs & CSSM_KEYATTR_PERMANENT);
983 RefPointer<Key> key;
984 database->generateKey(*ctx, creds, owneracl, usage, attrs, key);
985 CssmKey::Header newHeader;
986 key->returnKey(*newKey, newHeader);
987
988 if (!copyin(&newHeader, reinterpret_cast<xdrproc_t> (xdr_CSSM_KEYHEADER), keyHeader, keyHeaderLength))
989 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
990 Server::releaseWhenDone(*keyHeader);
991 END_IPC(CSP)
992 }
993
994 kern_return_t ucsp_server_generateKeyPair(UCSP_ARGS, DbHandle db, DATA_IN(context),
995 DATA_IN(cred), DATA_IN(owner),
996 uint32 pubUsage, uint32 pubAttrs, uint32 privUsage, uint32 privAttrs,
997 KeyHandle *pubKey, DATA_OUT(pubHeader), KeyHandle *privKey, DATA_OUT(privHeader))
998 {
999 BEGIN_IPC(generateKeyPair)
1000 CopyOutContext ctx(context, contextLength);
1001 CopyOutAccessCredentials creds(cred, credLength);
1002 CopyOutEntryAcl owneracl(owner, ownerLength);
1003 RefPointer<Database> database =
1004 Server::optionalDatabase(db, (privAttrs | pubAttrs) & CSSM_KEYATTR_PERMANENT);
1005 RefPointer<Key> pub, priv;
1006 database->generateKey(*ctx, creds, owneracl,
1007 pubUsage, pubAttrs, privUsage, privAttrs, pub, priv);
1008 CssmKey::Header tmpPubHeader, tmpPrivHeader;
1009
1010 pub->returnKey(*pubKey, tmpPubHeader);
1011 if (!copyin(&tmpPubHeader, reinterpret_cast<xdrproc_t> (xdr_CSSM_KEYHEADER), pubHeader, pubHeaderLength))
1012 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
1013 Server::releaseWhenDone(*pubHeader);
1014
1015 priv->returnKey(*privKey, tmpPrivHeader);
1016 if (!copyin(&tmpPrivHeader, reinterpret_cast<xdrproc_t> (xdr_CSSM_KEYHEADER), privHeader, privHeaderLength))
1017 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
1018 Server::releaseWhenDone(*privHeader);
1019
1020 END_IPC(CSP)
1021 }
1022
1023
1024 //
1025 // Key wrapping and unwrapping
1026 //
1027 kern_return_t ucsp_server_wrapKey(UCSP_ARGS, DATA_IN(context), KeyHandle hWrappingKey,
1028 DATA_IN(cred), KeyHandle hKeyToBeWrapped,
1029 DATA_IN(descriptiveData), DATA_OUT(wrappedKeyData))
1030 {
1031 BEGIN_IPC(wrapKey)
1032 CssmKey wrappedKey;
1033 CopyOutContext ctx(context, contextLength);
1034 CopyOutAccessCredentials creds(cred, credLength);
1035 RefPointer<Key> subjectKey = Server::key(hKeyToBeWrapped);
1036 RefPointer<Key> wrappingKey = Server::optionalKey(hWrappingKey);
1037 if ((ctx.context().algorithm() == CSSM_ALGID_NONE && subjectKey->attribute(CSSM_KEYATTR_SENSITIVE))
1038 || !subjectKey->attribute(CSSM_KEYATTR_EXTRACTABLE))
1039 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
1040 pickDb(subjectKey, wrappingKey)->wrapKey(*ctx, creds, wrappingKey, *subjectKey, DATA(descriptiveData), wrappedKey);
1041 Server::releaseWhenDone(wrappedKey.keyData().data());
1042
1043 if (!copyin(&wrappedKey, reinterpret_cast<xdrproc_t> (xdr_CSSM_KEY), wrappedKeyData, wrappedKeyDataLength))
1044 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
1045
1046 Server::releaseWhenDone(*wrappedKeyData);
1047 END_IPC(CSP)
1048 }
1049
1050 kern_return_t ucsp_server_unwrapKey(UCSP_ARGS, DbHandle db, DATA_IN(context),
1051 KeyHandle hWrappingKey, DATA_IN(cred), DATA_IN(owner),
1052 KeyHandle hPublicKey, DATA_IN(wrappedKeyData),
1053 CSSM_KEYUSE usage, CSSM_KEYATTR_FLAGS attrs, DATA_OUT(descriptiveData),
1054 KeyHandle *newKey, DATA_OUT(keyHeader)/*CssmKey::Header *newHeader*/)
1055 {
1056 BEGIN_IPC(unwrapKey)
1057 CopyOutContext ctx(context, contextLength);
1058 CopyOutKey wrappedKey(wrappedKeyData, wrappedKeyDataLength);
1059 CopyOutAccessCredentials creds(cred, credLength);
1060 CopyOutEntryAcl owneracl(owner, ownerLength);
1061 OutputData descriptiveDatas(descriptiveData, descriptiveDataLength);
1062 RefPointer<Key> wrappingKey = Server::optionalKey(hWrappingKey);
1063 RefPointer<Key> unwrappedKey;
1064 pickDb(Server::optionalDatabase(db), wrappingKey)->unwrapKey(*ctx, creds, owneracl,
1065 wrappingKey, Server::optionalKey(hPublicKey),
1066 usage, attrs, wrappedKey.key(), unwrappedKey, descriptiveDatas);
1067
1068 CssmKey::Header newHeader;
1069 unwrappedKey->returnKey(*newKey, newHeader);
1070 if (!copyin(&newHeader, reinterpret_cast<xdrproc_t> (xdr_CSSM_KEYHEADER), keyHeader, keyHeaderLength))
1071 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
1072 Server::releaseWhenDone(*keyHeader);
1073
1074 END_IPC(CSP)
1075 }
1076
1077
1078 //
1079 // Key derivation.
1080 //
1081 // Note that the "param" argument can have structure. The walker for the
1082 // (artificial) POD CssmDeriveData handles those that are known; if you add
1083 // an algorithm with structured param, you need to add a case there.
1084 //
1085 kern_return_t ucsp_server_deriveKey(UCSP_ARGS, DbHandle db, DATA_IN(context), KeyHandle hKey,
1086 DATA_IN(cred), DATA_IN(owner),
1087 DATA_IN(paramInput), DATA_OUT(paramOutput),
1088 uint32 usage, uint32 attrs, KeyHandle *newKey, DATA_OUT(keyHeader))
1089 {
1090 BEGIN_IPC(deriveKey)
1091 CopyOutContext ctx(context, contextLength);
1092 CopyOutAccessCredentials creds(cred, credLength);
1093 CopyOutEntryAcl owneracl(owner, ownerLength);
1094 CopyOutDeriveData deriveParam(paramInput, paramInputLength);
1095 if (deriveParam.algorithm() != ctx.context().algorithm())
1096 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR); // client layer fault
1097
1098 RefPointer<Database> database =
1099 Server::optionalDatabase(db, attrs & CSSM_KEYATTR_PERMANENT);
1100 RefPointer<Key> key = Server::optionalKey(hKey);
1101 CSSM_DATA param = deriveParam.cssm_data();
1102 RefPointer<Key> derivedKey;
1103 pickDb(Server::optionalDatabase(db, attrs & CSSM_KEYATTR_PERMANENT),
1104 key)->deriveKey(*ctx, key, creds, owneracl, static_cast<CssmData*>(&param), usage, attrs, derivedKey);
1105
1106 CssmKey::Header newHeader;
1107 derivedKey->returnKey(*newKey, newHeader);
1108
1109 if (!copyin(&newHeader, reinterpret_cast<xdrproc_t> (xdr_CSSM_KEYHEADER), keyHeader, keyHeaderLength))
1110 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
1111 Server::releaseWhenDone(*keyHeader);
1112
1113 if (param.Length) {
1114 if (!param.Data) // CSP screwed up
1115 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
1116 OutputData(paramOutput, paramOutputLength) = CssmAutoData(Server::csp().allocator(), param).release();
1117 }
1118 END_IPC(CSP)
1119 }
1120
1121
1122 //
1123 // Random generation
1124 //
1125 kern_return_t ucsp_server_generateRandom(UCSP_ARGS, uint32 ssid, DATA_IN(context), DATA_OUT(data))
1126 {
1127 BEGIN_IPC(generateRandom)
1128 CopyOutContext ctx(context, contextLength);
1129 if (ssid)
1130 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
1131
1132 // default version (use /dev/random)
1133 Allocator &allocator = Allocator::standard(Allocator::sensitive);
1134 if (size_t bytes = ctx.context().getInt(CSSM_ATTRIBUTE_OUTPUT_SIZE)) {
1135 void *buffer = allocator.malloc(bytes);
1136 Server::active().random(buffer, bytes);
1137 *data = buffer;
1138 *dataLength = int_cast<size_t, mach_msg_type_number_t>(bytes);
1139 Server::releaseWhenDone(allocator, buffer);
1140 }
1141 END_IPC(CSP)
1142 }
1143
1144
1145 //
1146 // ACL management.
1147 // Watch out for the memory-management tap-dance.
1148 //
1149 kern_return_t ucsp_server_getOwner(UCSP_ARGS, AclKind kind, KeyHandle key,
1150 DATA_OUT(ownerOut))
1151 {
1152 BEGIN_IPC(getOwner)
1153 AclOwnerPrototype owner;
1154 Server::aclBearer(kind, key).getOwner(owner); // allocates memory in owner
1155 void *owners_data; u_int owners_length;
1156 if (!::copyin(&owner, reinterpret_cast<xdrproc_t>(xdr_CSSM_ACL_OWNER_PROTOTYPE), &owners_data, &owners_length))
1157 CssmError::throwMe(CSSM_ERRCODE_MEMORY_ERROR);
1158
1159 { ChunkFreeWalker free; walk(free, owner); } // release chunked original
1160 Server::releaseWhenDone(owners_data); // throw flat copy out when done
1161 *ownerOut = owners_data;
1162 *ownerOutLength = owners_length;
1163 END_IPC(CSP)
1164 }
1165
1166 kern_return_t ucsp_server_setOwner(UCSP_ARGS, AclKind kind, KeyHandle key,
1167 DATA_IN(cred), DATA_IN(owner))
1168 {
1169 BEGIN_IPC(setOwner)
1170 CopyOutAccessCredentials creds(cred, credLength);
1171 CopyOutOwnerAcl owneracl(owner, ownerLength);
1172 Server::aclBearer(kind, key).changeOwner(*owneracl, creds);
1173 END_IPC(CSP)
1174 }
1175
1176 kern_return_t ucsp_server_getAcl(UCSP_ARGS, AclKind kind, KeyHandle key,
1177 boolean_t haveTag, const char *tag,
1178 uint32 *countp, DATA_OUT(acls))
1179 {
1180 BEGIN_IPC(getAcl)
1181 uint32 count;
1182 AclEntryInfo *aclList;
1183
1184 AclSource& aclRef = Server::aclBearer(kind, key);
1185 secinfo("SecAccess", "getting the ACL for handle %d [%d] (%p)", key, (uint32_t) kind, &aclRef);
1186 aclRef.getAcl(haveTag ? tag : NULL, count, aclList);
1187
1188 CSSM_ACL_ENTRY_INFO_ARRAY aclsArray = { count, aclList };
1189 void *acls_data; u_int acls_length;
1190 if (!::copyin(&aclsArray, reinterpret_cast<xdrproc_t>(xdr_CSSM_ACL_ENTRY_INFO_ARRAY), &acls_data, &acls_length))
1191 CssmError::throwMe(CSSM_ERRCODE_MEMORY_ERROR);
1192
1193 { // release the chunked memory originals
1194 ChunkFreeWalker free;
1195 for (uint32 n = 0; n < count; n++)
1196 walk(free, aclList[n]);
1197
1198 // release the memory allocated for the list itself when we are done
1199 Allocator::standard().free (aclList);
1200 }
1201
1202
1203 *countp = count; // XXX/cs count becomes part of the blob
1204 *aclsLength = acls_length;
1205 *acls = acls_data;
1206 Server::releaseWhenDone(acls_data);
1207 END_IPC(CSP)
1208 }
1209
1210 kern_return_t ucsp_server_changeAcl(UCSP_ARGS, AclKind kind, KeyHandle key,
1211 DATA_IN(cred), CSSM_ACL_EDIT_MODE mode, GenericHandle handle,
1212 DATA_IN(acl))
1213 {
1214 BEGIN_IPC(changeAcl)
1215 CopyOutAccessCredentials creds(cred, credLength);
1216 CopyOutAclEntryInput entryacl(acl, aclLength);
1217
1218 AclSource& aclRef = Server::aclBearer(kind, key);
1219 secinfo("SecAccess", "changing the ACL for handle %d [%d] (%p)", key, (uint32_t) kind, &aclRef);
1220 aclRef.changeAcl(AclEdit(mode, handle, entryacl), creds);
1221
1222 END_IPC(CSP)
1223 }
1224
1225
1226 //
1227 // Login/Logout
1228 //
1229 kern_return_t ucsp_server_login(UCSP_ARGS, DATA_IN(cred), DATA_IN(name))
1230 {
1231 BEGIN_IPC(login)
1232 CopyOutAccessCredentials creds(cred, credLength);
1233 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
1234 END_IPC(CSP)
1235 }
1236
1237 kern_return_t ucsp_server_logout(UCSP_ARGS)
1238 {
1239 BEGIN_IPC(logout)
1240 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
1241 END_IPC(CSP)
1242 }
1243
1244
1245 //
1246 // Miscellaneous CSP-related calls
1247 //
1248 kern_return_t ucsp_server_getStatistics(UCSP_ARGS, uint32 ssid, CSSM_CSP_OPERATIONAL_STATISTICS *statistics)
1249 {
1250 BEGIN_IPC(getStatistics)
1251 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
1252 END_IPC(CSP)
1253 }
1254
1255 kern_return_t ucsp_server_getTime(UCSP_ARGS, uint32 ssid, CSSM_ALGORITHMS algorithm, DATA_OUT(data))
1256 {
1257 BEGIN_IPC(getTime)
1258 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
1259 END_IPC(CSP)
1260 }
1261
1262 kern_return_t ucsp_server_getCounter(UCSP_ARGS, uint32 ssid, DATA_OUT(data))
1263 {
1264 BEGIN_IPC(getCounter)
1265 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
1266 END_IPC(CSP)
1267 }
1268
1269 kern_return_t ucsp_server_selfVerify(UCSP_ARGS, uint32 ssid)
1270 {
1271 BEGIN_IPC(selfVerify)
1272 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
1273 END_IPC(CSP)
1274 }
1275
1276
1277 //
1278 // Passthrough calls (separate for CSP and DL passthroughs)
1279 //
1280 kern_return_t ucsp_server_cspPassThrough(UCSP_ARGS, uint32 ssid, uint32 id, DATA_IN(context),
1281 KeyHandle hKey, DATA_IN(inData), DATA_OUT(outData))
1282 {
1283 BEGIN_IPC(cspPassThrough)
1284 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
1285 END_IPC(CSP)
1286 }
1287
1288 kern_return_t ucsp_server_dlPassThrough(UCSP_ARGS, uint32 ssid, uint32 id,
1289 DATA_IN(inData), DATA_OUT(outData))
1290 {
1291 BEGIN_IPC(dlPassThrough)
1292 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
1293 END_IPC(DL)
1294 }
1295
1296
1297 //
1298 // Database key management.
1299 // ExtractMasterKey looks vaguely like a key derivation operation, and is in fact
1300 // presented by the CSPDL's CSSM layer as such.
1301 //
1302 kern_return_t ucsp_server_extractMasterKey(UCSP_ARGS, DbHandle db, DATA_IN(context), DbHandle sourceDb,
1303 DATA_IN(cred), DATA_IN(owner),
1304 uint32 usage, uint32 attrs, KeyHandle *newKey, DATA_OUT(keyHeader))
1305 {
1306 BEGIN_IPC(extractMasterKey)
1307 CopyOutAccessCredentials creds(cred, credLength);
1308 CopyOutEntryAcl owneracl(owner, ownerLength);
1309 CopyOutContext ctx(context, contextLength);
1310 RefPointer<KeychainDatabase> keychain = Server::keychain(sourceDb);
1311 RefPointer<Key> masterKey = keychain->extractMasterKey(
1312 *Server::optionalDatabase(db, attrs & CSSM_KEYATTR_PERMANENT),
1313 creds, owneracl, usage, attrs);
1314 CssmKey::Header header;
1315 masterKey->returnKey(*newKey, header);
1316 if (!copyin(&header, reinterpret_cast<xdrproc_t> (xdr_CSSM_KEYHEADER), keyHeader, keyHeaderLength))
1317 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
1318 Server::releaseWhenDone(*keyHeader);
1319 END_IPC(CSP)
1320 }
1321
1322
1323 //
1324 // Notification core subsystem
1325 //
1326
1327 kern_return_t ucsp_server_postNotification(UCSP_ARGS, uint32 domain, uint32 event,
1328 DATA_IN(data), uint32 sequence)
1329 {
1330 BEGIN_IPC(postNotification)
1331 Listener::notify(domain, event, sequence, DATA(data), auditToken);
1332 END_IPC(CSSM)
1333 }
1334
1335
1336 //
1337 // Child check-in service.
1338 // Note that this isn't using the standard argument pattern.
1339 //
1340 kern_return_t ucsp_server_childCheckIn(mach_port_t serverPort,
1341 mach_port_t servicePort, mach_port_t taskPort)
1342 {
1343 BEGIN_IPCS
1344 ServerChild::checkIn(servicePort, TaskPort(taskPort).pid());
1345 END_IPCS(mach_port_deallocate(mach_task_self(), taskPort))
1346 }
1347
1348
1349 //
1350 // Code Signing Hosting registration.
1351 // Note that the Code Signing Proxy facility (implementing the "cshosting"
1352 // IPC protocol) is elsewhere.
1353 //
1354 kern_return_t ucsp_server_registerHosting(UCSP_ARGS, mach_port_t hostingPort, uint32 flags)
1355 {
1356 BEGIN_IPC(registerHosting)
1357 connection.process().registerCodeSigning(hostingPort, flags);
1358 END_IPC(CSSM)
1359 }
1360
1361 kern_return_t ucsp_server_hostingPort(UCSP_ARGS, pid_t hostPid, mach_port_t *hostingPort)
1362 {
1363 BEGIN_IPC(hostingPort)
1364 if (RefPointer<Process> process = Server::active().findPid(hostPid))
1365 *hostingPort = process->hostingPort();
1366 else
1367 *hostingPort = MACH_PORT_NULL;
1368 secinfo("hosting", "hosting port for for pid=%d is port %d", hostPid, *hostingPort);
1369 END_IPC(CSSM)
1370 }
1371
1372
1373 kern_return_t ucsp_server_setGuest(UCSP_ARGS, SecGuestRef guest, SecCSFlags flags)
1374 {
1375 BEGIN_IPC(setGuest)
1376 connection.guestRef(guest, flags);
1377 END_IPC(CSSM)
1378 }
1379
1380
1381 kern_return_t ucsp_server_createGuest(UCSP_ARGS, SecGuestRef host,
1382 uint32_t status, const char *path, DATA_IN(cdhash), DATA_IN(attributes),
1383 SecCSFlags flags, SecGuestRef *newGuest)
1384 {
1385 BEGIN_IPC(createGuest)
1386 *newGuest = connection.process().createGuest(host, status, path, DATA(cdhash), DATA(attributes), flags);
1387 END_IPC(CSSM)
1388 }
1389
1390 kern_return_t ucsp_server_setGuestStatus(UCSP_ARGS, SecGuestRef guest,
1391 uint32_t status, DATA_IN(attributes))
1392 {
1393 BEGIN_IPC(setGuestStatus)
1394 connection.process().setGuestStatus(guest, status, DATA(attributes));
1395 END_IPC(CSSM)
1396 }
1397
1398 kern_return_t ucsp_server_removeGuest(UCSP_ARGS, SecGuestRef host, SecGuestRef guest)
1399 {
1400 BEGIN_IPC(removeGuest)
1401 connection.process().removeGuest(host, guest);
1402 END_IPC(CSSM)
1403 }
1404
1405 kern_return_t ucsp_server_helpCheckLoad(UCSP_ARGS, const char path[PATH_MAX], uint32_t type)
1406 {
1407 BEGIN_IPC(helpCheckLoad)
1408 END_IPC(CSSM)
1409 }
1410
1411 //
1412 // Testing-related RPCs
1413 //
1414 kern_return_t ucsp_server_getUserPromptAttempts(UCSP_ARGS, uint32* attempts)
1415 {
1416 BEGIN_IPC(keychainPromptAttempts)
1417
1418 *attempts = KeychainPromptAclSubject::getPromptAttempts() + KeychainDatabase::getInteractiveUnlockAttempts();
1419
1420 END_IPC(DL)
1421 }
1422
1423 #pragma clang diagnostic pop