138905Sborman /* 2*61451Sbostic * Copyright (c) 1989, 1993 3*61451Sbostic * The Regents of the University of California. All rights reserved. 438905Sborman * 542673Sbostic * %sccs.include.redist.c% 638905Sborman */ 738905Sborman 838905Sborman #ifndef lint 9*61451Sbostic static char sccsid[] = "@(#)slc.c 8.1 (Berkeley) 06/04/93"; 1038905Sborman #endif /* not lint */ 1138905Sborman 1238905Sborman #include "telnetd.h" 1338905Sborman 1438905Sborman #ifdef LINEMODE 1538905Sborman /* 1638905Sborman * local varibles 1738905Sborman */ 1844364Sborman static unsigned char *def_slcbuf = (unsigned char *)0; 1944364Sborman static int def_slclen = 0; 2044364Sborman static int slcchange; /* change to slc is requested */ 2144364Sborman static unsigned char *slcptr; /* pointer into slc buffer */ 2244364Sborman static unsigned char slcbuf[NSLC*6]; /* buffer for slc negotiation */ 2338905Sborman 2438905Sborman /* 2538905Sborman * send_slc 2638905Sborman * 2738905Sborman * Write out the current special characters to the client. 2838905Sborman */ 2946809Sdab void 3038905Sborman send_slc() 3138905Sborman { 3238905Sborman register int i; 3338905Sborman 3438905Sborman /* 3538905Sborman * Send out list of triplets of special characters 3638905Sborman * to client. We only send info on the characters 3738905Sborman * that are currently supported. 3838905Sborman */ 3938905Sborman for (i = 1; i <= NSLC; i++) { 4045234Sborman if ((slctab[i].defset.flag & SLC_LEVELBITS) == SLC_NOSUPPORT) 4145234Sborman continue; 4245234Sborman add_slc((unsigned char)i, slctab[i].current.flag, 4338905Sborman slctab[i].current.val); 4438905Sborman } 4538905Sborman 4638905Sborman } /* end of send_slc */ 4738905Sborman 4838905Sborman /* 4938905Sborman * default_slc 5038905Sborman * 5138905Sborman * Set pty special characters to all the defaults. 5238905Sborman */ 5346809Sdab void 5438905Sborman default_slc() 5538905Sborman { 5638905Sborman register int i; 5738905Sborman 5838905Sborman for (i = 1; i <= NSLC; i++) { 5938905Sborman slctab[i].current.val = slctab[i].defset.val; 6045234Sborman if (slctab[i].current.val == (cc_t)(_POSIX_VDISABLE)) 6145234Sborman slctab[i].current.flag = SLC_NOSUPPORT; 6245234Sborman else 6345234Sborman slctab[i].current.flag = slctab[i].defset.flag; 6438905Sborman if (slctab[i].sptr) { 6538905Sborman *(slctab[i].sptr) = slctab[i].defset.val; 6638905Sborman } 6738905Sborman } 6838905Sborman slcchange = 1; 6938905Sborman 7038905Sborman } /* end of default_slc */ 7146809Sdab #endif /* LINEMODE */ 7238905Sborman 7338905Sborman /* 7438905Sborman * get_slc_defaults 7538905Sborman * 7638905Sborman * Initialize the slc mapping table. 7738905Sborman */ 7846809Sdab void 7938905Sborman get_slc_defaults() 8038905Sborman { 8138905Sborman register int i; 8238905Sborman 8338905Sborman init_termbuf(); 8438905Sborman 8538905Sborman for (i = 1; i <= NSLC; i++) { 8638905Sborman slctab[i].defset.flag = 8738905Sborman spcset(i, &slctab[i].defset.val, &slctab[i].sptr); 8838905Sborman slctab[i].current.flag = SLC_NOSUPPORT; 8938905Sborman slctab[i].current.val = 0; 9038905Sborman } 9138905Sborman 9238905Sborman } /* end of get_slc_defaults */ 9338905Sborman 9438905Sborman #ifdef LINEMODE 9538905Sborman /* 9638905Sborman * add_slc 9738905Sborman * 9838905Sborman * Add an slc triplet to the slc buffer. 9938905Sborman */ 10046809Sdab void 10138905Sborman add_slc(func, flag, val) 10246809Sdab register char func, flag; 10346809Sdab register cc_t val; 10438905Sborman { 10538905Sborman 10646809Sdab if ((*slcptr++ = (unsigned char)func) == 0xff) 10738905Sborman *slcptr++ = 0xff; 10838905Sborman 10946809Sdab if ((*slcptr++ = (unsigned char)flag) == 0xff) 11038905Sborman *slcptr++ = 0xff; 11138905Sborman 11240242Sborman if ((*slcptr++ = (unsigned char)val) == 0xff) 11338905Sborman *slcptr++ = 0xff; 11438905Sborman 11538905Sborman } /* end of add_slc */ 11638905Sborman 11738905Sborman /* 11838905Sborman * start_slc 11938905Sborman * 12038905Sborman * Get ready to process incoming slc's and respond to them. 12138905Sborman * 12238905Sborman * The parameter getit is non-zero if it is necessary to grab a copy 12338905Sborman * of the terminal control structures. 12438905Sborman */ 12546809Sdab void 12638905Sborman start_slc(getit) 12738905Sborman register int getit; 12838905Sborman { 12938905Sborman 13038905Sborman slcchange = 0; 13138905Sborman if (getit) 13238905Sborman init_termbuf(); 13346809Sdab (void) sprintf((char *)slcbuf, "%c%c%c%c", 13446809Sdab IAC, SB, TELOPT_LINEMODE, LM_SLC); 13538905Sborman slcptr = slcbuf + 4; 13638905Sborman 13738905Sborman } /* end of start_slc */ 13838905Sborman 13938905Sborman /* 14038905Sborman * end_slc 14138905Sborman * 14238905Sborman * Finish up the slc negotiation. If something to send, then send it. 14338905Sborman */ 14446809Sdab int 14538905Sborman end_slc(bufp) 14646809Sdab register unsigned 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)) { 16646809Sdab return(0); 16738905Sborman } 16838905Sborman 16938905Sborman if (slcptr > (slcbuf + 4)) { 17038905Sborman if (bufp) { 17138905Sborman *bufp = &slcbuf[4]; 17238905Sborman return(slcptr - slcbuf - 4); 17338905Sborman } else { 17446685Sbostic (void) sprintf((char *)slcptr, "%c%c", IAC, SE); 17538905Sborman slcptr += 2; 17638905Sborman len = slcptr - slcbuf; 17738905Sborman writenet(slcbuf, len); 17838905Sborman netflush(); /* force it out immediately */ 17957212Sdab DIAG(TD_OPTIONS, printsub('>', slcbuf+2, len-2);); 18038905Sborman } 18138905Sborman } 18246809Sdab return (0); 18338905Sborman 18438905Sborman } /* end of end_slc */ 18538905Sborman 18638905Sborman /* 18738905Sborman * process_slc 18838905Sborman * 18938905Sborman * Figure out what to do about the client's slc 19038905Sborman */ 19146809Sdab void 19238905Sborman process_slc(func, flag, val) 19340242Sborman register unsigned char func, flag; 19446809Sdab register cc_t val; 19538905Sborman { 19638905Sborman register int hislevel, mylevel, ack; 19738905Sborman 19838905Sborman /* 19938905Sborman * Ensure that we know something about this function 20038905Sborman */ 20138905Sborman if (func > NSLC) { 20238905Sborman add_slc(func, SLC_NOSUPPORT, 0); 20338905Sborman return; 20438905Sborman } 20538905Sborman 20638905Sborman /* 20738905Sborman * Process the special case requests of 0 SLC_DEFAULT 0 20838905Sborman * and 0 SLC_VARIABLE 0. Be a little forgiving here, don't 20938905Sborman * worry about whether the value is actually 0 or not. 21038905Sborman */ 21138905Sborman if (func == 0) { 21238905Sborman if ((flag = flag & SLC_LEVELBITS) == SLC_DEFAULT) { 21338905Sborman default_slc(); 21446809Sdab send_slc(); 21545234Sborman } else if (flag == SLC_VARIABLE) { 21646809Sdab send_slc(); 21738905Sborman } 21838905Sborman return; 21938905Sborman } 22038905Sborman 22138905Sborman /* 22238905Sborman * Appears to be a function that we know something about. So 22338905Sborman * get on with it and see what we know. 22438905Sborman */ 22538905Sborman 22638905Sborman hislevel = flag & SLC_LEVELBITS; 22738905Sborman mylevel = slctab[func].current.flag & SLC_LEVELBITS; 22838905Sborman ack = flag & SLC_ACK; 22938905Sborman /* 23038905Sborman * ignore the command if: 23138905Sborman * the function value and level are the same as what we already have; 23238905Sborman * or the level is the same and the ack bit is set 23338905Sborman */ 23438905Sborman if (hislevel == mylevel && (val == slctab[func].current.val || ack)) { 23538905Sborman return; 23645234Sborman } else if (ack) { 23745234Sborman /* 23845234Sborman * If we get here, we got an ack, but the levels don't match. 23945234Sborman * This shouldn't happen. If it does, it is probably because 24045234Sborman * we have sent two requests to set a variable without getting 24145234Sborman * a response between them, and this is the first response. 24245234Sborman * So, ignore it, and wait for the next response. 24345234Sborman */ 24445234Sborman return; 24538905Sborman } else { 24638905Sborman change_slc(func, flag, val); 24738905Sborman } 24838905Sborman 24938905Sborman } /* end of process_slc */ 25038905Sborman 25138905Sborman /* 25238905Sborman * change_slc 25338905Sborman * 25438905Sborman * Process a request to change one of our special characters. 25538905Sborman * Compare client's request with what we are capable of supporting. 25638905Sborman */ 25746809Sdab void 25838905Sborman change_slc(func, flag, val) 25946809Sdab register char func, flag; 26046809Sdab register cc_t val; 26138905Sborman { 26238905Sborman register int hislevel, mylevel; 26338905Sborman 26438905Sborman hislevel = flag & SLC_LEVELBITS; 26538905Sborman mylevel = slctab[func].defset.flag & SLC_LEVELBITS; 26638905Sborman /* 26738905Sborman * If client is setting a function to NOSUPPORT 26838905Sborman * or DEFAULT, then we can easily and directly 26938905Sborman * accomodate the request. 27038905Sborman */ 27138905Sborman if (hislevel == SLC_NOSUPPORT) { 27238905Sborman slctab[func].current.flag = flag; 27345234Sborman slctab[func].current.val = (cc_t)_POSIX_VDISABLE; 27438905Sborman flag |= SLC_ACK; 27538905Sborman add_slc(func, flag, val); 27638905Sborman return; 27738905Sborman } 27838905Sborman if (hislevel == SLC_DEFAULT) { 27938905Sborman /* 28038905Sborman * Special case here. If client tells us to use 28138905Sborman * the default on a function we don't support, then 28238905Sborman * return NOSUPPORT instead of what we may have as a 28338905Sborman * default level of DEFAULT. 28438905Sborman */ 28538905Sborman if (mylevel == SLC_DEFAULT) { 28638905Sborman slctab[func].current.flag = SLC_NOSUPPORT; 28738905Sborman } else { 28838905Sborman slctab[func].current.flag = slctab[func].defset.flag; 28938905Sborman } 29038905Sborman slctab[func].current.val = slctab[func].defset.val; 29138905Sborman add_slc(func, slctab[func].current.flag, 29238905Sborman slctab[func].current.val); 29338905Sborman return; 29438905Sborman } 29538905Sborman 29638905Sborman /* 29738905Sborman * Client wants us to change to a new value or he 29838905Sborman * is telling us that he can't change to our value. 29938905Sborman * Some of the slc's we support and can change, 30038905Sborman * some we do support but can't change, 30138905Sborman * and others we don't support at all. 30238905Sborman * If we can change it then we have a pointer to 30338905Sborman * the place to put the new value, so change it, 30438905Sborman * otherwise, continue the negotiation. 30538905Sborman */ 30638905Sborman if (slctab[func].sptr) { 30738905Sborman /* 30838905Sborman * We can change this one. 30938905Sborman */ 31038905Sborman slctab[func].current.val = val; 31138905Sborman *(slctab[func].sptr) = val; 31238905Sborman slctab[func].current.flag = flag; 31338905Sborman flag |= SLC_ACK; 31438905Sborman slcchange = 1; 31538905Sborman add_slc(func, flag, val); 31638905Sborman } else { 31738905Sborman /* 31838905Sborman * It is not possible for us to support this 31938905Sborman * request as he asks. 32038905Sborman * 32138905Sborman * If our level is DEFAULT, then just ack whatever was 32238905Sborman * sent. 32338905Sborman * 32438905Sborman * If he can't change and we can't change, 32538905Sborman * then degenerate to NOSUPPORT. 32638905Sborman * 32738905Sborman * Otherwise we send our level back to him, (CANTCHANGE 32838905Sborman * or NOSUPPORT) and if CANTCHANGE, send 32938905Sborman * our value as well. 33038905Sborman */ 33138905Sborman if (mylevel == SLC_DEFAULT) { 33238905Sborman slctab[func].current.flag = flag; 33338905Sborman slctab[func].current.val = val; 33438905Sborman flag |= SLC_ACK; 33538905Sborman } else if (hislevel == SLC_CANTCHANGE && 33638905Sborman mylevel == SLC_CANTCHANGE) { 33738905Sborman flag &= ~SLC_LEVELBITS; 33838905Sborman flag |= SLC_NOSUPPORT; 33938905Sborman slctab[func].current.flag = flag; 34038905Sborman } else { 34138905Sborman flag &= ~SLC_LEVELBITS; 34238905Sborman flag |= mylevel; 34338905Sborman slctab[func].current.flag = flag; 34438905Sborman if (mylevel == SLC_CANTCHANGE) { 34538905Sborman slctab[func].current.val = 34638905Sborman slctab[func].defset.val; 34738905Sborman val = slctab[func].current.val; 34838905Sborman } 34938905Sborman 35038905Sborman } 35138905Sborman add_slc(func, flag, val); 35238905Sborman } 35338905Sborman 35438905Sborman } /* end of change_slc */ 35538905Sborman 35645234Sborman #if defined(USE_TERMIO) && (VEOF == VMIN) 35740242Sborman cc_t oldeofc = '\004'; 35840242Sborman #endif 35940242Sborman 36038905Sborman /* 36138905Sborman * check_slc 36238905Sborman * 36338905Sborman * Check the special characters in use and notify the client if any have 36438905Sborman * changed. Only those characters that are capable of being changed are 36538905Sborman * likely to have changed. If a local change occurs, kick the support level 36638905Sborman * and flags up to the defaults. 36738905Sborman */ 36846809Sdab void 36938905Sborman check_slc() 37038905Sborman { 37138905Sborman register int i; 37238905Sborman 37338905Sborman for (i = 1; i <= NSLC; i++) { 37445234Sborman #if defined(USE_TERMIO) && (VEOF == VMIN) 37538905Sborman /* 37638905Sborman * In a perfect world this would be a neat little 37738905Sborman * function. But in this world, we should not notify 37838905Sborman * client of changes to the VEOF char when 37938905Sborman * ICANON is off, because it is not representing 38038905Sborman * a special character. 38138905Sborman */ 38240242Sborman if (i == SLC_EOF) { 38340242Sborman if (!tty_isediting()) 38440242Sborman continue; 38540242Sborman else if (slctab[i].sptr) 38640242Sborman oldeofc = *(slctab[i].sptr); 38740242Sborman } 38838905Sborman #endif /* defined(USE_TERMIO) && defined(SYSV_TERMIO) */ 38938905Sborman if (slctab[i].sptr && 39038905Sborman (*(slctab[i].sptr) != slctab[i].current.val)) { 39138905Sborman slctab[i].current.val = *(slctab[i].sptr); 39245234Sborman if (*(slctab[i].sptr) == (cc_t)_POSIX_VDISABLE) 39345234Sborman slctab[i].current.flag = SLC_NOSUPPORT; 39445234Sborman else 39545234Sborman slctab[i].current.flag = slctab[i].defset.flag; 39638905Sborman add_slc((unsigned char)i, slctab[i].current.flag, 39738905Sborman slctab[i].current.val); 39838905Sborman } 39938905Sborman } 40038905Sborman 40138905Sborman } /* check_slc */ 40238905Sborman 40338905Sborman /* 40438905Sborman * do_opt_slc 40538905Sborman * 40638905Sborman * Process an slc option buffer. Defer processing of incoming slc's 40738905Sborman * until after the terminal state has been processed. Save the first slc 40838905Sborman * request that comes along, but discard all others. 40938905Sborman * 41038905Sborman * ptr points to the beginning of the buffer, len is the length. 41138905Sborman */ 41246809Sdab void 41338905Sborman do_opt_slc(ptr, len) 41446809Sdab register unsigned char *ptr; 41546809Sdab register int len; 41638905Sborman { 41740242Sborman register unsigned char func, flag; 41840242Sborman cc_t val; 41946809Sdab register unsigned char *end = ptr + len; 42038905Sborman 42138905Sborman if (terminit()) { /* go ahead */ 42238905Sborman while (ptr < end) { 42338905Sborman func = *ptr++; 42438905Sborman if (ptr >= end) break; 42538905Sborman flag = *ptr++; 42638905Sborman if (ptr >= end) break; 42740242Sborman val = (cc_t)*ptr++; 42838905Sborman 42938905Sborman process_slc(func, flag, val); 43038905Sborman 43138905Sborman } 43238905Sborman } else { 43338905Sborman /* 43438905Sborman * save this slc buffer if it is the first, otherwise dump 43538905Sborman * it. 43638905Sborman */ 43744364Sborman if (def_slcbuf == (unsigned char *)0) { 43838905Sborman def_slclen = len; 43944364Sborman def_slcbuf = (unsigned char *)malloc((unsigned)len); 44044364Sborman if (def_slcbuf == (unsigned char *)0) 44138905Sborman return; /* too bad */ 44238905Sborman bcopy(ptr, def_slcbuf, len); 44338905Sborman } 44438905Sborman } 44538905Sborman 44638905Sborman } /* end of do_opt_slc */ 44738905Sborman 44838905Sborman /* 44938905Sborman * deferslc 45038905Sborman * 45138905Sborman * Do slc stuff that was deferred. 45238905Sborman */ 45346809Sdab void 45438905Sborman deferslc() 45538905Sborman { 45638905Sborman if (def_slcbuf) { 45738905Sborman start_slc(1); 45838905Sborman do_opt_slc(def_slcbuf, def_slclen); 45946809Sdab (void) end_slc(0); 46038905Sborman free(def_slcbuf); 46144364Sborman def_slcbuf = (unsigned char *)0; 46238905Sborman def_slclen = 0; 46338905Sborman } 46438905Sborman 46538905Sborman } /* end of deferslc */ 46638905Sborman 46738905Sborman #endif /* LINEMODE */ 468