get serial number of a certificate with code - windows

I am trying to write an application for applying for a certificate and revoking it with code.
By referring to the msdn, I implemented the Applying Certification part with ICertRequest3 interface, and the Revoking part with ICertAdmin2::RevokeCertificate interface.
Here is the problem, it requires serial number of a certificate for ICertAdmin2::RevokeCertificate to get to work and I do not know how to get the serial number property
of the certificate issued by the CA.
Specifically speaking, what I need is to find a way to extract the serial number property of the certificate issued by the CA after I submit the request with ICertRequest3.
For your information, below is the code snippet for applying and revoking certificate.
HRESULT enrollWithICertRequest3(
X509CertificateEnrollmentContext context,
LPCWSTR template_name,
X509EnrollmentAuthFlags policy_server_authtype,
LPCWSTR policy_server_url,
LPCWSTR policy_server_username,
LPCWSTR policy_server_password,
X509EnrollmentAuthFlags enrollment_server_authtype,
LPCWSTR enrollment_server_url,
LPCWSTR enrollment_server_username,
LPCWSTR enrollment_server_password,
BSTR *cert_base64)
{
HRESULT hr = S_OK;
BSTR bstr_template_name = NULL;
BSTR bstr_policyserver_url = NULL;
BSTR bstr_policyserver_id = NULL;
BSTR bstr_policyserver_username = NULL;
BSTR bstr_policyserver_password = NULL;
IX509EnrollmentPolicyServer *policyserver_interface = NULL;
IX509CertificateTemplates *templates_interface = NULL;
IX509CertificateTemplate *template_interface = NULL;
IX509Enrollment2 *enroll2_interface = NULL;
BSTR bstrRequest = NULL;
BSTR bstrEnrollmentServerUrl = NULL;
BSTR bstrEnrollmentServerUsername = NULL;
BSTR bstrEnrollmentServerPassword = NULL;
ICertRequest3 *request3_interface = NULL;
LONG disposition = 0;
BSTR bstr_disposition = NULL;
VARIANT var_fullresponse;
VariantInit(&var_fullresponse);
var_fullresponse.vt = VT_BSTR;
var_fullresponse.bstrVal = NULL;
bstr_template_name = SysAllocString(template_name);
bstr_policyserver_url = SysAllocString(policy_server_url);
if(!bstr_template_name && template_name ||
!bstr_policyserver_url && policy_server_url)
{
hr = E_OUTOFMEMORY;
goto error;
}
if(policy_server_authtype == X509AuthUsername)
{
bstr_policyserver_username = SysAllocString(policy_server_username);
bstr_policyserver_password = SysAllocString(policy_server_password);
if(!bstr_policyserver_username && policy_server_username ||
!bstr_policyserver_password && policy_server_password)
{
hr = E_OUTOFMEMORY;
goto error;
}
}
else if(policy_server_authtype == X509AuthCertificate)
{
//This call is preparation of the call to pPolicyServer->SetCredential.
//For certificate authentication, bstrPolicyServerUsername should be a
//pointer to a memory blob in which certificate hash value is stored.
hr = hex2BstrByte(policy_server_username, &bstr_policyserver_username);
if(FAILED(hr))
goto error;
}
hr = CoCreateInstance(
__uuidof(CX509EnrollmentPolicyWebService),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IX509EnrollmentPolicyServer),
(void **)&policyserver_interface);
if(FAILED(hr))
goto error;
//The bstrPolicyServerId is optional
hr = policyserver_interface->Initialize(
bstr_policyserver_url, //[in] BSTR bstrPolicyServerUrl
NULL, //[in] BSTR bstrPolicyServerId
policy_server_authtype, //[in] X509EnrollmentAuthFlags authFlags
false, //[in] VARIANT_BOOL fIsUnTrusted
context); //[in] X509CertificateEnrollmentContext context
if(FAILED(hr))
goto error;
//This call sets authentication type and authentication credential
//to policy server to the object pointed by pPolicyServer.
//This call is necessary even for Kerberos authentication type.
hr = policyserver_interface->SetCredential(
NULL, //[in] LONG hWndParent
policy_server_authtype, //[in] X509EnrollmentAuthFlags flag
bstr_policyserver_username, //[in] BSTR strCredential
bstr_policyserver_password); //[in] BSTR strPassword
if(FAILED(hr))
goto error;
//The flag LoadOptionDefault means enrollment process reads
//policies (templates) from local cache in file system if it exists.
//Otherwise, it queries policies (templates) from policy server through
//http protocol, then caches them in local file system.
//The flag LoadOptionReload queries policies (templates) directly from
//policy server regardless of if cached policies (templates) exist.
hr = policyserver_interface->LoadPolicy(LoadOptionDefault); //[in] X509EnrollmentPolicyLoadOption option
if(FAILED(hr))
goto error;
//pTemplates points to collection of policies (templates)
hr = policyserver_interface->GetTemplates(&templates_interface);
if(FAILED(hr))
goto error;
//pTemplate points to the policy (template) specified by a template name
hr = templates_interface->get_ItemByName(bstr_template_name, &template_interface);
if(FAILED(hr))
goto error;
//This call is preparation of the call IX509Enrollment2::InstallResponse2
hr = policyserver_interface->GetPolicyServerId(&bstr_policyserver_id);
if(FAILED(hr))
goto error;
hr = CoCreateInstance(
__uuidof(CX509Enrollment),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IX509Enrollment2),
(void **) &enroll2_interface);
if(FAILED(hr))
goto error;
//This is a new API in Windows 7 to support http protocol
hr = enroll2_interface->InitializeFromTemplate(
context, //[in] X509CertificateEnrollmentContext context
policyserver_interface, //[in] IX509EnrollmentPolicyServer *pPolicyServer
template_interface); //[in] IX509CertificateTemplate *pTemplate
if(FAILED(hr))
goto error;
//Get request blob for the call ICertRequest3::Submit
hr = enroll2_interface->CreateRequest(
XCN_CRYPT_STRING_BASE64,
&bstrRequest);
if(FAILED(hr))
goto error;
hr = CoCreateInstance(
__uuidof(CCertRequest),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(ICertRequest3),
(void **) &request3_interface);
if(FAILED(hr))
goto error;
bstrEnrollmentServerUrl = SysAllocString(enrollment_server_url);
if(!bstrEnrollmentServerUrl && enrollment_server_url)
{
hr = E_OUTOFMEMORY;
goto error;
}
if(enrollment_server_authtype == X509AuthUsername)
{
bstrEnrollmentServerUsername = SysAllocString(enrollment_server_username);
bstrEnrollmentServerPassword = SysAllocString(enrollment_server_password);
if(!bstrEnrollmentServerUsername && enrollment_server_username ||
!bstrEnrollmentServerPassword && enrollment_server_password)
{
hr = E_OUTOFMEMORY;
goto error;
}
}
else if(enrollment_server_authtype == X509AuthCertificate)
{
//This call is preparation of the call to pCertRequest3->SetCredential.
//For certificate authentication, bstrPolicyServerUsername should be a
//pointer to a memory blob in which certificate hash value is stored.
hr = hex2BstrByte(enrollment_server_username, &bstrEnrollmentServerUsername);
if(FAILED(hr))
goto error;
}
//This call sets authentication type and authentication credential
//to enrollment server to the object pointed by pCertRequest3.
//This call is necessary even for Kerberos authentication type.
hr = request3_interface->SetCredential(
NULL, //[in] LONG hWnd
enrollment_server_authtype, //[in] X509EnrollmentAuthFlags AuthType
bstrEnrollmentServerUsername, //[in] BSTR strCredential
bstrEnrollmentServerPassword); //[in] BSTR strPassword
if(FAILED(hr))
goto error;
//Submit request and get response
//For ICertRequest3::Submit, bstrConfig can be
//enrollment server URL
hr = request3_interface->Submit(
CR_IN_BASE64 | CR_IN_FORMATANY, //[in] LONG Flags
bstrRequest, //[in] BSTR const strRequest
NULL, //[in] BSTR const strAttributes
bstrEnrollmentServerUrl, //[in] BSTR const strConfig
&disposition); //[out, retval] LONG *pDisposition
if(FAILED(hr))
goto error;
//Check the submission status
if(disposition != CR_DISP_ISSUED) //Not enrolled
{
hr = request3_interface->GetDispositionMessage(&bstr_disposition);
if(FAILED(hr))
goto error;
request3_interface->GetLastStatus(&hr);
if(disposition == CR_DISP_UNDER_SUBMISSION) //Pending
{
wprintf(L"The submission is in pending status: %s \n", bstr_disposition);
goto error;
}
else //Failed
{
wprintf(L"The submission failed: %s \n", bstr_disposition);
goto error;
}
}
// Get the issued certificate
hr = request3_interface->GetCertificate(CR_OUT_BASE64, cert_base64);
if(FAILED(hr))
goto error;
////Get full response for installation
//hr = request3_interface->GetFullResponseProperty(
// FR_PROP_FULLRESPONSENOPKCS7, //[in] LONG PropId (FR_PROP_*)
// 0, //[in] LONG PropIndex
// PROPTYPE_BINARY, //[in] LONG PropType (PROPTYPE_*
// CR_OUT_BASE64, //[in] LONG Flags (CR_OUT_*)
// &var_fullresponse); //[out, retval] VARIANT *pvarPropertyValue
//if(FAILED(hr))
// goto error;
////Install the response
//hr = enroll2_interface->InstallResponse2(
// AllowNone, //[in] InstallResponseRestrictionFlags Restrictions
// var_fullresponse.bstrVal, //[in] BSTR strResponse
// XCN_CRYPT_STRING_BASE64, //[in] EnrodingType Encoding
// bstr_policyserver_password, //[in] BSTR strPassword
// bstr_policyserver_url, //[in] BSTR strEnrollmentPolicyServerUrl
// bstr_policyserver_id, //[in] BSTR strEnrollmentPolicyServerID
// PsfNone, //[in] PolicyServerUrlFlags EnrollmentPolicyServerFlags
// policy_server_authtype); //[in] X509EnrollmentAuthFlags authFlags
//if(FAILED(hr))
// goto error
/*BSTR pwd = SysAllocString(L"tOngbupan");
hr = enroll2_interface->CreatePFX(pwd, PFXExportEEOnly, XCN_CRYPT_STRING_BASE64, cert_base64);
SysFreeString(pwd);*/
error:
SysFreeString(bstr_template_name);
SysFreeString(bstr_policyserver_url);
SysFreeString(bstr_policyserver_id);
SysFreeString(bstr_policyserver_username);
SysFreeString(bstr_policyserver_password);
SysFreeString(bstr_disposition);
SysFreeString(bstrEnrollmentServerUrl);
SysFreeString(bstrEnrollmentServerPassword);
SysFreeString(bstrEnrollmentServerUsername);
SysFreeString(bstrRequest);
if(!var_fullresponse.bstrVal)
VariantClear(&var_fullresponse);
if(policyserver_interface)
policyserver_interface->Release();
if(templates_interface)
templates_interface->Release();
if(request3_interface)
request3_interface->Release();
if(template_interface)
template_interface->Release();
if(enroll2_interface)
enroll2_interface->Release();
return hr;
}
bool revokeUserCert(const wstring& cert_serial_num)
{
BSTR bstrSerial = NULL; // certificate serial number
HRESULT hr;
LONG nDisp;
ICertAdmin2* pCertAdmin = NULL;
bstrSerial = SysAllocString(cert_serial_num.c_str());
hr = CoCreateInstance(
CLSID_CCertAdmin,
NULL, // pUnkOuter
CLSCTX_INPROC_SERVER,
IID_ICertAdmin2,
(void **) &pCertAdmin);
if(FAILED(hr))
{
printf("init icertadmin error\n");
goto error;
}
ICertConfig* pCertConfig = NULL;
BSTR strCAConfig = NULL;
// Create ICertConfig
hr = CoCreateInstance(
__uuidof(CCertConfig),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(ICertConfig),
(void**)&pCertConfig);
// Get CA config
hr = pCertConfig->GetConfig(CC_FIRSTCONFIG, &strCAConfig);
if (FAILED(hr))
{
printf("Failed GetConfig [%x]\n", hr);
goto error;
}
hr = pCertAdmin->IsValidCertificate(strCAConfig, bstrSerial, &nDisp);
if (FAILED(hr))
{
printf("Failed IsValidCertificate [%x]\n", hr);
goto error;
}
if(nDisp != CA_DISP_VALID)
{
printf("givin certificate is not valid\n");
goto error;
}
// Revoke the certificate.
// pCertAdmin is a previously instantiated ICertAdmin object.
hr = pCertAdmin->RevokeCertificate( strCAConfig,
bstrSerial,
0,
0);
if (FAILED(hr))
{
/*_com_error err(hr);
LPCTSTR errMsg = err.ErrorMessage();*/
//printf("Failed RevokeCertificate. [%x] [%s]\n", hr, ConvertWCSToMBS(errMsg, sizeof(errMsg)).c_str());
printf("Failed RevokeCertificate. [%x] \n", hr);
goto error;
}
else
printf("Certificate %ws revoked.\n", bstrSerial );
// Done processing.
error:
// Free resources.
if (bstrSerial)
SysFreeString( bstrSerial );
if(strCAConfig)
SysFreeString( strCAConfig );
if(pCertAdmin != NULL) { pCertAdmin->Release(); }
if(pCertConfig != NULL) { pCertConfig->Release(); }
return SUCCEEDED(hr);
}

Once you have got the issued certificate into your cert_base64 string, convert this to a byte array then create a new X509Certificate2 object from the byte array. You can then access the serial number from the X509Certificate2.SerialNumber property. In C# this would be:
X509Certificate2 x509cert = new X509Certificate2(getBytes(cert_base64));
string serialNumber = x509cert.SerialNumber;
private byte[] getBytes(string str)
{
byte[] bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}

Related

C++ - Windows Shell API - Wrong path while iterating through a folder

Consider the following code:
bool ListFolderContent(const std::wstring& fileName)
{
PIDLIST_ABSOLUTE pidl = nullptr;
if (FAILED(::SHILCreateFromPath(fileName.c_str(), &pidl, nullptr)))
return false;
IShellFolder* pShellfolder = nullptr;
LPCITEMIDLIST pidlRelative = nullptr;
HRESULT hr = SHBindToParent(pidl, IID_IShellFolder, (void**)&pShellfolder, &pidlRelative);
if (FAILED(hr))
{
::CoTaskMemFree(pidl);
return false;
}
IEnumIDList* pEnumIDList = nullptr;
hr = pShellfolder->EnumObjects(nullptr, SHCONTF_NONFOLDERS, &pEnumIDList);
if (FAILED(hr))
{
pShellfolder->Release();
::CoTaskMemFree(pidl);
return false;
}
while (1)
{
LPITEMIDLIST pChild = nullptr;
hr = pEnumIDList->Next(1, &pChild, nullptr);
if (FAILED(hr))
{
pShellfolder->Release();
::CoTaskMemFree(pidl);
return false;
}
if (hr == S_FALSE)
break;
wchar_t buffer[MAX_PATH + 1];
if (::SHGetPathFromIDListW(pChild, buffer))
{
::OutputDebugString(buffer);
::OutputDebugString(L"\r\n");
}
}
pShellfolder->Release();
::CoTaskMemFree(pidl);
return true;
}
This code works well and logs the content of the folder owning the given file I pass through the fileName parameter.
However I have an issues with this code: Whatever I pass as file name, the logged path is always C:\Users\Admin\Desktop, and NOT the path to the parent folder I'm iterating, as expected. On the other hand the file names are correct.
Can someone explain me what I'm doing wrong?
You are passing just the last component ("filename") here: SHGetPathFromIDListW(pChild, buffer). Since the desktop is the root you are basically asking to get the filesystem path of [Desktop] [Filename] from the namespace.
There are two solutions:
pShellfolder->GetDisplayNameOf(pChild, SHGDN_FORPARSING, ...)+StrRetToBuf. This is fast since you already have an instance of the folder interface.
Call SHGetPathFromIDList with an absolute (full) pidl. On the pidl from SHILCreateFromPath, call ILCloneFull, ILRemoveLastID and ILCombine(clone, pChild).
HRESULT Example()
{
WCHAR buf[MAX_PATH];
GetWindowsDirectory(buf, MAX_PATH);
PathAppend(buf, L"Explorer.exe");
PIDLIST_ABSOLUTE pidl, pidlFullItem;
HRESULT hr = SHILCreateFromPath(buf, &pidl, nullptr); // %windir%\Explorer.exe
if (FAILED(hr)) return hr;
LPITEMIDLIST pLeaf;
IShellFolder*pShellfolder; // %windir%
hr = SHBindToParent(pidl, IID_IShellFolder, (void**)&pShellfolder, nullptr);
if (SUCCEEDED(hr))
{
IEnumIDList*pEnum;
// Method 1:
hr = pShellfolder->EnumObjects(nullptr, SHCONTF_NONFOLDERS, &pEnum);
if (SUCCEEDED(hr))
{
for (; S_OK == (hr = pEnum->Next(1, &pLeaf, nullptr));)
{
STRRET sr;
hr = pShellfolder->GetDisplayNameOf(pLeaf, SHGDN_FORPARSING, &sr);
if (SUCCEEDED(hr))
{
hr = StrRetToBuf(&sr, pLeaf, buf, MAX_PATH);
if (SUCCEEDED(hr)) wprintf(L"M1: Item: %s\n", buf);
}
}
pEnum->Release();
}
// Method 2:
ILRemoveLastID(pidl); // %windir%\Explorer.exe => %windir%
hr = pShellfolder->EnumObjects(nullptr, SHCONTF_NONFOLDERS, &pEnum);
if (SUCCEEDED(hr))
{
for (; S_OK == (hr = pEnum->Next(1, &pLeaf, nullptr));)
{
pidlFullItem = ILCombine(pidl, pLeaf); // %windir% + Filename
if (pidlFullItem)
{
hr = SHGetPathFromIDListW(pidlFullItem, buf);
if (SUCCEEDED(hr)) wprintf(L"M2: Item: %s\n", buf);
ILFree(pidlFullItem);
}
}
pEnum->Release();
}
pShellfolder->Release();
}
ILFree(pidl);
return hr;
}

How to serialize credentials in smart card credential provider for a domain account for logon and unlock?

I am building a credential provider which works same like windows smart card credential provider i.e this works only with domain accounts. I am facing an issue when passing the credentials to Negotiate SSP and I am using microsoft base smart card crypto provider as CSP. I am getting The parameter is incorrect error on lock screen after entering pin.
GetSerialization
HRESULT CCredential::GetSerialization(
CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE* pcpgsr,
CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs,
PWSTR* ppwszOptionalStatusText,
CREDENTIAL_PROVIDER_STATUS_ICON* pcpsiOptionalStatusIcon
)
{
UNREFERENCED_PARAMETER(ppwszOptionalStatusText);
UNREFERENCED_PARAMETER(pcpsiOptionalStatusIcon);
HRESULT hr;
WCHAR dmz[244] = L"demodomain";
PWSTR pwzProtectedPin;
hr = ProtectIfNecessaryAndCopyPassword(_rgFieldStrings[SFI_PIN], _cpus, _dwFlags, &pwzProtectedPin);
if (SUCCEEDED(hr))
{
KERB_CERTIFICATE_UNLOCK_LOGON kiul;
// Initialize kiul with weak references to our credential.
hr = UnlockLogonInit(dmz, _rgFieldStrings[SFI_USERNAME], pwzProtectedPin, _cpus, &kiul);
if (SUCCEEDED(hr))
{
PBASE_SMARTCARD_CSP_INFO pCspInfo = _pContainer->GetCSPInfo();
if (pCspInfo)
{
CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcp;
hr = UnlockLogonPack(kiul, pCspInfo, &pcpcs->rgbSerialization, &pcpcs->cbSerialization);
_pContainer->FreeCSPInfo(pCspInfo);
if (SUCCEEDED(hr))
{
ULONG ulAuthPackage;
hr = RetrieveNegotiateAuthPackage(&ulAuthPackage);
if (SUCCEEDED(hr))
{
pcpcs->ulAuthenticationPackage = ulAuthPackage;
pcpcs->clsidCredentialProvider = CLSID_CProvider;
// At this point the credential has created the serialized credential used for logon
// By setting this to CPGSR_RETURN_CREDENTIAL_FINISHED we are letting logonUI know
// that we have all the information we need and it should attempt to submit the
// serialized credential.
*pcpgsr = CPGSR_RETURN_CREDENTIAL_FINISHED;
}
else
{
PrintLn(WINEVENT_LEVEL_WARNING, L"RetrieveNegotiateAuthPackage not SUCCEEDED hr=0x%08x", hr);
}
}
else
{
PrintLn(WINEVENT_LEVEL_WARNING, L"UnlockLogonPack not SUCCEEDED hr=0x%08x", hr);
}
}
else
{
PrintLn(WINEVENT_LEVEL_WARNING, L"pCspInfo NULL");
}
}
else
{
PrintLn(WINEVENT_LEVEL_WARNING, L"UnlockLogonInit not SUCCEEDED hr=0x%08x", hr);
}
CoTaskMemFree(pwzProtectedPin);
}
else
{
PrintLn(WINEVENT_LEVEL_WARNING, L"ProtectIfNecessaryAndCopyPassword not SUCCEEDED hr=0x%08x", hr);
}
if (!SUCCEEDED(hr))
{
PrintLn(WINEVENT_LEVEL_WARNING, L"not SUCCEEDED hr=0x%08x", hr);
}
else
{
PrintLn(WINEVENT_LEVEL_WARNING, L"OK");
}
return hr;
}
UnlockLogonInit
HRESULT UnlockLogonInit(
PWSTR pwzDomain,
PWSTR pwzUsername,
PWSTR pwzPin,
CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus,
KERB_CERTIFICATE_UNLOCK_LOGON* pkiul
)
{
UNREFERENCED_PARAMETER(cpus);
KERB_CERTIFICATE_UNLOCK_LOGON kiul;
ZeroMemory(&kiul, sizeof(kiul));
KERB_CERTIFICATE_LOGON* pkil = &kiul.Logon;
HRESULT hr = UnicodeStringInitWithString(pwzDomain, &pkil->LogonDomainName);
if (SUCCEEDED(hr))
{
hr = UnicodeStringInitWithString(pwzUsername, &pkil->UserName);
if (SUCCEEDED(hr))
{
hr = UnicodeStringInitWithString(pwzPin, &pkil->Pin);
if (SUCCEEDED(hr))
{
// Set a MessageType based on the usage scenario.
pkil->MessageType = KerbCertificateLogon; //13
pkil->CspDataLength = 0;
pkil->CspData = NULL;
pkil->Flags = 0;
if (SUCCEEDED(hr))
{
// KERB_INTERACTIVE_UNLOCK_LOGON is just a series of structures. A
// flat copy will properly initialize the output parameter.
CopyMemory(pkiul, &kiul, sizeof(*pkiul));
}
}
}
}
return hr;
}
UnlockLogonPack
HRESULT UnlockLogonPack(
const KERB_CERTIFICATE_UNLOCK_LOGON& rkiulIn,
const PBASE_SMARTCARD_CSP_INFO pCspInfo,
BYTE** prgb,
DWORD* pcb
)
{
HRESULT hr;
const KERB_CERTIFICATE_LOGON* pkilIn = &rkiulIn.Logon;
// alloc space for struct plus extra for the three strings
DWORD cb = sizeof(rkiulIn) +
pkilIn->LogonDomainName.Length +
pkilIn->UserName.Length +
pkilIn->Pin.Length +
pCspInfo->dwCspInfoLen;
KERB_CERTIFICATE_UNLOCK_LOGON* pkiulOut = (KERB_CERTIFICATE_UNLOCK_LOGON*)CoTaskMemAlloc(cb);
if (pkiulOut)
{
ZeroMemory(&pkiulOut->LogonId, sizeof(LUID));
//
// point pbBuffer at the beginning of the extra space
//
BYTE* pbBuffer = (BYTE*)pkiulOut + sizeof(*pkiulOut);
KERB_CERTIFICATE_LOGON* pkilOut = &pkiulOut->Logon;
pkilOut->MessageType = pkilIn->MessageType;
pkilOut->Flags = pkilIn->Flags;
//
// copy each string,
// fix up appropriate buffer pointer to be offset,
// advance buffer pointer over copied characters in extra space
//
_UnicodeStringPackedUnicodeStringCopy(pkilIn->LogonDomainName, (PWSTR)pbBuffer, &pkilOut->LogonDomainName);
pkilOut->LogonDomainName.Buffer = (PWSTR)(pbBuffer - (BYTE*)pkiulOut);
pbBuffer += pkilOut->LogonDomainName.Length;
_UnicodeStringPackedUnicodeStringCopy(pkilIn->UserName, (PWSTR)pbBuffer, &pkilOut->UserName);
pkilOut->UserName.Buffer = (PWSTR)(pbBuffer - (BYTE*)pkiulOut);
pbBuffer += pkilOut->UserName.Length;
_UnicodeStringPackedUnicodeStringCopy(pkilIn->Pin, (PWSTR)pbBuffer, &pkilOut->Pin);
pkilOut->Pin.Buffer = (PWSTR)(pbBuffer - (BYTE*)pkiulOut);
pbBuffer += pkilOut->Pin.Length;
pkilOut->CspData = (PUCHAR) (pbBuffer - (BYTE*)pkiulOut);
pkilOut->CspDataLength = pCspInfo->dwCspInfoLen;
memcpy(pbBuffer,pCspInfo,pCspInfo->dwCspInfoLen);
*prgb = (BYTE*)pkiulOut;
*pcb = cb;
hr = S_OK;
}
else
{
hr = E_OUTOFMEMORY;
}
return hr;
}
_KERB_SMARTCARD_CSP_INFO Structure and GetCSPInfo
// based on _KERB_SMARTCARD_CSP_INFO
typedef struct _BASE_SMARTCARD_CSP_INFO
{
DWORD dwCspInfoLen;
DWORD MessageType;
union {
PVOID ContextInformation;
ULONG64 SpaceHolderForWow64;
} ;
DWORD flags;
DWORD KeySpec;
ULONG nCardNameOffset;
ULONG nReaderNameOffset;
ULONG nContainerNameOffset;
ULONG nCSPNameOffset;
TCHAR bBuffer[sizeof(DWORD)];
} BASE_SMARTCARD_CSP_INFO,
*PBASE_SMARTCARD_CSP_INFO;
PBASE_SMARTCARD_CSP_INFO CContainer::GetCSPInfo()
{
//szreaderName, szCardname, szproviderName, szContainerName are initialized with respective values in constructor
_ASSERTE( _CrtCheckMemory( ) );
DWORD dwReaderLen = (DWORD) _tcslen(_szReaderName)+1;
DWORD dwCardLen = (DWORD) _tcslen(_szCardName)+1;
DWORD dwProviderLen = (DWORD) _tcslen(_szProviderName)+1;
DWORD dwContainerLen = (DWORD) _tcslen(_szContainerName)+1;
DWORD dwBufferSize = dwReaderLen + dwCardLen + dwProviderLen + dwContainerLen;
PBASE_SMARTCARD_CSP_INFO pCspInfo = (PBASE_SMARTCARD_CSP_INFO) BASEAlloc(sizeof(BASE_SMARTCARD_CSP_INFO)+dwBufferSize*sizeof(TCHAR));
if (!pCspInfo) return NULL;
//ZeroMemory(pCspInfo);
memset(pCspInfo,0,sizeof(BASE_SMARTCARD_CSP_INFO));
pCspInfo->dwCspInfoLen = sizeof(BASE_SMARTCARD_CSP_INFO)+dwBufferSize*sizeof(TCHAR);
pCspInfo->MessageType = 1;
pCspInfo->KeySpec = _KeySpec;
pCspInfo->nCardNameOffset = ARRAYSIZE(pCspInfo->bBuffer);
pCspInfo->nReaderNameOffset = pCspInfo->nCardNameOffset + dwCardLen;
pCspInfo->nContainerNameOffset = pCspInfo->nReaderNameOffset + dwReaderLen;
pCspInfo->nCSPNameOffset = pCspInfo->nContainerNameOffset + dwContainerLen;
memset(pCspInfo->bBuffer,0,sizeof(pCspInfo->bBuffer));
_tcscpy_s(&pCspInfo->bBuffer[pCspInfo->nCardNameOffset] ,dwBufferSize + 4 - pCspInfo->nCardNameOffset, _szCardName);
_tcscpy_s(&pCspInfo->bBuffer[pCspInfo->nReaderNameOffset] ,dwBufferSize + 4 - pCspInfo->nReaderNameOffset, _szReaderName);
_tcscpy_s(&pCspInfo->bBuffer[pCspInfo->nContainerNameOffset] ,dwBufferSize + 4 - pCspInfo->nContainerNameOffset, _szContainerName);
_tcscpy_s(&pCspInfo->bBuffer[pCspInfo->nCSPNameOffset] ,dwBufferSize + 4 - pCspInfo->nCSPNameOffset, _szProviderName);
_ASSERTE( _CrtCheckMemory( ) );
return pCspInfo;
}
I don't understand where I am doing wrong, been stuck here for a while now. Any help would be appreciated.

Getting GUID of group with IADs interface

I'm using the following C++ code to get all groups for a user:
(from https://msdn.microsoft.com/en-us/library/windows/desktop/aa746342(v=vs.85).aspx. I just added a few liens to get the group GUID as well)
HRESULT CheckUserGroups(IADsUser *pUser)
{
IADsMembers *pGroups;
HRESULT hr = S_OK;
hr = pUser->Groups(&pGroups);
pUser->Release();
if (FAILED(hr)) return hr;
IUnknown *pUnk;
hr = pGroups->get__NewEnum(&pUnk);
if (FAILED(hr)) return hr;
pGroups->Release();
IEnumVARIANT *pEnum;
hr = pUnk->QueryInterface(IID_IEnumVARIANT, (void**)&pEnum);
if (FAILED(hr)) return hr;
pUnk->Release();
// Enumerate.
BSTR bstr;
VARIANT var;
IADs *pADs;
ULONG lFetch;
IDispatch *pDisp;
VariantInit(&var);
hr = pEnum->Next(1, &var, &lFetch);
while (hr == S_OK)
{
if (lFetch == 1)
{
pDisp = V_DISPATCH(&var);
pDisp->QueryInterface(IID_IADs, (void**)&pADs);
pADs->get_Name(&bstr);
printf("Group belonged: %S\n", bstr);
SysFreeString(bstr);
pADs->get_GUID(&bstr);
printf("Group guid: %S\n", bstr);
SysFreeString(bstr);
pADs->Release();
}
VariantClear(&var);
pDisp = NULL;
hr = pEnum->Next(1, &var, &lFetch);
};
hr = pEnum->Release();
return S_OK;
}
int main()
{
CoInitialize(NULL);
CComPtr<IADsUser> pUser;
std::wstring ADpathName = std::wstring(L"WinNT://domain/user");
if( ADsGetObject(ADpathName.c_str(), IID_IADsUser, (void**)&pUser) == S_OK )
{
CheckUserGroups(pUser);
}
return 0;
}
However, the GUID for all groups is the same and doesn't reflect the real group GUID. why is that?

Finding if the end point is default end point in windows 8

I have a code where I can enumerate all the audio-endpoints on my system, but I don't know how to find which end point is the default end point.
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hr = S_OK;
IMMDeviceEnumerator *pEnumerator = NULL;
IMMDeviceCollection *pCollection = NULL;
IMMDevice *pEndpoint = NULL;
IPropertyStore *pProps = NULL;
LPWSTR pwszID = NULL;
system("pause");
CoInitialize(NULL);
hr = CoCreateInstance(
CLSID_MMDeviceEnumerator, NULL,
CLSCTX_ALL, IID_IMMDeviceEnumerator,
(void**) &pEnumerator);
EXIT_ON_ERROR(hr)
hr = pEnumerator->EnumAudioEndpoints(
eRender, DEVICE_STATE_ACTIVE,
&pCollection);
EXIT_ON_ERROR(hr)
UINT count;
hr = pCollection->GetCount(&count);
EXIT_ON_ERROR(hr)
if (count == 0)
{
printf("No endpoints found.\n");
}
// Each loop prints the name of an endpoint device.
for (ULONG i = 0; i < count; i++)
{
// Get pointer to endpoint number i.
hr = pCollection->Item(i, &pEndpoint);
EXIT_ON_ERROR(hr)
// Get the endpoint ID string.
hr = pEndpoint->GetId(&pwszID);
EXIT_ON_ERROR(hr)
hr = pEndpoint->OpenPropertyStore(
STGM_READ, &pProps);
EXIT_ON_ERROR(hr)
PROPVARIANT varName;
// Initialize container for property value.
PropVariantInit(&varName);
// Get the endpoint's friendly-name property.
hr = pProps->GetValue(
PKEY_Device_FriendlyName, &varName);
EXIT_ON_ERROR(hr)
hr = pProps->GetValue(PKEY_Device_DeviceDesc, &varName );
EXIT_ON_ERROR(hr)
// Print endpoint friendly name and endpoint ID.
printf("Endpoint %d: \"%S\" (%S)\n",i, varName.pwszVal, pwszID);
//printf("Endpoint %d: \"%S\" (%S)\n",i, varName.pwszVal, pwszID);
CoTaskMemFree(pwszID);
pwszID = NULL;
PropVariantClear(&varName);
SAFE_RELEASE(pProps)
SAFE_RELEASE(pEndpoint)
}
SAFE_RELEASE(pEnumerator)
SAFE_RELEASE(pCollection)
system("pause");
return 0;
Exit:
printf("Error!\n");
CoTaskMemFree(pwszID);
SAFE_RELEASE(pEnumerator)
SAFE_RELEASE(pCollection)
SAFE_RELEASE(pEndpoint)
SAFE_RELEASE(pProps)
}
First of all, you should get the default driver:
using C#
const uint DRVM_MAPPER_PREFERRED_GET = 0x2015;
const uint DRVM_MAPPER_PREFERRED_SET = 0x2016;
uint ret = waveOutMessage(
WAVE_MAPPER,
DRVM_MAPPER_PREFERRED_GET,
ref defaultDeviceId,
ref param1);
So the defaultDeviceId variable will contain the correct index, and then you should query the defaultdriverName with waveOutGetDevCaps from system. The LPWAVEOUTCAPS will contain a valid szPname member.
And finally, you should compare this string(szPname) with value of PKEY_Device_FriendlyName property:
using C++
PROPVARIANT friendlyName;
PropVariantInit(&friendlyName);
hr = propertyStore->GetValue(PKEY_Device_FriendlyName, &friendlyName);
bstr_friendlyName = ::SysAllocString(friendlyName.pwszVal);
if (NULL != wcsstr(friendlyName.pwszVal, woc.szPname))//WAVEOUTCAPS szPname
//def device
uint ret = waveOutMessage(WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, ref defaultDeviceId, ref param1);
if (ret == MMSYSERR_NOERROR)
{
int waveOutDevicesCount = waveOutGetNumDevs(); //get total
if (waveOutDevicesCount > defaultDeviceId)
{
WaveOutCaps waveOutCaps = new WaveOutCaps();
waveOutGetDevCapsA((int)defaultDeviceId, ref waveOutCaps,
Marshal.SizeOf(typeof(WaveOutCaps)));
string defaultDeviceName = (new string(waveOutCaps.szPname).Remove(
new string(waveOutCaps.szPname).IndexOf('\0')).Trim());

Leverging Remote Assistance in Vista

On Windows XP there is a known way to create a Remote Assistance Ticket.
http://msdn.microsoft.com/en-us/library/ms811079.aspx
But on Vista this does not appear to work. How does one do this on Vista or Windows 7?
There turns out to be two ways. The Microsoft API is called IRASrv and is documented here:
http://msdn.microsoft.com/en-us/library/cc240176(PROT.10).aspx
Another way is to simply call msra.exe. with password and novice params (e.g. msra.exe /saveasfile testfile thepassword). However that does prompt the user with the password dialog.
Here is example code for calling the IRASrv interface and generating a Remote Assistance Connection String.
COSERVERINFO si; ::ZeroMemory( &si, sizeof( si ) );
MULTI_QI qi; ::ZeroMemory( &qi, sizeof( qi ) );
HRESULT hr = S_OK;
BSTR bstrUserName = SysAllocString(L"jon");
BSTR bstrDomainName = SysAllocString(L"");
BSTR bstrPasswordStr = SysAllocString(L"testpass");
// Get the security information entered by the user
_bstr_t bstrUser(bstrUserName);
_bstr_t bstrDomain(bstrDomainName);
_bstr_t bstrPassword(bstrPasswordStr);
// Set AuthIdentity
SEC_WINNT_AUTH_IDENTITY_W AuthIdentity = {
(unsigned short*)bstrUserName,
bstrUser.length(),
(unsigned short*)bstrDomainName,
bstrDomain.length(),
(unsigned short*)bstrPasswordStr,
bstrPassword.length(),
SEC_WINNT_AUTH_IDENTITY_UNICODE
};
COAUTHINFO AuthInfo = {
RPC_C_AUTHN_WINNT,
RPC_C_AUTHZ_DEFAULT,
NULL,
RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // The authentication level used
RPC_C_IMP_LEVEL_IMPERSONATE,
(COAUTHIDENTITY*)&AuthIdentity,
EOAC_NONE
};
si.pAuthInfo = &AuthInfo;
si.pwszName = bstrMachineName;
qi.pIID = &(__uuidof(RAServerLib::IRASrv));
hr = ::CoCreateInstanceEx(
__uuidof(RAServerLib::RASrv), NULL, CLSCTX_REMOTE_SERVER,
&si, 1, &qi );
if (FAILED(hr))
{
return hr;
}
CComPtr<RAServerLib::IRASrv> prasrv;
hr = qi.pItf->QueryInterface(__uuidof(RAServerLib::IRASrv), (void**)&prasrv);
if (FAILED(hr))
{
return hr;
}
LPWSTR pstr=NULL;
hr = prasrv->raw_GetNoviceUserInfo(&pstr);
if (FAILED(hr))
{
return hr;
}
pstr contains the Remote Assistance Connection String (type 2)

Resources