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