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