title: PHP Telnet/SSH dynamic login
body: <p>I have an issue that's stumped me.</p>
  
  <p>I'm trying to automate a CLI login to a router and run some commands obtained via a webpage. However I don't know if the router has telnet or SSH enabled (might be one,the other, or both) and I have a list of possible username/password combos that I need to try to gain access.<br>
  Oh, and I can't change either the protocol type or the credentials on the device, so that's not really an option. </p>
  
  <p>I was able to figure out how to login to a router with a known protocol and login credentials and run the necessary commands(included below), but I don't know if I should use an if/else block to work through the telnet/ssh decisions, or if a switch statement might be better? Would using Expect inside PHP be an easier way to go? </p>
  
  <pre><code>function tunnelRun($commands,$user,$pass, $yubi){
      $cpeIP = "1.2.3.4";
      $commands_explode = explode("\n", $commands);
  
      $screenOut = "";
  
      $ssh = new Net_SSH2('router_jumphost');
      if (!$ssh-&gt;login($user, $pass . $yubi)) {
          exit('Login Failed');
      }
  
  
      $ssh-&gt;setTimeout(2);
      $ssh-&gt;write("ssh -l username $cpeIP\n");
      $ssh-&gt;read("assword:");
      $ssh-&gt;write("password\n");
      $ssh-&gt;read("#");
      $ssh-&gt;write("\n");
      $cpePrompt = $ssh-&gt;read('/.*[#|&gt;]/', NET_SSH2_READ_REGEX);
      $cpePrompt = str_replace("\n", '', trim($cpePrompt));
      $ssh-&gt;write("config t\n");
  
  
      foreach ($commands_explode as $i) {
          $ssh-&gt;write("$i\n"); // note the "\n"
          $ssh-&gt;setTimeout(2);
          $screenOut .= $ssh-&gt;read();
  
      }
      $ssh-&gt;write("end\n");
      $ssh-&gt;read($cpePrompt);
      $ssh-&gt;write("exit\n");
      echo "Router Update completed! Results below:&lt;br&gt;&lt;br&gt;";
  
      echo "&lt;div id=\"text_out\"&gt;&lt;textarea style=\" border:none; width: 700px;\" rows=\"20\"&gt;".$screenOut."&lt;/textarea&gt;&lt;/div&gt;";
  </code></pre>
  
  <p><strong>Update:</strong></p>
  
  <p>The solution I went with was a while/switch loop. I would of gone the Expect route, but I kept running into issues on getting the Expect module integrated into PHP on my server (Windows box.) If I had been using a Unix/Linux server Expect would of been the simplest way to achieve this.
  I just made it into a working demo for now, so there are a lot of variations missing from the case statements still, and error-handling still needs to bef figured out, but the basic idea is there. I still want to move the preg_match statements around a bit more to do the matching at the top of the while loop (so I don't spam the whole case section with different preg_match lines), but that may prove to be more work than I want for now. Hope this might help someone else trying to do the same!</p>
  
  <pre><code>    &lt;?php
   include('Net/SSH2.php');
   define('NET_SSH2_LOGGING', NET_SSH2_LOG_COMPLEX);
   ini_set('display_errors', 1);
  
  $conn = new Net_SSH2('somewhere.outthere.com');
  if (!$conn-&gt;login($user, $pass . $yubi)) {
      exit('Login Failed');
  }
  
  $prompt = "Testing#";
  
  $conn-&gt;setTimeout(2);
  $conn-&gt;write("PS1=\"$prompt\"");
  $conn-&gt;read();
  $conn-&gt;write("\n");
  $screenOut = $conn-&gt;read();
  
  //echo "$screenOut is set on the shell&lt;br&gt;&lt;br&gt;";
  echo $login_db[3][0]. "  ". $login_db[3][1];
  
  $logged_in = false;
  $status = "SSH";
  $status_prev = "";
  $login_counter = 0;
  while (!$logged_in &amp;&amp; $login_counter &lt;=3) {
      switch ($status) {
  
          case "Telnet":
              break;
          case "SSH":
              $conn-&gt;write("\n");
              $conn-&gt;write("ssh -l " . $login_db[$login_counter][0] . " $cpeIP\n");
              $status_prev = $status;
              $status = $conn-&gt;read('/\n([.*])$/', NET_SSH2_READ_REGEX);
              break;
          case (preg_match('/Permission denied.*/', $status) ? true : false):
              $conn-&gt;write(chr(3)); //Sends Ctrl+C
              $status = $conn-&gt;read();
              if (strstr($status, "Testing#")) {
                  $status = "SSH";
                  $login_counter++;
                  break;
              } else {
                  break 2;
              }
          case (preg_match('/[pP]assword:/', $status) ? true : false):
  
              $conn-&gt;write($login_db[$login_counter][1] . "\n");
              $status_prev = $status;
              $status = $conn-&gt;read('/\n([.*])$/', NET_SSH2_READ_REGEX);
              break;
          case (preg_match('/yes\/no/', $status) ? true : false):
              $conn-&gt;write("yes\n");
              $status_prev = $status;
              $status = $conn-&gt;read('/\n([.*])$/', NET_SSH2_READ_REGEX);
              break;
          case (preg_match('/(^[a-zA-Z0-9_]+[#]$)|(&gt;)/', $status,$matches) ? true : false):
  
  
              $conn-&gt;write("show version\n");
              $status = $conn-&gt;read("&gt;");
              if(preg_match('/ADTRAN|Adtran|Cisco/', $status)? true:false){
                  $logged_in = true;
                  break;
              }
  
          default:
              echo "&lt;br&gt;Something done messed up! Exiting";
              break 2;
  
      }
      //echo "&lt;pre&gt;" . $conn-&gt;getLog() . "&lt;/pre&gt;";
  }
  if ($logged_in === true) {
      echo "&lt;br&gt; Made it out of the While loop cleanly";
  } else {
      echo "&lt;br&gt; Made it out of the While loop, but not cleanly";
  }
  echo "&lt;pre&gt;" . $conn-&gt;getLog() . "&lt;/pre&gt;";
  
  $conn-&gt;disconnect();
  echo "disconnected cleanly";
  }
  ?&gt;
  </code></pre>