Granting Access Permission to a File to a Specific User

How to grant permission to users for a directory using command line in Windows?

As of Vista, cacls is deprecated. Here's the first couple of help lines:

C:\>cacls
NOTE: Cacls is now deprecated, please use Icacls.

Displays or modifies access control lists (ACLs) of files

You should use icacls instead. This is how you grant John full control over D:\test folder and all its subfolders:

C:\>icacls "D:\test" /grant John:(OI)(CI)F /T

According do MS documentation:

  • F = Full Control
  • CI = Container Inherit - This flag indicates that subordinate containers will inherit this ACE.
  • OI = Object Inherit - This flag indicates that subordinate files will inherit the ACE.
  • /T = Apply recursively to existing files and sub-folders. (OI and CI only apply to new files and sub-folders). Credit: comment by @AlexSpence.

For complete documentation, you may run "icacls" with no arguments or see the Microsoft documentation here and here

Granting Access Permission to a file to a specific user

Unix uses discretionary access control (DAC) for permissions and access control. For better security SELinux provide mandatory access control (MAC). This is consider difficult for administrators to set up and maintain.

Use commands:

chown user_name file
chown user_name folder
chown -R user_name folder #recursive

How to grant one particular user read access to a unix file

Generally when you want more fine-grained permissions in Linux, you should use Access Control Lists. The Arch Wiki has a good guide on how to set it up.

Once set up, you can define more complex rules for modifying the access control policies for your mounted filesystem.

You can set these rules with commands that look like: setfacl -m "u:johny:r-x" abc.
This says "Give (user) Johny read and execute permissions to the file/directory specified by the path abc".

You would then also be able to see the permissions for a filesystem object using getfacl

root@testvm:/var/tmp# getfacl appdir/
# file: appdir/
# owner: root
# group: appgroup
user::rwx
group::rwx
group:testusers:r--
mask::rwx
other::r-x

In this example you can see the default for any user/group which is not (in) the testusers group, can read, write, or execute the directory. But testusers can only read.

File permission to a specific application

I see several possibilities:


If you don't want the user to "see" your data, then you have to encrypt the file content. There are a lot of Delphi encryption/decryption libraries. I suggest you start with Delphi Encryption Compendium which is available for free on GitHub.

You can store the data in an in-memory structure such as an XML or JSON (Delphi has built-in routine to handle both XML and JSON). Before writing to disc, you encrypt it and after having reloaded the encrypted file, you decrypt it before accessing it the standard way.

2° Use a file accessible from another account and make your program impersonate that account when access to the file is required.

I wrote some code for use to ease and demo that way. I created a class TImpersonateUser having two methods Logon and Logoff which will make the program connect to a given user account and disconnect from it.

To test, first logon using another account and create a file somewhere, for example in the documents. Then logon back to your normal user code and launch the demo program (code below). Fill username, domain and password (For domain, "." will authenticate only on local computer). Fill the filename with complete path of the file you created previously. The click "file access". It should answer "file not found". Then click "Impersonate" and again "File Access". Now you should have access to the file in the other account. Click on "Revert to self" and try again "File Access" it should fail again.

In summary, for your question, the data the user cannot see must be created under another account and you application impersonate that other account when it needs to access the data. Don't forget to somehow hide username and password in your program.

Note: Once you get a handle (file or stream opened), you can RevertToSelf and still use the handle (or stream). It keeps the security context (the account used) until closed. This means you can call Logon before opening the file, call logoff right after opening (or failure of opening) and continue to access the file.

EDIT: I wrote a blog post with more code.

unit ImpersonateUser;

interface

uses
Winapi.Windows, System.Classes;

const
LOGON32_LOGON_NEW_CREDENTIALS = 9; // Missing in Delphi

type
TImpersonateUser = class(TComponent)
protected
FUserToken : THandle;
FErrorCode : DWORD;
public
destructor Destroy; override;
function Logon(const UserName : String;
const Domain : String;
const Password : String) : Boolean;
procedure Logoff();
property ErrorCode : DWORD read FErrorCode;
end;

implementation

{ TImpersonateUser }

destructor TImpersonateUser.Destroy;
begin
if FUserToken <> 0 then begin
CloseHandle(FUserToken);
FUserToken := 0;
end;

inherited Destroy;
end;

procedure TImpersonateUser.Logoff;
begin
if FUserToken <> 0 then begin
RevertToSelf(); // Revert to our user
CloseHandle(FUserToken);
FUserToken := 0;
end;
end;

function TImpersonateUser.Logon(
const UserName : String;
const Domain : String;
const Password : String): Boolean;
var
LoggedOn : Boolean;
begin
Result := FALSE;
if FUserToken <> 0 then
Logoff();

if UserName = '' then begin // Must at least provide a user name
FErrorCode := ERROR_BAD_ARGUMENTS;
Exit;
end;

if Domain <> '' then
LoggedOn := LogonUser(PChar(UserName),
PChar(Domain),
PChar(Password),
LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT,
FUserToken)
else
LoggedOn := LogonUser(PChar(UserName),
PChar(Domain),
PChar(Password),
LOGON32_LOGON_NEW_CREDENTIALS,
LOGON32_PROVIDER_WINNT50,
FUserToken);
if not LoggedOn then begin
FErrorCode := GetLastError();
Exit;
end;

if not ImpersonateLoggedOnUser(FUserToken) then begin
FErrorCode := GetLastError();
Exit;
end;

FErrorCode := S_OK;
Result := TRUE;
end;

end.

Simple demo:

unit ImpersonateUserDemoMain;

interface

uses
Winapi.Windows, Winapi.Messages,
System.SysUtils, System.Variants, System.Classes,
Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
ImpersonateUser;

type
TImpersonateUserMainForm = class(TForm)
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
UserNameEdit: TEdit;
DomainEdit: TEdit;
PasswordEdit: TEdit;
ImpersonateButton: TButton;
Label4: TLabel;
FileNameEdit: TEdit;
RevertToSelfButton: TButton;
FileAccessButton: TButton;
procedure FileAccessButtonClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure ImpersonateButtonClick(Sender: TObject);
procedure RevertToSelfButtonClick(Sender: TObject);
private
FImpersonate : TImpersonateUser;
end;

var
ImpersonateUserMainForm: TImpersonateUserMainForm;

implementation

{$R *.dfm}

procedure TImpersonateUserMainForm.FileAccessButtonClick(Sender: TObject);
var
Stream : TFileStream;
begin
try
if not FileExists(FileNameEdit.Text) then
ShowMessage('File not found')
else begin
Stream := TFileStream.Create(FileNameEdit.Text, fmOpenRead);
try
ShowMessage('File opened');
finally
Stream.Free;
end;
end;
except
on E:Exception do
ShowMessage(E.Classname + ': ' + E.Message);
end;
end;

procedure TImpersonateUserMainForm.FormCreate(Sender: TObject);
begin
UserNameEdit.Text := 'YourUsername';
DomainEdit.Text := '.';
PasswordEdit.Text := 'YourPassword';
FilenameEdit.Text := 'C:\Users\AnotherUser\Documents\HelloWorld.txt';
FImpersonate := TImpersonateUser.Create(Self);
end;

procedure TImpersonateUserMainForm.ImpersonateButtonClick(Sender: TObject);
begin
if not FImpersonate.Logon(UserNameEdit.Text,
DomainEdit.Text,
PasswordEdit.Text) then begin
ShowMessage(Format('Failed with error 0x%X', [FImpersonate.ErrorCode]));
end
else
ShowMessage('Logon OK');
end;

procedure TImpersonateUserMainForm.RevertToSelfButtonClick(Sender: TObject);
begin
FImpersonate.Logoff;
ShowMessage('Reverted to self');
end;

end.

The DFM file:

object ImpersonateUserMainForm: TImpersonateUserMainForm
Left = 0
Top = 0
Caption = 'ImpersonateUserMainForm'
ClientHeight = 142
ClientWidth = 331
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object Label1: TLabel
Left = 16
Top = 20
Width = 49
Height = 13
Caption = 'UserName'
end
object Label2: TLabel
Left = 16
Top = 48
Width = 35
Height = 13
Caption = 'Domain'
end
object Label3: TLabel
Left = 12
Top = 76
Width = 46
Height = 13
Caption = 'Password'
end
object Label4: TLabel
Left = 16
Top = 104
Width = 16
Height = 13
Caption = 'File'
end
object UserNameEdit: TEdit
Left = 80
Top = 16
Width = 121
Height = 21
TabOrder = 0
Text = 'UserNameEdit'
end
object DomainEdit: TEdit
Left = 80
Top = 44
Width = 121
Height = 21
TabOrder = 1
Text = 'DomainEdit'
end
object PasswordEdit: TEdit
Left = 80
Top = 72
Width = 121
Height = 21
TabOrder = 2
Text = 'PasswordEdit'
end
object ImpersonateButton: TButton
Left = 232
Top = 14
Width = 75
Height = 25
Caption = 'Impersonate'
TabOrder = 3
OnClick = ImpersonateButtonClick
end
object FileNameEdit: TEdit
Left = 80
Top = 99
Width = 121
Height = 21
TabOrder = 4
Text = 'FileNameEdit'
end
object RevertToSelfButton: TButton
Left = 232
Top = 45
Width = 75
Height = 25
Caption = 'Revert to self'
TabOrder = 5
OnClick = RevertToSelfButtonClick
end
object FileAccessButton: TButton
Left = 232
Top = 76
Width = 75
Height = 25
Caption = 'File access'
TabOrder = 6
OnClick = FileAccessButtonClick
end
end

Deny folder access to specific users

This is possible and can be done with the cacls command in cmd:

for %A IN ("user1" "user2" "user3" "user4") do @cacls C:\some\folder /e /c /d %~A

where to allow access to these users to a certain folder again use:

for %A IN ("user1" "user2" "user3" "user4") do @cacls C:\some\folder /e /c /d %~A:f

Be sure to replace user1, user2, e.t.c. with the actual, correct usernames and add more if you want. You will need also to change C:\some\folder to the actual folder path.

For a batch-file solution, double the percent-signs like this:

@for %%A IN ("user1" "user2" "user3" "user4") do @cacls C:\some\folder /e /c /d %%~A:f

How to grant full permission to a file created by my application for ALL users?

Note to people using this.

When using literal strings for the FileSystemAccessRule, it should be WellKnownSidType.WorldSid instead of "everyone".

The reason is because there are multiple Window languages and Everyone only applies to EN ones, so for Spanish, it might be "Todos" (or something else).

using System.Security.AccessControl;
using System.Security.Principal;
using System.IO;

private void GrantAccess(string fullPath)
{
DirectoryInfo dInfo = new DirectoryInfo(fullPath);
DirectorySecurity dSecurity = dInfo.GetAccessControl();
dSecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.FullControl, InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.NoPropagateInherit, AccessControlType.Allow));
dInfo.SetAccessControl(dSecurity);
}


Related Topics



Leave a reply



Submit