0

This one is driving me nuts... I want to write a simple C# application (with GUI) that logs into our Cisco Wireless Lan Controller (short WLC) via SSH and creates guest users. This would be quite easy with SSH.NET if not Cisco for whatever reason decided to not allow non-interactive logon - meaning you can't pass on username and password but have to type it in at the console. Even worse: they put an additional (non-functional) user prompt in front of the actual user prompt. God...

Anyway I figured it out using plink.exe and it is working quite ok, however I want to inspect the terminal output so I can decide if some commands were executed correctly. I want to use the output for the login too as the prompt appears somewhat slow and I can't rely on constant timing.

I have found some articles about redirection of the output (eg Process.start: how to get the output?), but it's just not working. I was only able to collect the output when plink.exe has been closed, but I need to read the output live with plink still running.

Here's my code so far:

namespace WIFI
{
  public class Program
  {
    private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        Application.Run(new myForm());
    }

    public static String ProcessInput(string user)
    {
        GlobalVar.hasError = false;
        GlobalVar.status = "";

        if (user.Length < 5 || user.Length > 10)
        {
            GlobalVar.status = "Username ungültig";
            GlobalVar.hasError = true;
        }
        else
        {
            WLCconnection WLC = new WLCconnection();
            WLC.ConnectWLC();

            if (!GlobalVar.hasError) WLC.UserExists(user);

            if (!GlobalVar.hasError) WLC.CreateUser(user);

            WLC.CloseWLC();
        }

        return GlobalVar.status;
    }
  }

  public static class GlobalVar
  {
    public static Boolean hasError;
    public static String status;
  }

  public class WLCconnection
  {
    Process terminal = new Process();
    StringBuilder terminalOutput = new StringBuilder();

    Boolean telnet = Convert.ToBoolean(System.Configuration.ConfigurationManager.AppSettings["telnet"]);
    String WLChostname = System.Configuration.ConfigurationManager.AppSettings["WLChostname"];
    String WLCusername = System.Configuration.ConfigurationManager.AppSettings["WLCusername"];
    String WLCpassword = System.Configuration.ConfigurationManager.AppSettings["WLCpassword"];

    public void ConnectWLC()
    {
        terminal.StartInfo.FileName = @System.Configuration.ConfigurationManager.AppSettings["plinkpath"];
        terminal.StartInfo.UseShellExecute = false;
        terminal.StartInfo.RedirectStandardInput = true;
        terminal.StartInfo.RedirectStandardOutput = true;
        terminal.StartInfo.RedirectStandardError = true;
        terminal.StartInfo.CreateNoWindow = true;

        if (telnet) terminal.StartInfo.Arguments = "-telnet " + WLChostname;
        else terminal.StartInfo.Arguments = "-ssh " + WLChostname;

        terminal.OutputDataReceived += (s, e) => terminalOutput.Append(e.Data);
        //terminal.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
        terminal.ErrorDataReceived += (s, e) => terminalOutput.Append(e.Data);
        //terminal.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler);

        terminal.Start();
        terminal.BeginOutputReadLine();
        terminal.BeginErrorReadLine();

        int runs = 0;
        if (!telnet)
        {
            while (!terminalOutput.ToString().Contains("login as:") && !GlobalVar.hasError)
            {
                Thread.Sleep(500);
                if (runs < 20) runs++;
                else GlobalVar.hasError = true;
            }
            terminal.StandardInput.Write("workaroundSSHproblem\n");
        }

        runs = 0;
        while (!terminalOutput.ToString().Contains("User:") && !GlobalVar.hasError)
        {
            Thread.Sleep(500);
            if (runs < 20) runs++;
            else GlobalVar.hasError = true;
        }
        terminal.StandardInput.Write(WLCusername + "\n");

        runs = 0;
        while (!terminalOutput.ToString().Contains("Password:") && !GlobalVar.hasError)
        {
            Thread.Sleep(500);
            if (runs < 20) runs++;
            else GlobalVar.hasError = true;
        }
        terminal.StandardInput.Write(WLCpassword + "\n");
    }

    public void CloseWLC()
    {
        terminal.StandardInput.WriteLine("logout");
        terminal.WaitForExit();
        terminal.CancelOutputRead();
        terminal.Close();
        terminal.Dispose();
    }

    public Boolean UserExists(String user)
    {
        int runs = 0;
        while (!terminalOutput.ToString().Contains("(Cisco Controller) >") && !GlobalVar.hasError)
        {
            Thread.Sleep(500);
            if (runs < 20) runs++;
            else GlobalVar.hasError = true;
        }
        terminal.StandardInput.Write("show netuser detail " + user);

        if (!terminalOutput.ToString().Contains("blabla"))
        {
            GlobalVar.status = "User " + user + " bereits aktiviert";
            GlobalVar.hasError = true;
        }

        return GlobalVar.hasError;
    }

    public void CreateUser(String user)
    {
        int runs = 0;
        while (!terminalOutput.ToString().Contains("(Cisco Controller) >") && !GlobalVar.hasError)
        {
            Thread.Sleep(500);
            if (runs < 20) runs++;
            else GlobalVar.hasError = true;
        }
        terminal.StandardInput.Write("config netuser add " + user + " " + System.Configuration.ConfigurationManager.AppSettings["guestpassword"] + " wlan 3 userType guest lifetime 86400");

        if (!GlobalVar.hasError)
        {
            if (UserExists(user))
            {
                GlobalVar.status = "";
                GlobalVar.hasError = false;
            }
            else
            {
                GlobalVar.status = "User " + user + " konnte nicht aktiviert werden";
                GlobalVar.hasError = true;
            }

        }
    }

    protected void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
    {
        terminalOutput.Append(outLine.Data);
    }
  }
}

I'd really appreciate your help!

Ryan Hardy
  • 15
  • 1
  • 6
  • I do not think there's anything that you can do with Plink, that you cannot implement with SSH.NET. – Martin Prikryl Nov 11 '17 at 17:19
  • Thank you @MartinPrikryl - glad to hear that from someone who's an expert in that area (and kudos to your great work!). My problem with SSH.NET is that (as it seems) the input of user and password are not accepted by the Wireless Lan Controller when passed as _command_ - which is the only way SSH.NET can pass on any input AFAIK. So with this very special implementation of the interactive user login I wasn't able to successfully login in using SSH.NET. – Ryan Hardy Nov 12 '17 at 09:15
  • So ask a question about your problem with SSH.NET rather than about a workround with Plink. – Martin Prikryl Nov 12 '17 at 10:23

1 Answers1

0

For whom it may be of any help: I solved it using SSH.NET again, but this time not using the built in functions to login in but by using in combination with ShellStream to manually process in- and output. Working great so far.

Ryan Hardy
  • 15
  • 1
  • 6