                      remctl PECL Extension for PHP

OVERVIEW

  The remctl PECL extension for PHP provides PHP bindings to the libremctl
  client library.  The provided interface is roughly the same as the C and
  Perl interfaces, with some minor variations to be more consistent with
  the normal PHP function interface.

  This PECL extension provides two interfaces, one which performs a single
  call to a remctl server and returns the result, and another which
  provides more control over the connection, returns individual output
  tokens, and allows multiple commands to be sent via the same connection.

REQUIREMENTS

  The module has only been tested with PHP 5.2 and may or may not work
  with earlier versions.  As with all libremctl bindings, it does not
  itself obtain Kerberos tickets and requires that a Kerberos ticket cache
  already be set up before making remctl calls.

  The PECL module build infrastructure is created on the fly by the
  configure script for the main remctl package using phpize.  This means
  that you must have phpize and all of its dependencies installed to build
  the PECL module.

SIMPLIFIED INTERFACE

  remctl(HOSTNAME, PORT, PRINCIPAL, COMMAND)
      Runs COMMAND on the remote system and returns an object containing
      the results.  COMMAND should be an array of the command, the
      subcommand, and any parameters.  HOSTNAME is the remote host to
      connect to.  PORT is the port; pass 0 to use the default library
      behavior (first try 4373 and then fall back to 4444).  PRINCIPAL is
      the principal of the server to use for authentication; pass in the
      empty string to use the default of host/HOSTNAME with the realm
      determined by domain-realm mapping.

  The return value of remctl() is an object which will have the following
  properties:

  error
      The error message from the remote host or the local client library
      if the remctl command fails.  Set to the empty string if there was
      no error.  Checking whether error is the empty string is the
      suppported way of determining whether the call succeeded.

  stdout
      The command's standard output or null if there was none.

  stdout_len
      The length of the command's standard output or 0 if there was none.

  stderr
      The command's standard error or null if there was none.

  stderr_len
      The length of the command's standard error or 0 if there was none.

  status
      The exit status of the command.

  Here is an example using the simplified interface:

      dl('remctl.so');
      if (!extension_loaded('remctl')) {
          echo "Failed to load remctl extension\n";
          exit(2);
      }
      $command = array('test', 'echo', 'hello world');
      $result = remctl('server.example.com', 0, '', $command);
      if ($result->error) {
          echo "remctl failed: $result->error\n";
          exit(2);
      }
      if ($result->stdout_len) {
          echo "stdout: $result->stdout";
      }
      if ($result->stderr_len) {
          echo "stderr: $result->stderr";
      }
      echo "status: $result->status";

  Each call to remctl() will open a new connection to the remote host and
  close it after retrieving the results of the command.

FULL INTERFACE

  The full remctl interface requires the user to do more bookkeeping, but
  provides more flexibility and visibility into what is happening at a
  protocol level.  It allows issuing multiple commands on the same
  persistant connection (provided that the remote server supports protocol
  version two; if it doesn't, the library will transparently fall back to
  opening a connection for each command).

  To use the full interface, first create a connection object with
  remctl_new(), connect to a server with remctl_open(), and then
  issue a command with remctl_command() and read output tokens with
  remctl_output().  Once a status token has been received, the command is
  complete and another command can be issued.

  The provided functions are:

  remctl_new()
      Create a new connection object.  This doesn't attempt to connect to
      a host and will only fail if the extension cannot allocate memory.

  remctl_error(CONNECTION)
      Returns, as a string, the error message from the last failed
      operation on the connection object CONNECTION.

  remctl_set_ccache(CCACHE)
      Sets the credential cache for outgoing connections to CCACHE.  This
      is normally the full path to a Kerberos ticket cache, but may have
      other valid forms depending on the underlying Kerberos
      implementation in use by GSS-API.  This method will affect all
      subsquent remctl_open() calls on the same object, but will have no
      effect on connections that are already open.  Returns true on
      success, false on failure.

      If the remctl client library was built against a Kerberos library
      and the GSS-API library supported gss_krb5_import_cred, this call
      affects only this connection object.  Otherwise, this will affect
      not only all subsequent open() calls for the same object, but all
      subsequent remctl connections of any kind from the same process, and
      even other GSS-API connections from the same process unrelated to
      remctl.

      Not all GSS-API implementations support setting the credential
      cache.  If this is not supported, false (for failure) will be
      returned.

  remctl_set_source_ip(SOURCE)
      Sets the source IP for outgoing connections to SOURCE, which can be
      either an IPv4 or an IPv6 address (if IPv6 is supported).  It must
      be an IP address, not a host name.  This will affect all subsequent
      remctl_open() calls on the same object, but will have no effect on
      connections that are already open.  Returns true on success, false
      on failure.

  remctl_set_timeout(TIMEOUT)
      Sets the timeout for connections and commands to TIMEOUT, which
      should be an integer number of seconds.  TIMEOUT may be 0 to clear a
      timeout that was previously set.  All subsequent operations on this
      object will be subject to this timeout, including open() if called
      prior to calling open().  Returns true on success and false on
      failure.  Failure is only possible if TIMEOUT is malformed.

      The timeout is a timeout on network activity from the server, not on
      a complete operation.  So, for example, a timeout of ten seconds
      just requires that the server send some data every ten seconds.  If
      the server sends only tiny amounts of data at a time, the complete
      operation could take much longer than ten seconds without triggering
      the timeout.

  remctl_open(CONNECTION, HOSTNAME[, PORT[, PRINCIPAL]])
      Connect to HOSTNAME on port PORT using PRINCIPAL as the remote
      server's principal for authentication.  If PORT is omitted or 0, use
      the default (first try 4373, the registered remctl port, and fall
      back to the legacy 4444 port if that fails).  If PRINCIPAL is
      omitted or the empty string, use the default of host/HOSTNAME, with
      the realm determined by domain-realm mapping.  Returns true on
      success, false on failure.

  remctl_command(CONNECTION, COMMAND)
      Send COMMAND (which should be an array) to the remote host.  The
      command may, under the remctl protocol, contain any character, but
      be aware that most remctl servers will reject commands or arguments
      containing ASCII 0 (NUL).  This currently therefore cannot be used
      for upload of arbitrary unencoded binary data.  Returns true on
      success (meaning success in sending the command and implying nothing
      about the result of the command), and false on failure.

  remctl_output(CONNECTION)
      Returns the next output token from the remote host.  This will be an
      object with one or more of the following properties:

      type
          The type of the output token, which will be one of "output",
          "error", "status", or "done".  A command will result in either
          one "error" token or zero or more "output" tokens followed by a
          "status" token.  The output is complete as soon as any token
          other than an "output" token has been received, but the library
          will keep returning "done" tokens to the caller for as long as
          remctl_output() is called without another remctl_command().

      data
          Returns the contents of the token for either an "error" or
          "output" token.  The returned data may contain any character,
          including ASCII 0 (NUL).

      stream
          For an "output" token, returns the stream with which the data is
          associated.  Currently, this will either be 1 for standard
          output or 2 for standard error.  This value is undefined for all
          other token types.

      status
          For a "status" token, returns the exit status of the remote
          command.  This value is undefined for all other token types.

      error
          For an "error" token, returns the remctl error code for the
          protocol error.  The text message will be returned in data.

  remctl_noop(CONNECTION)
      Send a NOOP message to the server and read the reply.  This is
      primarily used to keep a connection to a remctl server alive, such
      as through a firewall with a session timeout, while waiting to issue
      further commands.  Returns true on success, false on failure.

      The NOOP message requires protocol version 3 support in the server,
      so the caller should be prepared for this function to fail,
      indicating that the connection could not be kept alive and possibly
      that it was closed by the server.  In this case, the client will
      need to explicitly reopen the connection with remctl_open.

  remctl_close(CONNECTION)
      Explicitly close the connection and destroy the connection object.
      This will also be done automatically when the object is destroyed,
      so calling remctl_close explicitly is often not necessary.

  Here is an example using the full interface:

      dl('remctl.so');
      if (!extension_loaded('remctl')) {
          echo "Failed to load remctl extension\n";
          exit(2);
      }
      $r = remctl_new();
      if ($r == null) {
          echo "remctl_new failed\n";
          exit(2);
      }
      if (!remctl_open($r, 'server.example.com')) {
          echo "remctl_open failed: " . remctl_error($r) . "\n";
          exit(2);
      }
      $command = array('test', 'echo', 'hello world');
      if (!remctl_command($r, $command)) {
          echo "remctl_command failed: " . remctl_error($r) . "\n";
      }
      $output = remctl_output($r);
      while ($output != null && $output->type != "done") {
          switch($output->type) {
          case "output":
              if ($output->stream == 1) {
                  echo "stdout: $output->data";
              } elseif ($output->stream == 2) {
                  echo "stderr: $output->data";
              }
              break;
          case "error":
              echo "error: $output->error ($output->data)\n";
              break;
          case "status":
              echo "status: $output->status\n";
              break;
          default:
              echo "unknown output token type $output->type\n";
          }
          $output = remctl_output($r);
      }
      if ($output == null) {
          echo "remctl_output failed: " . remctl_error($r) . "\n";
          exit(2);
      }
      remctl_noop($r)
      remctl_close($r)

  As mentioned above, the final remctl_close() is normally not needed.

HISTORY

  This binding was originally written by Andrew Mortensen. part of the
  stock remctl distribution and ongoing maintenance is done by Russ
  Allbery.

LICENSE

  Copyright 2008, 2009, 2011, 2012 The Board of Trustees of the Leland
  Stanford Junior University

  Copying and distribution of this file, with or without modification,
  are permitted in any medium without royalty provided the copyright
  notice and this notice are preserved.  This file is offered as-is,
  without any warranty.
