How to grant Access on Files on a share drive?

From: Jörgen Ahrens (jahrens_at_community.nospam)
Date: 11/08/05

  • Next message: Vladimir Nechipurenko: "Re: To detect weak or blank password?"
    Date: Tue, 8 Nov 2005 09:55:54 +0100
    
    

    Hi All

    We are trying to grant access on files on a share drive.

    We have a client application running on a client machine where we
    impersonate a technical user that has access to the server.
    The actual user doesn't have access to the files located on the server. At
    runtime we would like to grant access to the client user (on a specific file
    on the server).

    We managed to grant access by :
    - mapping the shared folder from the server to the client machine
    - we did not impersonate the technical user, but we ran the client
    application under the profile of the technical user (what is not what we
    need).

    It seems as if the impersonated would not recongnize the mapped drives.(we
    tried to implement the mapping on the client machine under the normal user
    account and under the technical user account as well as on the server
    machine)

    Is it true, that we need to have a mapped shared drive to actually succeed?
    or is it possible to access the shared folder directly without mapping the
    networkdrive?

    If we need to map the network drive, how can we assure that the impersonated
    user can see the mapped network drives?

    We attached our testprogram (Impersonation seemed to worked well and is not
    included in the testprogram).

    thanks for your help
    j.ahrens

    ---------------------------------------------------------------------------------------------
    Test scenario:

    Server: S01
    Client: W07
    Shared Folder on the Server: \\S01\_KnowledgeBase (D:\Daten\_KnowledgeBase)
    Mapped network drive: \\S01\_KnowledgeBase is mapped onto K:\ on the client
    (would be nice if we could drop that and just use \\S01\_KnowledgeBase
    directly)

    ---------------------------------------------------------------------------------------------
    CODE
    ---------------------------------------------------------------------------------------------

    using System;
    using System.Management;
    using System.Collections;

    namespace Ascami.LogExcellence.WinApp
    {
     // Access mask (see AccessMask property)
     [Flags]
     enum Mask : uint
     {
      FileReadData = 0x00000001,
      FileWriteData = 0x00000002,
      FileAppendData = 0x00000004,
      FileReadEA = 0x00000008,
      FileWriteEA = 0x00000010,
      FileExecute = 0x00000020,
      FileDeleteChild = 0x00000040,
      FileReadAttributes = 0x00000080,
      FileWriteAttributes= 0x00000100,

      Delete = 0x00010000,
      ReadControl = 0x00020000,
      WriteDac = 0x00040000,
      WriteOwner = 0x00080000,
      Synchronize = 0x00100000,

      AccessSystemSecurity = 0x01000000,
      MaximumAllowed = 0x02000000,

      GenericAll = 0x10000000,
      GenericExecute= 0x20000000,
      GenericWrite = 0x40000000,
      GenericRead = 0x80000000
     }

     [Flags]
     enum AceFlags : uint
     {
      NonInheritAce = 0,
      ObjectInheritAce = 1,
      ContainerInheritAce = 2,
      NoPropagateInheritAce = 4,
      InheritOnlyAce = 8,
      InheritedAce = 16
     }

     [Flags]
     enum AceType : uint
     {
      AccessAllowed = 0,
      AccessDenied = 1,
      Audit = 2
     }

     /// <summary>
     /// The class offers two static functions used to allow or deny access to
    files.
     /// </summary>
     class ManageFilePermissions
     {
      /// <summary>
      /// This main is used to test this class.
      /// </summary>
      public static void Main()
      {
       //Start Impersonation
    // Impersonation imp = new Impersonation();
    // imp.LoadProfile("Ascami", "logexcellence", "pwd");
    // imp.StartImpersonation();
    //
    //
    System.Windows.Forms.MessageBox.Show(System.IO.Directory.Exists("K:\\1\\2").ToString());

       bool success;
       //Allow access for samrein to file K:\1\2\3.xls on server S01
       success = ManageFilePermissions.AllowFileAccess("Ascami", "samrein",
    "K:\\1\\2\\3.xls", "S01");
       //Deny samrein
       success = ManageFilePermissions.DenyFileAccess("Ascami", "samrein",
    "K:\\1\\2\\3.xls", "S01");
       //Allow wiederkehr
       success = ManageFilePermissions.AllowFileAccess("Ascami", "swiederkehr",
    "K:\\1\\2\\3.xls", "S01");
       //Allow samrein
       success = ManageFilePermissions.AllowFileAccess("Ascami", "samrein",
    "K:\\1\\2\\3.xls", "S01");
       //Deny mahrenes
       success = ManageFilePermissions.DenyFileAccess("Ascami", "mahrens",
    "K:\\1\\2\\3.xls", "S01");
       //Deny wiederkehr
       success = ManageFilePermissions.DenyFileAccess("Ascami", "swiederkehr",
    "K:\\1\\2\\3.xls", "S01");
       //Deny samrein
       success = ManageFilePermissions.DenyFileAccess("Ascami", "samrein",
    "K:\\1\\2\\3.xls", "S01");

      }

      /// <summary>
      /// Allows the specified user to read and write the specified file.
      /// </summary>
      /// <param name="domain">The domain of the user</param>
      /// <param name="username">The username of the user</param>
      /// <param name="file">The file</param>
      /// <param name="server">The server of the file. If it is placed on the
    local machine use '.'</param>
      /// <returns>true if the user is now allowed to read and write</returns>
      public static bool AllowFileAccess(string domain, string username, string
    file, string server)
      {
       ManagementObject lfs;
       ManagementBaseObject descriptor; //The security descriptor
       ManagementBaseObject[] dacl = FetchDACL(server, file, out lfs, out
    descriptor);
       if (dacl == null)
       {
        System.Windows.Forms.MessageBox.Show("Failed to fetch DACL.", "Error");
        return false;
       }
       int aceIndex = GetACE(dacl, domain, username);
       if (aceIndex == -1)
       {
        //ace does not exist -> create it, add it
        ManagementBaseObject ace = CreateACE(domain, username, Mask.GenericRead
    | Mask.GenericWrite);
        if (ace == null)
        {
         System.Windows.Forms.MessageBox.Show("Could not create ACE for
    domain\\username.", "Error");
         return false;
        }
        dacl = AddACE(dacl, ace);
        if (!WriteDACL(dacl, lfs, descriptor))
        {
         System.Windows.Forms.MessageBox.Show("Could not write DACL.", "Error");
         return false;
        }
        return true;
       }
       else
       {
        //ace exists, modify it
        ManagementBaseObject ace = dacl[aceIndex];
        ModifyACE(ace, Mask.GenericRead | Mask.GenericWrite);
        if (!WriteDACL(dacl, lfs, descriptor))
        {
         System.Windows.Forms.MessageBox.Show("Could not write DACL.", "Error");
         return false;
        }
        return true;
       }
      }

      /// <summary>
      /// Denies the specified user to read and write the specified file.
      /// </summary>
      /// <param name="domain">The domain of the user</param>
      /// <param name="username">The username of the user</param>
      /// <param name="file">The file</param>
      /// <param name="server">The server of the file. If it is placed on the
    local machine use '.'</param>
      /// <returns>true if the user is now denied to read and write</returns>
      public static bool DenyFileAccess(string domain, string username, string
    file, string server)
      {
       ManagementObject lfs;
       ManagementBaseObject descriptor;
       ManagementBaseObject[] dacl = FetchDACL(server, file, out lfs, out
    descriptor);
       if (dacl == null)
       {
        System.Windows.Forms.MessageBox.Show("Failed to fetch DACL.", "Error");
        return false;
       }
       int aceIndex = GetACE(dacl, domain, username);
       if (aceIndex == -1)
       {
        //No entry exists, return
        return true;
       }
       else
       {
        dacl = RemoveACE(dacl, aceIndex);
        if (!WriteDACL(dacl, lfs, descriptor))
        {
         System.Windows.Forms.MessageBox.Show("Could not write DACL.", "Error");
         return false;
        }
        return true;
       }
      }

      /// <summary>
      /// Returns the index of the ACE from the DACL-list if it exists
      /// </summary>
      /// <param name="dacl">the discretionary access control list</param>
      /// <param name="domain">The domain of the user</param>
      /// <param name="username">The username of the user</param>
      /// <returns>the index of the ace or -1 if none exists</returns>
      private static int GetACE(ManagementBaseObject[] dacl, string domain,
    string username)
      {
       ManagementBaseObject ace;
       for (int i=0;i<dacl.Length;i++)
       {
        ace = dacl[i];

        //Find out if it is an ace of the specified user
        ManagementBaseObject trustee = (ManagementBaseObject)(ace["Trustee"]);
        string trusteeDomain = trustee.Properties["Domain"].Value.ToString();
        string trusteeUsername = trustee.Properties["Name"].Value.ToString();

        if (string.Compare(domain, trusteeDomain, true)!= 0) continue;
        if (string.Compare(username, trusteeUsername, true) != 0) continue;

        //return the ace
        return i;
       }

       return -1;
      }

      /// <summary>
      /// Sets the ACE access mask.
      /// </summary>
      /// <param name="ace">The access control entry you would liko to
    modify</param>
      /// <param name="accessMask">The access mask</param>
      private static void ModifyACE(ManagementBaseObject ace, Enum accessMask)
      {
       ace.Properties["AccessMask"].Value = accessMask;
      }

      /// <summary>
      /// Creates a new Access Control Entry
      /// </summary>
      /// <param name="domain">The domain of the user</param>
      /// <param name="username">The username of the user</param>
      /// <param name="accessMask">The access mask</param>
      /// <returns>The new Access Control Entry or null if the command
    failed</returns>
      private static ManagementBaseObject CreateACE(string domain, string
    username, Enum accessMask)
      {
       ManagementBaseObject trustee = null;
       ManagementBaseObject ace = null;

       // Initialize new Trustee
       try
       {
        trustee = new ManagementClass("Win32_Trustee");
        trustee.Properties["Domain"].Value = domain;
        trustee.Properties["Name"].Value = username;
       }
       catch (Exception)
       {
        //Happens if trustee does not exist
        return null;
       }
       try
       {
        ace = new ManagementClass("Win32_ACE");
        ace.Properties["AccessMask"].Value = accessMask;
        ace.Properties["AceFlags"].Value = AceFlags.NoPropagateInheritAce;
        ace.Properties["AceType"].Value = AceType.AccessAllowed;
        ace.Properties["Trustee"].Value = trustee;
       }
       catch (Exception)
       {
        //No idea when this happens...
        return null;
       }

       return ace;
      }

      /// <summary>
      /// Writes the passed Discretionary Access Control List.
      /// </summary>
      /// <param name="dacl">The Discretionary Access Control List</param>
      /// <param name="lfs">the object on which the dacl is written</param>
      /// <param name="descriptor">the security descriptor</param>
      /// <returns>true if successful, false if it failed</returns>
      private static bool WriteDACL(ManagementBaseObject[] dacl,
    ManagementObject lfs, ManagementBaseObject descriptor)
      {
       ManagementBaseObject inParams =
    lfs.GetMethodParameters("SetSecurityDescriptor");
       descriptor.Properties["Dacl"].Value = dacl;
       inParams["Descriptor"] = descriptor;
       ManagementBaseObject ret = lfs.InvokeMethod("SetSecurityDescriptor",
    inParams, null);
       if ((Convert.ToUInt32(ret.Properties["ReturnValue"].Value) == 0))
        return true;
       else
        return false;
      }

      /// <summary>
      /// Adds an ACE to a DACL
      /// </summary>
      /// <param name="dacl">The discretionary access control list</param>
      /// <param name="ace">The access control entry</param>
      /// <returns>the new discretionary access control list</returns>
      private static ManagementBaseObject[] AddACE(ManagementBaseObject[] dacl,
    ManagementBaseObject ace)
      {
       ManagementBaseObject[] newDacl = new ManagementBaseObject[dacl.Length+1];

       dacl.CopyTo(newDacl, 0);
       newDacl[newDacl.Length-1] = ace;

       return newDacl;
      }

      /// <summary>
      /// Removes an ACE of a DACL
      /// </summary>
      /// <param name="dacl">The discretionary access control list</param>
      /// <param name="index">The index of the ACE you would like to
    remove</param>
      /// <returns>the new discretionary access control list</returns>
      private static ManagementBaseObject[] RemoveACE(ManagementBaseObject[]
    dacl, int index)
      {
       ManagementBaseObject[] newDacl = new ManagementBaseObject[dacl.Length-1];
       int count = 0;
       for (int i=0;i<dacl.Length;i++)
       {
        if (i==index) continue;

        newDacl[count] = dacl[i];
        count++;
       }

       return newDacl;
      }

      /// <summary>
      /// Fetches the DACL for the specified file (non-inherited only!)
      /// </summary>
      /// <param name="server">The server the file is placed</param>
      /// <param name="file">The path of the file</param>
      /// <param name="lfs">out parameter: identifies the object(file)</param>
      /// <param name="descriptor">out parameter: identifies the security
    descriptor</param>
      /// <returns>The discretionary access control list</returns>
      private static ManagementBaseObject[] FetchDACL(string server, string
    file, out ManagementObject lfs, out ManagementBaseObject descriptor)
      {
       lfs = null;
       descriptor = null;

       //The WMI Path of the file
       try
       {
        ManagementPath path = new ManagementPath();
        path.Server = server;
        path.NamespacePath = @""; //for local machine @"root\cimv2" works, for
    server not
        //Replace backslashes by double blackslashes
        file = file.Replace("\\", "\\\\");
        path.RelativePath =
    @"Win32_LogicalFileSecuritySetting.Path='"+file+"'";

        //Fetch object
        lfs = new ManagementObject(path);

        // Get the security descriptor for this object
        // bool EnablePrivileges = lfs.Scope.Options.EnablePrivileges;
        lfs.Scope.Options.EnablePrivileges = true;
        ManagementBaseObject outParams =
    lfs.InvokeMethod("GetSecurityDescriptor", null, null);

        if (((uint)(outParams.Properties["ReturnValue"].Value)) != 0)
        {
         System.Windows.Forms.MessageBox.Show("Failed to fetch object.",
    "Error");
         return null;
        }

        descriptor =
    (ManagementBaseObject)(outParams.Properties["Descriptor"].Value);
        //The DACL is an array of Win32_ACE objects.
        ManagementBaseObject[] dacl =
    (ManagementBaseObject[])(descriptor.Properties["Dacl"].Value);

        //Remove all inherited aces
        ArrayList nonInheritedAces = new ArrayList();
        foreach(ManagementBaseObject ace in dacl)
        {
         if ((uint)ace["AceFlags"] == (uint)AceFlags.NonInheritAce)
         {
          nonInheritedAces.Add(ace);
         }
        }

        dacl = new ManagementBaseObject[nonInheritedAces.Count];
        nonInheritedAces.CopyTo(dacl);

        return dacl;
       }
       catch (Exception e)
       {
        e.ToString();
        return null;
       }
      }
     }
    }


  • Next message: Vladimir Nechipurenko: "Re: To detect weak or blank password?"

    Relevant Pages

    • Re: HELP! CreateProcessWithLogonW issue
      ... OK - here is how I impersonate - the impersonation class is at the end of ... impersonation and the executing of the process in WMI. ... string password = i.GetPasswordFromRegistry; ... ManagementBaseObject inParams = processClass.GetMethodParameters; ...
      (microsoft.public.dotnet.framework)
    • Re: HELP! CreateProcessWithLogonW issue
      ... OK - here is how I impersonate - the impersonation class is at the end of ... impersonation and the executing of the process in WMI. ... string password = i.GetPasswordFromRegistry; ... ManagementBaseObject inParams = processClass.GetMethodParameters; ...
      (microsoft.public.platformsdk.security)
    • Re: HELP! CreateProcessWithLogonW issue
      ... OK - here is how I impersonate - the impersonation class is at the end of ... impersonation and the executing of the process in WMI. ... string password = i.GetPasswordFromRegistry; ... ManagementBaseObject inParams = processClass.GetMethodParameters; ...
      (microsoft.public.dotnet.framework.aspnet.security)
    • Re: HELP! CreateProcessWithLogonW issue
      ... OK - here is how I impersonate - the impersonation class is at the end of ... impersonation and the executing of the process in WMI. ... string password = i.GetPasswordFromRegistry; ... ManagementBaseObject inParams = processClass.GetMethodParameters; ...
      (microsoft.public.dotnet.framework.aspnet.webservices)
    • Why does this WMI Invoke not work?
      ... private string pName; ... WMIParameter[] inParams, string UserName, string Password) ... ManagementBaseObject Params = processClass.GetMethodParameters; ...
      (microsoft.public.dotnet.languages.csharp)