1

我正在使用下面的代码来更改文件的所有者。此代码在用 C# 4.0 版编写的 Windows 服务中运行。它在本地服务器上运行,运行 Windows Server 2008 R2 Standard,Service Pack 1。

我需要将通过 FTP 接收的文件的所有者更改为域帐户。我可以登录到该框并使用资源管理器手动执行此操作,但是当我尝试通过代码运行此操作时,我得到一个 InvalidOperation 异常。我可以将所有者更改为本地系统帐户,但不能更改为网络帐户。对此的任何帮助将不胜感激。

我正在使用一些奇怪的 Microsoft Dynamics AX 代码来处理 EDI 文件。该过程要求文件的所有者是有效的 DAX 用户,在本例中为域用户。我们有供应商通过 FTP 向我们发送 EDI 数据。我们的 DAX 应用程序每 10 分钟检查一次 FTP 目录并处理文件。该过程当前失败,因为所有者无效。因此,我编写了一个服务来在文件到达时更改文件的所有者。但是,下面的代码失败,代码示例下方显示异常。

var ediFileOwner = new NTAccount("MyDomain", _ediEndpointUserAccount);

var fileSecurity = File.GetAccessControl(fileName);

var everyone = new SecurityIdentifier(WellKnownSidType.WorldSid, null);

fileSecurity.AddAccessRule(new FileSystemAccessRule(everyone, FileSystemRights.FullControl, AccessControlType.Allow));
fileSecurity.AddAccessRule(new FileSystemAccessRule(ediFileOwner, FileSystemRights.TakeOwnership, AccessControlType.Allow));


fileSecurity.SetOwner(ediFileOwner); //Change our owner from to our desired User

File.SetAccessControl(fileName, fileSecurity);

这是完整的例外:

System.InvalidOperationException: The security identifier is not allowed to be the owner of this object.
at System.Security.AccessControl.NativeObjectSecurity.Persist(String name, SafeHandle handle, AccessControlSections includeSections, Object exceptionContext)
at System.Security.AccessControl.NativeObjectSecurity.Persist(String name, AccessControlSections includeSections, Object exceptionContext)
at System.Security.AccessControl.NativeObjectSecurity.Persist(String name, AccessControlSections includeSections)
at System.Security.AccessControl.FileSystemSecurity.Persist(String fullPath)
at System.IO.File.SetAccessControl(String path, FileSecurity fileSecurity)

更新

如果我将运行服务的帐户更改为我试图更改为所有者的帐户,我会得到一个不同的异常。

意外异常:System.UnauthorizedAccessException:试图执行未经授权的操作。在 System.Security.AccessControl.Win32.SetSecurityInfo(ResourceType 类型、字符串名称、SafeHandle 句柄、SecurityInfos 安全信息、SecurityIdentifier 所有者、SecurityIdentifier 组、GenericAcl sacl、GenericAcl dacl)

4

1 回答 1

2

我最终使用了我在这里找到的一些代码,http://www.codeproject.com/Articles/10090/A-small-C-Class-for-impersonating-a-User

为了完成所有事情,我不得不跳过几圈,但它奏效了。为了避免我遇到的错误,除了在整个用户之间切换之外,我还必须使用我发现的 Impersonate 东西。

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

// ...        

//Copy the file. This allows our service account to take ownership of the copied file
var tempFileName = Path.Combine(Path.GetDirectoryName(file.FileName), "TEMP_" + file.FileNameOnly);
File.Copy(file.FileName, tempFileName);


var windowID = WindowsIdentity.GetCurrent();

var currUserName = windowID.User.Translate(typeof(NTAccount)).Value;
var splitChar = new[] { '\\' };

//var name = currUserName.Split(splitChar)[1];
//var domain = currUserName.Split(splitChar)[0];

var ediFileOwner = new NTAccount("TricorBraun", _radleyEDIEndpointUserAccount);

//We have to give Access to the service account to delete the original file
var fileSecurity = File.GetAccessControl(file.FileName);
var everyone = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
fileSecurity.AddAccessRule(new FileSystemAccessRule(everyone, FileSystemRights.FullControl, AccessControlType.Allow));
File.SetAccessControl(file.FileName, fileSecurity);
File.Delete(file.FileName);



//We rename our file to get our original file name back
File.Move(tempFileName, file.FileName);


//The following give our desired user permissions to take Ownership of the file.
//We have to do this while running under the service account.
fileSecurity = File.GetAccessControl(file.FileName);
var aosSID =  (SecurityIdentifier) ediFileOwner.Translate(typeof(SecurityIdentifier));
fileSecurity.AddAccessRule(new FileSystemAccessRule(aosSID, FileSystemRights.FullControl, AccessControlType.Allow));
File.SetAccessControl(file.FileName, fileSecurity);

//Now we user the Impersonator (http://www.codeproject.com/Articles/10090/A-small-C-Class-for-impersonating-a-User)
//This allows us to manage the file as the Account we wish to change ownership to.
//It makes itself the owner.
using (new Impersonator(_radleyEDIEndpointUserAccount, "MyDomain", "password")) {
    _logger.Debug(string.Format("Attempting changing owner to Tricorbraun\\{0}", _radleyEDIEndpointUserAccount));
    fileSecurity = File.GetAccessControl(file.FileName);
    fileSecurity.SetOwner(ediFileOwner); //Change our owner from LocalAdmin to our chosen DAX User
    _logger.Debug(string.Format("Setting owner to Tricorbraun - {0}", _radleyEDIEndpointUserAccount));
    File.SetAccessControl(file.FileName, fileSecurity);
}
于 2012-12-10T20:55:44.480 回答