I'm quite inexperienced in C++, and i'm trying to make a project, that can simply upload files from client PC's, to my plainFTP server. However, i'm noting that by default windows firewall is blocking this communication (I tested on both a PC in our active directory and outside to same result).
This is my code
void doUpload(char *LocFile, char *Rfile){
//LocFile must come with path e.g. C:\\helloworld.txt
//Rfile is the name of the file on the remote server. hi.txt
char *user="<FTPUSER>";
char *pass="<FTPPASS>";
char *ftpserver="<FTPIP>";
HINTERNET hInternet;
HINTERNET hFtpSession;
hInternet = InternetOpen(NULL,INTERNET_OPEN_TYPE_DIRECT,NULL,NULL,0);
hFtpSession = InternetConnect(hInternet,ftpserver , INTERNET_DEFAULT_FTP_PORT, user, pass, INTERNET_SERVICE_FTP, 0, 0);
//doupload
if(FtpPutFile(hFtpSession, LocFile, Rfile,FTP_TRANSFER_TYPE_BINARY,INTERNET_FLAG_PASSIVE)){
print("Upload Worked!");
Sleep(1000);
InternetCloseHandle(hFtpSession);
InternetCloseHandle(hInternet);
}
else{cout << "FAILED UPLOAD\n";cout << LocFile;cout << Rfile;}
}
The LocFile is the local file to be uploaded, and Rfile is the name to give it on the FTP server.
Interestingly even if i enable it in the firewall it seems to fail, but my main question is, is there a way to do this that will bypass the firewall/use an already permitted handle and shall not cause me to have to mess with the firewall rules in group policy (Even this would be an issue, as some computers are not in active directory)?
I know this is possibly with winsock, however in codeblocks i can't get winsock working, and i've never used it, and so would take more time than i have to code. If possible, i am looking for compatibility with windows XP up to 8.
EDIT:
I've added some more debug information, and the PC out of the Active directory is getting a timed out error, and my computer, in the AD is getting the following from internetgetlastmessage as error code 12 12003
200 Switching to Binary mode.
500 Illegal PORT command.
500 Unknown command.
Related
Running into a new Windows 10 error code opening a file for reading with CreateFile(). We get error 395, but there is scant information available about what it means or how to resolve. The details of the error from the Windows 10 SDK are as follows
Error number 395
Error constant
ERROR_CLOUD_FILE_ACCESS_DENIED
OS error message "Access to the
cloud file is denied."
The machine in question is Windows 10 Professional. It is running OneDrive, but the file is not located under the OneDrive folder. We suspect OneDrive may be using it's Known Folder Move feature
The code used to open the file is:
HANDLE hnd = ::CreateFile(fname,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_SEQUENTIAL_SCAN,
NULL);
if (hnd == INVALID_HANDLE_VALUE) {
DWORD exitcode = ::GetLastError();
printf("%d\n", exitcode);
}
If anyone has encountered this issue, we'd appreciate any insight you can share.
After careful research, we discovered this was caused by a simple permission issue. The user process executing the CreateFile() call did not have permissions to access the file which was being stored in the cloud. OneDrive's Known File Move had without our realizing it caused the folder to be stored in the cloud.
Once we realized it was a cloud-permission-issue, it was a simple matter to fix the cloud permission to allow the user process to open the file.
In our particular case, we arranged to run our process as Administrator, which allowed our call to CreateFile() to succeed. If you are trying to access a file stored in a OneDrive share that is owned by another user, then you will not be able to use this solution. You will need to ask the file owner to grant you the access you are requesting.
I've already tried:
GError *pError = NULL;
string uri = g_filename_to_uri(file.c_str(), NULL, &pError);
if (!g_app_info_launch_default_for_uri(uri.c_str(), NULL, &pError)) {
cout << "Failed to open uri: " << pError->message;
}
Here I get the error "URIs not supported". Is the uri I create here wrong?
My second approach was to spawn the file with an asynchronous command line:
file = quoteStr(file);
try {
Glib::spawn_command_line_async(file);
} catch (Glib::SpawnError error) {
cout << error.what();
} catch (Glib::ShellError error) {
cout << error.what();
}
Here the Glib::SpawnError exception is thrown with the error: "Failed to execute helper program (Invalid argument)". I mean, when I execute the quoted absolute file path in the Windows cmd, it opens the file (in this case a pdf file). Does this function work different?
Hopefully this is related and can provide a real answer rather than just a (clever!) workaround.
I ran into a strange situation: Launching a file (specifically an HTML document) by g_app_info_launch_default_for_uri() or gtk_show_uri_on_window() worked when the executable was run from my build directory. However, it did not work if I copied the exe to another directory (for distribution) and ran it from there.
In the latter case, I got the same error as your 2nd quote:
Failed to execute helper program (Invalid argument)
The build directory is not in my path, and nor is it special for any other reason (it's in a temp RAM drive). So I was completely baffled.
I then thought about that error... What helper program could it possibly be talking about?
And why might that program be found when running from the build directory? Well, my build uses a libtool wrapper, and that puts a bunch of things in the path, so that we don't need to copy all the DLLs etc in just to test builds.
So, I went to investigate whether there was anything relevant-looking in paths that might be searched by the MSYS2 shell and its libtool wrapper. The prime suspect, of course, is C:\msys64\mingw64\bin. And look what I found there:
gspawn-win64-helper-console.exe
After copying this executable to the directory from which my application is launched, my program now successfully launches the URI, regardless of which folder its executable currently resides in.
Edit
After updating my packages in MSYS2, it was back to the same error - as it seems now this is the helper that is required:
gspawn-win64-helper.exe
That actually makes more sense, since my application is graphical, not console. I guess maybe something changed here recently. You could distribute both to be extra safe.
I had a similar problem and I had to give up using glib to do that and ended up implementing a simple crossplatform (win, mac and linux) compatible way to do it:
// open an URI, different for each operating system
void
openuri(const char *url)
{
#ifdef WIN32
ShellExecute(GetActiveWindow(),
"open", url, NULL, NULL, SW_SHOWNORMAL);
#elif defined(__APPLE__)
char buffer[512];
::snprintf(buffer, sizeof(buffer), "open %s", url);
::system(buffer);
#else
char buffer[512];
::snprintf(buffer, sizeof(buffer), "xdg-open %s", url);
::system(buffer);
#endif
}
... it's not very nice but it's small and it works :)
I created a "special file system" for a very special security application.
I create a reparse point using an empty directory. Behind this reparse point is a filter driver, which handels the communication between NTFS and a usermode program, which is doing some encryption/decryption and control work (a mixture between FUSE, TrueCrypt, RamDisc,...). The whole thing is native in C/C++ and works fine unter Win7 x64.
Now I have the nice task to make it work for windwos xp x64 professional. When the whole application is running with admin rights it works fine, but when I switch to user account, I can't access the mounted directory.
The mounter and the "special file system" (lets name it sfs) are system services and an other app have to run under user account (COM relevant), the mount operation is successfull (when I switch to admin account after mount operation I can access the directory), the other parts of the application works fine too, but the only thing I can't manage is to get access to this very directory.
I gave the "everyone" and the users group and the specific user all permissions to the driver, the library(link between driver and sfs), the mounter and the special file system and did a lot in the registry too. I also gave this permissions to the mounted dir (all rigths, owner,...) but nothing works.
The debug outprint shows, that the request for the directory or the files inside never comes to to "sfs". It seems, that the IO-Manager never sends someting to this addres. An other problem is, that I can't manage to get all the debug outprints from the OS (boot in local debug mode and use DebugView.exe from SysInternals), but thats another story.
What did I miss? What is the difference between the security system of XP and Win7? Are there any basic restrictions in XP which I don't know?
Please ask if you need snippets of the code.
Any advise or idea is welcome!
Found it!
I forgot to set security for the device itselfe!
What a bad thing not to find this earlier! :-(
This is the section in the mount service:
static VOID GetSecAttr(PSECURITY_ATTRIBUTES SecAttr)
{
LPTSTR sd = L"D:P(A;;GA;;;SY)(A;;GRGWGX;;;BA)(A;;GRGW;;;WD)(A;;GR;;;RC)";
ZeroMemory(SecAttr, sizeof(SECURITY_ATTRIBUTES));
ConvertStringSecurityDescriptorToSecurityDescriptor(sd, SDDL_REVISION_1, &SecAttr->lpSecurityDescriptor, NULL);
SecAttr->nLength = sizeof(SECURITY_ATTRIBUTES);
SecAttr->bInheritHandle = TRUE;
}
static VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv)
{
//... some declarations ...
SECURITY_ATTRIBUTES sa;
//... some stuff like syncronisation, named pipe and so on...
GetSecAttr(&sa);
device = CreateFile(
MY_DEVICE_NAME,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
&sa, //!!! and this was NULL!!!
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
if (device == INVALID_HANDLE_VALUE) {/*...*/}
}
Thanks to all of you who spent time to help me!
... and why the hell did this work for Win7 ?!?
First, yes this is related to this stack overflow question, but I'm having a slightly different set of circumstances and my post there is not getting an answer.
So, on my Dell desktop workstation, Ubuntu 10.04 32 bit, I have developed a server program that is designed to offer a Unix-Domain socket to a PHP "program" run by Apache. (note: umask = 0022) I named the socket file /home/wmiller/ACT/web_socket_file. (ACT is a reference to the product name). /home/wmiller/ACT has permissions of 777. /home/wmiller/ACT/web_socket_file gets created with permissions of 777.
Now, I copy the program to my test platform, a Q7 format Intel processor board, which also has Ubuntu 10.04 32 bit and umask = 0022. Same directories, same 777 permission on the dir. However, now when i run the code /home/wmiller/ACT/web_socket_file comes up with 755 permissions and Apache/PHP can't open the Unix Domain socket because it gets r-x permissions instead of rw- or rwx. Apache is running in uid = www-data.
sockaddr_un webServAddr;
remove( g_webSocketFileName.c_str() ); // to erase any lingering file from last time
memset(&webServAddr, 0, sizeof(webServAddr));
webServAddr.sun_family = AF_UNIX;
snprintf( webServAddr.sun_path, UNIX_PATH_MAX, "%s", g_webSocketFileName.c_str() );
if (( g_webServerSock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0 )
{
PLOG( ERROR ) << "Failed to acquire the web Server socket: "; // uses google glog tool
return -1;
}
So I tried both of these and neither worked.
chmod( g_webSocketFileName.c_str(), S_IRWXU | S_IRWXG | S_IRWXO );
and
char temp[100];
sprintf( temp , "chmod o+w %s\n", g_webSocketFileName.c_str() );
system( temp );
Tried permissions of 777 and o+w.
I even tried adding a
unlink( g_webSocketFileName.c_str() );
But no help there.
Anyone have suggestions on why ir works on one machine and not on another almost identical machine?
Would I be better off to put the socket file elsewhere? Is there a standard place-where-socket-files-go?
On Linux, you need to call fchmod() on the Unix domain socket file descriptor before bind(). In this way the bind() call will create the filesystem object with the specified permissions. Calling fchmod() on an already bound socket is not effective.
Using chmod() could lead to TOCTTOU race condition. If possible, use fchmod() instead.
This is a Linux-specific hack. On most BSD systems, fchmod() will fail on a socket fd and set EINVAL.
Edit. I found this system-dependent behavior difference by tinkering. Perhaps the best "source" for this should be the kernel source code itself.
On FreeBSD, it appears that fchmod() on a Unix domain socket is defined as a no-op that sets EINVAL (Ref1)
On Linux, it appears that a Unix domain socket fd is created just like an inode, along with file modes (but with S_IFSOCK bitwise-or'ed in). (Ref2) Linux's fchmod() implementation will then happily apply changes to such an object. When binding a Unix domain socket to an address, the file modes are used in creating the filesystem-object. (Ref3) According to man 2 stat, S_IFSOCK is present in POSIX.1-2001.
If I read the sources wrong, please feel free to correct me.
As Cong Ma said, under Linux you should look at using fchmod() before the bind(). However, the umask() is still going to be applied. So the correct sequence goes like this:
// create the socket
int s = socket();
// restrict permissions
#ifdef __linux__
fchmod(s, S_IRUSR | S_IWUSR);
#endif
// bind the socket now
bind(s, &u, sizeof(u));
// finally, fix the permissions to your liking
chmod(u.sun_path, 0666); // <- change 0666 to what your permissions
Important Note: the code here does not show the error handling which is required to make sure things work as expected. See complete example here.
What is the problem with fchmod()?
If you try to set the exact mode that you need in fchmod(), the file gets created by bind() and at that point the umask gets applied. That means with a umask such as 022, you still do not get the write permissions for the group and other users (i.e. you would get 0644 instead of 0666).
One way to use fchmod() and skip on the chmod() after the bind() is to change umask with:
umask(0);
bind(...);
However, if like many of us you are running in a multithreaded application, changing the umask is probably not an option. The solution above works without having to use umask(0) which long term is a better way of doing things.
I have made a program to upload to my NAS via FTP protocol.
My program runs fine when I try to upload to my web page, but when I enter the IP of my NAS, the following line returns false:
HINTERNET MyhFtpSession = InternetConnect(MyhInternet, "ftp://89.xxx.xxx.xxx/media", INTERNET_DEFAULT_FTP_PORT, "MyUsername", "MyPassword", INTERNET_SERVICE_FTP, 0, 0);
What is the problem?
Is the IP line wrong?
From the documentation for InternetConnect():
Returns a valid handle to the session if the connection is successful, or NULL otherwise. To retrieve extended error information, call GetLastError(). An application can also use InternetGetLastResponseInfo() to determine why access to the service was denied.
In any case, the call is not returning false. Assuming you meant it returns NULL, then you need to call GetLastError() and/or InternetGetLastResponseInfo() to get the information. You can search for the meaning of the error code in the documentation on system error codes. If you post the result here, then we might be able to help you fix your problem.
First make sure you can actually connect to the site with FileZilla or something.
Also, what happens if you just put the IP address without the leading "ftp"//" and the trailing "/media" ???