1 /* $NetBSD: slc.c,v 1.15 2006/11/24 19:46:58 christos 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. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)slc.c 8.1 (Berkeley) 6/4/93"; 36 #else 37 __RCSID("$NetBSD: slc.c,v 1.15 2006/11/24 19:46:58 christos Exp $"); 38 #endif 39 #endif /* not lint */ 40 41 #include "telnetd.h" 42 43 #ifdef LINEMODE 44 /* 45 * local varibles 46 */ 47 static unsigned char *def_slcbuf = (unsigned char *)0; 48 static int def_slclen = 0; 49 static int slcchange; /* change to slc is requested */ 50 static unsigned char *slcptr; /* pointer into slc buffer */ 51 static unsigned char slcbuf[NSLC*6]; /* buffer for slc negotiation */ 52 53 void default_slc(void); 54 void process_slc(u_int, u_int, cc_t); 55 56 /* 57 * send_slc 58 * 59 * Write out the current special characters to the client. 60 */ 61 void 62 send_slc(void) 63 { 64 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(void) 87 { 88 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(void) 112 { 113 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(char func, char flag, cc_t val) 134 { 135 136 if ((*slcptr++ = (unsigned char)func) == 0xff) 137 *slcptr++ = 0xff; 138 139 if ((*slcptr++ = (unsigned char)flag) == 0xff) 140 *slcptr++ = 0xff; 141 142 if ((*slcptr++ = (unsigned char)val) == 0xff) 143 *slcptr++ = 0xff; 144 145 } /* end of add_slc */ 146 147 /* 148 * start_slc 149 * 150 * Get ready to process incoming slc's and respond to them. 151 * 152 * The parameter getit is non-zero if it is necessary to grab a copy 153 * of the terminal control structures. 154 */ 155 void 156 start_slc(int getit) 157 { 158 159 slcchange = 0; 160 if (getit) 161 init_termbuf(); 162 (void)snprintf((char *)slcbuf, sizeof slcbuf, "%c%c%c%c", 163 IAC, SB, TELOPT_LINEMODE, LM_SLC); 164 slcptr = slcbuf + 4; 165 166 } /* end of start_slc */ 167 168 /* 169 * end_slc 170 * 171 * Finish up the slc negotiation. If something to send, then send it. 172 */ 173 int 174 end_slc(unsigned char **bufp) 175 { 176 int len; 177 178 /* 179 * If a change has occurred, 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) snprintf((char *)slcptr, 202 sizeof(slcbuf) - (slcptr - slcbuf), "%c%c", 203 IAC, SE); 204 slcptr += 2; 205 len = slcptr - slcbuf; 206 writenet(slcbuf, len); 207 netflush(); /* force it out immediately */ 208 DIAG(TD_OPTIONS, printsub('>', slcbuf+2, len-2);); 209 } 210 } 211 return (0); 212 213 } /* end of end_slc */ 214 215 /* 216 * process_slc 217 * 218 * Figure out what to do about the client's slc 219 */ 220 void 221 process_slc(u_int func, u_int flag, cc_t val) 222 { 223 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(int func, int flag, cc_t val) 286 { 287 int hislevel, mylevel; 288 289 hislevel = flag & SLC_LEVELBITS; 290 mylevel = slctab[func].defset.flag & SLC_LEVELBITS; 291 /* 292 * If client is setting a function to NOSUPPORT 293 * or DEFAULT, then we can easily and directly 294 * accommodate the request. 295 */ 296 if (hislevel == SLC_NOSUPPORT) { 297 slctab[func].current.flag = flag; 298 slctab[func].current.val = (cc_t)_POSIX_VDISABLE; 299 flag |= SLC_ACK; 300 add_slc(func, flag, val); 301 return; 302 } 303 if (hislevel == SLC_DEFAULT) { 304 /* 305 * Special case here. If client tells us to use 306 * the default on a function we don't support, then 307 * return NOSUPPORT instead of what we may have as a 308 * default level of DEFAULT. 309 */ 310 if (mylevel == SLC_DEFAULT) { 311 slctab[func].current.flag = SLC_NOSUPPORT; 312 } else { 313 slctab[func].current.flag = slctab[func].defset.flag; 314 } 315 slctab[func].current.val = slctab[func].defset.val; 316 add_slc(func, slctab[func].current.flag, 317 slctab[func].current.val); 318 return; 319 } 320 321 /* 322 * Client wants us to change to a new value or he 323 * is telling us that he can't change to our value. 324 * Some of the slc's we support and can change, 325 * some we do support but can't change, 326 * and others we don't support at all. 327 * If we can change it then we have a pointer to 328 * the place to put the new value, so change it, 329 * otherwise, continue the negotiation. 330 */ 331 if (slctab[func].sptr) { 332 /* 333 * We can change this one. 334 */ 335 slctab[func].current.val = val; 336 *(slctab[func].sptr) = val; 337 slctab[func].current.flag = flag; 338 flag |= SLC_ACK; 339 slcchange = 1; 340 add_slc(func, flag, val); 341 } else { 342 /* 343 * It is not possible for us to support this 344 * request as he asks. 345 * 346 * If our level is DEFAULT, then just ack whatever was 347 * sent. 348 * 349 * If he can't change and we can't change, 350 * then degenerate to NOSUPPORT. 351 * 352 * Otherwise we send our level back to him, (CANTCHANGE 353 * or NOSUPPORT) and if CANTCHANGE, send 354 * our value as well. 355 */ 356 if (mylevel == SLC_DEFAULT) { 357 slctab[func].current.flag = flag; 358 slctab[func].current.val = val; 359 flag |= SLC_ACK; 360 } else if (hislevel == SLC_CANTCHANGE && 361 mylevel == SLC_CANTCHANGE) { 362 flag &= ~SLC_LEVELBITS; 363 flag |= SLC_NOSUPPORT; 364 slctab[func].current.flag = flag; 365 } else { 366 flag &= ~SLC_LEVELBITS; 367 flag |= mylevel; 368 slctab[func].current.flag = flag; 369 if (mylevel == SLC_CANTCHANGE) { 370 slctab[func].current.val = 371 slctab[func].defset.val; 372 val = slctab[func].current.val; 373 } 374 } 375 add_slc(func, flag, val); 376 } 377 378 } /* end of change_slc */ 379 380 #if VEOF == VMIN 381 cc_t oldeofc = '\004'; 382 #endif 383 384 /* 385 * check_slc 386 * 387 * Check the special characters in use and notify the client if any have 388 * changed. Only those characters that are capable of being changed are 389 * likely to have changed. If a local change occurs, kick the support level 390 * and flags up to the defaults. 391 */ 392 void 393 check_slc(void) 394 { 395 int i; 396 397 for (i = 1; i <= NSLC; i++) { 398 #if VEOF == VMIN 399 /* 400 * In a perfect world this would be a neat little 401 * function. But in this world, we should not notify 402 * client of changes to the VEOF char when 403 * ICANON is off, because it is not representing 404 * a special character. 405 */ 406 if (i == SLC_EOF) { 407 if (!tty_isediting()) 408 continue; 409 else if (slctab[i].sptr) 410 oldeofc = *(slctab[i].sptr); 411 } 412 #endif /* VEOF == VMIN */ 413 if (slctab[i].sptr && 414 (*(slctab[i].sptr) != slctab[i].current.val)) { 415 slctab[i].current.val = *(slctab[i].sptr); 416 if (*(slctab[i].sptr) == (cc_t)_POSIX_VDISABLE) 417 slctab[i].current.flag = SLC_NOSUPPORT; 418 else 419 slctab[i].current.flag = slctab[i].defset.flag; 420 add_slc((unsigned char)i, slctab[i].current.flag, 421 slctab[i].current.val); 422 } 423 } 424 } /* check_slc */ 425 426 /* 427 * do_opt_slc 428 * 429 * Process an slc option buffer. Defer processing of incoming slc's 430 * until after the terminal state has been processed. Save the first slc 431 * request that comes along, but discard all others. 432 * 433 * ptr points to the beginning of the buffer, len is the length. 434 */ 435 void 436 do_opt_slc(unsigned char *ptr, int len) 437 { 438 unsigned char func, flag; 439 cc_t val; 440 unsigned char *end = ptr + len; 441 442 if (terminit()) { /* go ahead */ 443 while (ptr < end) { 444 func = *ptr++; 445 if (ptr >= end) break; 446 flag = *ptr++; 447 if (ptr >= end) break; 448 val = (cc_t)*ptr++; 449 450 process_slc((u_int)func, (u_int)flag, val); 451 452 } 453 } else { 454 /* 455 * save this slc buffer if it is the first, otherwise dump 456 * it. 457 */ 458 if (def_slcbuf == (unsigned char *)0) { 459 def_slclen = len; 460 def_slcbuf = (unsigned char *)malloc((unsigned)len); 461 if (def_slcbuf == (unsigned char *)0) 462 return; /* too bad */ 463 memcpy(def_slcbuf, ptr, len); 464 } 465 } 466 467 } /* end of do_opt_slc */ 468 469 /* 470 * deferslc 471 * 472 * Do slc stuff that was deferred. 473 */ 474 void 475 deferslc(void) 476 { 477 if (def_slcbuf) { 478 start_slc(1); 479 do_opt_slc(def_slcbuf, def_slclen); 480 (void) end_slc(0); 481 free(def_slcbuf); 482 def_slcbuf = (unsigned char *)0; 483 def_slclen = 0; 484 } 485 486 } /* end of deferslc */ 487 488 #endif /* LINEMODE */ 489