1/*
2 * Copyright (c) 2000-2001,2003-2004 Apple Computer, 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// manager - CSSM manager/supervisor objects.
27//
28#include "manager.h"
29#include "module.h"
30#include <security_utilities/debugging.h>
31
32
33//
34// Constructing a CssmManager instance.
35// This does almost nothing - the actual intialization happens in the initialize() method.
36//
37CssmManager::CssmManager()
38{
39    initCount = 0;	// not yet initialized
40}
41
42CssmManager::~CssmManager()
43{
44	if (initCount > 0)
45		secdebug("cssm", "CSSM forcibly shutting down");
46}
47
48
49//
50// CSSM initialization.
51// THREADS: This function must run in an uncontested environment.
52//
53void CssmManager::initialize (const CSSM_VERSION &version,
54                              CSSM_PRIVILEGE_SCOPE scope,
55                              const Guid &callerGuid,
56                              CSSM_KEY_HIERARCHY keyHierarchy,
57                              CSSM_PVC_MODE &pvcPolicy)
58{
59    StLock<Mutex> _(mLock);
60
61    // check version first
62    checkVersion(version);
63
64    if (initCount) {
65        // re-initialization processing as per CSSM spec
66        if (pvcPolicy != mPvcPolicy) {
67            pvcPolicy = mPvcPolicy; // return old value
68            CssmError::throwMe(CSSMERR_CSSM_PVC_ALREADY_CONFIGURED);
69        }
70        initCount++;
71        secdebug("cssm", "re-initializing CSSM (%d levels)", initCount);
72        return;
73    }
74
75    // we don't support thread scope privileges
76    if (scope == CSSM_PRIVILEGE_SCOPE_THREAD)
77        CssmError::throwMe(CSSMERR_CSSM_SCOPE_NOT_SUPPORTED);
78
79    // keep the init arguments for future use - these become instance constants
80    mPrivilegeScope = scope;
81    mKeyHierarchy = keyHierarchy;
82    mPvcPolicy = pvcPolicy;
83    mCallerGuid = callerGuid;
84
85    // we are ready now
86    initCount = 1;
87    secdebug("cssm", "CSSM initialized");
88}
89
90
91//
92// CSSM Termination processing.
93// Returns true if this was the final (true) termination, false if a nested Init was undone.
94//
95bool CssmManager::terminate()
96{
97    StLock<Mutex> _(mLock);
98    switch (initCount) {
99    case 0:
100        CssmError::throwMe(CSSMERR_CSSM_NOT_INITIALIZED);
101    case 1:
102        secdebug("cssm", "Terminating CSSM");
103        if (!moduleMap.empty())
104            CssmError::throwMe(CSSM_ERRCODE_FUNCTION_FAILED);	// @#can't terminate with modules loaded
105        initCount = 0;	// mark uninitialized
106        return true;
107    default:
108        initCount--;	// nested INIT, just count down
109        secdebug("cssm", "CSSM nested termination (%d remaining)", initCount);
110        return false;
111    }
112}
113
114
115#if defined(RESTRICTED_CSP_LOADING)
116static const char * const allowedCSPs[] = {
117	"/System/Library/Security/AppleCSP.bundle",
118	"/System/Library/Security/AppleCSPDL.bundle",
119	NULL
120};
121#endif
122
123
124//
125// Load a module (well, try).
126//
127void CssmManager::loadModule(const Guid &guid,
128                             CSSM_KEY_HIERARCHY,
129                             const ModuleCallback &callback)
130{
131    StLock<Mutex> _(mLock);
132    ModuleMap::iterator it = moduleMap.find(guid);
133    Module *module;
134    if (it == moduleMap.end()) {
135        MdsComponent info(guid);
136#if defined(RESTRICTED_CSP_LOADING)
137		// An abominable temporary hack for legal reasons. They made me do it!
138		if (info.supportsService(CSSM_SERVICE_CSP)) {
139			string loadPath = info.path();
140			for (const char * const *pp = allowedCSPs; *pp; pp++)
141				if (loadPath == *pp)
142					goto allowed;
143			CssmError::throwMe(CSSM_ERRCODE_MODULE_MANIFEST_VERIFY_FAILED);
144		  allowed: ;
145		}
146#endif
147		secdebug("cssm", "loading module %s(%s) from %s",
148			info.name().c_str(), info.description().c_str(), info.path().c_str());
149        module = new Module(this, info, loader(info.path()));
150        moduleMap[guid] = module;
151    } else {
152        module = it->second;
153		secdebug("cssm", "%p reloaded module %s(%s) at %s",
154			module, module->name().c_str(), module->description().c_str(),
155			module->path().c_str());
156	}
157
158	// We are not playing the "key hierarchy" game around here.
159	// if we did, this is where we'd check the manifest.
160
161    module->add(callback);
162}
163
164
165//
166// Unload a module.
167// THREADS: Locking Manager(1), Module(2).
168//
169void CssmManager::unloadModule(const Guid &guid,
170                               const ModuleCallback &callback)
171{
172    StLock<Mutex> _(mLock);
173    Module *module = getModule(guid);
174    if (module->unload(callback)) {
175		secdebug("cssm", "%p module %s(%s) final unload",
176			module, module->name().c_str(), module->description().c_str());
177        moduleMap.erase(guid);
178        delete module;
179    } else
180		secdebug("cssm", "%p module %s(%s) load count now %u", module,
181			module->name().c_str(), module->description().c_str(), module->callbackCount());
182}
183
184
185//
186// Introductions
187//
188void CssmManager::introduce(const Guid &,
189                            CSSM_KEY_HIERARCHY)
190{
191    StLock<Mutex> _(mLock);
192    CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
193}
194
195void CssmManager::unIntroduce(const Guid &)
196{
197    StLock<Mutex> _(mLock);
198    CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
199}
200
201
202//
203// Support.
204// THREADS: These utilities run under lock protection by the caller.
205//
206void CssmManager::checkVersion(const CSSM_VERSION &version)
207{
208    if (version.Major != 2)
209        CssmError::throwMe(CSSM_ERRCODE_INCOMPATIBLE_VERSION);
210    if (version.Minor != 0)
211        CssmError::throwMe(CSSM_ERRCODE_INCOMPATIBLE_VERSION);
212}
213
214Module *CssmManager::getModule(const Guid &guid)
215{
216    ModuleMap::iterator it = moduleMap.find(guid);
217    if (it == moduleMap.end())
218        CssmError::throwMe(CSSMERR_CSSM_MODULE_NOT_LOADED);
219    return it->second;
220}
221