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