]> git.saurik.com Git - apple/security.git/blob - SecurityServer/transition.cpp
Security-29.tar.gz
[apple/security.git] / SecurityServer / transition.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 // transition - SecurityServer IPC-to-class-methods transition layer
21 //
22 #include <Security/AuthorizationWalkers.h>
23 #include "server.h"
24 #include "ucsp.h"
25 #include "session.h"
26 #include "xdatabase.h"
27 #include <mach/mach_error.h>
28
29
30 //
31 // Bracket Macros
32 //
33 #define UCSP_ARGS mach_port_t sport, mach_port_t rport, security_token_t securityToken, \
34 CSSM_RETURN *rcode
35 #define CONTEXT_ARGS Context context, Pointer contextBase, Context::Attr *attributes, mach_msg_type_number_t attrCount
36
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); }
45
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)
49
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
53
54
55 using LowLevelMemoryUtilities::increment;
56 using LowLevelMemoryUtilities::difference;
57
58
59 //
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
63 // error.
64 //
65 class OutputData : public CssmData {
66 public:
67 OutputData(void **outP, mach_msg_type_number_t *outLength)
68 : mData(*outP), mLength(*outLength) { }
69 ~OutputData()
70 { mData = data(); mLength = length(); Server::releaseWhenDone(mData); }
71
72 private:
73 void * &mData;
74 mach_msg_type_number_t &mLength;
75 };
76
77
78 //
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.
84 //
85 class CheckingReconstituteWalker {
86 public:
87 CheckingReconstituteWalker(void *ptr, void *base, size_t size)
88 : mBase(base), mLimit(increment(base, size)), mOffset(difference(ptr, base)) { }
89
90 template <class T>
91 void operator () (T * &addr, size_t size = sizeof(T))
92 {
93 if (addr) {
94 if (addr < mBase || increment(addr, size) > mLimit)
95 CssmError::throwMe(CSSM_ERRCODE_INVALID_POINTER);
96 addr = increment<T>(addr, mOffset);
97 }
98 }
99
100 static const bool needsRelinking = true;
101 static const bool needsSize = false;
102
103 private:
104 void *mBase; // old base address
105 void *mLimit; // old last byte address + 1
106 off_t mOffset; // relocation offset
107 };
108
109 template <class T>
110 void relocate(T *obj, T *base, size_t size)
111 {
112 if (obj) {
113 CheckingReconstituteWalker w(obj, base, size);
114 walk(w, base);
115 }
116 }
117
118
119
120 //
121 // Setup/Teardown functions.
122 //
123 kern_return_t ucsp_server_setup(UCSP_ARGS, mach_port_t taskPort, const char *identity)
124 {
125 BEGIN_IPCN
126 Server::active().setupConnection(rport, taskPort, securityToken, identity);
127 END_IPCN(CSSM)
128 return KERN_SUCCESS;
129 }
130
131 kern_return_t ucsp_server_teardown(UCSP_ARGS)
132 {
133 BEGIN_IPCN
134 Server::active().endConnection(rport);
135 END_IPCN(CSSM)
136 return KERN_SUCCESS;
137 }
138
139
140 //
141 // Database management
142 //
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),
146 DBParameters params)
147 {
148 BEGIN_IPC
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();
153 END_IPC(DL)
154 }
155
156 kern_return_t ucsp_server_decodeDb(UCSP_ARGS, DbHandle *db,
157 COPY_IN(DLDbFlatIdentifier, ident), COPY_IN(AccessCredentials, cred), DATA_IN(blob))
158 {
159 BEGIN_IPC
160 relocate(cred, credBase, credLength);
161 relocate(ident, identBase, identLength);
162 *db = (new Database(*ident, DATA(blob).interpretedAs<DbBlob>(),
163 connection.process, cred))->handle();
164 END_IPC(DL)
165 }
166
167 kern_return_t ucsp_server_encodeDb(UCSP_ARGS, DbHandle db, DATA_OUT(blob))
168 {
169 BEGIN_IPC
170 DbBlob *dbBlob = Server::database(db).encode(); // memory owned by database
171 *blob = dbBlob;
172 *blobLength = dbBlob->length();
173 END_IPC(DL)
174 }
175
176 kern_return_t ucsp_server_releaseDb(UCSP_ARGS, DbHandle db)
177 {
178 BEGIN_IPC
179 delete &Server::database(db);
180 END_IPC(DL)
181 }
182
183 kern_return_t ucsp_server_authenticateDb(UCSP_ARGS, DbHandle db,
184 COPY_IN(AccessCredentials, cred))
185 {
186 BEGIN_IPC
187 relocate(cred, credBase, credLength);
188 Server::database(db).authenticate(cred);
189 END_IPC(DL)
190 }
191
192 kern_return_t ucsp_server_setDbParameters(UCSP_ARGS, DbHandle db, DBParameters params)
193 {
194 BEGIN_IPC
195 Server::database(db).setParameters(params);
196 END_IPC(DL)
197 }
198
199 kern_return_t ucsp_server_getDbParameters(UCSP_ARGS, DbHandle db, DBParameters *params)
200 {
201 BEGIN_IPC
202 Server::database(db).getParameters(*params);
203 END_IPC(DL)
204 }
205
206 kern_return_t ucsp_server_changePassphrase(UCSP_ARGS, DbHandle db,
207 COPY_IN(AccessCredentials, cred))
208 {
209 BEGIN_IPC
210 relocate(cred, credBase, credLength);
211 Server::database(db).changePassphrase(cred);
212 END_IPC(DL)
213 }
214
215 kern_return_t ucsp_server_lockDb(UCSP_ARGS, DbHandle db)
216 {
217 BEGIN_IPC
218 Server::database(db).lock();
219 END_IPC(DL)
220 }
221
222 kern_return_t ucsp_server_unlockDb(UCSP_ARGS, DbHandle db)
223 {
224 BEGIN_IPC
225 Server::database(db).unlock();
226 END_IPC(DL)
227 }
228
229 kern_return_t ucsp_server_unlockDbWithPassphrase(UCSP_ARGS, DbHandle db, DATA_IN(passphrase))
230 {
231 BEGIN_IPC
232 Server::database(db).unlock(DATA(passphrase));
233 END_IPC(DL)
234 }
235
236 kern_return_t ucsp_server_isLocked(UCSP_ARGS, DbHandle db, boolean_t *locked)
237 {
238 BEGIN_IPC
239 *locked = Server::database(db).isLocked();
240 END_IPC(DL)
241 }
242
243
244 //
245 // Key management
246 //
247 kern_return_t ucsp_server_encodeKey(UCSP_ARGS, KeyHandle keyh, DATA_OUT(blob),
248 boolean_t wantUid, DATA_OUT(uid))
249 {
250 BEGIN_IPC
251 Key &key = Server::key(keyh);
252 KeyBlob *keyBlob = key.blob(); // still owned by key
253 *blob = keyBlob;
254 *blobLength = keyBlob->length();
255 if (wantUid) {
256 *uid = &key.uid();
257 *uidLength = sizeof(KeyUID);
258 } else {
259 *uidLength = 0; // do not return this
260 }
261 END_IPC(CSP)
262 }
263
264 kern_return_t ucsp_server_decodeKey(UCSP_ARGS, KeyHandle *keyh, CssmKey::Header *header,
265 DbHandle db, DATA_IN(blob))
266 {
267 BEGIN_IPC
268 Key &key = *new Key(Server::database(db), DATA(blob).interpretedAs<KeyBlob>());
269 key.returnKey(*keyh, *header);
270 END_IPC(CSP)
271 }
272
273 kern_return_t ucsp_server_releaseKey(UCSP_ARGS, KeyHandle key)
274 {
275 BEGIN_IPC
276 connection.releaseKey(key);
277 END_IPC(CSP)
278 }
279
280
281 //
282 // RNG interface
283 //
284 kern_return_t ucsp_server_generateRandom(UCSP_ARGS, uint32 bytes, DATA_OUT(data))
285 {
286 BEGIN_IPC
287 CssmAllocator &allocator = CssmAllocator::standard(CssmAllocator::sensitive);
288 void *buffer = allocator.malloc(bytes);
289 Server::active().random(buffer, bytes);
290 *data = buffer;
291 *dataLength = bytes;
292 Server::releaseWhenDone(allocator, buffer);
293 END_IPC(CSP)
294 }
295
296
297 //
298 // Signatures and MACs
299 //
300 kern_return_t ucsp_server_generateSignature(UCSP_ARGS, CONTEXT_ARGS, KeyHandle key,
301 DATA_IN(data), DATA_OUT(signature))
302 {
303 BEGIN_IPC
304 context.postIPC(contextBase, attributes);
305 OutputData sigData(signature, signatureLength);
306 connection.generateSignature(context, findHandle<Key>(key),
307 DATA(data), sigData);
308 END_IPC(CSP)
309 }
310
311 kern_return_t ucsp_server_verifySignature(UCSP_ARGS, CONTEXT_ARGS, KeyHandle key,
312 DATA_IN(data), DATA_IN(signature))
313 {
314 BEGIN_IPC
315 context.postIPC(contextBase, attributes);
316 connection.verifySignature(context, findHandle<Key>(key),
317 DATA(data), DATA(signature));
318 END_IPC(CSP)
319 }
320
321 kern_return_t ucsp_server_generateMac(UCSP_ARGS, CONTEXT_ARGS, KeyHandle key,
322 DATA_IN(data), DATA_OUT(mac))
323 {
324 BEGIN_IPC
325 context.postIPC(contextBase, attributes);
326 OutputData macData(mac, macLength);
327 connection.generateMac(context, findHandle<Key>(key),
328 DATA(data), macData);
329 END_IPC(CSP)
330 }
331
332 kern_return_t ucsp_server_verifyMac(UCSP_ARGS, CONTEXT_ARGS, KeyHandle key,
333 DATA_IN(data), DATA_IN(mac))
334 {
335 BEGIN_IPC
336 context.postIPC(contextBase, attributes);
337 connection.verifyMac(context, findHandle<Key>(key),
338 DATA(data), DATA(mac));
339 END_IPC(CSP)
340 }
341
342
343 //
344 // Encryption/Decryption
345 //
346 kern_return_t ucsp_server_encrypt(UCSP_ARGS, CONTEXT_ARGS, KeyHandle key,
347 DATA_IN(clear), DATA_OUT(cipher))
348 {
349 BEGIN_IPC
350 context.postIPC(contextBase, attributes);
351 OutputData cipherOut(cipher, cipherLength);
352 connection.encrypt(context, findHandle<Key>(key),
353 DATA(clear), cipherOut);
354 END_IPC(CSP)
355 }
356
357 kern_return_t ucsp_server_decrypt(UCSP_ARGS, CONTEXT_ARGS, KeyHandle key,
358 DATA_IN(cipher), DATA_OUT(clear))
359 {
360 BEGIN_IPC
361 context.postIPC(contextBase, attributes);
362 OutputData clearOut(clear, clearLength);
363 connection.decrypt(context, findHandle<Key>(key),
364 DATA(cipher), clearOut);
365 END_IPC(CSP)
366 }
367
368
369 //
370 // Key generation
371 //
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)
375 {
376 BEGIN_IPC
377 context.postIPC(contextBase, attributes);
378 relocate(cred, credBase, credLength);
379 relocate(owner, ownerBase, ownerLength);
380 Key *key;
381 connection.generateKey(Server::optionalDatabase(db),
382 context, cred, owner, usage, attrs, key);
383 key->returnKey(*newKey, *newHeader);
384 END_IPC(CSP)
385 }
386
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)
391 {
392 BEGIN_IPC
393 context.postIPC(contextBase, attributes);
394 relocate(cred, credBase, credLength);
395 relocate(owner, ownerBase, ownerLength);
396 Key *pub, *priv;
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);
402 END_IPC(CSP)
403 }
404
405
406 //
407 // Key wrapping and unwrapping
408 //
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))
412 {
413 BEGIN_IPC
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);
422 END_IPC(CSP)
423 }
424
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)
430 {
431 BEGIN_IPC
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);
444 END_IPC(CSP)
445 }
446
447
448 //
449 // ACL management.
450 // Watch out for the memory-management tap-dance.
451 //
452 kern_return_t ucsp_server_getOwner(UCSP_ARGS, AclKind kind, KeyHandle key,
453 COPY_OUT(AclOwnerPrototype, ownerOut))
454 {
455 BEGIN_IPC
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
463 END_IPC(CSP)
464 }
465
466 kern_return_t ucsp_server_setOwner(UCSP_ARGS, AclKind kind, KeyHandle key,
467 COPY_IN(AccessCredentials, cred), COPY_IN(AclOwnerPrototype, owner))
468 {
469 BEGIN_IPC
470 relocate(cred, credBase, credLength);
471 relocate(owner, ownerBase, ownerLength);
472 Server::aclBearer(kind, key).cssmChangeOwner(*owner, cred);
473 END_IPC(CSP)
474 }
475
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))
479 {
480 BEGIN_IPC
481 uint32 count;
482 AclEntryInfo *aclList;
483 Server::aclBearer(kind, key).cssmGetAcl(haveTag ? tag : NULL, count, aclList);
484 *countp = count;
485 Copier<AclEntryInfo> aclsOut(AclEntryInfo::overlay(aclList), count); // make flat copy
486
487 { // release the chunked memory originals
488 ChunkFreeWalker free;
489 for (uint32 n = 0; n < count; n++)
490 walk(free, aclList[n]);
491 }
492
493 // set result
494 *acls = *aclsBase = aclsOut;
495 *aclsLength = aclsOut.length();
496 Server::releaseWhenDone(aclsOut.keep());
497 END_IPC(CSP)
498 }
499
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))
503 {
504 BEGIN_IPC
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);
509 END_IPC(CSP)
510 }
511
512
513 //
514 // Authorization subsystem support
515 //
516 kern_return_t ucsp_server_authorizationCreate(UCSP_ARGS,
517 COPY_IN(AuthorizationItemSet, rights),
518 uint32 flags,
519 COPY_IN(AuthorizationItemSet, environment),
520 AuthorizationBlob *authorization)
521 {
522 BEGIN_IPC
523 relocate(rights, rightsBase, rightsLength);
524 relocate(environment, environmentBase, environmentLength);
525 *rcode = connection.process.session.authCreate(rights, environment,
526 flags, *authorization);
527 END_IPC(CSSM)
528 }
529
530 kern_return_t ucsp_server_authorizationRelease(UCSP_ARGS,
531 AuthorizationBlob authorization, uint32 flags)
532 {
533 BEGIN_IPC
534 connection.process.session.authFree(authorization, flags);
535 END_IPC(CSSM)
536 }
537
538 kern_return_t ucsp_server_authorizationCopyRights(UCSP_ARGS,
539 AuthorizationBlob authorization,
540 COPY_IN(AuthorizationItemSet, rights),
541 uint32 flags,
542 COPY_IN(AuthorizationItemSet, environment),
543 COPY_OUT(AuthorizationItemSet, result))
544 {
545 BEGIN_IPC
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());
555 END_IPC(CSSM)
556 }
557
558 kern_return_t ucsp_server_authorizationCopyInfo(UCSP_ARGS,
559 AuthorizationBlob authorization,
560 AuthorizationString tag,
561 COPY_OUT(AuthorizationItemSet, info))
562 {
563 BEGIN_IPC
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());
571 END_IPC(CSSM)
572 }
573
574 kern_return_t ucsp_server_authorizationExternalize(UCSP_ARGS,
575 AuthorizationBlob authorization, AuthorizationExternalForm *extForm)
576 {
577 BEGIN_IPC
578 *rcode = connection.process.session.authExternalize(authorization, *extForm);
579 END_IPC(CSSM)
580 }
581
582 kern_return_t ucsp_server_authorizationInternalize(UCSP_ARGS,
583 AuthorizationExternalForm extForm, AuthorizationBlob *authorization)
584 {
585 BEGIN_IPC
586 *rcode = connection.process.session.authInternalize(extForm, *authorization);
587 END_IPC(CSSM)
588 }
589
590
591 //
592 // Session management subsystem
593 //
594 kern_return_t ucsp_server_getSessionInfo(UCSP_ARGS,
595 SecuritySessionId *sessionId, SessionAttributeBits *attrs)
596 {
597 BEGIN_IPC
598 Session &session = Session::find(*sessionId);
599 *sessionId = session.handle();
600 *attrs = session.attributes();
601 END_IPC(CSSM)
602 }
603
604 kern_return_t ucsp_server_setupSession(UCSP_ARGS,
605 SessionCreationFlags flags, SessionAttributeBits attrs)
606 {
607 BEGIN_IPC
608 Session::setup(flags, attrs);
609 END_IPC(CSSM)
610 }