remctl allows me to remotely invoke a program (with arguments) and retrieve output (stdout and stderr) of said program, together with its exit status. Program invocation is authenticated and encrypted by GSS-API Kerberos 5.
Using the remctl client program, I might invoke the following command on a client machine, provided I have a valid Kerberos ticket:
remctl hippo who boot
and remctld (started on the specified server via inetd or as a daemon) will execute the following command:
/usr/local/bin/mywho boot
if the server’s remctl.conf
configuration file contains
server reboot /bin/reboot princ:f2@MENS.DE
who ALL /usr/local/bin/mywho ANYUSER
There are two magic tokens in the previous configuration line:
ALL
stands for all subcommands. Remctld supports the notion of subclassing a command and I can apply different ACLs to specific subcommands. In this particular case I leave that to the program.ANYUSER
in the ACL specifies that any principal may invoke this particular program/subcommand pair.
I launch remctl via xinetd thusly:
service remctl
{
socket_type = stream
disable = no
protocol = tcp
wait = no
user = root
server = /usr/sbin/remctld
port = 4373
}
The trivial mywho
script supports three “subcommands” (in remctld-speak):
#!/bin/sh
case "$1" in
users)
/usr/bin/who -u;;
boot)
/usr/bin/who -b;;
ami)
env | grep REMOTE;;
*) echo "Unknown subcommand $*" >&2;
exit 14;;
esac
exit 0
The program is invoked on the server (under remctld’s control) as the user remctld is
running as (typically root
). Reminiscent of HTTP CGI scripts, it gets these
environment variables passed to it:
REMOTE_USER
: the Kerberos identity of the caller.REMOTE_ADDR
: the IP address of the client host.REMOTE_HOST
: the name of the client host.
I can configure remctld to allow program invocation for particular principals
only, or I can (as in the example above) allow ANY user and use the $REMOTE_USER
to decide whether that principal may use the accounts program.
remctl is like a lightweight rsh or ssh and can be used for a number of purposes, such as
- Monitoring (think: fetch Nagios results)
- Service provisioning; for example, I could securely invoke an on-demand Puppet run on a machine.
- Centralized account creation (c.f. kadmin-remctl, a remctl back-end which implements
Kerberos account administration with the same functionality as
kadmin
) - Remote system-administration (e.g. reboot)
- Or even just checking for new mail. :)
remctl has bindings for C, Perl, PHP, Java and Python. Here’s a tiny example in C:
#include <stdio.h>
#include <stdlib.h>
#include <remctl.h>
int main(int argc, char **argv)
{
struct remctl_result *remc;
static const char *cmd[] = {
"who",
"ami",
NULL
};
int rc;
remc = remctl("hippo.ww.mens.de", 0, NULL, cmd);
if (remc == NULL) {
fprintf(stderr, "%s: Can't alloc remctl()\n", *argv);
exit(1);
}
if (remc->error != NULL) {
fprintf(stderr, "%s: remctl says: %s\n", *argv, remc->error);
exit(1);
}
/* Success? */
rc = remc->status;
if (remc->stdout_len > 0) {
fwrite(remc->stdout_buf, remc->stdout_len, 1, stdout);
}
if (remc->stderr_len > 0) {
fwrite(remc->stderr_buf, remc->stderr_len, 1, stderr);
}
remctl_result_free(remc);
return (rc);
}
When I run this, the output for my principal is:
REMOTE_HOST=jmbp.ww.mens.de
REMOTE_USER=jpm@MENS.DE
REMOTE_ADDR=192.168.1.145