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*46685Sbostic static char sccsid[] = "@(#)slc.c 5.6 (Berkeley) 02/26/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 */ 2938905Sborman send_slc() 3038905Sborman { 3138905Sborman register int i; 3238905Sborman 3338905Sborman /* 3438905Sborman * Send out list of triplets of special characters 3538905Sborman * to client. We only send info on the characters 3638905Sborman * that are currently supported. 3738905Sborman */ 3838905Sborman for (i = 1; i <= NSLC; i++) { 3945234Sborman if ((slctab[i].defset.flag & SLC_LEVELBITS) == SLC_NOSUPPORT) 4045234Sborman continue; 4145234Sborman add_slc((unsigned char)i, slctab[i].current.flag, 4238905Sborman slctab[i].current.val); 4338905Sborman } 4438905Sborman 4538905Sborman } /* end of send_slc */ 4638905Sborman 4738905Sborman /* 4838905Sborman * default_slc 4938905Sborman * 5038905Sborman * Set pty special characters to all the defaults. 5138905Sborman */ 5238905Sborman default_slc() 5338905Sborman { 5438905Sborman register int i; 5538905Sborman 5638905Sborman for (i = 1; i <= NSLC; i++) { 5738905Sborman slctab[i].current.val = slctab[i].defset.val; 5845234Sborman if (slctab[i].current.val == (cc_t)(_POSIX_VDISABLE)) 5945234Sborman slctab[i].current.flag = SLC_NOSUPPORT; 6045234Sborman else 6145234Sborman slctab[i].current.flag = slctab[i].defset.flag; 6238905Sborman if (slctab[i].sptr) { 6338905Sborman *(slctab[i].sptr) = slctab[i].defset.val; 6438905Sborman } 6538905Sborman } 6638905Sborman slcchange = 1; 6738905Sborman 6838905Sborman } /* end of default_slc */ 6938905Sborman #endif LINEMODE 7038905Sborman 7138905Sborman /* 7238905Sborman * get_slc_defaults 7338905Sborman * 7438905Sborman * Initialize the slc mapping table. 7538905Sborman */ 7638905Sborman get_slc_defaults() 7738905Sborman { 7838905Sborman register int i; 7938905Sborman 8038905Sborman init_termbuf(); 8138905Sborman 8238905Sborman for (i = 1; i <= NSLC; i++) { 8338905Sborman slctab[i].defset.flag = 8438905Sborman spcset(i, &slctab[i].defset.val, &slctab[i].sptr); 8538905Sborman slctab[i].current.flag = SLC_NOSUPPORT; 8638905Sborman slctab[i].current.val = 0; 8738905Sborman } 8838905Sborman 8938905Sborman } /* end of get_slc_defaults */ 9038905Sborman 9138905Sborman #ifdef LINEMODE 9238905Sborman /* 9338905Sborman * add_slc 9438905Sborman * 9538905Sborman * Add an slc triplet to the slc buffer. 9638905Sborman */ 9738905Sborman add_slc(func, flag, val) 9840242Sborman register unsigned char func, flag; 9940242Sborman cc_t val; 10038905Sborman { 10138905Sborman 10240242Sborman if ((*slcptr++ = func) == 0xff) 10338905Sborman *slcptr++ = 0xff; 10438905Sborman 10540242Sborman if ((*slcptr++ = flag) == 0xff) 10638905Sborman *slcptr++ = 0xff; 10738905Sborman 10840242Sborman if ((*slcptr++ = (unsigned char)val) == 0xff) 10938905Sborman *slcptr++ = 0xff; 11038905Sborman 11138905Sborman } /* end of add_slc */ 11238905Sborman 11338905Sborman /* 11438905Sborman * start_slc 11538905Sborman * 11638905Sborman * Get ready to process incoming slc's and respond to them. 11738905Sborman * 11838905Sborman * The parameter getit is non-zero if it is necessary to grab a copy 11938905Sborman * of the terminal control structures. 12038905Sborman */ 12138905Sborman start_slc(getit) 12238905Sborman register int getit; 12338905Sborman { 12438905Sborman 12538905Sborman slcchange = 0; 12638905Sborman if (getit) 12738905Sborman init_termbuf(); 128*46685Sbostic (void) sprintf((char *)slcbuf, 129*46685Sbostic "%c%c%c%c", IAC, SB, TELOPT_LINEMODE, LM_SLC); 13038905Sborman slcptr = slcbuf + 4; 13138905Sborman 13238905Sborman } /* end of start_slc */ 13338905Sborman 13438905Sborman /* 13538905Sborman * end_slc 13638905Sborman * 13738905Sborman * Finish up the slc negotiation. If something to send, then send it. 13838905Sborman */ 13938905Sborman end_slc(bufp) 14044364Sborman register unsigned char **bufp; 14138905Sborman { 14238905Sborman register int len; 14338905Sborman void netflush(); 14438905Sborman 14538905Sborman /* 14638905Sborman * If a change has occured, store the new terminal control 14738905Sborman * structures back to the terminal driver. 14838905Sborman */ 14938905Sborman if (slcchange) { 15038905Sborman set_termbuf(); 15138905Sborman } 15238905Sborman 15338905Sborman /* 15438905Sborman * If the pty state has not yet been fully processed and there is a 15538905Sborman * deferred slc request from the client, then do not send any 15638905Sborman * sort of slc negotiation now. We will respond to the client's 15738905Sborman * request very soon. 15838905Sborman */ 15938905Sborman if (def_slcbuf && (terminit() == 0)) { 16038905Sborman return; 16138905Sborman } 16238905Sborman 16338905Sborman if (slcptr > (slcbuf + 4)) { 16438905Sborman if (bufp) { 16538905Sborman *bufp = &slcbuf[4]; 16638905Sborman return(slcptr - slcbuf - 4); 16738905Sborman } else { 168*46685Sbostic (void) sprintf((char *)slcptr, "%c%c", IAC, SE); 16938905Sborman slcptr += 2; 17038905Sborman len = slcptr - slcbuf; 17138905Sborman writenet(slcbuf, len); 17238905Sborman netflush(); /* force it out immediately */ 17338905Sborman } 17438905Sborman } 17538905Sborman 17638905Sborman } /* end of end_slc */ 17738905Sborman 17838905Sborman /* 17938905Sborman * process_slc 18038905Sborman * 18138905Sborman * Figure out what to do about the client's slc 18238905Sborman */ 18338905Sborman process_slc(func, flag, val) 18440242Sborman register unsigned char func, flag; 18540242Sborman cc_t val; 18638905Sborman { 18738905Sborman register int hislevel, mylevel, ack; 18838905Sborman 18938905Sborman /* 19038905Sborman * Ensure that we know something about this function 19138905Sborman */ 19238905Sborman if (func > NSLC) { 19338905Sborman add_slc(func, SLC_NOSUPPORT, 0); 19438905Sborman return; 19538905Sborman } 19638905Sborman 19738905Sborman /* 19838905Sborman * Process the special case requests of 0 SLC_DEFAULT 0 19938905Sborman * and 0 SLC_VARIABLE 0. Be a little forgiving here, don't 20038905Sborman * worry about whether the value is actually 0 or not. 20138905Sborman */ 20238905Sborman if (func == 0) { 20338905Sborman if ((flag = flag & SLC_LEVELBITS) == SLC_DEFAULT) { 20438905Sborman default_slc(); 20545234Sborman send_slc(1); 20645234Sborman } else if (flag == SLC_VARIABLE) { 20745234Sborman send_slc(0); 20838905Sborman } 20938905Sborman return; 21038905Sborman } 21138905Sborman 21238905Sborman /* 21338905Sborman * Appears to be a function that we know something about. So 21438905Sborman * get on with it and see what we know. 21538905Sborman */ 21638905Sborman 21738905Sborman hislevel = flag & SLC_LEVELBITS; 21838905Sborman mylevel = slctab[func].current.flag & SLC_LEVELBITS; 21938905Sborman ack = flag & SLC_ACK; 22038905Sborman /* 22138905Sborman * ignore the command if: 22238905Sborman * the function value and level are the same as what we already have; 22338905Sborman * or the level is the same and the ack bit is set 22438905Sborman */ 22538905Sborman if (hislevel == mylevel && (val == slctab[func].current.val || ack)) { 22638905Sborman return; 22745234Sborman } else if (ack) { 22845234Sborman /* 22945234Sborman * If we get here, we got an ack, but the levels don't match. 23045234Sborman * This shouldn't happen. If it does, it is probably because 23145234Sborman * we have sent two requests to set a variable without getting 23245234Sborman * a response between them, and this is the first response. 23345234Sborman * So, ignore it, and wait for the next response. 23445234Sborman */ 23545234Sborman return; 23638905Sborman } else { 23738905Sborman change_slc(func, flag, val); 23838905Sborman } 23938905Sborman 24038905Sborman } /* end of process_slc */ 24138905Sborman 24238905Sborman /* 24338905Sborman * change_slc 24438905Sborman * 24538905Sborman * Process a request to change one of our special characters. 24638905Sborman * Compare client's request with what we are capable of supporting. 24738905Sborman */ 24838905Sborman change_slc(func, flag, val) 24940242Sborman register unsigned char func, flag; 25040242Sborman cc_t val; 25138905Sborman { 25238905Sborman register int hislevel, mylevel; 25338905Sborman 25438905Sborman hislevel = flag & SLC_LEVELBITS; 25538905Sborman mylevel = slctab[func].defset.flag & SLC_LEVELBITS; 25638905Sborman /* 25738905Sborman * If client is setting a function to NOSUPPORT 25838905Sborman * or DEFAULT, then we can easily and directly 25938905Sborman * accomodate the request. 26038905Sborman */ 26138905Sborman if (hislevel == SLC_NOSUPPORT) { 26238905Sborman slctab[func].current.flag = flag; 26345234Sborman slctab[func].current.val = (cc_t)_POSIX_VDISABLE; 26438905Sborman flag |= SLC_ACK; 26538905Sborman add_slc(func, flag, val); 26638905Sborman return; 26738905Sborman } 26838905Sborman if (hislevel == SLC_DEFAULT) { 26938905Sborman /* 27038905Sborman * Special case here. If client tells us to use 27138905Sborman * the default on a function we don't support, then 27238905Sborman * return NOSUPPORT instead of what we may have as a 27338905Sborman * default level of DEFAULT. 27438905Sborman */ 27538905Sborman if (mylevel == SLC_DEFAULT) { 27638905Sborman slctab[func].current.flag = SLC_NOSUPPORT; 27738905Sborman } else { 27838905Sborman slctab[func].current.flag = slctab[func].defset.flag; 27938905Sborman } 28038905Sborman slctab[func].current.val = slctab[func].defset.val; 28138905Sborman add_slc(func, slctab[func].current.flag, 28238905Sborman slctab[func].current.val); 28338905Sborman return; 28438905Sborman } 28538905Sborman 28638905Sborman /* 28738905Sborman * Client wants us to change to a new value or he 28838905Sborman * is telling us that he can't change to our value. 28938905Sborman * Some of the slc's we support and can change, 29038905Sborman * some we do support but can't change, 29138905Sborman * and others we don't support at all. 29238905Sborman * If we can change it then we have a pointer to 29338905Sborman * the place to put the new value, so change it, 29438905Sborman * otherwise, continue the negotiation. 29538905Sborman */ 29638905Sborman if (slctab[func].sptr) { 29738905Sborman /* 29838905Sborman * We can change this one. 29938905Sborman */ 30038905Sborman slctab[func].current.val = val; 30138905Sborman *(slctab[func].sptr) = val; 30238905Sborman slctab[func].current.flag = flag; 30338905Sborman flag |= SLC_ACK; 30438905Sborman slcchange = 1; 30538905Sborman add_slc(func, flag, val); 30638905Sborman } else { 30738905Sborman /* 30838905Sborman * It is not possible for us to support this 30938905Sborman * request as he asks. 31038905Sborman * 31138905Sborman * If our level is DEFAULT, then just ack whatever was 31238905Sborman * sent. 31338905Sborman * 31438905Sborman * If he can't change and we can't change, 31538905Sborman * then degenerate to NOSUPPORT. 31638905Sborman * 31738905Sborman * Otherwise we send our level back to him, (CANTCHANGE 31838905Sborman * or NOSUPPORT) and if CANTCHANGE, send 31938905Sborman * our value as well. 32038905Sborman */ 32138905Sborman if (mylevel == SLC_DEFAULT) { 32238905Sborman slctab[func].current.flag = flag; 32338905Sborman slctab[func].current.val = val; 32438905Sborman flag |= SLC_ACK; 32538905Sborman } else if (hislevel == SLC_CANTCHANGE && 32638905Sborman mylevel == SLC_CANTCHANGE) { 32738905Sborman flag &= ~SLC_LEVELBITS; 32838905Sborman flag |= SLC_NOSUPPORT; 32938905Sborman slctab[func].current.flag = flag; 33038905Sborman } else { 33138905Sborman flag &= ~SLC_LEVELBITS; 33238905Sborman flag |= mylevel; 33338905Sborman slctab[func].current.flag = flag; 33438905Sborman if (mylevel == SLC_CANTCHANGE) { 33538905Sborman slctab[func].current.val = 33638905Sborman slctab[func].defset.val; 33738905Sborman val = slctab[func].current.val; 33838905Sborman } 33938905Sborman 34038905Sborman } 34138905Sborman add_slc(func, flag, val); 34238905Sborman } 34338905Sborman 34438905Sborman } /* end of change_slc */ 34538905Sborman 34645234Sborman #if defined(USE_TERMIO) && (VEOF == VMIN) 34740242Sborman cc_t oldeofc = '\004'; 34840242Sborman #endif 34940242Sborman 35038905Sborman /* 35138905Sborman * check_slc 35238905Sborman * 35338905Sborman * Check the special characters in use and notify the client if any have 35438905Sborman * changed. Only those characters that are capable of being changed are 35538905Sborman * likely to have changed. If a local change occurs, kick the support level 35638905Sborman * and flags up to the defaults. 35738905Sborman */ 35838905Sborman check_slc() 35938905Sborman { 36038905Sborman register int i; 36138905Sborman 36238905Sborman for (i = 1; i <= NSLC; i++) { 36345234Sborman #if defined(USE_TERMIO) && (VEOF == VMIN) 36438905Sborman /* 36538905Sborman * In a perfect world this would be a neat little 36638905Sborman * function. But in this world, we should not notify 36738905Sborman * client of changes to the VEOF char when 36838905Sborman * ICANON is off, because it is not representing 36938905Sborman * a special character. 37038905Sborman */ 37140242Sborman if (i == SLC_EOF) { 37240242Sborman if (!tty_isediting()) 37340242Sborman continue; 37440242Sborman else if (slctab[i].sptr) 37540242Sborman oldeofc = *(slctab[i].sptr); 37640242Sborman } 37738905Sborman #endif /* defined(USE_TERMIO) && defined(SYSV_TERMIO) */ 37838905Sborman if (slctab[i].sptr && 37938905Sborman (*(slctab[i].sptr) != slctab[i].current.val)) { 38038905Sborman slctab[i].current.val = *(slctab[i].sptr); 38145234Sborman if (*(slctab[i].sptr) == (cc_t)_POSIX_VDISABLE) 38245234Sborman slctab[i].current.flag = SLC_NOSUPPORT; 38345234Sborman else 38445234Sborman slctab[i].current.flag = slctab[i].defset.flag; 38538905Sborman add_slc((unsigned char)i, slctab[i].current.flag, 38638905Sborman slctab[i].current.val); 38738905Sborman } 38838905Sborman } 38938905Sborman 39038905Sborman } /* check_slc */ 39138905Sborman 39238905Sborman /* 39338905Sborman * do_opt_slc 39438905Sborman * 39538905Sborman * Process an slc option buffer. Defer processing of incoming slc's 39638905Sborman * until after the terminal state has been processed. Save the first slc 39738905Sborman * request that comes along, but discard all others. 39838905Sborman * 39938905Sborman * ptr points to the beginning of the buffer, len is the length. 40038905Sborman */ 40138905Sborman do_opt_slc(ptr, len) 40238905Sborman register char *ptr; 40338905Sborman register int len; 40438905Sborman { 40540242Sborman register unsigned char func, flag; 40640242Sborman cc_t val; 40738905Sborman register char *end = (char *)(ptr + len); 40838905Sborman char *malloc(); 40938905Sborman 41038905Sborman if (terminit()) { /* go ahead */ 41138905Sborman while (ptr < end) { 41238905Sborman func = *ptr++; 41338905Sborman if (ptr >= end) break; 41438905Sborman flag = *ptr++; 41538905Sborman if (ptr >= end) break; 41640242Sborman val = (cc_t)*ptr++; 41738905Sborman 41838905Sborman process_slc(func, flag, val); 41938905Sborman 42038905Sborman } 42138905Sborman } else { 42238905Sborman /* 42338905Sborman * save this slc buffer if it is the first, otherwise dump 42438905Sborman * it. 42538905Sborman */ 42644364Sborman if (def_slcbuf == (unsigned char *)0) { 42738905Sborman def_slclen = len; 42844364Sborman def_slcbuf = (unsigned char *)malloc((unsigned)len); 42944364Sborman if (def_slcbuf == (unsigned char *)0) 43038905Sborman return; /* too bad */ 43138905Sborman bcopy(ptr, def_slcbuf, len); 43238905Sborman } 43338905Sborman } 43438905Sborman 43538905Sborman } /* end of do_opt_slc */ 43638905Sborman 43738905Sborman /* 43838905Sborman * deferslc 43938905Sborman * 44038905Sborman * Do slc stuff that was deferred. 44138905Sborman */ 44238905Sborman deferslc() 44338905Sborman { 44438905Sborman if (def_slcbuf) { 44538905Sborman start_slc(1); 44638905Sborman do_opt_slc(def_slcbuf, def_slclen); 44738905Sborman end_slc(0); 44838905Sborman free(def_slcbuf); 44944364Sborman def_slcbuf = (unsigned char *)0; 45038905Sborman def_slclen = 0; 45138905Sborman } 45238905Sborman 45338905Sborman } /* end of deferslc */ 45438905Sborman 45538905Sborman #endif /* LINEMODE */ 456