11573Srgrimes/* 21573Srgrimes * Copyright (c) 1980, 1993 31573Srgrimes * The Regents of the University of California. All rights reserved. 41573Srgrimes * 51573Srgrimes * Redistribution and use in source and binary forms, with or without 61573Srgrimes * modification, are permitted provided that the following conditions 71573Srgrimes * are met: 81573Srgrimes * 1. Redistributions of source code must retain the above copyright 91573Srgrimes * notice, this list of conditions and the following disclaimer. 101573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111573Srgrimes * notice, this list of conditions and the following disclaimer in the 121573Srgrimes * documentation and/or other materials provided with the distribution. 131573Srgrimes * 4. Neither the name of the University nor the names of its contributors 141573Srgrimes * may be used to endorse or promote products derived from this software 151573Srgrimes * without specific prior written permission. 161573Srgrimes * 171573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271573Srgrimes * SUCH DAMAGE. 2864243Skris * 2964243Skris * $FreeBSD$ 301573Srgrimes */ 311573Srgrimes 321573Srgrimes#if defined(LIBC_SCCS) && !defined(lint) 331573Srgrimesstatic char sccsid[] = "@(#)rexec.c 8.1 (Berkeley) 6/4/93"; 341573Srgrimes#endif /* LIBC_SCCS and not lint */ 351573Srgrimes 361573Srgrimes#include <sys/types.h> 377151Sphk#include <sys/uio.h> 381573Srgrimes#include <sys/socket.h> 397764Sjoerg#include <sys/param.h> 407764Sjoerg#include <sys/stat.h> 411573Srgrimes 421573Srgrimes#include <netinet/in.h> 431573Srgrimes 441573Srgrimes#include <stdio.h> 457151Sphk#include <unistd.h> 467764Sjoerg#include <string.h> 471573Srgrimes#include <netdb.h> 481573Srgrimes#include <errno.h> 497764Sjoerg#include <ctype.h> 507764Sjoerg#include <err.h> 517764Sjoerg#include <stdlib.h> 527764Sjoerg#include <unistd.h> 531573Srgrimes 541573Srgrimesint rexecoptions; 551573Srgrimeschar *getpass(), *getlogin(); 561573Srgrimes 577764Sjoerg/* 587764Sjoerg * Options and other state info. 597764Sjoerg */ 607764Sjoergstruct macel { 617764Sjoerg char mac_name[9]; /* macro name */ 627764Sjoerg char *mac_start; /* start of macro in macbuf */ 637764Sjoerg char *mac_end; /* end of macro in macbuf */ 647764Sjoerg}; 657764Sjoerg 667764Sjoergint macnum; /* number of defined macros */ 677764Sjoergstruct macel macros[16]; 687764Sjoergchar macbuf[4096]; 697764Sjoerg 707764Sjoergstatic FILE *cfile; 717764Sjoerg 727764Sjoerg#define DEFAULT 1 737764Sjoerg#define LOGIN 2 747764Sjoerg#define PASSWD 3 757764Sjoerg#define ACCOUNT 4 767764Sjoerg#define MACDEF 5 777764Sjoerg#define ID 10 787764Sjoerg#define MACH 11 797764Sjoerg 807764Sjoergstatic char tokval[100]; 817764Sjoerg 827764Sjoergstatic struct toktab { 837764Sjoerg char *tokstr; 847764Sjoerg int tval; 857764Sjoerg} toktab[]= { 867764Sjoerg { "default", DEFAULT }, 877764Sjoerg { "login", LOGIN }, 887764Sjoerg { "password", PASSWD }, 897764Sjoerg { "passwd", PASSWD }, 907764Sjoerg { "account", ACCOUNT }, 917764Sjoerg { "machine", MACH }, 927764Sjoerg { "macdef", MACDEF }, 937764Sjoerg { NULL, 0 } 947764Sjoerg}; 957764Sjoerg 967764Sjoergstatic int 977764Sjoergtoken() 987764Sjoerg{ 997764Sjoerg char *cp; 1007764Sjoerg int c; 1017764Sjoerg struct toktab *t; 1027764Sjoerg 1037764Sjoerg if (feof(cfile) || ferror(cfile)) 1047764Sjoerg return (0); 1057764Sjoerg while ((c = getc(cfile)) != EOF && 1067764Sjoerg (c == '\n' || c == '\t' || c == ' ' || c == ',')) 1077764Sjoerg continue; 1087764Sjoerg if (c == EOF) 1097764Sjoerg return (0); 1107764Sjoerg cp = tokval; 1117764Sjoerg if (c == '"') { 1127764Sjoerg while ((c = getc(cfile)) != EOF && c != '"') { 1137764Sjoerg if (c == '\\') 1147764Sjoerg c = getc(cfile); 1157764Sjoerg *cp++ = c; 1167764Sjoerg } 1177764Sjoerg } else { 1187764Sjoerg *cp++ = c; 1197764Sjoerg while ((c = getc(cfile)) != EOF 1207764Sjoerg && c != '\n' && c != '\t' && c != ' ' && c != ',') { 1217764Sjoerg if (c == '\\') 1227764Sjoerg c = getc(cfile); 1237764Sjoerg *cp++ = c; 1247764Sjoerg } 1257764Sjoerg } 1267764Sjoerg *cp = 0; 1277764Sjoerg if (tokval[0] == 0) 1287764Sjoerg return (0); 1297764Sjoerg for (t = toktab; t->tokstr; t++) 1307764Sjoerg if (!strcmp(t->tokstr, tokval)) 1317764Sjoerg return (t->tval); 1327764Sjoerg return (ID); 1337764Sjoerg} 1347764Sjoerg 1357764Sjoergstatic int 1367764Sjoergruserpass(host, aname, apass, aacct) 1377764Sjoerg char *host, **aname, **apass, **aacct; 1387764Sjoerg{ 1397764Sjoerg char *hdir, buf[BUFSIZ], *tmp; 1407764Sjoerg char myname[MAXHOSTNAMELEN], *mydomain; 1417764Sjoerg int t, i, c, usedefault = 0; 1427764Sjoerg struct stat stb; 1437764Sjoerg 1447764Sjoerg hdir = getenv("HOME"); 1457764Sjoerg if (hdir == NULL) 1467764Sjoerg hdir = "."; 14764243Skris if (strlen(hdir) + 8 > sizeof(buf)) 14864243Skris return (0); 1497764Sjoerg (void) sprintf(buf, "%s/.netrc", hdir); 1507764Sjoerg cfile = fopen(buf, "r"); 1517764Sjoerg if (cfile == NULL) { 1527764Sjoerg if (errno != ENOENT) 1537764Sjoerg warn("%s", buf); 1547764Sjoerg return (0); 1557764Sjoerg } 1567764Sjoerg if (gethostname(myname, sizeof(myname)) < 0) 1577764Sjoerg myname[0] = '\0'; 1587764Sjoerg if ((mydomain = strchr(myname, '.')) == NULL) 1597764Sjoerg mydomain = ""; 1607764Sjoergnext: 1617764Sjoerg while ((t = token())) switch(t) { 1627764Sjoerg 1637764Sjoerg case DEFAULT: 1647764Sjoerg usedefault = 1; 1657764Sjoerg /* FALL THROUGH */ 1667764Sjoerg 1677764Sjoerg case MACH: 1687764Sjoerg if (!usedefault) { 1697764Sjoerg if (token() != ID) 1707764Sjoerg continue; 1717764Sjoerg /* 1727764Sjoerg * Allow match either for user's input host name 1738870Srgrimes * or official hostname. Also allow match of 1747764Sjoerg * incompletely-specified host in local domain. 1757764Sjoerg */ 1767764Sjoerg if (strcasecmp(host, tokval) == 0) 1777764Sjoerg goto match; 1787764Sjoerg if ((tmp = strchr(host, '.')) != NULL && 1797764Sjoerg strcasecmp(tmp, mydomain) == 0 && 1807764Sjoerg strncasecmp(host, tokval, tmp - host) == 0 && 1817764Sjoerg tokval[tmp - host] == '\0') 1827764Sjoerg goto match; 1837764Sjoerg continue; 1847764Sjoerg } 1857764Sjoerg match: 1867764Sjoerg while ((t = token()) && t != MACH && t != DEFAULT) switch(t) { 1877764Sjoerg 1887764Sjoerg case LOGIN: 1897764Sjoerg if (token()) 1908870Srgrimes if (*aname == 0) { 1917764Sjoerg *aname = malloc((unsigned) strlen(tokval) + 1); 1927764Sjoerg (void) strcpy(*aname, tokval); 1937764Sjoerg } else { 1947764Sjoerg if (strcmp(*aname, tokval)) 1957764Sjoerg goto next; 1967764Sjoerg } 1977764Sjoerg break; 1987764Sjoerg case PASSWD: 1997764Sjoerg if ((*aname == 0 || strcmp(*aname, "anonymous")) && 2007764Sjoerg fstat(fileno(cfile), &stb) >= 0 && 2017764Sjoerg (stb.st_mode & 077) != 0) { 2027764Sjoerg warnx("Error: .netrc file is readable by others."); 2037764Sjoerg warnx("Remove password or make file unreadable by others."); 2047764Sjoerg goto bad; 2057764Sjoerg } 2067764Sjoerg if (token() && *apass == 0) { 2077764Sjoerg *apass = malloc((unsigned) strlen(tokval) + 1); 2087764Sjoerg (void) strcpy(*apass, tokval); 2097764Sjoerg } 2107764Sjoerg break; 2117764Sjoerg case ACCOUNT: 2127764Sjoerg if (fstat(fileno(cfile), &stb) >= 0 2137764Sjoerg && (stb.st_mode & 077) != 0) { 2147764Sjoerg warnx("Error: .netrc file is readable by others."); 2157764Sjoerg warnx("Remove account or make file unreadable by others."); 2167764Sjoerg goto bad; 2177764Sjoerg } 2187764Sjoerg if (token() && *aacct == 0) { 2197764Sjoerg *aacct = malloc((unsigned) strlen(tokval) + 1); 2207764Sjoerg (void) strcpy(*aacct, tokval); 2217764Sjoerg } 2227764Sjoerg break; 2237764Sjoerg case MACDEF: 2247764Sjoerg while ((c=getc(cfile)) != EOF && 2257764Sjoerg (c == ' ' || c == '\t')) 2267764Sjoerg ; 2277764Sjoerg if (c == EOF || c == '\n') { 2287764Sjoerg printf("Missing macdef name argument.\n"); 2297764Sjoerg goto bad; 2307764Sjoerg } 2317764Sjoerg if (macnum == 16) { 2327764Sjoerg printf("Limit of 16 macros have already been defined\n"); 2337764Sjoerg goto bad; 2347764Sjoerg } 2357764Sjoerg tmp = macros[macnum].mac_name; 2367764Sjoerg *tmp++ = c; 2377764Sjoerg for (i=0; i < 8 && (c=getc(cfile)) != EOF && 2387764Sjoerg !isspace(c); ++i) { 2397764Sjoerg *tmp++ = c; 2407764Sjoerg } 2417764Sjoerg if (c == EOF) { 2427764Sjoerg printf("Macro definition missing null line terminator.\n"); 2437764Sjoerg goto bad; 2447764Sjoerg } 2457764Sjoerg *tmp = '\0'; 2467764Sjoerg if (c != '\n') { 2477764Sjoerg while ((c=getc(cfile)) != EOF && c != '\n'); 2487764Sjoerg } 2497764Sjoerg if (c == EOF) { 2507764Sjoerg printf("Macro definition missing null line terminator.\n"); 2517764Sjoerg goto bad; 2527764Sjoerg } 2537764Sjoerg if (macnum == 0) { 2547764Sjoerg macros[macnum].mac_start = macbuf; 2557764Sjoerg } 2567764Sjoerg else { 2577764Sjoerg macros[macnum].mac_start = macros[macnum-1].mac_end + 1; 2587764Sjoerg } 2597764Sjoerg tmp = macros[macnum].mac_start; 2607764Sjoerg while (tmp != macbuf + 4096) { 2617764Sjoerg if ((c=getc(cfile)) == EOF) { 2627764Sjoerg printf("Macro definition missing null line terminator.\n"); 2637764Sjoerg goto bad; 2647764Sjoerg } 2657764Sjoerg *tmp = c; 2667764Sjoerg if (*tmp == '\n') { 2677764Sjoerg if (*(tmp-1) == '\0') { 2687764Sjoerg macros[macnum++].mac_end = tmp - 1; 2697764Sjoerg break; 2707764Sjoerg } 2717764Sjoerg *tmp = '\0'; 2727764Sjoerg } 2737764Sjoerg tmp++; 2747764Sjoerg } 2757764Sjoerg if (tmp == macbuf + 4096) { 2767764Sjoerg printf("4K macro buffer exceeded\n"); 2777764Sjoerg goto bad; 2787764Sjoerg } 2797764Sjoerg break; 2807764Sjoerg default: 2817764Sjoerg warnx("Unknown .netrc keyword %s", tokval); 2827764Sjoerg break; 2837764Sjoerg } 2847764Sjoerg goto done; 2857764Sjoerg } 2867764Sjoergdone: 2877764Sjoerg (void) fclose(cfile); 2887764Sjoerg return (0); 2897764Sjoergbad: 2907764Sjoerg (void) fclose(cfile); 2917764Sjoerg return (-1); 2927764Sjoerg} 2937764Sjoerg 29417141Sjkhint 2951573Srgrimesrexec(ahost, rport, name, pass, cmd, fd2p) 2961573Srgrimes char **ahost; 2971573Srgrimes int rport; 2981573Srgrimes char *name, *pass, *cmd; 2991573Srgrimes int *fd2p; 3001573Srgrimes{ 3011573Srgrimes struct sockaddr_in sin, sin2, from; 3021573Srgrimes struct hostent *hp; 3031573Srgrimes u_short port; 3041573Srgrimes int s, timo = 1, s3; 305189077Srdivacky char c, *acct; 3061573Srgrimes 3071573Srgrimes hp = gethostbyname(*ahost); 3081573Srgrimes if (hp == 0) { 3091573Srgrimes herror(*ahost); 3101573Srgrimes return (-1); 3111573Srgrimes } 3121573Srgrimes *ahost = hp->h_name; 313189077Srdivacky acct = NULL; 314189077Srdivacky ruserpass(hp->h_name, &name, &pass, &acct); 315189077Srdivacky free(acct); 3161573Srgrimesretry: 3171573Srgrimes s = socket(AF_INET, SOCK_STREAM, 0); 3181573Srgrimes if (s < 0) { 3191573Srgrimes perror("rexec: socket"); 3201573Srgrimes return (-1); 3211573Srgrimes } 3221573Srgrimes sin.sin_family = hp->h_addrtype; 3231573Srgrimes sin.sin_port = rport; 3241573Srgrimes bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length); 3251573Srgrimes if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { 3261573Srgrimes if (errno == ECONNREFUSED && timo <= 16) { 3271573Srgrimes (void) close(s); 3281573Srgrimes sleep(timo); 3291573Srgrimes timo *= 2; 3301573Srgrimes goto retry; 3311573Srgrimes } 3321573Srgrimes perror(hp->h_name); 333301152Struckman (void) close(s); 3341573Srgrimes return (-1); 3351573Srgrimes } 3361573Srgrimes if (fd2p == 0) { 3371573Srgrimes (void) write(s, "", 1); 3381573Srgrimes port = 0; 3391573Srgrimes } else { 3401573Srgrimes char num[8]; 3411573Srgrimes int s2, sin2len; 3428870Srgrimes 3431573Srgrimes s2 = socket(AF_INET, SOCK_STREAM, 0); 3441573Srgrimes if (s2 < 0) { 3451573Srgrimes (void) close(s); 3461573Srgrimes return (-1); 3471573Srgrimes } 3481573Srgrimes listen(s2, 1); 3491573Srgrimes sin2len = sizeof (sin2); 3501573Srgrimes if (getsockname(s2, (struct sockaddr *)&sin2, &sin2len) < 0 || 3511573Srgrimes sin2len != sizeof (sin2)) { 3521573Srgrimes perror("getsockname"); 3531573Srgrimes (void) close(s2); 3541573Srgrimes goto bad; 3551573Srgrimes } 3561573Srgrimes port = ntohs((u_short)sin2.sin_port); 3571573Srgrimes (void) sprintf(num, "%u", port); 3581573Srgrimes (void) write(s, num, strlen(num)+1); 3591573Srgrimes { int len = sizeof (from); 3601573Srgrimes s3 = accept(s2, (struct sockaddr *)&from, &len); 3611573Srgrimes close(s2); 3621573Srgrimes if (s3 < 0) { 3631573Srgrimes perror("accept"); 3641573Srgrimes port = 0; 3651573Srgrimes goto bad; 3661573Srgrimes } 3671573Srgrimes } 3681573Srgrimes *fd2p = s3; 3691573Srgrimes } 3701573Srgrimes (void) write(s, name, strlen(name) + 1); 3711573Srgrimes /* should public key encypt the password here */ 3721573Srgrimes (void) write(s, pass, strlen(pass) + 1); 3731573Srgrimes (void) write(s, cmd, strlen(cmd) + 1); 3741573Srgrimes if (read(s, &c, 1) != 1) { 3751573Srgrimes perror(*ahost); 3761573Srgrimes goto bad; 3771573Srgrimes } 3781573Srgrimes if (c != 0) { 3791573Srgrimes while (read(s, &c, 1) == 1) { 3801573Srgrimes (void) write(2, &c, 1); 3811573Srgrimes if (c == '\n') 3821573Srgrimes break; 3831573Srgrimes } 3841573Srgrimes goto bad; 3851573Srgrimes } 3861573Srgrimes return (s); 3871573Srgrimesbad: 3881573Srgrimes if (port) 3891573Srgrimes (void) close(*fd2p); 3901573Srgrimes (void) close(s); 3911573Srgrimes return (-1); 3921573Srgrimes} 393