C:\ file scan with C++, access denied to specific files - c++

Ok so I have written a code with recursive function that scans my (or any other) C:\ disc.
Using chdir() I'm changing the active directory to C:\ and using system("dir >> C:\Test\"filename") to get the files in that directory written in .txt and then reading it to know what I have. After that I'm checking for additional directories with temp.substr("<DIR>") and calling the function again just with longer path for that specific directory.
The code itself works as it should but I've ran to some directories that I can't access such as Administrator or specific folders in Windows. The only way I've found around them is by adding exeptions to the code so that it just avoids those folders. I'd like to know if there is a way to get a list of folders/files that I don't have access to from cmd since it would make my code a lot more precise or a way to access those directories.

While C++ file API does not have any idea about file permissions and such other than you'll fall when you try to read a file you don't have permissions to, C++ do have access to the Windows API. The Windows API are system calls that gives you access to native OS functionalities, such as calls to GetFileSecurity.
Note that using Windows API means your code would need to take extra steps to ensure portability if you want to run it on non Windows platforms.

The process (your program) runs with certain privileges, normally the users one. The access rights in Windows aren't as simple as "Administrator is god". Even if your user account is member of the "Administrators" group, you can not simply access everything. It usually depends if the OWNER of a file system object grants privileges to other groups and users.
A member of the "Administrators" group might be able to gain access by overriding security settings, but I would advise against that.
You might need elevated privileges and even might need to run your application under a SYSTEM account, it very much depends on what you are trying to achieve.
For more details I suggest to read the "Best practices for Security API" here:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms717796(v=vs.85).aspx
and especially the chapter "Running with Special Privileges".

Related

Create read only undeletable file

I tried to create file that will not be deletable and read only. (Its an exe, so maybe I need execute too.)
I tried to achieve it with this:
SetFileAttributes(My_File_Path,FILE_ATTRIBUTE_READONLY);
but it only protected against writes (it lets read it but not write to it), while against delete it's doing nothing, even though according to MSDN it's supposed to protect from deletion also:
A file that is read-only. Applications can read the file, but cannot write to it or delete it. This attribute is not honored on directories. For more information, see "You cannot view or change the Read-only or the System attributes of folders in Windows Server 2003, in Windows XP, or in Windows Vista
How can I prevent the file from being deleted?
The file system is NTFS.
It's for protection. The files are for kids' use, and I want to prevent them from deleting the file. (Or, make deleting hard as possible.)
I am looking for a programmatic solution
Deleting a file is a directory change, actually, not a file change. And as noted you can't use attributes, you need full-blown NTFS Access Control Lists (ACL) for that. In particular, what you need is an Access Control Entry (ACE) that
Denies
To Everyone
The right to modify the entire directory
You may optionally prefix another ACE to the ACL with the properties
Allows
To yourself
The right to modify the entire directory
ACE's on an ACL are processed in order, so this prevents you from locking yourself out.

Completely restricting all types of access to a folder

I am making a cocoa application, which creates some folders at my specified location in the user's environment. Now i want to protect these folders from any type of read, write, copy, drag access from all type of users(i.e Not accessible for admin and non-admin users).Is there a way to protect these folders from any type of access.
Can we use, NSFileManager method -setAttributes:OfItemAtPath:error:
But i am not sure on attributes dictionary of this method.
Basically i want to provide trail of some files to the user (let's say 1 day trial), and removing those files as soon as the trail expires, and all those files are placed inside a certain folder in the user's environment. What should be the best approach i should use to protect those files?
You could use NSFileManager setAttributes:OfItemAtPath:error: with the attributes key NSFilePosixPermissions. With this, you can set the Unix file permissions of your folder by specifying them with an integer value that represents the permission bit pattern. Setting it to zero would mean no access at all to that directory:
NSDictionary *attribs = [NSDictionary dictionaryWithObjectsAndKeys:
NSFilePosixPermissions, [NSNumber numberWithInt:0], nil];
However, it would still be possible to move or rename that directory.
Short answer: No. Someone with elevated privileges can do just about anything. No playing with permissions will get you there and still allow your application to access the files.
If you could just turn off all access rights how would you expect your own application to access the files? Turning on the access rights is itself an access right...
Longer answer: Maybe. This depends on what you are trying to achieve. Do you really want to stop the files being copied, or just their contents accessed?
Encryption can be used to protect content (e.g. at the file level, using an encrypted sparsebundle image, etc.), storing identification information in a file can alert you that you’re using a copy (e.g. see what happens if you move/copy a VMWare virtual machine or recreate a Google Drive folder), etc.
And you can always implement your own filesystem using FUSE; and prevent copying, access, etc. by your own mechanism, however the filesystem as a whole could still be copied (i.e. effectively implement your own equivalent of an encrypted sparsebundle via FUSE and implement your own access mechanism).
What are you trying to achieve? If you spell that out folk might be able to suggest alternative solutions.
See also this question on preventing root from writing to files.

How to get paths to user desktops from a service?

I need to enumerate paths to desktop folders for all users on a local Windows system from a service application. The catch is that some users may not be logged in at the time. So is there any API, or some other method to do that?
EDIT1: For those who didn't read the first paragraph let me repeat -- I do not have a token to a user account, a user may not be logged in at the time.
EDIT2: I need this to remove a shortcut from user desktops before a feature supported by my application is turned off, or the app is uninstalled.
Here's the best method I was able to come up so far. So I'd appreciate if someone with a non-English installation of Windows could check this for me?
(I'm posting just a pseudo-code for brevity.)
1 - All of the steps below are done from a local service application.
2 - To get paths to all user profiles enumerate subfolders in the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList key and read ProfileImagePath value from them. It will give profile paths for each user account.
3 - To get the folder name for the desktop, read the Desktop value from the HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders key from the service app (yes, I know HKCU sounds strange, but it worked for me.) After that get the path for the %USERPROFILE% environment variable, using environment variable APIs. So you'll get two paths, something like this:
C:\Windows\system32\config\systemprofile\Desktop
and
C:\Windows\system32\config\systemprofile
Then simply isolate the 2nd string from the 1st, using case-insensitive comparison, and you'll get the folder name for the desktop, (i.e. "\Desktop" in this case.)
4 - Add the desktop folder to the path obtained in step 2 to produce the full path to that user's desktop folder.
From userenv.h : GetProfilesDirectory (win2k+, iirc)
msdn.microsoft.com/en-us/library/windows/desktop/bb762278(v=vs.85).aspx
Use this to find the directory containing all the local user account profile directories.
To find the desktop folder:
Shlobj.h : SHGetKnownFolderPath (vista+)
msdn.microsoft.com/en-us/library/windows/desktop/bb762188(v=vs.85).aspx
You'll need FOLDERID_Desktop as the known-folder id. This symbol is declared in Knownfolders.h
msdn.microsoft.com/en-us/library/windows/desktop/dd378457(v=vs.85).aspx
Using these, you might get closer to what you want without directly reading the registry. Of course this belies any elegant way of enumerating the users aside from inferring from the folder list within the
GetProfilesDirectory. Perhaps there is a more api appropriate way to enumerate the local users.
Secondly, and this depends on the purpose of your service, but perhaps by working with the 'allusers' profile, instead of each individually you won't need to know the current list of local users.

How to detect if a file exists w/o getting derailed by permissions issues?

There are at least three techniques for detecting if a file exists:
Query the file attributes
Use FindFile() with a specific filename instead of a search pattern
Open the file in read mode and look at any resulting error
All of the above seem to suffer from false negatives. That is, I am told that the file doesn't exist when it actually does due to either glitches in how file-io over a network works, or due to file permissions issues.
I have a customer who can see that a file exists in explorer, delete that file, but is given "access denied" if they try to view that file.
I have been unsuccessful at replicating this exact behavior. But what I can create is a situation where the file exists, but due to restricting permissions on it, I cannot see the file in that folder under my user credentials. That is, GetFileAttributes(), FindFile(), and fopen() return failure, i.e. file not found for that file (but if I look in that same folder under a different account - say a network admin, I can see that the file most certainly exists).
As to how my end user (or anyone) would end up in such situations is opaque to me. I have no concrete ideas - maybe power failure while the file was previously opened, maybe some sort of network glitch causing the file handle to remain locked to a dead process on a foreign PC, ...? I'm just making stuff up because I have no idea what might cause such situations to arise.
However, what I really don't have is the ability to query Windows and know for a fact "does file X exist, or not"
Does anyone know of a technique that will honestly answer that question regardless of the user's permissions (assuming that they're allowed to query the contents of the folder itself - I'm not asking for an unauthorized access scenario - just a "normal" user X can't edit file Y, but still wants to know if file Y exists or not.
Hokay - this is getting bizarre.
Using any of the file detection techniques works so long as I ask twice. The first time always tells me "does not exist". Second+ tells me "yup, it's there, but you can't open it."
The file in question is on a shared folder on a Windows Server 2008 NTFS drive. It is shared for everyone full control. I have manually added an "Everyone Deny Read" ACL to the file, in order to simulate my customers problem. So I have denied read, but no other access, and only to the file, not to the share, or the folder in which this file lives.
(I used Explorer to make this modification, not my own software or a command line utility).
I can see that the file exists from the local admin account on that server. I cannot see that it even exists from my local workstation, logged in as a standard user under Windows 7, UAC enabled, non-elevated explorer / application.
It would appear that if a file's read-access is explicitly denied, that the file is not visible any longer (except to account for which that deny doesn't apply, or to the local admin which has some back-door way to see the file despite that deny ACL).
I have tried FindFirstFile, GetAttributes, CreateFile, _taccess_s, and PathFileExists. In every case, the first attempt to access the file indicates "file not found", but the second attempt in a row results in no-error (file found).
I cannot begin to explain these results. I think at this point I need to run all of my tests locally, to remove network file sharing from the mix. These results just don't make a whole heckuva lot of sense (to me).
fltmc output for the folder, from local admin account on the server:
Filter Name Num Instances Altitude Frame
------------------------------ ------------- ------------ -----
aksdf 8 145900 0
luafv 1 135000 0
There's a POSIX function named access that does this. It looks like there's a Windows equivalent _access: http://msdn.microsoft.com/en-us/library/1w06ktdy(v=vs.80).aspx
have You trie WinAPI call to CreateFile with second parameter set to 0 ? Here's description: http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858%28v=vs.85%29.aspx and part I point You to is: "If this parameter is zero, the application can query certain metadata such as file, directory, or device attributes without accessing that file or device, even if GENERIC_READ access would have been denied."
If permissions are set up to say "you're not allowed to even look at the name of this file" (e.g., denied you access to the directory it's in), any ability to "see" that file, even to the extent of just confirming or denying its existence is a clear security hole.
As such, there are only a few possibilities that I can see. The most obvious would be to use an Administrator account to search for the file. This will probably annoy the user, as they'll most likely need to enter credentials for that administrative account to use it. For users who don't have access to an Administrator account (most, you'd hope) it simply won't work at all.
Another possibility would be to find and exploit a security hole that lets you do what you want, even though you're really not supposed to be able to. This is (at least) equally problematic -- nearly any hotfix, service pack, etc., might "plug" the security hole you're exploiting, and your code will quit working. Likewise, there's at least a reasonable chance that some sort of anti-malware software might decide (more or less correctly) that your code is being naughty, and tell the user it's doing bad things.
Use the shell function PathFileExists.
An alternative is to mimic what FileExists in Delphi/BCB does, which is to employ FindFirstFile to get the WIN32_FIND_DATA of the file and thus check whether it exists or not.
And by the way, the situation you refer to is completely artificial. It relates to SeChangeNotifyPrivilege which every default installation assigns to even unprivileged users. The user right is called "bypass traverse checking" (in secpol.msc under Security Settings -> Local Policies -> User Rights Assignment) :)
It means that for all practical purposes you should be able to find out if a file exists if you know its path and name.
And yes, Jerry is right, this is a security hole. But a calculated one. Privileges ("user rights") are exactly that: a way to ignore certain permission issues. It's the very purpose of privileges in Windows.

C++ get appdata path of other users

In my program I have been using SHGetFolderPath to get the AppData path. However I need to get the AppData path of the other users on the computer. The only way I can think to do it is to get the path for the current user, and then replace the current user's name with the other users names. I don't know how to get a list of the users. There's probably a much more elegant solution aswell... If you have insight I would greatly appreciate it.
For your situation I would recommend the following:
Continue to store configuration files in AppData, but store it in CSIDL_COMMON_APPDATA (SHGetFolderPath). This AppData is shared with all users. Your setup program (or an administrator user) can set up a folder in this location named after your program that gives "Everyone" full access (this is very easy with Windows Installer). That way, any user can read/write to it. Everything in "Program Files" should never change. It should only contain read-only executables, DLLs, and other such resources. Microsoft has long discouraged writing to this location and many administrators no longer expect to encounter custom user data that requires regular backup & restore in Program Files.
When your software runs, you can check for data in the current user's AppData (i.e. stored by your old version) and merge it with the data in the machine's AppData (described by #1 above). To migrate the data for the user, log in as that user and run your software.
There really isn't a great way that I'm aware of for gathering all that data from other user profiles. Nothing supported by Microsoft, that is (that I'm aware of!).
Regarding storage of data in Program Files: http://msdn.microsoft.com/en-us/library/bb776776(VS.85).aspx "Do not store user data under the Program Files folder." There are many other references that say similar.