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