I am using OAuth2 with a server, and wininet as the http client. I cannot see how to set wininet to use a bearer token (just see how to set username and password for basic authentication). Is it possible to tell wininet to use a bearer token? (something like INTERNET_OPTION_USERNAME...)
This is same code to get access token from google. Note InternetOpenA uses NULL for username and password. If successful it reads a JSON file in to str which will contain access token, this access token is used with subsequent GET/POST requests.
std::string client_secret = "123";
std::string client_id = "1234";
std::string authorization_token = "token from browser";
std::string query, header;
{
stringstream ss;
ss << "code=" << authorization_token
<< "&client_id=" << client_id << ".apps.googleusercontent.com"
<< "&client_secret=" << client_secret
<< "&redirect_uri=urn:ietf:wg:oauth:2.0:oob&grant_type=authorization_code";
query = ss.str();
}
{
stringstream ss;
ss << "Content-Type: application/x-www-form-urlencoded\r\nContent-length: "
<< query.size() << "\r\nConnection: Close\r\n\r\n";
header = ss.str();
}
HINTERNET hopen = InternetOpenA("appname", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
HINTERNET hconnect = InternetConnectA(hopen,
"accounts.google.com", INTERNET_DEFAULT_HTTPS_PORT,
NULL, //username
NULL, //password
INTERNET_SERVICE_HTTP, 0, 1);
HINTERNET hrequest = HttpOpenRequestA(hconnect, "POST", "o/oauth2/token",
NULL, "http://localhost",
NULL, INTERNET_FLAG_SECURE | INTERNET_FLAG_DONT_CACHE, 0);
if(hrequest)
{
BOOL res = HttpSendRequestA(hrequest, header.c_str(), header.size(),
&query[0], query.size());
std::string data;
if(res)
{
DWORD received;
const int bufsize = 4096;
std::vector<BYTE> buf(bufsize);
while(InternetReadFile(hrequest, &buf[0], bufsize, &received) && received)
data.insert(data.end(), buf.begin(), buf.begin() + received);
std::string str(data.begin(), data.end());
//=> access token
}
InternetCloseHandle(hrequest);
}
InternetCloseHandle(hconnect);
InternetCloseHandle(hopen);
Pass "Authorization: Bearer " + the token to HttpAddRequestHeaders(). In my case I had to access an IdentityServer API from a win32 C++ MFC (WinInet) Client. Make sure to set InternetConnect() with the server domain instead of an IP address and that the token has correct scopes.
HINTERNET hSession, hConnect, hRequest;
hSession = InternetOpen( NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0 );
if( hSession )
{
CString strServerDomain = GetServerDomainName();
hConnect = InternetConnect( hSession, strServerDomain, INTERNET_DEFAULT_HTTPS_PORT,
NULL, NULL,INTERNET_SERVICE_HTTP, 0, 0 );
if( hConnect )
{
hRequest = HttpOpenRequest( hConnect, "GET", strParams, NULL, NULL, 0,
INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_SECURE, 0 ); // strParams = "projectName/controller/Action/"
if( hRequest )
{
CString strToken = "Your Token Goes Here"; // Token
CString strHeader = "";
strHeader.Format( "Authorization: Bearer %s", strToken );
BOOL bHeaderAdded = HttpAddRequestHeaders( hRequest, strHeader, strHeader.GetLength(), 0 );
ASSERT( bHeaderAdded );
BOOL hHttpRequest = HttpSendRequest( hRequest, NULL, 0, NULL, 0 );
Related
I am new to driver development and I want to be able to send an IRP request to the ((PDEVICE_EXTENSION)myDevice->DeviceExtension)->lowerDevice. This IRP request should be treated by the lowerDevice the same way as if I were to simply forward the incoming IRP. I am able to successfully build and send the IRP but it errors at the lowerDevice, Access violation - code c0000005. I greatly appreciate any help!
NTSTATUS DispatchRead(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
KEVENT event;
PIRP lowerIrp;
IO_STATUS_BLOCK ioStatus;
NTSTATUS status;
PIO_STACK_LOCATION pIoStackIrp = IoGetCurrentIrpStackLocation(Irp);
KeInitializeEvent(&event, NotificationEvent, FALSE);
SIZE_T len = max(pIoStackIrp->Parameters.DeviceIoControl.InputBufferLength, pIoStackIrp->Parameters.DeviceIoControl.OutputBufferLength);
PVOID InputBuffer = ExAllocatePool2(POOL_FLAG_NON_PAGED, len, 'ITag');
if (!InputBuffer) {
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory(InputBuffer, Irp->AssociatedIrp.SystemBuffer, pIoStackIrp->Parameters.DeviceIoControl.InputBufferLength);
Irp->IoStatus.Information = pIoStackIrp->Parameters.DeviceIoControl.InputBufferLength;
LARGE_INTEGER startingOffset;
startingOffset.QuadPart = (LONGLONG)0;
lowerIrp = IoBuildSynchronousFsdRequest(
IRP_MJ_READ,
((PDEVICE_EXTENSION)myDevice->DeviceExtension)->lowerDevice,
InputBuffer,
(ULONG)len,
&startingOffset,
&event,
&ioStatus
);
if (NULL == lowerIrp) {
ExFreePool(InputBuffer);
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
IoSetCompletionRoutine(lowerIrp, completionRoutine, NULL, TRUE, TRUE, TRUE);
status = IoCallDriver(((PDEVICE_EXTENSION)myDevice->DeviceExtension)->lowerDevice, lowerIrp);
if (status == STATUS_PENDING) {
status = KeWaitForSingleObject(
&event,
Executive,
KernelMode,
FALSE, // Not alertable
NULL);
status = ioStatus.Status;
}
return status;
}
I am trying to send a Raw Ethernet frame over layer 2, using the prottest.c example code for the NDIS driver, in C.
The example works without problem, but when I modify the Ether Type (0x88A4 EtherCat)
and adapt the frame with the necessary structure and information, the Writefile function always returns Error 87 (Incorrect parameters).
Is it not possible to write with this function on Layer 2, in Raw, without the TCP/IP stack, what could be wrong?
Thanks for your help.
Best regards.
VOID
DoWriteProc(
HANDLE Handle
)
{
PUCHAR pWriteBuf = NULL;
PUCHAR pData;
INT SendCount;
PETH_HEADER pEthHeader;
DWORD BytesWritten;
BOOLEAN bSuccess;
DEBUGP(("DoWriteProc\n"));
SendCount = 0;
do
{
pWriteBuf = malloc(PacketLength);
if (pWriteBuf == NULL)
{
DEBUGP(("DoWriteProc: Failed to malloc %d bytes\n", PacketLength));
break;
}
pEthHeader = (PETH_HEADER)pWriteBuf;
pEthHeader->EthType = EthType;
if (bUseFakeAddress)
{
memcpy(pEthHeader->SrcAddr, FakeSrcMacAddr, MAC_ADDR_LEN);
}
else
{
memcpy(pEthHeader->SrcAddr, SrcMacAddr, MAC_ADDR_LEN);
}
memcpy(pEthHeader->DstAddr, DstMacAddr, MAC_ADDR_LEN);
pData = (PUCHAR)(pEthHeader + 1);
*pData++ = (UCHAR)0x8C; //Lenght
*pData++ = (UCHAR)0x45; //Res & Type
*pData++ = (UCHAR)0xD0; //Publisher
*pData++ = (UCHAR)0x50;
*pData++ = (UCHAR)0x99;
*pData++ = (UCHAR)0x45;
*pData++ = (UCHAR)0x34;
*pData++ = (UCHAR)0x9D;
*pData++ = (UCHAR)0x01; //Count
*pData++ = (UCHAR)0x00;
*pData++ = (UCHAR)0x00; //Cycle
*pData++ = (UCHAR)0x00;
*pData++ = (UCHAR)0x00; //Res
*pData++ = (UCHAR)0x28; //EAP_SM
*pData++ = (UCHAR)0x04; //PD ID
*pData++ = (UCHAR)0x00;
*pData++ = (UCHAR)0x00; //Version
*pData++ = (UCHAR)0x00;
*pData++ = (UCHAR)0x78; //Lenght
*pData++ = (UCHAR)0x05;
*pData++ = (UCHAR)0x00; //Quality
*pData++ = (UCHAR)0x00;
unsigned char j = 0;
for (int k = 0; k < 1400; k++) //Data
{
*pData++ = (UCHAR)j;
j++;
if (j > 0xFF)
{
j = 0;
}
}
SendCount = 0;
while (TRUE)
{
bSuccess = (BOOLEAN)WriteFile(
Handle,
pWriteBuf,
PacketLength,
&BytesWritten,
NULL);
DWORD err = GetLastError();
printf("ERROR: %i", err);
if (!bSuccess)
{
PRINTF(("DoWriteProc: WriteFile failed on Handle %p\n", Handle));
break;
}
SendCount++;
DEBUGP(("DoWriteProc: sent %d bytes\n", BytesWritten));
if ((NumberOfPackets != -1) && (SendCount == NumberOfPackets))
{
break;
}
}
} while (FALSE);
if (pWriteBuf)
{
free(pWriteBuf);
}
PRINTF(("DoWriteProc: finished sending %d packets of %d bytes each\n",
SendCount, PacketLength));}
HANDLE
OpenHandle(_In_ PSTR pDeviceName){
DWORD DesiredAccess;
DWORD ShareMode;
LPSECURITY_ATTRIBUTES lpSecurityAttributes = NULL;
DWORD CreationDistribution;
DWORD FlagsAndAttributes;
HANDLE Handle;
DWORD BytesReturned;
DesiredAccess = GENERIC_READ | GENERIC_WRITE;
ShareMode = 0;
CreationDistribution = OPEN_EXISTING;
FlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
Handle = CreateFileA(
pDeviceName,
DesiredAccess,
ShareMode,
lpSecurityAttributes,
CreationDistribution,
FlagsAndAttributes,
NULL
);
if (Handle == INVALID_HANDLE_VALUE)
{
DEBUGP(("Creating file failed, error %x\n", GetLastError()));
return Handle;
}
//
// Wait for the driver to finish binding.
//
if (!DeviceIoControl(
Handle,
IOCTL_NDISPROT_BIND_WAIT,
NULL,
0,
NULL,
0,
&BytesReturned,
NULL))
{
DEBUGP(("IOCTL_NDISIO_BIND_WAIT failed, error %x\n", GetLastError()));
CloseHandle(Handle);
Handle = INVALID_HANDLE_VALUE;
}
return (Handle);
}
For security, the driver refuses to send these types of packets by default.
Of course, since you have the source code to the driver, you are free to modify this restriction however you like — it's your driver. You can add a line to specifically allow the 0x88A4 EtherType, or delete the entire if-statement to allow all EtherTypes. You can require the usermode process to be running as Administrator if it wants to send "suspicious" network frames.
A bit more detail on the security angle. If you allow untrusted users/programs to place arbitrary data onto the network, that may compromise or weaken network security. This is why the sample driver (and Windows in general) does not allow arbitrary programs to put arbitrary data on the network.
For example, a malicious program that has unrestricted access to the Ethernet layer can advertise a malicious DHCP server that points clients to a malicious DNS server, conduct ARP poisoning attacks on your switch, DoS a switch (with, for example, 802.3x PAUSE frames, or with LLDPDUs that undermine the QoS policy), or circumvent any firewall policies you might have.
These potential attacks aren't necessarily a deal-breaker: consider that this is roughly the equivalent of allowing someone to plug an arbitrary unmanaged device into an Ethernet jack on your network. If your network already has measures in place to defend against hostile Ethernet endpoints, then removing restrictions from the sample driver not making things much worse. Alternatively, if you have some level of trust for all the users & code on the PCs that will run your driver, then modifying the driver won't matter. Or if your threat model already assumes the network is hostile and unreliable, then removing these restrictions will only help fulfill your threat model's expectations. ;)
I consume a web services client.
I have a certificate with password. I can retrieve the certificate from my store and i can use it in InternetSetOption().
But I don't know how to send the password with the certificate.
Here is an example:
LPWSTR pswzFirstCert = L"xxxxx";// Subject of the first certificate.
LPWSTR pPassword = L"yyyyyy";// Spassword
HCERTSTORE hSystemStore; // The system store handle
PCCERT_CONTEXT pDesiredCert = NULL;
hSystemStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER,L"MY");
if(hSystemStore == NULL)
{
ShowMessage("Not Opened the MY system store.");
return;
}
// Get a certificate that has the string "Full Test Cert" in its subject.
if(pDesiredCert)
CertFreeCertificateContext(pDesiredCert);
pDesiredCert=CertFindCertificateInStore(hSystemStore, MY_ENCODING_TYPE, 0, CERT_FIND_SUBJECT_STR, pswzFirstCert, NULL);
if(pDesiredCert == NULL)
{
ShowMessage("The certificate was not found.");
return;
}
if(hSystemStore)
CertCloseStore(hSystemStore, CERT_CLOSE_STORE_CHECK_FLAG);
if( InternetSetOption (Data, INTERNET_OPTION_CLIENT_CERT_CONTEXT, (LPVOID)pDesiredCert, sizeof (CERT_CONTEXT) ) == FALSE )
ShowMessage("InternetSetOption failed with error.");
if( InternetSetOption (Data, INTERNET_OPTION_PASSWORD, (LPVOID)pPassword, sizeof (pPassword) ) == FALSE )
ShowMessage("InternetSetOption failed with error.");
if(pDesiredCert)
CertFreeCertificateContext(pDesiredCert);
The LuaSocket documentation says:
unconnected:sendto(datagram, ip, port)
If successful, the method returns 1. In case of error, the method
returns nil followed by an error message.
But I get a value of 4. What does return value of 4 means?
My code is here:
local socket = require("socket")
udp = socket.udp()
udp:setsockname("*", 8080)
local msg = "Test"
m=assert(udp:sendto( msg, "228.192.1.1", 8080))
print(m)
Looking closely at the source inside udp.c for sendo method
static int meth_sendto(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1);
size_t count, sent = 0;
const char *data = luaL_checklstring(L, 2, &count);
const char *ip = luaL_checkstring(L, 3);
const char *port = luaL_checkstring(L, 4);
p_timeout tm = &udp->tm;
int err;
struct addrinfo aihint;
struct addrinfo *ai;
memset(&aihint, 0, sizeof(aihint));
aihint.ai_family = udp->family;
aihint.ai_socktype = SOCK_DGRAM;
aihint.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
err = getaddrinfo(ip, port, &aihint, &ai);
if (err) {
lua_pushnil(L);
lua_pushstring(L, gai_strerror(err));
return 2;
}
timeout_markstart(tm);
err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr,
(socklen_t) ai->ai_addrlen, tm);
freeaddrinfo(ai);
if (err != IO_DONE) {
lua_pushnil(L);
lua_pushstring(L, udp_strerror(err));
return 2;
}
lua_pushnumber(L, (lua_Number) sent);
return 1;
}
Basically, the documentation's "returns 1" statement is wrong. The return 1 statement in the code means that the actual function returns one value, which is actually pushed into the stack:
lua_pushnumber(L, (lua_Number) sent);
where the variable sent was calculated just a few statements above (check socket_sendto call.
So, the returned 4 is exactly what #moteus commented: The number of bytes sent.
sendto returns the number of bytes sent.
I am trying to develop a desktop application that uses dropbox. I am using C++, libcurl (for the requests) liboauthcpp (for the authentication) and the Rest API (from dropbox).
Since I have successed the authentication and some more operations (list and download file), I cannot manage to upload a file. I am receiving the following error: {"error": "Invalid signature."}
Here is my code:
m_upload_url = "https://api-content.dropbox.com/1/files/sandbox/";
OAuth::Consumer consumer(m_consumer_key, m_consumer_secret);
OAuth::KeyValuePairs access_token_resp_data = OAuth::ParseKeyValuePairs(m_access_token_Response);
OAuth::Token access_token = OAuth::Token::extract( access_token_resp_data );
OAuth::Client oauth = OAuth::Client(&consumer, &access_token);
string oAuthQueryString = oauth.getURLQueryString( OAuth::Http::Post, m_upload_url);
string upload_Request = (string(m_upload_url) + string("?") + oAuthQueryString);
CURL *curl;
CURLcode res;
struct curl_httppost *formpost=NULL;
struct curl_httppost *lastptr=NULL;
struct curl_slist *headerlist=NULL;
static const char buf[] = "Expect:";
curl_global_init(CURL_GLOBAL_ALL);
/* Fill in the file upload field */
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "file",
CURLFORM_FILE, "C:/Users/Desktop/textfile.txt",
CURLFORM_END);
/* Fill in the filename field */
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "name",
CURLFORM_COPYCONTENTS, "textfile",
CURLFORM_END);
/* Fill in the submit field too, even if this is rarely needed */
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "submit",
CURLFORM_COPYCONTENTS, "send",
CURLFORM_END);
curl = curl_easy_init();
/* initalize custom header list (stating that Expect: 100-continue is not
wanted */
headerlist = curl_slist_append(headerlist, buf);
if(curl) {
/* what URL that receives this POST */
curl_easy_setopt(curl, CURLOPT_URL, upload_Request.c_str());
/* only disable 100-continue header if explicitly requested */
curl_easy_setopt(curl, CURLOPT_HTTPPOST, 1L);
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunction);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
/* Perform the request, res will get the return code */
res = curl_easy_perform(curl);
string response = string(gData);
qDebug() << QString::fromStdString(response);
/* Check for errors */
if(res != CURLE_OK)
qDebug() << "curl_easy_perform() failed: %s\n" << curl_easy_strerror(res);
/* always cleanup */
curl_easy_cleanup(curl);
/* then cleanup the formpost chain */
curl_formfree(formpost);
/* free slist */
curl_slist_free_all (headerlist);
}
and here is the writeFunction:
char gData[1024*1024];
unsigned int gDataLen = 0;
size_t writeFunction( char *ptr, size_t size, size_t nmemb)
{
memcpy( &( gData[gDataLen] ), ptr, (size * nmemb) );
gDataLen += (size * nmemb);
gData[ gDataLen ] = '\0';
return (size * nmemb);
}
Any ideas, please?
EDIT:
Here is the request that the present code produces:
https://api-content.dropbox.com/1/files/sandbox/?oauth_consumer_key=xxxxxxxxxxxxxxx&oauth_nonce=13xxxxxx83cf&oauth_signature=xxxxxx%xxxxxxxxxxxxxxxxxx%xxxxx%xx&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1371107283&oauth_token=xxxxxxxxxxxxxxx&oauth_version=1.0
and the request that I produse with the plaintext method:
https://api-content.dropbox.com/1/files/sandbox/?oauth_version=1.0&oauth_signature_method=PLAINTEXT&oauth_consumer_key=xxxxxxxxxxxxxxx&oauth_token=xxxxxxxxxxxxxxx&oauth_signature=xxxxxxxxxxxxxxx&xxxxxxxxxxxxxxx
Response that O get in both cases:
{"error": "Invalid signature."}
What OAuth signature method are you using? If it's anything but plaintext, then I believe the problem is that you're not passing the body of the HTTP request to getURLQueryString. The body needs to be part of the string that's signed. This explains why you've been able to get a few GET operations to work; those requests don't have a body.
Side note: it looks like you're using the POST form of file upload, which, as the docs say is considerably more complex than PUT. I think your life will be better if you switch. :-) For example, I think the submit field that you're adding will probably cause the call to not work.
EDIT: Here's a full working example using a manually-constructed plaintext signature. Fill in the app key, app secret, token, and token secret, and be sure to have a file called "hello.txt" for this to work:
#include <stdio.h>
#include <curl/curl.h>
#include <iostream>
#include <fstream>
using namespace std;
size_t read_data(void *ptr, size_t size, size_t nmeb, void *stream)
{
return fread(ptr,size,nmeb,(FILE*)stream);
}
int main(void)
{
CURL *curl;
CURLcode res;
FILE * rfp = fopen("hello.txt", "r");
string appkey = "<APP KEY>";
string appsecret = "<APP SECRET>";
string token = "<ACCESS TOKEN>";
string token_secret = "<ACCESS TOKEN SECRET>";
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "https://api-content.dropbox.com/1/files_put/sandbox/hello.txt");
struct curl_slist *headers = NULL;
string header = "Authorization: OAuth oauth_version=\"1.0\", oauth_signature_method=\"PLAINTEXT\", oauth_consumer_key=\"" + appkey + "\", oauth_token=\"" + token + "\", oauth_signature=\"" + appsecret + "&" + token_secret + "\"";
headers = curl_slist_append(headers, header.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_PUT, 1L);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_data);
curl_easy_setopt(curl, CURLOPT_READDATA, rfp);
res = curl_easy_perform(curl);
curl_slist_free_all(headers);
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
curl_easy_cleanup(curl);
}
fclose(rfp);
return 0;
}
Has anyone used liboauthcpp? I suspect that my mistake is in the way I use getURLQueryString.. I am passing the url into this function, but I am not sure if I have to pass the data too.
And unfortunately, there is no documentation for this library.