[comp.unix.wizards] remote command execution & passwords

stevens@hsi.UUCP (Richard Stevens) (02/25/88)

I see three ways for an arbitrary C program to execute a program on
another system and communicate with it:

(1) Use rexec(3).  Doing this requires that the user's unencrypted
    password be explicitly passed to rexec.  This can be done
	(a) explicitly pass it as an argument to rexec;
	(b) have all users make a .netrc file that is read-only to
	    them, containing their unencrypted password;
	(c) have all users of the program prompted for their password
	    whenever they run the program.

(2) Use rcmd(3).  Using this obviates the need to communicate passwords
    between the two systems, however the program that calls rcmd
    must be suid to root (in order for rcmd to be able to get a
    privileged port).

(3) Use the rsh(1) command as follows.  Have the C program create
    2 pipes, then fork.  The child process then exec's /usr/ucb/rsh
    with the name of the program to execute on the other system as
    an argument to rsh.  The pipes from the parent process are used
    for rsh's stdin and stdout, and rsh communicates with the
    process on the other system through a socket (or two).
    The problem with this is that all the data being transferred
    between the two programs on the two systems (through the socket)
    must also go through a pipe through the rsh program that's in the
    middle.

It appears that if you don't want to live with the unencrypted password
restrictions of rexec, and don't want a lot of suid-root programs,
option (3) is all that's left.  Am I missing something ??

Another related question:
------------------------
While going through the source for rexec I found a function ruserpass()
that called a function renv() that did the following:  If you have an
environment variable of the form

	MACH<host>=<username>,<cpassword>

then if you're communicating with the specified <host>, it will set
the corresponding <username> as the argument to be passed to the
rexecd on the host.  Also, it takes the supposedly encrypted <cpassword>
and turns it into "clear text" by calling a function nbsdecrypt() that's
also in the file.  This clear text password is then passed to the rexecd
on the other host.  The comment at the top of this code is that it
is "nbs.c stolen from Berknet".  I can't find any reference to this
MACH... environment variable in any of the man pages, and can't
understand how it can claim to unencrypt a password.  Anyone know
what's going on here ??  Thanks.

	Richard Stevens
	Health Systems International, New Haven, CT
           { uunet | ihnp4 } ! hsi ! stevens

dave@onfcanim.UUCP (Dave Martindale) (03/11/88)

In article <860@hsi.UUCP> stevens@hsi.UUCP (Richard Stevens) writes:
>I see three ways for an arbitrary C program to execute a program on
>another system and communicate with it:
>
>(1) Use rexec(3).  Doing this requires that the user's unencrypted
>    password be explicitly passed to rexec.
>
>(2) Use rcmd(3).  Using this obviates the need to communicate passwords
>    between the two systems, however the program that calls rcmd
>    must be suid to root
>
>(3) Use the rsh(1) command as follows.  [ messy stuff ]

There is another way, and it's faster than all of the above, if the
thing you want to do on the other system is run a single server process,
and you control the other system.

The idea is that you create a new network "service" and publish it,
then let the appropriate server process know about it.

For example, I have a server that sits on our IRIS workstations that
allows writing scanlines to the screen, so our VAX can display pictures
though it has no frame buffer directly attached.

First, you add an entry to the /etc/services file:

	iris_slave	700/tcp			# to display on IRIS framebuffer

700 was picked because it wasn't near other already-defined services.
This allows getservbyname() to find the service number.

Then you inform the inetd about the new service and the server for it
by adding a line to /etc/inetd.conf (or /usr/etc/inetd.conf on the IRIS):

	iris_slave stream tcp	nowait	nobody	/usr/local/lib/iris_slave	iris_slave

Then you kill and restart the inetd on the IRIS (kill -1 doesn't work).

Then you call the code below to establish a connection from your current
machine to the slave process on the target machine.  Anything you write
to the network file descriptor can be read from the slave's standard
input, and its standard output can be read from the network file
descriptor in the master, though they need to agree on a protocol of
whose turn it is to write.

Calling method:

	if ((remfd = connect_slave(hostname, "iris_slave", "tcp")) < 0) {
		fprintf(stderr, "Can't connect to slave");
	}

Code for connect_slave:

/*
 + File:	connect_slave.c
 + Purpose:	Establish a network connection to a process on a remote
 +		machine, using the "known services" mechanism.
 +
 * Author:	Dave Martindale, National Film Board of Canada
 * Date:	03-Jan-88
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <errno.h>
#ifdef m68000
#include <bsd/netdb.h>
#else
#include <netdb.h>
#endif

connect_slave(host, service, protocol)
char *host;
char *service;
char * protocol;
{
	int			s;
	unsigned int		timo = 1;
	struct hostent		*hp;
	struct servent		*sp;
	struct sockaddr_in	sin;
	extern int		errno;

	hp = gethostbyname(host);
	if (hp == (struct hostent *)0) {
		fprintf(stderr, "%s: unknown host\n", host);
		return -1;
	}

	sp = getservbyname(service, protocol);
	if (sp == (struct servent *)0) {
		fprintf(stderr, "%s: unknown service\n", service);
		return -1;
	}

retry:
	s = socket(AF_INET, SOCK_STREAM, 0);
	if (s < 0) {
		perror("connect_slave: socket");
		return -1;
	}
	sin.sin_family = hp->h_addrtype;
	sin.sin_port = sp->s_port;
	bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
	if (connect(s, &sin, sizeof(sin)) < 0) {
		if (errno == ECONNREFUSED && timo <= 16) {
			(void) close(s);
			sleep(timo);
			timo *= 2;
			goto retry;
		}
		perror(hp->h_name);
		return -1;
	}
	return s;
}

jerry@oliveb.olivetti.com (Jerry Aguirre) (03/17/88)

In article <860@hsi.UUCP> stevens@hsi.UUCP (Richard Stevens) writes:
>While going through the source for rexec I found a function ruserpass()
>that called a function renv() that did the following:  If you have an
>environment variable of the form
>
>	MACH<host>=<username>,<cpassword>
>
>then if you're communicating with the specified <host>, it will set
>the corresponding <username> as the argument to be passed to the
>rexecd on the host.  Also, it takes the supposedly encrypted <cpassword>
>and turns it into "clear text" by calling a function nbsdecrypt() that's
>also in the file.  This clear text password is then passed to the rexecd
>on the other host.  The comment at the top of this code is that it
>is "nbs.c stolen from Berknet".  I can't find any reference to this
>MACH... environment variable in any of the man pages, and can't
>understand how it can claim to unencrypt a password.  Anyone know
>what's going on here ??  Thanks.

This was from the "berknet" package (a batched star topology using tty
lines).  A program was would prompt you for your password and then
output an encryped version that could be placed in the environment.  The
idea was that the environment was more secure, as well as having faster
access, than a disk file (.netrc).

The encryption used an obvious key, I think it was the users login tty
name and the remote machine name.  Thus a command could find out what
tty it was running on and use that to decrypt the password.  The
encryption didn't provide much real security as finding out someone
else's tty is quite simple.  It did provide limited protection against
someone accidently seeing a printenv or examining kmem.  The main
protection was having it in your environment.  (Doesn't ps have an
option to display the environment?)

If you have 4.2BSD check out /usr/src/ucb/berknet (I think that was
where it was).  In 4.3BSD it is in /usr/src/old/berknet.  The berknet
code had some nice user interfaces but internally it was a mess.  We ran
over 30 systems on "berknet" here until we got our ethernet going.  I
did bug fixes and tuning like adding a "raw" protocol to speed things
up.
				Jerry Aguirre