138905Sborman /* 238905Sborman * Copyright (c) 1989 Regents of the University of California. 338905Sborman * All rights reserved. 438905Sborman * 538905Sborman * Redistribution and use in source and binary forms are permitted 638905Sborman * provided that the above copyright notice and this paragraph are 738905Sborman * duplicated in all such forms and that any documentation, 838905Sborman * advertising materials, and other materials related to such 938905Sborman * distribution and use acknowledge that the software was developed 1038905Sborman * by the University of California, Berkeley. The name of the 1138905Sborman * University may not be used to endorse or promote products derived 1238905Sborman * from this software without specific prior written permission. 1338905Sborman * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1438905Sborman * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1538905Sborman * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1638905Sborman */ 1738905Sborman 1838905Sborman #ifndef lint 19*40242Sborman static char sccsid[] = "@(#)slc.c 5.2 (Berkeley) 02/28/90"; 2038905Sborman #endif /* not lint */ 2138905Sborman 2238905Sborman #include "telnetd.h" 2338905Sborman 2438905Sborman #ifdef LINEMODE 2538905Sborman /* 2638905Sborman * local varibles 2738905Sborman */ 28*40242Sborman static char *def_slcbuf = (char *)0; 2938905Sborman static int def_slclen = 0; 3038905Sborman static int slcchange; /* change to slc is requested */ 3138905Sborman static char *slcptr; /* pointer into slc buffer */ 3238905Sborman static char slcbuf[NSLC*6]; /* buffer for slc negotiation */ 3338905Sborman 3438905Sborman /* 3538905Sborman * send_slc 3638905Sborman * 3738905Sborman * Write out the current special characters to the client. 3838905Sborman */ 3938905Sborman send_slc() 4038905Sborman { 4138905Sborman register int i; 4238905Sborman 4338905Sborman /* 4438905Sborman * Send out list of triplets of special characters 4538905Sborman * to client. We only send info on the characters 4638905Sborman * that are currently supported. 4738905Sborman */ 4838905Sborman for (i = 1; i <= NSLC; i++) { 4938905Sborman if ((slctab[i].current.flag & SLC_LEVELBITS) != SLC_NOSUPPORT) { 5038905Sborman add_slc((unsigned char)i, slctab[i].current.flag, 5138905Sborman slctab[i].current.val); 5238905Sborman } 5338905Sborman } 5438905Sborman 5538905Sborman } /* end of send_slc */ 5638905Sborman 5738905Sborman /* 5838905Sborman * default_slc 5938905Sborman * 6038905Sborman * Set pty special characters to all the defaults. 6138905Sborman */ 6238905Sborman default_slc() 6338905Sborman { 6438905Sborman register int i; 6538905Sborman 6638905Sborman for (i = 1; i <= NSLC; i++) { 6738905Sborman slctab[i].current.flag = slctab[i].defset.flag; 6838905Sborman slctab[i].current.val = slctab[i].defset.val; 6938905Sborman if (slctab[i].sptr) { 7038905Sborman *(slctab[i].sptr) = slctab[i].defset.val; 7138905Sborman } 7238905Sborman } 7338905Sborman slcchange = 1; 7438905Sborman 7538905Sborman } /* end of default_slc */ 7638905Sborman #endif LINEMODE 7738905Sborman 7838905Sborman /* 7938905Sborman * get_slc_defaults 8038905Sborman * 8138905Sborman * Initialize the slc mapping table. 8238905Sborman */ 8338905Sborman get_slc_defaults() 8438905Sborman { 8538905Sborman register int i; 8638905Sborman 8738905Sborman init_termbuf(); 8838905Sborman 8938905Sborman for (i = 1; i <= NSLC; i++) { 9038905Sborman slctab[i].defset.flag = 9138905Sborman spcset(i, &slctab[i].defset.val, &slctab[i].sptr); 9238905Sborman slctab[i].current.flag = SLC_NOSUPPORT; 9338905Sborman slctab[i].current.val = 0; 9438905Sborman } 9538905Sborman 9638905Sborman } /* end of get_slc_defaults */ 9738905Sborman 9838905Sborman #ifdef LINEMODE 9938905Sborman /* 10038905Sborman * add_slc 10138905Sborman * 10238905Sborman * Add an slc triplet to the slc buffer. 10338905Sborman */ 10438905Sborman add_slc(func, flag, val) 105*40242Sborman register unsigned char func, flag; 106*40242Sborman cc_t val; 10738905Sborman { 10838905Sborman 109*40242Sborman if ((*slcptr++ = func) == 0xff) 11038905Sborman *slcptr++ = 0xff; 11138905Sborman 112*40242Sborman if ((*slcptr++ = flag) == 0xff) 11338905Sborman *slcptr++ = 0xff; 11438905Sborman 115*40242Sborman if ((*slcptr++ = (unsigned char)val) == 0xff) 11638905Sborman *slcptr++ = 0xff; 11738905Sborman 11838905Sborman } /* end of add_slc */ 11938905Sborman 12038905Sborman /* 12138905Sborman * start_slc 12238905Sborman * 12338905Sborman * Get ready to process incoming slc's and respond to them. 12438905Sborman * 12538905Sborman * The parameter getit is non-zero if it is necessary to grab a copy 12638905Sborman * of the terminal control structures. 12738905Sborman */ 12838905Sborman start_slc(getit) 12938905Sborman register int getit; 13038905Sborman { 13138905Sborman 13238905Sborman slcchange = 0; 13338905Sborman if (getit) 13438905Sborman init_termbuf(); 13538905Sborman (void) sprintf(slcbuf, "%c%c%c%c", IAC, SB, TELOPT_LINEMODE, LM_SLC); 13638905Sborman slcptr = slcbuf + 4; 13738905Sborman 13838905Sborman } /* end of start_slc */ 13938905Sborman 14038905Sborman /* 14138905Sborman * end_slc 14238905Sborman * 14338905Sborman * Finish up the slc negotiation. If something to send, then send it. 14438905Sborman */ 14538905Sborman end_slc(bufp) 14638905Sborman register char **bufp; 14738905Sborman { 14838905Sborman register int len; 14938905Sborman void netflush(); 15038905Sborman 15138905Sborman /* 15238905Sborman * If a change has occured, store the new terminal control 15338905Sborman * structures back to the terminal driver. 15438905Sborman */ 15538905Sborman if (slcchange) { 15638905Sborman set_termbuf(); 15738905Sborman } 15838905Sborman 15938905Sborman /* 16038905Sborman * If the pty state has not yet been fully processed and there is a 16138905Sborman * deferred slc request from the client, then do not send any 16238905Sborman * sort of slc negotiation now. We will respond to the client's 16338905Sborman * request very soon. 16438905Sborman */ 16538905Sborman if (def_slcbuf && (terminit() == 0)) { 16638905Sborman return; 16738905Sborman } 16838905Sborman 16938905Sborman if (slcptr > (slcbuf + 4)) { 17038905Sborman if (bufp) { 17138905Sborman *bufp = &slcbuf[4]; 17238905Sborman return(slcptr - slcbuf - 4); 17338905Sborman } else { 17438905Sborman (void) sprintf(slcptr, "%c%c", IAC, SE); 17538905Sborman slcptr += 2; 17638905Sborman len = slcptr - slcbuf; 17738905Sborman writenet(slcbuf, len); 17838905Sborman netflush(); /* force it out immediately */ 17938905Sborman } 18038905Sborman } 18138905Sborman 18238905Sborman } /* end of end_slc */ 18338905Sborman 18438905Sborman /* 18538905Sborman * process_slc 18638905Sborman * 18738905Sborman * Figure out what to do about the client's slc 18838905Sborman */ 18938905Sborman process_slc(func, flag, val) 190*40242Sborman register unsigned char func, flag; 191*40242Sborman cc_t val; 19238905Sborman { 19338905Sborman register int hislevel, mylevel, ack; 19438905Sborman 19538905Sborman /* 19638905Sborman * Ensure that we know something about this function 19738905Sborman */ 19838905Sborman if (func > NSLC) { 19938905Sborman add_slc(func, SLC_NOSUPPORT, 0); 20038905Sborman return; 20138905Sborman } 20238905Sborman 20338905Sborman /* 20438905Sborman * Process the special case requests of 0 SLC_DEFAULT 0 20538905Sborman * and 0 SLC_VARIABLE 0. Be a little forgiving here, don't 20638905Sborman * worry about whether the value is actually 0 or not. 20738905Sborman */ 20838905Sborman if (func == 0) { 20938905Sborman if ((flag = flag & SLC_LEVELBITS) == SLC_DEFAULT) { 21038905Sborman default_slc(); 21138905Sborman } 21238905Sborman if (flag == SLC_DEFAULT || flag == SLC_VARIABLE) { 21338905Sborman send_slc(); 21438905Sborman } 21538905Sborman return; 21638905Sborman } 21738905Sborman 21838905Sborman /* 21938905Sborman * Appears to be a function that we know something about. So 22038905Sborman * get on with it and see what we know. 22138905Sborman */ 22238905Sborman 22338905Sborman hislevel = flag & SLC_LEVELBITS; 22438905Sborman mylevel = slctab[func].current.flag & SLC_LEVELBITS; 22538905Sborman ack = flag & SLC_ACK; 22638905Sborman /* 22738905Sborman * ignore the command if: 22838905Sborman * the function value and level are the same as what we already have; 22938905Sborman * or the level is the same and the ack bit is set 23038905Sborman */ 23138905Sborman if (hislevel == mylevel && (val == slctab[func].current.val || ack)) { 23238905Sborman return; 23338905Sborman } else { 23438905Sborman change_slc(func, flag, val); 23538905Sborman } 23638905Sborman 23738905Sborman } /* end of process_slc */ 23838905Sborman 23938905Sborman /* 24038905Sborman * change_slc 24138905Sborman * 24238905Sborman * Process a request to change one of our special characters. 24338905Sborman * Compare client's request with what we are capable of supporting. 24438905Sborman */ 24538905Sborman change_slc(func, flag, val) 246*40242Sborman register unsigned char func, flag; 247*40242Sborman cc_t val; 24838905Sborman { 24938905Sborman register int hislevel, mylevel; 25038905Sborman 25138905Sborman hislevel = flag & SLC_LEVELBITS; 25238905Sborman mylevel = slctab[func].defset.flag & SLC_LEVELBITS; 25338905Sborman /* 25438905Sborman * If client is setting a function to NOSUPPORT 25538905Sborman * or DEFAULT, then we can easily and directly 25638905Sborman * accomodate the request. 25738905Sborman */ 25838905Sborman if (hislevel == SLC_NOSUPPORT) { 25938905Sborman slctab[func].current.flag = flag; 26038905Sborman slctab[func].current.val = val; 26138905Sborman flag |= SLC_ACK; 26238905Sborman add_slc(func, flag, val); 26338905Sborman return; 26438905Sborman } 26538905Sborman if (hislevel == SLC_DEFAULT) { 26638905Sborman /* 26738905Sborman * Special case here. If client tells us to use 26838905Sborman * the default on a function we don't support, then 26938905Sborman * return NOSUPPORT instead of what we may have as a 27038905Sborman * default level of DEFAULT. 27138905Sborman */ 27238905Sborman if (mylevel == SLC_DEFAULT) { 27338905Sborman slctab[func].current.flag = SLC_NOSUPPORT; 27438905Sborman } else { 27538905Sborman slctab[func].current.flag = slctab[func].defset.flag; 27638905Sborman } 27738905Sborman slctab[func].current.val = slctab[func].defset.val; 27838905Sborman add_slc(func, slctab[func].current.flag, 27938905Sborman slctab[func].current.val); 28038905Sborman return; 28138905Sborman } 28238905Sborman 28338905Sborman /* 28438905Sborman * Client wants us to change to a new value or he 28538905Sborman * is telling us that he can't change to our value. 28638905Sborman * Some of the slc's we support and can change, 28738905Sborman * some we do support but can't change, 28838905Sborman * and others we don't support at all. 28938905Sborman * If we can change it then we have a pointer to 29038905Sborman * the place to put the new value, so change it, 29138905Sborman * otherwise, continue the negotiation. 29238905Sborman */ 29338905Sborman if (slctab[func].sptr) { 29438905Sborman /* 29538905Sborman * We can change this one. 29638905Sborman */ 29738905Sborman slctab[func].current.val = val; 29838905Sborman *(slctab[func].sptr) = val; 29938905Sborman slctab[func].current.flag = flag; 30038905Sborman flag |= SLC_ACK; 30138905Sborman slcchange = 1; 30238905Sborman add_slc(func, flag, val); 30338905Sborman } else { 30438905Sborman /* 30538905Sborman * It is not possible for us to support this 30638905Sborman * request as he asks. 30738905Sborman * 30838905Sborman * If our level is DEFAULT, then just ack whatever was 30938905Sborman * sent. 31038905Sborman * 31138905Sborman * If he can't change and we can't change, 31238905Sborman * then degenerate to NOSUPPORT. 31338905Sborman * 31438905Sborman * Otherwise we send our level back to him, (CANTCHANGE 31538905Sborman * or NOSUPPORT) and if CANTCHANGE, send 31638905Sborman * our value as well. 31738905Sborman */ 31838905Sborman if (mylevel == SLC_DEFAULT) { 31938905Sborman slctab[func].current.flag = flag; 32038905Sborman slctab[func].current.val = val; 32138905Sborman flag |= SLC_ACK; 32238905Sborman } else if (hislevel == SLC_CANTCHANGE && 32338905Sborman mylevel == SLC_CANTCHANGE) { 32438905Sborman flag &= ~SLC_LEVELBITS; 32538905Sborman flag |= SLC_NOSUPPORT; 32638905Sborman slctab[func].current.flag = flag; 32738905Sborman } else { 32838905Sborman flag &= ~SLC_LEVELBITS; 32938905Sborman flag |= mylevel; 33038905Sborman slctab[func].current.flag = flag; 33138905Sborman if (mylevel == SLC_CANTCHANGE) { 33238905Sborman slctab[func].current.val = 33338905Sborman slctab[func].defset.val; 33438905Sborman val = slctab[func].current.val; 33538905Sborman } 33638905Sborman 33738905Sborman } 33838905Sborman add_slc(func, flag, val); 33938905Sborman } 34038905Sborman 34138905Sborman } /* end of change_slc */ 34238905Sborman 343*40242Sborman #if defined(USE_TERMIO) && defined(SYSV_TERMIO) 344*40242Sborman cc_t oldeofc = '\004'; 345*40242Sborman #endif 346*40242Sborman 34738905Sborman /* 34838905Sborman * check_slc 34938905Sborman * 35038905Sborman * Check the special characters in use and notify the client if any have 35138905Sborman * changed. Only those characters that are capable of being changed are 35238905Sborman * likely to have changed. If a local change occurs, kick the support level 35338905Sborman * and flags up to the defaults. 35438905Sborman */ 35538905Sborman check_slc() 35638905Sborman { 35738905Sborman register int i; 35838905Sborman 35938905Sborman for (i = 1; i <= NSLC; i++) { 36038905Sborman #if defined(USE_TERMIO) && defined(SYSV_TERMIO) 36138905Sborman /* 36238905Sborman * In a perfect world this would be a neat little 36338905Sborman * function. But in this world, we should not notify 36438905Sborman * client of changes to the VEOF char when 36538905Sborman * ICANON is off, because it is not representing 36638905Sborman * a special character. 36738905Sborman */ 368*40242Sborman if (i == SLC_EOF) { 369*40242Sborman if (!tty_isediting()) 370*40242Sborman continue; 371*40242Sborman else if (slctab[i].sptr) 372*40242Sborman oldeofc = *(slctab[i].sptr); 373*40242Sborman } 37438905Sborman #endif /* defined(USE_TERMIO) && defined(SYSV_TERMIO) */ 37538905Sborman if (slctab[i].sptr && 37638905Sborman (*(slctab[i].sptr) != slctab[i].current.val)) { 37738905Sborman slctab[i].current.val = *(slctab[i].sptr); 37838905Sborman slctab[i].current.flag = slctab[i].defset.flag; 37938905Sborman add_slc((unsigned char)i, slctab[i].current.flag, 38038905Sborman slctab[i].current.val); 38138905Sborman } 38238905Sborman } 38338905Sborman 38438905Sborman } /* check_slc */ 38538905Sborman 38638905Sborman /* 38738905Sborman * do_opt_slc 38838905Sborman * 38938905Sborman * Process an slc option buffer. Defer processing of incoming slc's 39038905Sborman * until after the terminal state has been processed. Save the first slc 39138905Sborman * request that comes along, but discard all others. 39238905Sborman * 39338905Sborman * ptr points to the beginning of the buffer, len is the length. 39438905Sborman */ 39538905Sborman do_opt_slc(ptr, len) 39638905Sborman register char *ptr; 39738905Sborman register int len; 39838905Sborman { 399*40242Sborman register unsigned char func, flag; 400*40242Sborman cc_t val; 40138905Sborman register char *end = (char *)(ptr + len); 40238905Sborman char *malloc(); 40338905Sborman 40438905Sborman if (terminit()) { /* go ahead */ 40538905Sborman while (ptr < end) { 40638905Sborman func = *ptr++; 40738905Sborman if (ptr >= end) break; 40838905Sborman flag = *ptr++; 40938905Sborman if (ptr >= end) break; 410*40242Sborman val = (cc_t)*ptr++; 41138905Sborman 41238905Sborman process_slc(func, flag, val); 41338905Sborman 41438905Sborman } 41538905Sborman } else { 41638905Sborman /* 41738905Sborman * save this slc buffer if it is the first, otherwise dump 41838905Sborman * it. 41938905Sborman */ 42038905Sborman if (def_slcbuf == (char *)0) { 42138905Sborman def_slclen = len; 42238905Sborman def_slcbuf = malloc((unsigned)len); 42338905Sborman if (def_slcbuf == (char *)0) 42438905Sborman return; /* too bad */ 42538905Sborman bcopy(ptr, def_slcbuf, len); 42638905Sborman } 42738905Sborman } 42838905Sborman 42938905Sborman } /* end of do_opt_slc */ 43038905Sborman 43138905Sborman /* 43238905Sborman * deferslc 43338905Sborman * 43438905Sborman * Do slc stuff that was deferred. 43538905Sborman */ 43638905Sborman deferslc() 43738905Sborman { 43838905Sborman if (def_slcbuf) { 43938905Sborman start_slc(1); 44038905Sborman do_opt_slc(def_slcbuf, def_slclen); 44138905Sborman end_slc(0); 44238905Sborman free(def_slcbuf); 44338905Sborman def_slcbuf = (char *)0; 44438905Sborman def_slclen = 0; 44538905Sborman } 44638905Sborman 44738905Sborman } /* end of deferslc */ 44838905Sborman 44938905Sborman #endif /* LINEMODE */ 450