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