rcmd(3N)
NAME
rcmd(), rresvport(), ruserok() − return a stream to a remote command
SYNOPSIS
int rcmd(
char **ahost,
unsigned short inport,
const char *locuser,
const char *remuser,
const char *cmd,
int *fd2p);
int rresvport(int *port);
int ruserok(
const char *rhost,
int superuser,
const char *ruser,
const char *luser);
DESCRIPTION
rcmd() A routine used by privileged programs to execute cmd on the remote host *ahost using an authentication scheme based on reserved port numbers. rcmd() returns a file descriptor for the socket to which the standard input and standard output of cmd are attached. A command level interface to rcmd() is provided by remsh (see remsh(1)), which is the same command as BSD rsh.
rresvport() Returns a descriptor to a socket with an address in the privileged port space.
ruserok() Used by servers to authenticate clients requesting service with rcmd().
Any program using rcmd() or rresvport() must be run as super-user.
The name of the remote host can be either an official host name or an alias as understood by gethostbyname(); (see gethostent(3N), named(1M), and hosts(4)). rcmd() looks up the host *ahost using gethostbyname(), returning −1 if the host does not exist. Otherwise *ahost is set to the standard name of the host and a connection is established to a server residing at the Internet port inport. If the connection is refused after five tries, or if it was refused for a reason other than the port being in use, rcmd() returns −1.
If the call succeeds, a socket of type SOCK_STREAM is returned to the caller, and given to the remote command as stdin and stdout. If fd2p is non-zero, an auxiliary connection to a control process is set up, and a descriptor for it is placed in *fd2p. The control process returns diagnostic output from the command on this connection, and also accepts bytes on this connection as UNIX signal numbers, to be forwarded to the process group of the command. If the auxiliary port cannot be set up, rcmd() returns −1. If fd2p is 0, stderr of the remote command is made the same as stdout, and no provision is made for sending arbitrary signals to the remote process.
The protocol is described in detail by remshd(1M).
rresvport() is used to obtain a socket with a privileged address bound to it. This socket is suitable for use by rcmd() and several other routines. Privileged addresses consist of a port in the range 0 to 1023. Only the super-user is permitted to bind an address of this sort to a socket.
ruserok() verifies that ruser on rhost is authorized to act as luser on the local host. The superuser parameter to ruserok() is an integer flag that should be non-zero if the local user name corresponds to the super-user. If the superuser flag is not set, ruserok() first checks the file /etc/hosts.equiv to authenticate the request for service. If this check succeeds, ruserok() returns 0. If the superuser flag is set, or if there is no file /etc/hosts.equiv, or if the check fails, ruserok() then checks a file .rhosts (if there is one) in the local user’s home directory. ruserok() returns 0 if this check succeeds. Otherwise it returns −1.
Typically, the file /etc/hosts.equiv contains a list of host names, and users’ .rhosts files contain host-name/user-name pairs. A remote user is authenticated by ruserok() if the remote host name appears in /etc/hosts.equiv and the remote user name and local user name are the same, or if the remote host name and the remote user name appear together in .rhosts in the home directory of the local user.
For a complete explanation of the syntax understood by ruserok(), see hosts.equiv(4).
DIAGNOSTICS
rcmd Diagnostic Messages
rcmd() returns the following diagnostic messages:
hostname: Unknown host
gethostbyname was unable to find an entry in the hosts database matching the name of the server (see gethostent(3N) and hosts(4)).
Next step: Have the system administrator of your host check whether the remote host’s entry is in the hosts database (see hosts(4)).
connect: hostname: ...
Unable to establish a connection to the reserved port. A message that specifies the reason for the failure is appended to this diagnostic message.
write: Setting up stderr
Error writing to the socket connection set up for error message transmission.
system call: ...
Error executing the system call. Appended to this error is a message specifying the reason for the failure.
socket: Protocol failure in circuit setup
Socket connection not established on a reserved port or socket address not of the Internet family type.
read: hostname: ...
Error in reading information from the standard socket connection. Appended to this error is a message explaining the reason for the error.
Connection timeout
The remote host did not connect within 30 seconds to the secondary socket set up as an error connection.
Lost connection
The program attempted to read from the socket and failed. This means the socket connection with the remote host was lost.
message...
An error message can be transmitted through the socket connection from the daemon. That message will be sent to stderr.
primary connection shutdown
While waiting for the secondary socket to be set up, rcmd() had its primary connection shut down. This may have been caused by an inetd security failure.
recv: ...
While trying to set up the secondary (stderr) socket, rcmd() had an error condition on its primary connection.
accept: Interrupted system call
While trying to set up its secondary socket, rcmd() ran out of some resource that caused the accept to be timed out.
Next step: Repeat the command.
rcmd and rresvport Diagnostic Messages
The diagnostic messages associated with rresvport() can also appear in rcmd() since rcmd() calls rresvport():
system call:...
Error in executing the system call. The error message returned by the system call is appended to the message.
socket: All ports in use
All reserved ports in use. If a timeout occurs, check whether the ARPA Services are installed and inetd is running.
EXAMPLES
To execute the date command on remote host hpxzgy using the remote account chm, use rcmd() as shown below. This program requires super-user privileges, and the remote account must be equivalent (see hosts.equiv(4)) to the local account that runs the program.
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <pwd.h>
struct passwd *getpwuid();
char *host[] = { "hpxzgy" };
char *cmd = "date";
char *ruser = "chm";
main(argc,argv)
int argc;
char **argv;
{
struct servent *sp;
struct passwd *pwd;
FILE *fp;
char ch;
int rem;
sp = getservbyname("shell","tcp");
pwd = getpwuid(getuid());
rem = rcmd(host, sp−>s_port, pwd−>pw_name, ruser, cmd, 0);
if (rem < 0)
exit(1); /* rcmd outputs its own error messages */
fp = fdopen(rem, "r");
while ((ch = getc(fp)) != EOF)
putchar(ch);
}
WARNINGS
There is no way to specify options to the socket() call that rcmd() makes. Since rcmd() replaces the pointer to the hostname (∗ahost) with a pointer to the standard name of the host in a static data area, this value must be copied into the user’s data area if it is to be used later. Otherwise unpredictable results will occur.
AUTHOR
rcmd() was developed by the University of California, Berkeley.
SEE ALSO
login(1), rlogin(1), remsh(1), named(1M), remshd(1M), rexecd(1M), gethostent(3N), rexec(3N), hosts.equiv(4).
Hewlett-Packard Company — HP-UX Release 9.0: August 1992