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