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