Overwritten HOME Variable - bash

I recently learned that ~ refers to the HOME variable. So, if I set HOME=/foo and then try to use a bash script that would like to cd ~/Documents it ends up saying:
foo/Documents: No such file or directory
What's best practice in this situation? Crash and complain to the user that they overwrote HOME? Or is there some way to recover the default value of HOME?

I think you should just treat this like any other problem accessing files. If the file you're trying to access doesn't exist, or you're trying to create a file in the directory and you can't, you print an error message. If it's critical to the operation of the application, you exit after reporting the error.
As far as I'm aware, most applications that need to use the user's home directory just use the HOME environment variable, they don't try to second guess it.
There shouldn't be any security implication of this. The user still needs appropriate permission to access the files, so redirecting HOME won't allow them to write someone else's files that they shouldn't. If your application is set-uid, it should always revert back to the user's ID when opening files in the user's directory, not use the elevated privileges.

The source of truth for the user's home directory is /etc/passwd, which contains a line for every user on the system, listing the user's name, home directory, and some other information. If your question is "what is so-and-so's home directory?", then you should look it up in /etc/passwd.*
However, while /etc/passwd is correct, if the user has clobbered $HOME with some other path, they may want you to use that value instead of the "real" home directory. Unless there's a security problem with allowing the user to spoof the home directory, it may be preferable to blindly use the value given by the user.
Personally, I would check whether $HOME is a directory (e.g. with if [[ -d "$HOME" ]]), and if so, use it as is. If not, parse it out of /etc/passwd using grep and cut, perhaps with a warning printed to stderr to remind the user that their $HOME is bad. You can grep for the UID printed by id -u, which cannot be clobbered by a non-root user.
If you're really going to worry about $HOME being clobbered, however, you should also worry about $PATH, the $LC_* variables, and several other environment variables which can break various things. Ultimately, it's easier to just assume these variables are correct and use them as-is, unless there is a security concern. That would mean just blindly use $HOME and don't worry too much about it being wrong.
* On systems which are using LDAP or a similar networked system to manage accounts, the user's account might not be listed there. In some cases, there's an /etc/passwd.cache or something similar, which may contain the user, but this is not guaranteed to work on every system. Running strace(1) on whoami(1) can help indicate where this information is coming from.

Related

Where to save application data in windows?

I am trying to make a windows application. In this application, some files get modified as a user add or delete an entry. I saved these files on the application folder itself.
But After making binary file I installed it, As I try to add a entry it get crashed.
So, I figured out the issue. The windows doesn't allow to modified files inside C:\Program Files.
So, I installed it in other drive and it works. It solved my issue temporarily but I want to know how other application works in windows.
Where do those applications save their data?
I am not talking about some data which get saved in "Documents" but something which is essential need to modified every time user makes change like theme, formates.
No user access is allowed to the "program folder", and that's for good: it is a system folder, and it should only be accessed for system related operations (like installing or uninstalling a program).
There are many places where "program data" can be stored depending on the situation, and QStandardPaths provides access to their paths, according to the category location. What you might be interested in are:
ConfigLocation: Returns a directory location where user-specific configuration files should be written. This may be either a generic value or application-specific, and the returned path is never empty.
AppDataLocation: Returns a directory location where persistent application data can be stored. This is an application-specific directory.
AppLocalDataLocation: As the previous one, but Windows specific.
AppConfigLocation: Returns a directory location where user-specific configuration files should be written. This is an application-specific directory, and the returned path is never empty.
Those paths (along with the others listed in the documentation) can be accessed using the following static methods:
standardLocations(locationType): returns a list of paths for the requested location type, in order of priority (the first is usually the preferred one);
writableLocation(locationType): returns the preferred path for which write access is allowed (usually the first of the standardLocations());
If you need to store the user configuration, you can use QStandardPaths.writableLocation(AppConfigLocation), while if you have some user-specific internal data that is used by the application (email database, document templates, etc) QStandardPaths.writableLocation(AppLocalDataLocation) should be a good choice.
In both cases, those paths may not exist, so you need to ensure that and eventually create them, possibly by using QDir(path):
dataPath = QtCore.QStandardPaths.writableLocation(AppLocalDataLocation)
dataPathDir = QtCore.QDir(dataPath)
if not dataPathDir.exists():
# create the directory (including parent directories if they don't exist);
# that the argument of mkpath is relative to the QDir's object path, so
# using '.' means that it will create the actual dataPath
dataPathDir.mkpath('.')
Note that for all of the above (especially the last 3) it's required that you correctly set both the organizationName and the applicationName.

How to check whether the target of a directory symbolic link exists?

I'm developing a Windows application that targets Windows XP.
My app needs to resolve symbolic links to files and folders. To check whether the target exists, I can use CreateFile for symbolic links to files. But after I searched Google and MSDN for a whole day, I found that if I need to get the handle of a directory, I need to use the flag FILE_FLAG_BACKUP_SEMANTICS. This requires my application to request higher privileges. I know many users are not happy with this behavior, so I need to find another way to check whether the target of a directory symbolic link exists.
I have also read Symbolic Link Effects on File Systems Functions. The other functions I can use to test for the existence of a file or directory all check the symbolic link itself, not its target. I have tried some functions like _access_s. They also only check the symbolic link itself.
So my question is whether there is any way to check whether the target of a directory symbolic link exists without requiring higher privileges.
I could use CreateFile for symbolic file to get the file handle and
then check the file is exist or not.
If FILE_FLAG_OPEN_REPARSE_POINT is not specified in call CreateFile and you get file handle this mean that symbolic link/mount point target is exist. so already not need check something. if call fail because target not exist last error will be ERROR_FILE_NOT_FOUND or ERROR_PATH_NOT_FOUND (may be also ERROR_BAD_PATHNAME)
about FILE_FLAG_BACKUP_SEMANTICS - this is very bad design of CreateFile api. this api internal call NtCreateFile. the FILE_FLAG_BACKUP_SEMANTICS mapped to FILE_OPEN_FOR_BACKUP_INTENT CreateOptions flag. this flag checked inside IopCheckBackupRestorePrivilege
This function will determine if the caller is asking for any accesses
that may be satisfied by Backup or Restore privileges, and if so,
perform the privilege checks. If the privilege checks succeed, then
the appropriate bits will be moved out of the RemainingDesiredAccess
field in the AccessState structure and placed into the
PreviouslyGrantedAccess field.
Note that access is not denied if the caller does not have either or both of the privileges, since he may be granted the desired access via
the security descriptor on the object.
so even if caller have not either or both of the Backup or Restore privileges this not create problems.
but NtCreateFile have the next 2 options: FILE_DIRECTORY_FILE and FILE_NON_DIRECTORY_FILE - this let specify are we want create/open file or directory. if we (potential) create new item - we need specify are we want create directory (FILE_DIRECTORY_FILE must be set) or not directory (FILE_NON_DIRECTORY_FILE, but by default assume this case - so optional). when we open file - both this flags is optional - if we not specify both - this mean that we not care are we open file or directory. if we care about this - need specify one of this flags.
but if look to CreateFile visible that not exist option which explicity mapped to FILE_DIRECTORY_FILE or FILE_NON_DIRECTORY_FILE. the CreateFile use for this .. FILE_FLAG_BACKUP_SEMANTICS option. this is very not logical from my view, but as is. when FILE_FLAG_BACKUP_SEMANTICS not set CreateFile pass FILE_NON_DIRECTORY_FILE option for NtCreateFile. when it set - pass FILE_OPEN_FOR_BACKUP_INTENT and not pass FILE_NON_DIRECTORY_FILE. this allow you open file or directory. and no option for set FILE_DIRECTORY_FILE - because this CreatrFile can not create new directory.
so instead have separate option for FILE_DIRECTORY_FILE and FILE_NON_DIRECTORY_FILE, CreateFile abuse FILE_FLAG_BACKUP_SEMANTICS wich have double sense here

classic asp create text file on webserver: error 800a0034 Bad_file_name_or_number

I have a classic asp page in VBS and I am trying to create a file on the web server with the following code.
Set fso = CreateObject("Scripting.FileSystemObject")
Set file1 = fso.CreateTextFile("\\localhost\inetpub\wwwroot\cs\batch\123456dirs.bat", true)
This returns the following error:
|666|800a0034|Bad_file_name_or_number
Line 666 is the CreateTextFile line.
According to the Microsoft docs, this means that I'm trying to create a file with an invalid filename. Then it explains the rules for filenames and mine appears to be perfectly valid.
Any suggestions or ideas on how I can further troubleshoot this?
first thing to check to make sure your users have access to the folder. Assuming you're not using windows authentication, make sure IUSR account has write access to the folder.
second, unless inetpub is set up as a share to folder, you're syntax won't work. if the root of your website is located in the CS folder, you can do something like:
Set file1 = fso.CreateTextFile(Server.MapPath( "/cs/batch/123456dirs.bat" ), true)
The createtextfile() function runs on the web server but in the context of the local server itself. Simply put, any path you give it must resolve as if you were logged on to a windows desktop on the server and tried to CD to that path.
The format \localhost... is a UNC path. See this question for a discussion about UNC paths and windows. Unless you know for sure that there is a UNC path mapped for \localhost then that is probably your issue. You may be making the assumption the \localhost will be a reasonable path to use, but as I said unless you know for sure it is available then this is an invalid choice.
Lastly, if you decide to set up a share for \localhost, you will be getting in to some interesting territory around the user context that the web server operates in. You see you will have to set up the share for the IIS user that is configured as the run-as identity for IIS, so you will need to know that and create the required config to give that user the share.
If it were me, I would switch to using a standard windows path, although even then you need to appreciate the run-as user context and security config, etc.

TPath.GetTempFileName replies "The directory name is invalid"

TPath.GetTempFileName (which wraps the WinAPI GetTempFileName) replies "The directory name is invalid" when called from an application run by a user who is logged into a domain.
if they use a login that isn't using the domain, it works.
The customer having a problem is in another country and I am also not familiar with how a domain controller's configuration could be changed to avoid this problem.
I assume that since my application is the one that isn't working correctly, I should be getting a temporary file name in a different way.
"run as administrator" doesn't help.
I have directed them to ensure they have full control over the folders mentioned in the TEMP & TMP system environment variables and apparently they do but it still gives the same error.
My application as a Win32 Delphi desktop application but since Windows is the source of the error, I assume this information to be of limited usefulness.
Windows 10 is the OS.
TPath.GetTempFileName calls TPath.GetTempPath at the very beginning but does not check it before calling Winapi.Windows.GetTempFileName using the returned path.
It is very likely that the call to TPath.GetTempPath returns an empty or invalid path.
MSDN says:
The GetTempPath function checks for the existence of environment variables in the following order and uses the first path found:
The path specified by the TMP environment variable.
The path specified by the TEMP environment variable.
The path specified by the USERPROFILE environment variable.
The Windows directory.
If it would return the Windows directory, the call wouldn't fail with the said message. So, probably, there is a wrong path in one of those three environment variables.
Your customer should check these variables and validate them, in terms of existence.
You say, that the paths are "apparently" okay.
Experience taught me to doubt what customers say they checked... You could make a call to TPath.GetTempPath on your own before calling TPath.GetTempFileName to check if it exists. Alternatively you can call it in case of failure as part of handling the raised exception and add the path to the error message.

How can I work with Windows security groups without knowing their localized names in advance?

I've searched around online but can't find what I'm after. Basically, during an install, we fire off a separate executable that basically brute forces a few folders to be read/write enabled for the user group "EVERYONE".
Now, the person that wrote this never took into consideration system language. I had a call with a customer in France that kept failing installation because "EVERYONE" isn't what we would expect.
I'm after an API call to Windows that would return a security group name which would be "safe" to use in a localized environment. Essentially I'm looking to safely edit this code so instead of hardcoding in "EVERYONE", we call a function instead.
The fundamental mistake here is not so much the use of EVERYONE, but rather that the code is using names at all. Instead of using names you should use the well-known SIDs. In your case you need S-1-1-0.

Resources