CLR Stored procedure to execute command

六月ゝ 毕业季﹏ 提交于 2019-12-24 09:48:42

问题


I have written a CLR stored procedure to execute command passed to it as parameter. This is code for the CLR stored procedure; I have registered assembly as "unsafe" in SQL Server and created stored procedure from it.

[SqlProcedure]
public static int ExecuteCommand(string cmd)
{
    int success = 0;

    try
    {
        EventLog.WriteEntry("MyAppName", "Starting execution " + cmd + " Username: " + System.Security.Principal.WindowsIdentity.GetCurrent().Name + " OR " + Environment.UserName, EventLogEntryType.Information);

        Process p = new Process();
        p.StartInfo = new ProcessStartInfo() { FileName = "cmd.exe", Arguments = cmd, WindowStyle = ProcessWindowStyle.Hidden};
        p.Start();
    }
    catch (Exception ex)
    {
        EventLog.WriteEntry("MyAppName", "Executed command : " + cmd + "  with error : " + ex.Message, EventLogEntryType.Error);
        success = 1;
    }

    return success;
}

This code is able to write to event viewer and prints username as NT AUTHORITY\SYSTEM. Then it launches cmd.exe, but it doesn't execute passed commands(e.g. mkdir) and cmd.exe stays in running state. In task manager, I can see multiple instances of cmd.exe for every run of stored procedure but with no value in username column. SQL Server service is running with Local System account.

What is going wrong here? If it is related to permissions, then is there way to execute CLR stored proecedure under context of user who is invoking stored procedure?


回答1:


While permissions might be an issue, you definitely seem to be invoking cmd.exe incorrectly. If you simply call it as:

cmd.exe mkdir folder_name

then you would get the behavior that you are seeing, namely the folder doesn't get created and the process continues without exiting.

You need to call cmd.exe passing in the command to run using the /C command-line switch, which instructs CMD to execute the provided command and then exit. Hence, calling the following:

cmd.exe /C mkdir folder_name

would work as you are expecting. So perhaps you need to use:

Arguments = "/C " + cmd

Also, there is a possibility that you might need another "WindowStyle" and/or other ProcessStartInfo property. If the above doesn't work, I will check what I have used in the past as I have gotten this to work.

P.S. You should use the Sql* types for parameters and return values for SQLCLR methods. So use SqlString instead of string and SqlInt32 instead of int. All of the Sql* types have a .Value property that returns the expected .NET native type. Hence you would use it as follows:

Arguments = "/C " + cmd.Value



回答2:


Sounds like an issue with impersonation or rather the lack thereof. SQL CLR doesn't forward your token (credentials) to other applications unless you explicity tell it to. You could try something like:

[SqlProcedure]
public static int ExecuteCommand(string cmd)
{
    int success = 0;
    Impersonate impersonatedUser = new Impersonate();
    try
    {
        EventLog.WriteEntry("MyAppName", "Starting execution " + cmd + " Username: " + System.Security.Principal.WindowsIdentity.GetCurrent().Name + " OR " + Environment.UserName, EventLogEntryType.Information);
        Process p = new Process();
        p.StartInfo = new ProcessStartInfo() { FileName = "cmd.exe", Arguments = cmd, WindowStyle = ProcessWindowStyle.Hidden };
        p.Start();

    }
    catch (Exception ex)
    {
        EventLog.WriteEntry("MyAppName", "Executed command : " + cmd + "  with error : " + ex.Message, EventLogEntryType.Error);
        success = 1;
    }
    finally
    {
        impersonatedUser.Undo();
    }
    return success;
}

Notice there are only a couple of lines different.

Impersonate impersonatedUser = new Impersonate();

this one tells SQL to impersonate the user that is executing the stored procedure. This will fail with SQL Authentication as SQL Authentication isn't actually a windows user.

finally
{
     impersonatedUser.Undo();
}

If you fail to revert the impersonation it can lead to other issues so putting this in the finally block will make the impersonation revert no matter what.

Here is a Microsoft Article on the subject that says a little more about it:

https://msdn.microsoft.com/en-us/library/ms345105.aspx



来源:https://stackoverflow.com/questions/40968009/clr-stored-procedure-to-execute-command

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!