ディレクトリへのアクセス権が意図したとおりにならない (「特殊なアクセス許可」になってしまう) - C#

プログラムからディレクトリのアクセス権を追加した場合、「特殊なアクセス許可」になってしまい意図したアクセス権が設定できない現象について紹介します。

現象の確認

コード例

次のコードを準備します。
.NET の場合
private void button5_Click(object sender, EventArgs e)
{
  Directory.CreateDirectory(@"c:\\develop\dev");
  string filePath = @"c:\\develop\dev";

  FileSystemAccessRule rule = new FileSystemAccessRule(
    new NTAccount("everyone"),
    FileSystemRights.FullControl,
    AccessControlType.Allow);

  DirectoryInfo di = new DirectoryInfo(filePath);
  DirectorySecurity security = FileSystemAclExtensions.GetAccessControl(di);
  security.SetAccessRule(rule);
  FileSystemAclExtensions.SetAccessControl(di, security);
}
.NET Framework の場合
private void button6_Click(object sender, EventArgs e)
{
  Directory.CreateDirectory(@"c:\\develop\dev");
  string filePath = @"c:\\develop\dev";

  FileSystemAccessRule rule = new FileSystemAccessRule(
    new NTAccount("everyone"),
    FileSystemRights.FullControl,
    AccessControlType.Allow);

  DirectorySecurity security = Directory.GetAccessControl(filePath);
  security.SetAccessRule(rule);
  Directory.SetAccessControl(filePath, security);
}
上記のコードを実行すると、c:\develop フォルダに devフォルダを作成し、"everyone"のフルコントロール権を割り当てます。
しかし、実行後フォルダのプロパティのセキュリティタブを見ると、アクセス権に"everyone"のユーザーは追加されているものの、 フルコントロールのアクセス権にチェックが入っていません。
アクセス許可の欄を見ると[特殊なアクセス許可]に[許可]のチェックが入っているのみです。


アクセス権の設定内容を詳しく確認します。 フォルダのプロパティの[セキュリティタブ]の[詳細設定]ボタンを押し、セキュリティの詳細設定ダイアログを開き、[アクセス許可の変更]ボタンを押します。セキュリティの詳細設定ダイアログが開きますので、"everyone"を選択し、[編集]ボタンを押します。


下図のアクセス許可エントリダイアログが開きます。設定内容を確認すると、[適用先]の項目が[このフォルダのみ]になっています。


適用先のドロップダウンリストボックスをクリックし、リストの[このフォルダ、サブフォルダおよびファイル]をクリックして選択します。 設定後、[OK]ボタンを押しダイアログを閉じます。



フォルダのプロパティダイアログを開き、[セキュリティ]タブのアクセス権を確認すると、[フルコントロール]にチェックがついていることが確認できます。


対処法

アクセス権の追加時に、適用先を[このフォルダ、サブフォルダおよびファイル]にするには、以下のコードを記述します。

コード

下記のコードを実行すると、"everyone"にフルコントロールのアクセス権をつけられます。
FileSystemAccessRuleクラスのコンストラクタの第3引数に InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit を与え、第4引数に PropagationFlags.None を与えます。
.NET 5以降
private void button4_Click(object sender, EventArgs e)
{
  Directory.CreateDirectory(@"c:\\develop\dev");
  string filePath = @"c:\\develop\dev";

  FileSystemAccessRule rule = new FileSystemAccessRule(
    new NTAccount("everyone"),   //ユーザー
    FileSystemRights.FullControl, //変更権限
    InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit,
    PropagationFlags.None,
    AccessControlType.Allow);//アクセス許可

  DirectoryInfo di = new DirectoryInfo(filePath);
  DirectorySecurity security = FileSystemAclExtensions.GetAccessControl(di);
  security.SetAccessRule(rule);
  FileSystemAclExtensions.SetAccessControl(di, security);
}
.NET Framework
private void button3_Click(object sender, EventArgs e)
{
  Directory.CreateDirectory(@"c:\\develop\dev");
  string filePath = @"c:\\develop\dev";

  FileSystemAccessRule rule = new FileSystemAccessRule(
    new NTAccount("everyone"),   
    FileSystemRights.FullControl, 
    InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit,
    PropagationFlags.None,
    AccessControlType.Allow);
      
  DirectorySecurity security = Directory.GetAccessControl(filePath);
  security.SetAccessRule(rule);
  Directory.SetAccessControl(filePath, security); 
}

InheritanceFlagsの違いによるアクセス権の違い

FileSystemAccessRuleのコンストラクタの引数のInheritanceFlagsを変えてどのようにアクセス権が変わるか見てみます。

InheritanceFlags.ContainerInheritの場合

private void button3_Click(object sender, EventArgs e)
{
  Directory.CreateDirectory(@"c:\\develop\dev");
  string filePath = @"c:\\develop\dev";

  FileSystemAccessRule rule = new FileSystemAccessRule(
    new NTAccount("everyone"),   
    FileSystemRights.FullControl, 
    InheritanceFlags.ContainerInherit,
    PropagationFlags.None,
    AccessControlType.Allow);
      
  DirectorySecurity security = Directory.GetAccessControl(filePath);
  security.SetAccessRule(rule);
  Directory.SetAccessControl(filePath, security); 
}
InheritanceFlags.ContainerInheritを指定した場合は適用先が[このフォルダーとサブフォルダー]になります。


InheritanceFlags.Noneの場合

private void button3_Click(object sender, EventArgs e)
{
  Directory.CreateDirectory(@"c:\\develop\dev");
  string filePath = @"c:\\develop\dev";

  FileSystemAccessRule rule = new FileSystemAccessRule(
    new NTAccount("everyone"),   
    FileSystemRights.FullControl, 
    InheritanceFlags.None,
    PropagationFlags.None,
    AccessControlType.Allow);
      
  DirectorySecurity security = Directory.GetAccessControl(filePath);
  security.SetAccessRule(rule);
  Directory.SetAccessControl(filePath, security); 
}
InheritanceFlags.Noneを指定した場合は適用先が[このフォルダーのみ]になります。


InheritanceFlags.ObjectInheritの場合

private void button3_Click(object sender, EventArgs e)
{
  Directory.CreateDirectory(@"c:\\develop\dev");
  string filePath = @"c:\\develop\dev";

  FileSystemAccessRule rule = new FileSystemAccessRule(
    new NTAccount("everyone"),   
    FileSystemRights.FullControl, 
    InheritanceFlags.ObjectInherit,
    PropagationFlags.None,
    AccessControlType.Allow);
      
  DirectorySecurity security = Directory.GetAccessControl(filePath);
  security.SetAccessRule(rule);
  Directory.SetAccessControl(filePath, security); 
}
InheritanceFlags.ObjectInheritを指定した場合は適用先が[このフォルダーとファイル]になります。


InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInheritの場合

private void button3_Click(object sender, EventArgs e)
{
  Directory.CreateDirectory(@"c:\\develop\dev");
  string filePath = @"c:\\develop\dev";

  FileSystemAccessRule rule = new FileSystemAccessRule(
    new NTAccount("everyone"),
    FileSystemRights.FullControl,
    InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit,
    PropagationFlags.None,
    AccessControlType.Allow);

  DirectorySecurity security = Directory.GetAccessControl(filePath);
  security.SetAccessRule(rule);
  Directory.SetAccessControl(filePath, security);
}
InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit を指定した場合は適用先が[このフォルダー、サブフォルダーおよびファイル]になります。

著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
掲載日: 2010-11-22
改訂日: 2022-11-03
iPentec all rights reserverd.