home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / cvs-1.8.7-src.tgz / tar.out / fsf / cvs / windows-NT / rcmd.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  5KB  |  220 lines

  1. /* rcmd.c --- execute a command on a remote host from Windows NT
  2.    Jim Blandy <jimb@cyclic.com> --- August 1995  */
  3.  
  4. #include <io.h>
  5. #include <fcntl.h>
  6. #include <malloc.h>
  7. #include <errno.h>
  8. #include <winsock.h>
  9. #include <stdio.h>
  10. #include <assert.h>
  11.  
  12. #include "rcmd.h"
  13.  
  14. void
  15. init_winsock ()
  16. {
  17.     WSADATA data;
  18.     int optionValue = SO_SYNCHRONOUS_NONALERT;
  19.  
  20.     if (WSAStartup (MAKEWORD (1, 1), &data))
  21.     {
  22.       fprintf (stderr, "cvs: unable to initialize winsock\n");
  23.       exit (1);
  24.     }
  25.  
  26.      if (setsockopt(INVALID_SOCKET, SOL_SOCKET,
  27.                     SO_OPENTYPE, (char *)&optionValue, sizeof(optionValue))
  28.          == SOCKET_ERROR)
  29.      {
  30.          fprintf (stderr, "cvs: unable to setup winsock\n");
  31.          exit (1);
  32.      }
  33. }
  34.  
  35. static int
  36. resolve_address (const char **ahost, struct sockaddr_in *sai)
  37. {
  38.     {
  39.     unsigned long addr = inet_addr (*ahost);
  40.  
  41.     if (addr != (unsigned long) -1)
  42.     {
  43.         sai->sin_family = AF_INET;
  44.         sai->sin_addr.s_addr = addr;
  45.         return 0;
  46.     }
  47.     }
  48.  
  49.     {
  50.         struct hostent *e = gethostbyname (*ahost);
  51.  
  52.     if (e)
  53.     {
  54.         assert (e->h_addrtype == AF_INET);
  55.         assert (e->h_addr);
  56.         *ahost = e->h_name;
  57.         sai->sin_family = AF_INET;
  58.         memcpy (&sai->sin_addr, e->h_addr, sizeof (sai->sin_addr));
  59.         return 0;
  60.     }
  61.     }
  62.  
  63.     return -1;
  64. }
  65.  
  66. #if 0
  67. static int
  68. bind_local_end (SOCKET s)
  69. {
  70.     struct sockaddr_in sai;
  71.     int result;
  72.     u_short port;
  73.  
  74.     sai.sin_family = AF_INET;
  75.     sai.sin_addr.s_addr = htonl (INADDR_ANY);
  76.  
  77.     for (port = IPPORT_RESERVED - 2; port >= IPPORT_RESERVED/2; port--)
  78.     {
  79.         int error;
  80.         sai.sin_port = htons (port);
  81.     result = bind (s, (struct sockaddr *) &sai, sizeof (sai));
  82.     error = GetLastError ();
  83.     if (result != SOCKET_ERROR || error != WSAEADDRINUSE)
  84.         break;
  85.     }
  86.  
  87.     return result;
  88. }
  89. #endif
  90.  
  91. static SOCKET
  92. bind_and_connect (struct sockaddr_in *server_sai)
  93. {
  94.     SOCKET s;
  95.     struct sockaddr_in client_sai;
  96.     u_short client_port;
  97.  
  98.     client_sai.sin_family = AF_INET;
  99.     client_sai.sin_addr.s_addr = htonl (INADDR_ANY);
  100.  
  101.     for (client_port = IPPORT_RESERVED - 1;
  102.          client_port >= IPPORT_RESERVED/2;
  103.          client_port--)
  104.     {
  105.         int result, error;
  106.     client_sai.sin_port = htons (client_port);
  107.  
  108.         if ((s = socket (PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
  109.             return INVALID_SOCKET;
  110.  
  111.     result = bind (s, (struct sockaddr *) &client_sai,
  112.                    sizeof (client_sai));
  113.     error = GetLastError ();
  114.     if (result == SOCKET_ERROR)
  115.     {
  116.         closesocket (s);
  117.         if (error == WSAEADDRINUSE)
  118.         continue;
  119.         else
  120.             return INVALID_SOCKET;
  121.     }
  122.  
  123.     result = connect (s, (struct sockaddr *) server_sai,
  124.                       sizeof (*server_sai));
  125.     error = GetLastError ();
  126.     if (result == SOCKET_ERROR)
  127.     {
  128.         closesocket (s);
  129.         if (error == WSAEADDRINUSE)
  130.         continue;
  131.         else
  132.             return INVALID_SOCKET;
  133.     }
  134.  
  135.     return s;
  136.     }
  137.  
  138.     /* We couldn't find a free port.  */
  139.     return INVALID_SOCKET;
  140. }
  141.  
  142. static int
  143. rcmd_authenticate (int fd, char *locuser, char *remuser, char *command)
  144. {
  145.     /* Send them a bunch of information, each terminated by '\0':
  146.        - secondary stream port number (we don't use this)
  147.        - username on local machine
  148.        - username on server machine
  149.        - command
  150.        Now, the Ultrix man page says you transmit the username on the
  151.        server first, but that doesn't seem to work.  Transmitting the
  152.        client username first does.  Go figure.  The Linux man pages
  153.        get it right --- hee hee.  */
  154.     if (write (fd, "0\0", 2) < 0
  155.     || write (fd, locuser, strlen (locuser) + 1) < 0
  156.         || write (fd, remuser, strlen (remuser) + 1) < 0
  157.     || write (fd, command, strlen (command) + 1) < 0)
  158.     return -1;
  159.  
  160.     /* They sniff our butt, and send us a '\0' character if they
  161.        like us.  */
  162.     {
  163.         char c;
  164.         if (read (fd, &c, 1) <= 0
  165.         || c != '\0')
  166.     {
  167.         errno = EPERM;
  168.         return -1;
  169.     }
  170.     }
  171.  
  172.     return 0;
  173. }
  174.  
  175. int
  176. rcmd (const char **ahost,
  177.       unsigned short inport,
  178.       char *locuser,
  179.       char *remuser,
  180.       char *cmd,
  181.       int *fd2p)
  182. {
  183.     struct sockaddr_in sai;
  184.     SOCKET s;
  185.     int fd;
  186.  
  187.     assert (fd2p == 0);
  188.  
  189.     if (resolve_address (ahost, &sai) < 0)
  190.         return -1;
  191.  
  192.     sai.sin_port = htons (inport);
  193.  
  194. #if 0
  195.     if ((s = socket (PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
  196.         return -1;
  197.  
  198.     if (bind_local_end (s) < 0)
  199.         return -1;
  200.  
  201.     if (connect (s, (struct sockaddr *) &sai, sizeof (sai))
  202.         == SOCKET_ERROR)
  203.         return -1;
  204. #else
  205.     if ((s = bind_and_connect (&sai)) == INVALID_SOCKET)
  206.         return -1;
  207. #endif
  208.  
  209.     /* When using WinSock under Windows NT, sockets are low-level Windows
  210.        NT handles.  Turn the socket we've made into a Unix-like file
  211.        descriptor.  */
  212.     if ((fd = _open_osfhandle (s, _O_BINARY)) < 0)
  213.         return -1;
  214.  
  215.     if (rcmd_authenticate (fd, locuser, remuser, cmd) < 0)
  216.         return -1;
  217.  
  218.     return fd;
  219. }
  220.