129088Smarkm/* 229088Smarkm * Copyright (c) 1989, 1993 329088Smarkm * The Regents of the University of California. All rights reserved. 429088Smarkm * 529088Smarkm * Redistribution and use in source and binary forms, with or without 629088Smarkm * modification, are permitted provided that the following conditions 729088Smarkm * are met: 829088Smarkm * 1. Redistributions of source code must retain the above copyright 929088Smarkm * notice, this list of conditions and the following disclaimer. 1029088Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1129088Smarkm * notice, this list of conditions and the following disclaimer in the 1229088Smarkm * documentation and/or other materials provided with the distribution. 1329088Smarkm * 3. All advertising materials mentioning features or use of this software 1429088Smarkm * must display the following acknowledgement: 1529088Smarkm * This product includes software developed by the University of 1629088Smarkm * California, Berkeley and its contributors. 1729088Smarkm * 4. Neither the name of the University nor the names of its contributors 1829088Smarkm * may be used to endorse or promote products derived from this software 1929088Smarkm * without specific prior written permission. 2029088Smarkm * 2129088Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2229088Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2329088Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2429088Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2529088Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2629088Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2729088Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2829088Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2929088Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3029088Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3129088Smarkm * SUCH DAMAGE. 3229088Smarkm */ 3329088Smarkm 34114630Sobrien#if 0 3529088Smarkm#ifndef lint 3629181Smarkmstatic const char sccsid[] = "@(#)slc.c 8.2 (Berkeley) 5/30/95"; 3731622Scharnier#endif 38114630Sobrien#endif 39114630Sobrien#include <sys/cdefs.h> 40114630Sobrien__FBSDID("$FreeBSD$"); 4129088Smarkm 4229088Smarkm#include "telnetd.h" 4329088Smarkm 4429088Smarkm#ifdef LINEMODE 4529088Smarkm/* 4631622Scharnier * local variables 4729088Smarkm */ 4829088Smarkmstatic unsigned char *def_slcbuf = (unsigned char *)0; 4929088Smarkmstatic int def_slclen = 0; 5029088Smarkmstatic int slcchange; /* change to slc is requested */ 5129088Smarkmstatic unsigned char *slcptr; /* pointer into slc buffer */ 5229088Smarkmstatic unsigned char slcbuf[NSLC*6]; /* buffer for slc negotiation */ 5329088Smarkm 5429088Smarkm/* 5529088Smarkm * send_slc 5629088Smarkm * 5729088Smarkm * Write out the current special characters to the client. 5829088Smarkm */ 5987139Smarkmvoid 6087139Smarkmsend_slc(void) 6129088Smarkm{ 6287139Smarkm int i; 6329088Smarkm 6429088Smarkm /* 6529088Smarkm * Send out list of triplets of special characters 6629088Smarkm * to client. We only send info on the characters 6729088Smarkm * that are currently supported. 6829088Smarkm */ 6929088Smarkm for (i = 1; i <= NSLC; i++) { 7029088Smarkm if ((slctab[i].defset.flag & SLC_LEVELBITS) == SLC_NOSUPPORT) 7129088Smarkm continue; 7229088Smarkm add_slc((unsigned char)i, slctab[i].current.flag, 7329088Smarkm slctab[i].current.val); 7429088Smarkm } 7529088Smarkm 7629088Smarkm} /* end of send_slc */ 7729088Smarkm 7829088Smarkm/* 7929088Smarkm * default_slc 8029088Smarkm * 8129088Smarkm * Set pty special characters to all the defaults. 8229088Smarkm */ 8387139Smarkmstatic void 8487139Smarkmdefault_slc(void) 8529088Smarkm{ 8687139Smarkm int i; 8729088Smarkm 8829088Smarkm for (i = 1; i <= NSLC; i++) { 8929088Smarkm slctab[i].current.val = slctab[i].defset.val; 9029088Smarkm if (slctab[i].current.val == (cc_t)(_POSIX_VDISABLE)) 9129088Smarkm slctab[i].current.flag = SLC_NOSUPPORT; 9229088Smarkm else 9329088Smarkm slctab[i].current.flag = slctab[i].defset.flag; 9429088Smarkm if (slctab[i].sptr) { 9529088Smarkm *(slctab[i].sptr) = slctab[i].defset.val; 9629088Smarkm } 9729088Smarkm } 9829088Smarkm slcchange = 1; 9929088Smarkm 10029088Smarkm} /* end of default_slc */ 10129088Smarkm#endif /* LINEMODE */ 10229088Smarkm 10329088Smarkm/* 10429088Smarkm * get_slc_defaults 10529088Smarkm * 10629088Smarkm * Initialize the slc mapping table. 10729088Smarkm */ 10887139Smarkmvoid 10987139Smarkmget_slc_defaults(void) 11029088Smarkm{ 11187139Smarkm int i; 11229088Smarkm 11329088Smarkm init_termbuf(); 11429088Smarkm 11529088Smarkm for (i = 1; i <= NSLC; i++) { 11629088Smarkm slctab[i].defset.flag = 11729088Smarkm spcset(i, &slctab[i].defset.val, &slctab[i].sptr); 11829088Smarkm slctab[i].current.flag = SLC_NOSUPPORT; 11929088Smarkm slctab[i].current.val = 0; 12029088Smarkm } 12129088Smarkm 12229088Smarkm} /* end of get_slc_defaults */ 12329088Smarkm 12429088Smarkm#ifdef LINEMODE 12529088Smarkm/* 12629088Smarkm * add_slc 12729088Smarkm * 12829088Smarkm * Add an slc triplet to the slc buffer. 12929088Smarkm */ 13087139Smarkmvoid 13187139Smarkmadd_slc(char func, char flag, cc_t val) 13229088Smarkm{ 13329088Smarkm 13429088Smarkm if ((*slcptr++ = (unsigned char)func) == 0xff) 13529088Smarkm *slcptr++ = 0xff; 13629088Smarkm 13729088Smarkm if ((*slcptr++ = (unsigned char)flag) == 0xff) 13829088Smarkm *slcptr++ = 0xff; 13929088Smarkm 14029088Smarkm if ((*slcptr++ = (unsigned char)val) == 0xff) 14129088Smarkm *slcptr++ = 0xff; 14229088Smarkm 14329088Smarkm} /* end of add_slc */ 14429088Smarkm 14529088Smarkm/* 14629088Smarkm * start_slc 14729088Smarkm * 14829088Smarkm * Get ready to process incoming slc's and respond to them. 14929088Smarkm * 15029088Smarkm * The parameter getit is non-zero if it is necessary to grab a copy 15129088Smarkm * of the terminal control structures. 15229088Smarkm */ 15387139Smarkmvoid 15487139Smarkmstart_slc(int getit) 15529088Smarkm{ 15629088Smarkm 15729088Smarkm slcchange = 0; 15829088Smarkm if (getit) 15929088Smarkm init_termbuf(); 16029088Smarkm (void) sprintf((char *)slcbuf, "%c%c%c%c", 16129088Smarkm IAC, SB, TELOPT_LINEMODE, LM_SLC); 16229088Smarkm slcptr = slcbuf + 4; 16329088Smarkm 16429088Smarkm} /* end of start_slc */ 16529088Smarkm 16629088Smarkm/* 16729088Smarkm * end_slc 16829088Smarkm * 16929088Smarkm * Finish up the slc negotiation. If something to send, then send it. 17029088Smarkm */ 17187139Smarkmint 17287139Smarkmend_slc(unsigned char **bufp) 17329088Smarkm{ 17487139Smarkm int len; 17529088Smarkm 17629088Smarkm /* 17729088Smarkm * If a change has occured, store the new terminal control 17829088Smarkm * structures back to the terminal driver. 17929088Smarkm */ 18029088Smarkm if (slcchange) { 18129088Smarkm set_termbuf(); 18229088Smarkm } 18329088Smarkm 18429088Smarkm /* 18529088Smarkm * If the pty state has not yet been fully processed and there is a 18629088Smarkm * deferred slc request from the client, then do not send any 18729088Smarkm * sort of slc negotiation now. We will respond to the client's 18829088Smarkm * request very soon. 18929088Smarkm */ 19029088Smarkm if (def_slcbuf && (terminit() == 0)) { 19129088Smarkm return(0); 19229088Smarkm } 19329088Smarkm 19429088Smarkm if (slcptr > (slcbuf + 4)) { 19529088Smarkm if (bufp) { 19629088Smarkm *bufp = &slcbuf[4]; 19729088Smarkm return(slcptr - slcbuf - 4); 19829088Smarkm } else { 19929088Smarkm (void) sprintf((char *)slcptr, "%c%c", IAC, SE); 20029088Smarkm slcptr += 2; 20129088Smarkm len = slcptr - slcbuf; 20280038Sru output_datalen(slcbuf, len); 20329088Smarkm netflush(); /* force it out immediately */ 20429088Smarkm DIAG(TD_OPTIONS, printsub('>', slcbuf+2, len-2);); 20529088Smarkm } 20629088Smarkm } 20729088Smarkm return (0); 20829088Smarkm 20929088Smarkm} /* end of end_slc */ 21029088Smarkm 21129088Smarkm/* 21229088Smarkm * process_slc 21329088Smarkm * 21429088Smarkm * Figure out what to do about the client's slc 21529088Smarkm */ 21687139Smarkmvoid 21787139Smarkmprocess_slc(unsigned char func, unsigned char flag, cc_t val) 21829088Smarkm{ 21987139Smarkm int hislevel, mylevel, ack; 22029088Smarkm 22129088Smarkm /* 22229088Smarkm * Ensure that we know something about this function 22329088Smarkm */ 22429088Smarkm if (func > NSLC) { 22529088Smarkm add_slc(func, SLC_NOSUPPORT, 0); 22629088Smarkm return; 22729088Smarkm } 22829088Smarkm 22929088Smarkm /* 23029088Smarkm * Process the special case requests of 0 SLC_DEFAULT 0 23129088Smarkm * and 0 SLC_VARIABLE 0. Be a little forgiving here, don't 23229088Smarkm * worry about whether the value is actually 0 or not. 23329088Smarkm */ 23429088Smarkm if (func == 0) { 23529088Smarkm if ((flag = flag & SLC_LEVELBITS) == SLC_DEFAULT) { 23629088Smarkm default_slc(); 23729088Smarkm send_slc(); 23829088Smarkm } else if (flag == SLC_VARIABLE) { 23929088Smarkm send_slc(); 24029088Smarkm } 24129088Smarkm return; 24229088Smarkm } 24329088Smarkm 24429088Smarkm /* 24529088Smarkm * Appears to be a function that we know something about. So 24629088Smarkm * get on with it and see what we know. 24729088Smarkm */ 24829088Smarkm 24929088Smarkm hislevel = flag & SLC_LEVELBITS; 25029088Smarkm mylevel = slctab[func].current.flag & SLC_LEVELBITS; 25129088Smarkm ack = flag & SLC_ACK; 25229088Smarkm /* 25329088Smarkm * ignore the command if: 25429088Smarkm * the function value and level are the same as what we already have; 25529088Smarkm * or the level is the same and the ack bit is set 25629088Smarkm */ 25729088Smarkm if (hislevel == mylevel && (val == slctab[func].current.val || ack)) { 25829088Smarkm return; 25929088Smarkm } else if (ack) { 26029088Smarkm /* 26129088Smarkm * If we get here, we got an ack, but the levels don't match. 26229088Smarkm * This shouldn't happen. If it does, it is probably because 26329088Smarkm * we have sent two requests to set a variable without getting 26429088Smarkm * a response between them, and this is the first response. 26529088Smarkm * So, ignore it, and wait for the next response. 26629088Smarkm */ 26729088Smarkm return; 26829088Smarkm } else { 26929088Smarkm change_slc(func, flag, val); 27029088Smarkm } 27129088Smarkm 27229088Smarkm} /* end of process_slc */ 27329088Smarkm 27429088Smarkm/* 27529088Smarkm * change_slc 27629088Smarkm * 27729088Smarkm * Process a request to change one of our special characters. 27829088Smarkm * Compare client's request with what we are capable of supporting. 27929088Smarkm */ 28087139Smarkmvoid 28187139Smarkmchange_slc(char func, char flag, cc_t val) 28229088Smarkm{ 28387139Smarkm int hislevel, mylevel; 28429088Smarkm 28529088Smarkm hislevel = flag & SLC_LEVELBITS; 28629181Smarkm mylevel = slctab[(int)func].defset.flag & SLC_LEVELBITS; 28729088Smarkm /* 28829088Smarkm * If client is setting a function to NOSUPPORT 28929088Smarkm * or DEFAULT, then we can easily and directly 29029088Smarkm * accomodate the request. 29129088Smarkm */ 29229088Smarkm if (hislevel == SLC_NOSUPPORT) { 29329181Smarkm slctab[(int)func].current.flag = flag; 29429181Smarkm slctab[(int)func].current.val = (cc_t)_POSIX_VDISABLE; 29529088Smarkm flag |= SLC_ACK; 29629088Smarkm add_slc(func, flag, val); 29729088Smarkm return; 29829088Smarkm } 29929088Smarkm if (hislevel == SLC_DEFAULT) { 30029088Smarkm /* 30129088Smarkm * Special case here. If client tells us to use 30229088Smarkm * the default on a function we don't support, then 30329088Smarkm * return NOSUPPORT instead of what we may have as a 30429088Smarkm * default level of DEFAULT. 30529088Smarkm */ 30629088Smarkm if (mylevel == SLC_DEFAULT) { 30729181Smarkm slctab[(int)func].current.flag = SLC_NOSUPPORT; 30829088Smarkm } else { 30929181Smarkm slctab[(int)func].current.flag = slctab[(int)func].defset.flag; 31029088Smarkm } 31129181Smarkm slctab[(int)func].current.val = slctab[(int)func].defset.val; 31229181Smarkm add_slc(func, slctab[(int)func].current.flag, 31329181Smarkm slctab[(int)func].current.val); 31429088Smarkm return; 31529088Smarkm } 31629088Smarkm 31729088Smarkm /* 31829088Smarkm * Client wants us to change to a new value or he 31929088Smarkm * is telling us that he can't change to our value. 32029088Smarkm * Some of the slc's we support and can change, 32129088Smarkm * some we do support but can't change, 32229088Smarkm * and others we don't support at all. 32329088Smarkm * If we can change it then we have a pointer to 32429088Smarkm * the place to put the new value, so change it, 32529088Smarkm * otherwise, continue the negotiation. 32629088Smarkm */ 32729181Smarkm if (slctab[(int)func].sptr) { 32829088Smarkm /* 32929088Smarkm * We can change this one. 33029088Smarkm */ 33129181Smarkm slctab[(int)func].current.val = val; 33229181Smarkm *(slctab[(int)func].sptr) = val; 33329181Smarkm slctab[(int)func].current.flag = flag; 33429088Smarkm flag |= SLC_ACK; 33529088Smarkm slcchange = 1; 33629088Smarkm add_slc(func, flag, val); 33729088Smarkm } else { 33829088Smarkm /* 33929088Smarkm * It is not possible for us to support this 34029088Smarkm * request as he asks. 34129088Smarkm * 34229088Smarkm * If our level is DEFAULT, then just ack whatever was 34329088Smarkm * sent. 34429088Smarkm * 34529088Smarkm * If he can't change and we can't change, 34629088Smarkm * then degenerate to NOSUPPORT. 34729088Smarkm * 34829088Smarkm * Otherwise we send our level back to him, (CANTCHANGE 34929088Smarkm * or NOSUPPORT) and if CANTCHANGE, send 35029088Smarkm * our value as well. 35129088Smarkm */ 35229088Smarkm if (mylevel == SLC_DEFAULT) { 35329181Smarkm slctab[(int)func].current.flag = flag; 35429181Smarkm slctab[(int)func].current.val = val; 35529088Smarkm flag |= SLC_ACK; 35629088Smarkm } else if (hislevel == SLC_CANTCHANGE && 35729088Smarkm mylevel == SLC_CANTCHANGE) { 35829088Smarkm flag &= ~SLC_LEVELBITS; 35929088Smarkm flag |= SLC_NOSUPPORT; 36029181Smarkm slctab[(int)func].current.flag = flag; 36129088Smarkm } else { 36229088Smarkm flag &= ~SLC_LEVELBITS; 36329088Smarkm flag |= mylevel; 36429181Smarkm slctab[(int)func].current.flag = flag; 36529088Smarkm if (mylevel == SLC_CANTCHANGE) { 36629181Smarkm slctab[(int)func].current.val = 36729181Smarkm slctab[(int)func].defset.val; 36829181Smarkm val = slctab[(int)func].current.val; 36929088Smarkm } 37029088Smarkm } 37129088Smarkm add_slc(func, flag, val); 37229088Smarkm } 37329088Smarkm 37429088Smarkm} /* end of change_slc */ 37529088Smarkm 37629088Smarkm#if defined(USE_TERMIO) && (VEOF == VMIN) 37729088Smarkmcc_t oldeofc = '\004'; 37829088Smarkm#endif 37929088Smarkm 38029088Smarkm/* 38129088Smarkm * check_slc 38229088Smarkm * 38329088Smarkm * Check the special characters in use and notify the client if any have 38429088Smarkm * changed. Only those characters that are capable of being changed are 38529088Smarkm * likely to have changed. If a local change occurs, kick the support level 38629088Smarkm * and flags up to the defaults. 38729088Smarkm */ 38887139Smarkmvoid 38987139Smarkmcheck_slc(void) 39029088Smarkm{ 39187139Smarkm int i; 39229088Smarkm 39329088Smarkm for (i = 1; i <= NSLC; i++) { 39429088Smarkm#if defined(USE_TERMIO) && (VEOF == VMIN) 39529088Smarkm /* 39629088Smarkm * In a perfect world this would be a neat little 39729088Smarkm * function. But in this world, we should not notify 39829088Smarkm * client of changes to the VEOF char when 39929088Smarkm * ICANON is off, because it is not representing 40029088Smarkm * a special character. 40129088Smarkm */ 40229088Smarkm if (i == SLC_EOF) { 40329088Smarkm if (!tty_isediting()) 40429088Smarkm continue; 40529088Smarkm else if (slctab[i].sptr) 40629088Smarkm oldeofc = *(slctab[i].sptr); 40729088Smarkm } 40829088Smarkm#endif /* defined(USE_TERMIO) && defined(SYSV_TERMIO) */ 40929088Smarkm if (slctab[i].sptr && 41029088Smarkm (*(slctab[i].sptr) != slctab[i].current.val)) { 41129088Smarkm slctab[i].current.val = *(slctab[i].sptr); 41229088Smarkm if (*(slctab[i].sptr) == (cc_t)_POSIX_VDISABLE) 41329088Smarkm slctab[i].current.flag = SLC_NOSUPPORT; 41429088Smarkm else 41529088Smarkm slctab[i].current.flag = slctab[i].defset.flag; 41629088Smarkm add_slc((unsigned char)i, slctab[i].current.flag, 41729088Smarkm slctab[i].current.val); 41829088Smarkm } 41929088Smarkm } 42029088Smarkm} /* check_slc */ 42129088Smarkm 42229088Smarkm/* 42329088Smarkm * do_opt_slc 42429088Smarkm * 42529088Smarkm * Process an slc option buffer. Defer processing of incoming slc's 42629088Smarkm * until after the terminal state has been processed. Save the first slc 42729088Smarkm * request that comes along, but discard all others. 42829088Smarkm * 42929088Smarkm * ptr points to the beginning of the buffer, len is the length. 43029088Smarkm */ 43187139Smarkmvoid 43287139Smarkmdo_opt_slc(unsigned char *ptr, int len) 43329088Smarkm{ 43487139Smarkm unsigned char func, flag; 43529088Smarkm cc_t val; 43687139Smarkm unsigned char *end = ptr + len; 43729088Smarkm 43829088Smarkm if (terminit()) { /* go ahead */ 43929088Smarkm while (ptr < end) { 44029088Smarkm func = *ptr++; 44129088Smarkm if (ptr >= end) break; 44229088Smarkm flag = *ptr++; 44329088Smarkm if (ptr >= end) break; 44429088Smarkm val = (cc_t)*ptr++; 44529088Smarkm 44629088Smarkm process_slc(func, flag, val); 44729088Smarkm 44829088Smarkm } 44929088Smarkm } else { 45029088Smarkm /* 45129088Smarkm * save this slc buffer if it is the first, otherwise dump 45229088Smarkm * it. 45329088Smarkm */ 45429088Smarkm if (def_slcbuf == (unsigned char *)0) { 45529088Smarkm def_slclen = len; 45629088Smarkm def_slcbuf = (unsigned char *)malloc((unsigned)len); 45729088Smarkm if (def_slcbuf == (unsigned char *)0) 45829088Smarkm return; /* too bad */ 45929088Smarkm memmove(def_slcbuf, ptr, len); 46029088Smarkm } 46129088Smarkm } 46229088Smarkm 46329088Smarkm} /* end of do_opt_slc */ 46429088Smarkm 46529088Smarkm/* 46629088Smarkm * deferslc 46729088Smarkm * 46829088Smarkm * Do slc stuff that was deferred. 46929088Smarkm */ 47087139Smarkmvoid 47187139Smarkmdeferslc(void) 47229088Smarkm{ 47329088Smarkm if (def_slcbuf) { 47429088Smarkm start_slc(1); 47529088Smarkm do_opt_slc(def_slcbuf, def_slclen); 47629088Smarkm (void) end_slc(0); 47729088Smarkm free(def_slcbuf); 47829088Smarkm def_slcbuf = (unsigned char *)0; 47929088Smarkm def_slclen = 0; 48029088Smarkm } 48129088Smarkm 48229088Smarkm} /* end of deferslc */ 48329088Smarkm 48429088Smarkm#endif /* LINEMODE */ 485