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