1/*
2 * Copyright (c) 2000-2001,2011-2014 Apple 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// cssmclient - common client interface to CSSM and MDS
21//
22#ifndef _H_CDSA_CLIENT_CSSMCLIENT
23#define _H_CDSA_CLIENT_CSSMCLIENT  1
24
25#include <security_utilities/threading.h>
26#include <security_utilities/globalizer.h>
27#include <security_utilities/refcount.h>
28#include <security_cdsa_utilities/cssmalloc.h>
29#include <security_cdsa_utilities/cssmpods.h>
30#include <map>
31
32namespace Security {
33namespace CssmClient {
34
35
36//
37// Forward declarations
38//
39class Cssm;
40class Module;
41class Attachment;
42
43
44//
45// An mixin for objects that have (store) GUIDs.
46// The GUID value is meant to be set-once constant, and can be lock-handled accordingly.
47//
48class HasGuid {
49public:
50	HasGuid(const Guid &guid) { mGuid = guid; }
51	HasGuid() { }
52
53	const Guid &guid() const { return mGuid; }
54
55protected:
56	void setGuid(const Guid &guid) { mGuid = guid; }
57
58private:
59	Guid mGuid;
60};
61
62
63//
64// Exceptions are based on the CssmError utility class. We add our own class of client-side exceptions.
65//
66class Error : public CssmError {
67public:
68	Error(CSSM_RETURN err) : CssmError(err) { }
69	virtual const char *what () const throw();
70
71	enum {
72		objectBusy = -1,
73	};
74};
75
76
77//
78// The CssmObject abstract class models features common to different Cssm objects.
79// It handles a tree hierarchy of objects (parent/children) safely.
80//
81class Object;
82
83class ObjectImpl : virtual public RefCount
84{
85public:
86	explicit ObjectImpl(); // Constructor for Impl objects without a parent.
87	explicit ObjectImpl(const Object &parent);
88	virtual ~ObjectImpl();
89
90	bool isActive() const { return mActive; }
91
92	virtual Allocator &allocator() const;
93	virtual void allocator(Allocator &alloc);
94
95	// Pointer comparison by default.  Subclasses may override.
96	virtual bool operator <(const ObjectImpl &other) const;
97	virtual bool operator ==(const ObjectImpl &other) const;
98
99	static void check(CSSM_RETURN status);
100	bool isIdle() const { return mChildCount == 0; }
101
102protected:
103	bool mActive;					// loaded, attached, etc.
104    RecursiveMutex mActivateMutex;
105	mutable Allocator *mAllocator; // allocator hierarchy (NULL => TBD)
106
107	template <class Obj> Obj parent() const
108	{ assert(mParent); return Obj(static_cast<typename Obj::Impl *>(&(*mParent))); }
109
110	void addChild();
111	void removeChild();
112
113	// {de,}activate() assume you have locked *this
114	virtual void activate() = 0;
115	virtual void deactivate() = 0;
116
117private:
118	RefPointer<ObjectImpl> mParent;		// parent object
119	AtomicCounter<uint32> mChildCount;
120};
121
122
123class Object
124{
125	friend class ObjectImpl;
126public:
127	typedef ObjectImpl Impl;
128	explicit Object(Impl *impl) : mImpl(impl) {}
129
130protected:
131	// @@@ CSPDL subclass breaks if the is a static_cast
132	template <class _Impl> _Impl &impl() const
133	{ return dynamic_cast<_Impl &>(*mImpl); }
134
135public:
136	Impl *operator ->() const { return &(*mImpl); }
137	Impl &operator *() const { return *mImpl; }
138
139	// @@@ Why is this needed.  DbCursor which inheirits from Object wants to call this.
140	template <class _Impl> _Impl &checkedImpl() const
141	{ return dynamic_cast<_Impl &>(*mImpl); }
142
143	bool operator !() const { return !mImpl; }
144	operator bool() const { return mImpl; }
145
146    bool isActive() const				{ return mImpl && mImpl->isActive(); }
147    Allocator &allocator() const	{ return mImpl->allocator(); }
148	void release()						{ mImpl = NULL; }
149
150	bool operator <(const Object &other) const
151	{ return mImpl && other.mImpl ? *mImpl < *other.mImpl : mImpl < other.mImpl; }
152	bool operator ==(const Object &other) const
153	{ return mImpl && other.mImpl ? *mImpl == *other.mImpl : mImpl == other.mImpl; }
154
155    Impl* get() {return mImpl;}
156
157private:
158	RefPointer<Impl> mImpl;
159};
160
161
162//
163// Event callback mix-in class
164//
165class ModuleImpl;
166
167class RawModuleEvents {
168	friend class ModuleImpl;
169public:
170	virtual ~RawModuleEvents();
171
172	virtual void notify(uint32 subService,
173		CSSM_SERVICE_TYPE type, CSSM_MODULE_EVENT event) = 0;
174
175private:
176	static CSSM_RETURN sendNotify(const CSSM_GUID *, void *context, uint32 subService,
177		CSSM_SERVICE_TYPE type, CSSM_MODULE_EVENT event);
178};
179
180class ModuleEvents : public RawModuleEvents {
181public:
182	virtual void insertion(uint32 subService, CSSM_SERVICE_TYPE type);
183	virtual void removal(uint32 subService, CSSM_SERVICE_TYPE type);
184	virtual void fault(uint32 subService, CSSM_SERVICE_TYPE type);
185
186protected:
187	void notify(uint32 subService, CSSM_SERVICE_TYPE type, CSSM_MODULE_EVENT event);
188};
189
190
191//
192// A CSSM loadable module.
193// You rarely directly interact with these objects, but if you need to,
194// here they are.
195//
196class ModuleImpl : public ObjectImpl, public HasGuid
197{
198public:
199	ModuleImpl(const Guid &guid);
200	ModuleImpl(const Guid &guid, const Cssm &session);
201	virtual ~ModuleImpl();
202
203	void load() { activate(); }
204	void unload() { deactivate(); }
205	bool isLoaded() const { return isActive(); }
206
207	Cssm session() const;
208
209	void appNotifyCallback(CSSM_API_ModuleEventHandler appNotifyCallback, void *appNotifyCallbackCtx);
210	void appNotifyCallback(RawModuleEvents *handler);
211
212protected:
213	void activate();
214	void deactivate();
215
216	CSSM_API_ModuleEventHandler mAppNotifyCallback;
217	void *mAppNotifyCallbackCtx;
218};
219
220class Module : public Object
221{
222public:
223	typedef ModuleImpl Impl;
224	explicit Module(Impl *impl) : Object(impl) {}
225	Module() : Object(NULL) {} // XXX This might break operator <
226	Module(const Guid &guid) : Object(new Impl(guid)) {}
227	Module(const Guid &guid, const Cssm &session) : Object(new Impl(guid, session)) {}
228
229	Impl *operator ->() const { return &impl<Impl>(); }
230	Impl &operator *() const { return impl<Impl>(); }
231};
232
233
234//
235// An Attachment object. This is the base class of all typed attachment classes.
236//
237class AttachmentImpl : public ObjectImpl
238{
239public:
240	AttachmentImpl(const Guid &guid, CSSM_SERVICE_TYPE subserviceType);
241	AttachmentImpl(const Module &module, CSSM_SERVICE_TYPE subserviceType);
242	//AttachmentImpl(... mds reference ...);
243	virtual ~AttachmentImpl();
244
245	// Virtual so that subclasses can return there true mask.
246	virtual CSSM_SERVICE_MASK subserviceMask() const;
247
248	CSSM_SERVICE_TYPE subserviceType() const { return mSubserviceType; }
249	CSSM_VERSION version() const { return mVersion; }
250	void version(const CSSM_VERSION &v) { mVersion = v; }
251	uint32 subserviceId() const { return mSubserviceId; }
252	virtual void subserviceId(uint32 id);
253	CSSM_ATTACH_FLAGS flags() const { return mAttachFlags; }
254	void flags(CSSM_ATTACH_FLAGS f) { mAttachFlags = f; }
255
256	void attach() { activate(); }
257	void detach() { deactivate(); }
258	bool attached() const { return isActive(); }
259
260	Module module() const;
261	const Guid &guid() const { return module()->guid(); }
262	CSSM_MODULE_HANDLE handle() { attach(); return mHandle; }
263
264	CssmSubserviceUid subserviceUid() const;
265
266protected:
267	void activate();
268	void deactivate();
269
270private:
271	void make(CSSM_SERVICE_TYPE subserviceType);	// common constructor
272
273	CSSM_MODULE_HANDLE mHandle;
274
275	CSSM_SERVICE_TYPE mSubserviceType;				// set by constructor
276	CSSM_VERSION mVersion;
277	uint32 mSubserviceId;
278	CSSM_ATTACH_FLAGS mAttachFlags;
279
280	CssmAllocatorMemoryFunctions mMemoryFunctions;	// set on attach()
281};
282
283class Attachment : public Object
284{
285public:
286	typedef AttachmentImpl Impl;
287	explicit Attachment(Impl *impl) : Object(impl) {}
288	Attachment(const Guid &guid, CSSM_SERVICE_TYPE subserviceType)
289	: Object(new Impl(guid, subserviceType)) {}
290	Attachment(const Module &module, CSSM_SERVICE_TYPE subserviceType)
291	: Object(new Impl(module, subserviceType)) {}
292	//Attachment(... mds reference ...);
293
294	Impl *operator ->() const { return &impl<Impl>(); }
295	Impl &operator *() const { return impl<Impl>(); }
296};
297
298
299//
300// A CSSM session object.
301// You usually only have one per program, or library, or what-not.
302//
303class Cssm;
304
305class CssmImpl : public ObjectImpl {
306    class StandardCssm; friend class StandardCssm;
307public:
308	CssmImpl();
309	virtual ~CssmImpl();
310
311	void init() { activate(); }
312	void terminate() { deactivate(); }
313
314	CSSM_PRIVILEGE_SCOPE scope() const { return mScope; }
315	void scope(CSSM_PRIVILEGE_SCOPE sc) { mScope = sc; }
316	const Guid &callerGuid() const { return mCallerGuid; }
317	void callerGuid(const CSSM_GUID &guid) { mCallerGuid = Guid::overlay(guid); }
318
319	Module autoModule(const Guid &guid);
320
321protected:
322	explicit CssmImpl(bool);				// internal constructor
323
324	void setup();							// constructor setup
325
326	void activate();
327	void deactivate();
328
329private:
330	// CSSM global configuration -- picked up on each Init
331	CSSM_VERSION mVersion;
332	CSSM_PRIVILEGE_SCOPE mScope;
333	Guid mCallerGuid;
334
335	// module repository: modules by guid (protected by self)
336	typedef map<Guid, Module> ModuleMap;
337	ModuleMap moduleMap;
338	Mutex mapLock;
339
340public:
341	static Cssm standard();
342	static void catchExit();
343
344private:
345	static void atExitHandler();
346
347    class StandardCssm : public Mutex {
348    public:
349        StandardCssm() : mCssm(NULL) { }
350        ~StandardCssm();
351        void setCssm(CssmImpl *cssm);
352        void unsetCssm(CssmImpl *cssm);
353        CssmImpl *get();
354
355    private:
356        CssmImpl *mCssm;
357    };
358    static ModuleNexus<StandardCssm> mStandard;
359};
360
361class Cssm : public Object
362{
363public:
364	typedef CssmImpl Impl;
365	explicit Cssm(Impl *impl) : Object(impl) {}
366	explicit Cssm() : Object(new Impl()) {}
367
368	Impl *operator ->() const { return &impl<Impl>(); }
369	Impl &operator *() const { return impl<Impl>(); }
370
371	static Cssm standard() { return CssmImpl::standard(); }
372};
373
374} // end namespace CssmClient
375
376} // end namespace Security
377
378#endif // _H_CDSA_CLIENT_CSSMCLIENT
379