2016-12-05 5 views
1

Я написал хранимую процедуру CLR для выполнения команды, переданной ей в качестве параметра. Это код хранимой процедуры CLR; Я зарегистрировал сборку как «небезопасную» в SQL Server и создал из нее хранимую процедуру.CLR Сохраненная процедура для выполнения команды

[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; 
} 

Этот код может написать просмотра событий и выводит имя пользователя, как NT AUTHORITY\SYSTEM. Затем он запускает cmd.exe, но он не выполняет переданные команды (например, mkdir) и cmd.exe остается в рабочем состоянии. В диспетчере задач я могу увидеть несколько экземпляров cmd.exe для каждого запуска хранимой процедуры, но без значения в столбце имени пользователя. Служба SQL Server работает с учетной записью Local System.

Что здесь общего не работает? Если это связано с разрешениями, то есть способ выполнить хранимую процедуру CLR в контексте пользователя, который вызывает хранимую процедуру?

ответ

1

Хотя разрешения может быть вопрос, вы, безусловно, как представляется, применение cmd.exe неправильно , Если вы просто вызываете его как:

cmd.exe mkdir folder_name 

тогда вы получите поведение, которое вы видите, а именно папка не получает создана, и процесс продолжается без выхода.

Вам нужно позвонить cmd.exe передавая команды для запуска с помощью /C ключа командной строки, которая инструктирует CMD выполнить прилагаемую команду, а затем выйти. Следовательно, вызывая следующее:

cmd.exe /C mkdir folder_name 

будет работать так, как вы ожидаете. Поэтому, возможно, вам нужно использовать:

Arguments = "/C " + cmd 

Кроме того, существует вероятность того, что вам может понадобиться другое «Оформление_окно» и/или другой ProcessStartInfo собственности. Если вышеуказанное не работает, я проверю, что я использовал в прошлом, поскольку я получил это, чтобы работать.

P.S. Вы должны использовать типы Sql* для параметров и возвращаемые значения для методов SQLCLR. Поэтому используйте SqlString вместо string и SqlInt32 вместо int. Все типы Sql* имеют свойство .Value, которое возвращает ожидаемый родной тип .NET. Следовательно, вы использовали бы его следующим образом:

Arguments = "/C " + cmd.Value 
+1

Спасибо. Это работало, как чудо для меня. – Mahesh

0

Звучит как проблема с олицетворением или, скорее, ее отсутствие. SQL CLR не пересылает ваш токен (учетные данные) другим приложениям, если вы не объясните это. Вы можете попробовать что-то вроде:

[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; 
} 

Обратите внимание, что существует только несколько строк.

Impersonate impersonatedUser = new Impersonate(); 

это говорит SQL о выдаче себя за пользователя, выполняющего хранимую процедуру. Это приведет к сбою с аутентификацией SQL, поскольку проверка подлинности SQL на самом деле не является пользователем Windows.

finally 
{ 
    impersonatedUser.Undo(); 
} 

Если вы не вернуться олицетворение это может привести к другим проблемам, так это положить в блоке, наконец, заставит олицетворение вернуться ни на что.

Вот статья Microsoft на эту тему, говорит немного больше об этом:

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

 Смежные вопросы

  • Нет связанных вопросов^_^