1 | /*
|
---|
2 | * TNET A server program for MINIX which implements the TCP/IP
|
---|
3 | * suite of networking protocols. It is based on the
|
---|
4 | * TCP/IP code written by Phil Karn et al, as found in
|
---|
5 | * his NET package for Packet Radio communications.
|
---|
6 | *
|
---|
7 | * This module handles telnet option processing.
|
---|
8 | *
|
---|
9 | * Author: Michael Temari, <temari@temari.ae.ge.com> 01/13/93
|
---|
10 | *
|
---|
11 | */
|
---|
12 | #include <sys/types.h>
|
---|
13 | #include <string.h>
|
---|
14 | #include <fcntl.h>
|
---|
15 | #include <errno.h>
|
---|
16 | #include <unistd.h>
|
---|
17 | #include <termios.h>
|
---|
18 | #include "telnetd.h"
|
---|
19 | #include "telnet.h"
|
---|
20 | #include <stdio.h>
|
---|
21 | #include <sys/ioctl.h>
|
---|
22 |
|
---|
23 |
|
---|
24 | #define IN_DATA 0
|
---|
25 | #define IN_CR 1
|
---|
26 | #define IN_IAC 2
|
---|
27 | #define IN_IAC2 3
|
---|
28 | #define IN_SB 4
|
---|
29 |
|
---|
30 | _PROTOTYPE(static void dowill, (int c));
|
---|
31 | _PROTOTYPE(static void dowont, (int c));
|
---|
32 | _PROTOTYPE(static void dodo, (int c));
|
---|
33 | _PROTOTYPE(static void dodont, (int c));
|
---|
34 | _PROTOTYPE(static void respond, (int ack, int option));
|
---|
35 | _PROTOTYPE(static void respond_really, (int ack, int option));
|
---|
36 |
|
---|
37 | #define LASTTELOPT TELOPT_SGA
|
---|
38 |
|
---|
39 | static int r_winch = 0;
|
---|
40 |
|
---|
41 | static int TelROpts[LASTTELOPT+1];
|
---|
42 | static int TelLOpts[LASTTELOPT+1];
|
---|
43 |
|
---|
44 | static int telfdout;
|
---|
45 |
|
---|
46 | void tel_init()
|
---|
47 | {
|
---|
48 | int i;
|
---|
49 |
|
---|
50 | for(i = 0; i <= LASTTELOPT; i++) {
|
---|
51 | TelROpts[i] = 0;
|
---|
52 | TelLOpts[i] = 0;
|
---|
53 | }
|
---|
54 | }
|
---|
55 |
|
---|
56 | void telopt(fdout, what, option)
|
---|
57 | int fdout;
|
---|
58 | int what;
|
---|
59 | int option;
|
---|
60 | {
|
---|
61 | char buf[3];
|
---|
62 | int len;
|
---|
63 |
|
---|
64 | buf[0] = IAC;
|
---|
65 | buf[1] = what;
|
---|
66 | buf[2] = option;
|
---|
67 | len = 0;
|
---|
68 |
|
---|
69 | switch(what) {
|
---|
70 | case DO:
|
---|
71 | if(option <= LASTTELOPT) {
|
---|
72 | TelROpts[option] = 1;
|
---|
73 | len = 3;
|
---|
74 | } else if(option == TELOPT_WINCH && !r_winch) { r_winch = 1; len = 3; }
|
---|
75 | break;
|
---|
76 | case DONT:
|
---|
77 | if(option <= LASTTELOPT) {
|
---|
78 | TelROpts[option] = 1;
|
---|
79 | len = 3;
|
---|
80 | }
|
---|
81 | break;
|
---|
82 | case WILL:
|
---|
83 | if(option <= LASTTELOPT) {
|
---|
84 | TelLOpts[option] = 1;
|
---|
85 | len = 3;
|
---|
86 | }
|
---|
87 | break;
|
---|
88 | case WONT:
|
---|
89 | if(option <= LASTTELOPT) {
|
---|
90 | TelLOpts[option] = 1;
|
---|
91 | len = 3;
|
---|
92 | }
|
---|
93 | break;
|
---|
94 | }
|
---|
95 | if(len > 0)
|
---|
96 | (void) write(fdout, buf, len);
|
---|
97 | }
|
---|
98 |
|
---|
99 | int set_winsize(int fd, unsigned int cols, unsigned int rows)
|
---|
100 | {
|
---|
101 | struct winsize w;
|
---|
102 | memset(&w, 0, sizeof(w));
|
---|
103 | w.ws_col = cols;
|
---|
104 | w.ws_row = rows;
|
---|
105 | ioctl(fd, TIOCSWINSZ, (char *) &w);
|
---|
106 | }
|
---|
107 |
|
---|
108 | int tel_in(fdout, telout, buffer, len)
|
---|
109 | int fdout;
|
---|
110 | int telout;
|
---|
111 | char *buffer;
|
---|
112 | int len;
|
---|
113 | {
|
---|
114 | static int InState = IN_DATA;
|
---|
115 | static int ThisOpt = 0;
|
---|
116 | char *p;
|
---|
117 | char *p2;
|
---|
118 | int size;
|
---|
119 | int c;
|
---|
120 |
|
---|
121 | telfdout = telout;
|
---|
122 | p = p2 = buffer;
|
---|
123 | size = 0;
|
---|
124 |
|
---|
125 | while(len > 0) {
|
---|
126 | c = (unsigned char)*p++; len--;
|
---|
127 | switch(InState) {
|
---|
128 | case IN_CR:
|
---|
129 | InState = IN_DATA;
|
---|
130 | if(c == 0 || c == '\n')
|
---|
131 | break;
|
---|
132 | /* fall through */
|
---|
133 | case IN_DATA:
|
---|
134 | if(c == IAC) {
|
---|
135 | InState = IN_IAC;
|
---|
136 | break;
|
---|
137 | }
|
---|
138 | *p2++ = c; size++;
|
---|
139 | if(c == '\r') InState = IN_CR;
|
---|
140 | break;
|
---|
141 | case IN_IAC:
|
---|
142 | switch(c) {
|
---|
143 | case IAC:
|
---|
144 | *p2++ = c; size++;
|
---|
145 | InState = IN_DATA;
|
---|
146 | break;
|
---|
147 | case WILL:
|
---|
148 | case WONT:
|
---|
149 | case DO:
|
---|
150 | case DONT:
|
---|
151 | InState = IN_IAC2;
|
---|
152 | ThisOpt = c;
|
---|
153 | break;
|
---|
154 | case SB:
|
---|
155 | InState = IN_SB;
|
---|
156 | break;
|
---|
157 | case EOR:
|
---|
158 | case SE:
|
---|
159 | case NOP:
|
---|
160 | case BREAK:
|
---|
161 | case IP:
|
---|
162 | case AO:
|
---|
163 | case AYT:
|
---|
164 | case EC:
|
---|
165 | case EL:
|
---|
166 | case GA:
|
---|
167 | break;
|
---|
168 | default:
|
---|
169 | break;
|
---|
170 | }
|
---|
171 | break;
|
---|
172 | case IN_IAC2:
|
---|
173 | if(size > 0) {
|
---|
174 | write(fdout, buffer, size);
|
---|
175 | p2 = buffer;
|
---|
176 | size = 0;
|
---|
177 | }
|
---|
178 | InState = IN_DATA;
|
---|
179 | switch(ThisOpt) {
|
---|
180 | case WILL: dowill(c); break;
|
---|
181 | case WONT: dowont(c); break;
|
---|
182 | case DO: dodo(c); break;
|
---|
183 | case DONT: dodont(c); break;
|
---|
184 | }
|
---|
185 | break;
|
---|
186 | case IN_SB:
|
---|
187 | {
|
---|
188 | static int winchpos = -1;
|
---|
189 | /* Subnegotiation. */
|
---|
190 | if(winchpos >= 0) {
|
---|
191 | static unsigned int winchbuf[5], iacs = 0;
|
---|
192 | winchbuf[winchpos] = c;
|
---|
193 | /* IAC is escaped - unescape it. */
|
---|
194 | if(c == IAC) iacs++; else { iacs = 0; winchpos++; }
|
---|
195 | if(iacs == 2) { winchpos++; iacs = 0; }
|
---|
196 | if(winchpos >= 4) {
|
---|
197 | /* End of WINCH data. */
|
---|
198 | set_winsize(fdout,
|
---|
199 | (winchbuf[0] << 8) | winchbuf[1],
|
---|
200 | (winchbuf[2] << 8) | winchbuf[3]);
|
---|
201 | winchpos = -1;
|
---|
202 | }
|
---|
203 | } else {
|
---|
204 | static int lastiac = 0;
|
---|
205 | switch(c) {
|
---|
206 | case TELOPT_WINCH:
|
---|
207 | /* Start listening. */
|
---|
208 | winchpos = 0;
|
---|
209 | break;
|
---|
210 | case SE:
|
---|
211 | if(lastiac) InState = IN_DATA;
|
---|
212 | break;
|
---|
213 | default:
|
---|
214 | break;
|
---|
215 | }
|
---|
216 | if(c == IAC) lastiac = 1;
|
---|
217 | else lastiac = 0;
|
---|
218 |
|
---|
219 |
|
---|
220 | }
|
---|
221 | break;
|
---|
222 | }
|
---|
223 | }
|
---|
224 | }
|
---|
225 |
|
---|
226 | if(size > 0)
|
---|
227 | write(fdout, buffer, size);
|
---|
228 | }
|
---|
229 |
|
---|
230 | int tel_out(fdout, buf, size)
|
---|
231 | int fdout;
|
---|
232 | char *buf;
|
---|
233 | int size;
|
---|
234 | {
|
---|
235 | char *p;
|
---|
236 | int got_iac, len;
|
---|
237 |
|
---|
238 | p = buf;
|
---|
239 | while(size > 0) {
|
---|
240 | buf = p;
|
---|
241 | got_iac = 0;
|
---|
242 | if((p = (char *)memchr(buf, IAC, size)) != (char *)NULL) {
|
---|
243 | got_iac = 1;
|
---|
244 | p++;
|
---|
245 | } else
|
---|
246 | p = buf + size;
|
---|
247 | len = p - buf;
|
---|
248 | if(len > 0)
|
---|
249 | (void) write(fdout, buf, len);
|
---|
250 | if(got_iac)
|
---|
251 | (void) write(fdout, p - 1, 1);
|
---|
252 | size = size - len;
|
---|
253 | }
|
---|
254 | }
|
---|
255 |
|
---|
256 | static void dowill(c)
|
---|
257 | int c;
|
---|
258 | {
|
---|
259 | int ack;
|
---|
260 |
|
---|
261 | switch(c) {
|
---|
262 | case TELOPT_BINARY:
|
---|
263 | case TELOPT_ECHO:
|
---|
264 | case TELOPT_SGA:
|
---|
265 | if(TelROpts[c] == 1)
|
---|
266 | return;
|
---|
267 | TelROpts[c] = 1;
|
---|
268 | ack = DO;
|
---|
269 | break;
|
---|
270 | case TELOPT_WINCH:
|
---|
271 | if(r_winch) return;
|
---|
272 | r_winch = 1;
|
---|
273 | ack = DO;
|
---|
274 | respond_really(ack, c);
|
---|
275 | return;
|
---|
276 | default:
|
---|
277 | ack = DONT;
|
---|
278 | }
|
---|
279 |
|
---|
280 | respond(ack, c);
|
---|
281 | }
|
---|
282 |
|
---|
283 | static void dowont(c)
|
---|
284 | int c;
|
---|
285 | {
|
---|
286 | if(c <= LASTTELOPT) {
|
---|
287 | if(TelROpts[c] == 0)
|
---|
288 | return;
|
---|
289 | TelROpts[c] = 0;
|
---|
290 | }
|
---|
291 | respond(DONT, c);
|
---|
292 | }
|
---|
293 |
|
---|
294 | static void dodo(c)
|
---|
295 | int c;
|
---|
296 | {
|
---|
297 | int ack;
|
---|
298 |
|
---|
299 | switch(c) {
|
---|
300 | default:
|
---|
301 | ack = WONT;
|
---|
302 | }
|
---|
303 | respond(ack, c);
|
---|
304 | }
|
---|
305 |
|
---|
306 | static void dodont(c)
|
---|
307 | int c;
|
---|
308 | {
|
---|
309 | if(c <= LASTTELOPT) {
|
---|
310 | if(TelLOpts[c] == 0)
|
---|
311 | return;
|
---|
312 | TelLOpts[c] = 0;
|
---|
313 | }
|
---|
314 | respond(WONT, c);
|
---|
315 | }
|
---|
316 |
|
---|
317 | static void respond(ack, option)
|
---|
318 | int ack, option;
|
---|
319 | {
|
---|
320 | unsigned char c[3];
|
---|
321 |
|
---|
322 | c[0] = IAC;
|
---|
323 | c[1] = ack;
|
---|
324 | c[2] = option;
|
---|
325 | /* write(telfdout, c, 3); */
|
---|
326 | }
|
---|
327 |
|
---|
328 | static void respond_really(ack, option)
|
---|
329 | int ack, option;
|
---|
330 | {
|
---|
331 | unsigned char c[3];
|
---|
332 |
|
---|
333 | c[0] = IAC;
|
---|
334 | c[1] = ack;
|
---|
335 | c[2] = option;
|
---|
336 | write(telfdout, c, 3);
|
---|
337 | }
|
---|