xref: /openbsd-src/gnu/usr.bin/cvs/windows-NT/rcmd.c (revision 2286d8ed900f26153a3cd5227a124b1c0adce72f)
11e72d8d2Sderaadt /* rcmd.c --- execute a command on a remote host from Windows NT
22770ece5Stholo 
32770ece5Stholo    This program is free software; you can redistribute it and/or modify
42770ece5Stholo    it under the terms of the GNU General Public License as published by
52770ece5Stholo    the Free Software Foundation; either version 2, or (at your option)
62770ece5Stholo    any later version.
72770ece5Stholo 
82770ece5Stholo    This program is distributed in the hope that it will be useful,
92770ece5Stholo    but WITHOUT ANY WARRANTY; without even the implied warranty of
102770ece5Stholo    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
112770ece5Stholo    GNU General Public License for more details.
122770ece5Stholo 
131e72d8d2Sderaadt    Jim Blandy <jimb@cyclic.com> --- August 1995  */
141e72d8d2Sderaadt 
15*2286d8edStholo #include "cvs.h"
16*2286d8edStholo #include "rcmd.h"
17*2286d8edStholo 
181e72d8d2Sderaadt #include <io.h>
191e72d8d2Sderaadt #include <fcntl.h>
201e72d8d2Sderaadt #include <malloc.h>
211e72d8d2Sderaadt #include <errno.h>
222770ece5Stholo 
232770ece5Stholo #ifdef HAVE_WINSOCK_H
241e72d8d2Sderaadt   #include <winsock.h>
252770ece5Stholo #else
262770ece5Stholo   #include <sys/types.h>
272770ece5Stholo   #include <sys/socket.h>
282770ece5Stholo   #include <netinet/in.h>
292770ece5Stholo   #include <netdb.h>
302770ece5Stholo   typedef int SOCKET;
312770ece5Stholo   #define closesocket close
322770ece5Stholo   #define SOCK_ERRNO errno
332770ece5Stholo   #define SOCK_STRERROR strerror
342770ece5Stholo   /* Probably would be cleaner to just use EADDRINUSE, as NT has that too.  */
352770ece5Stholo   #define WSAEADDRINUSE EADDRINUSE
362770ece5Stholo   /* Probably would be cleaner to just check for < 0.  Might want to
372770ece5Stholo      double-check that doing so would seem to work on NT.  */
382770ece5Stholo   #define SOCKET_ERROR -1
392770ece5Stholo   #define INVALID_SOCKET -1
402770ece5Stholo #endif
412770ece5Stholo 
4213571821Stholo #include <stdio.h>
431e72d8d2Sderaadt #include <assert.h>
441e72d8d2Sderaadt 
45b6c02222Stholo /* The rest of this file contains the rcmd() code, which is used
46b6c02222Stholo    only by START_SERVER.  The idea for a long-term direction is
47b6c02222Stholo    that this code can be made portable (by using SOCK_ERRNO and
48b6c02222Stholo    so on), and then moved to client.c or someplace it can be
49b6c02222Stholo    shared with the VMS port and any other ports which may want it.  */
50b6c02222Stholo 
511e72d8d2Sderaadt 
521e72d8d2Sderaadt static int
resolve_address(const char ** ahost,struct sockaddr_in * sai)531e72d8d2Sderaadt resolve_address (const char **ahost, struct sockaddr_in *sai)
541e72d8d2Sderaadt {
551e72d8d2Sderaadt     {
561e72d8d2Sderaadt 	unsigned long addr = inet_addr (*ahost);
571e72d8d2Sderaadt 
581e72d8d2Sderaadt 	if (addr != (unsigned long) -1)
591e72d8d2Sderaadt 	{
601e72d8d2Sderaadt 	    sai->sin_family = AF_INET;
611e72d8d2Sderaadt 	    sai->sin_addr.s_addr = addr;
621e72d8d2Sderaadt 	    return 0;
631e72d8d2Sderaadt 	}
641e72d8d2Sderaadt     }
651e72d8d2Sderaadt 
661e72d8d2Sderaadt     {
671e72d8d2Sderaadt         struct hostent *e = gethostbyname (*ahost);
681e72d8d2Sderaadt 
691e72d8d2Sderaadt 	if (e)
701e72d8d2Sderaadt 	{
711e72d8d2Sderaadt 	    assert (e->h_addrtype == AF_INET);
721e72d8d2Sderaadt 	    assert (e->h_addr);
731e72d8d2Sderaadt 	    *ahost = e->h_name;
741e72d8d2Sderaadt 	    sai->sin_family = AF_INET;
751e72d8d2Sderaadt 	    memcpy (&sai->sin_addr, e->h_addr, sizeof (sai->sin_addr));
761e72d8d2Sderaadt 	    return 0;
771e72d8d2Sderaadt 	}
781e72d8d2Sderaadt     }
791e72d8d2Sderaadt 
80b6c02222Stholo     error (1, 0, "no such host %s", *ahost);
812770ece5Stholo     /* Shut up gcc -Wall.  */
822770ece5Stholo     return 1;
831e72d8d2Sderaadt }
841e72d8d2Sderaadt 
851e72d8d2Sderaadt static SOCKET
bind_and_connect(struct sockaddr_in * server_sai)861e72d8d2Sderaadt bind_and_connect (struct sockaddr_in *server_sai)
871e72d8d2Sderaadt {
881e72d8d2Sderaadt     SOCKET s;
891e72d8d2Sderaadt     struct sockaddr_in client_sai;
901e72d8d2Sderaadt     u_short client_port;
911e72d8d2Sderaadt 
921e72d8d2Sderaadt     client_sai.sin_family = AF_INET;
931e72d8d2Sderaadt     client_sai.sin_addr.s_addr = htonl (INADDR_ANY);
941e72d8d2Sderaadt 
951e72d8d2Sderaadt     for (client_port = IPPORT_RESERVED - 1;
961e72d8d2Sderaadt          client_port >= IPPORT_RESERVED/2;
971e72d8d2Sderaadt          client_port--)
981e72d8d2Sderaadt     {
99b6c02222Stholo 	int result, errcode;
1001e72d8d2Sderaadt 	client_sai.sin_port = htons (client_port);
1011e72d8d2Sderaadt 
1021e72d8d2Sderaadt         if ((s = socket (PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
103b6c02222Stholo 	    error (1, 0, "cannot create socket: %s",
104b6c02222Stholo 		   SOCK_STRERROR (SOCK_ERRNO));
1051e72d8d2Sderaadt 
1061e72d8d2Sderaadt 	result = bind (s, (struct sockaddr *) &client_sai,
1071e72d8d2Sderaadt 	               sizeof (client_sai));
108b6c02222Stholo 	errcode = SOCK_ERRNO;
1091e72d8d2Sderaadt 	if (result == SOCKET_ERROR)
1101e72d8d2Sderaadt 	{
1111e72d8d2Sderaadt 	    closesocket (s);
112b6c02222Stholo 	    if (errcode == WSAEADDRINUSE)
1131e72d8d2Sderaadt 		continue;
1141e72d8d2Sderaadt 	    else
115b6c02222Stholo 		error (1, 0, "cannot bind to socket: %s",
116b6c02222Stholo 		       SOCK_STRERROR (errcode));
1171e72d8d2Sderaadt 	}
1181e72d8d2Sderaadt 
1191e72d8d2Sderaadt 	result = connect (s, (struct sockaddr *) server_sai,
1201e72d8d2Sderaadt 	                  sizeof (*server_sai));
121b6c02222Stholo 	errcode = SOCK_ERRNO;
1221e72d8d2Sderaadt 	if (result == SOCKET_ERROR)
1231e72d8d2Sderaadt 	{
1241e72d8d2Sderaadt 	    closesocket (s);
125b6c02222Stholo 	    if (errcode == WSAEADDRINUSE)
1261e72d8d2Sderaadt 		continue;
1271e72d8d2Sderaadt 	    else
128b6c02222Stholo 		error (1, 0, "cannot connect to socket: %s",
129b6c02222Stholo 		       SOCK_STRERROR (errcode));
1301e72d8d2Sderaadt 	}
1311e72d8d2Sderaadt 
1321e72d8d2Sderaadt 	return s;
1331e72d8d2Sderaadt     }
1341e72d8d2Sderaadt 
135b6c02222Stholo     error (1, 0, "cannot find free port");
1362770ece5Stholo     /* Shut up gcc -Wall.  */
1372770ece5Stholo 	return s;
1381e72d8d2Sderaadt }
1391e72d8d2Sderaadt 
1401e72d8d2Sderaadt static int
rcmd_authenticate(int fd,char * locuser,char * remuser,char * command)1411e72d8d2Sderaadt rcmd_authenticate (int fd, char *locuser, char *remuser, char *command)
1421e72d8d2Sderaadt {
1431e72d8d2Sderaadt     /* Send them a bunch of information, each terminated by '\0':
1441e72d8d2Sderaadt        - secondary stream port number (we don't use this)
1451e72d8d2Sderaadt        - username on local machine
1461e72d8d2Sderaadt        - username on server machine
1471e72d8d2Sderaadt        - command
1481e72d8d2Sderaadt        Now, the Ultrix man page says you transmit the username on the
1491e72d8d2Sderaadt        server first, but that doesn't seem to work.  Transmitting the
1501e72d8d2Sderaadt        client username first does.  Go figure.  The Linux man pages
1511e72d8d2Sderaadt        get it right --- hee hee.  */
15250bf276cStholo     if ((send (fd, "0\0", 2, 0) == SOCKET_ERROR)
15350bf276cStholo 	|| (send (fd, locuser, strlen (locuser) + 1, 0) == SOCKET_ERROR)
15450bf276cStholo 	|| (send (fd, remuser, strlen (remuser) + 1, 0) == SOCKET_ERROR)
15550bf276cStholo 	|| (send (fd, command, strlen (command) + 1, 0) == SOCKET_ERROR))
156b6c02222Stholo 	error (1, 0, "cannot send authentication info to rshd: %s",
157b6c02222Stholo 	       SOCK_STRERROR (SOCK_ERRNO));
1581e72d8d2Sderaadt 
1591e72d8d2Sderaadt     /* They sniff our butt, and send us a '\0' character if they
1601e72d8d2Sderaadt        like us.  */
1611e72d8d2Sderaadt     {
1621e72d8d2Sderaadt         char c;
163b6c02222Stholo 	if (recv (fd, &c, 1, 0) == SOCKET_ERROR)
1641e72d8d2Sderaadt 	{
165b6c02222Stholo 	    error (1, 0, "cannot receive authentication info from rshd: %s",
166b6c02222Stholo 		   SOCK_STRERROR (SOCK_ERRNO));
167b6c02222Stholo 	}
168b6c02222Stholo 	if (c != '\0')
169b6c02222Stholo 	{
170*2286d8edStholo 	    /* All the junk with USER, LOGNAME, GetUserName, &c, is so
171*2286d8edStholo 	       confusing that we better give some clue as to what sort
172*2286d8edStholo 	       of user name we decided on.  */
173*2286d8edStholo 	    error (0, 0, "cannot log in as local user '%s', remote user '%s'",
174*2286d8edStholo 		   locuser, remuser);
175b6c02222Stholo 	    error (1, 0, "Permission denied by rshd");
1761e72d8d2Sderaadt 	}
1771e72d8d2Sderaadt     }
1781e72d8d2Sderaadt 
1791e72d8d2Sderaadt     return 0;
1801e72d8d2Sderaadt }
1811e72d8d2Sderaadt 
1821e72d8d2Sderaadt int
rcmd(const char ** ahost,unsigned short inport,char * locuser,char * remuser,char * cmd,int * fd2p)1831e72d8d2Sderaadt rcmd (const char **ahost,
1841e72d8d2Sderaadt       unsigned short inport,
1851e72d8d2Sderaadt       char *locuser,
1861e72d8d2Sderaadt       char *remuser,
1871e72d8d2Sderaadt       char *cmd,
1881e72d8d2Sderaadt       int *fd2p)
1891e72d8d2Sderaadt {
1901e72d8d2Sderaadt     struct sockaddr_in sai;
1911e72d8d2Sderaadt     SOCKET s;
1921e72d8d2Sderaadt 
1931e72d8d2Sderaadt     assert (fd2p == 0);
1941e72d8d2Sderaadt 
1951e72d8d2Sderaadt     if (resolve_address (ahost, &sai) < 0)
196b6c02222Stholo         error (1, 0, "internal error: resolve_address < 0");
1971e72d8d2Sderaadt 
1981e72d8d2Sderaadt     sai.sin_port = htons (inport);
1991e72d8d2Sderaadt 
2001e72d8d2Sderaadt     if ((s = bind_and_connect (&sai)) == INVALID_SOCKET)
201b6c02222Stholo 	error (1, 0, "internal error: bind_and_connect < 0");
2021e72d8d2Sderaadt 
20350bf276cStholo     if (rcmd_authenticate (s, locuser, remuser, cmd) < 0)
204b6c02222Stholo 	error (1, 0, "internal error: rcmd_authenticate < 0");
2051e72d8d2Sderaadt 
20650bf276cStholo     return s;
2071e72d8d2Sderaadt }
208