C++ FTP writing to file is not working - c++

I wrote this code that is SUPPOSED to write to a file on an ftp server, but it doesn't work. The file stays 0 bytes. There are also no errors. Here's my code:
#include <windows.h>
#include <wininet.h>
#include <stdio.h>
int main()
{
int error=0;
char buffer[256];
char *text="Hello world.";
HINTERNET hOpen=InternetOpen("",INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,INTERNET_FLAG_PASSIVE);
InternetGetLastResponseInfo((LPDWORD)error,(LPSTR)buffer,(LPDWORD)256);
printf("hOpen:%d:%s\n",error,buffer);
HINTERNET hConnect=InternetConnect(hOpen,"diabloip.host22.com",INTERNET_DEFAULT_FTP_PORT,"MY_USER_NAME","MY_PASSWORD",INTERNET_SERVICE_FTP,INTERNET_FLAG_PASSIVE,0);
InternetGetLastResponseInfo((LPDWORD)error,(LPSTR)buffer,(LPDWORD)256);
printf("hConnect:%d:%s\n",error,buffer);
HINTERNET hFile=FtpOpenFile(hConnect,"diabloip.host22.com/public_html/log.txt",GENERIC_WRITE,FTP_TRANSFER_TYPE_ASCII,0);
InternetGetLastResponseInfo((LPDWORD)error,(LPSTR)buffer,(LPDWORD)256);
printf("hFile:%d:%s\n",error,buffer);
InternetWriteFile(hFile,text,strlen(text),NULL);
return 0;
}

The problem is passing NULL as the last parameter to InternetWriteFile. It is not an optional parameter and if you had error checking for that call as the rest you'd see GetLastError returns 87, or ERROR_INVALID_PARAMETER.
This works correctly and cleans up some of the other issues with incorrect parameters and the excessive casting that masks the issues.
#include <windows.h>
#include <wininet.h>
#include <stdio.h>
#pragma comment(lib, "wininet.lib")
void PrintStatus(const char* title)
{
DWORD error = 0;
DWORD sz = 256;
char buffer[256];
InternetGetLastResponseInfo(&error, buffer, &sz);
printf("%s:%u:%s\n", title, error, buffer);
}
int main()
{
const char *text = "Hello world.";
HINTERNET hOpen = InternetOpen("", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, INTERNET_FLAG_PASSIVE);
PrintStatus("hOpen");
HINTERNET hConnect = InternetConnect(hOpen, "localhost", INTERNET_DEFAULT_FTP_PORT, "test", "test", INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0);
PrintStatus("hConnect");
HINTERNET hFile = FtpOpenFile(hConnect, "log.txt", GENERIC_WRITE, FTP_TRANSFER_TYPE_ASCII, 0);
PrintStatus("hFile");
DWORD wb = 0;
BOOL Success = InternetWriteFile(hFile, text, strlen(text), &wb);
if(!Success)
{
DWORD err = GetLastError();
printf("InternetWriteFile - Error = %u\n", err);
}
PrintStatus("InternetWriteFile");
InternetCloseHandle(hOpen);
return 0;
}

Related

InternetOpenUrl Unhandled exception [duplicate]

This is a shortened version of my code:
#include <iostream>
#include <urlmon.h>
#include <wininet.h>
#pragma comment(lib, "urlmon.lib")
#pragma comment(lib, "wininet.lib")
void data();
void test(std::string received) {
data();
Sleep(1);
}
void data() {
- >>HINTERNET connect = InternetOpen(L"MyBrowser", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
HINTERNET OpenAddress = InternetOpenUrl(connect, L"web page", NULL, 0, INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_KEEP_CONNECTION, 0);
char dataReceived[5000];
std::string received;
DWORD NumberOfBytesRead = 0;
while (InternetReadFile(OpenAddress, dataReceived, 5000, &NumberOfBytesRead) && NumberOfBytesRead)
{
received += std::string(dataReceived);
}
- >>InternetCloseHandle(connect);
InternetCloseHandle(OpenAddress);
test(received);
}
int main() {
data();
}
Please tell me how to normally move the selected lines (- >>) outside the function to run them once?
Change data() and test() to take an HINTERNET as a parameter, and then main() can create the HINTERNET to pass in, eg:
#include <iostream>
#include <urlmon.h>
#include <wininet.h>
#pragma comment(lib, "urlmon.lib")
#pragma comment(lib, "wininet.lib")
void data(HINTERNET connect);
void test(HINTERNET connect, std::string received) {
data(connect);
Sleep(1);
}
void data(HINTERNET connect) {
HINTERNET OpenAddress = InternetOpenUrl(connect, L"web page", NULL, 0, INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_KEEP_CONNECTION, 0);
char dataReceived[5000];
std::string received;
DWORD NumberOfBytesRead = 0;
while (InternetReadFile(OpenAddress, dataReceived, 5000, &NumberOfBytesRead) && NumberOfBytesRead)
{
received += std::string(dataReceived);
}
InternetCloseHandle(OpenAddress);
test(connect, received);
}
int main() {
HINTERNET connect = InternetOpen(L"MyBrowser", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
data(connect);
InternetCloseHandle(connect);
}

Move HINTERNET connect outside the procedure

This is a shortened version of my code:
#include <iostream>
#include <urlmon.h>
#include <wininet.h>
#pragma comment(lib, "urlmon.lib")
#pragma comment(lib, "wininet.lib")
void data();
void test(std::string received) {
data();
Sleep(1);
}
void data() {
- >>HINTERNET connect = InternetOpen(L"MyBrowser", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
HINTERNET OpenAddress = InternetOpenUrl(connect, L"web page", NULL, 0, INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_KEEP_CONNECTION, 0);
char dataReceived[5000];
std::string received;
DWORD NumberOfBytesRead = 0;
while (InternetReadFile(OpenAddress, dataReceived, 5000, &NumberOfBytesRead) && NumberOfBytesRead)
{
received += std::string(dataReceived);
}
- >>InternetCloseHandle(connect);
InternetCloseHandle(OpenAddress);
test(received);
}
int main() {
data();
}
Please tell me how to normally move the selected lines (- >>) outside the function to run them once?
Change data() and test() to take an HINTERNET as a parameter, and then main() can create the HINTERNET to pass in, eg:
#include <iostream>
#include <urlmon.h>
#include <wininet.h>
#pragma comment(lib, "urlmon.lib")
#pragma comment(lib, "wininet.lib")
void data(HINTERNET connect);
void test(HINTERNET connect, std::string received) {
data(connect);
Sleep(1);
}
void data(HINTERNET connect) {
HINTERNET OpenAddress = InternetOpenUrl(connect, L"web page", NULL, 0, INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_KEEP_CONNECTION, 0);
char dataReceived[5000];
std::string received;
DWORD NumberOfBytesRead = 0;
while (InternetReadFile(OpenAddress, dataReceived, 5000, &NumberOfBytesRead) && NumberOfBytesRead)
{
received += std::string(dataReceived);
}
InternetCloseHandle(OpenAddress);
test(connect, received);
}
int main() {
HINTERNET connect = InternetOpen(L"MyBrowser", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
data(connect);
InternetCloseHandle(connect);
}

Send POST data via HttpOpenRequestA

I'm trying to send my PC Name to my local server and save it in a file.
There is my code:
#include <stdio.h>
#include <windows.h>
#include <iostream>
#include <fstream>
#include <string>
#include <string.h>
#include <cstring>
#include <Lmcons.h>
#include <unistd.h>
#include <stdlib.h>
#include <WinInet.h>
#include <bits/stdc++.h>
#pragma comment( lib,"Wininet.lib")
using namespace std;
int main() {
TCHAR name [ UNLEN + 1 ];
DWORD size = UNLEN + 1;
static CHAR hdrs[] = "Content-Type: application/x-www-form-urlencoded";
if (GetUserName( (TCHAR*)name, &size ));
static CHAR frmdata[] = "data=", name;
HINTERNET hSession = InternetOpenA("http generic", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
HINTERNET hConnect = InternetConnect(hSession, "127.0.0.1", INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);
HINTERNET hRequest = HttpOpenRequestA(hConnect, "POST", "/test/index.php", NULL, NULL, NULL, 0, 1);
HttpSendRequestA(hRequest, hdrs, strlen(hdrs), frmdata, strlen(frmdata));
}
I've tried use static CHAR frmdata[] = "data=" + name; also but not works.
This is the error that I receive:
error: invalid operands of types 'const char [6]' and 'TCHAR [257] {aka char [257]}' to binary 'operator+'|
You can't concatenate char[] arrays like you are trying to do. Allocate a separate buffer of sufficient size and copy the input strings into it, eg:
#include <windows.h>
#include <Lmcons.h>
#include <WinInet.h>
#include <cstring>
//#include <cstdio>
using namespace std;
#pragma comment( lib, "Wininet.lib")
int main()
{
static char hdrs[] = "Content-Type: application/x-www-form-urlencoded";
char name[UNLEN + 1] = {};
DWORD size = UNLEN + 1;
GetUserNameA(name, &size);
char frmdata[5 + UNLEN + 1] = {};
strcpy(frmdata, "data=");
strcat(frmdata, name);
// alternatively:
// sprintf(frmdata, "data=%s", name);
HINTERNET hSession = InternetOpenA("http generic", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (!hSession) {
// error handling...
}
HINTERNET hConnect = InternetConnectA(hSession, "127.0.0.1", INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);
if (!hConnect) {
// error handling...
}
HINTERNET hRequest = HttpOpenRequestA(hConnect, "POST", "/test/index.php", NULL, NULL, NULL, 0, 1);
if (!hRequest) {
// error handling...
}
if (!HttpSendRequestA(hRequest, hdrs, strlen(hdrs), frmdata, strlen(frmdata))) {
// error handling...
}
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hSession);
return 0;
}
Alternatively, you can use a single buffer, just make it larger, and have GetUserNameA() populate a portion of it, then you don't need to make a copy afterwards, eg:
int main()
{
...
char frmdata[5 + UNLEN + 1] = "data=";
DWORD size = UNLEN + 1;
GetUserNameA(&frmdata[5], &size);
...
}
You need to concatenate, which std::string can do for you. You should also use the same base character type to avoid the need for additional conversions.
char name [ UNLEN + 1 ];
DWORD size = UNLEN + 1;
GetUserNameA( name, &size );
std::string frmdata;
frmdata += "data=";
frmdata += name;
...
HttpSendRequestA(hRequest, hdrs, strlen(hdrs), frmdata.data(), (DWORD)frmdata.size());
In case you want to transport unicode data (use std::wstring in that case) you will need to convert your data string to proper utf-8 (lookup WideCharToMultiByte).

Encountering seg fault in wininet ftp program

So i found this c++ program and i thought i would use it to automate backing up my files to my desktop ftp server but it always runs into the same seg fault problem, After checking the ftp server logs i can see that is does actually connect to the ftp server and log in with the user name and password but it when it reaches the actual upload part it crashes.
I ran it through the debugger in dev c++ and it says "Access violation (Seg faut)"
Is this a bug in wininet? and if so is there some sort of workaround?
#include <windows.h>
#include <wininet.h>
#pragma comment(lib, "wininet")
#include <fstream>
#include <string.h>
int send(const char * ftp, const char * user, const char * pass, const char * pathondisk, char * nameonftp)
{
HINTERNET hInternet;
HINTERNET hFtpSession;
hInternet = InternetOpen(NULL,INTERNET_OPEN_TYPE_DIRECT,NULL,NULL,0);
if(hInternet==NULL)
{
cout << GetLastError();
//system("PAUSE");
return 1;
}
hFtpSession = InternetConnect(hInternet,
(LPTSTR)ftp, INTERNET_DEFAULT_FTP_PORT,
(LPTSTR)user, (LPTSTR)pass, INTERNET_SERVICE_FTP,
INTERNET_FLAG_PASSIVE, 0);
if(hFtpSession==NULL)
{
cout << GetLastError();
//system("PAUSE");
return 1;
}
Sleep(1000);
char * buf=nameonftp;
strcat(buf,".txt");
if (!FtpPutFile(hFtpSession, (LPTSTR)pathondisk, (LPTSTR)buf, FTP_TRANSFER_TYPE_ASCII, 0)) {
cout << GetLastError();//this is never reached
return 1;
}
Sleep(1000);
InternetCloseHandle(hFtpSession);
InternetCloseHandle(hInternet);
return 0;
}
int main() {
send("127.0.0.1","testuser","test","file.pdf","backup");
return 0;
}
You must not modify string literals. Copy the string to a new buffer to edit the contents.
Also, you should use hogeA() APIs to have the system use ANSI charset explicitly.
Try this:
#include <windows.h>
#include <wininet.h>
#pragma comment(lib, "wininet")
#include <iostream>
#include <fstream>
#include <string.h>
using std::cout;
int send(const char * ftp, const char * user, const char * pass, const char * pathondisk, const char * nameonftp)
{
HINTERNET hInternet;
HINTERNET hFtpSession;
hInternet = InternetOpen(NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if(hInternet==NULL)
{
cout << GetLastError();
//system("PAUSE");
return 1;
}
hFtpSession = InternetConnectA(hInternet,
ftp, INTERNET_DEFAULT_FTP_PORT,
user, pass, INTERNET_SERVICE_FTP,
INTERNET_FLAG_PASSIVE, 0);
if(hFtpSession==NULL)
{
cout << GetLastError();
//system("PAUSE");
return 1;
}
Sleep(1000);
char * buf=new char[strlen(nameonftp) + 4 + 1];
strcpy(buf, nameonftp);
strcat(buf, ".txt");
if (!FtpPutFileA(hFtpSession, pathondisk, buf, FTP_TRANSFER_TYPE_ASCII, 0)) {
cout << GetLastError();
delete[] buf;
return 1;
}
delete[] buf;
Sleep(1000);
InternetCloseHandle(hFtpSession);
InternetCloseHandle(hInternet);
return 0;
}
int main() {
send("127.0.0.1", "testuser", "test", "file.pdf", "backup");
return 0;
}

Slightly different SHA256 on windows and linux

The code below generates SHA256 hash on Windows. As you can see it produces the hash from text "doublecheck" (5/NK+1ZAwTjzTY1PjZm0xcPRDf6KMQhmE4SVQnPOQ3M=)
I've created the code in the linux which should produce same hash, but it is different. (5/NK+1ZAwTjzTY1PjZm0xcPRDf6KMQhmE4SVQnPOQ3O/enx3tzCun78sgwQIOK6fv1T6eLc=)
Could anybody help me to fix any of those codes to get the same hashes?
Windows code:
#include "stdafx.h"
#include "Hash2.h"
#include <Wincrypt.h>
#pragma comment(lib, "Crypt32.lib")
DWORD BufSize;
#define BUF_SIZE 256
TCHAR Buf[BUF_SIZE];
CStringA BinaryToBase64(__in const byte * pbBinary, __in DWORD cbBinary)
{
ATLASSERT(pbBinary != NULL);
if (pbBinary == NULL)
AtlThrow(E_POINTER);
ATLASSERT(cbBinary != 0);
if (cbBinary == 0)
AtlThrow(E_INVALIDARG);
DWORD cchBase64;
if (!CryptBinaryToStringA(pbBinary, cbBinary, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, NULL, &cchBase64))
{
AtlThrowLastWin32();
}
CStringA strBase64;
LPSTR pszBase64 = strBase64.GetBuffer(cchBase64);
ATLASSERT(pszBase64 != NULL);
if (!CryptBinaryToStringA(pbBinary, cbBinary, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, pszBase64, &cchBase64))
AtlThrowLastWin32();
strBase64.ReleaseBuffer();
return strBase64;
}
// creates sha256 hash from string
LPCSTR CreateHash(LPCSTR tohash)
{
HCRYPTPROV hProv;
HCRYPTHASH hash;
if (CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
{
if (CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hash))
{
int sz = strlen(tohash);
if (CryptHashData(hash, (BYTE *)tohash, sz, 0))
{
ZeroMemory(&Buf, sizeof(Buf));
BufSize = sizeof(Buf);
if (!CryptGetHashParam(hash, HP_HASHVAL, (BYTE *)&Buf, &BufSize, 0))
AtlThrowLastWin32();
}
else
AtlThrowLastWin32();
if (!CryptDestroyHash(hash))
AtlThrowLastWin32();
}
else
AtlThrowLastWin32();
if (!CryptReleaseContext(hProv, 0))
AtlThrowLastWin32();
}
else
AtlThrowLastWin32();
CStringA stemp = BinaryToBase64(reinterpret_cast<BYTE *>(Buf), BufSize).Trim();
int sizeOfString = (stemp.GetLength() + 1);
LPSTR retVal = new char[sizeOfString];
strcpy_s(retVal, sizeOfString, stemp);
return retVal;
}
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
LPCSTR text = "doublecheck";
LPCSTR hash = CreateHash(text);
printf("\"%s\" hashed = %s", text, hash);
//output: "doublecheck" hashed = 5/NK+1ZAwTjzTY1PjZm0xcPRDf6KMQhmE4SVQnPOQ3M=
getchar();
}
Linux code:
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <openssl/sha.h>
#include <openssl/crypto.h>
int Base64Encode(const char* message, char** buffer) { //Encodes a string to base64
BIO *bio, *b64;
FILE* stream;
int encodedSize = 4*ceil((double)strlen(message)/3);
*buffer = (char *)malloc(encodedSize+1);
stream = fmemopen(*buffer, encodedSize+1, "w");
b64 = BIO_new(BIO_f_base64());
bio = BIO_new_fp(stream, BIO_NOCLOSE);
bio = BIO_push(b64, bio);
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Ignore newlines - write everything in one line
// edit: bad code BIO_write(bio, message, strlen(message));
BIO_write(bio, message, SHA256_DIGEST_LENGTH); // edit: correction
BIO_flush(bio);
BIO_free_all(bio);
fclose(stream);
return (0); //success
}
int main() {
unsigned char digest[SHA256_DIGEST_LENGTH];
const char* string = "doublecheck";
SHA256_CTX ctx;
SHA256_Init(&ctx);
SHA256_Update(&ctx, string, strlen(string));
SHA256_Final(digest, &ctx);
printf("SHA256 digest: %s\n", digest);
char* base64EncodeOutput;
Base64Encode((char*)digest, &base64EncodeOutput);
printf("Output (base64): %s\n", base64EncodeOutput);
// now the output here is: 5/NK+1ZAwTjzTY1PjZm0xcPRDf6KMQhmE4SVQnPOQ3M=
return 0;
}