1 /* 2 * Copyright (c) 1989, 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. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #if 0 31 #ifndef lint 32 static const char sccsid[] = "@(#)slc.c 8.2 (Berkeley) 5/30/95"; 33 #endif 34 #endif 35 #include <sys/cdefs.h> 36 __FBSDID("$FreeBSD$"); 37 38 #include "telnetd.h" 39 40 #ifdef LINEMODE 41 /* 42 * local variables 43 */ 44 static unsigned char *def_slcbuf = (unsigned char *)0; 45 static int def_slclen = 0; 46 static int slcchange; /* change to slc is requested */ 47 static unsigned char *slcptr; /* pointer into slc buffer */ 48 static unsigned char slcbuf[NSLC*6]; /* buffer for slc negotiation */ 49 50 /* 51 * send_slc 52 * 53 * Write out the current special characters to the client. 54 */ 55 void 56 send_slc(void) 57 { 58 int i; 59 60 /* 61 * Send out list of triplets of special characters 62 * to client. We only send info on the characters 63 * that are currently supported. 64 */ 65 for (i = 1; i <= NSLC; i++) { 66 if ((slctab[i].defset.flag & SLC_LEVELBITS) == SLC_NOSUPPORT) 67 continue; 68 add_slc((unsigned char)i, slctab[i].current.flag, 69 slctab[i].current.val); 70 } 71 72 } /* end of send_slc */ 73 74 /* 75 * default_slc 76 * 77 * Set pty special characters to all the defaults. 78 */ 79 static void 80 default_slc(void) 81 { 82 int i; 83 84 for (i = 1; i <= NSLC; i++) { 85 slctab[i].current.val = slctab[i].defset.val; 86 if (slctab[i].current.val == (cc_t)(_POSIX_VDISABLE)) 87 slctab[i].current.flag = SLC_NOSUPPORT; 88 else 89 slctab[i].current.flag = slctab[i].defset.flag; 90 if (slctab[i].sptr) { 91 *(slctab[i].sptr) = slctab[i].defset.val; 92 } 93 } 94 slcchange = 1; 95 96 } /* end of default_slc */ 97 #endif /* LINEMODE */ 98 99 /* 100 * get_slc_defaults 101 * 102 * Initialize the slc mapping table. 103 */ 104 void 105 get_slc_defaults(void) 106 { 107 int i; 108 109 init_termbuf(); 110 111 for (i = 1; i <= NSLC; i++) { 112 slctab[i].defset.flag = 113 spcset(i, &slctab[i].defset.val, &slctab[i].sptr); 114 slctab[i].current.flag = SLC_NOSUPPORT; 115 slctab[i].current.val = 0; 116 } 117 118 } /* end of get_slc_defaults */ 119 120 #ifdef LINEMODE 121 /* 122 * add_slc 123 * 124 * Add an slc triplet to the slc buffer. 125 */ 126 void 127 add_slc(char func, char flag, cc_t val) 128 { 129 130 if ((*slcptr++ = (unsigned char)func) == 0xff) 131 *slcptr++ = 0xff; 132 133 if ((*slcptr++ = (unsigned char)flag) == 0xff) 134 *slcptr++ = 0xff; 135 136 if ((*slcptr++ = (unsigned char)val) == 0xff) 137 *slcptr++ = 0xff; 138 139 } /* end of add_slc */ 140 141 /* 142 * start_slc 143 * 144 * Get ready to process incoming slc's and respond to them. 145 * 146 * The parameter getit is non-zero if it is necessary to grab a copy 147 * of the terminal control structures. 148 */ 149 void 150 start_slc(int getit) 151 { 152 153 slcchange = 0; 154 if (getit) 155 init_termbuf(); 156 (void) sprintf((char *)slcbuf, "%c%c%c%c", 157 IAC, SB, TELOPT_LINEMODE, LM_SLC); 158 slcptr = slcbuf + 4; 159 160 } /* end of start_slc */ 161 162 /* 163 * end_slc 164 * 165 * Finish up the slc negotiation. If something to send, then send it. 166 */ 167 int 168 end_slc(unsigned char **bufp) 169 { 170 int len; 171 172 /* 173 * If a change has occured, store the new terminal control 174 * structures back to the terminal driver. 175 */ 176 if (slcchange) { 177 set_termbuf(); 178 } 179 180 /* 181 * If the pty state has not yet been fully processed and there is a 182 * deferred slc request from the client, then do not send any 183 * sort of slc negotiation now. We will respond to the client's 184 * request very soon. 185 */ 186 if (def_slcbuf && (terminit() == 0)) { 187 return(0); 188 } 189 190 if (slcptr > (slcbuf + 4)) { 191 if (bufp) { 192 *bufp = &slcbuf[4]; 193 return(slcptr - slcbuf - 4); 194 } else { 195 (void) sprintf((char *)slcptr, "%c%c", IAC, SE); 196 slcptr += 2; 197 len = slcptr - slcbuf; 198 output_datalen(slcbuf, len); 199 netflush(); /* force it out immediately */ 200 DIAG(TD_OPTIONS, printsub('>', slcbuf+2, len-2);); 201 } 202 } 203 return (0); 204 205 } /* end of end_slc */ 206 207 /* 208 * process_slc 209 * 210 * Figure out what to do about the client's slc 211 */ 212 void 213 process_slc(unsigned char func, unsigned char flag, cc_t val) 214 { 215 int hislevel, mylevel, ack; 216 217 /* 218 * Ensure that we know something about this function 219 */ 220 if (func > NSLC) { 221 add_slc(func, SLC_NOSUPPORT, 0); 222 return; 223 } 224 225 /* 226 * Process the special case requests of 0 SLC_DEFAULT 0 227 * and 0 SLC_VARIABLE 0. Be a little forgiving here, don't 228 * worry about whether the value is actually 0 or not. 229 */ 230 if (func == 0) { 231 if ((flag = flag & SLC_LEVELBITS) == SLC_DEFAULT) { 232 default_slc(); 233 send_slc(); 234 } else if (flag == SLC_VARIABLE) { 235 send_slc(); 236 } 237 return; 238 } 239 240 /* 241 * Appears to be a function that we know something about. So 242 * get on with it and see what we know. 243 */ 244 245 hislevel = flag & SLC_LEVELBITS; 246 mylevel = slctab[func].current.flag & SLC_LEVELBITS; 247 ack = flag & SLC_ACK; 248 /* 249 * ignore the command if: 250 * the function value and level are the same as what we already have; 251 * or the level is the same and the ack bit is set 252 */ 253 if (hislevel == mylevel && (val == slctab[func].current.val || ack)) { 254 return; 255 } else if (ack) { 256 /* 257 * If we get here, we got an ack, but the levels don't match. 258 * This shouldn't happen. If it does, it is probably because 259 * we have sent two requests to set a variable without getting 260 * a response between them, and this is the first response. 261 * So, ignore it, and wait for the next response. 262 */ 263 return; 264 } else { 265 change_slc(func, flag, val); 266 } 267 268 } /* end of process_slc */ 269 270 /* 271 * change_slc 272 * 273 * Process a request to change one of our special characters. 274 * Compare client's request with what we are capable of supporting. 275 */ 276 void 277 change_slc(char func, char flag, cc_t val) 278 { 279 int hislevel, mylevel; 280 281 hislevel = flag & SLC_LEVELBITS; 282 mylevel = slctab[(int)func].defset.flag & SLC_LEVELBITS; 283 /* 284 * If client is setting a function to NOSUPPORT 285 * or DEFAULT, then we can easily and directly 286 * accomodate the request. 287 */ 288 if (hislevel == SLC_NOSUPPORT) { 289 slctab[(int)func].current.flag = flag; 290 slctab[(int)func].current.val = (cc_t)_POSIX_VDISABLE; 291 flag |= SLC_ACK; 292 add_slc(func, flag, val); 293 return; 294 } 295 if (hislevel == SLC_DEFAULT) { 296 /* 297 * Special case here. If client tells us to use 298 * the default on a function we don't support, then 299 * return NOSUPPORT instead of what we may have as a 300 * default level of DEFAULT. 301 */ 302 if (mylevel == SLC_DEFAULT) { 303 slctab[(int)func].current.flag = SLC_NOSUPPORT; 304 } else { 305 slctab[(int)func].current.flag = slctab[(int)func].defset.flag; 306 } 307 slctab[(int)func].current.val = slctab[(int)func].defset.val; 308 add_slc(func, slctab[(int)func].current.flag, 309 slctab[(int)func].current.val); 310 return; 311 } 312 313 /* 314 * Client wants us to change to a new value or he 315 * is telling us that he can't change to our value. 316 * Some of the slc's we support and can change, 317 * some we do support but can't change, 318 * and others we don't support at all. 319 * If we can change it then we have a pointer to 320 * the place to put the new value, so change it, 321 * otherwise, continue the negotiation. 322 */ 323 if (slctab[(int)func].sptr) { 324 /* 325 * We can change this one. 326 */ 327 slctab[(int)func].current.val = val; 328 *(slctab[(int)func].sptr) = val; 329 slctab[(int)func].current.flag = flag; 330 flag |= SLC_ACK; 331 slcchange = 1; 332 add_slc(func, flag, val); 333 } else { 334 /* 335 * It is not possible for us to support this 336 * request as he asks. 337 * 338 * If our level is DEFAULT, then just ack whatever was 339 * sent. 340 * 341 * If he can't change and we can't change, 342 * then degenerate to NOSUPPORT. 343 * 344 * Otherwise we send our level back to him, (CANTCHANGE 345 * or NOSUPPORT) and if CANTCHANGE, send 346 * our value as well. 347 */ 348 if (mylevel == SLC_DEFAULT) { 349 slctab[(int)func].current.flag = flag; 350 slctab[(int)func].current.val = val; 351 flag |= SLC_ACK; 352 } else if (hislevel == SLC_CANTCHANGE && 353 mylevel == SLC_CANTCHANGE) { 354 flag &= ~SLC_LEVELBITS; 355 flag |= SLC_NOSUPPORT; 356 slctab[(int)func].current.flag = flag; 357 } else { 358 flag &= ~SLC_LEVELBITS; 359 flag |= mylevel; 360 slctab[(int)func].current.flag = flag; 361 if (mylevel == SLC_CANTCHANGE) { 362 slctab[(int)func].current.val = 363 slctab[(int)func].defset.val; 364 val = slctab[(int)func].current.val; 365 } 366 } 367 add_slc(func, flag, val); 368 } 369 370 } /* end of change_slc */ 371 372 #if defined(USE_TERMIO) && (VEOF == VMIN) 373 cc_t oldeofc = '\004'; 374 #endif 375 376 /* 377 * check_slc 378 * 379 * Check the special characters in use and notify the client if any have 380 * changed. Only those characters that are capable of being changed are 381 * likely to have changed. If a local change occurs, kick the support level 382 * and flags up to the defaults. 383 */ 384 void 385 check_slc(void) 386 { 387 int i; 388 389 for (i = 1; i <= NSLC; i++) { 390 #if defined(USE_TERMIO) && (VEOF == VMIN) 391 /* 392 * In a perfect world this would be a neat little 393 * function. But in this world, we should not notify 394 * client of changes to the VEOF char when 395 * ICANON is off, because it is not representing 396 * a special character. 397 */ 398 if (i == SLC_EOF) { 399 if (!tty_isediting()) 400 continue; 401 else if (slctab[i].sptr) 402 oldeofc = *(slctab[i].sptr); 403 } 404 #endif /* defined(USE_TERMIO) && defined(SYSV_TERMIO) */ 405 if (slctab[i].sptr && 406 (*(slctab[i].sptr) != slctab[i].current.val)) { 407 slctab[i].current.val = *(slctab[i].sptr); 408 if (*(slctab[i].sptr) == (cc_t)_POSIX_VDISABLE) 409 slctab[i].current.flag = SLC_NOSUPPORT; 410 else 411 slctab[i].current.flag = slctab[i].defset.flag; 412 add_slc((unsigned char)i, slctab[i].current.flag, 413 slctab[i].current.val); 414 } 415 } 416 } /* check_slc */ 417 418 /* 419 * do_opt_slc 420 * 421 * Process an slc option buffer. Defer processing of incoming slc's 422 * until after the terminal state has been processed. Save the first slc 423 * request that comes along, but discard all others. 424 * 425 * ptr points to the beginning of the buffer, len is the length. 426 */ 427 void 428 do_opt_slc(unsigned char *ptr, int len) 429 { 430 unsigned char func, flag; 431 cc_t val; 432 unsigned char *end = ptr + len; 433 434 if (terminit()) { /* go ahead */ 435 while (ptr < end) { 436 func = *ptr++; 437 if (ptr >= end) break; 438 flag = *ptr++; 439 if (ptr >= end) break; 440 val = (cc_t)*ptr++; 441 442 process_slc(func, flag, val); 443 444 } 445 } else { 446 /* 447 * save this slc buffer if it is the first, otherwise dump 448 * it. 449 */ 450 if (def_slcbuf == (unsigned char *)0) { 451 def_slclen = len; 452 def_slcbuf = (unsigned char *)malloc((unsigned)len); 453 if (def_slcbuf == (unsigned char *)0) 454 return; /* too bad */ 455 memmove(def_slcbuf, ptr, len); 456 } 457 } 458 459 } /* end of do_opt_slc */ 460 461 /* 462 * deferslc 463 * 464 * Do slc stuff that was deferred. 465 */ 466 void 467 deferslc(void) 468 { 469 if (def_slcbuf) { 470 start_slc(1); 471 do_opt_slc(def_slcbuf, def_slclen); 472 (void) end_slc(0); 473 free(def_slcbuf); 474 def_slcbuf = (unsigned char *)0; 475 def_slclen = 0; 476 } 477 478 } /* end of deferslc */ 479 480 #endif /* LINEMODE */ 481