1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 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 * $FreeBSD$ 32 */ 33 34 #if defined(LIBC_SCCS) && !defined(lint) 35 static char sccsid[] = "@(#)rexec.c 8.1 (Berkeley) 6/4/93"; 36 #endif /* LIBC_SCCS and not lint */ 37 38 #include <sys/types.h> 39 #include <sys/uio.h> 40 #include <sys/socket.h> 41 #include <sys/param.h> 42 #include <sys/stat.h> 43 44 #include <netinet/in.h> 45 46 #include <stdio.h> 47 #include <unistd.h> 48 #include <string.h> 49 #include <netdb.h> 50 #include <errno.h> 51 #include <ctype.h> 52 #include <err.h> 53 #include <stdlib.h> 54 #include <unistd.h> 55 56 int rexecoptions; 57 char *getpass(), *getlogin(); 58 59 /* 60 * Options and other state info. 61 */ 62 struct macel { 63 char mac_name[9]; /* macro name */ 64 char *mac_start; /* start of macro in macbuf */ 65 char *mac_end; /* end of macro in macbuf */ 66 }; 67 68 int macnum; /* number of defined macros */ 69 struct macel macros[16]; 70 char macbuf[4096]; 71 72 static FILE *cfile; 73 74 #define DEFAULT 1 75 #define LOGIN 2 76 #define PASSWD 3 77 #define ACCOUNT 4 78 #define MACDEF 5 79 #define ID 10 80 #define MACH 11 81 82 static char tokval[100]; 83 84 static struct toktab { 85 char *tokstr; 86 int tval; 87 } toktab[]= { 88 { "default", DEFAULT }, 89 { "login", LOGIN }, 90 { "password", PASSWD }, 91 { "passwd", PASSWD }, 92 { "account", ACCOUNT }, 93 { "machine", MACH }, 94 { "macdef", MACDEF }, 95 { NULL, 0 } 96 }; 97 98 static int 99 token() 100 { 101 char *cp; 102 int c; 103 struct toktab *t; 104 105 if (feof(cfile) || ferror(cfile)) 106 return (0); 107 while ((c = getc(cfile)) != EOF && 108 (c == '\n' || c == '\t' || c == ' ' || c == ',')) 109 continue; 110 if (c == EOF) 111 return (0); 112 cp = tokval; 113 if (c == '"') { 114 while ((c = getc(cfile)) != EOF && c != '"') { 115 if (c == '\\') 116 c = getc(cfile); 117 *cp++ = c; 118 } 119 } else { 120 *cp++ = c; 121 while ((c = getc(cfile)) != EOF 122 && c != '\n' && c != '\t' && c != ' ' && c != ',') { 123 if (c == '\\') 124 c = getc(cfile); 125 *cp++ = c; 126 } 127 } 128 *cp = 0; 129 if (tokval[0] == 0) 130 return (0); 131 for (t = toktab; t->tokstr; t++) 132 if (!strcmp(t->tokstr, tokval)) 133 return (t->tval); 134 return (ID); 135 } 136 137 static int 138 ruserpass(host, aname, apass, aacct) 139 char *host, **aname, **apass, **aacct; 140 { 141 char *hdir, buf[BUFSIZ], *tmp; 142 char myname[MAXHOSTNAMELEN], *mydomain; 143 int t, i, c, usedefault = 0; 144 struct stat stb; 145 146 hdir = getenv("HOME"); 147 if (hdir == NULL) 148 hdir = "."; 149 if (strlen(hdir) + 8 > sizeof(buf)) 150 return (0); 151 (void) sprintf(buf, "%s/.netrc", hdir); 152 cfile = fopen(buf, "r"); 153 if (cfile == NULL) { 154 if (errno != ENOENT) 155 warn("%s", buf); 156 return (0); 157 } 158 if (gethostname(myname, sizeof(myname)) < 0) 159 myname[0] = '\0'; 160 if ((mydomain = strchr(myname, '.')) == NULL) 161 mydomain = ""; 162 next: 163 while ((t = token())) switch(t) { 164 165 case DEFAULT: 166 usedefault = 1; 167 /* FALL THROUGH */ 168 169 case MACH: 170 if (!usedefault) { 171 if (token() != ID) 172 continue; 173 /* 174 * Allow match either for user's input host name 175 * or official hostname. Also allow match of 176 * incompletely-specified host in local domain. 177 */ 178 if (strcasecmp(host, tokval) == 0) 179 goto match; 180 if ((tmp = strchr(host, '.')) != NULL && 181 strcasecmp(tmp, mydomain) == 0 && 182 strncasecmp(host, tokval, tmp - host) == 0 && 183 tokval[tmp - host] == '\0') 184 goto match; 185 continue; 186 } 187 match: 188 while ((t = token()) && t != MACH && t != DEFAULT) switch(t) { 189 190 case LOGIN: 191 if (token()) 192 if (*aname == NULL) { 193 *aname = malloc((unsigned) strlen(tokval) + 1); 194 (void) strcpy(*aname, tokval); 195 } else { 196 if (strcmp(*aname, tokval)) 197 goto next; 198 } 199 break; 200 case PASSWD: 201 if ((*aname == NULL || strcmp(*aname, "anonymous")) && 202 fstat(fileno(cfile), &stb) >= 0 && 203 (stb.st_mode & 077) != 0) { 204 warnx("Error: .netrc file is readable by others."); 205 warnx("Remove password or make file unreadable by others."); 206 goto bad; 207 } 208 if (token() && *apass == NULL) { 209 *apass = malloc((unsigned) strlen(tokval) + 1); 210 (void) strcpy(*apass, tokval); 211 } 212 break; 213 case ACCOUNT: 214 if (fstat(fileno(cfile), &stb) >= 0 215 && (stb.st_mode & 077) != 0) { 216 warnx("Error: .netrc file is readable by others."); 217 warnx("Remove account or make file unreadable by others."); 218 goto bad; 219 } 220 if (token() && *aacct == NULL) { 221 *aacct = malloc((unsigned) strlen(tokval) + 1); 222 (void) strcpy(*aacct, tokval); 223 } 224 break; 225 case MACDEF: 226 while ((c=getc(cfile)) != EOF && 227 (c == ' ' || c == '\t')) 228 ; 229 if (c == EOF || c == '\n') { 230 printf("Missing macdef name argument.\n"); 231 goto bad; 232 } 233 if (macnum == 16) { 234 printf("Limit of 16 macros have already been defined\n"); 235 goto bad; 236 } 237 tmp = macros[macnum].mac_name; 238 *tmp++ = c; 239 for (i=0; i < 8 && (c=getc(cfile)) != EOF && 240 !isspace(c); ++i) { 241 *tmp++ = c; 242 } 243 if (c == EOF) { 244 printf("Macro definition missing null line terminator.\n"); 245 goto bad; 246 } 247 *tmp = '\0'; 248 if (c != '\n') { 249 while ((c=getc(cfile)) != EOF && c != '\n'); 250 } 251 if (c == EOF) { 252 printf("Macro definition missing null line terminator.\n"); 253 goto bad; 254 } 255 if (macnum == 0) { 256 macros[macnum].mac_start = macbuf; 257 } 258 else { 259 macros[macnum].mac_start = macros[macnum-1].mac_end + 1; 260 } 261 tmp = macros[macnum].mac_start; 262 while (tmp != macbuf + 4096) { 263 if ((c=getc(cfile)) == EOF) { 264 printf("Macro definition missing null line terminator.\n"); 265 goto bad; 266 } 267 *tmp = c; 268 if (*tmp == '\n') { 269 if (*(tmp-1) == '\0') { 270 macros[macnum++].mac_end = tmp - 1; 271 break; 272 } 273 *tmp = '\0'; 274 } 275 tmp++; 276 } 277 if (tmp == macbuf + 4096) { 278 printf("4K macro buffer exceeded\n"); 279 goto bad; 280 } 281 break; 282 default: 283 warnx("Unknown .netrc keyword %s", tokval); 284 break; 285 } 286 goto done; 287 } 288 done: 289 (void) fclose(cfile); 290 return (0); 291 bad: 292 (void) fclose(cfile); 293 return (-1); 294 } 295 296 int 297 rexec(ahost, rport, name, pass, cmd, fd2p) 298 char **ahost; 299 int rport; 300 char *name, *pass, *cmd; 301 int *fd2p; 302 { 303 struct sockaddr_in sin, sin2, from; 304 struct hostent *hp; 305 u_short port; 306 int s, timo = 1, s3; 307 char c, *acct; 308 309 hp = gethostbyname(*ahost); 310 if (hp == NULL) { 311 herror(*ahost); 312 return (-1); 313 } 314 *ahost = hp->h_name; 315 acct = NULL; 316 ruserpass(hp->h_name, &name, &pass, &acct); 317 free(acct); 318 retry: 319 s = socket(AF_INET, SOCK_STREAM, 0); 320 if (s < 0) { 321 perror("rexec: socket"); 322 return (-1); 323 } 324 sin.sin_family = hp->h_addrtype; 325 sin.sin_port = rport; 326 bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length); 327 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { 328 if (errno == ECONNREFUSED && timo <= 16) { 329 (void) close(s); 330 sleep(timo); 331 timo *= 2; 332 goto retry; 333 } 334 perror(hp->h_name); 335 (void) close(s); 336 return (-1); 337 } 338 port = 0; 339 if (fd2p == 0) 340 (void) write(s, "", 1); 341 else { 342 char num[8]; 343 int s2, sin2len; 344 345 s2 = socket(AF_INET, SOCK_STREAM, 0); 346 if (s2 < 0) { 347 (void) close(s); 348 return (-1); 349 } 350 listen(s2, 1); 351 sin2len = sizeof (sin2); 352 if (getsockname(s2, (struct sockaddr *)&sin2, &sin2len) < 0 || 353 sin2len != sizeof (sin2)) { 354 perror("getsockname"); 355 (void) close(s2); 356 goto bad; 357 } 358 port = ntohs((u_short)sin2.sin_port); 359 (void) sprintf(num, "%hu", port); 360 (void) write(s, num, strlen(num)+1); 361 { int len = sizeof (from); 362 s3 = accept(s2, (struct sockaddr *)&from, &len); 363 close(s2); 364 if (s3 < 0) { 365 perror("accept"); 366 port = 0; 367 goto bad; 368 } 369 } 370 *fd2p = s3; 371 } 372 (void) write(s, name, strlen(name) + 1); 373 /* should public key encypt the password here */ 374 (void) write(s, pass, strlen(pass) + 1); 375 (void) write(s, cmd, strlen(cmd) + 1); 376 if (read(s, &c, 1) != 1) { 377 perror(*ahost); 378 goto bad; 379 } 380 if (c != 0) { 381 while (read(s, &c, 1) == 1) { 382 (void) write(2, &c, 1); 383 if (c == '\n') 384 break; 385 } 386 goto bad; 387 } 388 return (s); 389 bad: 390 if (port) 391 (void) close(*fd2p); 392 (void) close(s); 393 return (-1); 394 } 395