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