[ Index ]

PHP Cross Reference of phpSSH

/ -> util.php (source)

   1  <?
   2  /**
   3   * General utility functions
   4   *
   5   * This file contains convenience functions used throughout the package. 
   6   *
   7   * @author José R. Valverde <jrvalverde@cnb.uam.es>
   8   * @version 1.0
   9   * @copyright CSIC - GPL
  10   */
  11  
  12  /**
  13   * include global configuration definitions
  14   */
  15  require_once("./config.php");
  16  
  17  // ------------- COMMODITY ROUTINES ----------------
  18  
  19  /**
  20   * Start the display of a www page
  21   *
  22   * We have it as a function so we can customise all pages generated as
  23   * needed. This routine will open HTML, create the page header, and 
  24   * include any needed style sheets (if any) to provide a common 
  25   * look-and-feel for all pages generated.
  26   */
  27  function set_header()
  28  {
  29      global $app_name, $app_dir;
  30      // Start HTML vx.xx output
  31      echo "<html>";
  32      // Print headers
  33      echo "<head>";
  34      echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\">";
  35      echo "<meta name=\"DESCRIPTION\" content=\"a web interface to run TINKER molecular modelling on the EGEE grid\">";
  36      echo "<meta name=\"AUTHOR\" content=\"EMBnet/CNB\">";
  37      echo "<meta name=\"COPYRIGHT\" content=\"(c) 2004-5 by CSIC - Open Source Software\">";
  38      echo "<meta name=\"GENERATOR\" content=\"$app_name\">";
  39      echo "<link rel=\"StyleSheet\" href=\"$app_dir/style/style.css\" type=\"text/css\"/>";
  40      echo "<link rel=\"shortcut icon\" href=\"$app_dir/images/favicon.ico\"/>";
  41      echo "<title=\"$app_name\">";
  42      echo "</head>";
  43      // Prepare body
  44      echo "<body bgcolor=\"white\" background=\"$app_dir/images/6h2o-w-small.gif\" link=\"ffc600\" VLINK=\"#cc9900\" ALINK=\"#4682b4\">";
  45  }
  46  
  47  /**
  48   * close a web page
  49   *
  50   * Make sure we end the page with all the appropriate formulisms:
  51   * close the body, include copyright notice, state creator and
  52   * any needed details, and close the page.
  53   */
  54  function set_footer()
  55  {
  56      global $maintainer, $app_dir;
  57      // close body
  58      echo "</body><hr>";
  59      // footer
  60      echo "<center><table border=\"0\" width=\"90%\"><tr>";
  61          // Copyright and author
  62          echo "<td><A HREF=\"$app_dir/c/copyright.html\">&copy;</a>EMBnet/CNB</td>";
  63              // contact info
  64          echo "<td align=\"RIGHT\"><A HREF=\"emailto:$maintainer\">$maintainer</a></td>";
  65      echo "</tr></table></center>";
  66      // Page
  67      echo "</html>";
  68  }
  69  
  70  /**
  71   * print a warning
  72   *
  73   * Prints a warning in a separate pop-up window.
  74   * A warning is issued when a non-critical problem has been detected.
  75   * Execution can be resumed using some defaults, but the user should
  76   * be notified. In order to not disrupt the web page we are displaying
  77   * we use a JavaScript pop-up alert to notify the user.
  78   *
  79   * @param msg the warning message to send the user
  80   */
  81  function warning($msg)
  82  {
  83      echo "<script language=\"JavaScript\">";
  84      echo "alert(\"WARNING:\n $msg\");";
  85      echo "</script>";
  86  }
  87  
  88  /**
  89   * print an error message and exit
  90   *
  91   * Whenever we detect something wrong, we must tell the user. This function
  92   * will take an error message as its argument, format it suitably and
  93   * spit it out.
  94   *
  95   * @note This might look nicer using javascript to pop up a nice window with
  96   * the error message. Style sheets would be nice too.
  97   *
  98   * @param where the name of the caller routine or the process where the
  99   *         error occurred
 100   * @param what  a description of the abnormal condition that triggered
 101   *          the error
 102   */
 103  
 104  function error($where, $what)
 105  {
 106      // format the message
 107      echo "<p></p><center><table border=\"2\">\n";
 108      echo "<tr><td><center><font color=\"red\"><strong>\n";
 109  
 110      // output the message
 111      echo "ERROR - HORROR\n";
 112  
 113      // close format
 114      echo "</strong></font></center></td></tr>\n";
 115      echo "<tr><td><center><b>$where</b></center></td></tr>\n";
 116      echo "<tr><td><center>$what</center></td></tr>\n";
 117      echo "</table></center><p></p>\n";
 118  }
 119  
 120  /**
 121   * print a letal error message and die
 122   *
 123   * This function is called whenever a letal error (one that prevents
 124   * further processing) is detected. The function will spit out an
 125   * error message, close the page and exit the program.
 126   * It should seldomly be used, since it may potentially disrupt the
 127   * page layout (e.g. amid a table) by not closing open tags of which
 128   * it is unaware.
 129   * Actually it is a wrapper for error + terminate.
 130   *
 131   * @param where location (physical or logical) where the error was
 132   * detected: a physical location (routine name/line number) may be
 133   * helpful for debugging, a logical location (during which part of
 134   * the processing it happened) will be more helful to the user.
 135   *
 136   * @param what a descrition of the abnormality detected.
 137   */
 138  function letal($what, $where)
 139  {
 140      error($what, $where);
 141      set_footer();
 142          exit();
 143  }
 144  
 145  // ------------- SSH ROUTINES ----------------
 146  
 147  /**
 148   *  Execute a single command remotely using ssh and 
 149   * return its entire output (like passthru)
 150   *
 151   *  This might be done as well using a pipe on /tmp and
 152   * making the command 'cat' the pipe: when ssh runs, it
 153   * runs the command 'cat' on the pipe and hangs on read.
 154   *  Then we just need a thread to open the pipe, put the
 155   * password and close the pipe.
 156   *  This other way the password is never wirtten down.
 157   * But, OTOH, the file life is so ephemeral that most
 158   * of the time it will only exist in the internal system
 159   * cache, so this approach is not that bad either.
 160   *
 161   *  @param remote   The remote end to run the command, in
 162   *                  the form 'user@host' (or 'host' if the
 163   *                  username is the same).
 164   *  @param password The remote password. Note that if direct
 165   *                  RSA/DSA/.shosts/.rhosts login is enabled
 166   *                  then the password should be ignored as
 167   *                  SSH should not run the ASKPASS command).
 168   *  @param command  The command to execute on the remote end
 169   *                  NOTE: if you want to use redirection, the
 170   *                  entire remote command line should be 
 171   *                  enclosed in additional quotes!
 172   *  @param status   Optional, this will hold the termination
 173   *                  status of SSH after invocation, which
 174   *                  should be the exit status of the remote
 175   *                  command or 255 if an error occurred
 176   *  @return output  The output of the remote command.
 177   */
 178  function ssh_passthru($remote, $password, $command, $status)
 179  {
 180      umask(0077);
 181      $tmpfname = tempnam("/tmp", "egTinker");
 182      chmod($tmpfname, 0700);
 183      $fp = fopen($tmpfname, "w");
 184      fputs($fp, "#!/bin/sh\necho $password\n");
 185      fputs($fp, "rm -f $tmpfname\n");
 186      fclose($fp);
 187      putenv("DISPLAY=none:0.");
 188      putenv("SSH_ASKPASS=$tmpfname");
 189      return passthru("ssh -x -t -t $remote $command", $status);
 190  }
 191  
 192  // Do a remote scp connection with local password
 193  /**
 194   *  Copy a file or directory from one source to a destination
 195   *
 196   *  This function copies source to dest, where one of them is a
 197   * local filespec and the other a remote filespec of the form
 198   * [user@]host:path
 199   *
 200   *  If the original source is a directory, it will be copied
 201   * recursively to destination (hence easing file transfers).
 202   *
 203   *  The function returns TRUE on success or FALSE on failure.
 204   *
 205   */
 206  function ssh_copy($origin, $destination, $password)
 207  {
 208      umask(0077);
 209      $tmpfname = tempnam("/tmp", "egTinker");
 210      chmod($tmpfname, 0700);
 211      $fp = fopen($tmpfname, "w");
 212      fputs($fp, "#!/bin/sh\necho $password\n");
 213      fputs($fp, "rm $tmpfname\n");
 214      fclose($fp);
 215      putenv("DISPLAY=none:0.");
 216      putenv("SSH_ASKPASS=$tmpfname");
 217      system("scp -pqrC $origin $destination", $status);
 218      if ($status == 0)
 219          return TRUE;
 220      else
 221          return FALSE;
 222  }
 223  
 224  function ssh_open($remote, $password)
 225  {    
 226      global $php_version;
 227      global $debug;
 228  
 229      // Open a child process with the 'proc_open' function. 
 230      //
 231      // Some tricks: we must open the connection using '-x' to disable
 232      // X11 forwarding, and use '-t -t' to avoid SSH generating an error
 233      // because we are not connected to any terminal.
 234      // NOTE:
 235      //   We require users to have an account and password on
 236      //   the UI and provide their user/password through the web or
 237      //   otherwise (e.g. using myproxy)
 238      //
 239      // NOTE: if the web server is trusted remotely (i.e. it's SSH public 
 240      // key is accepted in ~user@host:.ssh/authorized_keys) then any 
 241      // password will do.
 242      if ($php_version < 5) {
 243      // Prepare I/O
 244      $descriptorspec = array(
 245              0 => array("pipe", "r"),  // connect child's stdin to the read end of a pipe
 246              1 => array("pipe", "w"),  // connect child's stdout to the write end of a pipe
 247              2 => array("pipe", "w")   // stderr is a pipe to read from
 248      );
 249      // prepare password
 250      putenv("DISPLAY=none:0.");
 251      putenv("SSH_ASKPASS=$tmpfname");
 252      umask(0077);
 253      $tmpfname = tempnam("/tmp", "egTinker");
 254      chmod($tmpfname, 0700);
 255      $fp = fopen($tmpfname, "w");
 256      fputs($fp, "#!/bin/sh\necho $password\n");
 257      fputs($fp, "rm $tmpfname\n");
 258      fclose($fp);
 259  
 260      $process = proc_open("ssh -x -t -t $remote", 
 261                   $descriptorspec,
 262               $pipes);
 263      if ($debug) echo "ssh -x -t -t $remote<br />\n";
 264      // check status
 265      if (!is_resource($process)) 
 266      {
 267          letal("SSH::connect", "cannot connect to the remote host");
 268          return;
 269      }
 270      if ($debug) echo "proc_open<br />\n";
 271  
 272      }
 273      else {     /* php5 -- we can use PTYs */
 274          /* XXX -- untested -- probably unneeded */
 275      $descriptorspec = array(
 276          0 => array("pty"),
 277          1 => array("pty"),
 278          2 => array("pty")
 279      );
 280      // prepare password
 281      putenv("DISPLAY=none:0.");
 282      putenv("SSH_ASKPASS=$tmpfname");
 283      umask(0077);
 284      $tmpfname = tempnam("/tmp", "egTinker");
 285      chmod($tmpfname, 0700);
 286      $fp = fopen($tmpfname, "w");
 287      fputs($fp, "#!/bin/sh\necho $password\n");
 288      fputs($fp, "rm $tmpfname\n");
 289      fclose($fp);
 290  
 291      $process = proc_open("ssh -x -t -t $remote", 
 292                       $descriptorspec,
 293               $pipes);
 294  
 295      // check status
 296      if (!is_resource($process)) 
 297      {
 298          letal("SSH::connect", "cannot connect to the remote host");
 299          return;
 300      }
 301  
 302      $status = proc_get_status($process);
 303      if ($status->running == FALSE) {
 304          fclose($pipes[0]); fclose($pipes[1]); fclose($pipes[2]);
 305          proc_close($process);
 306          letal("SSH::connect", "connection exited ".$status->exitcode);
 307          return;
 308      }
 309      if ($status->signaled) {
 310          fclose($pipes[0]); fclose($pipes[1]); fclose($pipes[2]);
 311          proc_close($process);
 312          letal("SSH::connect", "connection terminated by ".$status->termsig);
 313          return;
 314      }
 315      if ($status->stopped) {
 316          // Tell the user and hope for the best
 317          warning("SSH::connect stopped by ".$status->stopsig.
 318          " it may still have a chance though");
 319      }
 320  
 321      }
 322  
 323      // $pipes now looks like this:
 324      //   0 => writeable handle connected to child stdin
 325      //   1 => readable handle connected to child stdout
 326  
 327      // We now have a connection to the remote Grid User Interface
 328      // Server which we may use to send commands/receive output
 329      return array('stdin' => $pipes[0],
 330                   'stdout' => $pipes[1],
 331           'stderr' => $pipes[2] );
 332  }
 333  
 334  ?>


Generated: Tue May 31 15:44:47 2005 Cross-referenced by PHPXref 0.4.1