[9] | 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 | }
|
---|