2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
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
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.
20 // transition - SecurityServer IPC-to-class-methods transition layer
22 #include <Security/AuthorizationWalkers.h>
26 #include "xdatabase.h"
27 #include <mach/mach_error.h>
33 #define UCSP_ARGS mach_port_t sport, mach_port_t rport, security_token_t securityToken, \
35 #define CONTEXT_ARGS Context context, Pointer contextBase, Context::Attr *attributes, mach_msg_type_number_t attrCount
37 #define BEGIN_IPCN *rcode = CSSM_OK; try {
38 #define BEGIN_IPC BEGIN_IPCN Connection &connection = Server::connection(rport);
39 #define END_IPC(base) END_IPCN(base) Server::requestComplete(); return KERN_SUCCESS;
40 #define END_IPCN(base) } \
41 catch (const CssmCommonError &err) { *rcode = err.cssmError(CSSM_ ## base ## _BASE_ERROR); } \
42 catch (std::bad_alloc) { *rcode = CssmError::merge(CSSM_ERRCODE_MEMORY_ERROR, CSSM_ ## base ## _BASE_ERROR); } \
43 catch (Connection *conn) { *rcode = 0; } \
44 catch (...) { *rcode = CssmError::merge(CSSM_ERRCODE_INTERNAL_ERROR, CSSM_ ## base ## _BASE_ERROR); }
46 #define DATA_IN(base) void *base, mach_msg_type_number_t base##Length
47 #define DATA_OUT(base) void **base, mach_msg_type_number_t *base##Length
48 #define DATA(base) CssmData(base, base##Length)
50 #define COPY_IN(type,name) type *name, mach_msg_type_number_t name##Length, type *name##Base
51 #define COPY_OUT(type,name) \
52 type **name, mach_msg_type_number_t *name##Length, type **name##Base
55 using LowLevelMemoryUtilities::increment
;
56 using LowLevelMemoryUtilities::difference
;
60 // An OutputData object will take memory allocated within the SecurityServer,
61 // hand it to the MIG return-output parameters, and schedule it to be released
62 // after the MIG reply has been sent. It will also get rid of it in case of
65 class OutputData
: public CssmData
{
67 OutputData(void **outP
, mach_msg_type_number_t
*outLength
)
68 : mData(*outP
), mLength(*outLength
) { }
70 { mData
= data(); mLength
= length(); Server::releaseWhenDone(mData
); }
74 mach_msg_type_number_t
&mLength
;
79 // A CheckingReconstituteWalker is a variant of an ordinary ReconstituteWalker
80 // that checks object pointers and sizes against the incoming block limits.
81 // It throws an exception if incoming data has pointers outside the incoming block.
82 // This avoids trouble inside of the SecurityServer caused (by bug or malice)
83 // from someone spoofing the client access side.
85 class CheckingReconstituteWalker
{
87 CheckingReconstituteWalker(void *ptr
, void *base
, size_t size
)
88 : mBase(base
), mLimit(increment(base
, size
)), mOffset(difference(ptr
, base
)) { }
91 void operator () (T
* &addr
, size_t size
= sizeof(T
))
94 if (addr
< mBase
|| increment(addr
, size
) > mLimit
)
95 CssmError::throwMe(CSSM_ERRCODE_INVALID_POINTER
);
96 addr
= increment
<T
>(addr
, mOffset
);
100 static const bool needsRelinking
= true;
101 static const bool needsSize
= false;
104 void *mBase
; // old base address
105 void *mLimit
; // old last byte address + 1
106 off_t mOffset
; // relocation offset
110 void relocate(T
*obj
, T
*base
, size_t size
)
113 CheckingReconstituteWalker
w(obj
, base
, size
);
121 // Setup/Teardown functions.
123 kern_return_t
ucsp_server_setup(UCSP_ARGS
, mach_port_t taskPort
, const char *identity
)
126 Server::active().setupConnection(rport
, taskPort
, securityToken
, identity
);
131 kern_return_t
ucsp_server_teardown(UCSP_ARGS
)
134 Server::active().endConnection(rport
);
141 // Database management
143 kern_return_t
ucsp_server_createDb(UCSP_ARGS
, DbHandle
*db
,
144 COPY_IN(DLDbFlatIdentifier
, ident
),
145 COPY_IN(AccessCredentials
, cred
), COPY_IN(AclEntryPrototype
, owner
),
149 relocate(cred
, credBase
, credLength
);
150 relocate(owner
, ownerBase
, ownerLength
);
151 relocate(ident
, identBase
, identLength
);
152 *db
= (new Database(*ident
, params
, connection
.process
, cred
, owner
))->handle();
156 kern_return_t
ucsp_server_decodeDb(UCSP_ARGS
, DbHandle
*db
,
157 COPY_IN(DLDbFlatIdentifier
, ident
), COPY_IN(AccessCredentials
, cred
), DATA_IN(blob
))
160 relocate(cred
, credBase
, credLength
);
161 relocate(ident
, identBase
, identLength
);
162 *db
= (new Database(*ident
, DATA(blob
).interpretedAs
<DbBlob
>(),
163 connection
.process
, cred
))->handle();
167 kern_return_t
ucsp_server_encodeDb(UCSP_ARGS
, DbHandle db
, DATA_OUT(blob
))
170 DbBlob
*dbBlob
= Server::database(db
).encode(); // memory owned by database
172 *blobLength
= dbBlob
->length();
176 kern_return_t
ucsp_server_releaseDb(UCSP_ARGS
, DbHandle db
)
179 delete &Server::database(db
);
183 kern_return_t
ucsp_server_authenticateDb(UCSP_ARGS
, DbHandle db
,
184 COPY_IN(AccessCredentials
, cred
))
187 relocate(cred
, credBase
, credLength
);
188 Server::database(db
).authenticate(cred
);
192 kern_return_t
ucsp_server_setDbParameters(UCSP_ARGS
, DbHandle db
, DBParameters params
)
195 Server::database(db
).setParameters(params
);
199 kern_return_t
ucsp_server_getDbParameters(UCSP_ARGS
, DbHandle db
, DBParameters
*params
)
202 Server::database(db
).getParameters(*params
);
206 kern_return_t
ucsp_server_changePassphrase(UCSP_ARGS
, DbHandle db
,
207 COPY_IN(AccessCredentials
, cred
))
210 relocate(cred
, credBase
, credLength
);
211 Server::database(db
).changePassphrase(cred
);
215 kern_return_t
ucsp_server_lockDb(UCSP_ARGS
, DbHandle db
)
218 Server::database(db
).lock();
222 kern_return_t
ucsp_server_unlockDb(UCSP_ARGS
, DbHandle db
)
225 Server::database(db
).unlock();
229 kern_return_t
ucsp_server_unlockDbWithPassphrase(UCSP_ARGS
, DbHandle db
, DATA_IN(passphrase
))
232 Server::database(db
).unlock(DATA(passphrase
));
236 kern_return_t
ucsp_server_isLocked(UCSP_ARGS
, DbHandle db
, boolean_t
*locked
)
239 *locked
= Server::database(db
).isLocked();
247 kern_return_t
ucsp_server_encodeKey(UCSP_ARGS
, KeyHandle keyh
, DATA_OUT(blob
),
248 boolean_t wantUid
, DATA_OUT(uid
))
251 Key
&key
= Server::key(keyh
);
252 KeyBlob
*keyBlob
= key
.blob(); // still owned by key
254 *blobLength
= keyBlob
->length();
257 *uidLength
= sizeof(KeyUID
);
259 *uidLength
= 0; // do not return this
264 kern_return_t
ucsp_server_decodeKey(UCSP_ARGS
, KeyHandle
*keyh
, CssmKey::Header
*header
,
265 DbHandle db
, DATA_IN(blob
))
268 Key
&key
= *new Key(Server::database(db
), DATA(blob
).interpretedAs
<KeyBlob
>());
269 key
.returnKey(*keyh
, *header
);
273 kern_return_t
ucsp_server_releaseKey(UCSP_ARGS
, KeyHandle key
)
276 connection
.releaseKey(key
);
284 kern_return_t
ucsp_server_generateRandom(UCSP_ARGS
, uint32 bytes
, DATA_OUT(data
))
287 CssmAllocator
&allocator
= CssmAllocator::standard(CssmAllocator::sensitive
);
288 void *buffer
= allocator
.malloc(bytes
);
289 Server::active().random(buffer
, bytes
);
292 Server::releaseWhenDone(allocator
, buffer
);
298 // Signatures and MACs
300 kern_return_t
ucsp_server_generateSignature(UCSP_ARGS
, CONTEXT_ARGS
, KeyHandle key
,
301 DATA_IN(data
), DATA_OUT(signature
))
304 context
.postIPC(contextBase
, attributes
);
305 OutputData
sigData(signature
, signatureLength
);
306 connection
.generateSignature(context
, findHandle
<Key
>(key
),
307 DATA(data
), sigData
);
311 kern_return_t
ucsp_server_verifySignature(UCSP_ARGS
, CONTEXT_ARGS
, KeyHandle key
,
312 DATA_IN(data
), DATA_IN(signature
))
315 context
.postIPC(contextBase
, attributes
);
316 connection
.verifySignature(context
, findHandle
<Key
>(key
),
317 DATA(data
), DATA(signature
));
321 kern_return_t
ucsp_server_generateMac(UCSP_ARGS
, CONTEXT_ARGS
, KeyHandle key
,
322 DATA_IN(data
), DATA_OUT(mac
))
325 context
.postIPC(contextBase
, attributes
);
326 OutputData
macData(mac
, macLength
);
327 connection
.generateMac(context
, findHandle
<Key
>(key
),
328 DATA(data
), macData
);
332 kern_return_t
ucsp_server_verifyMac(UCSP_ARGS
, CONTEXT_ARGS
, KeyHandle key
,
333 DATA_IN(data
), DATA_IN(mac
))
336 context
.postIPC(contextBase
, attributes
);
337 connection
.verifyMac(context
, findHandle
<Key
>(key
),
338 DATA(data
), DATA(mac
));
344 // Encryption/Decryption
346 kern_return_t
ucsp_server_encrypt(UCSP_ARGS
, CONTEXT_ARGS
, KeyHandle key
,
347 DATA_IN(clear
), DATA_OUT(cipher
))
350 context
.postIPC(contextBase
, attributes
);
351 OutputData
cipherOut(cipher
, cipherLength
);
352 connection
.encrypt(context
, findHandle
<Key
>(key
),
353 DATA(clear
), cipherOut
);
357 kern_return_t
ucsp_server_decrypt(UCSP_ARGS
, CONTEXT_ARGS
, KeyHandle key
,
358 DATA_IN(cipher
), DATA_OUT(clear
))
361 context
.postIPC(contextBase
, attributes
);
362 OutputData
clearOut(clear
, clearLength
);
363 connection
.decrypt(context
, findHandle
<Key
>(key
),
364 DATA(cipher
), clearOut
);
372 kern_return_t
ucsp_server_generateKey(UCSP_ARGS
, DbHandle db
, CONTEXT_ARGS
,
373 COPY_IN(AccessCredentials
, cred
), COPY_IN(AclEntryPrototype
, owner
),
374 uint32 usage
, uint32 attrs
, KeyHandle
*newKey
, CssmKey::Header
*newHeader
)
377 context
.postIPC(contextBase
, attributes
);
378 relocate(cred
, credBase
, credLength
);
379 relocate(owner
, ownerBase
, ownerLength
);
381 connection
.generateKey(Server::optionalDatabase(db
),
382 context
, cred
, owner
, usage
, attrs
, key
);
383 key
->returnKey(*newKey
, *newHeader
);
387 kern_return_t
ucsp_server_generateKeyPair(UCSP_ARGS
, DbHandle db
, CONTEXT_ARGS
,
388 COPY_IN(AccessCredentials
, cred
), COPY_IN(AclEntryPrototype
, owner
),
389 uint32 pubUsage
, uint32 pubAttrs
, uint32 privUsage
, uint32 privAttrs
,
390 KeyHandle
*pubKey
, CssmKey::Header
*pubHeader
, KeyHandle
*privKey
, CssmKey::Header
*privHeader
)
393 context
.postIPC(contextBase
, attributes
);
394 relocate(cred
, credBase
, credLength
);
395 relocate(owner
, ownerBase
, ownerLength
);
397 connection
.generateKey(Server::optionalDatabase(db
),
398 context
, cred
, owner
,
399 pubUsage
, pubAttrs
, privUsage
, privAttrs
, pub
, priv
);
400 pub
->returnKey(*pubKey
, *pubHeader
);
401 priv
->returnKey(*privKey
, *privHeader
);
407 // Key wrapping and unwrapping
409 kern_return_t
ucsp_server_wrapKey(UCSP_ARGS
, CONTEXT_ARGS
, KeyHandle key
,
410 COPY_IN(AccessCredentials
, cred
), KeyHandle keyToBeWrapped
,
411 DATA_IN(descriptiveData
), CssmKey
*wrappedKey
, DATA_OUT(keyData
))
414 context
.postIPC(contextBase
, attributes
);
415 relocate(cred
, credBase
, credLength
);
416 connection
.wrapKey(context
, Server::optionalKey(key
),
417 Server::key(keyToBeWrapped
), cred
, DATA(descriptiveData
), *wrappedKey
);
418 // transmit key data back as a separate blob
419 *keyData
= wrappedKey
->data();
420 *keyDataLength
= wrappedKey
->length();
421 Server::releaseWhenDone(*keyData
);
425 kern_return_t
ucsp_server_unwrapKey(UCSP_ARGS
, DbHandle db
, CONTEXT_ARGS
, KeyHandle key
,
426 COPY_IN(AccessCredentials
, cred
), COPY_IN(AclEntryPrototype
, owner
),
427 KeyHandle publicKey
, CssmKey wrappedKey
, DATA_IN(wrappedKeyData
),
428 uint32 usage
, uint32 attr
, DATA_OUT(descriptiveData
),
429 KeyHandle
*newKey
, CssmKey::Header
*newHeader
)
432 context
.postIPC(contextBase
, attributes
);
433 wrappedKey
.KeyData
= DATA(wrappedKeyData
);
434 relocate(cred
, credBase
, credLength
);
435 relocate(owner
, ownerBase
, ownerLength
);
436 CssmData descriptiveDatas
;
437 Key
&theKey
= connection
.unwrapKey(Server::optionalDatabase(db
),
438 context
, Server::optionalKey(key
), cred
, owner
, usage
, attr
, wrappedKey
,
439 Server::optionalKey(publicKey
), &descriptiveDatas
);
440 theKey
.returnKey(*newKey
, *newHeader
);
441 *descriptiveData
= descriptiveDatas
.data();
442 *descriptiveDataLength
= descriptiveDatas
.length();
443 Server::releaseWhenDone(*descriptiveData
);
450 // Watch out for the memory-management tap-dance.
452 kern_return_t
ucsp_server_getOwner(UCSP_ARGS
, AclKind kind
, KeyHandle key
,
453 COPY_OUT(AclOwnerPrototype
, ownerOut
))
456 AclOwnerPrototype owner
;
457 Server::aclBearer(kind
, key
).cssmGetOwner(owner
); // allocates memory in owner
458 Copier
<AclOwnerPrototype
> owners(&owner
, CssmAllocator::standard()); // make flat copy
459 { ChunkFreeWalker free
; walk(free
, owner
); } // release chunked original
460 *ownerOut
= *ownerOutBase
= owners
;
461 *ownerOutLength
= owners
.length();
462 Server::releaseWhenDone(owners
.keep()); // throw flat copy out when done
466 kern_return_t
ucsp_server_setOwner(UCSP_ARGS
, AclKind kind
, KeyHandle key
,
467 COPY_IN(AccessCredentials
, cred
), COPY_IN(AclOwnerPrototype
, owner
))
470 relocate(cred
, credBase
, credLength
);
471 relocate(owner
, ownerBase
, ownerLength
);
472 Server::aclBearer(kind
, key
).cssmChangeOwner(*owner
, cred
);
476 kern_return_t
ucsp_server_getAcl(UCSP_ARGS
, AclKind kind
, KeyHandle key
,
477 boolean_t haveTag
, const char *tag
,
478 uint32
*countp
, COPY_OUT(AclEntryInfo
, acls
))
482 AclEntryInfo
*aclList
;
483 Server::aclBearer(kind
, key
).cssmGetAcl(haveTag
? tag
: NULL
, count
, aclList
);
485 Copier
<AclEntryInfo
> aclsOut(AclEntryInfo::overlay(aclList
), count
); // make flat copy
487 { // release the chunked memory originals
488 ChunkFreeWalker free
;
489 for (uint32 n
= 0; n
< count
; n
++)
490 walk(free
, aclList
[n
]);
494 *acls
= *aclsBase
= aclsOut
;
495 *aclsLength
= aclsOut
.length();
496 Server::releaseWhenDone(aclsOut
.keep());
500 kern_return_t
ucsp_server_changeAcl(UCSP_ARGS
, AclKind kind
, KeyHandle key
,
501 COPY_IN(AccessCredentials
, cred
), CSSM_ACL_EDIT_MODE mode
, CSSM_ACL_HANDLE handle
,
502 COPY_IN(AclEntryPrototype
, acl
))
505 relocate(cred
, credBase
, credLength
);
506 relocate(acl
, aclBase
, aclLength
);
507 AclEntryInput
input(*acl
);
508 Server::aclBearer(kind
, key
).cssmChangeAcl(AclEdit(mode
, handle
, &input
), cred
);
514 // Authorization subsystem support
516 kern_return_t
ucsp_server_authorizationCreate(UCSP_ARGS
,
517 COPY_IN(AuthorizationItemSet
, rights
),
519 COPY_IN(AuthorizationItemSet
, environment
),
520 AuthorizationBlob
*authorization
)
523 relocate(rights
, rightsBase
, rightsLength
);
524 relocate(environment
, environmentBase
, environmentLength
);
525 *rcode
= connection
.process
.session
.authCreate(rights
, environment
,
526 flags
, *authorization
);
530 kern_return_t
ucsp_server_authorizationRelease(UCSP_ARGS
,
531 AuthorizationBlob authorization
, uint32 flags
)
534 connection
.process
.session
.authFree(authorization
, flags
);
538 kern_return_t
ucsp_server_authorizationCopyRights(UCSP_ARGS
,
539 AuthorizationBlob authorization
,
540 COPY_IN(AuthorizationItemSet
, rights
),
542 COPY_IN(AuthorizationItemSet
, environment
),
543 COPY_OUT(AuthorizationItemSet
, result
))
546 relocate(rights
, rightsBase
, rightsLength
);
547 relocate(environment
, environmentBase
, environmentLength
);
548 Authorization::MutableRightSet grantedRights
;
549 *rcode
= connection
.process
.session
.authGetRights(authorization
,
550 rights
, environment
, flags
, grantedRights
);
551 Copier
<AuthorizationRights
> returnedRights(grantedRights
, CssmAllocator::standard());
552 *result
= *resultBase
= returnedRights
;
553 *resultLength
= returnedRights
.length();
554 Server::releaseWhenDone(returnedRights
.keep());
558 kern_return_t
ucsp_server_authorizationCopyInfo(UCSP_ARGS
,
559 AuthorizationBlob authorization
,
560 AuthorizationString tag
,
561 COPY_OUT(AuthorizationItemSet
, info
))
564 Authorization::MutableRightSet result
;
565 *rcode
= connection
.process
.session
.authGetInfo(authorization
,
566 tag
[0] ? tag
: NULL
, result
);
567 Copier
<AuthorizationItemSet
> returnedInfo(result
, CssmAllocator::standard());
568 *info
= *infoBase
= returnedInfo
;
569 *infoLength
= returnedInfo
.length();
570 Server::releaseWhenDone(returnedInfo
.keep());
574 kern_return_t
ucsp_server_authorizationExternalize(UCSP_ARGS
,
575 AuthorizationBlob authorization
, AuthorizationExternalForm
*extForm
)
578 *rcode
= connection
.process
.session
.authExternalize(authorization
, *extForm
);
582 kern_return_t
ucsp_server_authorizationInternalize(UCSP_ARGS
,
583 AuthorizationExternalForm extForm
, AuthorizationBlob
*authorization
)
586 *rcode
= connection
.process
.session
.authInternalize(extForm
, *authorization
);
592 // Session management subsystem
594 kern_return_t
ucsp_server_getSessionInfo(UCSP_ARGS
,
595 SecuritySessionId
*sessionId
, SessionAttributeBits
*attrs
)
598 Session
&session
= Session::find(*sessionId
);
599 *sessionId
= session
.handle();
600 *attrs
= session
.attributes();
604 kern_return_t
ucsp_server_setupSession(UCSP_ARGS
,
605 SessionCreationFlags flags
, SessionAttributeBits attrs
)
608 Session::setup(flags
, attrs
);