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