public static IList<WindowsCertificateStore> EnumerateStores(
WindowsStoreType storeType,
string hostName,
string serviceNameOrUserSid)
{
List<WindowsCertificateStore> stores = new List<WindowsCertificateStore>();
EnumResults results = new EnumResults();
GCHandle hResults = GCHandle.Alloc(results, GCHandleType.Pinned);
IntPtr wszStoreBaseName = IntPtr.Zero;
try
{
uint dwFlags = 0;
// contruct base name for the store to enumerate.
string storeBaseName = null;
if (!String.IsNullOrEmpty(hostName) && hostName != ".")
{
storeBaseName = Utils.Format("{0}", hostName);
}
if (!String.IsNullOrEmpty(serviceNameOrUserSid))
{
if (!String.IsNullOrEmpty(storeBaseName))
{
storeBaseName = Utils.Format("{0}\\{1}", storeBaseName, serviceNameOrUserSid);
}
else
{
storeBaseName = serviceNameOrUserSid;
}
}
// allocate the store base name.
wszStoreBaseName = DuplicateString(storeBaseName);
// set the flags based on store type.
dwFlags |= GetFlags(storeType);
// get list of names.
results.Capacity = 10;
results.Count = 0;
results.Names = Marshal.AllocHGlobal(results.Capacity*IntPtr.Size);
IntPtr pResults = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(EnumResults)));
Marshal.StructureToPtr(results, pResults, false);
int bResult = NativeMethods.CertEnumSystemStore(
dwFlags,
wszStoreBaseName,
pResults,
EnumStoreCallback);
int dwError = Marshal.GetLastWin32Error();
results = (EnumResults)Marshal.PtrToStructure(pResults, typeof(EnumResults));
Marshal.DestroyStructure(pResults, typeof(EnumResults));
Marshal.FreeHGlobal(pResults);
if (bResult == 0)
{
throw ServiceResultException.Create(
StatusCodes.BadUnexpectedError,
"Can't enumerate the contents of the certificate store.\r\nType={0}, HostName={1}, ServiceNameOrUserSid={2}, Error={3:X8}",
storeType,
hostName,
serviceNameOrUserSid,
dwError);
}
// copy names.
IntPtr[] names = new IntPtr[results.Count];
Marshal.Copy(results.Names, names, 0, results.Count);
for (uint ii = 0; ii < results.Count; ii++)
{
IntPtr wszSymbolicName = names[ii];
IntPtr hStore = NativeMethods.CertOpenStore(
new IntPtr(CERT_STORE_PROV_SYSTEM),
0,
IntPtr.Zero,
GetFlags(storeType) | CERT_STORE_READONLY_FLAG | CERT_STORE_OPEN_EXISTING_FLAG,
wszSymbolicName);
if (hStore == IntPtr.Zero)
{
continue;
}
int result = NativeMethods.CertCloseStore(hStore, 0);
if (result == 0)
{
Utils.Trace("Could not close certificate store. Error={0:X8}", Marshal.GetLastWin32Error());
}
WindowsCertificateStore store = new WindowsCertificateStore();
store.m_symbolicName = Marshal.PtrToStringUni(wszSymbolicName);
store.m_storeType = storeType;
store.m_displayName = store.m_symbolicName;
// extract the store name from the end of the symbolic name.
int index = store.m_symbolicName.LastIndexOf('\\');
if (index >= 0)
{
store.m_displayName = store.m_symbolicName.Substring(index+1);
store.m_serviceNameOrUserSid = store.m_symbolicName.Substring(0, index);
}
// check if the service name or user sid has a host name prefix.
if (!String.IsNullOrEmpty(store.m_serviceNameOrUserSid))
{
index = store.m_serviceNameOrUserSid.LastIndexOf('\\');
if (index >= 0)
{
store.m_hostName = store.m_serviceNameOrUserSid.Substring(0, index);
store.m_serviceNameOrUserSid = store.m_serviceNameOrUserSid.Substring(index+1);
}
}
// remove the leading '\\' from the host name.
if (!String.IsNullOrEmpty(store.m_hostName))
{
if (store.m_hostName.StartsWith("\\\\", StringComparison.Ordinal))
{
store.m_hostName = store.m_hostName.Substring(2);
}
}
store.m_displayName = GetStoreDisplayName(store.m_storeType, store.m_serviceNameOrUserSid, store.m_symbolicName);
// add the store to the list.
stores.Add(store);
}
}
finally
{
if (results.Names != IntPtr.Zero)
{
IntPtr[] names = new IntPtr[results.Count];
Marshal.Copy(results.Names, names, 0, results.Count);
for (uint ii = 0; ii < names.Length; ii++)
{
Marshal.FreeHGlobal(names[ii]);
}
Marshal.FreeHGlobal(results.Names);
}
if (hResults.IsAllocated)
{
hResults.Free();
}
if (wszStoreBaseName != IntPtr.Zero)
{
Marshal.FreeHGlobal(wszStoreBaseName);
}
}
return stores;
}