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