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