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