I have been using windows server 2012 R2 and I have bitvise SSH for SFTP and I want to create SFTP user programmatically in my application.
What I am thinking to do is When any user signup into the application then application will create a new folder and SFTP credentials for a newly created folder.So each user can access their SFTP credentials for uploading their files in their associated folder.
I can find the solution to create FTP users dynamically but I want to create SFTP user.
Question: Is it possible to create SFTP user using c#? If it is then how?
You can create SFPT user using C# like :
var cfg = new CBssCfg726("BssCfg726.BssCfg726");
cfg.SetSite("Bitvise SSH Server");
cfg.LoadServerSettings();
cfg.settings.access.virtAccountsEx.#new.virtAccount ="Virtual Account Name";
cfg.settings.access.virtAccountsEx.#new.virtPassword.Set("Password");
cfg.settings.access.virtAccountsEx.#new.group = "Virtual Users";
//if already virtAccountsEx then first delete...
for (uint i = 0; i < cfg.settings.access.virtAccountsEx.count; i++) {
if (cfg.settings.access.virtAccountsEx.GetItem(i).virtAccount == "Virtual Account Name") {
cfg.settings.access.virtAccountsEx.Erase(i);
}
}
cfg.settings.access.virtAccountsEx.#new.fwding.srvSideC2S.ipv4Ex.#new.targetHost = "127.0.0.1";
cfg.settings.access.virtAccountsEx.#new.fwding.srvSideC2S.ipv4Ex.#new.targetPort = 80;
cfg.settings.access.virtAccountsEx.#new.fwding.srvSideC2S.ipv4Ex.#new.proxyProfile = "Default";
cfg.settings.access.virtAccountsEx.#new.loginAllowed = cfg.DefaultYesNo.yes;
cfg.settings.access.virtAccountsEx.#new.xfer.mountPointsEx.Clear();
cfg.settings.access.virtAccountsEx.#new.xfer.mountPointsEx.#new.sfsMountPath = "/";
cfg.settings.access.virtAccountsEx.#new.xfer.mountPointsEx.#new.realRootPath = "Path to folder";
cfg.settings.access.virtAccountsEx.#new.xfer.mountPointsEx.NewCommit();
cfg.settings.access.virtAccountsEx.#new.fwding.srvSideC2S.ipv4Ex.NewCommit();
cfg.settings.access.virtAccountsEx.NewCommit();
cfg.SaveServerSettings();
Related
I am trying to read and write data in a Linux machine from another server machine which is Windows OS using a console application exe file, since the Linux machine is accessible only from the server windows machine.
I have read json data from the .json file and updated it using the code mentioned below.
Now I want to write the same in the .json file by overwriting file with updated data and saving it.
try
{
AuthenticationMethod method = new PasswordAuthenticationMethod(appSettings.Value.Username, appSettings.Value.Password);
ConnectionInfo connection = new ConnectionInfo(appSettings.Value.Host, appSettings.Value.Username, method);
var client = new SshClient(connection);
client.Connect();
if (!client.IsConnected)
{
Console.WriteLine("Not Connected...");
}
else
{
Console.WriteLine("Connected...");
var readCommand = client.RunCommand("cat /AAA/BBB/CCC/DDD/main_copy.json");
//Console.WriteLine(readCommand.Result);
dynamic jsonObj = Newtonsoft.Json.JsonConvert.DeserializeObject(readCommand.Result);
jsonObj["Load_Frequency"] = "Monthly";
string output = Newtonsoft.Json.JsonConvert.SerializeObject(jsonObj, Newtonsoft.Json.Formatting.Indented);
//File.WriteAllText("settings.json", output);--here I need to write code that run Linux command for overwriting .json file with updated data.
//var writeCommand = client.RunCommand("mkdir \"/home/user/ssh_output\"");
Thread.Sleep(100000);
}
}
I tried below command:
var writeCommand = client.RunCommand("cat " + output + " > /AAA/BBB/CCC/DDD/main_copy.json");
But it is showing No such file or directory when I execute this command directly in the putty.
Can you help to write linux command for that.
I am creating an assembly file so that get files and put files can be called as a Stored Procedure from SQL Server. Below is the method for put files. When I pass SqlBoolean DeleteLocalFolder=true, WinSCP errors out with the below error message:
Error: WinSCP.SessionRemoteException: Error deleting file System
Error. Code: 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;
}
}
I have written custom code in SSIS script task and have called the Session.PutFiles method by passing the argument bool remove = true. It works with out any problem. Can anyone please explain why it errors only in the custom assembly?
By default, processes that reach outside of SQL Server use the security context of the service account of the MSSQLSERVER (or MSSQL.InstanceName) service. When using this default setup, this service account would need to have write / modify access to the folder that the file is in (and possibly to the file itself if the file permissions are using inheritance).
Alternatively, you can use impersonation to change the security context of the external process to that of the Login (within SQL Server) executing the stored procedure, but only if the Login is a Windows Login. SQL Server logins do not have an SID known to the OS, so their security context would use the default, which again is that of the service account for the main SQL Server Database Engine process.
using System.Security.Principal;
public class stuff
{
[SqlProcedure]
public static void PutFiles()
{
using (WindowsImpersonationContext __ImpersonationIdentity =
SqlContext.WindowsIdentity.Impersonate())
{
... {do stuff} ...
__ImpersonationIdentity.Undo();
}
}
}
Also, Martin Prikryl commented on this answer to mention that:
WinSCP .NET assembly supports impersonation on its own. See Session.ExecutableProcessUserName and Session.ExecutableProcessPassword
The idea being ( I assume, though I have not tested):
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() */
In the example above, the username and password are string literals, but in practice those values can come from input parameters to the stored procedure or even from the sqlservr.exe.Config file. Or since the Assembly has a PERMISSION_SET of UNSAFE in order to reference the COM object, you can really get the values from anywhere, including the registry, etc.
So perhaps that is something to try. I am not sure of the timing of when that takes effect, so try one option and if it doesn't work, then try the other.
Please note that, at the very least, the difference between the options is:
Using impersonation via SQLCLR as I provided code for above only allows for the calling Login to be impersonated (and only if that Login is a Windows Login), not any random Login. But, this doesn't require a password either.
Using WinSCP for the impersonation allows for flexibility in what Login / account is being impersonated, BUT it requires passing in a password.
The WinSCP impersonation will allow impersonation to be used by a SQL Server Login, so that is an interesting option there
In my C# project I have included ChilkatDotNet2.dll in order to connect to a SFTP server. For the moment, I have tried to implemt a simple connection method like the following:
Chilkat.Ftp2 F = null;
F = (Chilkat.Ftp2)new Chilkat.Ftp2();
F.Hostname = "sftp.domain.com";
F.Username = "username";
F.Password = "password";
F.Port = 22;
F.AuthTls = true;
if (!(F.Connect())) {
MainFrm.set_AlertMessage(F.ConnectFailReason);
}
and it always fails connecting and I always get the error 200 which means
Connected, but failed to receive greeting from FTP server.
according to Chilkat documentation.
What am I missing? I have tried to connect to a simple ftp server test (without SSL/TLS) and it connects correctly so I think I am missing something.
The credentials I was given are correct as I tried to connect to the SFTP server with Filezilla.
Thank you.
UPDATE
Chilkat.SFtp v_SFTP = null;
v_SFTP = (Chilkat.SFtp)new Chilkat.SFtp();
if (v_SFTP.Connect("sftp.domain.com", 22) {
if (v_SFTP.AuthenticatePw("username", "password")) {
IDVariant v_SUCCESS = null;
bool v_SUCCESS = v_SFTP.InitializeSftp();
}
}
else {
MainFrm.set_AlertMessage(v_SFTP.LastErrorText);
}
F = (Chilkat.Ftp2)new Chilkat.Ftp2();
Chilkat.Ftp2 is an FTP client. It supports the FTP protocol. SFTP is a completely different protocol which just happens to have a similar name.
If you want to connect to an SFTP server using Chilkat, look at Chilkat.SFtp.
This question already has answers here:
Enumerating Network Sessions
(2 answers)
Closed 6 years ago.
how to retrieve the details who are connected to Shared folder Sessions.
Computer Management->Shared Folders->Sessions ??
I have tried retrieving shared folder details using ManagementScope Class , but unable to get the list of sessions connected to the shared folder ..
i am unable to get the details of the sessions which are present in the network computer
You can use the command "Icacls.exe" to get a list of user that are accessing a folder. In C#, you can do it like:
// Start a process and with the folder path as parameter
string folder = #"N:\Documents\Files\folderName";
ProcessStartInfo oInfo = new ProcessStartInfo();
oInfo.FileName = "Icacls.exe";
oInfo.Arguments = folder;
oInfo.RedirectStandardOutput = true;
oInfo.UseShellExecute = false;
Process oProcess = new Process();
oProcess.StartInfo = oInfo;
oProcess.Start();
// Redirect the result in a string
string result = oProcess.StandardOutput.ReadToEnd();
Console.WriteLine(result);
Console.Read();
// Do some stuff with the string
When running the code below, I keep getting "access is denied", but i have full administrative rights on the folder.
{"Cannot open backup device '\\\\networkDrive\backups\\'. Operating system error 5(Access is denied.).\r\nBACKUP DATABASE is terminating abnormally."}
the folder target is #"\networkDrive\backups";
I've also tried #"C:\backups"\ and #"C:\backups"
private static string publicConString = "server=myServer;Trusted_Connection=Yes;persist security info=False;connection timeout=120";
public static void BackupDatabase(String databaseName, String userName, String password, String serverName, String destinationPath)
{
Backup sqlBackup = new Backup();
sqlBackup.Action = BackupActionType.Database;
sqlBackup.BackupSetDescription = "ArchiveDataBase:" +
DateTime.Now.ToShortDateString();
sqlBackup.BackupSetName = "Archive";
sqlBackup.Database = databaseName;
BackupDeviceItem deviceItem = new BackupDeviceItem(destinationPath, DeviceType.File);
SqlConnection sqlCon = new SqlConnection(publicConString);
ServerConnection connection = new ServerConnection(sqlCon);
Server sqlServer = new Server(connection);
Database db = sqlServer.Databases[databaseName];
sqlBackup.Initialize = true;
sqlBackup.Checksum = true;
sqlBackup.ContinueAfterError = true;
sqlBackup.Devices.Add(deviceItem);
sqlBackup.Incremental = false;
sqlBackup.ExpirationDate = DateTime.Now.AddDays(3);
//sqlBackup.LogTruncation = BackupTruncateLogType.Truncate;
sqlBackup.FormatMedia = false;
sqlBackup.SqlBackup(sqlServer);
From your description, I think you would like to back up database to a network share folder, right?
Based on the error message, I think the SQL Server service account doesn’t have sufficient permission on the share folder. Please ensure the SQL Server service account is a domain account and it has sufficient permissions.
Please refer to this info for more information.
You cannot back up databases to a network drive if your account have not sufficient permissions to access the network drive.