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