SQLCLR函数通过模拟获取文件信息

时间:2013-11-27 20:01:18

标签: c# sql-server sqlclr

所以,我有一个SQLCLR函数,我已经编写以获取文件系统信息,如果我在本地SQL服务器上获取信息,但是当我尝试通过UNC在远程计算机上获取文件信息时,它可以正常工作路径(\\ server \ c $ \ directory \)我得到权限被拒绝的问题。我认为这是双跳权限问题,但我无法弄清楚如何解决这个问题。这是代码的简化版本,只返回文件名...以降低复杂性和行。

using System;
using System.Collections;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.IO;
using System.Security.Principal;
using Microsoft.SqlServer.Server;

namespace CLRFunctions
{
    public class SQLFileSystem
    {
        [SqlFunction(FillRowMethodName = "FillRow", TableDefinition = "FileName nvarchar(500)", DataAccess = DataAccessKind.Read)]
        public static IEnumerable fnGetFiles(SqlString Path, SqlString FilePattern, SqlBoolean Recursive)
        {
            String[] files = null;
            WindowsIdentity clientId = null;
            WindowsImpersonationContext impersonatedUser = null;

            clientId = SqlContext.WindowsIdentity;

            try
            {
                try
                {
                    impersonatedUser = clientId.Impersonate();
                    if (impersonatedUser != null)
                    {
                        files = Recursive ? Directory.GetFiles(Path.ToString(), FilePattern.ToString(), SearchOption.AllDirectories) : Directory.GetFiles(Path.ToString(), FilePattern.ToString(), SearchOption.TopDirectoryOnly);
                    }
                }
                catch (Exception ex)
                {
                    files = null;
                }
                finally
                {
                    if (impersonatedUser != null)
                    {
                        impersonatedUser.Undo();
                    }
                }
            }
            catch
            {
                throw;
            }

            return files;
        }

        public static void FillRow(Object obj, out SqlString FileName)
        {
            String file = (String)obj;
            FileInfo fi = new FileInfo(file);
            FileName = fi.Name;
        }
    }
}

这是我得到的错误。

Msg 6522, Level 16, State 1, Line 1
A .NET Framework error occurred during execution of user-defined routine or aggregate "fnGetFiles": 
System.UnauthorizedAccessException: Access to the path '\\server\c$\temp' is denied.
System.UnauthorizedAccessException: 
    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
    at System.IO.Directory.InternalGetFileDirectoryNames(String path, String userPathOriginal, String searchPattern, Boolean includeFiles, Boolean includeDirs, SearchOption searchOption)
    at System.IO.Directory.GetFiles(String path, String searchPattern, SearchOption searchOption)
    at VanClinic.Libraries.SQLFileSystem.SQLFileSystem.fnGetFiles(SqlString Path, SqlString FilePattern, SqlBoolean Recursive)

1 个答案:

答案 0 :(得分:1)

默认情况下,Impersonation仅允许凭据在本地系统上运行。要在本地系统之外应用这些凭据,您需要为您的帐户启用委派。以下定义取自:http://msdn.microsoft.com/en-us/library/system.security.principal.tokenimpersonationlevel.aspx

  

模拟:服务器进程可以模拟客户端   本地系统上的安全上下文。服务器无法模拟   远程系统上的客户端。

     

委派:服务器进程可以模拟客户端的安全性   远程系统上下文。

此设置可在Active Directory中配置,还需要先设置SPN。下面的文章详细介绍了实现这项工作所需的步骤(我相信需要免费注册):

Removing the Linked Server 2 hop Limitation