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