FTP upload problem - c++

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" ???

Related

FTPPutFile triguring firewall issues causing falure

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.

CreateProcessWithLogonW : unable to start process

Hi I am completely new to programming. And please someone help me.
I am trying to start a pocess from a service.
I need to start the new process by prompting user to enter admin credentials.
I was trying to use CreateProcessWithLogonW().
Am I using the right function.
I tried to give input username, password, domain as localhost. I gave full pathe to the .exe file that i need to start.
Here is the piece of code.
CreateProcessWithLogonW(L"Administrator",
L"localhost",
L"password",
0,
NULL,
L"c:\myupdates\myapp.exe",
NORMAL_PRIORITY_CLASS | CREATE_CONSOLE,
NULL,
NULL,
&si,
&pi);
Si.cb = sizeof(si);
Si.lpDesktop = L"winsta0\\default";
But the process never started. Can you guys tell me what I am doing wrong.
And what do I need to do to promt user to enter credentials of administrator instead of hardcoding it.
None of CreateProcess* functions will do any promting. They are low level APIs and know nothing about GUI.
If you want user to be prompted, use ShellExecuteEx with runas command. Windows will first ask a permission to elevate and then prompt for credentials.
You may want to escape the program string properly as well:
L"c:\myupdates\myapp.exe"
should at least be:
L"c:\\myupdates\\myapp.exe"
Frankly, there are a multitude of things wrong with this code, from improper setup of SI, to the parameters passed to the API itself. I suggest you read up more.
One problem is passing a string literal as the command-line argument, as that argument must be modifiable. From CreateProcessWithLogon() in relation to the command-line argument:
The function can modify the contents of this string. Therefore, this parameter cannot be a pointer to read-only memory (such as a const variable or a literal string). If this parameter is a constant string, the function may cause an access violation.
You also need to escape the backslashes. Change to:
WCHAR cmdLine[] = L"c:\\myupdates\\myapp.exe"; /* 'cmdLine' is a
copy of the string
literal. */
and pass cmdLine instead.
After any WINAPI function failure check GetLastError() as it will inform you of the reason for failure.
Maybe it's too late to help you. But it might be helpful for others, though. If you use the CreateProcessWithLogonW function and you are using the Default desktop just keep lpDesktop as NULL.
If lpDesktop is not Null you have to enter the user's sid (getting with LookupAccountNamean) as a ACE in desktops and winstation's DACL
So here are the steps you have to do to add an ACE for a desktop:
get Desktop handle with OpenDesktop, use the right dwDesiredAccess
get the Security Descriptor with GetSecurityInfo and DACL_SECURITY_INFORMATIONas securityinfo
get the DACL from your Security Descriptor
Add AddAccessAllowedAcewith the sid of your User's sid
Set the modified DACL to your Desktop handle
now repeat those steps for winsta0 winstation
The commantary of Mr. Furious in the documantary helped me alot to solve this problem.
The access violation is down to the lpCommandLine parameter. That is meant to a editable memory, LPWSTR and the API function does modify the buffer. But you pass a pointer to non-modifiable memory.
But there's a more fundamental problem. You say you want to prompt for credentials from a service. Services should not show UI and in modern versions of Windows, a service simply cannot show UI. Your design is flawed and you need to re-consider it.

No bytes in named pipe

Service:
Creates std out,err,in named pipes. Attaches them to a process that it creates.
HANDLE hStdOut = CreateNamedPipe(szStdOutPipeName,
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE,
1,
100,
100,
15000,
pSa);
yStartupInfo.hStdOutput = hStdOut;
CreateProcessAsUserW( ..., yStartupInfo, ... );
This part works. The created process's output is being redirected into the pipes.
Client:
Connection to named pipe, Successful. Check if there are bytes to read with a peek (at this point bytes are pushed into the pipe!). Then read the bytes from the pipe.
hStdOutPide = CreateFileW(szPipeNameStdOut,
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL );
PeekNamedPipe(hStdOutPide,
szBuffer,
kunBufferSize,
&ulBytesRead,
&ulBytesAvailable,
&ulRemainingBytes);
if( ulBytesAvailable > 0)
ReadFile(hStdOutPide, szBuffer, 1000, &ulBytesRead, NULL)
I have removed the surrounding code that makes sure the handles are valid and the process is running and so on.
The Peek reveals that ulRemainingBytes is ALWAYS 0. Does anyone see where my error could be? I have been trying to get this to work for some time and don't know what the proper flags for anything is anymore. Please ask if you need more information!
Security Attributes in the CreateNamesPipe are generated from a method. It is used in many other places in the code so I do not believe the problem to be there.
Thanks.
PeekNamedPipe() returns a BOOL that should be checked.
If it fails (FALSE or 0), use GetLastError() to figure out the reason.
And before that you should also check the return value of CreateFile() (hStdOutPide) against INVALID_HANDLE_VALUE. If the returned handle is invalid that could well be a reason for PeekNamedPipe() to fail.
All in all you seem to be taking too many (good) results for taken. Don't! Check your return codes and never rely on luck.
Just one more thing: it's possible that the sharing flags are set improperly. Make sure that they don't conflict with what you want to do. Either way, GetLastError() will again tell you about such issue in case CreateFile() failed.
I suspect you are trying to read from the stdout rather than stdin in your child process. But from the limited code I cannot confirm this. Refer to this question for IPC using pipes
How do I take the output of one program and use it as the input of another on C++?

try to change ActivePowerScheme: RegOpenKeyEx failed with error 0

I need to set ActivePowerScheme by changing it in registry key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power\User\PowerSchemes.
So I try to do it with winapi functions RegOpenKeyEx and RegSetValueEx
wchar_t *PowerScheme=TEXT("8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c");
HKEY hRootKey = HKEY_LOCAL_MACHINE;
PWCHAR sKey = TEXT("SYSTEM\\CurrentControlSet\\Control\\Power\\User\\PowerSchemes");
PWCHAR sActivePowerS = TEXT("ActivePowerScheme");
HKEY hKeyResult = NULL;
//open
if (RegOpenKeyEx(hRootKey,sKey,0,KEY_ALL_ACCESS,&hKeyResult)!=ERROR_SUCCESS) {
//it is always failing with error 0 !
DWORD dw = GetLastError();
}
But RegOpenKeyEx() is always failing with error 0, that means "Operation completed successfully". And RegSetValueEx() returns same value.
if(RegSetValueEx(hKeyResult,sActivePowerS,0,REG_SZ,
(BYTE *)PowerScheme,wcslen(PowerScheme))!=ERROR_SUCCESS) {
//it is always failing with error 0
DWORD dw = GetLastError();
}
And of course current power scheme doesn't change value. But according to msdn:
"If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is a nonzero error code".
I will be grateful to any your answers.
P.S. it compiled in Windows 7 and executed with rights of admin
You are going about this the wrong way. You RARELY need to change stuff in the registry yourself.
Read Power Scheme Management on the MSDN site for the proper way of doing it.
As documentation states, RegOpenKeyEx does not update GetLastError, and return value is the error code itself. Would you mind checking it?
I'd bet you have ERROR_ACCESS_DENIED error here.
UPD: While this perhaps answers your question, you should consider using API suggested by RedX in order to update power management settings. Permissions on this registry key are set (for a reason!) in a way that even Administrators have only read permissions, and not write.
In the comments you state that RegOpenKeyEx returns ERROR_ACCESS_DENIED. This is because you request write access to a key to which you do not have sufficient rights because of UAC. You will need to run your process elevated to write to this key.
As others have correctly pointed out, you should not call GetLastError since RegOpenKeyEx does not set the last error value and instead returns the error code directly. More importantly you should be using the power management API rather than hacking the registry.
Even when you switch to the power management API you will still require administrator rights. You can arrange this by setting requestedExecutionLevel to requireAdministrator in your application manifest.
In Visual Studio you can make this change in the project configuration under Linker | Manifest File | UAC Execution Level.

How to find out the distinguished name of the information store to feed to IExchangeManageStore::GetMailboxTable?

There is a Microsoft knowledge base article with sample code to open all mailboxes in a given information store. It works so far (requires a bit of copy & pasting on compilers newer than VC++ 6.0).
At one point it calls IExchangeManageStore::GetMailboxTable with the distinguished name of the information store. For the Exchange 2007 Trial Virtual Server image it has to look like this:
"/o=Litware Inc/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Configuration/cn=servers/cn=DC1".
Using OutlookSpy and clicking on IMsgStore and IExchangeManageStore reveals the desired string next to "Server DN:".
I want to avoid forcing the user to put this into a config file. So if OutlookSpy can do it, how can my application find out the distinguished name of the information store where the currently open mailbox is on?
Thinking there must be a pure MAPI solution, I believe I've figured out how OutlookSpy does it.
The following code snippet, inserted after
printf("Created MAPI session\n");
in the example from KB194627, will show the Server DN.
LPPROFSECT lpProfSect;
hr = lpSess->OpenProfileSection((LPMAPIUID)pbGlobalProfileSectionGuid, NULL, 0, &lpProfSect);
if(SUCCEEDED(hr))
{
LPSPropValue lpPropValue;
hr = HrGetOneProp(lpProfSect, PR_PROFILE_HOME_SERVER_DN, &lpPropValue);
if(SUCCEEDED(hr))
{
printf("Server DN: %s\n", lpPropValue->Value.lpszA);
MAPIFreeBuffer(lpPropValue);
}
lpProfSect->Release();
}
Update:
There is the function HrGetServerDN in the EDK 5.5 source code, it extracts the Server DN from a given session's PR_EMS_AB_HOME_MTA. I'll try it if the other way turns out to be unreliable.
It'll be in Active Directory, so you'd use ADSI/LDAP to look at CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=example,DC=com. Use Sysinternals' ADExplorer to have a dig around in there to find the value you're looking for.
I'd download the source for MFCMapi and see how they do this.