Get file / directory Owner as displayed in Windows Explorer - c#

When I look at a file or folder in Windows explorer, it generally shows the Owner as a specific user; in my environment, showing as <domain>\<username>. It shows this information both when I add the Owner column to a folder view, and by right-clicking on a file and looking at the Details tab. I think this is what most people expect to see when they think about the Owner of a file or directory.
I want to grab this owning-user information for a large number of files and folders. However, when I do what every tutorial, blog post and forum answer suggests to get the Owner programmatically in powershell, it shows the Owner as BUILTIN\Administrators:
PS:>Get-Item '.\file.txt' | Get-Acl | Format-List
Path : Microsoft.PowerShell.Core\FileSystem::Z:\path\to\file.txt
Owner : BUILTIN\Administrators
Group : <domain>\Domain Users
Access : NT AUTHORITY\SYSTEM Allow FullControl
BUILTIN\Administrators Allow FullControl
<domain>\<myusername> Allow FullControl
Audit :
Sddl : <lots of fancy letters>
There are various posts around which explain why this happens (TL;DR: items created by users who are members of the Administrators group), so don't need to retread that here. And I can see that the info I'm really looking for is there as one of the System.Security.AccessControl.FileSystemAccessRule objects under the Access property. I am considering workarounds including filtering BUILTIN / NT AUTHORITY records out of the Access list, or perhaps filtering on a class as in this helpful question.
However, those solutions seem both inefficient and inelegant. In the UI, Windows seems to "know what I mean" when I want to see the Owner of an item. So it seems really strange that there's no more straightforward way to grab that information in code.
Where does Explorer pull its Owner information from? Is it really doing some kind of inefficient, heuristic list-filtering under the hood as well?
Or must there not be direct way to approach this?
Solutions in powershell, c# or any .net language gratefully received!
Tried and failed:
The solution in this question of calling .GetAccessControl().GetOwner(typeof(System.Security.Principal.SecurityIdentifier)) first, and then .Translate(typeof(System.Security.Principal.NTAccount)) on the result, has not worked for me; still outputs only BUILTIN\Administrators.
cmd.exe's dir <file> /Q gives the same, as suggested in various places including this answer.
Have also found that $file.GetAccessControl() yields the same, unhelpful info as the Get-Acl commandlet.

Related

Cannot create StorageItem in Outlook Add-In

I'm trying to run this code:
this.storage =
Application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts)
.GetStorage("ws_up_storage", Outlook.OlStorageIdentifierType.olIdentifyByMessageClass);
It runs perfectly well on some machines, but on others it throws this exception:
I also tried other folder names, like olFolderInbox, olFolderCalendar. I've looked at Microsoft docs for this, and it says this error is to be expected if the folder is one of the following:
The folder is a Microsoft Exchange public folder, an Internet Message Access Protocol (IMAP), MSN Hotmail, or a Microsoft SharePoint Foundation folder.
The user permission for the folder is read-only.
The store provider does not support hidden items.
The sad fact is, I do not know how to check which one of these is true and if it's at all possible.
How would I go about determining the cause of the problem and addressing it?
The easiest way to handle all these cases is to try to get a storage. You will need much efforts to implement all cases. The PR_MDB_PROVIDER property allows to identify the store provider, but not all cases such as user permissions for the folder and etc. You can use the try/catch block where you may check the error code - 0x80040102 (MAPI_E_NO_SUPPORT).
However, you may use any low-level property viewers (for example, a free open source tool - MFCMAPI) for exploring Extended MAPI property values. Thus, you may find all the required info about not supported scenarious.
The error 0x80040102 is MAPI_E_NO_SUPPORT, which means the store does not support hidden (associated) items.
Read the PR_MDB_PROVIDER property (DASL name http://schemas.microsoft.com/mapi/proptag/0x34140102) using PropertyAccessor.GetProperty. The returned 16 byte array will be specific for each store kind. E.g. for an Exchange store, it will be pbExchangeProviderPrimaryUserGuid (5494A1C0297F101BA58708002B2A2517). Take a look at any object in the store in question using OutlookSpy (I am its author - click IMessage, IMAPIFolder, or IMsgStore) to see the PR_MDB_PROVIDER property.

How to give Create, Read and Modify permissions to all users for a file created by my application in C:\ProgramData?

My application basically creates an XML file in C:\ProgramData\MyAppFolder and dumps config settings in it.
I need to allow even standard users to have permission to add or delete settings to these config files. Right now I see that standard users only have read/execute permission but not "Full Control".
I've seen other questions being answered with ways to modify permissions to that particular folder but I don't want to change the default permission level, since it might be reset by a system admin.
If C:\ProgramData can't give that access to all users, is there any folder that best suits the needs of application?
EDIT:
My initial question might be misleading. I don't want to give rights to users, but rather allow the application to modify the XML file when it is run by all users.
DECISION:
I think changing the permissions while creating the folder in ProgramData is the only option.
And if that's not possible, CommonDocuments is the way to go.
Thanks Eve.
I would use a folder in the Environment.SpecialFolder enum.
Example:
var path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
Assuming you have an installer for your application, your installer can create a subfolder in the common appdata directory (aka C:\ProgramData) which your application will have read/write access to. Depending on your choice of installation technology you can set the permissions on that folder as well, although that may be overkill. I know with WiX basically all you have to do is a per-machine installation and make sure that sub folder gets created.
Users should not be allowed to write arbitrary data to this directory. This is equivalent to regular users being able to modify the C:\Users\AllUsers directory. If users need to be modifying this directory you have serious design flaws and should reconsider this approach. What should happen is the users are given GUI interface to interact with that manipulates these values behind the scenes without giving them direct access, similar to how getters/setters work in most programming languages. Needless to say it is a very large security hole when regular users can corrupt a system for other users.
UPDATE
I don't want to give users direct access to the file. My question
might have been misleading. I want to allow the program to have full
control on the file even when it being run by all users. I'm actually
doing this: "users are given GUI interface to interact with that
manipulates these values behind the scenes without giving them direct
access"
This article which has far too much information to post here, will provide details on remaining secure as to not leak permissions. The first thing you want to do is make sure that your application user is in its own group and cannot login/have any special permissions. What you can than do is have this group added to the directory with write permissions, which would allow this application to perform these tasks. If that is not possible you will need to work within UAC to not break the security of the system as is detailed in the article above.
Second Update
Thanks for the link. Any suggestions on some other folder which can do
the job, rather than messing with the permissions?
Sure you can write it into the directory where the application is written to, i.e. C:\Program Files\Some Awesome Program, this keeps everything in one place, and you only have to worry about your user/group and anything that the person who installed it has allowed for. It also prevents other people from messing with it unless of course they are administrators.

How to track directory opening

I'm not sure if the question's title makes sense, and I'm sorry if it doesn't; I didn't really know what to title it.. Anyway, is there a way to make your program track the viewing of a folder?
What I'm trying to achieve: Windows 7 Home Premium doesn't allow encryption. So, I made a folder inside my user directory, and set it to hidden. Although, you can easily find it by changing windows settings.. So, is there a way to make a program pull up a window if the user tries to access that certain folder?
I don't think you can detect the "opening" of a folder.
Instead, you may want to set a FileSystemWatcher to detect any file access to the files in that particular folder.
Hope this helps.
First of all, I have to wonder why you're not just setting an ACL on the directory to prevent access.
However, it sounds like you want to find when somebody is accessing a particular directory. To do this, you enable filesystem auditing, then set the audit ACL to generate audit entries for "List folder". This will cause entries to be generated in the Security Event Log whenever the directory is viewed.
Now you just have to write a program that watches the Security event log looking for entries indicating that somebody has listed the directory in question and take action as necessary.
Well, there is an article on code project describing how you can hook into windows system calls: http://www.codeproject.com/KB/system/hooksys.aspx - it's not simple though (and also not C#) and has the potential to screw with your system but if it might be a fun project to work on.
A simpler option would be: Use a 3rd party desktop encryption tool - not much programming involved here but it might do the job better than anything else.

FileSystemWatcher surpassing file system permissions

While experimenting with FileSystemWatcher, I've found out that it somehow surpasses my user account's permissions to files and folders, and will raise change events with information about what has changed in files and folders that you don't even have access to.
I have two questions about that:
1) Why does this happen ?
2) Is this a problem in the AD configuration ? how do I fix it ?
3) Is there any way to gather these files, or even create a FileSystemInfo of them to get more info about the files (not only the changes made on them) ?
As far as I've tried, only the FileSystemWatcher immune to the restrictions, I can't run any other thing over it, here's a list of what I've tried:
File.Exists
Directory.Exists
FileInfo instance on found files
DirectoryInfo instance on found files
File.Copy
File.Delete
Update: Tried helge's solution, with somethin similar to what he's sugested, not through windows' api, but through the command prompt:
robocopy /B \myserver\folder c:\somefolder
Best command name ever.
You can check through robocopy that /B stands for "backup mode", which is what helge's suggested that would be the cause to this security surpassing.
I'll try anything, I want to find out what exactly causes FileSystemWatcher to be able to watch folders I do not have permission to open. Knowing why, I want to learn both how to block FileSystemWatcher, and how to gather found files.
I'd make a survey if I was with my personal account. Please, can someone help me ? I'll write a blog post about the solution, among other things that might help anyone with the same doubt in the future.
According to this answer on SO the FileSystemWatcher is based on the API function ReadDirectoryChangesW. If that is true it explains the behavior witnessed by you - and why that is not a security hole.
As documented on MSDN ReadDirectoryChangesW needs the privilege SeBackupPrivilege (which is requested by the parameter FILE_FLAG_BACKUP_SEMANTICS to CreateFile). If a file is opened in that mode, the returned handle grants full access to the file, circumventing access checks. This feature is designed for backup programs that need to be able to read everything on disk regardless of permissions.
This is not a security hole because the privilege SeBackupPrivilege which is required for this to work is by default granted to administrators only. Administrators, and in fact anyone with physical access to a machine, are always capable of taking control of and reading every file - unless it is encrypted.
As to which functions can be used to access files in backup mode: There is at least BackupRead for reading. Enumeration is easily possible with FindFirstFile/FindNextFile. Of course this requires the real Windows API, not the crippled .NET file system functions.

WPF/C#: Where should I be saving user preferences files?

What is the recommended location to save user preference files? Is there a recommended method for dealing with user preferences?
Currently I use the path returned from typeof(MyLibrary).Assembly.Location as a default location to store files generated or required by the application.
EDIT:
I found two related/interesting questions:
Best place to save user information for Windows XP and Vista applications
What's the way to implement Save / Load functionality?
EDIT #2:
This is just a note for people like me who had never used settings before.
Settings are pretty useful, but I had to do a whole bunch of digging to figure out what was going on (coming from the Python world, not something I am used too). Things got complicated as I wanted to save dictionaries and apparently they can't be serialized. Settings also seem to get stored in 3 different files depending on what you do. There is an app.config, user.config and a settings.setting file. So here are two more links that I found useful:
http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/ddeaca86-a093-4997-82c9-01bc0c630138
http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/efe370dc-f933-4e55-adf7-3cd8063949b0/
You can use the Application Settings easily enough.
If you haven't done so before just right click on the project and choose Properties. Select the Settings tab. Make sure you chose "User" for the scope (otherwise the setting is read-only).
The code to access this is simple:
forms.Width = Application1.Properties.Settings.Default.Width;
If you need to save it:
Application1.Properties.Settings.Default.Width = forms.Width;
Application1.Properties.Settings.Default.Save();
In the sample above, Width is the custom setting name you define in the Settings tab and Application1 is the Namespace of your application.
Edit: Responding to further questions
You mentioned you wanted to store Dictionary objects in the Settings. As you discovered, you can't do this directly because Dictionary objects are not serializable. However, you can create your own serializable dictionary pretty easily. Paul Welzer had an excellent example on his blog.
You have a couple of links which sort of muddy the situation a little. Your original question is where to save "User Preference Files". I'm pretty certain Microsoft's intention with the Settings functionality is exactly that... storing user skin preferences, layout choices, etc. It not meant as a generic repository for an application's data although it could be easily abused that way.
The data is stored in separate places for a good reason. Some of the settings are Application settings and are read-only. These are settings which the app needs to function but is not specific to a user (for example, URIs to app resources or maybe a tax rate). These are stored in the app.config.
User settings are stored in an obfuscated directory deep within the User Document/Settings folder. The defaults are stored in app.config (I think, can't recall for certain off the top of my head) but any user changes are stored in their personal folder. This is meant for data that changes from user to user. (By "user" I mean Windows user, not your app's user.)
Hope this clarified this somewhat for you. The system is actually pretty simple. It might seem a little foreign at first but after a few days of using it you'll never have to think of it again... it just works.
When running as non-admin or on Vista you can't write to the "Program files" folder (or any sub folder of it).
The correct location to store user preference is (replace MyCompanyName and MyApplicationName with the correct names, obviously)
On disk:
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\MyCompanyName\\MyApplicationName"
Or in the registry under the key:
HKEY_CURRENT_USER\Software\MyCompanyName\MyApplicationName
Those location are per-user and they work with non-admin user, several users using the same computer, fast user switching, terminal services and all the other ways people can interact with your software.
If you need a common location for all users then:
It will only work when the user run as an administrator
It will not work reliably on Vista
You have to take care of everything yourself (like two users running the application on the same computer at the same time via fast user switching).
and the locations are:
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationCommonData) + "\\MyCompanyName\\MyApplicationName"
Or in the registry under the key:
HKEY_LOCAL_MACHINE\Software\MyCompanyName\MyApplicationName
You can use isolated storage. You can isolate by user, assembly and/or domain.
Introduction to Isolated Storage
http://msdn.microsoft.com/en-us/library/3ak841sy(VS.80).aspx
Types of Isolation
http://msdn.microsoft.com/en-us/library/eh5d60e1(VS.80).aspx
the following seems to be the best option:
Application.UserAppDataPath

Categories