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