Initial import from FreeBSD RELENG_4:
[dragonfly.git] / usr.sbin / faithd / rsh.c
1 /*      $KAME: rsh.c,v 1.7 2001/09/05 01:10:30 itojun Exp $     */
2
3 /*
4  * Copyright (C) 1997 and 1998 WIDE Project.
5  * 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 project 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 PROJECT 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 PROJECT 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  * $FreeBSD: src/usr.sbin/faithd/rsh.c,v 1.2.2.4 2002/04/28 05:40:29 suz Exp $
32  */
33
34 #include <sys/param.h>
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <sys/ioctl.h>
38 #include <sys/time.h>
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <syslog.h>
44 #include <unistd.h>
45 #include <errno.h>
46
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
49 #include <netdb.h>
50
51 #include "faithd.h"
52
53 char rshbuf[MSS];
54
55 int s_ctl, s_ctl6, s_rcv, s_snd;
56 int half;
57
58 void
59 rsh_relay(int s_src, int s_dst)
60 {
61         ssize_t n;
62         fd_set readfds;
63         int error;
64         struct timeval tv;
65
66         FD_ZERO(&readfds);
67         FD_SET(s_src, &readfds);
68         tv.tv_sec = FAITH_TIMEOUT;
69         tv.tv_usec = 0;
70         error = select(256, &readfds, NULL, NULL, &tv);
71         if (error == -1)
72                 exit_failure("select %d: %s", s_src, strerror(errno));
73         else if (error == 0)
74                 exit_failure("connection timeout");
75
76         n = read(s_src, rshbuf, sizeof(rshbuf));
77         if (rshbuf[0] != 0) {
78                 rsh_dual_relay(s_src, s_dst);
79                 /* NOTREACHED */
80         }
81         write(s_dst, rshbuf, n);
82         tcp_relay(s_src, s_dst, "rsh");
83                 /* NOTREACHED */
84 }
85
86 static void
87 relay(int src, int dst)
88 {
89         int error;
90         ssize_t n;      
91         int atmark;
92
93         error = ioctl(s_rcv, SIOCATMARK, &atmark);
94         if (error != -1 && atmark == 1) {
95                 n = read(s_rcv, rshbuf, 1);
96                 if (n == 1)
97                         send(s_snd, rshbuf, 1, MSG_OOB);
98                 return;
99         }
100
101         n = read(s_rcv, rshbuf, sizeof(rshbuf));
102
103         switch (n) {
104         case -1:
105                 exit_failure("%s", strerror(errno));
106         case 0:
107                 if (s_rcv == src) {
108                         /* half close */
109                         shutdown(dst, 1);
110                         half = YES;
111                         break;
112                 }
113                 close(src);
114                 close(dst);
115                 close(s_ctl);
116                 close(s_ctl6);                  
117                 exit_success("terminating rsh/contorol connections");
118                 break;
119         default:
120                 write(s_snd, rshbuf, n);
121         }
122 }
123
124 void
125 rsh_dual_relay(int s_src, int s_dst)
126 {
127         fd_set readfds;
128         int len, s_wld, error;
129         struct sockaddr_storage ctladdr6;
130         struct sockaddr_storage ctladdr;
131         int port6 = 0, lport, lport6;
132         char *p;
133         struct timeval tv;
134         struct sockaddr *sa;
135
136         half = NO;
137         s_rcv = s_src;
138         s_snd = s_dst;
139         syslog(LOG_INFO, "starting rsh connection");
140
141         for (p = rshbuf; *p; p++)
142                 port6 = port6 * 10 + *p - '0';
143
144         len = sizeof(ctladdr6);
145         getpeername(s_src, (struct sockaddr *)&ctladdr6, &len);
146         if (((struct sockaddr *)&ctladdr6)->sa_family == AF_INET6)
147                 ((struct sockaddr_in6 *)&ctladdr6)->sin6_port = htons(port6);
148         else
149                 ((struct sockaddr_in *)&ctladdr6)->sin_port = htons(port6);
150
151         s_wld = rresvport(&lport);
152         if (s_wld == -1) goto bad;
153         error = listen(s_wld, 1);
154         if (error == -1) goto bad;
155         snprintf(rshbuf, sizeof(rshbuf), "%d", lport);
156         write(s_dst, rshbuf, strlen(rshbuf)+1);
157
158         len = sizeof(ctladdr);
159         s_ctl = accept(s_wld, (struct sockaddr *)&ctladdr, &len);
160         if (s_ctl == -1) goto bad;
161         close(s_wld);
162         
163         sa = (struct sockaddr *)&ctladdr6;
164         s_ctl6 = rresvport_af(&lport6, sa->sa_family);
165         if (s_ctl6 == -1) goto bad;
166         error = connect(s_ctl6, sa, sa->sa_len);
167         if (error == -1) goto bad;
168         
169         syslog(LOG_INFO, "starting rsh control connection");
170
171         for (;;) {
172                 FD_ZERO(&readfds);
173                 if (half == NO)
174                         FD_SET(s_src, &readfds);
175                 FD_SET(s_dst, &readfds);
176                 FD_SET(s_ctl, &readfds);
177                 FD_SET(s_ctl6, &readfds);
178                 tv.tv_sec = FAITH_TIMEOUT;
179                 tv.tv_usec = 0;
180
181                 error = select(256, &readfds, NULL, NULL, &tv);
182                 if (error == -1)
183                         exit_failure("select 4 sockets: %s", strerror(errno));
184                 else if (error == 0)
185                         exit_failure("connection timeout");
186
187                 if (half == NO && FD_ISSET(s_src, &readfds)) {
188                         s_rcv = s_src;
189                         s_snd = s_dst;
190                         relay(s_src, s_dst);
191                 }
192                 if (FD_ISSET(s_dst, &readfds)) {
193                         s_rcv = s_dst;
194                         s_snd = s_src;
195                         relay(s_src, s_dst);
196                 }
197                 if (FD_ISSET(s_ctl, &readfds)) {
198                         s_rcv = s_ctl;
199                         s_snd = s_ctl6;
200                         relay(s_src, s_dst);
201                 }
202                 if (FD_ISSET(s_ctl6, &readfds)) {
203                         s_rcv = s_ctl6;
204                         s_snd = s_ctl;
205                         relay(s_src, s_dst);
206                 }
207         }
208         /* NOTREACHED */
209
210  bad:
211         exit_failure("%s", strerror(errno));
212 }