1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
|
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.
|