Remove some duplicate includes in bin/, games/ and lib/.
[dragonfly.git] / lib / libcompat / 4.3 / rexec.c
1 /*
2  * Copyright (c) 1980, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * $FreeBSD: src/lib/libcompat/4.3/rexec.c,v 1.5.8.3 2000/11/22 13:36:00 ben Exp $
34  *
35  * @(#)rexec.c  8.1 (Berkeley) 6/4/93
36  */
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
55 int     rexecoptions;
56 char    *getpass(), *getlogin();
57
58 /*
59  * Options and other state info.
60  */
61 struct macel {
62         char mac_name[9];       /* macro name */
63         char *mac_start;        /* start of macro in macbuf */
64         char *mac_end;          /* end of macro in macbuf */
65 };
66
67 int macnum;                     /* number of defined macros */
68 struct macel macros[16];
69 char macbuf[4096];
70
71 static  FILE *cfile;
72
73 #define DEFAULT 1
74 #define LOGIN   2
75 #define PASSWD  3
76 #define ACCOUNT 4
77 #define MACDEF  5
78 #define ID      10
79 #define MACH    11
80
81 static char tokval[100];
82
83 static struct toktab {
84         char *tokstr;
85         int tval;
86 } toktab[]= {
87         { "default",    DEFAULT },
88         { "login",      LOGIN },
89         { "password",   PASSWD },
90         { "passwd",     PASSWD },
91         { "account",    ACCOUNT },
92         { "machine",    MACH },
93         { "macdef",     MACDEF },
94         { NULL,         0 }
95 };
96
97 static int
98 token(void)
99 {
100         char *cp;
101         int c;
102         struct toktab *t;
103
104         if (feof(cfile) || ferror(cfile))
105                 return (0);
106         while ((c = getc(cfile)) != EOF &&
107             (c == '\n' || c == '\t' || c == ' ' || c == ','))
108                 continue;
109         if (c == EOF)
110                 return (0);
111         cp = tokval;
112         if (c == '"') {
113                 while ((c = getc(cfile)) != EOF && c != '"') {
114                         if (c == '\\')
115                                 c = getc(cfile);
116                         *cp++ = c;
117                 }
118         } else {
119                 *cp++ = c;
120                 while ((c = getc(cfile)) != EOF
121                     && c != '\n' && c != '\t' && c != ' ' && c != ',') {
122                         if (c == '\\')
123                                 c = getc(cfile);
124                         *cp++ = c;
125                 }
126         }
127         *cp = 0;
128         if (tokval[0] == 0)
129                 return (0);
130         for (t = toktab; t->tokstr; t++)
131                 if (!strcmp(t->tokstr, tokval))
132                         return (t->tval);
133         return (ID);
134 }
135
136 static int
137 ruserpass(char *host, const char **aname, const char **apass, char **aacct)
138 {
139         char *hdir, buf[BUFSIZ], *tmp;
140         char myname[MAXHOSTNAMELEN], *mydomain;
141         int t, i, c, usedefault = 0;
142         struct stat stb;
143
144         hdir = getenv("HOME");
145         if (hdir == NULL)
146                 hdir = ".";
147         if (strlen(hdir) + 8 > sizeof(buf))
148                 return (0);
149         (void) sprintf(buf, "%s/.netrc", hdir);
150         cfile = fopen(buf, "r");
151         if (cfile == NULL) {
152                 if (errno != ENOENT)
153                         warn("%s", buf);
154                 return (0);
155         }
156         if (gethostname(myname, sizeof(myname)) < 0)
157                 myname[0] = '\0';
158         if ((mydomain = strchr(myname, '.')) == NULL)
159                 mydomain = "";
160 next:
161         while ((t = token())) switch(t) {
162
163         case DEFAULT:
164                 usedefault = 1;
165                 /* FALL THROUGH */
166
167         case MACH:
168                 if (!usedefault) {
169                         if (token() != ID)
170                                 continue;
171                         /*
172                          * Allow match either for user's input host name
173                          * or official hostname.  Also allow match of
174                          * incompletely-specified host in local domain.
175                          */
176                         if (strcasecmp(host, tokval) == 0)
177                                 goto match;
178                         if ((tmp = strchr(host, '.')) != NULL &&
179                             strcasecmp(tmp, mydomain) == 0 &&
180                             strncasecmp(host, tokval, tmp - host) == 0 &&
181                             tokval[tmp - host] == '\0')
182                                 goto match;
183                         continue;
184                 }
185         match:
186                 while ((t = token()) && t != MACH && t != DEFAULT) switch(t) {
187
188                 case LOGIN:
189                         if (token())
190                                 if (*aname == NULL) {
191                                         char *tmp;
192                                         tmp = malloc(strlen(tokval) + 1);
193                                         strcpy(tmp, tokval);
194                                         *aname = tmp;
195                                 } else {
196                                         if (strcmp(*aname, tokval))
197                                                 goto next;
198                                 }
199                         break;
200                 case PASSWD:
201                         if ((*aname == 0 || 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 == 0) {
209                                 char *tmp;
210                                 tmp = malloc(strlen(tokval) + 1);
211                                 strcpy(tmp, tokval);
212                                 *apass = tmp;
213                         }
214                         break;
215                 case ACCOUNT:
216                         if (fstat(fileno(cfile), &stb) >= 0
217                             && (stb.st_mode & 077) != 0) {
218         warnx("Error: .netrc file is readable by others.");
219         warnx("Remove account or make file unreadable by others.");
220                                 goto bad;
221                         }
222                         if (token() && *aacct == 0) {
223                                 *aacct = malloc((unsigned) strlen(tokval) + 1);
224                                 (void) strcpy(*aacct, tokval);
225                         }
226                         break;
227                 case MACDEF:
228                         while ((c=getc(cfile)) != EOF &&
229                                                 (c == ' ' || c == '\t'))
230                                 ;
231                         if (c == EOF || c == '\n') {
232                                 printf("Missing macdef name argument.\n");
233                                 goto bad;
234                         }
235                         if (macnum == 16) {
236                                 printf("Limit of 16 macros have already been defined\n");
237                                 goto bad;
238                         }
239                         tmp = macros[macnum].mac_name;
240                         *tmp++ = c;
241                         for (i=0; i < 8 && (c=getc(cfile)) != EOF &&
242                             !isspace(c); ++i) {
243                                 *tmp++ = c;
244                         }
245                         if (c == EOF) {
246                                 printf("Macro definition missing null line terminator.\n");
247                                 goto bad;
248                         }
249                         *tmp = '\0';
250                         if (c != '\n') {
251                                 while ((c=getc(cfile)) != EOF && c != '\n');
252                         }
253                         if (c == EOF) {
254                                 printf("Macro definition missing null line terminator.\n");
255                                 goto bad;
256                         }
257                         if (macnum == 0) {
258                                 macros[macnum].mac_start = macbuf;
259                         }
260                         else {
261                                 macros[macnum].mac_start = macros[macnum-1].mac_end + 1;
262                         }
263                         tmp = macros[macnum].mac_start;
264                         while (tmp != macbuf + 4096) {
265                                 if ((c=getc(cfile)) == EOF) {
266                                 printf("Macro definition missing null line terminator.\n");
267                                         goto bad;
268                                 }
269                                 *tmp = c;
270                                 if (*tmp == '\n') {
271                                         if (*(tmp-1) == '\0') {
272                                            macros[macnum++].mac_end = tmp - 1;
273                                            break;
274                                         }
275                                         *tmp = '\0';
276                                 }
277                                 tmp++;
278                         }
279                         if (tmp == macbuf + 4096) {
280                                 printf("4K macro buffer exceeded\n");
281                                 goto bad;
282                         }
283                         break;
284                 default:
285                         warnx("Unknown .netrc keyword %s", tokval);
286                         break;
287                 }
288                 goto done;
289         }
290 done:
291         (void) fclose(cfile);
292         return (0);
293 bad:
294         (void) fclose(cfile);
295         return (-1);
296 }
297
298 int
299 rexec_af(char **ahost, int rport, const char *name, const char *pass,
300     const char *cmd, int *fd2p, sa_family_t *af)
301 {
302         struct sockaddr_storage sa2, from;
303         struct addrinfo hints, *res0;
304         const char *orig_name = name;
305         const char *orig_pass = pass;
306         static char *ahostbuf;
307         u_short port = 0;
308         int s, timo = 1, s3;
309         char c;
310         int gai;
311         char servbuff[NI_MAXSERV];
312
313         snprintf(servbuff, sizeof(servbuff), "%d", ntohs(rport));
314         servbuff[sizeof(servbuff) - 1] = '\0';
315
316         memset(&hints, '\0', sizeof(hints));
317         if (af)
318                 hints.ai_family = *af;
319         hints.ai_socktype = SOCK_STREAM;
320         hints.ai_flags = AI_CANONNAME;
321         gai = getaddrinfo(*ahost, servbuff, &hints, &res0);
322         if (gai){
323                 /* XXX: set errno? */
324                 return -1;
325         }
326
327         if (res0->ai_canonname){
328                 free (ahostbuf);
329                 ahostbuf = strdup (res0->ai_canonname);
330                 if (ahostbuf == NULL) {
331                         perror ("rexec: strdup");
332                         return (-1);
333                 }
334                 *ahost = ahostbuf;
335         } else {
336                 *ahost = NULL;
337                 __set_errno (ENOENT);
338                 return -1;
339         }
340         ruserpass(res0->ai_canonname, &name, &pass, 0);
341 retry:
342         s = socket(res0->ai_family, res0->ai_socktype, 0);
343         if (s < 0) {
344                 perror("rexec: socket");
345                 return (-1);
346         }
347         if (connect(s, res0->ai_addr, res0->ai_addrlen) < 0) {
348                 if (errno == ECONNREFUSED && timo <= 16) {
349                         (void) close(s);
350                         sleep(timo);
351                         timo *= 2;
352                         goto retry;
353                 }
354                 perror(res0->ai_canonname);
355                 return (-1);
356         }
357         if (fd2p == 0) {
358                 (void) write(s, "", 1);
359                 port = 0;
360         } else {
361                 char num[32];
362                 int s2;
363                 socklen_t sa2len;
364
365                 s2 = socket(res0->ai_family, res0->ai_socktype, 0);
366                 if (s2 < 0) {
367                         (void) close(s);
368                         return (-1);
369                 }
370                 listen(s2, 1);
371                 sa2len = sizeof (sa2);
372                 if (getsockname(s2, (struct sockaddr *)&sa2, &sa2len) < 0) {
373                         perror("getsockname");
374                         (void) close(s2);
375                         goto bad;
376                 } else if (sa2len != SA_LEN((struct sockaddr *)&sa2)) {
377                         __set_errno(EINVAL);
378                         (void) close(s2);
379                         goto bad;
380                 }
381                 port = 0;
382                 if (!getnameinfo((struct sockaddr *)&sa2, sa2len,
383                                  NULL, 0, servbuff, sizeof(servbuff),
384                                  NI_NUMERICSERV))
385                         port = atoi(servbuff);
386                 (void) sprintf(num, "%u", port);
387                 (void) write(s, num, strlen(num)+1);
388                 { socklen_t len = sizeof (from);
389                   s3 = accept(s2, (struct sockaddr *)&from,
390                                                   &len);
391                   close(s2);
392                   if (s3 < 0) {
393                         perror("accept");
394                         port = 0;
395                         goto bad;
396                   }
397                 }
398                 *fd2p = s3;
399         }
400
401         (void) write(s, name, strlen(name) + 1);
402         /* should public key encypt the password here */
403         (void) write(s, pass, strlen(pass) + 1);
404         (void) write(s, cmd, strlen(cmd) + 1);
405
406         /* We don't need the memory allocated for the name and the password
407            in ruserpass anymore.  */
408         if (name != orig_name)
409           free ((char *) name);
410         if (pass != orig_pass)
411           free ((char *) pass);
412
413         if (read(s, &c, 1) != 1) {
414                 perror(*ahost);
415                 goto bad;
416         }
417         if (c != 0) {
418                 while (read(s, &c, 1) == 1) {
419                         (void) write(2, &c, 1);
420                         if (c == '\n')
421                                 break;
422                 }
423                 goto bad;
424         }
425         freeaddrinfo(res0);
426         return (s);
427 bad:
428         if (port)
429                 (void) close(*fd2p);
430         (void) close(s);
431         freeaddrinfo(res0);
432         return (-1);
433 }
434
435
436 int
437 rexec(char **ahost, int rport, const char *name, const char *pass, char *cmd, int *fd2p)
438 {
439         struct sockaddr_in sin, sin2, from;
440         struct hostent *hp;
441         u_short port;
442         int s, timo = 1, s3;
443         char c;
444         char *acct = NULL;
445
446         hp = gethostbyname(*ahost);
447         if (hp == 0) {
448                 herror(*ahost);
449                 return (-1);
450         }
451         *ahost = hp->h_name;
452         ruserpass(hp->h_name, &name, &pass, &acct);
453         if (acct != NULL)
454                 free(acct);
455 retry:
456         s = socket(AF_INET, SOCK_STREAM, 0);
457         if (s < 0) {
458                 perror("rexec: socket");
459                 return (-1);
460         }
461         sin.sin_family = hp->h_addrtype;
462         sin.sin_port = rport;
463         bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
464         if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
465                 if (errno == ECONNREFUSED && timo <= 16) {
466                         (void) close(s);
467                         sleep(timo);
468                         timo *= 2;
469                         goto retry;
470                 }
471                 perror(hp->h_name);
472                 return (-1);
473         }
474         if (fd2p == 0) {
475                 (void) write(s, "", 1);
476                 port = 0;
477         } else {
478                 char num[8];
479                 int s2, sin2len;
480
481                 s2 = socket(AF_INET, SOCK_STREAM, 0);
482                 if (s2 < 0) {
483                         (void) close(s);
484                         return (-1);
485                 }
486                 listen(s2, 1);
487                 sin2len = sizeof (sin2);
488                 if (getsockname(s2, (struct sockaddr *)&sin2, &sin2len) < 0 ||
489                   sin2len != sizeof (sin2)) {
490                         perror("getsockname");
491                         (void) close(s2);
492                         goto bad;
493                 }
494                 port = ntohs((u_short)sin2.sin_port);
495                 (void) sprintf(num, "%u", port);
496                 (void) write(s, num, strlen(num)+1);
497                 { int len = sizeof (from);
498                   s3 = accept(s2, (struct sockaddr *)&from, &len);
499                   close(s2);
500                   if (s3 < 0) {
501                         perror("accept");
502                         port = 0;
503                         goto bad;
504                   }
505                 }
506                 *fd2p = s3;
507         }
508         (void) write(s, name, strlen(name) + 1);
509         /* should public key encypt the password here */
510         (void) write(s, pass, strlen(pass) + 1);
511         (void) write(s, cmd, strlen(cmd) + 1);
512         if (read(s, &c, 1) != 1) {
513                 perror(*ahost);
514                 goto bad;
515         }
516         if (c != 0) {
517                 while (read(s, &c, 1) == 1) {
518                         (void) write(2, &c, 1);
519                         if (c == '\n')
520                                 break;
521                 }
522                 goto bad;
523         }
524         return (s);
525 bad:
526         if (port)
527                 (void) close(*fd2p);
528         (void) close(s);
529         return (-1);
530 }