1 | # Net::Remctl -- Perl bindings for the remctl client library. |
---|
2 | # |
---|
3 | # This is the Perl boostrap file for the Net::Remctl module, nearly all of |
---|
4 | # which is implemented in XS. For the actual source, see Remctl.xs. This |
---|
5 | # file contains the bootstrap and export code and the documentation. |
---|
6 | # |
---|
7 | # Written by Russ Allbery <rra@stanford.edu> |
---|
8 | # Copyright 2007, 2008 Board of Trustees, Leland Stanford Jr. University |
---|
9 | # |
---|
10 | # See LICENSE for licensing terms. |
---|
11 | |
---|
12 | package Net::Remctl; |
---|
13 | |
---|
14 | use 5.006; |
---|
15 | use strict; |
---|
16 | use warnings; |
---|
17 | |
---|
18 | our $VERSION = '@PACKAGE_VERSION@'; |
---|
19 | |
---|
20 | require Exporter; |
---|
21 | require DynaLoader; |
---|
22 | |
---|
23 | our @ISA = qw(Exporter DynaLoader); |
---|
24 | our @EXPORT = qw(remctl); |
---|
25 | |
---|
26 | bootstrap Net::Remctl; |
---|
27 | 1; |
---|
28 | |
---|
29 | =head1 NAME |
---|
30 | |
---|
31 | Net::Remctl - Perl bindings for remctl (Kerberos remote command execution) |
---|
32 | |
---|
33 | =head1 SYNOPSIS |
---|
34 | |
---|
35 | # Simplified form. |
---|
36 | use Net::Remctl; |
---|
37 | my $result = remctl("hostname", undef, undef, "test", "echo", "Hi"); |
---|
38 | if ($result->error) { |
---|
39 | die "test echo failed with error ", $result->error, "\n"; |
---|
40 | } else { |
---|
41 | warn $result->stderr; |
---|
42 | print $result->stdout; |
---|
43 | exit $result->status; |
---|
44 | } |
---|
45 | |
---|
46 | # Full interface. |
---|
47 | use Net::Remctl (); |
---|
48 | my $remctl = Net::Remctl->new; |
---|
49 | $remctl->open("hostname") |
---|
50 | or die "Cannot connect to hostname: ", $remctl->error, "\n"; |
---|
51 | $remctl->command("test", "echo", "Hi there") |
---|
52 | or die "Cannot send command: ", $remctl->error, "\n"; |
---|
53 | my $output; |
---|
54 | do { |
---|
55 | $output = $remctl->output; |
---|
56 | if ($output->type eq 'output') { |
---|
57 | if ($output->stream == 1) { |
---|
58 | print $output->data; |
---|
59 | } elsif ($output->stream == 2) { |
---|
60 | warn $output->data; |
---|
61 | } |
---|
62 | } elsif ($output->type eq 'error') { |
---|
63 | warn $output->error, "\n"; |
---|
64 | } elsif ($output->type eq 'status') { |
---|
65 | exit $output->status; |
---|
66 | } else { |
---|
67 | die "Unknown output token from library: ", $output->type, "\n"; |
---|
68 | } |
---|
69 | } while ($output->type eq 'output'); |
---|
70 | |
---|
71 | =head1 DESCRIPTION |
---|
72 | |
---|
73 | Net::Remctl provides Perl bindings to the libremctl client library. remctl |
---|
74 | is a protocol for remote command execution using GSS-API authentication. |
---|
75 | The specific allowable commands must be listed in a configuration file on |
---|
76 | the remote system and the remote system can map the remctl command names to |
---|
77 | any local command without exposing that mapping to the client. This module |
---|
78 | implements a remctl client. |
---|
79 | |
---|
80 | =head2 Simplified Interface |
---|
81 | |
---|
82 | If you want to run a single command on a remote system and get back the |
---|
83 | output and exit status, you can use the exported remctl() function: |
---|
84 | |
---|
85 | =over 4 |
---|
86 | |
---|
87 | =item remctl(HOSTNAME, PORT, PRINCIPAL, COMMAND, [ARGS, ...]) |
---|
88 | |
---|
89 | Runs a command on the remote system and returns a Net::Remctl::Result |
---|
90 | object (see below). HOSTNAME is the remote host to contact. PORT is the |
---|
91 | port of the remote B<remctld> server and may be 0 to tell the library to |
---|
92 | use the default (first try 4373, the registered remctl port, and fall back |
---|
93 | to the legacy 4444 port if that fails). PRINCIPAL is the principal of the |
---|
94 | server to use for authentication; pass in the empty string to use the |
---|
95 | default of host/HOSTNAME, with the realm determined by domain-realm |
---|
96 | mapping. The remaining arguments are the remctl command and arguments |
---|
97 | passed to the remote server. |
---|
98 | |
---|
99 | As far as the module is concerned, undef may be passed as PORT and |
---|
100 | PRINCIPAL and is the same as 0 and the empty string respectively. |
---|
101 | However, Perl will warn about passing undef explicitly as a function |
---|
102 | argument. |
---|
103 | |
---|
104 | The return value is a Net::Remctl::Result object which supports the |
---|
105 | following methods: |
---|
106 | |
---|
107 | =over 4 |
---|
108 | |
---|
109 | =item error() |
---|
110 | |
---|
111 | Returns the error message from either the remote host or from the local |
---|
112 | client library (if, for instance, contacting the remote host failed). |
---|
113 | Returns undef if there was no error. Checking whether error() returns undef |
---|
114 | is the supported way of determining whether the remctl() call succeeded. |
---|
115 | |
---|
116 | =item stdout() |
---|
117 | |
---|
118 | Returns the command's standard output or undef if there was none. |
---|
119 | |
---|
120 | =item stderr() |
---|
121 | |
---|
122 | Returns the command's standard error or undef if there was none. |
---|
123 | |
---|
124 | =item status() |
---|
125 | |
---|
126 | Returns the command's exit status. |
---|
127 | |
---|
128 | =back |
---|
129 | |
---|
130 | Each call to remctl() will open a new connection to the remote host and |
---|
131 | close it after retrieving the results of the command. To maintain a |
---|
132 | persistant connection, use the full interface described below. |
---|
133 | |
---|
134 | =back |
---|
135 | |
---|
136 | =head2 Full Interface |
---|
137 | |
---|
138 | The full remctl library interface requires that the user do more |
---|
139 | bookkeeping, but it provides more flexibility and allows one to issue |
---|
140 | multiple commands on the same persistent connection (provided that the |
---|
141 | remote server supports protocol version two; if not, the library will |
---|
142 | transparently fall back to opening a new connection for each command). |
---|
143 | |
---|
144 | To use the full interface, first create a Net::Remctl object with new() and |
---|
145 | then connect() to a remote server. Then, issue a command() and call |
---|
146 | output() to retrieve output tokens (as Net::Remctl::Output objects) until a |
---|
147 | status token is received. Destroying the Net::Remctl object will close the |
---|
148 | connection. |
---|
149 | |
---|
150 | The supported object methods are: |
---|
151 | |
---|
152 | =over 4 |
---|
153 | |
---|
154 | =item new() |
---|
155 | |
---|
156 | Create a new Net::Remctl object. This doesn't attempt to connect to a host |
---|
157 | and hence will only fail (by throwing an exception) if the library cannot |
---|
158 | allocate memory. |
---|
159 | |
---|
160 | =item error() |
---|
161 | |
---|
162 | Retrieves the error message from the last failing operation and returns it |
---|
163 | as a string. |
---|
164 | |
---|
165 | =item open(HOSTNAME[, PORT[, PRINCIPAL]]) |
---|
166 | |
---|
167 | Connect to HOSTNAME on port PORT using PRINCIPAL as the remote server's |
---|
168 | principal for authentication. If PORT is omitted or 0, use the default |
---|
169 | (first try 4373, the registered remctl port, and fall back to the legacy |
---|
170 | 4444 port if that fails). If PRINCIPAL is omitted or the empty string, |
---|
171 | use the default of host/HOSTNAME, with the realm determined by |
---|
172 | domain-realm mapping. Returns true on success, false on failure. On |
---|
173 | failure, call error() to get the failure message. |
---|
174 | |
---|
175 | As far as the module is concerned, undef may be passed as PORT and |
---|
176 | PRINCIPAL and is the same as 0 and the empty string respectively. |
---|
177 | However, Perl will warn about passing undef explicitly as a function |
---|
178 | argument. |
---|
179 | |
---|
180 | =item command(COMMAND[, ARGS, ...]) |
---|
181 | |
---|
182 | Send the command and arguments to the remote host. The command and the |
---|
183 | arguments may, under the remctl protocol, contain any character, but be |
---|
184 | aware that most remctl servers will reject commands or arguments containing |
---|
185 | ASCII 0 (NUL), so currently this cannot be used for upload of arbitrary |
---|
186 | unencoded binary data. Returns true on success (meaning success in sending |
---|
187 | the command, and implying nothing about the result of the command), false on |
---|
188 | failure. On failure, call error() to get the failure message. |
---|
189 | |
---|
190 | =item output() |
---|
191 | |
---|
192 | Returns the next output token from the remote host. The token is returned |
---|
193 | as a Net::Remctl::Output object, which supports the following methods: |
---|
194 | |
---|
195 | =over 4 |
---|
196 | |
---|
197 | =item type() |
---|
198 | |
---|
199 | Returns the type of the output token, which will be one of C<output>, |
---|
200 | C<error>, C<status>, or C<done>. A command will result in either one |
---|
201 | C<error> token or zero or more C<output> tokens followed by a C<status> |
---|
202 | token. After either a C<error> or C<status> token is seen, another command |
---|
203 | can be issued. If the caller tries to retrieve another output token when it |
---|
204 | has already consumed all of them for that command, the library will return a |
---|
205 | C<done> token. |
---|
206 | |
---|
207 | =item data() |
---|
208 | |
---|
209 | Returns the contents of the token. This method only makes sense for |
---|
210 | C<output> and C<error> tokens; otherwise, it will return undef. Note that |
---|
211 | the returned value may contain any character, including ASCII 0 (NUL). |
---|
212 | |
---|
213 | =item length() |
---|
214 | |
---|
215 | Returns the length of the data in the token. As with data(), this method |
---|
216 | only makes sense for the C<output> and C<error> tokens. It will return 0 if |
---|
217 | there is no data or if the data is zero-length. |
---|
218 | |
---|
219 | =item stream() |
---|
220 | |
---|
221 | For an C<output> token, returns the stream with which the data is |
---|
222 | associated. Currently, only two stream values will be used: 1, meaning |
---|
223 | standard output; and 2, meaning standard error. The value is undefined for |
---|
224 | all other output token types. |
---|
225 | |
---|
226 | =item status() |
---|
227 | |
---|
228 | For a C<status> token, returns the exit status of the remote command. The |
---|
229 | value is undefined for all other token types. |
---|
230 | |
---|
231 | =item error() |
---|
232 | |
---|
233 | For an C<error> token, returns the remctl error code for the protocol |
---|
234 | error. The text message will be returned by data(). The value is undefined |
---|
235 | for all other token types. |
---|
236 | |
---|
237 | =back |
---|
238 | |
---|
239 | =back |
---|
240 | |
---|
241 | Note that, due to internal implementation details in the library, the |
---|
242 | Net::Remctl::Output object returned by output() will be invalidated by the |
---|
243 | next call to command() or output() or by destroying the producing |
---|
244 | Net::Remctl object. Therefore, any data in the output token should be |
---|
245 | processed and stored if needed before making any further Net::Remctl method |
---|
246 | calls on the same object. |
---|
247 | |
---|
248 | =head1 CAVEATS |
---|
249 | |
---|
250 | If the I<principal> argument to remctl() or remctl_open() is NULL, most |
---|
251 | GSS-API libraries will canonicalize the I<host> using DNS before deriving |
---|
252 | the principal name from it. This means that when connecting to a remctl |
---|
253 | server via a CNAME, remctl() and remctl_open() will normally authenticate |
---|
254 | using a principal based on the canonical name of the host instead of the |
---|
255 | specified I<host> parameter. This behavior may cause problems if two |
---|
256 | consecutive DNS lookups of I<host> may return two different results, such |
---|
257 | as with some DNS-based load-balancing systems. |
---|
258 | |
---|
259 | The canonicalization behavior is controlled by the GSS-API library; with |
---|
260 | the MIT Kerberos GSS-API library, canonicalization can be disabled by |
---|
261 | setting C<rdns> to false in the [libdefaults] section of F<krb5.conf>. It |
---|
262 | can also be disabled by passing an explicit Kerberos principal name via |
---|
263 | the I<principal> argument, which will then be used without changes. If |
---|
264 | canonicalization is desired, the caller may wish to canonicalizae I<host> |
---|
265 | before calling remctl() or remctl_open() to avoid problems with multiple |
---|
266 | DNS calls returning different results. |
---|
267 | |
---|
268 | The default behavior, when the port is not specified, of trying 4373 and |
---|
269 | falling back to 4444 will be removed in a future version of this module in |
---|
270 | favor of using the C<remctl> service in F</etc/services> if set and then |
---|
271 | falling back on only 4373. 4444 was the poorly-chosen original remctl |
---|
272 | port and should be phased out. |
---|
273 | |
---|
274 | =head1 NOTES |
---|
275 | |
---|
276 | The remctl port number, 4373, was derived by tracing the diagonals of a |
---|
277 | QWERTY keyboard up from the letters C<remc> to the number row. |
---|
278 | |
---|
279 | =head1 SEE ALSO |
---|
280 | |
---|
281 | remctl(1), remctld(8) |
---|
282 | |
---|
283 | The current version of this module is available from its web page at |
---|
284 | L<http://www.eyrie.org/~eagle/software/remctl/>. |
---|
285 | |
---|
286 | =head1 AUTHOR |
---|
287 | |
---|
288 | Russ Allbery <rra@stanford.edu> |
---|
289 | |
---|
290 | =head1 COPYRIGHT AND LICENSE |
---|
291 | |
---|
292 | Copyright 2007, 2008 Board of Trustees, Leland Stanford Jr. University. All |
---|
293 | rights reserved. |
---|
294 | |
---|
295 | Permission to use, copy, modify, and distribute this software and its |
---|
296 | documentation for any purpose and without fee is hereby granted, provided |
---|
297 | that the above copyright notice appear in all copies and that both that |
---|
298 | copyright notice and this permission notice appear in supporting |
---|
299 | documentation, and that the name of Stanford University not be used in |
---|
300 | advertising or publicity pertaining to distribution of the software without |
---|
301 | specific, written prior permission. Stanford University makes no |
---|
302 | representations about the suitability of this software for any purpose. It |
---|
303 | is provided "as is" without express or implied warranty. |
---|
304 | |
---|
305 | THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED |
---|
306 | WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF |
---|
307 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
---|
308 | |
---|
309 | =cut |
---|