]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cdsa_client/lib/dlclient.h
6617a392377c616c565f9ba954268f5a43c195b3
[apple/security.git] / OSX / libsecurity_cdsa_client / lib / dlclient.h
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 // dlclient - client interface to CSSM DLs and their operations
21 //
22
23 #ifndef _H_CDSA_CLIENT_DLCLIENT
24 #define _H_CDSA_CLIENT_DLCLIENT 1
25
26 #include <security_cdsa_client/cssmclient.h>
27 #include <security_cdsa_client/dliterators.h>
28 #include <security_cdsa_client/aclclient.h>
29 #include <security_cdsa_client/DLDBList.h>
30 #include <security_cdsa_utilities/cssmacl.h>
31 #include <security_cdsa_utilities/cssmdb.h>
32 #include <security_cdsa_utilities/cssmdata.h>
33
34
35 namespace Security
36 {
37
38 namespace CssmClient
39 {
40
41 #define CSSM_DB_ATTR(ATTR) ATTR
42 #define CSSM_DB_ATTR_SCHEMA(ATTR) ATTR ## Schema
43
44 #define CSSM_DB_INDEX(ATTR) ATTR ## Index
45 #define CSSM_DB_UNIQUE(ATTR) ATTR ## Unique
46
47 //
48 // Helper macro for declaring and defining a Db index unique and non-unique attributes
49 //
50 #define CSSM_DB_INDEX_DECL(ATTR) static const CSSM_DB_INDEX_INFO CSSM_DB_INDEX(ATTR)
51 #define CSSM_DB_UNIQUE_DECL(ATTR) static const CSSM_DB_INDEX_INFO CSSM_DB_UNIQUE(ATTR)
52
53
54 //
55 // Use this macro for defining a non-unique attribute
56 //
57 #define CSSM_DB_INDEX_DEF(ATTR) \
58 const CSSM_DB_INDEX_INFO CSSM_DB_INDEX(ATTR) = \
59 { \
60 CSSM_DB_INDEX_NONUNIQUE, \
61 CSSM_DB_INDEX_ON_ATTRIBUTE, \
62 CSSM_DB_ATTR(ATTR) \
63 }
64
65 //
66 // Use this macro for defining a unique attribute
67
68 //
69 #define CSSM_DB_UNIQUE_DEF(ATTR) \
70 const CSSM_DB_INDEX_INFO CSSM_DB_UNIQUE(ATTR) = \
71 { \
72 CSSM_DB_INDEX_UNIQUE, \
73 CSSM_DB_INDEX_ON_ATTRIBUTE, \
74 CSSM_DB_ATTR(ATTR) \
75 }
76
77
78
79 //
80 // Helper macro for declaring and defining a Db schema attributes
81 // Use this macro in your header to declare each attribute you require.
82 //
83 #define CSSM_DB_ATTR_DECL(ATTR) \
84 static const CSSM_DB_ATTRIBUTE_INFO CSSM_DB_ATTR(ATTR); \
85 static const CSSM_DB_SCHEMA_ATTRIBUTE_INFO CSSM_DB_ATTR_SCHEMA(ATTR)
86
87 //
88 // Don't directly use this macro use one of the below instead.
89 //
90 #define CSSM_DB_ATTR_DEFINE_SCHEMA(ATTR, INTEGER, NAME, OID_LEN, OID_DATA, VALUETYPE) \
91 const CSSM_DB_SCHEMA_ATTRIBUTE_INFO CSSM_DB_ATTR_SCHEMA(ATTR) = \
92 { \
93 INTEGER, \
94 NAME, \
95 { OID_LEN, OID_DATA }, \
96 CSSM_DB_ATTRIBUTE_FORMAT_ ## VALUETYPE \
97 }
98
99
100 //
101 // Use one of the following macros to defined each declared attribute required by your application.
102 //
103 //
104 // Use this macro to define attributes which are looked up by integer AttributeID.
105 //
106 #define CSSM_DB_INTEGER_ATTR(ATTR, INTEGER, NAME, OID_LEN, OID_DATA, VALUETYPE) \
107 const CSSM_DB_ATTRIBUTE_INFO ATTR = \
108 { \
109 CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER, \
110 {(char *)INTEGER}, \
111 CSSM_DB_ATTRIBUTE_FORMAT_ ## VALUETYPE \
112 };\
113 \
114 CSSM_DB_ATTR_DEFINE_SCHEMA(ATTR, INTEGER, NAME, OID_LEN, OID_DATA, VALUETYPE)
115
116 //
117 // Use this macro to define attributes which are looked up by string AttributeName.
118 //
119 #define CSSM_DB_NAME_ATTR(ATTR, INTEGER, NAME, OID_LEN, OID_DATA, VALUETYPE) \
120 const CSSM_DB_ATTRIBUTE_INFO ATTR = \
121 { \
122 CSSM_DB_ATTRIBUTE_NAME_AS_STRING, \
123 {NAME}, \
124 CSSM_DB_ATTRIBUTE_FORMAT_ ## VALUETYPE \
125 };\
126 \
127 CSSM_DB_ATTR_DEFINE_SCHEMA(ATTR, INTEGER, NAME, OID_LEN, OID_DATA, VALUETYPE)
128
129 //
130 // Use this macro to define attributes which are looked up by OID AttributeNameID.
131 // XXX This does not work yet.
132 //
133 #define CSSM_DB_OID_ATTR(ATTR, INTEGER, NAME, OID_LEN, OID_DATA, VALUETYPE) \
134 const CSSM_DB_ATTRIBUTE_INFO ATTR = \
135 { \
136 CSSM_DB_ATTRIBUTE_NAME_AS_OID, \
137 {{OID_LEN, OID_DATA}}, \
138 CSSM_DB_ATTRIBUTE_FORMAT_ ## VALUETYPE \
139 };\
140 \
141 CSSM_DB_ATTR_DEFINE_SCHEMA(ATTR, INTEGER, NAME, OID_LEN, OID_DATA, VALUETYPE)
142
143
144 //
145 // Use this macro to define attributes which are part of the primary key.
146 //
147 #define CSSM_DB_PRIMARKEY_ATTR(ATTR, NAME) \
148 const CSSM_DB_ATTRIBUTE_INFO ATTR = \
149 { \
150 CSSM_DB_INDEX_UNIQUE, \
151 CSSM_DB_INDEX_ON_ATTRIBUTE, \
152 CSSM_DB_ATTRIBUTE_FORMAT_ ## VALUETYPE \
153 };\
154 \
155 CSSM_DB_ATTR_DEFINE_SCHEMA(ATTR, INTEGER, NAME, OID_LEN, OID_DATA, VALUETYPE)
156
157
158
159 //
160 // Maker interfaces used by various Impl objects
161 //
162
163 // DbMaker -- someone who can create a new DbImpl.
164 class DbImpl;
165 class DbMaker
166 {
167 public:
168 virtual ~DbMaker();
169 virtual DbImpl *newDb(const char *inDbName, const CSSM_NET_ADDRESS *inDbLocation) = 0;
170 };
171
172 // DbCursorMaker -- someone who can create a new DbCursorImpl.
173 class DbCursorImpl;
174 class DbCursorMaker
175 {
176 public:
177 virtual ~DbCursorMaker();
178 virtual DbCursorImpl *newDbCursor(const CSSM_QUERY &query, Allocator &allocator) = 0;
179 virtual DbCursorImpl *newDbCursor(uint32 capacity, Allocator &allocator) = 0;
180 };
181
182 // DbUniqueRecordMaker -- someone who can create a new DbUniqueRecordImpl.
183 class DbUniqueRecordImpl;
184 class DbUniqueRecordMaker
185 {
186 public:
187 virtual ~DbUniqueRecordMaker();
188 virtual DbUniqueRecordImpl *newDbUniqueRecord() = 0;
189 };
190
191
192 //
193 // A DL attachment
194 //
195 class DLImpl : public AttachmentImpl, public DbMaker
196 {
197 public:
198 DLImpl(const Guid &guid);
199 DLImpl(const Module &module);
200 virtual ~DLImpl();
201
202 virtual void getDbNames(char **);
203 virtual void freeNameList(char **);
204
205 // DbMaker
206 virtual DbImpl *newDb(const char *inDbName, const CSSM_NET_ADDRESS *inDbLocation);
207 private:
208 };
209
210 class DL : public Attachment
211 {
212 public:
213 typedef DLImpl Impl;
214
215 explicit DL(Impl *impl) : Attachment(impl) {}
216 DL() : Attachment(NULL) {}
217 DL(const Guid &guid) : Attachment(new Impl(guid)) {}
218 DL(const Module &module) : Attachment(new Impl(module)) {}
219
220 Impl *operator ->() const { return &impl<Impl>(); }
221 Impl &operator *() const { return impl<Impl>(); }
222
223 // Conversion to DbMaker.
224 operator DbMaker &() const { return impl<Impl>(); }
225 };
226
227
228 class DbAttributes;
229 class DbUniqueRecord;
230 class Db;
231
232
233 //
234 // A CSSM_DLDB handle.
235 // Dbs always belong to DLs (DL attachments)
236 //
237 class DbImpl : public ObjectImpl, public AclBearer,
238 public DbCursorMaker, public DbUniqueRecordMaker
239 {
240 public:
241 DbImpl(const DL &dl, const char *inDbName = NULL, const CSSM_NET_ADDRESS *inDbLocation = NULL);
242 virtual ~DbImpl();
243
244 DL dl() const { return parent<DL>(); }
245 Module module() const { return dl()->module(); }
246
247 virtual void open();
248 virtual void create();
249 virtual void createWithBlob (CssmData &blob);
250 virtual void close();
251 virtual void deleteDb();
252 virtual void rename(const char *newName);
253 virtual void authenticate(CSSM_DB_ACCESS_TYPE inAccessRequest,
254 const CSSM_ACCESS_CREDENTIALS *inAccessCredentials);
255 virtual void name(char *&outName); // CSSM_DL_GetDbNameFromHandle()
256
257 virtual void createRelation(CSSM_DB_RECORDTYPE inRelationID,
258 const char *inRelationName,
259 uint32 inNumberOfAttributes,
260 const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *pAttributeInfo,
261 uint32 inNumberOfIndexes,
262 const CSSM_DB_SCHEMA_INDEX_INFO *pIndexInfo);
263 virtual void destroyRelation(CSSM_DB_RECORDTYPE inRelationID);
264
265 virtual DbUniqueRecord insert(CSSM_DB_RECORDTYPE recordType,
266 const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
267 const CSSM_DATA *data);
268
269 virtual DbUniqueRecord insertWithoutEncryption(CSSM_DB_RECORDTYPE recordType,
270 const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
271 CSSM_DATA *data);
272
273 const CSSM_DL_DB_HANDLE &handle() { activate(); return mHandle; }
274
275 const DbName &dbName() { return mDbName; }
276 void dbName(const DbName &dbName) { mDbName = dbName; }
277
278 // Attempt to get a (cached) name from CSSM_DL_GetDbNameFromHandle(), falls
279 // back to the name passed in to the constructor if this fails.
280 const char *name();
281
282 const CSSM_NET_ADDRESS *dbLocation() const { return mDbName.dbLocation(); }
283
284 CSSM_DB_ACCESS_TYPE accessRequest() const { return mAccessRequest; }
285 void accessRequest(CSSM_DB_ACCESS_TYPE inAccessRequest)
286 { mAccessRequest = inAccessRequest; }
287
288 const CSSM_ACCESS_CREDENTIALS *accessCredentials() const
289 { return mAccessCredentials; }
290 void accessCredentials(const CSSM_ACCESS_CREDENTIALS *inAccessCredentials)
291 { mAccessCredentials = inAccessCredentials; }
292
293 const void *openParameters() const { return mOpenParameters; }
294 void openParameters(const void *inOpenParameters)
295 { mOpenParameters = inOpenParameters; }
296
297 const CSSM_DBINFO *dbInfo() const { return mDbInfo; }
298 void dbInfo(const CSSM_DBINFO *inDbInfo) { mDbInfo = inDbInfo; }
299
300 const ResourceControlContext *resourceControlContext() const
301 { return mResourceControlContext; }
302 void resourceControlContext(const CSSM_RESOURCE_CONTROL_CONTEXT *inResourceControlContext)
303 { mResourceControlContext = ResourceControlContext::overlay(inResourceControlContext); }
304
305 void passThrough(uint32 passThroughId, const void *in, void **out = NULL);
306
307 template <class TIn, class TOut>
308 void passThrough(uint32 passThroughId, const TIn *in, TOut *out = NULL)
309 { passThrough(passThroughId, (const void *)in, (void **)out); }
310
311 // Passthrough functions (only implemented by AppleCSPDL).
312 virtual void lock();
313 virtual void unlock();
314 virtual void unlock(const CSSM_DATA &password);
315 virtual void stash();
316 virtual void stashCheck();
317 virtual void getSettings(uint32 &outIdleTimeout, bool &outLockOnSleep);
318 virtual void setSettings(uint32 inIdleTimeout, bool inLockOnSleep);
319 virtual bool isLocked();
320 virtual void changePassphrase(const CSSM_ACCESS_CREDENTIALS *cred);
321 virtual void recode(const CSSM_DATA &data, const CSSM_DATA &extraData);
322 virtual void copyBlob(CssmData &data);
323 virtual void setBatchMode(Boolean mode, Boolean rollback);
324
325 // Get the version of this database's encoding
326 virtual uint32 dbBlobVersion();
327
328 // Attempt to recode this database to the new version
329 virtual uint32 recodeDbToVersion(uint32 version);
330
331 // Try to take or release the file lock on the underlying database.
332 // You _must_ call these as a pair. They start a transaction on the
333 // underlying DL object, and that transaction is only finished when release
334 // is called. Pass success=true if you want the transaction to commit; otherwise
335 // it will roll back.
336 virtual void takeFileLock();
337 virtual void releaseFileLock(bool success);
338
339 // Make a backup of this database on the filesystem
340 virtual void makeBackup();
341
342
343 // Utility methods
344
345 // Always use the dbName and dbLocation that were passed in during
346 // construction.
347 virtual DLDbIdentifier dlDbIdentifier();
348
349 // DbCursorMaker
350 virtual DbCursorImpl *newDbCursor(const CSSM_QUERY &query, Allocator &allocator);
351 virtual DbCursorImpl *newDbCursor(uint32 capacity, Allocator &allocator);
352
353 // DbUniqueRecordMaker
354 virtual DbUniqueRecordImpl *newDbUniqueRecord();
355
356 // Acl manipulation
357 void getAcl(AutoAclEntryInfoList &aclInfos, const char *selectionTag = NULL) const;
358 void changeAcl(const CSSM_ACL_EDIT &aclEdit,
359 const CSSM_ACCESS_CREDENTIALS *accessCred);
360
361 // Acl owner manipulation
362 void getOwner(AutoAclOwnerPrototype &owner) const;
363 void changeOwner(const CSSM_ACL_OWNER_PROTOTYPE &newOwner,
364 const CSSM_ACCESS_CREDENTIALS *accessCred = NULL);
365
366 // default-credential hook
367 class DefaultCredentialsMaker {
368 public:
369 virtual ~DefaultCredentialsMaker();
370 virtual const AccessCredentials *makeCredentials() = 0;
371 };
372
373 void defaultCredentials(DefaultCredentialsMaker *maker); // NULL to turn off
374
375 void activate();
376
377 protected:
378 void deactivate();
379
380 private:
381 CSSM_DL_DB_HANDLE mHandle; // CSSM DLDB handle
382
383 DbName mDbName;
384 bool mUseNameFromHandle; // false if CSSM_DL_GetDbNameFromHandle failed
385 char *mNameFromHandle; // Cached CSSM_DL_GetDbNameFromHandle result.
386 CSSM_DB_ACCESS_TYPE mAccessRequest;
387 const CSSM_ACCESS_CREDENTIALS *mAccessCredentials;
388 DefaultCredentialsMaker *mDefaultCredentials;
389 const void *mOpenParameters;
390
391 // Arguments to create
392 const CSSM_DBINFO *mDbInfo;
393 const ResourceControlContext *mResourceControlContext;
394 };
395
396
397 class Db : public Object, public DLAccess
398 {
399 public:
400 typedef DbImpl Impl;
401 typedef Impl::DefaultCredentialsMaker DefaultCredentialsMaker;
402
403 explicit Db(Impl *impl) : Object(impl) {}
404 Db() : Object(NULL) {}
405 Db(DbMaker &maker, const char *inDbName, const CSSM_NET_ADDRESS *inDbLocation = NULL)
406 : Object(maker.newDb(inDbName, inDbLocation)) {}
407
408 Impl *operator ->() const { return &impl<Impl>(); }
409 Impl &operator *() const { return impl<Impl>(); }
410
411 // Conversion to DbCursorMaker.
412 operator DbCursorMaker &() const { return impl<Impl>(); }
413 // Conversion to DbUniqueRecordMaker.
414 operator DbUniqueRecordMaker &() const { return impl<Impl>(); }
415
416 const CSSM_DL_DB_HANDLE &handle() { return impl<Impl>().handle(); }
417
418 protected:
419 // DLAccess adapters
420 CSSM_HANDLE dlGetFirst(const CSSM_QUERY &query,
421 CSSM_DB_RECORD_ATTRIBUTE_DATA &attributes, CSSM_DATA *data,
422 CSSM_DB_UNIQUE_RECORD *&id);
423 bool dlGetNext(CSSM_HANDLE handle,
424 CSSM_DB_RECORD_ATTRIBUTE_DATA &attributes, CSSM_DATA *data,
425 CSSM_DB_UNIQUE_RECORD *&id);
426 void dlAbortQuery(CSSM_HANDLE handle);
427 void dlFreeUniqueId(CSSM_DB_UNIQUE_RECORD *id);
428 void dlDeleteRecord(CSSM_DB_UNIQUE_RECORD *id);
429 Allocator &allocator();
430 };
431
432 //
433 // DbCursor
434 //
435
436 // This class is still abstract. You must subclass it in order to be able to instantiate an instance.
437 class DbCursorImpl : public ObjectImpl, public CssmAutoQuery
438 {
439 public:
440 DbCursorImpl(const Object &parent, const CSSM_QUERY &query, Allocator &allocator);
441 DbCursorImpl(const Object &parent, uint32 capacity, Allocator &allocator);
442
443 virtual Allocator &allocator() const;
444 virtual void allocator(Allocator &alloc);
445
446 virtual bool next(DbAttributes *attributes, ::CssmDataContainer *data, DbUniqueRecord &uniqueId) = 0;
447 void abort() { deactivate(); }
448 };
449
450 class DbCursor : public Object
451 {
452 public:
453 typedef DbCursorImpl Impl;
454
455 explicit DbCursor(Impl *impl) : Object(impl) {}
456 DbCursor() : Object(NULL) {}
457 DbCursor(DbCursorMaker &maker, const CSSM_QUERY &query,
458 Allocator &allocator = Allocator::standard())
459 : Object(maker.newDbCursor(query, allocator)) {}
460 DbCursor(DbCursorMaker &maker, uint32 capacity = 0,
461 Allocator &allocator = Allocator::standard())
462 : Object(maker.newDbCursor(capacity, allocator)) {}
463
464 Impl *operator ->() const { return &impl<Impl>(); }
465 Impl &operator *() const { return impl<Impl>(); }
466 };
467
468
469 //
470 // DbUniqueRecord
471 //
472 class DbUniqueRecordImpl : public ObjectImpl
473 {
474 public:
475 DbUniqueRecordImpl(const Db &db);
476 virtual ~DbUniqueRecordImpl();
477
478 virtual void deleteRecord();
479 virtual void modify(CSSM_DB_RECORDTYPE recordType,
480 const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
481 const CSSM_DATA *data,
482 CSSM_DB_MODIFY_MODE modifyMode);
483
484 virtual void modifyWithoutEncryption (CSSM_DB_RECORDTYPE recordType,
485 const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
486 const CSSM_DATA *data,
487 CSSM_DB_MODIFY_MODE modifyMode);
488
489 virtual void get(DbAttributes *attributes, ::CssmDataContainer *data);
490
491 virtual void getWithoutEncryption(DbAttributes *attributes, ::CssmDataContainer *data);
492
493 Db database() const { return parent<Db>(); }
494
495 void free() { deactivate(); }
496
497 // Client must call activate() after calling this function if mUniqueId is successfully set.
498 operator CSSM_DB_UNIQUE_RECORD_PTR *() { if (mActive) free(); return &mUniqueId; }
499
500 operator CSSM_DB_UNIQUE_RECORD *() { return mUniqueId; }
501 operator const CSSM_DB_UNIQUE_RECORD *() const { return mUniqueId; }
502
503 void activate();
504
505 void getRecordIdentifier(CSSM_DATA &data);
506
507 void setUniqueRecordPtr (CSSM_DB_UNIQUE_RECORD_PTR uniquePtr); // because cast overloading is evil!
508
509 protected:
510 void deactivate();
511
512 CSSM_DB_UNIQUE_RECORD_PTR mUniqueId;
513 bool mDestroyID;
514 RecursiveMutex mActivateMutex;
515 };
516
517 class DbUniqueRecord : public Object
518 {
519 public:
520 typedef DbUniqueRecordImpl Impl;
521
522 explicit DbUniqueRecord(Impl *impl) : Object(impl) {}
523 DbUniqueRecord() : Object(NULL) {}
524 DbUniqueRecord(DbUniqueRecordMaker &maker) : Object(maker.newDbUniqueRecord()) {}
525
526 Impl *operator ->() { return &impl<Impl>(); }
527 Impl &operator *() { return impl<Impl>(); }
528 const Impl &operator *() const { return impl<Impl>(); }
529
530 // Conversion operators must be here.
531
532 // Client must activate after calling this function if mUniqueId is successfully set.
533 operator CSSM_DB_UNIQUE_RECORD_PTR *() { return **this; }
534
535 operator CSSM_DB_UNIQUE_RECORD *() { return **this; }
536 operator const CSSM_DB_UNIQUE_RECORD *() const { return **this; }
537 };
538
539
540 //
541 // DbAttributes
542 //
543 class DbAttributes : public CssmAutoDbRecordAttributeData
544 {
545 public:
546 DbAttributes();
547 DbAttributes(const Db &db, uint32 capacity = 0, Allocator &allocator = Allocator::standard());
548
549 // Similar to CssmAutoDbRecordAttributeData::updateWith, but a different
550 // signature. Will canonicalize the elements in both this and the newValues dbAttributes.
551 void updateWithDbAttributes(DbAttributes* newValues);
552
553 // Try to change the infos in this database to a canonicalized form
554 void canonicalize();
555 };
556
557
558 //
559 // DbDbCursor -- concrete subclass of DbCursorImpl for querying Db's
560 //
561 class DbDbCursorImpl : public DbCursorImpl
562 {
563 public:
564 DbDbCursorImpl(const Db &db, const CSSM_QUERY &query, Allocator &allocator);
565 DbDbCursorImpl(const Db &db, uint32 capacity, Allocator &allocator);
566 virtual ~DbDbCursorImpl();
567
568 bool next(DbAttributes *attributes, ::CssmDataContainer *data, DbUniqueRecord &uniqueId);
569
570 protected:
571 Db database() { return parent<Db>(); }
572
573 void activate();
574 void deactivate();
575
576 private:
577 CSSM_HANDLE mResultsHandle;
578 RecursiveMutex mActivateMutex;
579 };
580
581 } // end namespace CssmClient
582
583 } // end namespace Security
584
585 #endif // _H_CDSA_CLIENT_DLCLIENT