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