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