]> git.saurik.com Git - apple/security.git/blob - securityd/src/transition.cpp
Security-57740.1.18.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 *db = (new TokenDatabase(ssid, connection.process(), name, creds))->handle();
331 END_IPC(DL)
332 }
333
334 kern_return_t ucsp_server_findFirst(UCSP_ARGS, DbHandle db,
335 DATA_IN(inQuery), DATA_IN(inAttributes), DATA_OUT(outAttributes),
336 boolean_t getData, DATA_OUT(data),
337 KeyHandle *hKey, SearchHandle *hSearch, IPCRecordHandle *hRecord)
338 {
339 BEGIN_IPC(findFirst)
340 CopyOutQuery query(inQuery, inQueryLength);
341 CopyOutDbRecordAttributes attrs(inAttributes, inAttributesLength);
342
343 RefPointer<Database::Search> search;
344 RefPointer<Database::Record> record;
345 RefPointer<Key> key;
346 CssmData outData;
347 CssmDbRecordAttributeData *outAttrs = NULL; mach_msg_type_number_t outAttrsLength;
348 Server::database(db)->findFirst(*query,
349 attrs.attribute_data(), attrs.length(),
350 getData ? &outData : NULL, key, search, record, outAttrs, outAttrsLength);
351
352 // handle nothing-found case without exceptions
353 if (!record) {
354 *hRecord = noRecord;
355 *hSearch = noSearch;
356 *hKey = noKey;
357 } else {
358 // return handles
359 *hRecord = record->handle();
360 *hSearch = search->handle();
361 *hKey = key ? key->handle() : noKey;
362
363 if (outAttrsLength && outAttrs) {
364 Server::releaseWhenDone(outAttrs); // exception proof it against next line
365 if (!copyin(outAttrs, reinterpret_cast<xdrproc_t> (xdr_CSSM_DB_RECORD_ATTRIBUTE_DATA), outAttributes, outAttributesLength))
366 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
367 Server::releaseWhenDone(*outAttributes);
368 }
369
370 // return data (temporary fix)
371 if (getData) {
372 Server::releaseWhenDone(outData.data());
373 xdrproc_t encode_proc = reinterpret_cast<xdrproc_t>(xdr_CSSM_NO_KEY_IN_DATA);
374 if (key)
375 encode_proc = reinterpret_cast<xdrproc_t>(xdr_CSSM_KEY_IN_DATA);
376 if (!copyin(&outData, encode_proc, data, dataLength))
377 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
378 Server::releaseWhenDone(*data);
379 }
380 }
381 END_IPC(DL)
382 }
383
384
385 kern_return_t ucsp_server_findNext(UCSP_ARGS, SearchHandle hSearch,
386 DATA_IN(inAttributes),
387 DATA_OUT(outAttributes),
388 boolean_t getData, DATA_OUT(data), KeyHandle *hKey,
389 IPCRecordHandle *hRecord)
390 {
391 BEGIN_IPC(findNext)
392 CopyOutDbRecordAttributes attrs(inAttributes, inAttributesLength);
393 RefPointer<Database::Search> search =
394 Server::find<Database::Search>(hSearch, CSSMERR_DL_INVALID_RESULTS_HANDLE);
395 RefPointer<Database::Record> record;
396 RefPointer<Key> key;
397 CssmData outData;
398 CssmDbRecordAttributeData *outAttrs = NULL; mach_msg_type_number_t outAttrsLength;
399 search->database().findNext(search, attrs.attribute_data(), attrs.length(),
400 getData ? &outData : NULL, key, record, outAttrs, outAttrsLength);
401
402 // handle nothing-found case without exceptions
403 if (!record) {
404 *hRecord = noRecord;
405 *hKey = noKey;
406 } else {
407 // return handles
408 *hRecord = record->handle();
409 *hKey = key ? key->handle() : noKey;
410
411 if (outAttrsLength && outAttrs) {
412 secinfo("attrmem", "Found attrs: %p of length: %d", outAttrs, outAttrsLength);
413 Server::releaseWhenDone(outAttrs); // exception proof it against next line
414 if (!copyin(outAttrs, reinterpret_cast<xdrproc_t> (xdr_CSSM_DB_RECORD_ATTRIBUTE_DATA), outAttributes, outAttributesLength))
415 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
416 secinfo("attrmem", "Copied attrs: %p of length: %d", *outAttributes, *outAttributesLength);
417 Server::releaseWhenDone(*outAttributes);
418 }
419
420 // return data (temporary fix)
421 if (getData) {
422 Server::releaseWhenDone(outData.data());
423 xdrproc_t encode_proc = reinterpret_cast<xdrproc_t>(xdr_CSSM_NO_KEY_IN_DATA);
424 if (key)
425 encode_proc = reinterpret_cast<xdrproc_t>(xdr_CSSM_KEY_IN_DATA);
426 if (!copyin(&outData, encode_proc, data, dataLength))
427 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
428 Server::releaseWhenDone(*data);
429 }
430 }
431 END_IPC(DL)
432 }
433
434 kern_return_t ucsp_server_findRecordHandle(UCSP_ARGS, IPCRecordHandle hRecord,
435 DATA_IN(inAttributes), DATA_OUT(outAttributes),
436 boolean_t getData, DATA_OUT(data), KeyHandle *hKey)
437 {
438 BEGIN_IPC(findRecordHandle)
439 CopyOutDbRecordAttributes attrs(inAttributes, inAttributesLength);
440 RefPointer<Database::Record> record =
441 Server::find<Database::Record>(hRecord, CSSMERR_DL_INVALID_RECORD_UID);
442 RefPointer<Key> key;
443 CssmData outData;
444 CssmDbRecordAttributeData *outAttrs; mach_msg_type_number_t outAttrsLength;
445 record->database().findRecordHandle(record, attrs.attribute_data(), attrs.length(),
446 getData ? &outData : NULL, key, outAttrs, outAttrsLength);
447
448 // return handles
449 *hKey = key ? key->handle() : noKey;
450
451 if (outAttrsLength && outAttrs) {
452 Server::releaseWhenDone(outAttrs); // exception proof it against next line
453 if (!copyin(outAttrs, reinterpret_cast<xdrproc_t> (xdr_CSSM_DB_RECORD_ATTRIBUTE_DATA), outAttributes, outAttributesLength))
454 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
455 Server::releaseWhenDone(*outAttributes);
456 }
457
458 // return data (temporary fix)
459 if (getData) {
460 /*
461 We can't release this with the usual allocator (which calls free(), since
462 it was VM allocated. Part of the fix for:
463 <rdar://problem/6738709> securityd leaks VM memory during certain smartcard operations
464 will be to call Server::releaseWhenDone below with a new vm allocator param
465 */
466 Server::releaseWhenDone(outData.data());
467 xdrproc_t encode_proc = reinterpret_cast<xdrproc_t>(xdr_CSSM_NO_KEY_IN_DATA);
468 if (key)
469 encode_proc = reinterpret_cast<xdrproc_t>(xdr_CSSM_KEY_IN_DATA);
470 if (!copyin(&outData, encode_proc, data, dataLength))
471 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
472 Server::releaseWhenDone(*data);
473 }
474 END_IPC(DL)
475 }
476
477 kern_return_t ucsp_server_insertRecord(UCSP_ARGS, DbHandle db, CSSM_DB_RECORDTYPE recordType,
478 DATA_IN(inAttributes), DATA_IN(data), IPCRecordHandle *record)
479 {
480 BEGIN_IPC(insertRecord)
481 RecordHandle recordHandle;
482 CopyOutDbRecordAttributes attrs(inAttributes, inAttributesLength);
483 Server::database(db)->insertRecord(recordType, attrs.attribute_data(), attrs.length(),
484 DATA(data), recordHandle);
485 *record = recordHandle;
486 END_IPC(DL)
487 }
488
489 kern_return_t ucsp_server_modifyRecord(UCSP_ARGS, DbHandle db, IPCRecordHandle *hRecord,
490 CSSM_DB_RECORDTYPE recordType, DATA_IN(attributes),
491 boolean_t setData, DATA_IN(data), CSSM_DB_MODIFY_MODE modifyMode)
492 {
493 BEGIN_IPC(modifyRecord)
494 CopyOutDbRecordAttributes attrs(attributes, attributesLength);
495 CssmData newData(DATA(data));
496 RefPointer<Database::Record> record =
497 Server::find<Database::Record>(*hRecord, CSSMERR_DL_INVALID_RECORD_UID);
498 Server::database(db)->modifyRecord(recordType, record, attrs.attribute_data(), attrs.length(),
499 setData ? &newData : NULL, modifyMode);
500 // note that the record handle presented to the client never changes here
501 // (we could, but have no reason to - our record handles are just always up to date)
502 END_IPC(DL)
503 }
504
505 kern_return_t ucsp_server_deleteRecord(UCSP_ARGS, DbHandle db, IPCRecordHandle hRecord)
506 {
507 BEGIN_IPC(deleteRecord)
508 Server::database(db)->deleteRecord(
509 Server::find<Database::Record>(hRecord, CSSMERR_DL_INVALID_RECORD_UID));
510 END_IPC(DL)
511 }
512
513 kern_return_t ucsp_server_releaseSearch(UCSP_ARGS, SearchHandle hSearch)
514 {
515 BEGIN_IPC(releaseSearch)
516 RefPointer<Database::Search> search = Server::find<Database::Search>(hSearch, 0);
517 search->database().releaseSearch(*search);
518 END_IPC(DL)
519 }
520
521 kern_return_t ucsp_server_releaseRecord(UCSP_ARGS, IPCRecordHandle hRecord)
522 {
523 BEGIN_IPC(releaseRecord)
524 RefPointer<Database::Record> record = Server::find<Database::Record>(hRecord, 0);
525 record->database().releaseRecord(*record);
526 END_IPC(DL)
527 }
528
529
530 //
531 // Internal database management
532 //
533 kern_return_t ucsp_server_createDb(UCSP_ARGS, DbHandle *db,
534 DATA_IN(ident), DATA_IN(cred), DATA_IN(owner),
535 DBParameters params)
536 {
537 BEGIN_IPC(createDb)
538 CopyOutAccessCredentials creds(cred, credLength);
539 CopyOutEntryAcl owneracl(owner, ownerLength);
540 CopyOut flatident(ident, identLength, reinterpret_cast<xdrproc_t>(xdr_DLDbFlatIdentifierRef));
541 *db = (new KeychainDatabase(*reinterpret_cast<DLDbFlatIdentifier*>(flatident.data()), params, connection.process(), creds, owneracl))->handle();
542 END_IPC(DL)
543 }
544
545 kern_return_t ucsp_server_cloneDb(UCSP_ARGS, DbHandle srcDb, DATA_IN(ident), DbHandle *newDb) {
546 BEGIN_IPC(cloneDb)
547
548 secnotice("integrity", "cloning a db");
549
550 CopyOut flatident(ident, identLength, reinterpret_cast<xdrproc_t>(xdr_DLDbFlatIdentifierRef));
551
552 RefPointer<KeychainDatabase> srcKC = Server::keychain(srcDb);
553 secnotice("integrity", "cloning db %d", srcKC->handle());
554
555 KeychainDatabase* newKC = new KeychainDatabase(*reinterpret_cast<DLDbFlatIdentifier*>(flatident.data()), *srcKC, connection.process());
556 secnotice("integrity", "returning db %d", newKC->handle());
557 *newDb = newKC->handle();
558
559 END_IPC(DL)
560 }
561
562 kern_return_t ucsp_server_recodeDbForSync(UCSP_ARGS, DbHandle dbToClone,
563 DbHandle srcDb, DbHandle *newDb)
564 {
565 BEGIN_IPC(recodeDbForSync)
566 RefPointer<KeychainDatabase> srcKC = Server::keychain(srcDb);
567 *newDb = (new KeychainDatabase(*srcKC, connection.process(), dbToClone))->handle();
568 END_IPC(DL)
569 }
570
571 kern_return_t ucsp_server_recodeDbToVersion(UCSP_ARGS, uint32 newVersion, DbHandle srcDb, DbHandle *newDb)
572 {
573 BEGIN_IPC(recodeDbToVersion)
574 RefPointer<KeychainDatabase> srcKC = Server::keychain(srcDb);
575
576 // You can only recode an unlocked keychain, so let's make sure.
577 srcKC->unlockDb(false);
578
579 KeychainDatabase* newKC = new KeychainDatabase(newVersion, *srcKC, connection.process());
580 if(newKC->blob()->version() != newVersion) {
581 CssmError::throwMe(CSSM_ERRCODE_INCOMPATIBLE_VERSION);
582 }
583
584 *newDb = newKC->handle();
585
586 END_IPC(DL)
587 }
588
589 kern_return_t ucsp_server_recodeFinished(UCSP_ARGS, DbHandle db)
590 {
591 BEGIN_IPC(recodeDbToVersion)
592 Server::keychain(db)->recodeFinished();
593 END_IPC(DL)
594 }
595
596
597 kern_return_t ucsp_server_authenticateDbsForSync(UCSP_ARGS, DATA_IN(dbHandleArray),
598 DATA_IN(agentData), DbHandle* authenticatedDBHandle)
599 {
600 BEGIN_IPC(authenticateDbsForSync)
601 QueryDBBlobSecret query;
602 query.inferHints(connection.process());
603 query.addHint(AGENT_HINT_KCSYNC_DICT, agentData, agentDataLength);
604 CSSM_DATA dbData = DATA(dbHandleArray);
605 uint8 ipcDbHandleArrayCount = *(dbData.Data);
606 DbHandle *ipcDbHandleArray = (DbHandle *)Allocator::standard().malloc(ipcDbHandleArrayCount * sizeof(DbHandle));
607 if ( ipcDbHandleArray == 0 )
608 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
609 DbHandle *currIPCDbHandleArrayPtr = ipcDbHandleArray;
610 DbHandle *dbHandleArrayPtr = (DbHandle *)(dbData.Data+1);
611 int index;
612 for (index=0; index < ipcDbHandleArrayCount; index++)
613 {
614 *currIPCDbHandleArrayPtr = *dbHandleArrayPtr;
615 Server::keychain(*currIPCDbHandleArrayPtr)->lockDb(); // lock this db if it was unlocked in the past (user could have deleted the kc, resetLogin, etc.)
616 currIPCDbHandleArrayPtr++;
617 dbHandleArrayPtr++;
618 }
619 Server::releaseWhenDone(ipcDbHandleArray);
620 if (query(ipcDbHandleArray, ipcDbHandleArrayCount, authenticatedDBHandle) != SecurityAgent::noReason)
621 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
622 END_IPC(DL)
623 }
624
625 kern_return_t ucsp_server_commitDbForSync(UCSP_ARGS, DbHandle srcDb,
626 DbHandle cloneDb, DATA_OUT(blob))
627 {
628 BEGIN_IPC(commitDbForSync)
629 RefPointer<KeychainDatabase> srcKC = Server::keychain(srcDb);
630 RefPointer<KeychainDatabase> cloneKC = Server::keychain(cloneDb);
631 srcKC->commitSecretsForSync(*cloneKC);
632
633 // re-encode blob for convenience
634 if (blob && blobLength) {
635 DbBlob *dbBlob = srcKC->blob();
636 *blob = dbBlob;
637 *blobLength = dbBlob->length();
638 } else {
639 secinfo("kcrecode", "No blob can be returned to client");
640 }
641 END_IPC(DL)
642 }
643
644 kern_return_t ucsp_server_decodeDb(UCSP_ARGS, DbHandle *db,
645 DATA_IN(ident), DATA_IN(cred), DATA_IN(blob))
646 {
647 BEGIN_IPC(decodeDb)
648 CopyOutAccessCredentials creds(cred, credLength);
649 CopyOut flatident(ident, identLength, reinterpret_cast<xdrproc_t>(xdr_DLDbFlatIdentifierRef));
650 DLDbFlatIdentifier* flatID = (DLDbFlatIdentifier*) flatident.data();
651 DLDbIdentifier id = *flatID; // invokes a casting operator
652
653 *db = (new KeychainDatabase(id, SSBLOB(DbBlob, blob),
654 connection.process(), creds))->handle();
655 END_IPC(DL)
656 }
657
658 kern_return_t ucsp_server_encodeDb(UCSP_ARGS, DbHandle db, DATA_OUT(blob))
659 {
660 BEGIN_IPC(encodeDb)
661 DbBlob *dbBlob = Server::keychain(db)->blob(); // memory owned by database
662 *blob = dbBlob;
663 *blobLength = dbBlob->length();
664 END_IPC(DL)
665 }
666
667 kern_return_t ucsp_server_setDbParameters(UCSP_ARGS, DbHandle db, DBParameters params)
668 {
669 BEGIN_IPC(setDbParameters)
670 Server::keychain(db)->setParameters(params);
671 END_IPC(DL)
672 }
673
674 kern_return_t ucsp_server_getDbParameters(UCSP_ARGS, DbHandle db, DBParameters *params)
675 {
676 BEGIN_IPC(getDbParameters)
677 Server::keychain(db)->getParameters(*params);
678 END_IPC(DL)
679 }
680
681 kern_return_t ucsp_server_changePassphrase(UCSP_ARGS, DbHandle db,
682 DATA_IN(cred))
683 {
684 BEGIN_IPC(changePassphrase)
685 CopyOutAccessCredentials creds(cred, credLength);
686 Server::keychain(db)->changePassphrase(creds);
687 END_IPC(DL)
688 }
689
690 kern_return_t ucsp_server_lockAll (UCSP_ARGS, boolean_t)
691 {
692 BEGIN_IPC(lockAll)
693 connection.session().processLockAll();
694 END_IPC(DL)
695 }
696
697 kern_return_t ucsp_server_unlockDb(UCSP_ARGS, DbHandle db)
698 {
699 BEGIN_IPC(unlockDb)
700 Server::keychain(db)->unlockDb(true);
701 END_IPC(DL)
702 }
703
704 static void check_stash_entitlement(Process & proc)
705 {
706 OSStatus status = noErr;
707 CFDictionaryRef code_info = NULL;
708 CFDictionaryRef entitlements = NULL;
709 CFTypeRef value = NULL;
710 bool entitled = false;
711
712 status = proc.copySigningInfo(kSecCSRequirementInformation, &code_info);
713 require_noerr(status, done);
714
715 if (CFDictionaryGetValueIfPresent(code_info, kSecCodeInfoEntitlementsDict, &value)) {
716 if (CFGetTypeID(value) == CFDictionaryGetTypeID()) {
717 entitlements = (CFDictionaryRef)value;
718 }
719 }
720 require(entitlements != NULL, done);
721
722 if (CFDictionaryGetValueIfPresent(entitlements, CFSTR("com.apple.private.securityd.stash"), &value)) {
723 if (CFGetTypeID(value) && CFBooleanGetTypeID()) {
724 entitled = CFBooleanGetValue((CFBooleanRef)value);
725 }
726 }
727
728 done:
729 if (code_info) {
730 CFRelease(code_info);
731 }
732
733 if (!entitled) {
734 CssmError::throwMe(CSSM_ERRCODE_OS_ACCESS_DENIED);
735 }
736 }
737
738 kern_return_t ucsp_server_unlockDbWithPassphrase(UCSP_ARGS, DbHandle db, DATA_IN(passphrase))
739 {
740 BEGIN_IPC(unlockDbWithPassphrase)
741 Server::keychain(db)->unlockDb(DATA(passphrase), true);
742 END_IPC(DL)
743 }
744
745 kern_return_t ucsp_server_stashDb(UCSP_ARGS, DbHandle db)
746 {
747 BEGIN_IPC(stashDb)
748 check_stash_entitlement(connection.process());
749 Server::keychain(db)->stashDb();
750 END_IPC(DL)
751 }
752
753 kern_return_t ucsp_server_stashDbCheck(UCSP_ARGS, DbHandle db)
754 {
755 BEGIN_IPC(stashDbCheck)
756 check_stash_entitlement(connection.process());
757 Server::keychain(db)->stashDbCheck();
758 END_IPC(DL)
759 }
760
761 kern_return_t ucsp_server_isLocked(UCSP_ARGS, DbHandle db, boolean_t *locked)
762 {
763 BEGIN_IPC(isLocked)
764 *locked = Server::database(db)->isLocked();
765 END_IPC(DL)
766 }
767
768 kern_return_t ucsp_server_verifyKeyStorePassphrase(UCSP_ARGS, uint32_t retries)
769 {
770 BEGIN_IPC(verifyKeyStorePassphrase)
771 connection.process().session().verifyKeyStorePassphrase(retries);
772 END_IPC(DL)
773 }
774
775 kern_return_t ucsp_server_changeKeyStorePassphrase(UCSP_ARGS)
776 {
777 BEGIN_IPC(verifyKeyStorePassphrase)
778 connection.process().session().changeKeyStorePassphrase();
779 END_IPC(DL)
780 }
781
782 kern_return_t ucsp_server_resetKeyStorePassphrase(UCSP_ARGS, DATA_IN(passphrase))
783 {
784 BEGIN_IPC(verifyKeyStorePassphrase)
785 connection.process().session().resetKeyStorePassphrase(DATA(passphrase));
786 END_IPC(DL)
787 }
788
789 //
790 // Key management
791 //
792 kern_return_t ucsp_server_encodeKey(UCSP_ARGS, KeyHandle keyh, DATA_OUT(blob),
793 boolean_t wantUid, DATA_OUT(uid))
794 {
795 BEGIN_IPC(encodeKey)
796 RefPointer<Key> gKey = Server::key(keyh);
797 if (KeychainKey *key = dynamic_cast<KeychainKey *>(gKey.get())) {
798 KeyBlob *keyBlob = key->blob(); // still owned by key
799 *blob = keyBlob;
800 *blobLength = keyBlob->length();
801 if (wantUid) { // uid generation is not implemented
802 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
803 } else {
804 *uidLength = 0; // do not return this
805 }
806 } else { // not a KeychainKey
807 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
808 }
809 END_IPC(CSP)
810 }
811
812 kern_return_t ucsp_server_decodeKey(UCSP_ARGS, KeyHandle *keyh, DATA_OUT(keyHeader),
813 DbHandle db, DATA_IN(blob))
814 {
815 BEGIN_IPC(decodeKey)
816 RefPointer<Key> key = new KeychainKey(*Server::keychain(db), SSBLOB(KeyBlob, blob));
817 CssmKey::Header header;
818 key->returnKey(*keyh, header);
819 if (!copyin(&header, reinterpret_cast<xdrproc_t> (xdr_CSSM_KEYHEADER), keyHeader, keyHeaderLength))
820 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
821 Server::releaseWhenDone(*keyHeader);
822 END_IPC(CSP)
823 }
824
825 // keychain synchronization
826 kern_return_t ucsp_server_recodeKey(UCSP_ARGS, DbHandle oldDb, KeyHandle keyh,
827 DbHandle newDb, DATA_OUT(newBlob))
828 {
829 BEGIN_IPC(recodeKey)
830 // If the old key is passed in as DATA_IN(oldBlob):
831 // RefPointer<KeychainKey> key = new KeychainKey(*Server::keychain(oldDb), SSBLOB(KeyBlob, oldBlob));
832 RefPointer<Key> key = Server::key(keyh);
833 if (KeychainKey *kckey = dynamic_cast<KeychainKey *>(key.get())) {
834 KeyBlob *blob = Server::keychain(newDb)->recodeKey(*kckey);
835 *newBlob = blob;
836 *newBlobLength = blob->length();
837 Server::releaseWhenDone(*newBlob);
838 // @@@ stop leaking blob
839 } else { // not a KeychainKey
840 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
841 }
842 END_IPC(CSP)
843 }
844
845 kern_return_t ucsp_server_releaseKey(UCSP_ARGS, KeyHandle keyh)
846 {
847 BEGIN_IPC(releaseKey)
848 RefPointer<Key> key = Server::key(keyh);
849 key->database().releaseKey(*key);
850 END_IPC(CSP)
851 }
852
853 kern_return_t ucsp_server_queryKeySizeInBits(UCSP_ARGS, KeyHandle keyh, CSSM_KEY_SIZE *length)
854 {
855 BEGIN_IPC(queryKeySizeInBits)
856 RefPointer<Key> key = Server::key(keyh);
857 key->database().queryKeySizeInBits(*key, CssmKeySize::overlay(*length));
858 END_IPC(CSP)
859 }
860
861 kern_return_t ucsp_server_getOutputSize(UCSP_ARGS, DATA_IN(context), KeyHandle keyh,
862 uint32 inputSize, boolean_t encrypt, uint32 *outputSize)
863 {
864 BEGIN_IPC(getOutputSize)
865 CopyOutContext ctx(context, contextLength);
866 RefPointer<Key> key = Server::key(keyh);
867 key->database().getOutputSize(*ctx, *key, inputSize, encrypt, *outputSize);
868 END_IPC(CSP)
869 }
870
871 kern_return_t ucsp_server_getKeyDigest(UCSP_ARGS, KeyHandle key, DATA_OUT(digest))
872 {
873 BEGIN_IPC(getKeyDigest)
874 CssmData digestData = Server::key(key)->canonicalDigest();
875 *digest = digestData.data();
876 *digestLength = int_cast<size_t, mach_msg_type_number_t>(digestData.length());
877 END_IPC(CSP)
878 }
879
880
881 //
882 // Signatures and MACs
883 //
884 kern_return_t ucsp_server_generateSignature(UCSP_ARGS, DATA_IN(context), KeyHandle keyh,
885 CSSM_ALGORITHMS signOnlyAlgorithm, DATA_IN(data), DATA_OUT(signature))
886 {
887 BEGIN_IPC(generateSignature)
888 CopyOutContext ctx(context, contextLength);
889 RefPointer<Key> key = Server::key(keyh);
890 OutputData sigData(signature, signatureLength);
891 key->database().generateSignature(*ctx, *key, signOnlyAlgorithm,
892 DATA(data), sigData);
893 END_IPC(CSP)
894 }
895
896 kern_return_t ucsp_server_verifySignature(UCSP_ARGS, DATA_IN(context), KeyHandle keyh,
897 CSSM_ALGORITHMS verifyOnlyAlgorithm, DATA_IN(data), DATA_IN(signature))
898 {
899 BEGIN_IPC(verifySignature)
900 CopyOutContext ctx(context, contextLength);
901 RefPointer<Key> key = Server::key(keyh);
902 key->database().verifySignature(*ctx, *key, verifyOnlyAlgorithm,
903 DATA(data), DATA(signature));
904 END_IPC(CSP)
905 }
906
907 kern_return_t ucsp_server_generateMac(UCSP_ARGS, DATA_IN(context), KeyHandle keyh,
908 DATA_IN(data), DATA_OUT(mac))
909 {
910 BEGIN_IPC(generateMac)
911 CopyOutContext ctx(context, contextLength);
912 RefPointer<Key> key = Server::key(keyh);
913 OutputData macData(mac, macLength);
914 key->database().generateMac(*ctx, *key, DATA(data), macData);
915 END_IPC(CSP)
916 }
917
918 kern_return_t ucsp_server_verifyMac(UCSP_ARGS, DATA_IN(context), KeyHandle keyh,
919 DATA_IN(data), DATA_IN(mac))
920 {
921 BEGIN_IPC(verifyMac)
922 CopyOutContext ctx(context, contextLength);
923 RefPointer<Key> key = Server::key(keyh);
924 key->database().verifyMac(*ctx, *key, DATA(data), DATA(mac));
925 END_IPC(CSP)
926 }
927
928
929 //
930 // Encryption/Decryption
931 //
932 kern_return_t ucsp_server_encrypt(UCSP_ARGS, DATA_IN(context), KeyHandle keyh,
933 DATA_IN(clear), DATA_OUT(cipher))
934 {
935 BEGIN_IPC(encrypt)
936 CopyOutContext ctx(context, contextLength);
937 RefPointer<Key> key = Server::key(keyh);
938 OutputData cipherOut(cipher, cipherLength);
939 key->database().encrypt(*ctx, *key, DATA(clear), cipherOut);
940 END_IPC(CSP)
941 }
942
943 kern_return_t ucsp_server_decrypt(UCSP_ARGS, DATA_IN(context), KeyHandle keyh,
944 DATA_IN(cipher), DATA_OUT(clear))
945 {
946 BEGIN_IPC(decrypt)
947 CopyOutContext ctx(context, contextLength);
948 RefPointer<Key> key = Server::key(keyh);
949 OutputData clearOut(clear, clearLength);
950 key->database().decrypt(*ctx, *key, DATA(cipher), clearOut);
951 END_IPC(CSP)
952 }
953
954
955 //
956 // Key generation
957 //
958 kern_return_t ucsp_server_generateKey(UCSP_ARGS, DbHandle db, DATA_IN(context),
959 DATA_IN(cred), DATA_IN(owner),
960 uint32 usage, uint32 attrs, KeyHandle *newKey, DATA_OUT(keyHeader))
961 {
962 BEGIN_IPC(generateKey)
963 CopyOutContext ctx(context, contextLength);
964 CopyOutAccessCredentials creds(cred, credLength);
965
966 CopyOutEntryAcl owneracl(owner, ownerLength);
967 //@@@ preliminary interpretation - will get "type handle"
968 RefPointer<Database> database =
969 Server::optionalDatabase(db, attrs & CSSM_KEYATTR_PERMANENT);
970 RefPointer<Key> key;
971 database->generateKey(*ctx, creds, owneracl, usage, attrs, key);
972 CssmKey::Header newHeader;
973 key->returnKey(*newKey, newHeader);
974
975 if (!copyin(&newHeader, reinterpret_cast<xdrproc_t> (xdr_CSSM_KEYHEADER), keyHeader, keyHeaderLength))
976 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
977 Server::releaseWhenDone(*keyHeader);
978 END_IPC(CSP)
979 }
980
981 kern_return_t ucsp_server_generateKeyPair(UCSP_ARGS, DbHandle db, DATA_IN(context),
982 DATA_IN(cred), DATA_IN(owner),
983 uint32 pubUsage, uint32 pubAttrs, uint32 privUsage, uint32 privAttrs,
984 KeyHandle *pubKey, DATA_OUT(pubHeader), KeyHandle *privKey, DATA_OUT(privHeader))
985 {
986 BEGIN_IPC(generateKeyPair)
987 CopyOutContext ctx(context, contextLength);
988 CopyOutAccessCredentials creds(cred, credLength);
989 CopyOutEntryAcl owneracl(owner, ownerLength);
990 RefPointer<Database> database =
991 Server::optionalDatabase(db, (privAttrs | pubAttrs) & CSSM_KEYATTR_PERMANENT);
992 RefPointer<Key> pub, priv;
993 database->generateKey(*ctx, creds, owneracl,
994 pubUsage, pubAttrs, privUsage, privAttrs, pub, priv);
995 CssmKey::Header tmpPubHeader, tmpPrivHeader;
996
997 pub->returnKey(*pubKey, tmpPubHeader);
998 if (!copyin(&tmpPubHeader, reinterpret_cast<xdrproc_t> (xdr_CSSM_KEYHEADER), pubHeader, pubHeaderLength))
999 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
1000 Server::releaseWhenDone(*pubHeader);
1001
1002 priv->returnKey(*privKey, tmpPrivHeader);
1003 if (!copyin(&tmpPrivHeader, reinterpret_cast<xdrproc_t> (xdr_CSSM_KEYHEADER), privHeader, privHeaderLength))
1004 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
1005 Server::releaseWhenDone(*privHeader);
1006
1007 END_IPC(CSP)
1008 }
1009
1010
1011 //
1012 // Key wrapping and unwrapping
1013 //
1014 kern_return_t ucsp_server_wrapKey(UCSP_ARGS, DATA_IN(context), KeyHandle hWrappingKey,
1015 DATA_IN(cred), KeyHandle hKeyToBeWrapped,
1016 DATA_IN(descriptiveData), DATA_OUT(wrappedKeyData))
1017 {
1018 BEGIN_IPC(wrapKey)
1019 CssmKey wrappedKey;
1020 CopyOutContext ctx(context, contextLength);
1021 CopyOutAccessCredentials creds(cred, credLength);
1022 RefPointer<Key> subjectKey = Server::key(hKeyToBeWrapped);
1023 RefPointer<Key> wrappingKey = Server::optionalKey(hWrappingKey);
1024 if ((ctx.context().algorithm() == CSSM_ALGID_NONE && subjectKey->attribute(CSSM_KEYATTR_SENSITIVE))
1025 || !subjectKey->attribute(CSSM_KEYATTR_EXTRACTABLE))
1026 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
1027 pickDb(subjectKey, wrappingKey)->wrapKey(*ctx, creds, wrappingKey, *subjectKey, DATA(descriptiveData), wrappedKey);
1028 Server::releaseWhenDone(wrappedKey.keyData().data());
1029
1030 if (!copyin(&wrappedKey, reinterpret_cast<xdrproc_t> (xdr_CSSM_KEY), wrappedKeyData, wrappedKeyDataLength))
1031 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
1032
1033 Server::releaseWhenDone(*wrappedKeyData);
1034 END_IPC(CSP)
1035 }
1036
1037 kern_return_t ucsp_server_unwrapKey(UCSP_ARGS, DbHandle db, DATA_IN(context),
1038 KeyHandle hWrappingKey, DATA_IN(cred), DATA_IN(owner),
1039 KeyHandle hPublicKey, DATA_IN(wrappedKeyData),
1040 CSSM_KEYUSE usage, CSSM_KEYATTR_FLAGS attrs, DATA_OUT(descriptiveData),
1041 KeyHandle *newKey, DATA_OUT(keyHeader)/*CssmKey::Header *newHeader*/)
1042 {
1043 BEGIN_IPC(unwrapKey)
1044 CopyOutContext ctx(context, contextLength);
1045 CopyOutKey wrappedKey(wrappedKeyData, wrappedKeyDataLength);
1046 CopyOutAccessCredentials creds(cred, credLength);
1047 CopyOutEntryAcl owneracl(owner, ownerLength);
1048 OutputData descriptiveDatas(descriptiveData, descriptiveDataLength);
1049 RefPointer<Key> wrappingKey = Server::optionalKey(hWrappingKey);
1050 RefPointer<Key> unwrappedKey;
1051 pickDb(Server::optionalDatabase(db), wrappingKey)->unwrapKey(*ctx, creds, owneracl,
1052 wrappingKey, Server::optionalKey(hPublicKey),
1053 usage, attrs, wrappedKey.key(), unwrappedKey, descriptiveDatas);
1054
1055 CssmKey::Header newHeader;
1056 unwrappedKey->returnKey(*newKey, newHeader);
1057 if (!copyin(&newHeader, reinterpret_cast<xdrproc_t> (xdr_CSSM_KEYHEADER), keyHeader, keyHeaderLength))
1058 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
1059 Server::releaseWhenDone(*keyHeader);
1060
1061 END_IPC(CSP)
1062 }
1063
1064
1065 //
1066 // Key derivation.
1067 //
1068 // Note that the "param" argument can have structure. The walker for the
1069 // (artificial) POD CssmDeriveData handles those that are known; if you add
1070 // an algorithm with structured param, you need to add a case there.
1071 //
1072 kern_return_t ucsp_server_deriveKey(UCSP_ARGS, DbHandle db, DATA_IN(context), KeyHandle hKey,
1073 DATA_IN(cred), DATA_IN(owner),
1074 DATA_IN(paramInput), DATA_OUT(paramOutput),
1075 uint32 usage, uint32 attrs, KeyHandle *newKey, DATA_OUT(keyHeader))
1076 {
1077 BEGIN_IPC(deriveKey)
1078 CopyOutContext ctx(context, contextLength);
1079 CopyOutAccessCredentials creds(cred, credLength);
1080 CopyOutEntryAcl owneracl(owner, ownerLength);
1081 CopyOutDeriveData deriveParam(paramInput, paramInputLength);
1082 if (deriveParam.algorithm() != ctx.context().algorithm())
1083 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR); // client layer fault
1084
1085 RefPointer<Database> database =
1086 Server::optionalDatabase(db, attrs & CSSM_KEYATTR_PERMANENT);
1087 RefPointer<Key> key = Server::optionalKey(hKey);
1088 CSSM_DATA param = deriveParam.cssm_data();
1089 RefPointer<Key> derivedKey;
1090 pickDb(Server::optionalDatabase(db, attrs & CSSM_KEYATTR_PERMANENT),
1091 key)->deriveKey(*ctx, key, creds, owneracl, static_cast<CssmData*>(&param), usage, attrs, derivedKey);
1092
1093 CssmKey::Header newHeader;
1094 derivedKey->returnKey(*newKey, newHeader);
1095
1096 if (!copyin(&newHeader, reinterpret_cast<xdrproc_t> (xdr_CSSM_KEYHEADER), keyHeader, keyHeaderLength))
1097 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
1098 Server::releaseWhenDone(*keyHeader);
1099
1100 if (param.Length) {
1101 if (!param.Data) // CSP screwed up
1102 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
1103 OutputData(paramOutput, paramOutputLength) = CssmAutoData(Server::csp().allocator(), param).release();
1104 }
1105 END_IPC(CSP)
1106 }
1107
1108
1109 //
1110 // Random generation
1111 //
1112 kern_return_t ucsp_server_generateRandom(UCSP_ARGS, uint32 ssid, DATA_IN(context), DATA_OUT(data))
1113 {
1114 BEGIN_IPC(generateRandom)
1115 CopyOutContext ctx(context, contextLength);
1116 if (ssid)
1117 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
1118
1119 // default version (use /dev/random)
1120 Allocator &allocator = Allocator::standard(Allocator::sensitive);
1121 if (size_t bytes = ctx.context().getInt(CSSM_ATTRIBUTE_OUTPUT_SIZE)) {
1122 void *buffer = allocator.malloc(bytes);
1123 Server::active().random(buffer, bytes);
1124 *data = buffer;
1125 *dataLength = int_cast<size_t, mach_msg_type_number_t>(bytes);
1126 Server::releaseWhenDone(allocator, buffer);
1127 }
1128 END_IPC(CSP)
1129 }
1130
1131
1132 //
1133 // ACL management.
1134 // Watch out for the memory-management tap-dance.
1135 //
1136 kern_return_t ucsp_server_getOwner(UCSP_ARGS, AclKind kind, KeyHandle key,
1137 DATA_OUT(ownerOut))
1138 {
1139 BEGIN_IPC(getOwner)
1140 AclOwnerPrototype owner;
1141 Server::aclBearer(kind, key).getOwner(owner); // allocates memory in owner
1142 void *owners_data; u_int owners_length;
1143 if (!::copyin(&owner, reinterpret_cast<xdrproc_t>(xdr_CSSM_ACL_OWNER_PROTOTYPE), &owners_data, &owners_length))
1144 CssmError::throwMe(CSSM_ERRCODE_MEMORY_ERROR);
1145
1146 { ChunkFreeWalker free; walk(free, owner); } // release chunked original
1147 Server::releaseWhenDone(owners_data); // throw flat copy out when done
1148 *ownerOut = owners_data;
1149 *ownerOutLength = owners_length;
1150 END_IPC(CSP)
1151 }
1152
1153 kern_return_t ucsp_server_setOwner(UCSP_ARGS, AclKind kind, KeyHandle key,
1154 DATA_IN(cred), DATA_IN(owner))
1155 {
1156 BEGIN_IPC(setOwner)
1157 CopyOutAccessCredentials creds(cred, credLength);
1158 CopyOutOwnerAcl owneracl(owner, ownerLength);
1159 Server::aclBearer(kind, key).changeOwner(*owneracl, creds);
1160 END_IPC(CSP)
1161 }
1162
1163 kern_return_t ucsp_server_getAcl(UCSP_ARGS, AclKind kind, KeyHandle key,
1164 boolean_t haveTag, const char *tag,
1165 uint32 *countp, DATA_OUT(acls))
1166 {
1167 BEGIN_IPC(getAcl)
1168 uint32 count;
1169 AclEntryInfo *aclList;
1170
1171 AclSource& aclRef = Server::aclBearer(kind, key);
1172 secinfo("SecAccess", "getting the ACL for handle %d [%d] (%p)", key, (uint32_t) kind, &aclRef);
1173 aclRef.getAcl(haveTag ? tag : NULL, count, aclList);
1174
1175 CSSM_ACL_ENTRY_INFO_ARRAY aclsArray = { count, aclList };
1176 void *acls_data; u_int acls_length;
1177 if (!::copyin(&aclsArray, reinterpret_cast<xdrproc_t>(xdr_CSSM_ACL_ENTRY_INFO_ARRAY), &acls_data, &acls_length))
1178 CssmError::throwMe(CSSM_ERRCODE_MEMORY_ERROR);
1179
1180 { // release the chunked memory originals
1181 ChunkFreeWalker free;
1182 for (uint32 n = 0; n < count; n++)
1183 walk(free, aclList[n]);
1184
1185 // release the memory allocated for the list itself when we are done
1186 Allocator::standard().free (aclList);
1187 }
1188
1189
1190 *countp = count; // XXX/cs count becomes part of the blob
1191 *aclsLength = acls_length;
1192 *acls = acls_data;
1193 Server::releaseWhenDone(acls_data);
1194 END_IPC(CSP)
1195 }
1196
1197 kern_return_t ucsp_server_changeAcl(UCSP_ARGS, AclKind kind, KeyHandle key,
1198 DATA_IN(cred), CSSM_ACL_EDIT_MODE mode, GenericHandle handle,
1199 DATA_IN(acl))
1200 {
1201 BEGIN_IPC(changeAcl)
1202 CopyOutAccessCredentials creds(cred, credLength);
1203 CopyOutAclEntryInput entryacl(acl, aclLength);
1204
1205 AclSource& aclRef = Server::aclBearer(kind, key);
1206 secinfo("SecAccess", "changing the ACL for handle %d [%d] (%p)", key, (uint32_t) kind, &aclRef);
1207 aclRef.changeAcl(AclEdit(mode, handle, entryacl), creds);
1208
1209 END_IPC(CSP)
1210 }
1211
1212
1213 //
1214 // Login/Logout
1215 //
1216 kern_return_t ucsp_server_login(UCSP_ARGS, DATA_IN(cred), DATA_IN(name))
1217 {
1218 BEGIN_IPC(login)
1219 CopyOutAccessCredentials creds(cred, credLength);
1220 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
1221 END_IPC(CSP)
1222 }
1223
1224 kern_return_t ucsp_server_logout(UCSP_ARGS)
1225 {
1226 BEGIN_IPC(logout)
1227 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
1228 END_IPC(CSP)
1229 }
1230
1231
1232 //
1233 // Miscellaneous CSP-related calls
1234 //
1235 kern_return_t ucsp_server_getStatistics(UCSP_ARGS, uint32 ssid, CSSM_CSP_OPERATIONAL_STATISTICS *statistics)
1236 {
1237 BEGIN_IPC(getStatistics)
1238 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
1239 END_IPC(CSP)
1240 }
1241
1242 kern_return_t ucsp_server_getTime(UCSP_ARGS, uint32 ssid, CSSM_ALGORITHMS algorithm, DATA_OUT(data))
1243 {
1244 BEGIN_IPC(getTime)
1245 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
1246 END_IPC(CSP)
1247 }
1248
1249 kern_return_t ucsp_server_getCounter(UCSP_ARGS, uint32 ssid, DATA_OUT(data))
1250 {
1251 BEGIN_IPC(getCounter)
1252 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
1253 END_IPC(CSP)
1254 }
1255
1256 kern_return_t ucsp_server_selfVerify(UCSP_ARGS, uint32 ssid)
1257 {
1258 BEGIN_IPC(selfVerify)
1259 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
1260 END_IPC(CSP)
1261 }
1262
1263
1264 //
1265 // Passthrough calls (separate for CSP and DL passthroughs)
1266 //
1267 kern_return_t ucsp_server_cspPassThrough(UCSP_ARGS, uint32 ssid, uint32 id, DATA_IN(context),
1268 KeyHandle hKey, DATA_IN(inData), DATA_OUT(outData))
1269 {
1270 BEGIN_IPC(cspPassThrough)
1271 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
1272 END_IPC(CSP)
1273 }
1274
1275 kern_return_t ucsp_server_dlPassThrough(UCSP_ARGS, uint32 ssid, uint32 id,
1276 DATA_IN(inData), DATA_OUT(outData))
1277 {
1278 BEGIN_IPC(dlPassThrough)
1279 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
1280 END_IPC(DL)
1281 }
1282
1283
1284 //
1285 // Database key management.
1286 // ExtractMasterKey looks vaguely like a key derivation operation, and is in fact
1287 // presented by the CSPDL's CSSM layer as such.
1288 //
1289 kern_return_t ucsp_server_extractMasterKey(UCSP_ARGS, DbHandle db, DATA_IN(context), DbHandle sourceDb,
1290 DATA_IN(cred), DATA_IN(owner),
1291 uint32 usage, uint32 attrs, KeyHandle *newKey, DATA_OUT(keyHeader))
1292 {
1293 BEGIN_IPC(extractMasterKey)
1294 CopyOutAccessCredentials creds(cred, credLength);
1295 CopyOutEntryAcl owneracl(owner, ownerLength);
1296 CopyOutContext ctx(context, contextLength);
1297 RefPointer<KeychainDatabase> keychain = Server::keychain(sourceDb);
1298 RefPointer<Key> masterKey = keychain->extractMasterKey(
1299 *Server::optionalDatabase(db, attrs & CSSM_KEYATTR_PERMANENT),
1300 creds, owneracl, usage, attrs);
1301 CssmKey::Header header;
1302 masterKey->returnKey(*newKey, header);
1303 if (!copyin(&header, reinterpret_cast<xdrproc_t> (xdr_CSSM_KEYHEADER), keyHeader, keyHeaderLength))
1304 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
1305 Server::releaseWhenDone(*keyHeader);
1306 END_IPC(CSP)
1307 }
1308
1309
1310 //
1311 // Notification core subsystem
1312 //
1313
1314 kern_return_t ucsp_server_postNotification(UCSP_ARGS, uint32 domain, uint32 event,
1315 DATA_IN(data), uint32 sequence)
1316 {
1317 BEGIN_IPC(postNotification)
1318 Listener::notify(domain, event, sequence, DATA(data));
1319 END_IPC(CSSM)
1320 }
1321
1322
1323 //
1324 // Child check-in service.
1325 // Note that this isn't using the standard argument pattern.
1326 //
1327 kern_return_t ucsp_server_childCheckIn(mach_port_t serverPort,
1328 mach_port_t servicePort, mach_port_t taskPort)
1329 {
1330 BEGIN_IPCS
1331 ServerChild::checkIn(servicePort, TaskPort(taskPort).pid());
1332 END_IPCS(mach_port_deallocate(mach_task_self(), taskPort))
1333 }
1334
1335
1336 //
1337 // Code Signing Hosting registration.
1338 // Note that the Code Signing Proxy facility (implementing the "cshosting"
1339 // IPC protocol) is elsewhere.
1340 //
1341 kern_return_t ucsp_server_registerHosting(UCSP_ARGS, mach_port_t hostingPort, uint32 flags)
1342 {
1343 BEGIN_IPC(registerHosting)
1344 connection.process().registerCodeSigning(hostingPort, flags);
1345 END_IPC(CSSM)
1346 }
1347
1348 kern_return_t ucsp_server_hostingPort(UCSP_ARGS, pid_t hostPid, mach_port_t *hostingPort)
1349 {
1350 BEGIN_IPC(hostingPort)
1351 if (RefPointer<Process> process = Server::active().findPid(hostPid))
1352 *hostingPort = process->hostingPort();
1353 else
1354 *hostingPort = MACH_PORT_NULL;
1355 secinfo("hosting", "hosting port for for pid=%d is port %d", hostPid, *hostingPort);
1356 END_IPC(CSSM)
1357 }
1358
1359
1360 kern_return_t ucsp_server_setGuest(UCSP_ARGS, SecGuestRef guest, SecCSFlags flags)
1361 {
1362 BEGIN_IPC(setGuest)
1363 connection.guestRef(guest, flags);
1364 END_IPC(CSSM)
1365 }
1366
1367
1368 kern_return_t ucsp_server_createGuest(UCSP_ARGS, SecGuestRef host,
1369 uint32_t status, const char *path, DATA_IN(cdhash), DATA_IN(attributes),
1370 SecCSFlags flags, SecGuestRef *newGuest)
1371 {
1372 BEGIN_IPC(createGuest)
1373 *newGuest = connection.process().createGuest(host, status, path, DATA(cdhash), DATA(attributes), flags);
1374 END_IPC(CSSM)
1375 }
1376
1377 kern_return_t ucsp_server_setGuestStatus(UCSP_ARGS, SecGuestRef guest,
1378 uint32_t status, DATA_IN(attributes))
1379 {
1380 BEGIN_IPC(setGuestStatus)
1381 connection.process().setGuestStatus(guest, status, DATA(attributes));
1382 END_IPC(CSSM)
1383 }
1384
1385 kern_return_t ucsp_server_removeGuest(UCSP_ARGS, SecGuestRef host, SecGuestRef guest)
1386 {
1387 BEGIN_IPC(removeGuest)
1388 connection.process().removeGuest(host, guest);
1389 END_IPC(CSSM)
1390 }
1391
1392 kern_return_t ucsp_server_helpCheckLoad(UCSP_ARGS, const char path[PATH_MAX], uint32_t type)
1393 {
1394 BEGIN_IPC(helpCheckLoad)
1395 END_IPC(CSSM)
1396 }
1397
1398 //
1399 // Testing-related RPCs
1400 //
1401 kern_return_t ucsp_server_getUserPromptAttempts(UCSP_ARGS, uint32* attempts)
1402 {
1403 BEGIN_IPC(keychainPromptAttempts)
1404
1405 *attempts = KeychainPromptAclSubject::getPromptAttempts() + KeychainDatabase::getInteractiveUnlockAttempts();
1406
1407 END_IPC(DL)
1408 }
1409
1410 #pragma clang diagnostic pop