slc.c revision 29089
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 35static char sccsid[] = "@(#)slc.c 8.2 (Berkeley) 5/30/95"; 36#endif /* not lint */ 37 38#include "telnetd.h" 39 40#ifdef LINEMODE 41/* 42 * local varibles 43 */ 44static unsigned char *def_slcbuf = (unsigned char *)0; 45static int def_slclen = 0; 46static int slcchange; /* change to slc is requested */ 47static unsigned char *slcptr; /* pointer into slc buffer */ 48static 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 56send_slc() 57{ 58 register 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 void 80default_slc() 81{ 82 register 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 105get_slc_defaults() 106{ 107 register 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 127add_slc(func, flag, val) 128 register char func, flag; 129 register cc_t val; 130{ 131 132 if ((*slcptr++ = (unsigned char)func) == 0xff) 133 *slcptr++ = 0xff; 134 135 if ((*slcptr++ = (unsigned char)flag) == 0xff) 136 *slcptr++ = 0xff; 137 138 if ((*slcptr++ = (unsigned char)val) == 0xff) 139 *slcptr++ = 0xff; 140 141} /* end of add_slc */ 142 143/* 144 * start_slc 145 * 146 * Get ready to process incoming slc's and respond to them. 147 * 148 * The parameter getit is non-zero if it is necessary to grab a copy 149 * of the terminal control structures. 150 */ 151 void 152start_slc(getit) 153 register int getit; 154{ 155 156 slcchange = 0; 157 if (getit) 158 init_termbuf(); 159 (void) sprintf((char *)slcbuf, "%c%c%c%c", 160 IAC, SB, TELOPT_LINEMODE, LM_SLC); 161 slcptr = slcbuf + 4; 162 163} /* end of start_slc */ 164 165/* 166 * end_slc 167 * 168 * Finish up the slc negotiation. If something to send, then send it. 169 */ 170 int 171end_slc(bufp) 172 register unsigned char **bufp; 173{ 174 register int len; 175 void netflush(); 176 177 /* 178 * If a change has occured, store the new terminal control 179 * structures back to the terminal driver. 180 */ 181 if (slcchange) { 182 set_termbuf(); 183 } 184 185 /* 186 * If the pty state has not yet been fully processed and there is a 187 * deferred slc request from the client, then do not send any 188 * sort of slc negotiation now. We will respond to the client's 189 * request very soon. 190 */ 191 if (def_slcbuf && (terminit() == 0)) { 192 return(0); 193 } 194 195 if (slcptr > (slcbuf + 4)) { 196 if (bufp) { 197 *bufp = &slcbuf[4]; 198 return(slcptr - slcbuf - 4); 199 } else { 200 (void) sprintf((char *)slcptr, "%c%c", IAC, SE); 201 slcptr += 2; 202 len = slcptr - slcbuf; 203 writenet(slcbuf, len); 204 netflush(); /* force it out immediately */ 205 DIAG(TD_OPTIONS, printsub('>', slcbuf+2, len-2);); 206 } 207 } 208 return (0); 209 210} /* end of end_slc */ 211 212/* 213 * process_slc 214 * 215 * Figure out what to do about the client's slc 216 */ 217 void 218process_slc(func, flag, val) 219 register unsigned char func, flag; 220 register cc_t val; 221{ 222 register int hislevel, mylevel, ack; 223 224 /* 225 * Ensure that we know something about this function 226 */ 227 if (func > NSLC) { 228 add_slc(func, SLC_NOSUPPORT, 0); 229 return; 230 } 231 232 /* 233 * Process the special case requests of 0 SLC_DEFAULT 0 234 * and 0 SLC_VARIABLE 0. Be a little forgiving here, don't 235 * worry about whether the value is actually 0 or not. 236 */ 237 if (func == 0) { 238 if ((flag = flag & SLC_LEVELBITS) == SLC_DEFAULT) { 239 default_slc(); 240 send_slc(); 241 } else if (flag == SLC_VARIABLE) { 242 send_slc(); 243 } 244 return; 245 } 246 247 /* 248 * Appears to be a function that we know something about. So 249 * get on with it and see what we know. 250 */ 251 252 hislevel = flag & SLC_LEVELBITS; 253 mylevel = slctab[func].current.flag & SLC_LEVELBITS; 254 ack = flag & SLC_ACK; 255 /* 256 * ignore the command if: 257 * the function value and level are the same as what we already have; 258 * or the level is the same and the ack bit is set 259 */ 260 if (hislevel == mylevel && (val == slctab[func].current.val || ack)) { 261 return; 262 } else if (ack) { 263 /* 264 * If we get here, we got an ack, but the levels don't match. 265 * This shouldn't happen. If it does, it is probably because 266 * we have sent two requests to set a variable without getting 267 * a response between them, and this is the first response. 268 * So, ignore it, and wait for the next response. 269 */ 270 return; 271 } else { 272 change_slc(func, flag, val); 273 } 274 275} /* end of process_slc */ 276 277/* 278 * change_slc 279 * 280 * Process a request to change one of our special characters. 281 * Compare client's request with what we are capable of supporting. 282 */ 283 void 284change_slc(func, flag, val) 285 register char func, flag; 286 register cc_t val; 287{ 288 register int hislevel, mylevel; 289 290 hislevel = flag & SLC_LEVELBITS; 291 mylevel = slctab[func].defset.flag & SLC_LEVELBITS; 292 /* 293 * If client is setting a function to NOSUPPORT 294 * or DEFAULT, then we can easily and directly 295 * accomodate the request. 296 */ 297 if (hislevel == SLC_NOSUPPORT) { 298 slctab[func].current.flag = flag; 299 slctab[func].current.val = (cc_t)_POSIX_VDISABLE; 300 flag |= SLC_ACK; 301 add_slc(func, flag, val); 302 return; 303 } 304 if (hislevel == SLC_DEFAULT) { 305 /* 306 * Special case here. If client tells us to use 307 * the default on a function we don't support, then 308 * return NOSUPPORT instead of what we may have as a 309 * default level of DEFAULT. 310 */ 311 if (mylevel == SLC_DEFAULT) { 312 slctab[func].current.flag = SLC_NOSUPPORT; 313 } else { 314 slctab[func].current.flag = slctab[func].defset.flag; 315 } 316 slctab[func].current.val = slctab[func].defset.val; 317 add_slc(func, slctab[func].current.flag, 318 slctab[func].current.val); 319 return; 320 } 321 322 /* 323 * Client wants us to change to a new value or he 324 * is telling us that he can't change to our value. 325 * Some of the slc's we support and can change, 326 * some we do support but can't change, 327 * and others we don't support at all. 328 * If we can change it then we have a pointer to 329 * the place to put the new value, so change it, 330 * otherwise, continue the negotiation. 331 */ 332 if (slctab[func].sptr) { 333 /* 334 * We can change this one. 335 */ 336 slctab[func].current.val = val; 337 *(slctab[func].sptr) = val; 338 slctab[func].current.flag = flag; 339 flag |= SLC_ACK; 340 slcchange = 1; 341 add_slc(func, flag, val); 342 } else { 343 /* 344 * It is not possible for us to support this 345 * request as he asks. 346 * 347 * If our level is DEFAULT, then just ack whatever was 348 * sent. 349 * 350 * If he can't change and we can't change, 351 * then degenerate to NOSUPPORT. 352 * 353 * Otherwise we send our level back to him, (CANTCHANGE 354 * or NOSUPPORT) and if CANTCHANGE, send 355 * our value as well. 356 */ 357 if (mylevel == SLC_DEFAULT) { 358 slctab[func].current.flag = flag; 359 slctab[func].current.val = val; 360 flag |= SLC_ACK; 361 } else if (hislevel == SLC_CANTCHANGE && 362 mylevel == SLC_CANTCHANGE) { 363 flag &= ~SLC_LEVELBITS; 364 flag |= SLC_NOSUPPORT; 365 slctab[func].current.flag = flag; 366 } else { 367 flag &= ~SLC_LEVELBITS; 368 flag |= mylevel; 369 slctab[func].current.flag = flag; 370 if (mylevel == SLC_CANTCHANGE) { 371 slctab[func].current.val = 372 slctab[func].defset.val; 373 val = slctab[func].current.val; 374 } 375 } 376 add_slc(func, flag, val); 377 } 378 379} /* end of change_slc */ 380 381#if defined(USE_TERMIO) && (VEOF == VMIN) 382cc_t oldeofc = '\004'; 383#endif 384 385/* 386 * check_slc 387 * 388 * Check the special characters in use and notify the client if any have 389 * changed. Only those characters that are capable of being changed are 390 * likely to have changed. If a local change occurs, kick the support level 391 * and flags up to the defaults. 392 */ 393 void 394check_slc() 395{ 396 register int i; 397 398 for (i = 1; i <= NSLC; i++) { 399#if defined(USE_TERMIO) && (VEOF == VMIN) 400 /* 401 * In a perfect world this would be a neat little 402 * function. But in this world, we should not notify 403 * client of changes to the VEOF char when 404 * ICANON is off, because it is not representing 405 * a special character. 406 */ 407 if (i == SLC_EOF) { 408 if (!tty_isediting()) 409 continue; 410 else if (slctab[i].sptr) 411 oldeofc = *(slctab[i].sptr); 412 } 413#endif /* defined(USE_TERMIO) && defined(SYSV_TERMIO) */ 414 if (slctab[i].sptr && 415 (*(slctab[i].sptr) != slctab[i].current.val)) { 416 slctab[i].current.val = *(slctab[i].sptr); 417 if (*(slctab[i].sptr) == (cc_t)_POSIX_VDISABLE) 418 slctab[i].current.flag = SLC_NOSUPPORT; 419 else 420 slctab[i].current.flag = slctab[i].defset.flag; 421 add_slc((unsigned char)i, slctab[i].current.flag, 422 slctab[i].current.val); 423 } 424 } 425} /* check_slc */ 426 427/* 428 * do_opt_slc 429 * 430 * Process an slc option buffer. Defer processing of incoming slc's 431 * until after the terminal state has been processed. Save the first slc 432 * request that comes along, but discard all others. 433 * 434 * ptr points to the beginning of the buffer, len is the length. 435 */ 436 void 437do_opt_slc(ptr, len) 438 register unsigned char *ptr; 439 register int len; 440{ 441 register unsigned char func, flag; 442 cc_t val; 443 register unsigned char *end = ptr + len; 444 445 if (terminit()) { /* go ahead */ 446 while (ptr < end) { 447 func = *ptr++; 448 if (ptr >= end) break; 449 flag = *ptr++; 450 if (ptr >= end) break; 451 val = (cc_t)*ptr++; 452 453 process_slc(func, flag, val); 454 455 } 456 } else { 457 /* 458 * save this slc buffer if it is the first, otherwise dump 459 * it. 460 */ 461 if (def_slcbuf == (unsigned char *)0) { 462 def_slclen = len; 463 def_slcbuf = (unsigned char *)malloc((unsigned)len); 464 if (def_slcbuf == (unsigned char *)0) 465 return; /* too bad */ 466 memmove(def_slcbuf, ptr, len); 467 } 468 } 469 470} /* end of do_opt_slc */ 471 472/* 473 * deferslc 474 * 475 * Do slc stuff that was deferred. 476 */ 477 void 478deferslc() 479{ 480 if (def_slcbuf) { 481 start_slc(1); 482 do_opt_slc(def_slcbuf, def_slclen); 483 (void) end_slc(0); 484 free(def_slcbuf); 485 def_slcbuf = (unsigned char *)0; 486 def_slclen = 0; 487 } 488 489} /* end of deferslc */ 490 491#endif /* LINEMODE */ 492