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