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