]> git.saurik.com Git - apple/security.git/blob - SecurityServer/sstransit.cpp
Security-179.tar.gz
[apple/security.git] / SecurityServer / sstransit.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 //
20 // sstransit - SecurityServer client library transition code.
21 //
22 // These are the functions that implement CssmClient methods in terms of
23 // MIG IPC client calls, plus their supporting machinery.
24 //
25 #include "sstransit.h"
26 #include <Security/cspclient.h>
27 #include <Security/ktracecodes.h>
28 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
29
30 namespace Security {
31
32 using MachPlusPlus::check;
33 using MachPlusPlus::VMGuard;
34
35
36 //
37 // DataOutput helper.
38 // This happens "at the end" of a glue method, via the DataOutput destructor.
39 //
40 DataOutput::~DataOutput()
41 {
42 VMGuard _(mData, mLength);
43 if (mData) { // was assigned to; IPC returned OK
44 if (argument) { // buffer was provided
45 if (argument.length() < mLength)
46 CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR);
47 argument.length(mLength);
48 } else { // allocate buffer
49 argument = CssmData(allocator.malloc(mLength), mLength);
50 }
51 memcpy(argument.data(), mData, mLength);
52 }
53 }
54
55
56 CssmList chunkCopy(CssmList &list, CssmAllocator &alloc)
57 {
58 CssmList copy = list;
59 ChunkCopyWalker w(alloc);
60 walk(w, copy);
61 return copy;
62 }
63
64
65 //
66 // Create a packaged-up Context for IPC transmission.
67 // In addition to collecting the context into a contiguous blob for transmission,
68 // we also evaluate CssmCryptoData callbacks at this time.
69 //
70 SendContext::SendContext(const Security::Context &ctx) : context(ctx)
71 {
72 CssmCryptoData cryptoDataValue; // holding area for CssmCryptoData element
73 IFDEBUG(uint32 cryptoDataUsed = 0);
74 Context::Builder builder(CssmAllocator::standard());
75 for (unsigned n = 0; n < ctx.attributesInUse(); n++) {
76 switch (ctx[n].baseType()) {
77 case CSSM_ATTRIBUTE_DATA_CRYPTO_DATA: {
78 CssmCryptoData &data = ctx[n]; // extract CssmCryptoData value
79 cryptoDataValue = data(); // evaluate callback (if any)
80 builder.setup(&cryptoDataValue); // use evaluted value
81 IFDEBUG(cryptoDataUsed++);
82 break;
83 }
84 default:
85 builder.setup(ctx[n]);
86 break;
87 }
88 }
89 attributeSize = builder.make();
90 for (unsigned n = 0; n < ctx.attributesInUse(); n++) {
91 const Context::Attr &attr = ctx[n];
92 switch (attr.baseType()) {
93 case CSSM_ATTRIBUTE_DATA_CRYPTO_DATA:
94 builder.put(attr.type(), &cryptoDataValue);
95 break;
96 default:
97 builder.put(attr);
98 break;
99 }
100 }
101 uint32 count; // not needed
102 builder.done(attributes, count);
103 assert(cryptoDataUsed <= 1); // no more than one slot converted
104 }
105
106
107 //
108 // Copy an AccessCredentials for shipment.
109 // In addition, scan the samples for "special" database locking samples
110 // and translate certain items for safe shipment. Note that this overwrites
111 // part of the CssmList value (CSPHandle -> SS/KeyHandle), but we do it on
112 // the COPY, so that's okay.
113 //
114 DatabaseAccessCredentials::DatabaseAccessCredentials(const AccessCredentials *creds, CssmAllocator &alloc)
115 : Copier<AccessCredentials>(creds, alloc)
116 {
117 if (creds) {
118 for (uint32 n = 0; n < value()->samples().length(); n++) {
119 TypedList sample = value()->samples()[n];
120 sample.checkProper();
121 switch (sample.type()) {
122 case CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK:
123 case CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK:
124 sample.snip(); // skip sample type
125 sample.checkProper();
126 if (sample.type() == CSSM_WORDID_SYMMETRIC_KEY) {
127 secdebug("SSclient", "key sample encountered");
128 // proper form is sample[1] = DATA:CSPHandle, sample[2] = DATA:CSSM_KEY
129 if (sample.length() != 3
130 || sample[1].type() != CSSM_LIST_ELEMENT_DATUM
131 || sample[2].type() != CSSM_LIST_ELEMENT_DATUM)
132 CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
133 mapKeySample(
134 *sample[1].data().interpretedAs<CSSM_CSP_HANDLE>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE),
135 *sample[2].data().interpretedAs<CssmKey>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE));
136 }
137 break;
138 default:
139 break;
140 }
141 }
142 }
143 }
144
145 void DatabaseAccessCredentials::mapKeySample(CSSM_CSP_HANDLE &cspHandle, CssmKey &key)
146 {
147 // if the key belongs to the AppleCSPDL, look it up and write the SS KeyHandle
148 // into the CSPHandle element for transmission
149 if (key.header().cspGuid() == gGuidAppleCSPDL) {
150 // @@@ can't use CssmClient (it makes its own attachments)
151 CSSM_CC_HANDLE ctx;
152 if (CSSM_RETURN err = CSSM_CSP_CreatePassThroughContext(cspHandle, &key, &ctx))
153 CssmError::throwMe(err);
154 KeyHandle ssKey;
155 CSSM_RETURN passthroughError =
156 CSSM_CSP_PassThrough(ctx, CSSM_APPLESCPDL_CSP_GET_KEYHANDLE, NULL, (void **)&ssKey);
157 CSSM_DeleteContext(ctx); // ignore error
158 if (passthroughError)
159 CssmError::throwMe(passthroughError);
160 // we happen to know that they're both uint32 values
161 assert(sizeof(CSSM_CSP_HANDLE) >= sizeof(KeyHandle));
162 cspHandle = ssKey;
163 secdebug("SSclient", "key sample mapped to key 0x%lx", ssKey);
164 }
165 }
166
167
168 namespace SecurityServer
169 {
170
171 //
172 // Database control
173 //
174 DbHandle ClientSession::createDb(const DLDbIdentifier &dbId,
175 const AccessCredentials *cred, const AclEntryInput *owner,
176 const DBParameters &params)
177 {
178 DatabaseAccessCredentials creds(cred, internalAllocator);
179 Copier<AclEntryPrototype> proto(&owner->proto(), internalAllocator);
180 DataWalkers::DLDbFlatIdentifier ident(dbId);
181 Copier<DataWalkers::DLDbFlatIdentifier> id(&ident, internalAllocator);
182 DbHandle db;
183 IPC(ucsp_client_createDb(UCSP_ARGS, &db, COPY(id), COPY(creds), COPY(proto), params));
184 return db;
185 }
186
187 DbHandle ClientSession::decodeDb(const DLDbIdentifier &dbId,
188 const AccessCredentials *cred, const CssmData &blob)
189 {
190 DatabaseAccessCredentials creds(cred, internalAllocator);
191 DataWalkers::DLDbFlatIdentifier ident(dbId);
192 Copier<DataWalkers::DLDbFlatIdentifier> id(&ident, internalAllocator);
193 DbHandle db;
194 IPC(ucsp_client_decodeDb(UCSP_ARGS, &db, COPY(id), COPY(creds), DATA(blob)));
195 return db;
196 }
197
198 void ClientSession::encodeDb(DbHandle db, CssmData &blob, CssmAllocator &alloc)
199 {
200 DataOutput outBlob(blob, alloc);
201 IPC(ucsp_client_encodeDb(UCSP_ARGS, db, DATA(outBlob)));
202 }
203
204 void ClientSession::releaseDb(DbHandle db)
205 {
206 IPC(ucsp_client_releaseDb(UCSP_ARGS, db));
207 }
208
209 void ClientSession::getDbSuggestedIndex(DbHandle db, CssmData &index, CssmAllocator &alloc)
210 {
211 DataOutput outBlob(index, alloc);
212 IPC(ucsp_client_getDbIndex(UCSP_ARGS, db, DATA(outBlob)));
213 }
214
215 void ClientSession::authenticateDb(DbHandle db, DBAccessType type,
216 const AccessCredentials *cred)
217 {
218 DatabaseAccessCredentials creds(cred, internalAllocator);
219 IPC(ucsp_client_authenticateDb(UCSP_ARGS, db, COPY(creds)));
220 }
221
222 void ClientSession::setDbParameters(DbHandle db, const DBParameters &params)
223 {
224 IPC(ucsp_client_setDbParameters(UCSP_ARGS, db, params));
225 }
226
227 void ClientSession::getDbParameters(DbHandle db, DBParameters &params)
228 {
229 IPC(ucsp_client_getDbParameters(UCSP_ARGS, db, &params));
230 }
231
232 void ClientSession::changePassphrase(DbHandle db, const AccessCredentials *cred)
233 {
234 Copier<AccessCredentials> creds(cred, internalAllocator);
235 IPC(ucsp_client_changePassphrase(UCSP_ARGS, db, COPY(creds)));
236 }
237
238
239 void ClientSession::lock(DbHandle db)
240 {
241 IPC(ucsp_client_lockDb(UCSP_ARGS, db));
242 }
243
244 void ClientSession::lockAll (bool forSleep)
245 {
246 IPC(ucsp_client_lockAll (UCSP_ARGS, forSleep));
247 }
248
249 void ClientSession::unlock(DbHandle db)
250 {
251 IPC(ucsp_client_unlockDb(UCSP_ARGS, db));
252 }
253
254 void ClientSession::unlock(DbHandle db, const CssmData &passphrase)
255 {
256 IPC(ucsp_client_unlockDbWithPassphrase(UCSP_ARGS, db, DATA(passphrase)));
257 }
258
259 bool ClientSession::isLocked(DbHandle db)
260 {
261 boolean_t locked;
262 IPC(ucsp_client_isLocked(UCSP_ARGS, db, &locked));
263 return locked;
264 }
265
266
267 //
268 // Key control
269 //
270 void ClientSession::encodeKey(KeyHandle key, CssmData &blob,
271 KeyUID *uid, CssmAllocator &alloc)
272 {
273 DataOutput oBlob(blob, alloc);
274 void *uidp;
275 mach_msg_type_number_t uidLength;
276 IPC(ucsp_client_encodeKey(UCSP_ARGS, key, oBlob.data(), oBlob.length(),
277 (uid != NULL), &uidp, &uidLength));
278 // return key uid if requested
279 if (uid) {
280 assert(uidLength == sizeof(KeyUID));
281 memcpy(uid, uidp, sizeof(KeyUID));
282 }
283 }
284
285
286 KeyHandle ClientSession::decodeKey(DbHandle db, const CssmData &blob, CssmKey::Header &header)
287 {
288 KeyHandle key;
289 IPC(ucsp_client_decodeKey(UCSP_ARGS, &key, &header, db, blob.data(), blob.length()));
290 return key;
291 }
292
293 void ClientSession::releaseKey(KeyHandle key)
294 {
295 IPC(ucsp_client_releaseKey(UCSP_ARGS, key));
296 }
297
298
299 CssmKeySize ClientSession::queryKeySizeInBits(KeyHandle key)
300 {
301 CssmKeySize length;
302 IPC(ucsp_client_queryKeySizeInBits(UCSP_ARGS, key, &length));
303 return length;
304 }
305
306
307 uint32 ClientSession::getOutputSize(const Context &context, KeyHandle key,
308 uint32 inputSize, bool encrypt)
309 {
310 SendContext ctx(context);
311 uint32 outputSize;
312 IPC(ucsp_client_getOutputSize(UCSP_ARGS, CONTEXT(ctx), key, inputSize, encrypt, &outputSize));
313 return outputSize;
314 }
315
316
317 //
318 // Random number generation.
319 // This interfaces to the secure RNG inside the SecurityServer; it does not access
320 // a PRNG in its CSP. If you need a reproducible PRNG, attach a local CSP and use it.
321 // Note that this function does not allocate a buffer; it always fills the buffer provided.
322 //
323 void ClientSession::generateRandom(CssmData &data)
324 {
325 void *result;
326 mach_msg_type_number_t resultLength;
327 IPC(ucsp_client_generateRandom(UCSP_ARGS, data.length(), &result, &resultLength));
328 assert(resultLength == data.length());
329 memcpy(data.data(), result, data.length());
330 }
331
332
333 //
334 // Signatures and MACs
335 //
336 void ClientSession::generateSignature(const Context &context, KeyHandle key,
337 const CssmData &data, CssmData &signature, CssmAllocator &alloc, CSSM_ALGORITHMS signOnlyAlgorithm)
338 {
339 SendContext ctx(context);
340 DataOutput sig(signature, alloc);
341 IPCKEY(ucsp_client_generateSignature(UCSP_ARGS, CONTEXT(ctx), key, signOnlyAlgorithm,
342 DATA(data), DATA(sig)),
343 key, CSSM_ACL_AUTHORIZATION_SIGN);
344 }
345
346 void ClientSession::verifySignature(const Context &context, KeyHandle key,
347 const CssmData &data, const CssmData &signature, CSSM_ALGORITHMS verifyOnlyAlgorithm)
348 {
349 SendContext ctx(context);
350 IPC(ucsp_client_verifySignature(UCSP_ARGS, CONTEXT(ctx), key, verifyOnlyAlgorithm,
351 DATA(data), DATA(signature)));
352 }
353
354
355 void ClientSession::generateMac(const Context &context, KeyHandle key,
356 const CssmData &data, CssmData &signature, CssmAllocator &alloc)
357 {
358 SendContext ctx(context);
359 DataOutput sig(signature, alloc);
360 IPCKEY(ucsp_client_generateMac(UCSP_ARGS, CONTEXT(ctx), key,
361 DATA(data), DATA(sig)),
362 key, CSSM_ACL_AUTHORIZATION_MAC);
363 }
364
365 void ClientSession::verifyMac(const Context &context, KeyHandle key,
366 const CssmData &data, const CssmData &signature)
367 {
368 SendContext ctx(context);
369 IPCKEY(ucsp_client_verifyMac(UCSP_ARGS, CONTEXT(ctx), key,
370 DATA(data), DATA(signature)),
371 key, CSSM_ACL_AUTHORIZATION_MAC);
372 }
373
374
375 //
376 // Encryption/Decryption
377 //
378
379 void ClientSession::encrypt(const Context &context, KeyHandle key,
380 const CssmData &clear, CssmData &cipher, CssmAllocator &alloc)
381 {
382 SendContext ctx(context);
383 DataOutput cipherOut(cipher, alloc);
384 IPCKEY(ucsp_client_encrypt(UCSP_ARGS, CONTEXT(ctx), key, DATA(clear), DATA(cipherOut)),
385 key, CSSM_ACL_AUTHORIZATION_ENCRYPT);
386 }
387
388 void ClientSession::decrypt(const Context &context, KeyHandle key,
389 const CssmData &cipher, CssmData &clear, CssmAllocator &alloc)
390 {
391 Debug::trace (kSecTraceUCSPServerDecryptBegin);
392
393 SendContext ctx(context);
394 DataOutput clearOut(clear, alloc);
395 IPCKEY(ucsp_client_decrypt(UCSP_ARGS, CONTEXT(ctx), key, DATA(cipher), DATA(clearOut)),
396 key, CSSM_ACL_AUTHORIZATION_DECRYPT);
397 }
398
399
400 //
401 // Key generation
402 //
403 void ClientSession::generateKey(DbHandle db, const Context &context, uint32 keyUsage, uint32 keyAttr,
404 const AccessCredentials *cred, const AclEntryInput *owner,
405 KeyHandle &newKey, CssmKey::Header &newHeader)
406 {
407 SendContext ctx(context);
408 Copier<AccessCredentials> creds(cred, internalAllocator);
409 Copier<AclEntryPrototype> proto(&owner->proto(), internalAllocator);
410 IPC(ucsp_client_generateKey(UCSP_ARGS, db, CONTEXT(ctx),
411 COPY(creds), COPY(proto), keyUsage, keyAttr, &newKey, &newHeader));
412 }
413
414 void ClientSession::generateKey(DbHandle db, const Context &context,
415 uint32 pubKeyUsage, uint32 pubKeyAttr,
416 uint32 privKeyUsage, uint32 privKeyAttr,
417 const AccessCredentials *cred, const AclEntryInput *owner,
418 KeyHandle &pubKey, CssmKey::Header &pubHeader,
419 KeyHandle &privKey, CssmKey::Header &privHeader)
420 {
421 SendContext ctx(context);
422 Copier<AccessCredentials> creds(cred, internalAllocator);
423 Copier<AclEntryPrototype> proto(&owner->proto(), internalAllocator);
424 IPC(ucsp_client_generateKeyPair(UCSP_ARGS, db, CONTEXT(ctx),
425 COPY(creds), COPY(proto),
426 pubKeyUsage, pubKeyAttr, privKeyUsage, privKeyAttr,
427 &pubKey, &pubHeader, &privKey, &privHeader));
428 }
429
430
431 //
432 // Key derivation
433 // This is a bit strained; the incoming 'param' value may have structure
434 // and needs to be handled on a per-algorithm basis, which means we have to
435 // know which key derivation algorithms we support for passing to our CSP(s).
436 // The default behavior is to handle "flat" data blobs, which is as good
437 // a default as we can manage.
438 // NOTE: The param-specific handling must be synchronized with the server
439 // transition layer code (in transition.cpp).
440 //
441 void ClientSession::deriveKey(DbHandle db, const Context &context, KeyHandle baseKey,
442 uint32 keyUsage, uint32 keyAttr, CssmData &param,
443 const AccessCredentials *cred, const AclEntryInput *owner,
444 KeyHandle &newKey, CssmKey::Header &newHeader, CssmAllocator &allocator)
445 {
446 SendContext ctx(context);
447 Copier<AccessCredentials> creds(cred, internalAllocator);
448 Copier<AclEntryPrototype> proto(&owner->proto(), internalAllocator);
449 DataOutput paramOutput(param, allocator);
450 switch (context.algorithm()) {
451 case CSSM_ALGID_PKCS5_PBKDF2: {
452 typedef CSSM_PKCS5_PBKDF2_PARAMS Params;
453 Copier<Params> params(param.interpretedAs<Params>(CSSM_ERRCODE_INVALID_INPUT_POINTER),
454 internalAllocator);
455 IPCKEY(ucsp_client_deriveKey(UCSP_ARGS, db, CONTEXT(ctx), baseKey,
456 COPY(creds), COPY(proto), COPY(params), DATA(paramOutput),
457 keyUsage, keyAttr, &newKey, &newHeader),
458 baseKey, CSSM_ACL_AUTHORIZATION_DERIVE);
459 break; }
460 default: {
461 IPCKEY(ucsp_client_deriveKey(UCSP_ARGS, db, CONTEXT(ctx), baseKey,
462 COPY(creds), COPY(proto),
463 param.data(), param.length(), param.data(),
464 DATA(paramOutput),
465 keyUsage, keyAttr, &newKey, &newHeader),
466 baseKey, CSSM_ACL_AUTHORIZATION_DERIVE);
467 break; }
468 }
469 }
470
471
472 //
473 // Digest generation
474 //
475 void ClientSession::getKeyDigest(KeyHandle key, CssmData &digest, CssmAllocator &allocator)
476 {
477 DataOutput dig(digest, allocator);
478 IPC(ucsp_client_getKeyDigest(UCSP_ARGS, key, DATA(dig)));
479 }
480
481
482 //
483 // Key wrapping and unwrapping
484 //
485 void ClientSession::wrapKey(const Context &context, KeyHandle wrappingKey,
486 KeyHandle keyToBeWrapped, const AccessCredentials *cred,
487 const CssmData *descriptiveData, CssmWrappedKey &wrappedKey, CssmAllocator &alloc)
488 {
489 SendContext ctx(context);
490 Copier<AccessCredentials> creds(cred, internalAllocator);
491 DataOutput keyData(wrappedKey, alloc);
492 /* @@@ When <rdar://problem/3525664>: CSSM_WrapKey doesn't check the acl of the key doing the wrapping. is fixed, we need to potentially edit the CSSM_ACL_AUTHORIZATION_ENCRYPT acl of the wrapping key as opposed to the key being wrapped. We need to know which of the 2 keys to edit though somehow. */
493 IPCKEY(ucsp_client_wrapKey(UCSP_ARGS, CONTEXT(ctx), wrappingKey, COPY(creds),
494 keyToBeWrapped, OPTIONALDATA(descriptiveData),
495 &wrappedKey, DATA(keyData)),
496 keyToBeWrapped,
497 context.algorithm() == CSSM_ALGID_NONE
498 ? CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR : CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED);
499 wrappedKey = CssmData(); // null out data section (force allocation for key data)
500 }
501
502 void ClientSession::unwrapKey(DbHandle db, const Context &context, KeyHandle key,
503 KeyHandle publicKey, const CssmWrappedKey &wrappedKey,
504 uint32 usage, uint32 attr,
505 const AccessCredentials *cred, const AclEntryInput *acl,
506 CssmData &descriptiveData,
507 KeyHandle &newKey, CssmKey::Header &newHeader, CssmAllocator &alloc)
508 {
509 SendContext ctx(context);
510 DataOutput descriptor(descriptiveData, alloc);
511 Copier<AccessCredentials> creds(cred, internalAllocator);
512 Copier<AclEntryPrototype> proto(&acl->proto(), internalAllocator);
513 IPCKEY(ucsp_client_unwrapKey(UCSP_ARGS, db, CONTEXT(ctx), key,
514 COPY(creds), COPY(proto),
515 publicKey, wrappedKey, DATA(wrappedKey), usage, attr, DATA(descriptor),
516 &newKey, &newHeader),
517 key, CSSM_ACL_AUTHORIZATION_DECRYPT);
518 }
519
520
521 //
522 // ACL management
523 //
524 void ClientSession::getAcl(AclKind kind, KeyHandle key, const char *tag,
525 uint32 &infoCount, AclEntryInfo * &infoArray, CssmAllocator &alloc)
526 {
527 uint32 count;
528 AclEntryInfo *info, *infoBase;
529 mach_msg_type_number_t infoLength;
530 IPC(ucsp_client_getAcl(UCSP_ARGS, kind, key,
531 (tag != NULL), tag ? tag : "",
532 &count, COPY_OUT(info)));
533 VMGuard _(info, infoLength);
534 infoCount = count;
535
536 // relocate incoming AclEntryInfo array
537 ReconstituteWalker relocator(info, infoBase);
538 for (uint32 n = 0; n < count; n++)
539 walk(relocator, info[n]);
540
541 // copy AclEntryInfo array into discrete memory nodes
542 infoArray = alloc.alloc<AclEntryInfo>(count);
543 ChunkCopyWalker chunker(alloc);
544 for (uint32 n = 0; n < count; n++) {
545 infoArray[n] = info[n];
546 walk(chunker, infoArray[n]);
547 }
548 }
549
550 void ClientSession::changeAcl(AclKind kind, KeyHandle key, const AccessCredentials &cred,
551 const AclEdit &edit)
552 {
553 Copier<AccessCredentials> creds(&cred, internalAllocator);
554 //@@@ ignoring callback
555 Copier<AclEntryInput> newEntry(edit.newEntry(), internalAllocator);
556 IPCKEY(ucsp_client_changeAcl(UCSP_ARGS, kind, key, COPY(creds),
557 edit.mode(), edit.handle(), COPY(newEntry)),
558 key, CSSM_ACL_AUTHORIZATION_CHANGE_ACL);
559 }
560
561 void ClientSession::getOwner(AclKind kind, KeyHandle key, AclOwnerPrototype &owner,
562 CssmAllocator &alloc)
563 {
564 AclOwnerPrototype *proto, *protoBase;
565 mach_msg_type_number_t protoLength;
566 IPC(ucsp_client_getOwner(UCSP_ARGS, kind, key, COPY_OUT(proto)));
567 // turn the returned AclOwnerPrototype into its proper output form
568 relocate(proto, protoBase);
569 owner.TypedSubject = chunkCopy(proto->subject(), alloc);
570 owner.Delegate = proto->delegate();
571 }
572
573 void ClientSession::changeOwner(AclKind kind, KeyHandle key,
574 const AccessCredentials &cred, const AclOwnerPrototype &proto)
575 {
576 Copier<AccessCredentials> creds(&cred, internalAllocator);
577 Copier<AclOwnerPrototype> protos(&proto, internalAllocator);
578 IPCKEY(ucsp_client_setOwner(UCSP_ARGS, kind, key, COPY(creds), COPY(protos)),
579 key, CSSM_ACL_AUTHORIZATION_CHANGE_OWNER);
580 }
581
582
583 void ClientSession::getKeyAcl(DbHandle db, const char *tag,
584 uint32 &count, AclEntryInfo * &info, CssmAllocator &alloc)
585 { getAcl(keyAcl, db, tag, count, info, alloc); }
586
587 void ClientSession::changeKeyAcl(DbHandle db, const AccessCredentials &cred,
588 const AclEdit &edit)
589 { changeAcl(keyAcl, db, cred, edit); }
590
591 void ClientSession::getKeyOwner(DbHandle db, AclOwnerPrototype &owner, CssmAllocator &alloc)
592 { getOwner(keyAcl, db, owner, alloc); }
593
594 void ClientSession::changeKeyOwner(DbHandle db, const AccessCredentials &cred,
595 const AclOwnerPrototype &edit)
596 { changeOwner(keyAcl, db, cred, edit); }
597
598 void ClientSession::getDbAcl(DbHandle db, const char *tag,
599 uint32 &count, AclEntryInfo * &info, CssmAllocator &alloc)
600 { getAcl(dbAcl, db, tag, count, info, alloc); }
601
602 void ClientSession::changeDbAcl(DbHandle db, const AccessCredentials &cred,
603 const AclEdit &edit)
604 { changeAcl(dbAcl, db, cred, edit); }
605
606 void ClientSession::getDbOwner(DbHandle db, AclOwnerPrototype &owner, CssmAllocator &alloc)
607 { getOwner(dbAcl, db, owner, alloc); }
608
609 void ClientSession::changeDbOwner(DbHandle db, const AccessCredentials &cred,
610 const AclOwnerPrototype &edit)
611 { changeOwner(dbAcl, db, cred, edit); }
612
613
614 //
615 // Database key management
616 //
617 void ClientSession::extractMasterKey(DbHandle db, const Context &context, DbHandle sourceDb,
618 uint32 keyUsage, uint32 keyAttr,
619 const AccessCredentials *cred, const AclEntryInput *owner,
620 KeyHandle &newKey, CssmKey::Header &newHeader, CssmAllocator &alloc)
621 {
622 SendContext ctx(context);
623 Copier<AccessCredentials> creds(cred, internalAllocator);
624 Copier<AclEntryPrototype> proto(&owner->proto(), internalAllocator);
625 IPC(ucsp_client_extractMasterKey(UCSP_ARGS, db, CONTEXT(ctx), sourceDb,
626 COPY(creds), COPY(proto),
627 keyUsage, keyAttr, &newKey, &newHeader));
628 }
629
630
631 //
632 // Authorization subsystem entry
633 //
634 void ClientSession::authCreate(const AuthorizationItemSet *rights,
635 const AuthorizationItemSet *environment, AuthorizationFlags flags,
636 AuthorizationBlob &result)
637 {
638 Copier<AuthorizationItemSet> rightSet(rights, internalAllocator);
639 Copier<AuthorizationItemSet> environ(environment, internalAllocator);
640 IPC(ucsp_client_authorizationCreate(UCSP_ARGS,
641 COPY(rightSet), flags, COPY(environ), &result));
642 }
643
644 void ClientSession::authRelease(const AuthorizationBlob &auth,
645 AuthorizationFlags flags)
646 {
647 IPC(ucsp_client_authorizationRelease(UCSP_ARGS, auth, flags));
648 }
649
650 void ClientSession::authCopyRights(const AuthorizationBlob &auth,
651 const AuthorizationItemSet *rights, const AuthorizationItemSet *environment,
652 AuthorizationFlags flags,
653 AuthorizationItemSet **grantedRights)
654 {
655 Copier<AuthorizationItemSet> rightSet(rights, internalAllocator);
656 Copier<AuthorizationItemSet> environ(environment, internalAllocator);
657 COPY_OUT_DECL(AuthorizationItemSet, result);
658 IPC(ucsp_client_authorizationCopyRights(UCSP_ARGS, auth, COPY(rightSet),
659 flags | (grantedRights ? 0 : kAuthorizationFlagNoData),
660 COPY(environ), COPY_OUT(result)));
661 VMGuard _(result, resultLength);
662 // return rights vector (only) if requested
663 if (grantedRights) {
664 relocate(result, resultBase);
665 *grantedRights = copy(result, returnAllocator);
666 }
667 }
668
669 void ClientSession::authCopyInfo(const AuthorizationBlob &auth,
670 const char *tag,
671 AuthorizationItemSet * &info)
672 {
673 COPY_OUT_DECL(AuthorizationItemSet, result);
674 if (tag == NULL)
675 tag = "";
676 else if (tag[0] == '\0')
677 MacOSError::throwMe(errAuthorizationInvalidTag);
678 IPC(ucsp_client_authorizationCopyInfo(UCSP_ARGS, auth, tag, COPY_OUT(result)));
679 VMGuard _(result, resultLength);
680 relocate(result, resultBase);
681 info = copy(result, returnAllocator);
682 }
683
684 void ClientSession::authExternalize(const AuthorizationBlob &auth,
685 AuthorizationExternalForm &extForm)
686 {
687 IPC(ucsp_client_authorizationExternalize(UCSP_ARGS, auth, &extForm));
688 }
689
690 void ClientSession::authInternalize(const AuthorizationExternalForm &extForm,
691 AuthorizationBlob &auth)
692 {
693 IPC(ucsp_client_authorizationInternalize(UCSP_ARGS, extForm, &auth));
694 }
695
696
697 //
698 // Get session information (security session status)
699 //
700 void ClientSession::getSessionInfo(SecuritySessionId &sessionId, SessionAttributeBits &attrs)
701 {
702 IPC(ucsp_client_getSessionInfo(UCSP_ARGS, &sessionId, &attrs));
703 }
704
705
706 //
707 // Create a new session.
708 //
709 // Caveat: This discards all SecurityServer held state for this process, including
710 // authorizations, database handles, etc. If you are multi-threaded at this point,
711 // and other threads have talked to SecurityServer, they will leak a few resources
712 // (mach ports and the like). Nothing horrendous, unless you create masses of sessions
713 // that way (which we wouldn't exactly recommend for other reasons).
714 //
715 // Hacker's note: This engages in an interesting dance with SecurityServer's state tracking.
716 // If you don't know the choreography, don't change things here until talking to an expert.
717 //
718 // Yes, if the client had multiple threads each of which has talked to SecurityServer,
719 // the reply ports for all but the calling thread will leak. If that ever turns out to
720 // be a real problem, we can fix it by keeping a (locked) set of client replyPorts to ditch.
721 // Hardly worth it, though. This is a rare call.
722 //
723 void ClientSession::setupSession(SessionCreationFlags flags, SessionAttributeBits attrs)
724 {
725 mGlobal().thread().replyPort.destroy(); // kill this thread's reply port
726 mGlobal.reset(); // kill existing cache (leak all other threads)
727 mSetupSession = true; // global flag to Global constructor
728 IPC(ucsp_client_setupSession(UCSP_ARGS, flags, attrs)); // reinitialize and call
729 }
730
731
732 //
733 // Notification subsystem
734 //
735 void ClientSession::requestNotification(Port receiver, Listener::Domain domain, Listener::EventMask events)
736 {
737 IPC(ucsp_client_requestNotification(UCSP_ARGS, receiver, domain, events));
738 }
739
740 void ClientSession::stopNotification(Port port)
741 {
742 IPC(ucsp_client_stopNotification(UCSP_ARGS, port.port()));
743 }
744
745 void ClientSession::postNotification(Listener::Domain domain, Listener::Event event, const CssmData &data)
746 {
747 IPC(ucsp_client_postNotification(UCSP_ARGS, domain, event, DATA(data)));
748 }
749
750 OSStatus ClientSession::dispatchNotification(const mach_msg_header_t *message,
751 ConsumeNotification *consumer, void *context) throw()
752 {
753 struct Message {
754 mach_msg_header_t Head;
755 /* start of the kernel processed data */
756 mach_msg_body_t msgh_body;
757 mach_msg_ool_descriptor_t data;
758 /* end of the kernel processed data */
759 NDR_record_t NDR;
760 uint32 domain;
761 uint32 event;
762 mach_msg_type_number_t dataCnt;
763 uint32 sender;
764 } *msg = (Message *)message;
765
766 OSStatus status;
767 try
768 {
769 status = consumer(msg->domain, msg->event, msg->data.address, msg->dataCnt, context);
770 }
771 catch (const CssmCommonError &err) { status = err.osStatus(); }
772 catch (const std::bad_alloc &) { status = memFullErr; }
773 catch (...) { status = internalComponentErr; }
774
775 mig_deallocate((vm_offset_t) msg->data.address, msg->dataCnt);
776 msg->data.address = (vm_offset_t) 0;
777 msg->data.size = (mach_msg_size_t) 0;
778
779 return status;
780 }
781
782
783 //
784 // authorizationdbGet/Set/Remove
785 //
786 void ClientSession::authorizationdbGet(const AuthorizationString rightname, CssmData &rightDefinition, CssmAllocator &alloc)
787 {
788 DataOutput definition(rightDefinition, alloc);
789 IPC(ucsp_client_authorizationdbGet(UCSP_ARGS, rightname, DATA(definition)));
790 }
791
792 void ClientSession::authorizationdbSet(const AuthorizationBlob &auth, const AuthorizationString rightname, uint32_t rightDefinitionLength, const void *rightDefinition)
793 {
794 // @@@ DATA_IN in transition.cpp is not const void *
795 IPC(ucsp_client_authorizationdbSet(UCSP_ARGS, auth, rightname, const_cast<void *>(rightDefinition), rightDefinitionLength));
796 }
797
798 void ClientSession::authorizationdbRemove(const AuthorizationBlob &auth, const AuthorizationString rightname)
799 {
800 IPC(ucsp_client_authorizationdbRemove(UCSP_ARGS, auth, rightname));
801 }
802
803
804 //
805 // Miscellaneous administrative calls
806 //
807 void ClientSession::addCodeEquivalence(const CssmData &oldHash, const CssmData &newHash,
808 const char *name, bool forSystem /* = false */)
809 {
810 IPC(ucsp_client_addCodeEquivalence(UCSP_ARGS, DATA(oldHash), DATA(newHash),
811 name, forSystem));
812 }
813
814 void ClientSession::removeCodeEquivalence(const CssmData &hash, const char *name, bool forSystem /* = false */)
815 {
816 IPC(ucsp_client_removeCodeEquivalence(UCSP_ARGS, DATA(hash), name, forSystem));
817 }
818
819 void ClientSession::setAlternateSystemRoot(const char *path)
820 {
821 IPC(ucsp_client_setAlternateSystemRoot(UCSP_ARGS, path));
822 }
823
824
825 } // end namespace SecurityServer
826 } // end namespace Security