1/* $NetBSD: rexec.c,v 1.15 2002/11/11 23:43:03 thorpej Exp $ */ 2 3/* 4 * Copyright (c) 1980, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33#if defined(LIBC_SCCS) && !defined(lint) 34#if 0 35static char sccsid[] = "@(#)rexec.c 8.1 (Berkeley) 6/4/93"; 36#else 37__RCSID("$NetBSD: rexec.c,v 1.15 2002/11/11 23:43:03 thorpej Exp $"); 38#endif 39#endif /* LIBC_SCCS and not lint */ 40 41#include <sys/types.h> 42#include <sys/socket.h> 43 44#include <netinet/in.h> 45 46#include <assert.h> 47#include <err.h> 48#include <errno.h> 49#include <netdb.h> 50#include <stdio.h> 51#include <string.h> 52#include <unistd.h> 53 54int rexecoptions; 55 56int ruserpass __P((const char *, char **, char **)); 57int rexec __P((char **, int, char *, char *, char *, int *)); 58 59int 60rexec(ahost, rport, name, pass, cmd, fd2p) 61 char **ahost; 62 int rport; 63 char *name, *pass, *cmd; 64 int *fd2p; 65{ 66 struct sockaddr_in rsin, from; 67 socklen_t fromlen; 68 struct hostent *hp; 69 u_short port; 70 size_t len; 71 unsigned int timo = 1; 72 int s, s3; 73 char c; 74 75 _DIAGASSERT(ahost != NULL); 76 _DIAGASSERT(name != NULL); 77 _DIAGASSERT(pass != NULL); 78 _DIAGASSERT(cmd != NULL); 79 /* fd2p may be NULL */ 80 81 hp = gethostbyname(*ahost); 82 if (hp == 0) { 83 warnx("Error resolving %s (%s)", *ahost, hstrerror(h_errno)); 84 return -1; 85 } 86 *ahost = hp->h_name; 87 (void)ruserpass(hp->h_name, &name, &pass); 88retry: 89 if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) { 90 warn("Cannot create socket"); 91 return (-1); 92 } 93 rsin.sin_family = hp->h_addrtype; 94 rsin.sin_len = sizeof(rsin); 95 rsin.sin_port = rport; 96 /* Avoid data corruption from bogus DNS results */ 97 if (hp->h_length > (int) sizeof(rsin.sin_addr)) 98 len = sizeof(rsin.sin_addr); 99 else 100 len = hp->h_length; 101 memcpy(&rsin.sin_addr, hp->h_addr, len); 102 if (connect(s, (struct sockaddr *)(void *)&rsin, sizeof(rsin)) == -1) { 103 if (errno == ECONNREFUSED && timo <= 16) { 104 (void)close(s); 105 sleep(timo); 106 timo *= 2; 107 goto retry; 108 } 109 warn("Cannot connect to %s", hp->h_name); 110 return -1; 111 } 112 port = 0; 113 if (fd2p == 0) { 114 (void)write(s, "", 1); 115 } else { 116 char num[8]; 117 int s2; 118 struct sockaddr_in sin2; 119 socklen_t sin2len; 120 121 s2 = socket(AF_INET, SOCK_STREAM, 0); 122 if (s2 == -1) { 123 warn("Error creating socket"); 124 (void)close(s); 125 return -1; 126 } 127 listen(s2, 1); 128 sin2len = sizeof(sin2); 129 if (getsockname(s2, (struct sockaddr *)(void *)&sin2, 130 &sin2len) == -1 || sin2len != sizeof(sin2)) { 131 warn("Failed to get socket name"); 132 (void)close(s2); 133 goto bad; 134 } 135 port = ntohs((u_short)sin2.sin_port); 136 (void)snprintf(num, sizeof(num), "%u", port); 137 (void)write(s, num, strlen(num)+1); 138 139 fromlen = sizeof(from); 140 s3 = accept(s2, (struct sockaddr *)(void *)&from, &fromlen); 141 (void)close(s2); 142 if (s3 == -1) { 143 warn("Error accepting connection"); 144 port = 0; 145 goto bad; 146 } 147 *fd2p = s3; 148 } 149 (void)write(s, name, strlen(name) + 1); 150 /* should public key encypt the password here */ 151 (void)write(s, pass, strlen(pass) + 1); 152 (void)write(s, cmd, strlen(cmd) + 1); 153 if (read(s, &c, 1) != 1) { 154 warn("Error reading from %s", *ahost); 155 goto bad; 156 } 157 if (c != 0) { 158 while (read(s, &c, 1) == 1) { 159 (void) write(2, &c, 1); 160 if (c == '\n') 161 break; 162 } 163 goto bad; 164 } 165 return s; 166bad: 167 if (port) 168 (void)close(*fd2p); 169 (void)close(s); 170 return -1; 171} 172