-
March 30th, 2013, 02:00 AM
#1
deployment catch 22
I have dialog app that requires two external *.exe s to function properly. The most important of these is Init.exe which copies a couple of needed files from the main app root (installation) directory to a User directory on the main app's first run. The main app recognizes a 'first time' run on a given machine and, in response, runs Init.exe from the root directory which in turn creates and copies two other files, a *.dll and another *.exe to the User directory.
If all this seems unecessarily complicated, it has been forced upon me because of the enhanced security of Windows 7. The latter OS will not allow the running of Init.exe to copy files out of Programs Files (x86) without administrative privileges. In fact, any Win 7 program installed in Program Files (x86) is prevented from copying or moving files out of the root directory without administrative privileges. Not only does this create runtime problems for such programs run by non-administrators, but for my program, it simply will not run unless the necessary files are in the User directory.
Now it is easy enough to initialize the user directory manually, or even on first run of the main program, provided administrative privileges are held, but woe to the non-administrator who tries to install and run the program. I appreciate the fact that this added security is a safeguard to prevent any user from installing malicious or damaging software, but it also creates a host of other problems as noted here.
Has anyone devised a workaround to deal with this problem? How do you manage your apps in this regard? Manual setup of the User directory and files is a big thing to ask of the average user. Installation outside of Program Files (x86) is an unappealing option - mainly because Windows Installer does not provide a user-friendly option and the non-administrator installer user would have to know where to install the app - a big order for most users. Reconfiguring the security on a machine is only an option if the machine is not on a network requiring local machine security where administrative privileges are granted to only a select few.
Your thoughts and suggestions most welcome.
Last edited by Mike Pliam; March 30th, 2013 at 02:03 AM.
mpliam
-
March 30th, 2013, 05:33 AM
#2
Re: deployment catch 22
Frankly, can't you see that you're not using the correct approach?
Personally I would totally freak-out if an application created an exe and/or dlls in my user folders when runned. In my mind only malicious software do that.
-
March 30th, 2013, 06:49 AM
#3
Re: deployment catch 22
Not only does this create runtime problems for such programs run by non-administrators,
That's the whole idea!!! To improve security of the system and to attempt to prevent malicious programs doing malicious things.
but for my program, it simply will not run unless the necessary files are in the User directory.
As S_M_A has said, this is not the correct approach. No exe/dll should ever be placed in the User directory. These all belong in Program Files. If your program has been so badly designed to need these in the User directory then you should re-design your program so that it doesn't. Any program on my system that started to create exe and dll files outside of the stated Program Files folder would find itself terminated and purged with extreme predudice quicker than you could say bad idea.
All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!
C++23 Compiler: Microsoft VS2022 (17.6.5)
-
March 30th, 2013, 09:38 AM
#4
Re: deployment catch 22
Mike, ask yourself "is there an existing piece of software that does what I want to do?". If the answer is "no", then there is a reason for that, given the vast amount of Windows software that has to go through an "official" installation process.
Regards,
Paul McKenzie
-
March 30th, 2013, 01:00 PM
#5
Re: deployment catch 22
I misspoke about the dll. No dll is placed in the User directory. Sorry. But the *.exe is a simple Win32 CheckForUpdates.exe that the Main App runs via a ShellExecute to do what it's name implies. It uses the URLDownloadToFile method to download a file from a website that can be compared with the current version. The reason that CheckForUpdates.exe is copied from the Main App root to the User is because Windows 7 won't allow it to use http connection necessary from the Program Files (x86) directory. The other file that is copied to User is a short (256 bit) binary file that serves as a required key for the main app and can be changed by the user when desired.
While I certainly appreciate your comments, nowhere in them do I find a suggestion as to how to overcome the limitations imposed by Win7+ security for non-administrators. All that I gather is that we must now give up applications designed to interact with other executables that copy files to User directories or that attempt to download files from a website. If that is the case, I will need to revise my thinking on application design. Dissappointing. I thought I had solved the problem.
Last edited by Mike Pliam; March 30th, 2013 at 01:03 PM.
mpliam
-
March 30th, 2013, 10:45 PM
#6
Re: deployment catch 22
![Quote](images/misc/quote_icon.png) Originally Posted by Mike Pliam
While I certainly appreciate your comments, nowhere in them do I find a suggestion as to how to overcome the limitations imposed by Win7+ security for non-administrators. All that I gather is that we must now give up applications designed to interact with other executables that copy files to User directories or that attempt to download files from a website. If that is the case, I will need to revise my thinking on application design. Dissappointing. I thought I had solved the problem.
Frankly, I do not understand the whole drama. There's gonna be no suggestion ever "how to overcome the limitations imposed by Win7+ security for non-administrators" as the thing if existed would look absurd from security standpoint. And yes, you must change the design due to imposed limitations, or change the requirements. Period. You either keep complaining (I believe I already heard about the download thing a couple of months ago) or do your job (as it was exactly recommended last time, no change, sorry), it's absolutely up to you.
And what's wrong with copying your exe to user profile as long as the one is intended for comparison only? Or it's not?
BTW, first thing, if your app is properly versioned, there's no need to download anything to see if update required. You just request the latest available version info and compare it with the currently installed version. Second thing, if your program was installed with elevated privileges, it's absolutely normal thing to require the same for running updates. There's no any ground to be disappointed, you just do the things right way.
Best regards,
Igor
-
March 31st, 2013, 12:49 AM
#7
Re: deployment catch 22
just request the latest available version info
In order to compare the user's version with the latest and greatest version, the user would have to use his browser to go to the website to check a recent posting, a cumbersome task, or obtain 'the latest available version info' programatically and compare it with that user's version. I'm not a web expert, but I have done some fair amount of web programming (see http://www.pliatech.com and http://www.sfhi.com) using asp.net and c#. Outside of downloading a file containing update info, I'm uncertain as to how the user's app would obtain update info. Please tell me how you would do that. Most of the sophistocated programs that I've come across use a Check For Updates menu item that requires an internet connection to work (and can be rigged to autoupdate if so desired). Of course, your point and the others is well-taken, if one is not a member of the administrator group, they shouldn't be allowed to check for updates much less install them.
And thanks once again for your most valuable input. : )
Last edited by Mike Pliam; March 31st, 2013 at 12:53 AM.
mpliam
-
March 31st, 2013, 10:23 AM
#8
Re: deployment catch 22
![Quote](images/misc/quote_icon.png) Originally Posted by Mike Pliam
Outside of downloading a file containing update info, I'm uncertain as to how the user's app would obtain update info. Please tell me how you would do that.
This is just about making a single GET to the web page that replies with version info JSON/XML/plain text/whatever, no matter which way this info is built, static or extracted on the fly. You read that in memory with InternetReadFile (see sample), there's no need to write to file.
Last edited by Igor Vartanov; March 31st, 2013 at 07:33 PM.
Best regards,
Igor
-
March 31st, 2013, 11:03 AM
#9
Re: deployment catch 22
![Quote](images/misc/quote_icon.png) Originally Posted by Mike Pliam
if one is not a member of the administrator group, they shouldn't be allowed to check for updates much less install them.
Checking for need in updates is not something unsecure. The same to downloading bits. But running the downloaded file must be done with caution. The downloaded file must embed manifest where running with admin level is required.
Best regards,
Igor
-
April 3rd, 2013, 06:54 AM
#10
Re: deployment catch 22
you shouldn't download a whole exe simply to compare if your current exe is the right one. you should look into a proper versioning system and just check if you have the right version and download the exe only when necessary.
Things exist for a reason, and what you suggest wouldn't even work properly if the user ran in a low-rights environment. The admin may have set up the system so exe's don't even run other than from known locations.
The reason that CheckForUpdates.exe is copied from the Main App root to the User is because Windows 7 won't allow it to use http connection necessary from the Program Files (x86) directory.
wait. wot ? i've never heard of any such sillyness. There is no relation between program files and ability to do downloads. If there is, it's set as such by the system admin/user explicitely in their firewall/proxy and then it has a reason to be that way. If it works by copying exe's elsewhere, that's more a sign of said user failing to properly plug his own security holes than an actual inherent feature of Windows.
If your exe has a need for automatic upgrades without administrator actions, then there are solutions for that, but somewhere somehow, an admin will have to allow such automatic unattended upgrades being allowed in the first place. It'll typically involve (among others) you having to digitally sign your exe's to make sure the upgrades are indeed valid upgrades from you and not from some malware trying to abuse your autoupdate system to do it's evil deeds.
The thing to keep in mind here...
If you try to bend windows into doing things countrary to it's design or it's security goals. Expect your software to break down horribly every time a new version of windows (or even just service packs) come out and get installed.
-
April 13th, 2013, 12:53 PM
#11
Re: deployment catch 22
In fact, there are reliable programs that place dlls, exe's and whathaveyou in the User directory, e.g., Juniper Networks/Setup Client. But that is not the issue here. I agree that it would be much simpler for a non-administrator user to simply be able to read the contents of a remote server text file to determine if there is a more recent update, then let the network administrator do the rest. The problem is how to read that remote server file. Igor has suggested a way using InternetReadFile or the MFC version, but I cannot get either to work for me. Note that the Url and file exist and have been enabled for anonymous read. The non-MFC version fails to make a connection. A dump of the MFC verson buffer yields:
<html><head><title>Error</title></head><body><head><title>Directory Listing Deni
ed</title></head>
<body><h1>Directory Listing Denied</h1>This Virtual Directory does not allow con
tents to be listed.</body></body></html>
Obviously, I'm missing something here - but what?
Code:
#include "stdafx.h"
#include <Windows.h>
#include <WinInet.h>
#pragma comment (lib, "WinInet.lib")
#include <string>
#include <iostream>
using namespace std;
BOOL GetFile (HINTERNET IN hOpen, CHAR *szUrl, CHAR *szFileName);
int _tmain(int argc, _TCHAR* argv[])
{
BOOL bResult = FALSE;
HINTERNET IN hOpen = NULL;
CHAR *szUrl = "http://www.pliatech.com/UeberKrypt";
CHAR *szFileName = "ueberkryptupdate.inf";
bResult = GetFile (hOpen, szUrl, szFileName);
return 0;
}
BOOL GetFile (HINTERNET IN hOpen, // Handle from InternetOpen()
CHAR *szUrl, // Full URL
CHAR *szFileName) // Local file name
{
DWORD dwSize;
CHAR szHead[] = "Accept: */*\r\n\r\n";
VOID * szTemp[25];
HINTERNET hConnect;
FILE * pFile;
if ( !(hConnect = InternetOpenUrl ( hOpen, szUrl, szHead,
lstrlen (szHead), INTERNET_FLAG_DONT_CACHE, 0)))
{
cerr << "hConnect Error !" << endl;
return 0;
}
if ( !(pFile = fopen (szFileName, "wb" ) ) )
{
cerr << "fopen Error !" << endl;
return FALSE;
}
do
{
// Keep coping in 25 bytes chunks, while file has any data left.
// Note: bigger buffer will greatly improve performance.
if (!InternetReadFile (hConnect, szTemp, 50, &dwSize) )
{
fclose (pFile);
cerr << "InternetReadFile Error !" << endl;
return FALSE;
}
if (!dwSize)
break; // Condition of dwSize=0 indicate EOF. Stop.
else
fwrite(szTemp, sizeof (char), dwSize , pFile);
} // do
while (TRUE);
fflush (pFile);
fclose (pFile);
cout << szTemp << endl;
return TRUE;
}
The MFC version
Code:
#include "stdafx.h"
#include <afx.h>
#include <afxinet.h>
#include <Windows.h>
#include <WinInet.h>
#pragma comment (lib, "WinInet.lib")
#include <string>
#include <iostream>
using namespace std;
BOOL GetFile (CHAR *szUrl, CHAR *szFileName);
int _tmain(int argc, _TCHAR* argv[])
{
BOOL bResult = FALSE;
CHAR *szUrl = "http://www.pliatech.com/UeberKrypt";
CHAR *szFileName = "ueberkryptupdate.inf";
bResult = GetFile (szUrl, szFileName);
return 0;
}
BOOL GetFile (CHAR *szUrl, CHAR *szFileName)
{
TCHAR sz[1024];
CInternetSession session (_T("MyTest agent"), 1, INTERNET_OPEN_TYPE_DIRECT);
CStdioFile* pFile = NULL;
CHAR szHead[] = "Accept: */*\r\n\r\n";
DWORD nRead;
CFile myFile;
CFileException fileException;
if ( !myFile.Open (szFileName, CFile::modeCreate | CFile::modeReadWrite,
&fileException ) )
{
cerr << "Can't open file: " << szFileName
<< " error = " << fileException.m_cause <<"\n";
return FALSE;
}
try
{
pFile = session.OpenURL (szUrl, 1, INTERNET_FLAG_RELOAD
|INTERNET_FLAG_TRANSFER_BINARY,
szHead, -1L);
}
catch (CInternetException *pEx)
{
cerr <<"OpenUrl failed: "<< pEx-> m_dwError << endl;
return FALSE;
}
memset(sz, 0x00, 1024);
do
{
nRead = pFile->Read(sz, 1023);
if (nRead != 0)
myFile.Write (sz, nRead);
} while (nRead != 0);
cout << sz << endl;
myFile.Close();
pFile->Close();
if (pFile != NULL)
delete pFile;
session.Close();
return TRUE;
}
Any help greatly appreciated.
Last edited by Mike Pliam; April 13th, 2013 at 12:58 PM.
mpliam
-
April 13th, 2013, 05:15 PM
#12
Re: deployment catch 22
The first version fails at the InternetOpenUrl call. Read the docs for InternetOpenUrl, specifically the 'Return value' section which explains what the function returns & what to do when it returns NULL as it is in your case. Once you do that you will have more information about why the function failed & should be able to fix that problem. Once you fix that, you have the same problem as in your 2nd version. Manually confirm that your url works by testing it ("http://www.pliatech.com/UeberKrypt") with a browser.
-
April 14th, 2013, 01:17 AM
#13
Re: deployment catch 22
Thanks, Martin. The InternetOpenUrl error is:
ERROR_INTERNET_NOT_INITIALIZED 12172
Initialization of the WinINet API has not occurred. Indicates that a higher-level function, such as InternetOpen, has not been called yet.
Don't know how to properly initialize WinINetAPI.
Testing the target url file with a browser, it readily downloads the file, but that is not what I want to do, only to read it.
So I'm still in the dark about how to read file on a remote server.
mpliam
-
April 14th, 2013, 02:17 AM
#14
Re: deployment catch 22
![Quote](images/misc/quote_icon.png) Originally Posted by Mike Pliam
Thanks, Martin. The InternetOpenUrl error is:
1) Where is the call to InternetOpen()?
http://msdn.microsoft.com/en-us/libr...=vs.85%29.aspx
2) Mike, going back to your two attempts, hopefully you aren't creating software that assumes API functions work without checking and reporting errors (Calling GetLastError(), FormatMessage(), etc.).
Regards,
Paul McKenzie
-
April 14th, 2013, 09:31 AM
#15
Re: deployment catch 22
Re-read the docs for InternetOpenUrl. Specifically what it says about the 1st parameter. In general though, when you're having problems with some API, the best thing is to read/re-read the docs for it, in its entirety. The 'Parameters' section, 'Return value' section, 'Remarks', etc...everything. After that if you still have problems also try googling '<api> example c++'.
Testing the target url file with a browser, it readily downloads the file, but that is not what I want to do, only to read it.
One phrase I think applies very well to programming is 'the devil is in the details'. Did you copy & paste the *exact* url I specified in my previous post? I included it there for a reason. That's the one in your InternetOpenUrl call. Entering that in the browser gives the same 'This Virtual Directory does not allow...' error that you are getting in your program.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|