#include <stdlib.h>
#include <unistd.h>
#include <Security/cssmapi.h>
#include <Security/cssmapple.h>
#include "testmore.h"
#include "testenv.h"
#include "testcssm.h"
#include "testleaks.h"
#define DBNAME "testdl"
CSSM_APPLEDL_OPEN_PARAMETERS openParameters =
{
sizeof(CSSM_APPLEDL_OPEN_PARAMETERS),
CSSM_APPLEDL_OPEN_PARAMETERS_VERSION,
CSSM_FALSE,
kCSSM_APPLEDL_MASK_MODE,
0600
};
CSSM_DBINFO dbInfo =
{
0 ,
NULL,
NULL,
NULL,
CSSM_TRUE ,
NULL,
NULL
};
CSSM_DB_SCHEMA_ATTRIBUTE_INFO attributeInfo[] =
{
{
1,
"string-1",
{},
CSSM_DB_ATTRIBUTE_FORMAT_STRING
},
{
2,
"sint32-2",
{},
CSSM_DB_ATTRIBUTE_FORMAT_SINT32
},
{
3,
"uint32-3",
{},
CSSM_DB_ATTRIBUTE_FORMAT_UINT32
},
{
4,
"big_num-4",
{},
CSSM_DB_ATTRIBUTE_FORMAT_BIG_NUM
},
{
5,
"real-5",
{},
CSSM_DB_ATTRIBUTE_FORMAT_REAL
},
{
6,
"time-date-6",
{},
CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
},
{
7,
"blob-7",
{},
CSSM_DB_ATTRIBUTE_FORMAT_BLOB
},
{
8,
"multi-uint32-8",
{},
CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32
},
#if 0
{
9,
"complex-9",
{},
CSSM_DB_ATTRIBUTE_FORMAT_COMPLEX
}
#endif
};
CSSM_DB_SCHEMA_INDEX_INFO indexInfo[] =
{
{
1,
0,
CSSM_DB_INDEX_UNIQUE,
CSSM_DB_INDEX_ON_ATTRIBUTE
},
{
1,
1,
CSSM_DB_INDEX_NONUNIQUE,
CSSM_DB_INDEX_ON_ATTRIBUTE
},
{
2,
2,
CSSM_DB_INDEX_NONUNIQUE,
CSSM_DB_INDEX_ON_ATTRIBUTE
}
};
CSSM_DATA values_str_1[] =
{
{ 7, (uint8 *)"value-1" }
};
CSSM_DATA values_str_2[] =
{
{ 7, (uint8 *)"value-2" }
};
CSSM_DATA values_sint32_1[] =
{
{ sizeof(sint32), (uint8 *)"1111" }
};
CSSM_DATA values_sint32_2[] =
{
{ sizeof(sint32), (uint8 *)"2222" }
};
CSSM_DB_ATTRIBUTE_DATA attributeData[] =
{
{
{
CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER,
{ (char *)((uint64_t)1<<32|1) },
CSSM_DB_ATTRIBUTE_FORMAT_STRING
},
sizeof(values_str_1) / sizeof(CSSM_DATA),
values_str_1
},
{
{
CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER,
{ (char *)((uint64_t)2<<32|2) },
CSSM_DB_ATTRIBUTE_FORMAT_SINT32
},
sizeof(values_sint32_1) / sizeof(CSSM_DATA),
values_sint32_1
}
};
CSSM_DB_RECORD_ATTRIBUTE_DATA attributes =
{
42,
0x00008000,
sizeof(attributeData) / sizeof(CSSM_DB_ATTRIBUTE_DATA),
attributeData
};
CSSM_DB_ATTRIBUTE_DATA newAttributeData[] =
{
{
{
CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER,
{ (char *)((uint64_t)1<<32|1) },
CSSM_DB_ATTRIBUTE_FORMAT_STRING
},
sizeof(values_str_2) / sizeof(CSSM_DATA),
values_str_2
},
{
{
CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER,
{ (char *)((uint64_t)2<<32|2) },
CSSM_DB_ATTRIBUTE_FORMAT_SINT32
},
sizeof(values_sint32_2) / sizeof(CSSM_DATA),
values_sint32_2
}
};
CSSM_DB_RECORD_ATTRIBUTE_DATA newAttributes =
{
42,
0x80000001,
sizeof(newAttributeData) / sizeof(CSSM_DB_ATTRIBUTE_DATA),
newAttributeData
};
static void free_attributes_data(const CSSM_API_MEMORY_FUNCS *memfuncs,
CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR attributes, CSSM_DATA_PTR data)
{
if (data && data->Data)
{
memfuncs->free_func(data->Data, memfuncs->AllocRef);
data->Data = NULL;
}
if (attributes && attributes->AttributeData)
{
uint32 aix;
for (aix = 0; aix < attributes->NumberOfAttributes; ++aix)
{
if (attributes->AttributeData[aix].Value)
{
uint32 vix;
for (vix = 0;
vix < attributes->AttributeData[aix].NumberOfValues; ++vix)
{
if (attributes->AttributeData[aix].Value[vix].Data)
{
memfuncs->free_func(
attributes->AttributeData[aix].Value[vix].Data,
memfuncs->AllocRef);
}
}
memfuncs->free_func(attributes->AttributeData[aix].Value,
memfuncs->AllocRef);
attributes->AttributeData[aix].NumberOfValues = 0;
attributes->AttributeData[aix].Value = NULL;
}
}
}
}
static int test_is_attributes_data(
const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes1, const CSSM_DATA *data1,
const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes2, const CSSM_DATA *data2,
const char *description, const char *directive,
const char *reason, const char *file, unsigned line)
{
if (attributes1 || attributes2)
{
if (!attributes1 || !attributes2)
return test_ok(0, description, directive, reason, file, line,
"# got CSSM_DB_RECORD_ATTRIBUTE_DATA %p\n"
"# expected CSSM_DB_RECORD_ATTRIBUTE_DATA %p\n",
attributes1, attributes2);
if (attributes1->DataRecordType != attributes2->DataRecordType ||
attributes1->SemanticInformation !=
attributes2->SemanticInformation ||
attributes1->NumberOfAttributes != attributes2->NumberOfAttributes)
return test_ok(0, description, directive, reason, file, line,
"# got CSSM_DB_RECORD_ATTRIBUTE_DATA:\n"
"# DataRecordType: %08x\n"
"# SemanticInformation: %08x\n"
"# NumberOfAttributes: %lu\n"
"# expected CSSM_DB_RECORD_ATTRIBUTE_DATA:\n"
"# DataRecordType: %08x\n"
"# SemanticInformation: %08x\n"
"# NumberOfAttributes: %lu\n",
attributes1->DataRecordType,
attributes1->SemanticInformation,
attributes1->NumberOfAttributes,
attributes2->DataRecordType,
attributes2->SemanticInformation,
attributes2->NumberOfAttributes);
uint32 ai;
for (ai = 0; ai < attributes1->NumberOfAttributes; ++ai)
{
const CSSM_DB_ATTRIBUTE_DATA *a1 = &attributes1->AttributeData[ai];
const CSSM_DB_ATTRIBUTE_DATA *a2 = &attributes2->AttributeData[ai];
if (a1->Info.AttributeFormat != a2->Info.AttributeFormat ||
a1->NumberOfValues != a2->NumberOfValues)
return test_ok(0, description, directive, reason, file, line,
"# got AttributeData[%lu]:\n"
"# AttributeFormat: %08x\n"
"# NumberOfValues: %lu\n"
"# expected AttributeData[%lu]:\n"
"# AttributeFormat: %08x\n"
"# NumberOfValues: %lu\n",
ai, a1->Info.AttributeFormat, a1->NumberOfValues,
ai, a2->Info.AttributeFormat, a2->NumberOfValues);
uint32 vi;
for (vi = 0; vi < a1->NumberOfValues; ++vi)
{
const CSSM_DATA *d1 = &a1->Value[vi];
const CSSM_DATA *d2 = &a2->Value[vi];
if (d1->Length != d2->Length || !d1->Data || !d2->Data ||
memcmp(d1->Data, d2->Data, d1->Length))
return test_ok(d1->Data == d2->Data, description,
directive, reason, file, line,
"# got AttributeData[%lu].Value[%lu]:\n"
"# length: %lu\n"
"# data: '%.*s'\n"
"# expected AttributeData[%lu].Value[%lu]:\n"
"# length: %lu\n"
"# data: '%.*s'\n",
ai, vi, d1->Length, (int)d1->Length, d1->Data,
ai, vi, d2->Length, (int)d2->Length, d2->Data);
}
}
}
if (data1 || data2)
{
if (!data1 || !data2)
return test_ok(0, description, directive, reason, file, line,
"# got CSSM_DATA %p\n"
"# expected CSSM_DATA %p\n", data1, data2);
if (data1->Length != data2->Length || !data1->Data || !data2->Data ||
memcmp(data1->Data, data2->Data, data1->Length))
return test_ok(data1->Data == data2->Data, description, directive,
reason, file, line,
"# got CSSM_DATA:\n"
"# length: %lu\n"
"# data: '%.*s'\n"
"# expected CSSM_DATA:\n"
"# length: %lu\n"
"# data: '%.*s'\n",
data1->Length, (int)data1->Length, data1->Data,
data2->Length, (int)data2->Length, data2->Data);
}
return test_ok(1, description, directive, reason, file, line, NULL);
}
#define is_attributes_data(A1, D1, A2, D2, TESTNAME) \
( \
test_is_attributes_data((A1), (D1), (A2), (D2), \
TESTNAME, test_directive, test_reason, __FILE__, __LINE__) \
)
static void test1(CSSM_DL_HANDLE dl)
{
CSSM_DL_DB_HANDLE dldb = { dl };
CSSM_DB_UNIQUE_RECORD_PTR uniqueId;
CSSM_DATA data = { 4, (uint8 *)"test" };
ok_status(CSSM_DL_DbCreate(dl, DBNAME, NULL ,
&dbInfo,
CSSM_DB_ACCESS_READ | CSSM_DB_ACCESS_WRITE,
NULL ,
NULL ,
&dldb.DBHandle),
"CSSM_DL_DbCreate");
is_status(CSSM_DL_DataInsert(dldb,
attributes.DataRecordType,
&attributes,
&data,
&uniqueId),
CSSMERR_DL_INVALID_RECORDTYPE, "CSSM_DL_DataInsert no table");
ok_status(CSSM_DL_CreateRelation(dldb,
42,
"Fourty Two",
sizeof(attributeInfo) / sizeof(CSSM_DB_SCHEMA_ATTRIBUTE_INFO),
attributeInfo,
sizeof(indexInfo) / sizeof(CSSM_DB_SCHEMA_INDEX_INFO),
indexInfo), "CSSM_DL_CreateRelation");
ok_status(CSSM_DL_DataInsert(dldb,
attributes.DataRecordType,
&attributes,
&data,
&uniqueId), "CSSM_DL_DataInsert");
is_status(CSSM_DL_DataInsert(dldb,
attributes.DataRecordType,
&attributes,
&data,
&uniqueId),
CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA, "CSSM_DL_DataInsert dupe");
ok_status(CSSM_DL_DataModify(dldb,
attributes.DataRecordType,
uniqueId,
&newAttributes,
&data,
CSSM_DB_MODIFY_ATTRIBUTE_REPLACE), "CSSM_DL_DataModify");
ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
"CSSM_DL_FreeUniqueRecord");
ok_status(CSSM_DL_DataInsert(dldb,
attributes.DataRecordType,
&attributes,
&data,
&uniqueId), "CSSM_DL_DataInsert old one again");
CSSM_API_MEMORY_FUNCS memfuncs = {};
ok_status(CSSM_GetAPIMemoryFunctions(dldb.DLHandle, &memfuncs),
"CSSM_GetAPIMemoryFunctions");
ok_status(CSSM_DL_DataGetFromUniqueRecordId(dldb, uniqueId, NULL, NULL),
"CSSM_DL_DataGetFromUniqueRecordId get nothing");
CSSM_DATA resultData = {};
ok_status(CSSM_DL_DataGetFromUniqueRecordId(dldb, uniqueId,
NULL, &resultData),
"CSSM_DL_DataGetFromUniqueRecordId get data");
is_attributes_data(NULL, &resultData, NULL, &data, "Does data match?");
free_attributes_data(&memfuncs, NULL, &resultData);
CSSM_DB_RECORD_ATTRIBUTE_DATA baseNoAttrs = attributes;
baseNoAttrs.NumberOfAttributes = 0;
baseNoAttrs.AttributeData = NULL;
CSSM_DB_RECORD_ATTRIBUTE_DATA resultNoAttrs = {};
ok_status(CSSM_DL_DataGetFromUniqueRecordId(dldb, uniqueId,
&resultNoAttrs, NULL),
"CSSM_DL_DataGetFromUniqueRecordId get 0 attributes");
is_attributes_data(&resultNoAttrs, NULL, &baseNoAttrs, NULL,
"Do attrs match?");
free_attributes_data(&memfuncs, &resultNoAttrs, NULL);
ok_status(CSSM_DL_DataGetFromUniqueRecordId(dldb, uniqueId,
&resultNoAttrs, &resultData),
"CSSM_DL_DataGetFromUniqueRecordId get data and 0 attributes");
is_attributes_data(&resultNoAttrs, &resultData, &baseNoAttrs, &data,
"Do attrs and data match?");
free_attributes_data(&memfuncs, &resultNoAttrs, &resultData);
CSSM_DB_ATTRIBUTE_DATA resultAttributeData[] =
{
{{ CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER, { (char *)((uint64_t)1<<32|1) } }},
{{ CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER, { (char *)((uint64_t)2<<32|2) } }}
};
CSSM_DB_RECORD_ATTRIBUTE_DATA resultAttrs =
{
0, 0,
sizeof(resultAttributeData) / sizeof(*resultAttributeData),
resultAttributeData
};
ok_status(CSSM_DL_DataGetFromUniqueRecordId(dldb, uniqueId,
&resultAttrs, &resultData),
"CSSM_DL_DataGetFromUniqueRecordId get data and 2 attributes");
is_attributes_data(&resultAttrs, &resultData, &attributes, &data,
"Do attrs and data match?");
free_attributes_data(&memfuncs, &resultAttrs, &resultData);
ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
"CSSM_DL_FreeUniqueRecord");
CSSM_SELECTION_PREDICATE predicates[] =
{
{
CSSM_DB_EQUAL,
{
{ CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER, { (char *)((uint64_t)1<<32|1) } },
1, values_str_1
}
}
};
CSSM_QUERY query =
{
attributes.DataRecordType,
CSSM_DB_AND,
sizeof(predicates) / sizeof(*predicates),
predicates,
{ CSSM_QUERY_TIMELIMIT_NONE, CSSM_QUERY_SIZELIMIT_NONE },
0
};
CSSM_HANDLE search = CSSM_INVALID_HANDLE;
is_status(CSSM_DL_DataGetFirst(dldb, &query, NULL,
NULL, NULL, NULL), CSSM_ERRCODE_INVALID_POINTER,
"CSSM_DL_DataGetFirst no search handle, no unique_record");
is_status(CSSM_DL_DataGetFirst(dldb, &query, &search,
NULL, NULL, NULL), CSSM_ERRCODE_INVALID_POINTER,
"CSSM_DL_DataGetFirst no unique_record");
is_status(CSSM_DL_DataGetFirst(dldb, &query, NULL,
NULL, NULL, &uniqueId), CSSM_ERRCODE_INVALID_POINTER,
"CSSM_DL_DataGetFirst no search handle");
ok_status(CSSM_DL_DataGetFirst(dldb, &query, &search,
NULL, NULL, &uniqueId),
"CSSM_DL_DataGetFirst no data no attrs");
ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
"CSSM_DL_FreeUniqueRecord");
ok_status(CSSM_DL_DataAbortQuery(dldb, search),
"CSSM_DL_DataAbortQuery");
ok_status(CSSM_DL_DataGetFirst(dldb, &query, &search,
&resultNoAttrs, NULL, &uniqueId),
"CSSM_DL_DataGetFirst 0 attrs");
is_attributes_data(&resultNoAttrs, NULL, &baseNoAttrs, NULL,
"Do attrs match?");
free_attributes_data(&memfuncs, &resultNoAttrs, NULL);
ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
"CSSM_DL_FreeUniqueRecord");
ok_status(CSSM_DL_DataAbortQuery(dldb, search),
"CSSM_DL_DataAbortQuery");
ok_status(CSSM_DL_DataGetFirst(dldb, &query, &search,
NULL, &resultData, &uniqueId),
"CSSM_DL_DataGetFirst data");
is_attributes_data(NULL, &resultData, NULL, &data, "Does data match?");
free_attributes_data(&memfuncs, NULL, &resultData);
ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
"CSSM_DL_FreeUniqueRecord");
ok_status(CSSM_DL_DataAbortQuery(dldb, search),
"CSSM_DL_DataAbortQuery");
ok_status(CSSM_DL_DataGetFirst(dldb, &query, &search,
&resultNoAttrs, &resultData, &uniqueId),
"CSSM_DL_DataGetFirst 0 attrs and data");
is_attributes_data(&resultNoAttrs, &resultData, &baseNoAttrs, &data,
"Do attrs and data match?");
free_attributes_data(&memfuncs, &resultNoAttrs, &resultData);
ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
"CSSM_DL_FreeUniqueRecord");
ok_status(CSSM_DL_DataAbortQuery(dldb, search),
"CSSM_DL_DataAbortQuery");
ok_status(CSSM_DL_DataGetFirst(dldb, &query, &search,
&resultAttrs, &resultData, &uniqueId),
"CSSM_DL_DataGetFirst 2 attrs and data");
is_attributes_data(&resultAttrs, &resultData, &attributes, &data,
"Do attrs and data match?");
free_attributes_data(&memfuncs, &resultAttrs, &resultData);
ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
"CSSM_DL_FreeUniqueRecord");
ok_status(CSSM_DL_DataAbortQuery(dldb, search),
"CSSM_DL_DataAbortQuery");
SKIP: {
skip("nothing to free", 2,
ok_status(CSSM_DL_DataGetFirst(dldb, &query, &search,
&resultAttrs, &resultData, &uniqueId),
"CSSM_DL_DataGetFirst 2 attrs and data"));
is_attributes_data(&resultAttrs, &resultData, &attributes, &data,
"Do attrs and data match?");
free_attributes_data(&memfuncs, &resultAttrs, &resultData);
ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
"CSSM_DL_FreeUniqueRecord");
}
is_status(CSSM_DL_DataGetNext(dldb, search,
&resultAttrs, &resultData, &uniqueId),
CSSMERR_DL_ENDOFDATA, "CSSM_DL_DataGetNext returns eod");
CSSM_QUERY query2 =
{
attributes.DataRecordType,
CSSM_DB_NONE,
0,
NULL,
{ CSSM_QUERY_TIMELIMIT_NONE, CSSM_QUERY_SIZELIMIT_NONE },
0
};
ok_status(CSSM_DL_DataGetFirst(dldb, &query2, &search,
&resultAttrs, &resultData, &uniqueId),
"CSSM_DL_DataGetFirst 2 attrs and data");
free_attributes_data(&memfuncs, &resultAttrs, &resultData);
ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
"CSSM_DL_FreeUniqueRecord");
ok_status(CSSM_DL_DataGetNext(dldb, search,
&resultAttrs, &resultData, &uniqueId),
"CSSM_DL_DataGetNext 2 attrs and data");
free_attributes_data(&memfuncs, &resultAttrs, &resultData);
ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
"CSSM_DL_FreeUniqueRecord");
ok_status(CSSM_DL_DataAbortQuery(dldb, search),
"CSSM_DL_DataAbortQuery");
ok_status(CSSM_DL_DbClose(dldb),
"CSSM_DL_DbClose");
}
static void test2(CSSM_DL_HANDLE dl)
{
CSSM_DL_DB_HANDLE dldb = { dl };
CSSM_DB_UNIQUE_RECORD_PTR uniqueId;
ok_status(CSSM_DL_DbCreate(dl, DBNAME, NULL ,
&dbInfo,
CSSM_DB_ACCESS_READ | CSSM_DB_ACCESS_WRITE,
NULL ,
NULL,
&dldb.DBHandle),
"CSSM_DL_DbCreate");
ok_status(CSSM_DL_DbClose(dldb),
"CSSM_DL_DbClose");
ok_status(CSSM_DL_DbOpen(dl, DBNAME, NULL ,
CSSM_DB_ACCESS_READ | CSSM_DB_ACCESS_WRITE,
NULL ,
&openParameters,
&dldb.DBHandle),
"CSSM_DL_DbOpen");
is_status(CSSM_DL_DataInsert(dldb,
attributes.DataRecordType,
&attributes,
NULL,
&uniqueId),
CSSMERR_DL_INVALID_RECORDTYPE, "CSSM_DL_DataInsert no table");
ok_status(CSSM_DL_CreateRelation(dldb,
42,
"Fourty Two",
sizeof(attributeInfo) / sizeof(CSSM_DB_SCHEMA_ATTRIBUTE_INFO),
attributeInfo,
sizeof(indexInfo) / sizeof(CSSM_DB_SCHEMA_INDEX_INFO),
indexInfo), "CSSM_DL_CreateRelation");
ok_status(CSSM_DL_DataInsert(dldb,
attributes.DataRecordType,
&attributes,
NULL,
&uniqueId), "CSSM_DL_DataInsert fails unless 4039735 is fixed");
is_status(CSSM_DL_DataInsert(dldb,
attributes.DataRecordType,
&attributes,
NULL,
&uniqueId),
CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA,
"CSSM_DL_DataInsert dupe");
ok_status(CSSM_DL_DataDelete(dldb, uniqueId),
"CSSM_DL_Delete");
is_status(CSSM_DL_DataDelete(dldb, uniqueId),
CSSMERR_DL_RECORD_NOT_FOUND, "delete again should fail");
ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
"CSSM_DL_FreeUniqueRecord");
ok_status(CSSM_DL_DataInsert(dldb,
attributes.DataRecordType,
&attributes,
NULL,
&uniqueId), "Insert again after delete");
ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
"CSSM_DL_FreeUniqueRecord");
ok_status(CSSM_DL_DbClose(dldb),
"CSSM_DL_DbDelete");
}
int
main(int argc, char * const *argv)
{
int guid_alt = argc > 1 && !strcmp(argv[1], "-g");
CSSM_GUID s3dl_guid =
{
0x2cb56191, 0xee6f, 0x432d,
{ 0xa3, 0x77, 0x85, 0x3d, 0x3c, 0x6b, 0x94, 0x9e }
};
const CSSM_GUID *guid = guid_alt ? & s3dl_guid : &gGuidAppleFileDL;
plan_tests(70);
CSSM_DL_HANDLE dl;
ok(cssm_attach(guid, &dl), "cssm_attach");
ok(tests_begin(argc, argv), "tests_begin");
test1(dl);
ok_status(CSSM_DL_DbDelete(dl, DBNAME, NULL ,
NULL ), "CSSM_DL_DbDelete");
test2(dl);
ok_status(CSSM_DL_DbDelete(dl, DBNAME, NULL ,
NULL ), "CSSM_DL_DbDelete");
ok(cssm_detach(guid, dl), "cssm_detach");
ok_leaks("no leaks");
return !tests_end(1);
}