WinSCP Session.PutFiles with Remove = true возвращает «Ошибка удаления файла Системная ошибка. Код: 5» при вызове из SQLCLR, но работает в задаче сценария служб SSIS - PullRequest
0 голосов
/ 18 сентября 2018

Я создаю файл сборки, чтобы получить файлы и положить файлы могут быть вызваны как хранимая процедура из SQL Server.Ниже приведен способ размещения файлов.Когда я передаю SqlBoolean DeleteLocalFolder=true, WinSCP выдает ошибку с приведенным ниже сообщением об ошибке:

Ошибка: WinSCP.SessionRemoteException: Ошибка удаления файла Системная ошибка.Код: 5

[SqlProcedure]
public static void PutFiles(SqlString HostName, SqlString UserName, SqlString Password,
                            SqlString SshHostKeyFingerprint, SqlString SshPrivateKeyPath, 
                            SqlString SshPrivateKeyPassphrase, SqlString LocalFolderPath,
                            SqlString RemoteFolderPath,SqlBoolean DeleteLocalFolder,
                            SqlString FileMask, out SqlString strMessage)
{
    // Declare Variables to hold the input parameter values
    string hostName = HostName.Value;
    string userName = UserName.Value;
    string password = Password.Value;
    string sshFingerPrint = SshHostKeyFingerprint.Value;
    string sshPrivateKey = SshPrivateKeyPath.Value;
    string sshPassPhrase = SshPrivateKeyPassphrase.Value;

    bool delateLocalFolder = DeleteLocalFolder.Value;
    //Local Directory 
    DirectoryInfo dir = new DirectoryInfo(LocalFolderPath.Value);
    string folderName = dir.Name;

    //Begin connection to SFTP **Always uses default SFTP port 
    try
    {
        string FtpFolderPath = RemoteFolderPath.Value;

        SessionOptions options = new SessionOptions()
        {
            Protocol = Protocol.Sftp,
            HostName = hostName,
            UserName = userName,
            Password = password,
            SshHostKeyFingerprint = sshFingerPrint,
            SshPrivateKeyPath = sshPrivateKey,
            SshPrivateKeyPassphrase = sshPassPhrase                          
        };

        //Open the Remote session
        using (Session session = new Session())
        {
            session.ExecutablePath = ExecutablePath+"WinSCP.exe";
            session.SessionLogPath = ExecutablePath+"WinscpLog.log";
            session.DisableVersionCheck = true;
            session.Open(options);

            session.ExecutableProcessUserName = "username to log into the sql server instance";

            SecureString _Password = new SecureString();
            foreach (char _PasswordChar in "password to log in sql instance")
            {
                _Password.AppendChar(_PasswordChar);
            }
            session.ExecutableProcessPassword = _Password;
            // Upload files
            TransferOptions transferOptions = new TransferOptions();
            transferOptions.TransferMode = TransferMode.Binary;
            transferOptions.FileMask = FileMask.Value;

            TransferOperationResult transferoperationalResult;

            transferoperationalResult = session.PutFiles(LocalFolderPath.Value, FtpFolderPath, false, transferOptions);
            transferoperationalResult.Check();

            if (transferoperationalResult.IsSuccess)
            {
                if (dir.Exists == true)
                {
                    string sourcePath = FtpFolderPath + folderName + "//";
                    session.MoveFile(sourcePath + "*.*", FtpFolderPath); 
                    session.RemoveFiles(sourcePath);
                }
            }
        }

        strMessage = "Upload of files successful";
    }
    catch (Exception e)
    {
        //Console.WriteLine("Error: {0}", e);
        strMessage = "Error: "+ e;
    }
}

Я написал собственный код в задаче сценария служб SSIS и вызвал метод Session.PutFiles , передав аргумент bool remove = true.Это работает без каких-либо проблем.Может кто-нибудь объяснить, почему это ошибки только в кастомной сборке?

1 Ответ

0 голосов
/ 18 сентября 2018

По умолчанию процессы, выходящие за пределы SQL Server, используют контекст безопасности учетной записи службы службы MSSQLSERVER (или MSSQL.InstanceName).При использовании этой настройки по умолчанию эта учетная запись службы должна иметь доступ на запись / изменение к папке, в которой находится файл (и, возможно, к самому файлу, если права доступа к файлу используют наследование).

Кроме того, вы можетеможет использовать олицетворение для изменения контекста безопасности внешнего процесса на контекст входа в систему (в SQL Server), выполняющего хранимую процедуру, но только в том случае, если имя входа является именем входа Windows.У имен входа SQL Server нет идентификатора безопасности, известного операционной системе, поэтому их контекст безопасности будет использовать значение по умолчанию, которое опять-таки соответствует учетной записи службы для основного процесса компонента SQL Server Database Engine.

using System.Security.Principal;

public class stuff
{
   [SqlProcedure]
   public static void PutFiles()
   {

      using (WindowsImpersonationContext __ImpersonationIdentity =
                   SqlContext.WindowsIdentity.Impersonate())
      {
         ... {do stuff} ...

         __ImpersonationIdentity.Undo();
      }
   }
}

Кроме того,Мартин Прикрыл прокомментировал этот ответ, отметив, что:

Сборка WinSCP .NET поддерживает олицетворение самостоятельно.См. Session.ExecutableProcessUserName и Session.ExecutableProcessPassword

Идея заключается в том (я предполагаю, хотя я не проверял):

using System.Security;

  ...

   using (Session session = new Session())
   {
     session.ExecutableProcessUserName = "some_user_name";

     SecureString _Password = new SecureString();
     foreach (char _PasswordChar in "some_password")
     {
        _Password.AppendChar(_PasswordChar);
     }
     session.ExecutableProcessPassword = _Password;
     ... other session stuff...
     session.Open(options);

       ...more stuff...

     _Password.Dispose();
   } /* using() */

В приведенном выше примере имя пользователя и пароль являются строковыми литералами, но на практике эти значения могут поступать из входных параметров в хранимую процедуру или даже из файла sqlservr.exe.Config.Или, поскольку сборка имеет PERMISSION_SET из UNSAFE для ссылки на COM-объект, вы действительно можете получить значения из любого места, включая реестр и т. Д.

Так что, возможно, стоит попробовать.Я не уверен в сроках, когда это вступит в силу, поэтому попробуйте один вариант, и если он не работает, то попробуйте другой.

Обратите внимание, что, по крайней мере, разница между вариантамиis:

  1. Использование олицетворения через SQLCLR, как я предоставил для кода выше, позволяет только олицетворять вызывающий вход в систему (и только если этот вход в систему является входом в систему Windows), а не случайный вход в систему.Но для этого также не требуется пароль.
  2. Использование WinSCP для олицетворения допускает гибкость в том, какая учетная запись / олицетворяется, НО требует ввода пароля.
  3. WinSCPолицетворение позволит использовать олицетворение при входе в систему на SQL Server, так что это интересный вариант
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...