Path: utzoo!mnetor!uunet!husc6!mailrus!umix!umich!mibte!gamma!ulysses!thumper!faline!bellcore!clyde!watmath!onfcanim!dave From: dave@onfcanim.UUCP (Dave Martindale) Newsgroups: comp.unix.wizards Subject: Re: remote command execution & passwords Message-ID: <15577@onfcanim.UUCP> Date: 11 Mar 88 06:49:37 GMT References: <860@hsi.UUCP> Reply-To: dave@onfcanim.UUCP (Dave Martindale) Organization: National Film Board / Office national du film, Montreal Lines: 118 Keywords: rcmd, rexec, crypt 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 #include #include #include #include #ifdef m68000 #include #else #include #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; }