質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.99%

internal sealed class にアクセスできない

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 392

mercurian-teto

score 73

実現したいこと

ファイルの所有者を変更して、アクセス権を変更しようと思っています。
現在のユーザーアカウントのファイルの所有権をAdministratorsに変更し、ファイルのアクセス権を変更することができました。

しかし、ファイルの所有者がTrustedInstallerの場合はうまくいきませんでしたので
visualstudioは管理者権限で起動しています。
ネットで検索してみると、
ファイルの所有者がTrusted Installerの場合はPrivelegeのクラスを用意しなければならないらしいので、以下のように実装しました。(ファイルの所有者を変更するところまで記載しています。)

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Security.AccessControl;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using System.Windows;


    public class ModifyPermission
    {

 public  static bool DenyFileAccess(string filepath)
        {

            FileSecurity fs;

            fs = File.GetAccessControl(filepath);

            var ntAccount = new NTAccount("BUILTIN", "Administrators");
            fs.SetOwner(ntAccount);

            Privilege p;
            bool ownerChanged = false;
            try
            {
                p = new Privilege(Privilege.TakeOwnership);
                p.Enable();

                fs.SetOwner(new System.Security.Principal.NTAccount(
                    Environment.UserDomainName, Environment.UserName));

                ownerChanged = true;
            }
            catch (PrivilegeNotHeldException e)
            {
                // privilege not held
                // TODO: show an error message, write logs, etc.
            }
            finally
            {
                p.Revert();
            }


            if (!ownerChanged) return false;

            try
            {
                File.SetAccessControl(filepath, fs);
            }
            catch (InvalidOperationException ex)
            {
                //Debug.WriteLine("You cannot assign ownership to that user." +
                // "Either you don't have TakeOwnership permissions, or it is not your user account."
                //);
                //throw;
                return false;
            }
            catch(System.UnauthorizedAccessException e3)
            {
                MessageBox.Show("error");
            }
//以下省略

}

}


すると、
Privelegeはアクセスできない保護レベルですといわれましたとエラーがはかれました。

Privelegeの定義へ移動すると
internal sealed class privilegeとなっていました。
今回の自作クラスは継承をしていないので、internalに問題があるかと思い、
AssemblyInfo.csに

[assembly: InternalsVisibleTo("System.Security.AccessControl")]


を追加しました。しかしエラーが出たままです。
上の属性の文字列の部分に該当の名前空間を入れたはずなのですが、エラーが出たままでした。
どこをどのように修正すれば、エラーが払えるでしょうか。
回答お願いします。

環境

windows10 pro 1803
visualstudio 2017

追記2

System.Reflectionを使用して実装しました。
例外を投げずに処理ができたのですが、
ファイルのアクセス権および所有者は変更されませんでした。
下記のサイトを参考にしました。
https://stackoverflow.com/questions/5528888/how-to-enable-the-secreateglobalprivilege-in-net-without-resorting-to-p-invoke?lq=1

    public  static  bool DenyFileAccess(string filepath)
        {

            FileSecurity fs;

            fs = File.GetAccessControl(filepath);


            Type privilegeType = Type.GetType("System.Security.AccessControl.Privilege");
            object privilege;

            bool ownerChanged = false;

            try
            {

                privilege = Activator.CreateInstance(privilegeType, "SeTakeOwnershipPrivilege");

                // => privilege.Enable();
                privilegeType.GetMethod("Enable").Invoke(privilege, null);

                var ntAccount = new NTAccount("BUILTIN", "Administrators");
                fs.SetOwner(ntAccount);

                File.SetAccessControl(filepath, fs);


                privilegeType.GetMethod("Revert").Invoke(privilege, null);

                ownerChanged = true;
            }
            catch 
            {

                MessageBox.Show("error");

            }

            if (!ownerChanged) return false;

            try
            {


                File.SetAccessControl(filepath, fs);
            }
            catch (InvalidOperationException ex)
            {

                MessageBox.Show("error");
                return false;
            }
            catch (System.UnauthorizedAccessException e3)
            {
                MessageBox.Show("error");
            }

            try
            {


                Debug.WriteLine("Adding access control entry for "
                    + filepath);

                //管理者権限で起動していても、デスクトップユーザーのアカウント名が返されます。nuget->Cassia
                ITerminalServicesManager manager = new TerminalServicesManager();
                ITerminalServicesSession session = manager.CurrentSession;
                string username = session.UserName;

                // Add the access control entry to the file.
                string principal = string.Format(@"{0}\{1}", System.Environment.MachineName, username);
                AddFileSecurity(filepath, principal,
                    FileSystemRights.ReadAndExecute, AccessControlType.Deny);
                AddFileSecurity(filepath, principal,
                    FileSystemRights.Read, AccessControlType.Deny);

                //Console.WriteLine("Removing access control entry from "
                //    + filepath);

                //// Remove the access control entry from the file.
                //RemoveFileSecurity(filepath, @"BUILTIN\Administrators",
                //    FileSystemRights.ReadData, AccessControlType.Allow);

                Console.WriteLine("Done.");
            }

            catch (System.UnauthorizedAccessException e3)
            {
                MessageBox.Show("error");
            }

            catch (Exception e2)
            {
                Console.WriteLine(e2);
                return false;
            }

追記3

方法2

        static class Program
        {
            [STAThread]
            static void Main()
            {


            string filepath = @"C:\WINDOWS\system32\cmd.exe";
            FileSecurity fs;

            fs = File.GetAccessControl(filepath);

            var takeOwnerShip = new Privirage(PrivirageNames.SeTakeOwnershipPrivilege);
                takeOwnerShip.Enable();
                ProcessStartInfo psi = new ProcessStartInfo("whoami.exe", "/priv")
                {
                    UseShellExecute = false
                };
                using (Process pprocess = Process.Start(psi))
                {
                    pprocess.WaitForExit();
                }

            var ntAccount = new NTAccount("BUILTIN", "Administrators");
            fs.SetOwner(ntAccount);


            File.SetAccessControl(filepath, fs);

            takeOwnerShip.Revert();

             psi = new ProcessStartInfo("whoami.exe", "/priv")
            {
                UseShellExecute = false
            };
            using (Process pprocess = Process.Start(psi))
            {
                pprocess.WaitForExit();
            }
            Console.ReadKey();
            }
        }
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+2

internal なクラスは他のアセンブリからアクセスできません。

stack overflow で触れられている Privilege クラスは MSDN マガジンに掲載された記事に付属していたサンプルのようです。

InternalsVisibleTo は単体テストで使用する属性ですので、指定したからといって他のアセンブリの非公開部分にアクセスできるわけではありません。

System.Reflection を使って非公開部分にアクセスすることはできますが、せっかく Microsoft がソースコードを公開してくれているのですから、勉強がてら実装してみてはいかがでしょうか。

「privilege.cs」
https://referencesource.microsoft.com/#mscorlib/system/security/accesscontrol/privilege.cs

TakeOwnership 特権を有効にしたいだけなら、System.Security.AccessControl.ObjectSecurity クラスをを継承して Persist メソッドをオーバーライドすればなんとかなりそうではあります。

https://referencesource.microsoft.com/#mscorlib/system/security/accesscontrol/objectsecurity.cs,344

あと、MSDN フォーラムでやりとりしながら作っていただいたサンプルソース(VB)があります。
私が「回答の候補に設定」したソースはきちんと動きますが、何点か修正しておいたほうが良い部分があってスレッドの中で指摘しています。
ご参考になれば幸いです。

SeBackupPrivilegeについて

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/07/27 16:15 編集

    サンプルありがとうございます。
    サンプルを用いてcmd.exeの所有者をadministartorに変更しようところ見ましたが(追記2)、TakeOwnerShipは有効になっていても所有者は変更されていませんでした。
    kozさんの指摘通り、タイトルが別の話題になってしまい、又,当初のinternal classにアクセスすると言うことは実現できたので、違うレスにて質問しようと思います。回答ありがとうございました。

    キャンセル

  • 2019/07/27 23:54

    FileSecurity.SetOwner だとうまくいかないですね。

    SetNamedSecurityInfo API を使うとうまくいきます。
    サンプルを更新しておきました。

    キャンセル

  • 2019/07/28 00:42

    >FileSecurity.SetOwner だとうまくいかないですね。
    と思ったら SetAccessControl が自分のコードには抜けていて、追加したらちゃんと変更できました。

    mercurian-teto さんのとこで動かないのは SysWow64 のほうを更新しているのかも。

    キャンセル

0

Privelegeはアクセスできない保護レベルですといわれましたとエラー

まず、エラーメッセージはそのまま、書いた方が回答がつき易いです。

internal sealed class privilegeとなっていました。

privilegeは何処で定義されているクラスでしょうか? Systemにあるクラスでしょうか? もしそうならば、外部(一般アプリ)からの利用が許されていない、と考えられます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/07/27 00:52

    回答ありがとうございます。
    Privilegeは
    System.Security.AccessControl名前空間にある
    internal sealed class Privilegeでした。

    キャンセル

0

これじゃないですか?

ProcessPrivileges

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/07/27 01:08 編集

    internal なクラスをリフレクションで無理やり使うなんてことをやっていいわけがない。使わないでくれという意味でわざわざ internal にしてるのに。

    キャンセル

  • 2019/07/27 16:22

    低評価の人は理由をどうぞ。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.99%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる