Trying to get socket from wininet HTTP connection - c

We have a legacy application that implements an SSL tunnel over Web proxies. It uses the wininet API and it worked fine for years on XP, but now it fails on Windows 7. I've tried to isolate the code and made a small program to reproduce the problem. It's a small C program compiled with MSVC 9. See below.
On Windows 7, once connected to the proxy (status code 200), I just cannot get the socket descriptor from the API. All I get is an INVALID_SOCKET, even though all wininet functions returned successfully and GetLastError() returned 0.
On the XP machine, all works fine and the returned socket is valid.
Does anyone have any idea?
Thank you very much in advance.
#include <windows.h>
#include <wininet.h>
#include <stdio.h>
const char *_connect()
{
HINTERNET hOpen = 0;
HINTERNET hConnect = 0;
HINTERNET hRequest = 0;
int remotePort = 443;
const char *remoteHost = "a.b.c.d"; // Cannot disclose
hOpen = InternetOpen("wininet-test", INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, 0);
if (!hOpen) return "InternetOpen";
hConnect = InternetConnect(hOpen, remoteHost, remotePort, 0, 0, INTERNET_SERVICE_HTTP, 0, 0);
if (!hConnect) return "InternetConnect";
{
DWORD flags =
INTERNET_FLAG_CACHE_IF_NET_FAIL |
INTERNET_FLAG_IGNORE_CERT_CN_INVALID |
INTERNET_FLAG_IGNORE_CERT_DATE_INVALID |
INTERNET_FLAG_KEEP_CONNECTION |
INTERNET_FLAG_NO_CACHE_WRITE |
INTERNET_FLAG_PRAGMA_NOCACHE |
INTERNET_FLAG_RELOAD |
INTERNET_FLAG_RESYNCHRONIZE |
INTERNET_FLAG_SECURE;
char url[100];
sprintf(url, "http://%s:%d/", remoteHost, remotePort);
hRequest = HttpOpenRequest(hConnect, "GET", "connect.html", "HTTP/1.0", url, 0, flags, 0);
if (!hRequest) return "HttpOpenRequest";
}
{
DWORD flags=0;
DWORD bufferLength = sizeof(flags);
if (!InternetQueryOption(hRequest, INTERNET_OPTION_SECURITY_FLAGS, &flags, &bufferLength)) {
return "InternetQueryOption";
}
flags |= (SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_REVOCATION);
if (!InternetSetOption(hRequest, INTERNET_OPTION_SECURITY_FLAGS, &flags, sizeof(flags))) {
return "InternetSetOption";
}
}
if (!HttpSendRequest(hRequest, 0, 0, 0, 0)) {
return "HttpSendRequest";
} else {
char buffer[4];
DWORD bufferSize = sizeof(buffer);
if (!HttpQueryInfo(hRequest, HTTP_QUERY_STATUS_CODE, &buffer, &bufferSize, NULL)) {
return "HttpQueryInfo";
} else if (atoi(buffer) != 200) {
return "status code";
}
}
{
INTERNET_DIAGNOSTIC_SOCKET_INFO idsi;
DWORD bufferSize = sizeof(idsi);
if (!InternetQueryOption(hRequest, INTERNET_OPTION_DIAGNOSTIC_SOCKET_INFO, &idsi, &bufferSize)) {
return "InternetQueryOption";
} else if (idsi.Socket == INVALID_SOCKET) {
/* This is always the case on our Windows 7 platform, why? */
return "invalid socket";
}
}
return 0;
}
int main(int argc, const char **argv)
{
const char *error = _connect();
if (error) {
printf("ERROR: %s (%d)\n", error, GetLastError());
} else {
printf("SUCCESS\n");
}
return 0;
}

Is the HTTP request using keep-alives? If not, then my guess would be that WinInet under Win7 is invalidating the socket handle after closing it when receiving the server's response, whereas XP does not invalidate the socket.

From MSDN
INTERNET_OPTION_DIAGNOSTIC_SOCKET_INFO 67
Retrieves an INTERNET_DIAGNOSTIC_SOCKET_INFO structure that contains data about a specified HTTP Request. This flag is used by InternetQueryOption.
Windows 7: This option is no longer supported.

Are your sure your project is not compiling for unicode? In case it does you need to change your char declaration to wchar_t and prefix your constants with L like:
const wchar_t * pszTmp = L"hello world";

Related

CreateFile over USB HID device fails with Access Denied (5) since Windows 10 1809

Since the latest Windows 10 1809 update we can no longer open a USB HID keyboard-like device of ours using CreateFile. We reduced the problem to this minimal example:
#include <windows.h>
#include <setupapi.h>
#include <stdio.h>
#include <hidsdi.h>
void bad(const char *msg) {
DWORD w = GetLastError();
fprintf(stderr, "bad: %s, GetLastError() == 0x%08x\n", msg, (unsigned)w);
}
int main(void) {
int i;
GUID hidGuid;
HDEVINFO deviceInfoList;
const size_t DEVICE_DETAILS_SIZE = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + MAX_PATH;
SP_DEVICE_INTERFACE_DETAIL_DATA *deviceDetails = alloca(DEVICE_DETAILS_SIZE);
deviceDetails->cbSize = sizeof(*deviceDetails);
HidD_GetHidGuid(&hidGuid);
deviceInfoList = SetupDiGetClassDevs(&hidGuid, NULL, NULL,
DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
if(deviceInfoList == INVALID_HANDLE_VALUE) {
bad("SetupDiGetClassDevs");
return 1;
}
for (i = 0; ; ++i) {
SP_DEVICE_INTERFACE_DATA deviceInfo;
DWORD size = DEVICE_DETAILS_SIZE;
HIDD_ATTRIBUTES deviceAttributes;
HANDLE hDev = INVALID_HANDLE_VALUE;
fprintf(stderr, "Trying device %d\n", i);
deviceInfo.cbSize = sizeof(deviceInfo);
if (!SetupDiEnumDeviceInterfaces(deviceInfoList, 0, &hidGuid, i,
&deviceInfo)) {
if (GetLastError() == ERROR_NO_MORE_ITEMS) {
break;
} else {
bad("SetupDiEnumDeviceInterfaces");
continue;
}
}
if(!SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInfo,
deviceDetails, size, &size, NULL)) {
bad("SetupDiGetDeviceInterfaceDetail");
continue;
}
fprintf(stderr, "Opening device %s\n", deviceDetails->DevicePath);
hDev = CreateFile(deviceDetails->DevicePath, 0,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, 0, NULL);
if(hDev == INVALID_HANDLE_VALUE) {
bad("CreateFile");
continue;
}
deviceAttributes.Size = sizeof(deviceAttributes);
if(HidD_GetAttributes(hDev, &deviceAttributes)) {
fprintf(stderr, "VID = %04x PID = %04x\n", (unsigned)deviceAttributes.VendorID, (unsigned)deviceAttributes.ProductID);
} else {
bad("HidD_GetAttributes");
}
CloseHandle(hDev);
}
SetupDiDestroyDeviceInfoList(deviceInfoList);
return 0;
}
It enumerates all HID devices, trying to obtain the vendor ID/product ID for each one using CreateFile over the path provided by SetupDiGetDeviceInterfaceDetail and then calling HidD_GetAttributes.
This code runs without problems on previous Windows versions (tested on Windows 7, Windows 10 1709 and 1803, and the original code from which this was extracted works since always from XP onwards), but with the latest update (1809) all keyboard devices (including ours) cannot be opened, as CreateFile fails with access denied (GetLastError() == 5). Running the program as administrator doesn't have any effect.
Comparing the output before and after the update, I noticed that the devices that now cannot be opened gained a trailing \kbd in the device path, i.e. what previously was
\\?\hid#vid_24d6&pid_8000&mi_00#7&294a3305&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
now is
\\?\hid#vid_24d6&pid_8000&mi_00#7&294a3305&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}\kbd
Is it a bug/new security restriction in the latest Windows 10 version? Was this code always wrong and it worked by chance before? Can this be fixed?
Update
As a desperate attempt, we tried to remove the \kbd from the returned string... and CreateFile now works! So, now we have a workaround, but it would be interesting to understand if that's a bug in SetupDiGetDeviceInterfaceDetail, if it's intentional and if this workaround is actually the correct thing to do.
I think this is a new security restriction in the latest Windows 10 version.
I looked for the string KBD (in UTF-16 format) - it exists only in two drivers in version 1809, hidclass.sys and kbdhid.sys, and doesn't exist in version 1709.
In hidclass.sys they changed the HidpRegisterDeviceInterface function. Before this release it called IoRegisterDeviceInterface with GUID_DEVINTERFACE_HID and the ReferenceString pointer set to 0. But in the new version, depending on the result of GetHidClassCollection, it passes KBD as ReferenceString pointer.
Inside kbdhid.sys they changed KbdHid_Create, and here is a check for the KBD string to return errors (access denied or sharing violation).
To understand more exactly why, more research is needed. Some disasm:
For reference, HidpRegisterDeviceInterface from 1709 build
here ReferenceString == 0 always (xor r8d,r8d), and there's no check cmp word [rbp + a],6 on class collection data
However, KbdHid_Create in 1809 contains a bug. The code is:
NTSTATUS KbdHid_Create(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
//...
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
if (PFILE_OBJECT FileObject = IrpSp->FileObject)
{
PCUNICODE_STRING FileName = &FileObject->FileName;
if (FileName->Length)
{
#if ver == 1809
UNICODE_STRING KBD = RTL_CONSTANT_STRING(L"KBD"); // !! bug !!
NTSTATUS status = RtlEqualUnicodeString(FileName, &KBD, FALSE)
? STATUS_SHARING_VIOLATION : STATUS_ACCESS_DENIED;
#else
NTSTATUS status = STATUS_ACCESS_DENIED;
#endif
// log
Irp->IoStatus.Status = status;
IofCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
}
// ...
}
What it this function trying to do here? It looks for passed PFILE_OBJECT FileObject from Irp current stack location. It no FileObject is provided or it has an empty name, allow open; otherwise, the open fails.
Before 1809 it always failed with error STATUS_ACCESS_DENIED (0xc0000022), but starting from 1809, the name is checked, and if it's equal to KBD (case sensitive) another error - STATUS_SHARING_VIOLATION is returned. However, name always begins with the \ symbol, so it will never match KBD. It can be \KBD, so, to fix this check, the following line needs to be changed to:
UNICODE_STRING KBD = RTL_CONSTANT_STRING(L"\\KBD");
and perform the comparison with this string. So, by design we should have got a STATUS_SHARING_VIOLATION error when trying to open a keyboard device via *\KBD name, but due to an implementation error we actually got STATUS_ACCESS_DENIED here
Another change was in HidpRegisterDeviceInterface - before the call to IoRegisterDeviceInterface on the device it queries the GetHidClassCollection result, and if some WORD (2 byte) field in the structure is equal to 6, adds KBD suffix (ReferenceString). I guess (but I'm not sure) that 6 can be the Usage ID for keyboard, and the rationale for this prefix is to set Exclusive access mode
Actually, we can have a FileName begin without \ if we use relative device open via OBJECT_ATTRIBUTES. So, just for test, we can do this: if the interface name ends with \KBD, first open the file without this suffix (so with empty relative device name), and this open must work ok; then, we can try relative open file with name KBD - we must get STATUS_SHARING_VIOLATION in 1809 and STATUS_ACCESS_DENIED in previous builds (but here we will be have no \KBD suffix):
void TestOpen(PWSTR pszDeviceInterface)
{
HANDLE hFile;
if (PWSTR c = wcsrchr(pszDeviceInterface, '\\'))
{
static const UNICODE_STRING KBD = RTL_CONSTANT_STRING(L"KBD");
if (!wcscmp(c + 1, KBD.Buffer))
{
*c = 0;
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, const_cast<PUNICODE_STRING>(&KBD) };
oa.RootDirectory = CreateFileW(pszDeviceInterface, 0,
FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (oa.RootDirectory != INVALID_HANDLE_VALUE)
{
IO_STATUS_BLOCK iosb;
// will be STATUS_SHARING_VIOLATION (c0000043)
NTSTATUS status = NtOpenFile(&hFile, SYNCHRONIZE, &oa, &iosb,
FILE_SHARE_VALID_FLAGS, FILE_SYNCHRONOUS_IO_NONALERT);
CloseHandle(oa.RootDirectory);
if (0 <= status)
{
PrintAttr(hFile);
CloseHandle(hFile);
}
}
return ;
}
}
hFile = CreateFileW(pszDeviceInterface, 0,
FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
PrintAttr(hFile);
CloseHandle(hFile);
}
}
void PrintAttr(HANDLE hFile)
{
HIDD_ATTRIBUTES deviceAttributes = { sizeof(deviceAttributes) };
if(HidD_GetAttributes(hFile, &deviceAttributes)) {
printf("VID = %04x PID = %04x\r\n",
(ULONG)deviceAttributes.VendorID, (ULONG)deviceAttributes.ProductID);
} else {
bad(L"HidD_GetAttributes");
}
}
In a test on 1809 I actually got STATUS_SHARING_VIOLATION, that also shows another bug in kbdhid.KbdHid_Create - if we check FileName, we need to check RelatedFileObject - is it 0 or not.
Also, not related to bug, but as suggestion: it is more efficient to use CM_Get_Device_Interface_List instead of the SetupAPI:
volatile UCHAR guz = 0;
CONFIGRET EnumInterfaces(PGUID InterfaceClassGuid)
{
CONFIGRET err;
PVOID stack = alloca(guz);
ULONG BufferLen = 0, NeedLen = 256;
union {
PVOID buf;
PWSTR pszDeviceInterface;
};
for(;;)
{
if (BufferLen < NeedLen)
{
BufferLen = RtlPointerToOffset(buf = alloca((NeedLen - BufferLen) * sizeof(WCHAR)), stack) / sizeof(WCHAR);
}
switch (err = CM_Get_Device_Interface_ListW(InterfaceClassGuid,
0, pszDeviceInterface, BufferLen, CM_GET_DEVICE_INTERFACE_LIST_PRESENT))
{
case CR_BUFFER_SMALL:
if (err = CM_Get_Device_Interface_List_SizeW(&NeedLen, InterfaceClassGuid,
0, CM_GET_DEVICE_INTERFACE_LIST_PRESENT))
{
default:
return err;
}
continue;
case CR_SUCCESS:
while (*pszDeviceInterface)
{
TestOpen(pszDeviceInterface);
pszDeviceInterface += 1 + wcslen(pszDeviceInterface);
}
return 0;
}
}
}
EnumInterfaces(const_cast<PGUID>(&GUID_DEVINTERFACE_HID));
The fix is in this windows update released today (March 1, 2019).
https://support.microsoft.com/en-us/help/4482887/windows-10-update-kb4482887
You can find a workaround at Delphi-Praxis in German
For short: Change in the Unit JvHidControllerClass
if not HidD_GetAttributes(HidFileHandle, FAttributes) then
raise EControllerError.CreateRes(#RsEDeviceCannotBeIdentified);
to
HidD_GetAttributes(HidFileHandle, FAttributes);
and recompile the Delhi JCL and JCVL Components by running the JEDI Install EXE.

receive ip frames using ndisuio

I'm writing a DHCP client for Windows ce. after doing it all with sockets I realized that I coudn't send packets from ip 0.0.0.0 so I found that I need to use NDISUIO.
After googling about NDISUIO I can send working DHCP Discovery Packets BUT I can't receive the server response ( the program gets stuck waiting for packets). Note that I can see them in wireshark.
int cUDP::Start()
{
char MensajeLog[256];
char buff[1024];
TCHAR pDevName[1024];
TCHAR pDevBuf[1024];
PNDISUIO_QUERY_BINDING pQueryBinding;
ULONG ulData;
NDISUIO_SET_OID set_oid;
//NDISUIO_QUERY_OID query_oid;
//El ethernet type para el protocolo IP es 0x0800
USHORT uEther =0x0800;
//###########################################################
if(m_hAdapter == INVALID_HANDLE_VALUE)
m_hAdapter = CreateFile(
NDISUIO_DEVICE_NAME,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
INVALID_HANDLE_VALUE);
if(m_hAdapter == INVALID_HANDLE_VALUE || m_hAdapter == NULL)
{
m_iLastError = CUDP_SOCKET_ERROR;
return 1;
}
pQueryBinding = (PNDISUIO_QUERY_BINDING) buff;
pQueryBinding->BindingIndex = 0;
if(!DeviceIoControl( m_hAdapter,
IOCTL_NDISUIO_QUERY_BINDING,
pQueryBinding,
sizeof(NDISUIO_QUERY_BINDING),
NULL,
1024,
&m_dwReturnedBytes,
NULL))
{
CloseHandle(m_hAdapter);
return 2;
}
else
{
memset(pDevName,0,1024);
memcpy(pDevName,&buff[pQueryBinding->DeviceNameOffset], pQueryBinding->DeviceNameLength);
}
if(!DeviceIoControl( m_hAdapter,
IOCTL_NDISUIO_OPEN_DEVICE,
pDevName,
wcslen(pDevName)*sizeof(TCHAR),
NULL,
0,
&m_dwReturnedBytes,
NULL))
{
CloseHandle(m_hAdapter);
return 3;
}
if(!DeviceIoControl( m_hAdapter,
IOCTL_NDISUIO_SET_ETHER_TYPE,
&uEther,
sizeof(uEther),
NULL,
0,
&m_dwReturnedBytes,
NULL))
{
CloseHandle(m_hAdapter);
return 5;
}
ulData = NDIS_PACKET_TYPE_ALL_LOCAL|NDIS_PACKET_TYPE_BROADCAST|NDIS_PACKET_TYPE_PROMISCUOUS;
set_oid.Oid = OID_GEN_CURRENT_PACKET_FILTER;
CopyMemory(&set_oid.Data[0], &ulData,sizeof(ulData));
set_oid.ptcDeviceName = pDevName;
if(!DeviceIoControl( m_hAdapter,
IOCTL_NDISUIO_SET_OID_VALUE,
&set_oid,
sizeof(set_oid),
NULL,
0,
&m_dwReturnedBytes,
NULL))
{
CloseHandle(m_hAdapter);
return 6;
}
return 0;
};
int cUDP::ReceiveFrame ( BYTE* pBuffer,
DWORD Timeout_ms )
{
int timeout;
int timepoint;
DWORD pdwReadBytes;
socklen_t SendAddrlen = sizeof(m_SendAddr);
int BufferLen = sizeof(IPHeaderFormat) +
sizeof(UDPHeaderFormat) +
sizeof (DHCPMsgFormat);//sizeof (DHCPMsgFormat);
timepoint = GetTickCount();
do
{
timeout = GetTickCount();
{
if(!ReadFile( m_hAdapter,
pBuffer,
0,
NULL,
NULL))
{
m_iLastError = CUDP_RECEIVING_ERROR;
}
}
}while(((unsigned) (timeout - timepoint) < Timeout_ms));
return m_iLastError;
};
Anyone can push me in the right direction? thanks in advance
After reading and searching a lot, I found that the problem was on the call to DeviceIoControl with IOCTL_NDISUIO_SET_ETHER_TYPE. It turns out that uEther must be in network byte order so changing this variable to uEther = 0x0008; will do the trick.

How to Send IOCTL's to all drivers on windows in C

Can someone provide me with a sample C code that list´s all device Names that i can open with Createfile()? i always get error code 3 : path does not exist
sample code that doesnt works:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <windows.h>
#include <regstr.h>
#include <devioctl.h>
#include <usb.h>
#include <usbiodef.h>
#include <usbioctl.h>
#include <usbprint.h>
#include <setupapi.h>
#include <devguid.h>
#include <wdmguid.h>
#pragma comment(lib, "Setupapi.lib")
int main(void){
HDEVINFO deviceInfoList;
deviceInfoList = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);
if (deviceInfoList != INVALID_HANDLE_VALUE)
{
SP_DEVINFO_DATA deviceInfoData;
deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (DWORD i = 0; SetupDiEnumDeviceInfo(deviceInfoList, i, &deviceInfoData); i++)
{
LPTSTR buffer = NULL;
DWORD buffersize = 0;
while (!SetupDiGetDeviceInstanceIdA(deviceInfoList, &deviceInfoData, buffer, buffersize, &buffersize))
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
if (buffer) delete buffer;
buffer = new TCHAR[buffersize];
}
else
{
printf("%ls\n", "error");
break;
}
}
HANDLE hFile = CreateFileA(buffer,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if (hFile == INVALID_HANDLE_VALUE) {
printf("InvalidHandle, error code: %d\n", GetLastError());
}
CloseHandle(hFile);
printf("%s\n", buffer);
if (buffer) { delete buffer; buffer = NULL; }
}
}
getchar();
}
my Goal is to print all valid device Names and try to get a valid handle on it that i can later user for sending ioctl`s
thx
EDIT:
ok abhineet so thats what i got now :
DWORD EnumerateDevices(){
DWORD dwResult = 0;
HDEVINFO hdev = SetupDiGetClassDevs(&GUID_DEVCLASS_BATTERY, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);// DIGCF_ALLCLASSES
/*HDEVINFO hdev =SetupDiGetClassDevs(NULL,
0, // Enumerator
0,
DIGCF_PRESENT | DIGCF_ALLCLASSES); */
if (INVALID_HANDLE_VALUE != hdev) {
for (int idev = 0; idev < 100; idev++)
{
SP_DEVICE_INTERFACE_DATA did = { 0 };
did.cbSize = sizeof(did);
if (SetupDiEnumDeviceInterfaces(hdev, NULL, &GUID_DEVCLASS_BATTERY, idev, &did))
{
DWORD cbRequired = 0;
SetupDiGetDeviceInterfaceDetail(hdev,
&did,
NULL,
0,
&cbRequired,
0);
if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
{
PSP_DEVICE_INTERFACE_DETAIL_DATA pdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR, cbRequired);
if (pdidd) {
pdidd->cbSize = sizeof(*pdidd);
if (SetupDiGetDeviceInterfaceDetail(hdev, &did, pdidd, cbRequired, &cbRequired, 0)) {
wprintf(L"%s\n", pdidd->DevicePath);
HANDLE hBattery = CreateFile(pdidd->DevicePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE != hBattery)
{
printf("Successfully opened Handle\n");
CloseHandle(hBattery);
}
else{
wprintf(L"CreateFile(%s) failed %d\n", pdidd->DevicePath, GetLastError());
}
}
else{
printf("SetupDiGetDeviceInterfaceDetail() failed %d\n", GetLastError());
}
LocalFree(pdidd);
}
}
else{
printf("SetupDiGetDeviceInterfaceDetail() failed %d\n", GetLastError());
}
}
else if (ERROR_NO_MORE_ITEMS == GetLastError())
{
printf("-NoMoreItems-");
break; // Enumeration failed - perhaps we're out of items
}
}
SetupDiDestroyDeviceInfoList(hdev);
}
else{
printf("SetupDiGetClassDevs() failed %d\n", GetLastError());
}
return dwResult;
}
i ripped the most from here : https://msdn.microsoft.com/en-us/library/windows/desktop/bb204769(v=vs.85).aspx
and my Output is :
\\?\acpi#pnp0c0a#1#{72631e54-78a4-11d0-bcf7-00aa00b7b32a}
Successfully opened Handle
-NoMoreItems-
at least i got a valid handle!
so i wanna do this an all devices avaible on the System , how to do that?
IMHO, I don't think, you can do a CreateFile on InstanceID. To do a CreateFile, you need the symbolic name of the device. You can use the following SetupAPIs,
SetupDiEnumDeviceInterfaces
SetupDiGetDeviceInterfaceDetail
The Remark section of both APIs state that,
SetupDiEnumDeviceInterfaces:: DeviceInterfaceData points to a structure that identifies a requested
device interface. To get detailed information about an interface, call
SetupDiGetDeviceInterfaceDetail. The detailed information includes the
name of the device interface that can be passed to a Win32 function
such as CreateFile (described in Microsoft Windows SDK documentation)
to get a handle to the interface.
SetupDiGetDeviceInterfaceDetail:: The interface detail returned by this function consists of a device path that can be passed to Win32
functions such as CreateFile. Do not attempt to parse the device path
symbolic name. The device path can be reused across system starts.
This might be of your use, how to get DevicePath from DeviceID

How to use ldap_sasl_bind in WinLDAP?

I currently use ldap_bind_s to bind to the server in my C application with SEC_WINNT_AUTH_IDENTITY struct, but the function is marked as deprecated. For this reason I would like to change it to the ldap_sasl_bind_s function.
int main(void) {
LDAP *ld;
int rc = 0;
char *binddn = "cn=admin,dc=local";
const int version = LDAP_VERSION3;
SEC_WINNT_AUTH_IDENTITY wincreds;
struct berval saslcred;
wincreds.User = "admin";
wincreds.UserLength = 5;
wincreds.Password = "secret";
wincreds.PasswordLength = 6;
wincreds.Domain = NULL;
wincreds.DomainLength = 0;
wincreds.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
ld = ldap_initA("localhost", LDAP_PORT);
ldap_set_optionA(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
rc = ldap_bind_sA(ld, binddn, (PCHAR)&wincreds, LDAP_AUTH_DIGEST);
printf("0x%x\n", rc); // It's OK (0x0)
ldap_unbind(ld);
saslcred.bv_val = "secret";
saslcred.bv_len = 6;
rc = ldap_sasl_bind_sA(ld, binddn, "DIGEST-MD5", &saslcred, NULL, NULL, NULL);
printf("0x%x\n", rc); // Returns with 0x59
ldap_unbind(ld)
return 0;
}
The ldap_sasl_bind_s returns with LDAP_PARAM_ERROR code. Clearly, the function parameters are wrong above, but I can't find a working sample code with winldap and SASL binding.
I would be grateful for some guide, how to make this code working.
The last parameter of ldap_sasl_bind_sA cannot be NULL. It has to point to a place the function can put the server's response (struct berval*).
...
struct berval* serverResponse = NULL;
rc = ldap_sasl_bind_sA(ld, binddn, "DIGEST-MD5", &saslcred, NULL, NULL, &serverResponse);
...
So finally, after some research and debugging in the past two weeks, I've managed to write a working example code that uses DIGEST-MD5 authentication with WinLDAP's ldap_sasl_bind_s function. The corresponding RFC, this answer and the official SSPI documentation gave me a lot of helps.
Some gotchas that I ran into:
Regardless what documentation says about the ldap_connect function: If you would like to use the ldap_sasl_bind_s function it is not just a "good programming practice" to call it first, it is necessary. Without it the ldap_sasl_bind_s returns with LDAP_SERVER_DOWN (0x51) error code.
The valid pszTargetName (digest-uri) parameter is crucial for the InitializeSecurityContext function to avoid invalid token error.
I hope it will help others to spend less time about figuring out how to use SASL binding mechanisms with WinLDAP.
#include <stdio.h>
#include <windows.h>
#include <winldap.h>
#define SECURITY_WIN32 1
#include <security.h>
#include <sspi.h>
int _tmain(int argc, _TCHAR* argv[]) {
LDAP *ld;
int rc = 0;
const int version = LDAP_VERSION3;
SEC_WINNT_AUTH_IDENTITY wincreds;
struct berval *servresp = NULL;
SECURITY_STATUS res;
CredHandle credhandle;
CtxtHandle newhandle;
SecBufferDesc OutBuffDesc;
SecBuffer OutSecBuff;
SecBufferDesc InBuffDesc;
SecBuffer InSecBuff;
unsigned long contextattr;
ZeroMemory(&wincreds, sizeof(wincreds));
// Set credential information
wincreds.User = (unsigned short *)L"root";
wincreds.UserLength = 4;
wincreds.Password = (unsigned short *)L"p#ssword";
wincreds.PasswordLength = 8;
wincreds.Domain = NULL;
wincreds.DomainLength = 0;
wincreds.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
res = AcquireCredentialsHandle(NULL, L"WDigest", SECPKG_CRED_OUTBOUND,
NULL, &wincreds, NULL, NULL, &credhandle, NULL);
// Buffer for the output token.
OutBuffDesc.ulVersion = 0;
OutBuffDesc.cBuffers = 1;
OutBuffDesc.pBuffers = &OutSecBuff;
OutSecBuff.BufferType = SECBUFFER_TOKEN;
OutSecBuff.pvBuffer = NULL;
ld = ldap_init(L"localhost", LDAP_PORT);
rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, (void*)&version);
rc = ldap_connect(ld, NULL); // Need to connect before SASL bind!
do {
if (servresp != NULL) {
InBuffDesc.ulVersion = 0;
InBuffDesc.cBuffers = 1;
InBuffDesc.pBuffers = &InSecBuff;
/* The digest-challenge will be passed as an input buffer to
InitializeSecurityContext function */
InSecBuff.cbBuffer = servresp->bv_len;
InSecBuff.BufferType = SECBUFFER_TOKEN;
InSecBuff.pvBuffer = servresp->bv_val;
/* The OutBuffDesc will contain the digest-response. */
res = InitializeSecurityContext(&credhandle, &newhandle, L"ldap/localhost", ISC_REQ_MUTUAL_AUTH | ISC_REQ_ALLOCATE_MEMORY,
0, 0, &InBuffDesc, 0, &newhandle, &OutBuffDesc, &contextattr, NULL);
}
else {
res = InitializeSecurityContext(&credhandle, NULL, L"ldap/localhost", ISC_REQ_MUTUAL_AUTH, 0, 0, NULL, 0, &newhandle, &OutBuffDesc, &contextattr, NULL);
}
switch (res) {
case SEC_I_COMPLETE_NEEDED:
case SEC_I_COMPLETE_AND_CONTINUE:
case SEC_E_OK:
case SEC_I_CONTINUE_NEEDED:
break;
case SEC_E_INVALID_HANDLE:
return -2;
case SEC_E_INVALID_TOKEN:
return -1;
default:
break;
}
struct berval cred;
cred.bv_len = OutSecBuff.cbBuffer;
/* The digest-response will be passed to the server
as credential after the second (loop)run. */
cred.bv_val = (char *)OutSecBuff.pvBuffer;
// The servresp will contain the digest-challange after the first call.
rc = ldap_sasl_bind_s(ld, L"", L"DIGEST-MD5", &cred, NULL, NULL, &servresp);
ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &res)
} while (res == LDAP_SASL_BIND_IN_PROGRESS);
if (rc != LDAP_SUCCESS) {
printf("Bind failed with 0x%x\n", rc);
} else {
printf("Bind succeeded\n");
}
return 0;
}

Get ERROR_NOACCESS error on write DWORD value to registry by using C code

I'm not strong in C code and this is my problem:
I try to write REG_DWORD to registry (I use minGW).
However I get an error 998 ERROR_NOACCESS and don't know why.
All stuff seems valid.
In my case I try to write 777
It's really strange why so basic task, like to add value to registry seems so complicated and Google doesn't contains any information
Please, help
this is my code:
#define _WIN32_WINNT 0x0501
//#define _WIN32_WINNT 0x0500 // Windows 2000
//#define _WIN32_WINNT 0x0400 // Windows NT 4.0
//#define _WIN32_WINDOWS 0x0500 // Windows ME
//#define _WIN32_WINDOWS 0x0410 // Windows 98
//#define _WIN32_WINDOWS 0x0400 // Windows 95
#include <windows.h>
#include <stdio.h>
....
const char *WriteValue()
{
HKEY hkey;
LONG result_open, result_close;
const char *defaultVal = "0";
DWORD data = 777;
DWORD dwValue, dwType, dwSize = sizeof(dwValue);
DWORD szType = REG_DWORD;
printf("Opening Key...\n");
result_open = RegOpenKeyEx(HKEY_CURRENT_USER,
"Software\\screen-capture-recorder",
0, KEY_WRITE, &hkey);
if(result_open != ERROR_SUCCESS) {
if(result_open == ERROR_FILE_NOT_FOUND) {
printf("Not found\n");
} else {
printf("Error Opening Key\n");
}
} else {
printf("SUCCESS!!!\n");
}
printf("Writing Value named capture_height\n");
LONG result_write = RegSetValueEx(hkey, "capture_height", 0, szType, (LPBYTE)data, dwSize+1);
if(result_write != ERROR_SUCCESS) {
printf("Error Writing Value\n");
} else {
printf("SUCCESS!!!\n");
}
printf("Closing Key...\n");
result_close = RegCloseKey(hkey);
if(result_close != ERROR_SUCCESS) {
printf("Error Closing Key\n");
} else {
printf("SUCCESS!!!!\n");
}
return defaultVal;
}
[Compilation]
$ gcc -L/local/lib -I/local/include -o readRegistry readRegistry.c
[Run]
$ ./readRegistry.exe
Opening Key...
SUCCESS!!!
Writing Value named capture_height
Error Writing Value
Closing Key...
SUCCESS!!!!
[Registry before]
[EDIT 1]
Regards to #Mat comment:
I get error 998, from Winerror.h
ERROR_NOACCESS 998L
[EDIT 2]
When I run:
LONG result_write = RegSetValueEx(hkey, "capture_height", 0, szType, (LPBYTE)"0x00000006", dwSize+1);
I get no error but in registry I see Invalid DWORD (32-bit) value.
I tried to use:
int32_t i;
i = 0x00000777;
LONG result_write = RegSetValueEx(hkey, "capture_height", 0, szType, (LPBYTE)i, dwSize+1);
get the same error
[EDIT 3]
To be sure that i have right infra i run some test:
LONG result_write = RegSetValueEx(hkey, "capture_height1", 0, REG_SZ, (LPBYTE)"bobo", dwSizeI*2+1);
And I get in registry right value "bobo" defined as REG_SZ
Thanks to #Edward Clements and #Mat for help,
After hours of "monkey-work" at last I did it:
I need add mode: KEY_ALL_ACCESS
result_open = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\screen-capture-recorder", 0, KEY_ALL_ACCESS, &hkey);
and change LPBYTE to BYTE
LONG result_write = RegSetValueEx(hkey, "capture_height1", 0, REG_DWORD, (const BYTE*)&value, sizeof(value));
so now this is working code:
const char *WriteValue()
{
HKEY hkey;
LONG result_open, result_close;
const char *defaultVal = "0";
result_open = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\screen-capture-recorder", 0, KEY_ALL_ACCESS, &hkey);
if(result_open != ERROR_SUCCESS) {
if(result_open == ERROR_FILE_NOT_FOUND) {
printf("Not found\n");
} else {
printf("Error Opening Key\n");
}
} else {
printf("SUCCESS!!!\n");
}
DWORD value=777;
printf("Writing Value named capture_height\n");
LONG result_write = RegSetValueEx(hkey, "capture_height1", 0, REG_DWORD, (const BYTE*)&value, sizeof(value));
printf("response %ld\n", result_write);
if(result_write != ERROR_SUCCESS) {
printf("Error Writing Value\n");
} else {
printf("SUCCESS!!!\n");
}
printf("Closing Key...\n");
result_close = RegCloseKey(hkey);
if(result_close != ERROR_SUCCESS) {
printf("Error Closing Key\n");
} else {
printf("SUCCESS!!!!\n");
}
return defaultVal;
}
I used for answer this example
Could you try adding KEY_READ in your call to RegOpenKeyEx() so that the 4th parameter reads KEY_READ | KEY_WRITE?
[It could be that you also need to ask for the read permission when you are updating existing values]

Resources