/ OSX / libsecurity_cssm / lib / manager.cpp
manager.cpp
  1  /*
  2   * Copyright (c) 2000-2001,2003-2004,2011,2014 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  // 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  //
 37  CssmManager::CssmManager()
 38  {
 39      initCount = 0;	// not yet initialized
 40  }
 41  
 42  CssmManager::~CssmManager()
 43  {
 44  	if (initCount > 0)
 45  		secinfo("cssm", "CSSM forcibly shutting down");
 46  }
 47  
 48  
 49  //
 50  // CSSM initialization.
 51  // THREADS: This function must run in an uncontested environment.
 52  //
 53  void 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          secinfo("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      secinfo("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  //
 95  bool CssmManager::terminate()
 96  {
 97      StLock<Mutex> _(mLock);
 98      switch (initCount) {
 99      case 0:
100          CssmError::throwMe(CSSMERR_CSSM_NOT_INITIALIZED);
101      case 1:
102          secinfo("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          secinfo("cssm", "CSSM nested termination (%d remaining)", initCount);
110          return false;
111      }
112  }
113  
114  
115  #if defined(RESTRICTED_CSP_LOADING)
116  static 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  //
127  void 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  		secinfo("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  		secinfo("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  //
169  void 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  		secinfo("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  		secinfo("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  //
188  void CssmManager::introduce(const Guid &,
189                              CSSM_KEY_HIERARCHY)
190  {
191      StLock<Mutex> _(mLock);
192      CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
193  }
194  
195  void 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  //
206  void 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  
214  Module *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  }