138905Sborman /* 238905Sborman * Copyright (c) 1989 Regents of the University of California. 338905Sborman * All rights reserved. 438905Sborman * 542673Sbostic * %sccs.include.redist.c% 638905Sborman */ 738905Sborman 838905Sborman #ifndef lint 9*46809Sdab static char sccsid[] = "@(#)slc.c 5.7 (Berkeley) 03/01/91"; 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 */ 29*46809Sdab 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 */ 53*46809Sdab 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 */ 71*46809Sdab #endif /* LINEMODE */ 7238905Sborman 7338905Sborman /* 7438905Sborman * get_slc_defaults 7538905Sborman * 7638905Sborman * Initialize the slc mapping table. 7738905Sborman */ 78*46809Sdab 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 */ 100*46809Sdab void 10138905Sborman add_slc(func, flag, val) 102*46809Sdab register char func, flag; 103*46809Sdab register cc_t val; 10438905Sborman { 10538905Sborman 106*46809Sdab if ((*slcptr++ = (unsigned char)func) == 0xff) 10738905Sborman *slcptr++ = 0xff; 10838905Sborman 109*46809Sdab 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 */ 125*46809Sdab void 12638905Sborman start_slc(getit) 12738905Sborman register int getit; 12838905Sborman { 12938905Sborman 13038905Sborman slcchange = 0; 13138905Sborman if (getit) 13238905Sborman init_termbuf(); 133*46809Sdab (void) sprintf((char *)slcbuf, "%c%c%c%c", 134*46809Sdab 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 */ 144*46809Sdab int 14538905Sborman end_slc(bufp) 146*46809Sdab 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)) { 166*46809Sdab 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 */ 17938905Sborman } 18038905Sborman } 181*46809Sdab return (0); 18238905Sborman 18338905Sborman } /* end of end_slc */ 18438905Sborman 18538905Sborman /* 18638905Sborman * process_slc 18738905Sborman * 18838905Sborman * Figure out what to do about the client's slc 18938905Sborman */ 190*46809Sdab void 19138905Sborman process_slc(func, flag, val) 19240242Sborman register unsigned char func, flag; 193*46809Sdab register cc_t val; 19438905Sborman { 19538905Sborman register int hislevel, mylevel, ack; 19638905Sborman 19738905Sborman /* 19838905Sborman * Ensure that we know something about this function 19938905Sborman */ 20038905Sborman if (func > NSLC) { 20138905Sborman add_slc(func, SLC_NOSUPPORT, 0); 20238905Sborman return; 20338905Sborman } 20438905Sborman 20538905Sborman /* 20638905Sborman * Process the special case requests of 0 SLC_DEFAULT 0 20738905Sborman * and 0 SLC_VARIABLE 0. Be a little forgiving here, don't 20838905Sborman * worry about whether the value is actually 0 or not. 20938905Sborman */ 21038905Sborman if (func == 0) { 21138905Sborman if ((flag = flag & SLC_LEVELBITS) == SLC_DEFAULT) { 21238905Sborman default_slc(); 213*46809Sdab send_slc(); 21445234Sborman } else if (flag == SLC_VARIABLE) { 215*46809Sdab send_slc(); 21638905Sborman } 21738905Sborman return; 21838905Sborman } 21938905Sborman 22038905Sborman /* 22138905Sborman * Appears to be a function that we know something about. So 22238905Sborman * get on with it and see what we know. 22338905Sborman */ 22438905Sborman 22538905Sborman hislevel = flag & SLC_LEVELBITS; 22638905Sborman mylevel = slctab[func].current.flag & SLC_LEVELBITS; 22738905Sborman ack = flag & SLC_ACK; 22838905Sborman /* 22938905Sborman * ignore the command if: 23038905Sborman * the function value and level are the same as what we already have; 23138905Sborman * or the level is the same and the ack bit is set 23238905Sborman */ 23338905Sborman if (hislevel == mylevel && (val == slctab[func].current.val || ack)) { 23438905Sborman return; 23545234Sborman } else if (ack) { 23645234Sborman /* 23745234Sborman * If we get here, we got an ack, but the levels don't match. 23845234Sborman * This shouldn't happen. If it does, it is probably because 23945234Sborman * we have sent two requests to set a variable without getting 24045234Sborman * a response between them, and this is the first response. 24145234Sborman * So, ignore it, and wait for the next response. 24245234Sborman */ 24345234Sborman return; 24438905Sborman } else { 24538905Sborman change_slc(func, flag, val); 24638905Sborman } 24738905Sborman 24838905Sborman } /* end of process_slc */ 24938905Sborman 25038905Sborman /* 25138905Sborman * change_slc 25238905Sborman * 25338905Sborman * Process a request to change one of our special characters. 25438905Sborman * Compare client's request with what we are capable of supporting. 25538905Sborman */ 256*46809Sdab void 25738905Sborman change_slc(func, flag, val) 258*46809Sdab register char func, flag; 259*46809Sdab register cc_t val; 26038905Sborman { 26138905Sborman register int hislevel, mylevel; 26238905Sborman 26338905Sborman hislevel = flag & SLC_LEVELBITS; 26438905Sborman mylevel = slctab[func].defset.flag & SLC_LEVELBITS; 26538905Sborman /* 26638905Sborman * If client is setting a function to NOSUPPORT 26738905Sborman * or DEFAULT, then we can easily and directly 26838905Sborman * accomodate the request. 26938905Sborman */ 27038905Sborman if (hislevel == SLC_NOSUPPORT) { 27138905Sborman slctab[func].current.flag = flag; 27245234Sborman slctab[func].current.val = (cc_t)_POSIX_VDISABLE; 27338905Sborman flag |= SLC_ACK; 27438905Sborman add_slc(func, flag, val); 27538905Sborman return; 27638905Sborman } 27738905Sborman if (hislevel == SLC_DEFAULT) { 27838905Sborman /* 27938905Sborman * Special case here. If client tells us to use 28038905Sborman * the default on a function we don't support, then 28138905Sborman * return NOSUPPORT instead of what we may have as a 28238905Sborman * default level of DEFAULT. 28338905Sborman */ 28438905Sborman if (mylevel == SLC_DEFAULT) { 28538905Sborman slctab[func].current.flag = SLC_NOSUPPORT; 28638905Sborman } else { 28738905Sborman slctab[func].current.flag = slctab[func].defset.flag; 28838905Sborman } 28938905Sborman slctab[func].current.val = slctab[func].defset.val; 29038905Sborman add_slc(func, slctab[func].current.flag, 29138905Sborman slctab[func].current.val); 29238905Sborman return; 29338905Sborman } 29438905Sborman 29538905Sborman /* 29638905Sborman * Client wants us to change to a new value or he 29738905Sborman * is telling us that he can't change to our value. 29838905Sborman * Some of the slc's we support and can change, 29938905Sborman * some we do support but can't change, 30038905Sborman * and others we don't support at all. 30138905Sborman * If we can change it then we have a pointer to 30238905Sborman * the place to put the new value, so change it, 30338905Sborman * otherwise, continue the negotiation. 30438905Sborman */ 30538905Sborman if (slctab[func].sptr) { 30638905Sborman /* 30738905Sborman * We can change this one. 30838905Sborman */ 30938905Sborman slctab[func].current.val = val; 31038905Sborman *(slctab[func].sptr) = val; 31138905Sborman slctab[func].current.flag = flag; 31238905Sborman flag |= SLC_ACK; 31338905Sborman slcchange = 1; 31438905Sborman add_slc(func, flag, val); 31538905Sborman } else { 31638905Sborman /* 31738905Sborman * It is not possible for us to support this 31838905Sborman * request as he asks. 31938905Sborman * 32038905Sborman * If our level is DEFAULT, then just ack whatever was 32138905Sborman * sent. 32238905Sborman * 32338905Sborman * If he can't change and we can't change, 32438905Sborman * then degenerate to NOSUPPORT. 32538905Sborman * 32638905Sborman * Otherwise we send our level back to him, (CANTCHANGE 32738905Sborman * or NOSUPPORT) and if CANTCHANGE, send 32838905Sborman * our value as well. 32938905Sborman */ 33038905Sborman if (mylevel == SLC_DEFAULT) { 33138905Sborman slctab[func].current.flag = flag; 33238905Sborman slctab[func].current.val = val; 33338905Sborman flag |= SLC_ACK; 33438905Sborman } else if (hislevel == SLC_CANTCHANGE && 33538905Sborman mylevel == SLC_CANTCHANGE) { 33638905Sborman flag &= ~SLC_LEVELBITS; 33738905Sborman flag |= SLC_NOSUPPORT; 33838905Sborman slctab[func].current.flag = flag; 33938905Sborman } else { 34038905Sborman flag &= ~SLC_LEVELBITS; 34138905Sborman flag |= mylevel; 34238905Sborman slctab[func].current.flag = flag; 34338905Sborman if (mylevel == SLC_CANTCHANGE) { 34438905Sborman slctab[func].current.val = 34538905Sborman slctab[func].defset.val; 34638905Sborman val = slctab[func].current.val; 34738905Sborman } 34838905Sborman 34938905Sborman } 35038905Sborman add_slc(func, flag, val); 35138905Sborman } 35238905Sborman 35338905Sborman } /* end of change_slc */ 35438905Sborman 35545234Sborman #if defined(USE_TERMIO) && (VEOF == VMIN) 35640242Sborman cc_t oldeofc = '\004'; 35740242Sborman #endif 35840242Sborman 35938905Sborman /* 36038905Sborman * check_slc 36138905Sborman * 36238905Sborman * Check the special characters in use and notify the client if any have 36338905Sborman * changed. Only those characters that are capable of being changed are 36438905Sborman * likely to have changed. If a local change occurs, kick the support level 36538905Sborman * and flags up to the defaults. 36638905Sborman */ 367*46809Sdab void 36838905Sborman check_slc() 36938905Sborman { 37038905Sborman register int i; 37138905Sborman 37238905Sborman for (i = 1; i <= NSLC; i++) { 37345234Sborman #if defined(USE_TERMIO) && (VEOF == VMIN) 37438905Sborman /* 37538905Sborman * In a perfect world this would be a neat little 37638905Sborman * function. But in this world, we should not notify 37738905Sborman * client of changes to the VEOF char when 37838905Sborman * ICANON is off, because it is not representing 37938905Sborman * a special character. 38038905Sborman */ 38140242Sborman if (i == SLC_EOF) { 38240242Sborman if (!tty_isediting()) 38340242Sborman continue; 38440242Sborman else if (slctab[i].sptr) 38540242Sborman oldeofc = *(slctab[i].sptr); 38640242Sborman } 38738905Sborman #endif /* defined(USE_TERMIO) && defined(SYSV_TERMIO) */ 38838905Sborman if (slctab[i].sptr && 38938905Sborman (*(slctab[i].sptr) != slctab[i].current.val)) { 39038905Sborman slctab[i].current.val = *(slctab[i].sptr); 39145234Sborman if (*(slctab[i].sptr) == (cc_t)_POSIX_VDISABLE) 39245234Sborman slctab[i].current.flag = SLC_NOSUPPORT; 39345234Sborman else 39445234Sborman slctab[i].current.flag = slctab[i].defset.flag; 39538905Sborman add_slc((unsigned char)i, slctab[i].current.flag, 39638905Sborman slctab[i].current.val); 39738905Sborman } 39838905Sborman } 39938905Sborman 40038905Sborman } /* check_slc */ 40138905Sborman 40238905Sborman /* 40338905Sborman * do_opt_slc 40438905Sborman * 40538905Sborman * Process an slc option buffer. Defer processing of incoming slc's 40638905Sborman * until after the terminal state has been processed. Save the first slc 40738905Sborman * request that comes along, but discard all others. 40838905Sborman * 40938905Sborman * ptr points to the beginning of the buffer, len is the length. 41038905Sborman */ 411*46809Sdab void 41238905Sborman do_opt_slc(ptr, len) 413*46809Sdab register unsigned char *ptr; 414*46809Sdab register int len; 41538905Sborman { 41640242Sborman register unsigned char func, flag; 41740242Sborman cc_t val; 418*46809Sdab register unsigned char *end = ptr + len; 41938905Sborman 42038905Sborman if (terminit()) { /* go ahead */ 42138905Sborman while (ptr < end) { 42238905Sborman func = *ptr++; 42338905Sborman if (ptr >= end) break; 42438905Sborman flag = *ptr++; 42538905Sborman if (ptr >= end) break; 42640242Sborman val = (cc_t)*ptr++; 42738905Sborman 42838905Sborman process_slc(func, flag, val); 42938905Sborman 43038905Sborman } 43138905Sborman } else { 43238905Sborman /* 43338905Sborman * save this slc buffer if it is the first, otherwise dump 43438905Sborman * it. 43538905Sborman */ 43644364Sborman if (def_slcbuf == (unsigned char *)0) { 43738905Sborman def_slclen = len; 43844364Sborman def_slcbuf = (unsigned char *)malloc((unsigned)len); 43944364Sborman if (def_slcbuf == (unsigned char *)0) 44038905Sborman return; /* too bad */ 44138905Sborman bcopy(ptr, def_slcbuf, len); 44238905Sborman } 44338905Sborman } 44438905Sborman 44538905Sborman } /* end of do_opt_slc */ 44638905Sborman 44738905Sborman /* 44838905Sborman * deferslc 44938905Sborman * 45038905Sborman * Do slc stuff that was deferred. 45138905Sborman */ 452*46809Sdab void 45338905Sborman deferslc() 45438905Sborman { 45538905Sborman if (def_slcbuf) { 45638905Sborman start_slc(1); 45738905Sborman do_opt_slc(def_slcbuf, def_slclen); 458*46809Sdab (void) end_slc(0); 45938905Sborman free(def_slcbuf); 46044364Sborman def_slcbuf = (unsigned char *)0; 46138905Sborman def_slclen = 0; 46238905Sborman } 46338905Sborman 46438905Sborman } /* end of deferslc */ 46538905Sborman 46638905Sborman #endif /* LINEMODE */ 467