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// module - CSSM Module objects
27//
28#include "module.h"
29#include "manager.h"
30#include "attachment.h"
31#include <security_cdsa_utilities/cssmbridge.h>
32
33
34//
35// Module object construction.
36//
37Module::Module(CssmManager *mgr, const MdsComponent &info, Plugin *plug)
38: MdsComponent(info), cssm(*mgr), plugin(plug)
39{
40    // invoke module's load entry (tell it it's being loaded)
41    if (CSSM_RETURN err = plugin->load(&gGuidCssm, // CSSM's Guid
42            &myGuid(),			// module's Guid
43            spiEventRelay, this)) {
44        plugin->unload();
45        CssmError::throwMe(err);	// self-destruct this module
46    }
47}
48
49
50//
51// Destroy the module object.
52// The unload() method must have succeeded and returned true before
53// you get to delete a Module. A destructor is too precarious a place
54// to negotiate with a plugin...
55//
56Module::~Module()
57{
58}
59
60
61bool Module::unload(const ModuleCallback &callback)
62{
63    StLock<Mutex> _(mLock);
64    // locked module - no more attachment creations possible
65    if (callbackCount() == 1) {
66        // would be last callback if successful, check for actual unload
67        if (attachmentCount() > 0)
68            CssmError::throwMe(CSSM_ERRCODE_FUNCTION_FAILED);	// @# module is busy
69        // no attachments active - we are idle and ready to unload
70        if (CSSM_RETURN err = plugin->unload(&gGuidCssm, // CSSM's Guid
71                &myGuid(),		// module's Guid
72                spiEventRelay, this)) // our callback
73            CssmError::throwMe(err);	// tough...
74        // okay, commit
75        remove(callback);
76        plugin->unload();
77        return true;
78    } else {
79        // more callbacks - we're not going to unload
80        remove(callback);
81        return false;
82    }
83}
84
85
86//
87// Create a new attachment for this module
88//
89CSSM_HANDLE Module::attach(const CSSM_VERSION &version,
90                           uint32 subserviceId,
91                           CSSM_SERVICE_TYPE subserviceType,
92                           const CSSM_API_MEMORY_FUNCS &memoryOps,
93                           CSSM_ATTACH_FLAGS attachFlags,
94                           CSSM_KEY_HIERARCHY keyHierarchy,
95                           CSSM_FUNC_NAME_ADDR *functionTable,
96                           uint32 functionTableSize)
97{
98    StLock<Mutex> _(mLock);
99
100    // check if the module can do this kind of service
101    if (!supportsService(subserviceType))
102        CssmError::throwMe(CSSMERR_CSSM_INVALID_SERVICE_MASK);
103
104    Attachment *attachment = cssm.attachmentMakerFor(subserviceType)->make(this,
105                                   version,
106                                   subserviceId, subserviceType,
107                                   memoryOps,
108                                   attachFlags,
109                                   keyHierarchy,
110                                   functionTable, functionTableSize);
111
112    try {
113        // add to module's attachment map
114        attachmentMap.insert(AttachmentMap::value_type(attachment->handle(), attachment));
115    } catch (...) {
116        delete attachment;
117        throw;
118    }
119
120    // all done
121    return attachment->handle();
122}
123
124
125//
126// Detach an Attachment from this module.
127// THREADS: Requires the attachment to be idled out, i.e. caller
128//  is responsible for keeping more users from entering it.
129//
130void Module::detach(Attachment *attachment)
131{
132    StLock<Mutex> _(mLock);
133    attachmentMap.erase(attachment->handle());
134}
135
136
137//
138// Handle events sent by the loaded module.
139//
140void Module::spiEvent(CSSM_MODULE_EVENT event,
141                      const Guid &guid,
142                      uint32 subserviceId,
143                      CSSM_SERVICE_TYPE serviceType)
144{
145    StLock<Mutex> _(mLock);
146    if (guid != myGuid())
147        CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
148    callbackSet(event, guid, subserviceId, serviceType);
149}
150
151// static shim
152CSSM_RETURN Module::spiEventRelay(const CSSM_GUID *ModuleGuid,
153                                   void *Context,
154                                   uint32 SubserviceId,
155                                   CSSM_SERVICE_TYPE ServiceType,
156                                   CSSM_MODULE_EVENT EventType)
157{
158    BEGIN_API
159    static_cast<Module *>(Context)->spiEvent(EventType,
160                                             Guid::required(ModuleGuid),
161                                             SubserviceId,
162                                             ServiceType);
163    END_API(CSSM)
164}
165