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