diff --git a/CHANGES b/CHANGES index 3fd8772..f56d4db 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,26 @@ CHANGES ======= +version 8.1.0 (Jan 18, 2004): + - fixes for HP-UX compilation - patch by Petter Reinholdtsen + + - fixes for compilation under various operating systems - + patch by Albert Chin + - added a 'protocol' option for either 'telnet' or 'raw' socket + communication - also reflected in -i output + - changed the client/server protocol to use 0xff as a command + character for sending control commands - similiar to the + telnet protocol - improves the ^Ec| interaction + - client -E option now disables ssl encryption attempts, useful + for broken SSL environents - suggested by Graydon Dodson + + - bad error message connecting non-ssl client with ssl-required + server - reported by Graydon Dodson + - added note about pam configuration to conserver.passwd.man - + suggested by Erik Sjolund + - improved telnet protocol option handling such that connections + to standard telnet ports should work properly + version 8.0.9 (Dec 10, 2003): - fixed major bug in connect() handling which causes most socket-based consoles to timeout after 10 seconds - reported @@ -643,5 +663,5 @@ before version 6.05: and enhancements of various types were applied. # -# $Id: CHANGES,v 1.141 2003/12/10 18:33:40 bryan Exp $ +# $Id: CHANGES,v 1.148 2004/01/18 17:28:31 bryan Exp $ # diff --git a/INSTALL b/INSTALL index 7f5f7f5..4b2f206 100644 --- a/INSTALL +++ b/INSTALL @@ -10,6 +10,14 @@ Upgrading? new features added to the client if you're considering *not* upgrading. + Version 8.1.0 + + - The client/server protocol has changed to better protect 8-bit + data and to allow programs invoked with '^Ec|' not have to + worry about accidentally sending the escape sequence to the + server. Though it will look like things are mostly + backward-compatible, don't count on it and just upgrade. + Version 8.0.2 - I've added a '^Ec;' sequence to allow the client to signal the @@ -255,5 +263,5 @@ Other Information And Gotchas # -# $Id: INSTALL,v 1.34 2003/10/03 17:52:31 bryan Exp $ +# $Id: INSTALL,v 1.35 2003/12/25 19:21:59 bryan Exp $ # diff --git a/config.guess b/config.guess index 61f2e4c..e8c6fc0 100755 --- a/config.guess +++ b/config.guess @@ -3,7 +3,7 @@ # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003 Free Software Foundation, Inc. -timestamp='2003-10-20' +timestamp='2004-01-05' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -1186,7 +1186,7 @@ EOF *:QNX:*:4*) echo i386-pc-qnx exit 0 ;; - NSR-[DGKLNPTVWY]:NONSTOP_KERNEL:*:*) + NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit 0 ;; *:NonStop-UX:*:*) diff --git a/config.h.in b/config.h.in index 18ea785..3e61e9e 100644 --- a/config.h.in +++ b/config.h.in @@ -348,3 +348,6 @@ /* Define if does not define sig_atomic_t */ #undef sig_atomic_t + +/* Define to `unsigned' if does not define. */ +#undef size_t diff --git a/config.sub b/config.sub index fac5195..463186d 100755 --- a/config.sub +++ b/config.sub @@ -3,7 +3,7 @@ # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003 Free Software Foundation, Inc. -timestamp='2003-11-20' +timestamp='2004-01-05' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software @@ -380,6 +380,9 @@ case $basic_machine in amd64) basic_machine=x86_64-pc ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; amdahl) basic_machine=580-amdahl os=-sysv diff --git a/configure b/configure index c6b04b4..a2ea8b1 100755 --- a/configure +++ b/configure @@ -3973,6 +3973,63 @@ _ACEOF fi +echo "$as_me:$LINENO: checking for size_t" >&5 +echo $ECHO_N "checking for size_t... $ECHO_C" >&6 +if test "${ac_cv_type_size_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if ((size_t *) 0) + return 0; +if (sizeof (size_t)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_size_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_size_t=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5 +echo "${ECHO_T}$ac_cv_type_size_t" >&6 +if test $ac_cv_type_size_t = yes; then + : +else + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned +_ACEOF + +fi + echo "$as_me:$LINENO: checking for sig_atomic_t" >&5 echo $ECHO_N "checking for sig_atomic_t... $ECHO_C" >&6 diff --git a/configure.in b/configure.in index ec87328..7402068 100644 --- a/configure.in +++ b/configure.in @@ -256,6 +256,7 @@ AC_HEADER_SYS_WAIT AC_TYPE_MODE_T AC_TYPE_SIGNAL AC_TYPE_PID_T +AC_TYPE_SIZE_T AC_CHECK_TYPE([sig_atomic_t],, AC_DEFINE(sig_atomic_t, volatile int, diff --git a/conserver.cf/Makefile.in b/conserver.cf/Makefile.in index db3abde..46b2ca6 100644 --- a/conserver.cf/Makefile.in +++ b/conserver.cf/Makefile.in @@ -3,7 +3,7 @@ srcdir = @srcdir@ prefix = @prefix@ mandir = @mandir@ sysconfdir = @sysconfdir@ -exampledir = $(prefix)/share/examples/conserver +exampledir = @datadir@/examples/conserver ### Installation programs and flags INSTALL = @INSTALL@ diff --git a/conserver.cf/conserver.cf.man b/conserver.cf/conserver.cf.man index 509424e..3e00280 100644 --- a/conserver.cf/conserver.cf.man +++ b/conserver.cf/conserver.cf.man @@ -1,5 +1,5 @@ -.\" $Id: conserver.cf.man,v 1.54 2003/12/10 18:33:56 bryan Exp $ -.TH CONSERVER.CF 5 "2003/12/10" "conserver-8.0.9" "conserver" +.\" $Id: conserver.cf.man,v 1.55 2003/12/21 16:23:03 bryan Exp $ +.TH CONSERVER.CF 5 "2003/12/21" "conserver-8.1.0" "conserver" .SH NAME conserver.cf \- console configuration file for .BR conserver (8) @@ -695,7 +695,7 @@ The conserver option .B \-7 will set this flag for all consoles. Default is -.BR !stiphigh . +.BR !striphigh . .TP .B reinitoncc Automatically reinitialize (``bring up'') a downed console when a client @@ -798,6 +798,21 @@ See .B port for the details of the formula. .TP +.B protocol +.RB [ " telnet " | " raw " ] +.br +Set the protocol used to send and receive data from the console. +If +.B raw +is used, all data is sent ``as is'', unprotected by any protocol specification. +If +.B telnet +is used (which is the default), data is encapsulated in the telnet protocol. +The +.B striphigh +console option still applies when data is read by the server, and if enabled, +can impact the encapsulation process. +.TP .B ro .RI "[ [\fB!\fP]" username ,... | "" ] diff --git a/conserver.cf/conserver.passwd.man b/conserver.cf/conserver.passwd.man index 141d225..ade8746 100644 --- a/conserver.cf/conserver.passwd.man +++ b/conserver.cf/conserver.passwd.man @@ -1,5 +1,5 @@ -.\" $Id: conserver.passwd.man,v 1.9 2003/07/04 20:20:52 bryan Exp $ -.TH CONSERVER.PASSWD 5 "2003/07/04" "conserver-8.0.9" "conserver" +.\" $Id: conserver.passwd.man,v 1.10 2004/01/08 16:12:33 bryan Exp $ +.TH CONSERVER.PASSWD 5 "2004/01/08" "conserver-8.1.0" "conserver" .SH NAME conserver.passwd \- user access information for .BR conserver (8) @@ -59,7 +59,8 @@ in the system If PAM support has been enabled .RB ( --with-pam ), PAM lookups will be done instead of -.BR passwd " (or " shadow ") lookups." +.BR passwd " (or " shadow ") lookups" +(you may need to edit /etc/pam.conf or create /etc/pam.d/conserver). If this field is empty, password checking is bypassed for this user. .SH EXAMPLE .TP 24 diff --git a/conserver.html b/conserver.html index b60b387..6df9889 100644 --- a/conserver.html +++ b/conserver.html @@ -183,11 +183,11 @@

Downloading

-

The current version, released on Dec 10, 2003, is 8.0.9.tar.gz. You can get it via +

The current version, released on Jan 18, 2004, is 8.1.0.tar.gz. You can get it via FTP - or HTTP. See the FTP + or HTTP. See the CHANGES file for information on the latest updates.

diff --git a/conserver/Makefile.in b/conserver/Makefile.in index c37b3aa..42f6de3 100644 --- a/conserver/Makefile.in +++ b/conserver/Makefile.in @@ -6,7 +6,7 @@ exec_prefix = @exec_prefix@ sbindir = @sbindir@ sysconfdir = @sysconfdir@ mandir = @mandir@ -exampledir = $(prefix)/share/examples/conserver +exampledir = @datadir@/examples/conserver ### Installation programs and flags INSTALL = @INSTALL@ diff --git a/conserver/client.h b/conserver/client.h index 820aa27..bc4d771 100644 --- a/conserver/client.h +++ b/conserver/client.h @@ -1,5 +1,5 @@ /* - * $Id: client.h,v 5.35 2003/11/28 15:55:34 bryan Exp $ + * $Id: client.h,v 5.36 2003/12/25 19:22:00 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -47,7 +47,8 @@ typedef enum clientState { S_PASSWD, /* still needs a passwd to connect */ S_QUOTE, /* send any character we can spell */ S_BCAST, /* send a broadcast message to all clients */ - S_CWAIT /* wait for client */ + S_CWAIT, /* wait for client */ + S_CEXEC /* client execing a program */ } CLIENTSTATE; typedef struct client { /* Connection Information: */ diff --git a/conserver/consent.c b/conserver/consent.c index 0784a9e..8fc2aed 100644 --- a/conserver/consent.c +++ b/conserver/consent.c @@ -1,5 +1,5 @@ /* - * $Id: consent.c,v 5.133 2003/12/10 18:33:47 bryan Exp $ + * $Id: consent.c,v 5.134 2003/12/20 06:11:53 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -691,7 +691,7 @@ ConsInit(pCE) TagLogfile(pCE, "Console up"); switch (pCE->type) { - case UNKNOWN: /* shut up gcc */ + case UNKNOWNTYPE: /* shut up gcc */ break; case EXEC: if ((cofile = @@ -826,7 +826,7 @@ ConsInit(pCE) } switch (pCE->type) { - case UNKNOWN: /* shut up gcc */ + case UNKNOWNTYPE: /* shut up gcc */ break; case EXEC: Verbose("[%s] pid %lu on %s", pCE->server, pCE->ipid, @@ -857,9 +857,9 @@ ConsInit(pCE) if (pCE->ioState == ISNORMAL) { pCE->lastWrite = tyme; if (pCE->idletimeout != (time_t)0 && - (timers[T_IDLE] == (time_t)0 || - timers[T_IDLE] > pCE->lastWrite + pCE->idletimeout)) - timers[T_IDLE] = pCE->lastWrite + pCE->idletimeout; + (timers[T_CIDLE] == (time_t)0 || + timers[T_CIDLE] > pCE->lastWrite + pCE->idletimeout)) + timers[T_CIDLE] = pCE->lastWrite + pCE->idletimeout; } /* If we have marks, adjust the next one so that it's in the future */ diff --git a/conserver/consent.h b/conserver/consent.h index 33bdd3c..90d5b3e 100644 --- a/conserver/consent.h +++ b/conserver/consent.h @@ -1,5 +1,5 @@ /* - * $Id: consent.h,v 5.53 2003/11/28 23:36:02 bryan Exp $ + * $Id: consent.h,v 5.55 2003/12/21 16:23:02 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -52,7 +52,7 @@ typedef struct parity { /* a parity bits table */ } PARITY; typedef enum consType { - UNKNOWN = 0, + UNKNOWNTYPE = 0, DEVICE, EXEC, HOST @@ -95,6 +95,7 @@ typedef struct consent { /* console information */ unsigned short port; /* port number socket = portbase + */ unsigned short portbase; /* port base portinc * port */ unsigned short portinc; /* port increment */ + unsigned short raw; /* raw or telnet protocol? */ /* type == EXEC */ char *exec; /* exec command */ char *execsubst; /* exec substitution pattern */ diff --git a/conserver/conserver.man b/conserver/conserver.man index 2ad6d67..e61e9e9 100644 --- a/conserver/conserver.man +++ b/conserver/conserver.man @@ -1,6 +1,6 @@ .\" @(#)conserver.8 01/06/91 OSU CIS; Thomas A. Fine .\" $Id: conserver.man,v 1.40 2003/11/10 15:37:24 bryan Exp $ -.TH CONSERVER 8 "2003/11/10" "conserver-8.0.9" "conserver" +.TH CONSERVER 8 "2003/11/10" "conserver-8.1.0" "conserver" .SH NAME conserver \- console server daemon .SH SYNOPSIS diff --git a/conserver/cutil.c b/conserver/cutil.c index 6ff34dc..aa3dc6b 100644 --- a/conserver/cutil.c +++ b/conserver/cutil.c @@ -1,5 +1,5 @@ /* - * $Id: cutil.c,v 1.109 2003/12/02 16:21:43 bryan Exp $ + * $Id: cutil.c,v 1.113 2004/01/18 13:05:43 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -238,6 +238,35 @@ BuildStringN(str, n, msg) return msg->string; } +void * +#if PROTOTYPES +MemMove(void *dest, void *src, size_t n) +#else +MemMove(void *dest, void *src, size_t n) + void *dest; + void *src; + size_t n; +#endif +{ +#if HAVE_MEMMOVE + return memmove(dest, src, n); +#else + char *s = src; + char *d = dest; + + if (s < d) { + /* Moving from low mem to hi mem; start at end. */ + for (s += n, d += n; n > 0; --n) + *--d = *--s; + } else if (s != d) { + /* Moving from hi mem to low mem; start at beginning. */ + for (; n > 0; --n) + *d++ = *s++; + } + return dest; +#endif +} + char * #if PROTOTYPES ShiftString(STRING *msg, int n) @@ -250,17 +279,8 @@ ShiftString(msg, n) if (msg == (STRING *)0 || n <= 0 || n > msg->used - 1) return (char *)0; -#if HAVE_MEMMOVE - memmove(msg->string, msg->string + n, msg->used - n); -#else - { - char *s, *e; - int len; - for (s = msg->string, e = s + n, len = msg->used - n; len > 0; - len--) - *s++ = *e++; - } -#endif + MemMove(msg->string, msg->string + n, msg->used - n); + msg->used -= n; return msg->string; } @@ -730,6 +750,27 @@ FileOpenFD(fd, type) cfp->ssl = (SSL *)0; cfp->waitForRead = cfp->waitForWrite = FLAGFALSE; #endif +#if DEBUG_CONSFILE_IO + { + char buf[1024]; + sprintf(buf, "CONSFILE-%s-%lu-%d.w", progname, + (unsigned long)thepid, fd); + if ((cfp->debugwfd = + open(buf, O_WRONLY | O_CREAT | O_APPEND, 0644)) != -1) { + sprintf(buf, "[---- STARTED - %s ----]\n", + StrTime((time_t *)0)); + write(cfp->debugwfd, buf, strlen(buf)); + } + sprintf(buf, "CONSFILE-%s-%lu-%d.r", progname, + (unsigned long)thepid, fd); + if ((cfp->debugrfd = + open(buf, O_WRONLY | O_CREAT | O_APPEND, 0644)) != -1) { + sprintf(buf, "[---- STARTED - %s ----]\n", + StrTime((time_t *)0)); + write(cfp->debugrfd, buf, strlen(buf)); + } + } +#endif CONDDEBUG((2, "FileOpenFD(): encapsulated fd %d type %d", fd, type)); return cfp; @@ -760,6 +801,27 @@ FileOpenPipe(fd, fdout) cfp->ssl = (SSL *)0; cfp->waitForRead = cfp->waitForWrite = FLAGFALSE; #endif +#if DEBUG_CONSFILE_IO + { + char buf[1024]; + sprintf(buf, "CONSFILE-%s-%lu-%d.w", progname, + (unsigned long)thepid, fdout); + if ((cfp->debugwfd = + open(buf, O_WRONLY | O_CREAT | O_APPEND, 0644)) != -1) { + sprintf(buf, "[---- STARTED - %s ----]\n", + StrTime((time_t *)0)); + write(cfp->debugwfd, buf, strlen(buf)); + } + sprintf(buf, "CONSFILE-%s-%lu-%d.r", progname, + (unsigned long)thepid, fd); + if ((cfp->debugrfd = + open(buf, O_WRONLY | O_CREAT | O_APPEND, 0644)) != -1) { + sprintf(buf, "[---- STARTED - %s ----]\n", + StrTime((time_t *)0)); + write(cfp->debugrfd, buf, strlen(buf)); + } + } +#endif CONDDEBUG((2, "FileOpenPipe(): encapsulated pipe pair fd %d and fd %d", fd, fdout)); @@ -798,6 +860,12 @@ FileUnopen(cfp) } CONDDEBUG((2, "FileUnopen(): unopened fd %d", cfp->fd)); DestroyString(cfp->wbuf); +#if DEBUG_CONSFILE_IO + if (cfp->debugwfd != -1) + close(cfp->debugwfd); + if (cfp->debugrfd != -1) + close(cfp->debugrfd); +#endif free(cfp); return retval; @@ -833,6 +901,27 @@ FileOpen(path, flag, mode) cfp->ssl = (SSL *)0; cfp->waitForRead = cfp->waitForWrite = FLAGFALSE; #endif +#if DEBUG_CONSFILE_IO + { + char buf[1024]; + sprintf(buf, "CONSFILE-%s-%lu-%d.w", progname, + (unsigned long)thepid, fd); + if ((cfp->debugwfd = + open(buf, O_WRONLY | O_CREAT | O_APPEND, 0644)) != -1) { + sprintf(buf, "[---- STARTED - %s ----]\n", + StrTime((time_t *)0)); + write(cfp->debugwfd, buf, strlen(buf)); + } + sprintf(buf, "CONSFILE-%s-%lu-%d.r", progname, + (unsigned long)thepid, fd); + if ((cfp->debugrfd = + open(buf, O_WRONLY | O_CREAT | O_APPEND, 0644)) != -1) { + sprintf(buf, "[---- STARTED - %s ----]\n", + StrTime((time_t *)0)); + write(cfp->debugrfd, buf, strlen(buf)); + } + } +#endif CONDDEBUG((2, "FileOpen(): opened `%s' as fd %d", path, fd)); return cfp; @@ -928,6 +1017,12 @@ FileClose(pcfp) CONDDEBUG((2, "FileClose(): closed fd %d", cfp->fd)); } DestroyString(cfp->wbuf); +#if DEBUG_CONSFILE_IO + if (cfp->debugwfd != -1) + close(cfp->debugwfd); + if (cfp->debugrfd != -1) + close(cfp->debugrfd); +#endif free(cfp); *pcfp = (CONSFILE *)0; @@ -969,6 +1064,10 @@ FileRead(cfp, buf, len) retval = -1; break; } +#if DEBUG_CONSFILE_IO + if (cfp->debugrfd != -1) + write(cfp->debugrfd, buf, retval); +#endif } break; #if HAVE_OPENSSL @@ -1007,6 +1106,10 @@ FileRead(cfp, buf, len) cfp->ftype = simpleSocket; break; } +#if DEBUG_CONSFILE_IO + if (cfp->debugrfd != -1) + write(cfp->debugrfd, buf, retval); +#endif break; #endif default: @@ -1080,9 +1183,23 @@ FileWrite(cfp, bufferonly, buf, len) tmpString->string, fdout)); } } + /* save the data */ - if (len > 0 && buf != (char *)0) - BuildStringN(buf, len, cfp->wbuf); + if (len > 0 && buf != (char *)0) { + if (cfp->quoteiac == FLAGTRUE) { + int l, o; + for (o = l = 0; l < len; l++) { + if (buf[l] == (char)OB_IAC) { + BuildStringN(buf + o, l + 1 - o, cfp->wbuf); + BuildStringChar((char)OB_IAC, cfp->wbuf); + o = l + 1; + } + } + if (o < len) + BuildStringN(buf + o, len - o, cfp->wbuf); + } else + BuildStringN(buf, len, cfp->wbuf); + } if (bufferonly == FLAGTRUE) return 0; @@ -1132,6 +1249,10 @@ FileWrite(cfp, bufferonly, buf, len) strerror(errno)); break; } +#if DEBUG_CONSFILE_IO + if (cfp->debugwfd != -1) + write(cfp->debugwfd, buf, retval); +#endif buf += retval; len -= retval; len_out += retval; @@ -1176,6 +1297,10 @@ FileWrite(cfp, bufferonly, buf, len) } if (retval <= 0) break; +#if DEBUG_CONSFILE_IO + if (cfp->debugwfd != -1) + write(cfp->debugwfd, buf, retval); +#endif buf += retval; len -= retval; len_out += retval; @@ -1757,6 +1882,58 @@ FileSetType(cfp, type) cfp->ftype = type; } +/* Sets the file quoting method */ +void +#if PROTOTYPES +FileSetQuoteIAC(CONSFILE *cfp, FLAG flag) +#else +FileSetQuoteIAC(cfp, flag) + CONSFILE *cfp; + FLAG flag; +#endif +{ + cfp->quoteiac = flag; +} + +FLAG +#if PROTOTYPES +FileSawQuoteSusp(CONSFILE *cfp) +#else +FileSawQuoteSusp(cfp) + CONSFILE *cfp; +#endif +{ + FLAG r = cfp->sawiacsusp; + cfp->sawiacsusp = FLAGFALSE; + return r; +} + +FLAG +#if PROTOTYPES +FileSawQuoteExec(CONSFILE *cfp) +#else +FileSawQuoteExec(cfp) + CONSFILE *cfp; +#endif +{ + FLAG r = cfp->sawiacexec; + cfp->sawiacexec = FLAGFALSE; + return r; +} + +FLAG +#if PROTOTYPES +FileSawQuoteAbrt(CONSFILE *cfp) +#else +FileSawQuoteAbrt(cfp) + CONSFILE *cfp; +#endif +{ + FLAG r = cfp->sawiacabrt; + cfp->sawiacabrt = FLAGFALSE; + return r; +} + #if HAVE_OPENSSL /* Get the SSL instance */ SSL * @@ -2088,3 +2265,106 @@ StrDup(msg) #endif return buf; } + +char * +#if PROTOTYPES +StringChar(STRING *msg, int offset, char c) +#else +StringChar(msg, offset, c) + STRING *msg; + int offset; + char c; +#endif +{ + int o; + + if (msg == (STRING *)0 || msg->used <= 1 || offset < 0 || + offset > msg->used) + return (char *)0; + + for (o = offset; o != msg->used; o++) { + if (msg->string[o] == c) + return &(msg->string[o]); + } + return (char *)0; +} + +/* this takes a buffer, and returns the number of characters to use, + * which goes up to the first OB_IAC character sequence (that isn't + * OB_IAC/OB_IAC). if it is an OB_IAC sequence, it sets the flag and + * returns zero. if it's invalid args, we return -1. + * so <0 == no data, 0 == check flags, >0 number of chars to use + * this *WILL* modify the buffer (OB_IAC sequences get extracted/shrunk) + */ +int +#if PROTOTYPES +ParseIACBuf(CONSFILE *cfp, void *msg, int *len) +#else +ParseIACBuf(cfp, msg, len) + CONSFILE *cfp; + void *msg; + int *len; +#endif +{ + int l = 0; + unsigned char *b = msg; + + if (*len <= 0) + return -1; + + if (cfp->quoteiac != FLAGTRUE) + return *len; + + /* split OB_IAC/char pair OR OB_IAC at start */ + if (cfp->sawiac == FLAGTRUE || b[0] == OB_IAC) { + int i = 1; + + if (cfp->sawiac == FLAGTRUE) { + i = 0; + cfp->sawiac = FLAGFALSE; + } + if (i == *len) { /* only thing is OB_IAC */ + cfp->sawiac = FLAGTRUE; + return -1; + } + + if (b[i] == OB_SUSP) + cfp->sawiacsusp = FLAGTRUE; + else if (b[i] == OB_EXEC) + cfp->sawiacexec = FLAGTRUE; + else if (b[i] == OB_ABRT) + cfp->sawiacabrt = FLAGTRUE; + else { + if (b[i] != OB_IAC) + Error + ("ParseIACBuf(): fd %d: unrecognized quoted-OB_IAC char", + cfp->fd, strerror(errno)); + l = 1; + } + *len = *len - i - 1 + l; + MemMove(b, b + i + 1 - l, *len); + if (l == 0) + return 0; + } + for (; l < *len; l++) { + if (b[l] == OB_IAC) { + if (l + 1 == *len) + return l; + else if (b[l + 1] == OB_SUSP) + return l; + else if (b[l + 1] == OB_EXEC) + return l; + else if (b[l + 1] == OB_ABRT) + return l; + else { + if (b[l + 1] != OB_IAC) + Error + ("ParseIACBuf(): fd %d: unrecognized quoted-OB_IAC char", + cfp->fd, strerror(errno)); + --(*len); + MemMove(b + l, b + l + 1, *len - l); + } + } + } + return l; +} diff --git a/conserver/cutil.h b/conserver/cutil.h index 45b002f..46ee9d5 100644 --- a/conserver/cutil.h +++ b/conserver/cutil.h @@ -1,5 +1,5 @@ /* - * $Id: cutil.h,v 1.57 2003/11/28 00:47:29 bryan Exp $ + * $Id: cutil.h,v 1.60 2004/01/18 13:05:43 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -18,9 +18,10 @@ /* communication constants */ +#define OB_IAC 0xff /* quote char */ #define OB_EXEC 'E' /* exec a command on the client */ #define OB_SUSP 'Z' /* suspended by server */ -#define OB_DROP '.' /* dropped by server */ +#define OB_ABRT '.' /* abort */ /* Struct to wrap information about a "file"... * This can be a socket, local file, whatever. We do this so @@ -68,6 +69,11 @@ typedef struct consFile { int fd; int fdout; /* only used when a simplePipe */ STRING *wbuf; + FLAG quoteiac; + FLAG sawiac; + FLAG sawiacsusp; + FLAG sawiacexec; + FLAG sawiacabrt; #if HAVE_OPENSSL /* SSL stuff */ SSL *ssl; @@ -75,6 +81,10 @@ typedef struct consFile { FLAG waitForRead; #endif /* Add crypto stuff to suit */ +#if DEBUG_CONSFILE_IO + int debugrfd; + int debugwfd; +#endif } CONSFILE; extern int isMultiProc, fDebug, fVerbose, fErrorPrinted; @@ -128,6 +138,10 @@ extern STRING *AllocString PARAMS((void)); extern char *ReadLine PARAMS((FILE *, STRING *, int *)); extern enum consFileType FileGetType PARAMS((CONSFILE *)); extern void FileSetType PARAMS((CONSFILE *, enum consFileType)); +extern void FileSetQuoteIAC PARAMS((CONSFILE *, FLAG)); +extern FLAG FileSawQuoteSusp PARAMS((CONSFILE *)); +extern FLAG FileSawQuoteExec PARAMS((CONSFILE *)); +extern FLAG FileSawQuoteAbrt PARAMS((CONSFILE *)); extern void Bye PARAMS((int)); extern void DestroyDataStructures PARAMS((void)); extern int IsMe PARAMS((char *)); @@ -137,6 +151,9 @@ extern int FileCanWrite PARAMS((CONSFILE *, fd_set *, fd_set *)); extern int FileBufEmpty PARAMS((CONSFILE *)); extern int SetFlags PARAMS((int, int, int)); extern char *StrDup PARAMS((char *)); +extern int ParseIACBuf PARAMS((CONSFILE *, void *, int *)); +extern void *MemMove PARAMS((void *, void *, size_t)); +extern char *StringChar PARAMS((STRING *, int, char)); #if HAVE_OPENSSL extern SSL *FileGetSSL PARAMS((CONSFILE *)); extern void FileSetSSL PARAMS((CONSFILE *, SSL *)); diff --git a/conserver/group.c b/conserver/group.c index f9c5d1e..b28abda 100644 --- a/conserver/group.c +++ b/conserver/group.c @@ -1,5 +1,5 @@ /* - * $Id: group.c,v 5.280 2003/12/10 18:33:47 bryan Exp $ + * $Id: group.c,v 5.284 2004/01/18 16:33:25 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -1350,14 +1350,6 @@ ReapVirt(pGE) } } -static char acStop[] = { /* buffer for OOB stop command */ - OB_SUSP -}; - -static char acExec[] = { /* buffer for OOB exec command */ - OB_EXEC -}; - int #if PROTOTYPES CheckPasswd(CONSCLIENT *pCL, char *pw_string) @@ -1482,8 +1474,14 @@ PutConsole(pCEServing, c, quote) * the wbufIAC variable...that way we don't have to do a string * search every time we flush this thing ('cause it should be * rather infrequent to have an IAC char). + * + * quote == 0, raw - processed by conserver + * quote == 1, console - processed by console + * quote == 2, telnet - processed by telnet protocol + * if console != telnet, 1 == 2 */ - if (quote && pCEServing->type == HOST && c == IAC) { + if (quote == 1 && pCEServing->type == HOST && !pCEServing->raw && + c == IAC) { BuildStringChar((char)c, pCEServing->wbuf); if (pCEServing->wbufIAC == 0) pCEServing->wbufIAC = pCEServing->wbuf->used; @@ -1853,7 +1851,7 @@ CommandExamine(pGE, pCLServing, pCEServing, tyme) b = "Netwk"; p = ' '; break; - case UNKNOWN: /* shut up gcc */ + case UNKNOWNTYPE: /* shut up gcc */ break; } FilePrint(pCLServing->fd, FLAGFALSE, @@ -2017,8 +2015,9 @@ CommandInfo(pGE, pCLServing, pCEServing, tyme) (unsigned long)pCE->ipid, pCE->execSlave); break; case HOST: - FilePrint(pCLServing->fd, FLAGTRUE, "!:%s,%hu", pCE->host, - pCE->port); + FilePrint(pCLServing->fd, FLAGTRUE, "!:%s,%hu,%s", + pCE->host, pCE->port, + (pCE->raw ? "raw" : "telnet")); break; case DEVICE: FilePrint(pCLServing->fd, FLAGTRUE, "/:%s,%s%c", @@ -2026,7 +2025,7 @@ CommandInfo(pGE, pCLServing, pCEServing, tyme) (pCE->baud ? pCE->baud->acrate : ""), (pCE->parity ? pCE->parity->key[0] : ' ')); break; - case UNKNOWN: /* shut up gcc */ + case UNKNOWNTYPE: /* shut up gcc */ break; } FilePrint(pCLServing->fd, FLAGTRUE, ",%d:", @@ -2089,8 +2088,10 @@ CommandInfo(pGE, pCLServing, pCEServing, tyme) s = BuildTmpString(",ixany"); if (pCE->ixoff == FLAGTRUE) s = BuildTmpString(",ixoff"); +#if defined(CRTSCTS) if (pCE->crtscts == FLAGTRUE) s = BuildTmpString(",crtscts"); +#endif if (pCE->ondemand == FLAGTRUE) s = BuildTmpString(",ondemand"); if (pCE->reinitoncc == FLAGTRUE) @@ -2216,6 +2217,36 @@ CommandWho(pGE, pCLServing, pCEServing, tyme) } } +char * +#if PROTOTYPES +TelOpt(int o) +#else +TelOpt(o) + int o; +#endif +{ + static char opt[128]; + char *telopts[] = { + "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME", + "STATUS", "TIMING MARK", "RCTE", "NAOL", "NAOP", + "NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", "NAOVTS", + "NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO", + "DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT", + "SEND LOCATION", "TERMINAL TYPE", "END OF RECORD", + "TACACS UID", "OUTPUT MARKING", "TTYLOC", + "3270 REGIME", "X.3 PAD", "NAWS", "TSPEED", "LFLOW", + "LINEMODE", "XDISPLOC", "OLD-ENVIRON", "AUTHENTICATION", + "ENCRYPT", "NEW-ENVIRON" + }; + + if (o < sizeof(telopts) / sizeof(char *)) + return telopts[o]; + else { + sprintf(opt, "%d", o); + return opt; + } +} + void #if PROTOTYPES DoConsoleRead(CONSENT *pCEServing) @@ -2245,11 +2276,13 @@ DoConsoleRead(pCEServing) CONDDEBUG((1, "DoConsoleRead(): read %d bytes from fd %d", nr, cofile)); - if (pCEServing->type == HOST) { + if (pCEServing->type == HOST && !pCEServing->raw) { /* Do a little Telnet Protocol interpretation * state = 0: normal * = 1: Saw a IAC char - * = 2: Saw a DONT/DO/WONT/WILL command + * = 2: Saw a DONT/WONT command + * = 3: Saw a WILL command + * = 4: Saw a DO command * = 5: Saw a \r */ int new = 0, state; @@ -2260,17 +2293,61 @@ DoConsoleRead(pCEServing) pCEServing->server)); state = 1; } else if (state == 1 && acInOrig[i] != IAC) { - CONDDEBUG((1, "DoConsoleRead(): [%s] got telnet cmd `%u'", - pCEServing->server, acInOrig[i])); - if (acInOrig[i] == DONT || acInOrig[i] == DO || - acInOrig[i] == WILL || acInOrig[i] == WONT) + if (acInOrig[i] == WILL) { + state = 3; + CONDDEBUG((1, + "DoConsoleRead(): [%s] got telnet cmd `WILL'", + pCEServing->server)); + } else if (acInOrig[i] == DO) { + state = 4; + CONDDEBUG((1, + "DoConsoleRead(): [%s] got telnet cmd `DO'", + pCEServing->server)); + } else if (acInOrig[i] == DONT) { state = 2; - else + CONDDEBUG((1, + "DoConsoleRead(): [%s] got telnet cmd `DONT'", + pCEServing->server)); + } else if (acInOrig[i] == WONT) { + state = 2; + CONDDEBUG((1, + "DoConsoleRead(): [%s] got telnet cmd `WONT'", + pCEServing->server)); + } else { + CONDDEBUG((1, + "DoConsoleRead(): [%s] got telnet cmd `%u'", + pCEServing->server, acInOrig[i])); state = 0; + } } else if (state == 2) { CONDDEBUG((1, - "DoConsoleRead(): [%s] got telnet option `%u'", - pCEServing->server, acInOrig[i])); + "DoConsoleRead(): [%s] got telnet option `%s'", + pCEServing->server, TelOpt(acInOrig[i]))); + state = 0; + } else if (state == 3) { + CONDDEBUG((1, + "DoConsoleRead(): [%s] got telnet option `%s'", + pCEServing->server, TelOpt(acInOrig[i]))); + if (acInOrig[i] == TELOPT_ECHO || + acInOrig[i] == TELOPT_SGA) { + PutConsole(pCEServing, IAC, 2); + PutConsole(pCEServing, DO, 2); + PutConsole(pCEServing, acInOrig[i], 2); + CONDDEBUG((1, + "DoConsoleRead(): [%s] sent telnet DO `%s'", + pCEServing->server, TelOpt(acInOrig[i]))); + } + state = 0; + } else if (state == 4) { + CONDDEBUG((1, + "DoConsoleRead(): [%s] got telnet option `%s'", + pCEServing->server, TelOpt(acInOrig[i]))); + PutConsole(pCEServing, IAC, 2); + PutConsole(pCEServing, WONT, 2); + PutConsole(pCEServing, acInOrig[i], 2); + CONDDEBUG((1, + "DoConsoleRead(): [%s] sent telnet WONT `%s'", + pCEServing->server, TelOpt(acInOrig[i]))); state = 0; } else { if (state == 5) { @@ -2360,9 +2437,8 @@ DoConsoleRead(pCEServing) */ for (pCL = pCEServing->pCLon; (CONSCLIENT *)0 != pCL; pCL = pCL->pCLnext) { - if (pCL->fcon) { + if (pCL->fcon || pCL->iState == S_CEXEC) FileWrite(pCL->fd, FLAGFALSE, (char *)acIn, nr); - } } } @@ -2411,7 +2487,7 @@ DoClientRead(pGE, pCLServing) struct termios sbuf; CONSENT *pCEServing = pCLServing->pCEto; CONSENT *pCE; - int nr, i; + int nr, i, l; unsigned char acIn[BUFSIZ], acInOrig[BUFSIZ]; time_t tyme; static STRING *bcast = (STRING *)0; @@ -2430,187 +2506,201 @@ DoClientRead(pGE, pCLServing) DisconnectClient(pGE, pCLServing, (char *)0, FLAGFALSE); return; } + if (nr == 0) return; - /* update last keystroke time - */ + /* update last keystroke time */ pCLServing->typetym = tyme = time((time_t *)0); - for (i = 0; i < nr; ++i) { - acInOrig[i] = acIn[i]; - if (pCEServing->striphigh == FLAGTRUE) { - acIn[i] &= 127; + while ((l = ParseIACBuf(pCLServing->fd, acIn, &nr)) >= 0) { + if (l == 0) { + if (FileSawQuoteExec(pCLServing->fd) == FLAGTRUE) { + if (pCLServing->iState == S_CWAIT) { + pCLServing->iState = S_CEXEC; + if (pCEServing->pCLwr == pCLServing) + FileWrite(pCLServing->fd, FLAGFALSE, "[rw]\r\n", + 6); + else + FileWrite(pCLServing->fd, FLAGFALSE, "[ro]\r\n", + 6); + } + } + if (FileSawQuoteAbrt(pCLServing->fd) == FLAGTRUE) { + if (pCLServing->iState == S_CWAIT || + pCLServing->iState == S_CEXEC) { + pCLServing->fcon = 1; + pCLServing->iState = S_NORMAL; + } + } + /* not used (yet?) + if (FileSawQuoteSusp(pCLServing->fd) == FLAGTRUE) { + } + */ + continue; } - } - for (i = 0; i < nr; ++i) { - if (pGE->pCEctl == pCEServing) { - static char *pcArgs; - static char *pcCmd; - - if ('\n' != acIn[i]) { - BuildStringChar(acIn[i], pCLServing->accmd); - continue; - } - if ((pCLServing->accmd->used > 1) && - ('\r' == - pCLServing->accmd->string[pCLServing->accmd->used - 2])) { - pCLServing->accmd->string[pCLServing->accmd->used - 2] = - '\000'; - pCLServing->accmd->used--; + for (i = 0; i < l; ++i) { + acInOrig[i] = acIn[i]; + if (pCEServing->striphigh == FLAGTRUE) { + acIn[i] &= 127; } + } - /* process password here...before we corrupt accmd */ - if (pCLServing->iState == S_PASSWD) { - if (CheckPasswd(pCLServing, pCLServing->accmd->string) != - AUTH_SUCCESS) { - FileWrite(pCLServing->fd, FLAGFALSE, - "invalid password\r\n", -1); - BuildString((char *)0, pCLServing->accmd); - DisconnectClient(pGE, pCLServing, (char *)0, - FLAGFALSE); - return; + for (i = 0; i < l; ++i) { + if (pGE->pCEctl == pCEServing) { + static char *pcArgs; + static char *pcCmd; + + if ('\n' != acIn[i]) { + BuildStringChar(acIn[i], pCLServing->accmd); + continue; } - Verbose(" login %s", pCLServing->acid->string); - FileWrite(pCLServing->fd, FLAGFALSE, "ok\r\n", -1); - pCLServing->iState = S_NORMAL; - BuildString((char *)0, pCLServing->accmd); - continue; - } - - if ((pcArgs = - strchr(pCLServing->accmd->string, ' ')) != (char *)0) { - *pcArgs++ = '\000'; - } - if (pcArgs != (char *)0) - pcArgs = PruneSpace(pcArgs); - pcCmd = PruneSpace(pCLServing->accmd->string); - - if (strcmp(pcCmd, "help") == 0) { - static char *apcHelp1[] = { - "exit disconnect\r\n", - "help this help message\r\n", - "login log in\r\n", -#if HAVE_OPENSSL - "ssl start ssl session\r\n", -#endif - (char *)0 - }; - static char *apcHelp2[] = { - "broadcast send broadcast message\r\n", - "call connect to given console\r\n", - "disconnect* disconnect the given user(s)\r\n", - "examine examine port and baud rates\r\n", - "exit disconnect\r\n", - "group show users in this group\r\n", - "help this help message\r\n", - "hosts show host status and user\r\n", - "info show console information\r\n", - "textmsg send a text message\r\n", - "* = requires admin privileges\r\n", - (char *)0 - }; - char **ppc; - for (ppc = - (pCLServing->iState == S_IDENT ? apcHelp1 : apcHelp2); - (char *)0 != *ppc; ++ppc) { - FileWrite(pCLServing->fd, FLAGTRUE, *ppc, -1); + if ((pCLServing->accmd->used > 1) && + ('\r' == + pCLServing->accmd->string[pCLServing->accmd->used - + 2])) { + pCLServing->accmd->string[pCLServing->accmd->used - + 2] = '\000'; + pCLServing->accmd->used--; } - FileWrite(pCLServing->fd, FLAGFALSE, (char *)0, 0); - } else if (strcmp(pcCmd, "exit") == 0) { - FileWrite(pCLServing->fd, FLAGFALSE, "goodbye\r\n", -1); - DisconnectClient(pGE, pCLServing, (char *)0, FLAGFALSE); - return; -#if HAVE_OPENSSL - } else if (pCLServing->iState == S_IDENT && - strcmp(pcCmd, "ssl") == 0) { - FileWrite(pCLServing->fd, FLAGFALSE, "ok\r\n", -1); - if (!AttemptSSL(pCLServing)) { - DisconnectClient(pGE, pCLServing, (char *)0, - FLAGFALSE); - return; - } -#endif - } else if (pCLServing->iState == S_IDENT && - strcmp(pcCmd, "login") == 0) { -#if HAVE_OPENSSL - if (config->sslrequired == FLAGTRUE && - FileGetType(pCLServing->fd) != SSLSocket) { - FileWrite(pCLServing->fd, FLAGFALSE, - "encryption required\r\n", -1); - } else { -#endif - if (pcArgs == (char *)0) { + + /* process password here...before we corrupt accmd */ + if (pCLServing->iState == S_PASSWD) { + if (CheckPasswd(pCLServing, pCLServing->accmd->string) + != AUTH_SUCCESS) { FileWrite(pCLServing->fd, FLAGFALSE, - "login requires argument\r\n", -1); - } else { - BuildString((char *)0, pCLServing->username); - BuildString((char *)0, pCLServing->acid); - BuildString(pcArgs, pCLServing->username); - BuildString(pcArgs, pCLServing->acid); - BuildStringChar('@', pCLServing->acid); - BuildString(pCLServing->peername->string, - pCLServing->acid); - if (pCLServing->caccess == 't' || - CheckPasswd(pCLServing, "") == AUTH_SUCCESS) { - pCLServing->iState = S_NORMAL; - Verbose(" login %s", - pCLServing->acid->string); - FileWrite(pCLServing->fd, FLAGFALSE, "ok\r\n", - -1); - } else { - FilePrint(pCLServing->fd, FLAGFALSE, - "passwd? %s\r\n", myHostname); - pCLServing->iState = S_PASSWD; - } + "invalid password\r\n", -1); + BuildString((char *)0, pCLServing->accmd); + DisconnectClient(pGE, pCLServing, (char *)0, + FLAGFALSE); + return; } -#if HAVE_OPENSSL + Verbose(" login %s", pCLServing->acid->string); + FileWrite(pCLServing->fd, FLAGFALSE, "ok\r\n", -1); + pCLServing->iState = S_NORMAL; + BuildString((char *)0, pCLServing->accmd); + continue; } + + if ((pcArgs = + strchr(pCLServing->accmd->string, + ' ')) != (char *)0) { + *pcArgs++ = '\000'; + } + if (pcArgs != (char *)0) + pcArgs = PruneSpace(pcArgs); + pcCmd = PruneSpace(pCLServing->accmd->string); + + if (strcmp(pcCmd, "help") == 0) { + static char *apcHelp1[] = { + "exit disconnect\r\n", + "help this help message\r\n", + "login log in\r\n", +#if HAVE_OPENSSL + "ssl start ssl session\r\n", #endif - } else if (pCLServing->iState == S_NORMAL && - strcmp(pcCmd, "call") == 0) { - if (pcArgs == (char *)0) - FileWrite(pCLServing->fd, FLAGFALSE, - "call requires argument\r\n", -1); - else { - CONSENT *pCEwant = (CONSENT *)0; - /* try to move to the given console - * we assume all the right checks for ambiguity - * were already done by the master process, so - * the first match should be what the user wants - */ - for (pCE = pGE->pCElist; pCE != (CONSENT *)0; - pCE = pCE->pCEnext) { - NAMES *n = (NAMES *)0; - if (strcasecmp(pcArgs, pCE->server) - == 0) { - pCEwant = pCE; - break; - } - for (n = pCE->aliases; n != (NAMES *)0; - n = n->next) { - if (strcasecmp(pcArgs, n->name) - == 0) { - pCEwant = pCE; - break; + (char *)0 + }; + static char *apcHelp2[] = { + "broadcast send broadcast message\r\n", + "call connect to given console\r\n", + "disconnect* disconnect the given user(s)\r\n", + "examine examine port and baud rates\r\n", + "exit disconnect\r\n", + "group show users in this group\r\n", + "help this help message\r\n", + "hosts show host status and user\r\n", + "info show console information\r\n", + "textmsg send a text message\r\n", + "* = requires admin privileges\r\n", + (char *)0 + }; + char **ppc; + for (ppc = + (pCLServing->iState == + S_IDENT ? apcHelp1 : apcHelp2); + (char *)0 != *ppc; ++ppc) { + FileWrite(pCLServing->fd, FLAGTRUE, *ppc, -1); + } + FileWrite(pCLServing->fd, FLAGFALSE, (char *)0, 0); + } else if (strcmp(pcCmd, "exit") == 0) { + FileWrite(pCLServing->fd, FLAGFALSE, "goodbye\r\n", + -1); + DisconnectClient(pGE, pCLServing, (char *)0, + FLAGFALSE); + return; +#if HAVE_OPENSSL + } else if (pCLServing->iState == S_IDENT && + strcmp(pcCmd, "ssl") == 0) { + FileWrite(pCLServing->fd, FLAGFALSE, "ok\r\n", -1); + if (!AttemptSSL(pCLServing)) { + DisconnectClient(pGE, pCLServing, (char *)0, + FLAGFALSE); + return; + } +#endif + } else if (pCLServing->iState == S_IDENT && + strcmp(pcCmd, "login") == 0) { +#if HAVE_OPENSSL + if (config->sslrequired == FLAGTRUE && + FileGetType(pCLServing->fd) != SSLSocket) { + FileWrite(pCLServing->fd, FLAGFALSE, + "encryption required\r\n", -1); + } else { +#endif + if (pcArgs == (char *)0) { + FileWrite(pCLServing->fd, FLAGFALSE, + "login requires argument\r\n", -1); + } else { + BuildString((char *)0, pCLServing->username); + BuildString((char *)0, pCLServing->acid); + BuildString(pcArgs, pCLServing->username); + BuildString(pcArgs, pCLServing->acid); + BuildStringChar('@', pCLServing->acid); + BuildString(pCLServing->peername->string, + pCLServing->acid); + if (pCLServing->caccess == 't' || + CheckPasswd(pCLServing, + "") == AUTH_SUCCESS) { + pCLServing->iState = S_NORMAL; + Verbose(" login %s", + pCLServing->acid->string); + FileWrite(pCLServing->fd, FLAGFALSE, + "ok\r\n", -1); + } else { + FilePrint(pCLServing->fd, FLAGFALSE, + "passwd? %s\r\n", myHostname); + pCLServing->iState = S_PASSWD; } } - if (n != (NAMES *)0) - break; +#if HAVE_OPENSSL } - if (pCEwant == (CONSENT *)0) { - NAMES *n = (NAMES *)0; - int len = strlen(pcArgs); +#endif + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "call") == 0) { + if (pcArgs == (char *)0) + FileWrite(pCLServing->fd, FLAGFALSE, + "call requires argument\r\n", -1); + else { + CONSENT *pCEwant = (CONSENT *)0; + /* try to move to the given console + * we assume all the right checks for ambiguity + * were already done by the master process, so + * the first match should be what the user wants + */ for (pCE = pGE->pCElist; pCE != (CONSENT *)0; pCE = pCE->pCEnext) { - if (strncasecmp(pcArgs, pCE->server, len) == 0) { + NAMES *n = (NAMES *)0; + if (strcasecmp(pcArgs, pCE->server) + == 0) { pCEwant = pCE; break; } for (n = pCE->aliases; n != (NAMES *)0; n = n->next) { - if (strncasecmp(pcArgs, n->name, len) == 0) { + if (strcasecmp(pcArgs, n->name) + == 0) { pCEwant = pCE; break; } @@ -2618,215 +2708,229 @@ DoClientRead(pGE, pCLServing) if (n != (NAMES *)0) break; } + if (pCEwant == (CONSENT *)0) { + NAMES *n = (NAMES *)0; + int len = strlen(pcArgs); + for (pCE = pGE->pCElist; pCE != (CONSENT *)0; + pCE = pCE->pCEnext) { + if (strncasecmp(pcArgs, pCE->server, len) + == 0) { + pCEwant = pCE; + break; + } + for (n = pCE->aliases; n != (NAMES *)0; + n = n->next) { + if (strncasecmp(pcArgs, n->name, len) + == 0) { + pCEwant = pCE; + break; + } + } + if (n != (NAMES *)0) + break; + } + } + + if (pCEwant == (CONSENT *)0) { + FilePrint(pCLServing->fd, FLAGFALSE, + "%s: no such console\r\n", pcArgs); + DisconnectClient(pGE, pCLServing, (char *)0, + FLAGFALSE); + return; + } + + pCLServing->fro = + ClientAccess(pCEwant, + pCLServing->username->string); + if (pCLServing->fro == -1) { + FilePrint(pCLServing->fd, FLAGFALSE, + "%s: permission denied\r\n", pcArgs); + DisconnectClient(pGE, pCLServing, (char *)0, + FLAGFALSE); + return; + } + + /* remove from current host */ + if ((CONSCLIENT *)0 != pCLServing->pCLnext) { + pCLServing->pCLnext->ppCLbnext = + pCLServing->ppCLbnext; + } + *(pCLServing->ppCLbnext) = pCLServing->pCLnext; + if (pCLServing->fwr) { + pCLServing->fwr = 0; + pCLServing->fwantwr = 0; + TagLogfileAct(pCEServing, "%s detached", + pCLServing->acid->string); + pCEServing->pCLwr = (CONSCLIENT *)0; + FindWrite(pCEServing); + } + + /* inform operators of the change + */ + Verbose(" attach %s to %s", + pCLServing->acid->string, pCEwant->server); + Msg("[%s] login %s", pCEwant->server, + pCLServing->acid->string); + + /* set new host and link into new host list + */ + pCEServing = pCEwant; + pCLServing->pCEto = pCEServing; + pCLServing->pCLnext = pCEServing->pCLon; + pCLServing->ppCLbnext = &pCEServing->pCLon; + if ((CONSCLIENT *)0 != pCLServing->pCLnext) { + pCLServing->pCLnext->ppCLbnext = + &pCLServing->pCLnext; + } + pCEServing->pCLon = pCLServing; + + /* try to reopen line if specified at server startup + */ + if ((pCEServing->ondemand == FLAGTRUE || + pCEServing->reinitoncc == FLAGTRUE) && + !pCEServing->fup) + ConsInit(pCEServing); + + /* try for attach on new console + */ + if (pCEServing->fronly) { + FileWrite(pCLServing->fd, FLAGFALSE, + "[console is read-only]\r\n", -1); + } else if (pCEServing->initfile != (CONSFILE *)0 || + pCEServing->ioState == INCONNECT) { + pCLServing->fwantwr = 1; + FileWrite(pCLServing->fd, FLAGFALSE, + "[read-only -- initializing]\r\n", + -1); + } else + if (! + (pCEServing->fup && + pCEServing->ioState == ISNORMAL)) { + FileWrite(pCLServing->fd, FLAGFALSE, + "[line to console is down]\r\n", -1); + } else if (((CONSCLIENT *)0 == pCEServing->pCLwr) + && !pCLServing->fro) { + pCEServing->pCLwr = pCLServing; + pCLServing->fwr = 1; + FileWrite(pCLServing->fd, FLAGFALSE, + "[attached]\r\n", -1); + /* this keeps the ops console neat */ + pCEServing->iend = 0; + TagLogfileAct(pCEServing, "%s attached", + pCLServing->acid->string); + } else { + pCLServing->fwantwr = 1; + FileWrite(pCLServing->fd, FLAGFALSE, + "[spy]\r\n", -1); + } + pCLServing->fcon = 0; + pCLServing->iState = S_NORMAL; } - - if (pCEwant == (CONSENT *)0) { - FilePrint(pCLServing->fd, FLAGFALSE, - "%s: no such console\r\n", pcArgs); - DisconnectClient(pGE, pCLServing, (char *)0, - FLAGFALSE); - return; - } - - pCLServing->fro = - ClientAccess(pCEwant, - pCLServing->username->string); - if (pCLServing->fro == -1) { - FilePrint(pCLServing->fd, FLAGFALSE, - "%s: permission denied\r\n", pcArgs); - DisconnectClient(pGE, pCLServing, (char *)0, - FLAGFALSE); - return; - } - - /* remove from current host */ - if ((CONSCLIENT *)0 != pCLServing->pCLnext) { - pCLServing->pCLnext->ppCLbnext = - pCLServing->ppCLbnext; - } - *(pCLServing->ppCLbnext) = pCLServing->pCLnext; - if (pCLServing->fwr) { - pCLServing->fwr = 0; - pCLServing->fwantwr = 0; - TagLogfileAct(pCEServing, "%s detached", - pCLServing->acid->string); - pCEServing->pCLwr = (CONSCLIENT *)0; - FindWrite(pCEServing); - } - - /* inform operators of the change - */ - Verbose(" attach %s to %s", - pCLServing->acid->string, pCEwant->server); - Msg("[%s] login %s", pCEwant->server, - pCLServing->acid->string); - - /* set new host and link into new host list - */ - pCEServing = pCEwant; - pCLServing->pCEto = pCEServing; - pCLServing->pCLnext = pCEServing->pCLon; - pCLServing->ppCLbnext = &pCEServing->pCLon; - if ((CONSCLIENT *)0 != pCLServing->pCLnext) { - pCLServing->pCLnext->ppCLbnext = - &pCLServing->pCLnext; - } - pCEServing->pCLon = pCLServing; - - /* try to reopen line if specified at server startup - */ - if ((pCEServing->ondemand == FLAGTRUE || - pCEServing->reinitoncc == FLAGTRUE) && - !pCEServing->fup) - ConsInit(pCEServing); - - /* try for attach on new console - */ - if (pCEServing->fronly) { + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "info") == 0) { + CommandInfo(pGE, pCLServing, pCEServing, tyme); + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "examine") == 0) { + CommandExamine(pGE, pCLServing, pCEServing, tyme); + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "group") == 0) { + CommandGroup(pGE, pCLServing, pCEServing, tyme); + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "hosts") == 0) { + CommandHosts(pGE, pCLServing, pCEServing, tyme); + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "broadcast") == 0) { + if (pcArgs == (char *)0) { FileWrite(pCLServing->fd, FLAGFALSE, - "[console is read-only]\r\n", -1); - } else if (pCEServing->initfile != (CONSFILE *)0 || - pCEServing->ioState == INCONNECT) { - pCLServing->fwantwr = 1; - FileWrite(pCLServing->fd, FLAGFALSE, - "[read-only -- initializing]\r\n", -1); - } else - if (! - (pCEServing->fup && - pCEServing->ioState == ISNORMAL)) { - FileWrite(pCLServing->fd, FLAGFALSE, - "[line to console is down]\r\n", -1); - } else if (((CONSCLIENT *)0 == pCEServing->pCLwr) - && !pCLServing->fro) { - pCEServing->pCLwr = pCLServing; - pCLServing->fwr = 1; - FileWrite(pCLServing->fd, FLAGFALSE, - "[attached]\r\n", -1); - /* this keeps the ops console neat */ - pCEServing->iend = 0; - TagLogfileAct(pCEServing, "%s attached", - pCLServing->acid->string); + "broadcast requires argument\r\n", -1); } else { - pCLServing->fwantwr = 1; - FileWrite(pCLServing->fd, FLAGFALSE, "[spy]\r\n", - -1); - } - pCLServing->fcon = 0; - pCLServing->iState = S_NORMAL; - } - } else if (pCLServing->iState == S_NORMAL && - strcmp(pcCmd, "info") == 0) { - CommandInfo(pGE, pCLServing, pCEServing, tyme); - } else if (pCLServing->iState == S_NORMAL && - strcmp(pcCmd, "examine") == 0) { - CommandExamine(pGE, pCLServing, pCEServing, tyme); - } else if (pCLServing->iState == S_NORMAL && - strcmp(pcCmd, "group") == 0) { - CommandGroup(pGE, pCLServing, pCEServing, tyme); - } else if (pCLServing->iState == S_NORMAL && - strcmp(pcCmd, "hosts") == 0) { - CommandHosts(pGE, pCLServing, pCEServing, tyme); - } else if (pCLServing->iState == S_NORMAL && - strcmp(pcCmd, "broadcast") == 0) { - if (pcArgs == (char *)0) { - FileWrite(pCLServing->fd, FLAGFALSE, - "broadcast requires argument\r\n", -1); - } else { - BuildString((char *)0, bcast); - BuildStringChar('[', bcast); - BuildString(pCLServing->acid->string, bcast); - BuildString(": ", bcast); - BuildString(pcArgs, bcast); - BuildString("]\r\n", bcast); - SendAllClientsMsg(pGE, bcast->string); - FileWrite(pCLServing->fd, FLAGFALSE, "ok\r\n", -1); - } - } else if (pCLServing->iState == S_NORMAL && - strcmp(pcCmd, "textmsg") == 0) { - char *pcMsg; - if (pcArgs == (char *)0) { - FileWrite(pCLServing->fd, FLAGFALSE, - "textmsg requires two arguments\r\n", -1); - } else { - if ((pcMsg = strchr(pcArgs, ' ')) != (char *)0) { - *pcMsg++ = '\000'; - } - if (pcMsg == (char *)0) { - FileWrite(pCLServing->fd, FLAGFALSE, - "textmsg requires two arguments\r\n", - -1); - } else { - pcMsg = PruneSpace(pcMsg); - BuildString((char *)0, bcast); BuildStringChar('[', bcast); BuildString(pCLServing->acid->string, bcast); BuildString(": ", bcast); - BuildString(pcMsg, bcast); + BuildString(pcArgs, bcast); BuildString("]\r\n", bcast); - - SendCertainClientsMsg(pGE, pcArgs, bcast->string); + SendAllClientsMsg(pGE, bcast->string); FileWrite(pCLServing->fd, FLAGFALSE, "ok\r\n", -1); } - } - } else if (pCLServing->iState == S_NORMAL && - strcmp(pcCmd, "disconnect") == 0) { - if (pcArgs == (char *)0) { - FileWrite(pCLServing->fd, FLAGFALSE, - "disconnect requires argument\r\n", -1); - } else { - if (ConsentUserOk - (pADList, pCLServing->username->string) == 1) { - int num; - Verbose("disconnect command (of `%s') by %s", - pcArgs, pCLServing->acid->string); - num = - DisconnectCertainClients(pGE, - pCLServing->acid-> - string, pcArgs); - /* client expects this string to be formatted - * in this way only. - */ - FilePrint(pCLServing->fd, FLAGFALSE, - "ok -- disconnected %d users\r\n", num); - } else + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "textmsg") == 0) { + char *pcMsg; + if (pcArgs == (char *)0) { FileWrite(pCLServing->fd, FLAGFALSE, - "unauthorized command\r\n", -1); + "textmsg requires two arguments\r\n", + -1); + } else { + if ((pcMsg = strchr(pcArgs, ' ')) != (char *)0) { + *pcMsg++ = '\000'; + } + if (pcMsg == (char *)0) { + FileWrite(pCLServing->fd, FLAGFALSE, + "textmsg requires two arguments\r\n", + -1); + } else { + pcMsg = PruneSpace(pcMsg); + + BuildString((char *)0, bcast); + BuildStringChar('[', bcast); + BuildString(pCLServing->acid->string, bcast); + BuildString(": ", bcast); + BuildString(pcMsg, bcast); + BuildString("]\r\n", bcast); + + SendCertainClientsMsg(pGE, pcArgs, + bcast->string); + FileWrite(pCLServing->fd, FLAGFALSE, "ok\r\n", + -1); + } + } + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "disconnect") == 0) { + if (pcArgs == (char *)0) { + FileWrite(pCLServing->fd, FLAGFALSE, + "disconnect requires argument\r\n", -1); + } else { + if (ConsentUserOk + (pADList, pCLServing->username->string) == 1) { + int num; + Verbose("disconnect command (of `%s') by %s", + pcArgs, pCLServing->acid->string); + num = + DisconnectCertainClients(pGE, + pCLServing->acid-> + string, pcArgs); + /* client expects this string to be formatted + * in this way only. + */ + FilePrint(pCLServing->fd, FLAGFALSE, + "ok -- disconnected %d users\r\n", + num); + } else + FileWrite(pCLServing->fd, FLAGFALSE, + "unauthorized command\r\n", -1); + } + } else { + FileWrite(pCLServing->fd, FLAGFALSE, + "unknown command\r\n", -1); } - } else { - FileWrite(pCLServing->fd, FLAGFALSE, "unknown command\r\n", - -1); - } - BuildString((char *)0, pCLServing->accmd); - } else - switch (pCLServing->iState) { - case S_IDENT: - case S_PASSWD: - /* these are not used in this mode */ - break; - case S_BCAST: - /* gather message */ - if ('\r' != acIn[i]) { - if (acIn[i] == '\a' || - (acIn[i] >= ' ' && acIn[i] <= '~')) { - BuildStringChar(acIn[i], pCLServing->msg); - if (pGE->pCEctl != pCEServing) - FileWrite(pCLServing->fd, FLAGFALSE, - (char *)&acIn[i], 1); - } else if ((acIn[i] == '\b' || acIn[i] == 0x7f) - && pCLServing->msg->used > 1) { - if (pCLServing->msg-> - string[pCLServing->msg->used - 2] != '\a' - && pGE->pCEctl != pCEServing) { - FileWrite(pCLServing->fd, FLAGFALSE, - "\b \b", 3); - } - pCLServing->msg->string[pCLServing->msg->used - - 2] = '\000'; - pCLServing->msg->used--; - } else if ((acIn[i] == 0x15) && - pCLServing->msg->used > 1) { - while (pCLServing->msg->used > 1) { + BuildString((char *)0, pCLServing->accmd); + } else + switch (pCLServing->iState) { + case S_IDENT: + case S_PASSWD: + /* these are not used in this mode */ + break; + case S_BCAST: + /* gather message */ + if ('\r' != acIn[i]) { + if (acIn[i] == '\a' || + (acIn[i] >= ' ' && acIn[i] <= '~')) { + BuildStringChar(acIn[i], pCLServing->msg); + if (pGE->pCEctl != pCEServing) + FileWrite(pCLServing->fd, FLAGFALSE, + (char *)&acIn[i], 1); + } else if ((acIn[i] == '\b' || acIn[i] == 0x7f) + && pCLServing->msg->used > 1) { if (pCLServing->msg-> string[pCLServing->msg->used - 2] != '\a' && pGE->pCEctl != pCEServing) { @@ -2836,527 +2940,559 @@ DoClientRead(pGE, pCLServing) pCLServing->msg->string[pCLServing->msg-> used - 2] = '\000'; pCLServing->msg->used--; + } else if ((acIn[i] == 0x15) && + pCLServing->msg->used > 1) { + while (pCLServing->msg->used > 1) { + if (pCLServing->msg-> + string[pCLServing->msg->used - + 2] != '\a' && + pGE->pCEctl != pCEServing) { + FileWrite(pCLServing->fd, + FLAGFALSE, "\b \b", 3); + } + pCLServing->msg->string[pCLServing-> + msg->used - + 2] = '\000'; + pCLServing->msg->used--; + } } - } - continue; - } - FileWrite(pCLServing->fd, FLAGFALSE, "]\r\n", 3); - BuildString((char *)0, bcast); - BuildStringChar('[', bcast); - BuildString(pCLServing->acid->string, bcast); - BuildString(": ", bcast); - BuildString(pCLServing->msg->string, bcast); - BuildString("]\r\n", bcast); - SendClientsMsg(pCEServing, bcast->string); - - BuildString((char *)0, pCLServing->msg); - pCLServing->iState = S_NORMAL; - continue; - - case S_QUOTE: /* send octal code */ - /* must type in 3 octal digits */ - if (acIn[i] >= '0' && acIn[i] <= '7') { - BuildStringChar(acIn[i], pCLServing->accmd); - if (pCLServing->accmd->used < 4) { - FileWrite(pCLServing->fd, FLAGFALSE, - (char *)&acIn[i], 1); continue; } - FileWrite(pCLServing->fd, FLAGTRUE, - (char *)&acIn[i], 1); - FileWrite(pCLServing->fd, FLAGFALSE, "]", 1); + FileWrite(pCLServing->fd, FLAGFALSE, "]\r\n", 3); + BuildString((char *)0, bcast); + BuildStringChar('[', bcast); + BuildString(pCLServing->acid->string, bcast); + BuildString(": ", bcast); + BuildString(pCLServing->msg->string, bcast); + BuildString("]\r\n", bcast); + SendClientsMsg(pCEServing, bcast->string); - pCLServing->accmd->string[0] = - (((pCLServing->accmd->string[0] - '0') * 8 + - (pCLServing->accmd->string[1] - '0')) * 8) + - (pCLServing->accmd->string[2] - '0'); - PutConsole(pCEServing, - pCLServing->accmd->string[0], 1); - BuildString((char *)0, pCLServing->accmd); - } else { - FileWrite(pCLServing->fd, FLAGFALSE, - " aborted]\r\n", -1); - } - pCLServing->iState = S_NORMAL; - continue; + BuildString((char *)0, pCLServing->msg); + pCLServing->iState = S_NORMAL; + continue; - case S_SUSP: - if (! - (pCEServing->fup && - pCEServing->ioState == ISNORMAL)) { - FileWrite(pCLServing->fd, FLAGFALSE, - " -- line down]\r\n", -1); - } else if (pCEServing->fronly) { - FileWrite(pCLServing->fd, FLAGFALSE, - " -- read-only]\r\n", -1); - } else if (((CONSCLIENT *)0 == pCEServing->pCLwr) - && !pCLServing->fro) { - pCEServing->pCLwr = pCLServing; - pCLServing->fwr = 1; - if (pCEServing->nolog) { - FileWrite(pCLServing->fd, FLAGFALSE, - " -- attached (nologging)]\r\n", -1); + case S_QUOTE: /* send octal code */ + /* must type in 3 octal digits */ + if (acIn[i] >= '0' && acIn[i] <= '7') { + BuildStringChar(acIn[i], pCLServing->accmd); + if (pCLServing->accmd->used < 4) { + FileWrite(pCLServing->fd, FLAGFALSE, + (char *)&acIn[i], 1); + continue; + } + FileWrite(pCLServing->fd, FLAGTRUE, + (char *)&acIn[i], 1); + FileWrite(pCLServing->fd, FLAGFALSE, "]", 1); + + pCLServing->accmd->string[0] = + (((pCLServing->accmd->string[0] - + '0') * 8 + + (pCLServing->accmd->string[1] - + '0')) * 8) + + (pCLServing->accmd->string[2] - '0'); + PutConsole(pCEServing, + pCLServing->accmd->string[0], 1); + BuildString((char *)0, pCLServing->accmd); } else { FileWrite(pCLServing->fd, FLAGFALSE, - " -- attached]\r\n", -1); + " aborted]\r\n", -1); } - TagLogfileAct(pCEServing, "%s attached", - pCLServing->acid->string); - } else { - FileWrite(pCLServing->fd, FLAGFALSE, - " -- spy mode]\r\n", -1); - } - /* fall through */ - case S_CWAIT: - pCLServing->fcon = 1; - pCLServing->iState = S_NORMAL; - if (acInOrig[i] == OB_EXEC) { - if (pCEServing->pCLwr == pCLServing) + pCLServing->iState = S_NORMAL; + continue; + + case S_SUSP: + if (! + (pCEServing->fup && + pCEServing->ioState == ISNORMAL)) { FileWrite(pCLServing->fd, FLAGFALSE, - "[rw]\r\n", -1); - else + " -- line down]\r\n", -1); + } else if (pCEServing->fronly) { FileWrite(pCLServing->fd, FLAGFALSE, - "[ro]\r\n", -1); - } - continue; - - case S_NORMAL: - /* if it is an escape sequence shift states - */ - if (acInOrig[i] == pCLServing->ic[0]) { - pCLServing->iState = S_ESC1; - continue; - } - /* if we can write, write to slave tty - */ - if (pCLServing->fwr) { - PutConsole(pCEServing, acIn[i], 1); - continue; - } - /* if the client is stuck in spy mode - * give them a clue as to how to get out - * (LLL nice to put chars out as ^Ec, rather - * than octal escapes, but....) - */ - if ('\r' == acIn[i] || '\n' == acIn[i]) { - FilePrint(pCLServing->fd, FLAGFALSE, - "[read-only -- use %s %s ? for help]\r\n", - FmtCtl(pCLServing->ic[0], acA1), - FmtCtl(pCLServing->ic[1], acA2)); - } - continue; - - case S_HALT1: /* halt sequence? */ - pCLServing->iState = S_NORMAL; - if (acIn[i] != '?' && (acIn[i] < '0' || acIn[i] > '9')) { - FileWrite(pCLServing->fd, FLAGFALSE, - "aborted]\r\n", -1); - continue; - } - - if (acIn[i] == '?') { - int i; - FileWrite(pCLServing->fd, FLAGFALSE, "list]\r\n", - -1); - i = pCEServing->breakNum; - if (i == 0 || breakList[i - 1].seq->used <= 1) - FileWrite(pCLServing->fd, FLAGTRUE, - " 0 - 0ms, \r\n", -1); - else { - FmtCtlStr(breakList[i - 1].seq->string, - breakList[i - 1].seq->used - 1, - acA1); - FilePrint(pCLServing->fd, FLAGTRUE, - " 0 - %3dms, `%s'\r\n", - breakList[i - 1].delay, - acA1->string); + " -- read-only]\r\n", -1); + } else if (((CONSCLIENT *)0 == pCEServing->pCLwr) + && !pCLServing->fro) { + pCEServing->pCLwr = pCLServing; + pCLServing->fwr = 1; + if (pCEServing->nolog) { + FileWrite(pCLServing->fd, FLAGFALSE, + " -- attached (nologging)]\r\n", + -1); + } else { + FileWrite(pCLServing->fd, FLAGFALSE, + " -- attached]\r\n", -1); + } + TagLogfileAct(pCEServing, "%s attached", + pCLServing->acid->string); + } else { + FileWrite(pCLServing->fd, FLAGFALSE, + " -- spy mode]\r\n", -1); } - for (i = 0; i < 9; i++) { - if (breakList[i].seq->used > 1) { - FmtCtlStr(breakList[i].seq->string, - breakList[i].seq->used - 1, + pCLServing->fcon = 1; + pCLServing->iState = S_NORMAL; + continue; + + case S_CWAIT: + continue; + + case S_NORMAL: + /* if it is an escape sequence shift states + */ + if (acInOrig[i] == pCLServing->ic[0]) { + pCLServing->iState = S_ESC1; + continue; + } + /* fall through */ + case S_CEXEC: + /* if we can write, write to slave tty + */ + if (pCLServing->fwr) { + PutConsole(pCEServing, acIn[i], 1); + continue; + } + /* if the client is stuck in spy mode + * give them a clue as to how to get out + * (LLL nice to put chars out as ^Ec, rather + * than octal escapes, but....) + */ + if ('\r' == acIn[i] || '\n' == acIn[i]) { + FilePrint(pCLServing->fd, FLAGFALSE, + "[read-only -- use %s %s ? for help]\r\n", + FmtCtl(pCLServing->ic[0], acA1), + FmtCtl(pCLServing->ic[1], acA2)); + } + continue; + + case S_HALT1: /* halt sequence? */ + pCLServing->iState = S_NORMAL; + if (acIn[i] != '?' && + (acIn[i] < '0' || acIn[i] > '9')) { + FileWrite(pCLServing->fd, FLAGFALSE, + "aborted]\r\n", -1); + continue; + } + + if (acIn[i] == '?') { + int i; + FileWrite(pCLServing->fd, FLAGFALSE, + "list]\r\n", -1); + i = pCEServing->breakNum; + if (i == 0 || breakList[i - 1].seq->used <= 1) + FileWrite(pCLServing->fd, FLAGTRUE, + " 0 - 0ms, \r\n", + -1); + else { + FmtCtlStr(breakList[i - 1].seq->string, + breakList[i - 1].seq->used - 1, acA1); FilePrint(pCLServing->fd, FLAGTRUE, - " %d - %3dms, `%s'\r\n", i + 1, - breakList[i].delay, + " 0 - %3dms, `%s'\r\n", + breakList[i - 1].delay, acA1->string); } + for (i = 0; i < 9; i++) { + if (breakList[i].seq->used > 1) { + FmtCtlStr(breakList[i].seq->string, + breakList[i].seq->used - 1, + acA1); + FilePrint(pCLServing->fd, FLAGTRUE, + " %d - %3dms, `%s'\r\n", + i + 1, breakList[i].delay, + acA1->string); + } + } + FileWrite(pCLServing->fd, FLAGFALSE, (char *)0, + 0); + } else { + if (pCLServing->fwr) { + int bt = acIn[i] - '0'; + SendBreak(pCLServing, pCEServing, bt); + } else + FileWrite(pCLServing->fd, FLAGFALSE, + "attach to send break]\r\n", -1); } - FileWrite(pCLServing->fd, FLAGFALSE, (char *)0, 0); - } else { - if (pCLServing->fwr) { - int bt = acIn[i] - '0'; - SendBreak(pCLServing, pCEServing, bt); - } else - FileWrite(pCLServing->fd, FLAGFALSE, - "attach to send break]\r\n", -1); - } - continue; - - case S_CATTN: /* redef escape sequence? */ - pCLServing->ic[0] = acInOrig[i]; - FmtCtl(acInOrig[i], acA1); - FilePrint(pCLServing->fd, FLAGFALSE, "%s ", - acA1->string); - pCLServing->iState = S_CESC; - continue; - - case S_CESC: /* escape sequent 2 */ - pCLServing->ic[1] = acInOrig[i]; - pCLServing->iState = S_NORMAL; - FmtCtl(acInOrig[i], acA1); - FilePrint(pCLServing->fd, FLAGFALSE, "%s ok]\r\n", - acA1->string); - continue; - - case S_ESC1: /* first char in escape sequence */ - if (acInOrig[i] == pCLServing->ic[1]) { - if (pCLServing->fecho) - FileWrite(pCLServing->fd, FLAGFALSE, "\r\n[", - 3); - else - FileWrite(pCLServing->fd, FLAGFALSE, "[", 1); - pCLServing->iState = S_CMD; continue; - } - /* ^E^Ec or ^_^_^[ - * pass (possibly stripped) first ^E (^_) and - * stay in same state - */ - if (acInOrig[i] == pCLServing->ic[0]) { + + case S_CATTN: /* redef escape sequence? */ + pCLServing->ic[0] = acInOrig[i]; + FmtCtl(acInOrig[i], acA1); + FilePrint(pCLServing->fd, FLAGFALSE, "%s ", + acA1->string); + pCLServing->iState = S_CESC; + continue; + + case S_CESC: /* escape sequent 2 */ + pCLServing->ic[1] = acInOrig[i]; + pCLServing->iState = S_NORMAL; + FmtCtl(acInOrig[i], acA1); + FilePrint(pCLServing->fd, FLAGFALSE, "%s ok]\r\n", + acA1->string); + continue; + + case S_ESC1: /* first char in escape sequence */ + if (acInOrig[i] == pCLServing->ic[1]) { + if (pCLServing->fecho) + FileWrite(pCLServing->fd, FLAGFALSE, + "\r\n[", 3); + else + FileWrite(pCLServing->fd, FLAGFALSE, "[", + 1); + pCLServing->iState = S_CMD; + continue; + } + /* ^E^Ec or ^_^_^[ + * pass (possibly stripped) first ^E (^_) and + * stay in same state + */ + if (acInOrig[i] == pCLServing->ic[0]) { + if (pCLServing->fwr) { + PutConsole(pCEServing, acIn[i], 1); + } + continue; + } + /* ^Ex or ^_x + * pass both characters to slave tty (possibly stripped) + */ + pCLServing->iState = S_NORMAL; if (pCLServing->fwr) { + char c = pCLServing->ic[0]; + if (pCEServing->striphigh == FLAGTRUE) + c = c & 127; + PutConsole(pCEServing, c, 1); PutConsole(pCEServing, acIn[i], 1); } continue; - } - /* ^Ex or ^_x - * pass both characters to slave tty (possibly stripped) - */ - pCLServing->iState = S_NORMAL; - if (pCLServing->fwr) { - char c = pCLServing->ic[0]; - if (pCEServing->striphigh == FLAGTRUE) - c = c & 127; - PutConsole(pCEServing, c, 1); - PutConsole(pCEServing, acIn[i], 1); - } - continue; - case S_CMD: /* have 1/2 of the escape sequence */ - pCLServing->iState = S_NORMAL; - switch (acIn[i]) { - case ';': - if (pCLServing->fcon == 1) - goto unknownchar; - FileWrite(pCLServing->fd, FLAGFALSE, - "connected]\r\n", -1); - pCLServing->fcon = 1; - break; - case '+': - case '-': - if (0 != (pCLServing->fecho = '+' == acIn[i])) + case S_CMD: /* have 1/2 of the escape sequence */ + pCLServing->iState = S_NORMAL; + switch (acIn[i]) { + case ';': + if (pCLServing->fcon == 1) + goto unknownchar; FileWrite(pCLServing->fd, FLAGFALSE, - "drop line]\r\n", -1); - else + "connected]\r\n", -1); + pCLServing->fcon = 1; + break; + case '+': + case '-': + if (0 != + (pCLServing->fecho = '+' == acIn[i])) + FileWrite(pCLServing->fd, FLAGFALSE, + "drop line]\r\n", -1); + else + FileWrite(pCLServing->fd, FLAGFALSE, + "no drop line]\r\n", -1); + break; + + case 'b': /* broadcast message */ + case 'B': FileWrite(pCLServing->fd, FLAGFALSE, - "no drop line]\r\n", -1); - break; + "Enter message: ", -1); + pCLServing->iState = S_BCAST; + break; - case 'b': /* broadcast message */ - case 'B': - FileWrite(pCLServing->fd, FLAGFALSE, - "Enter message: ", -1); - pCLServing->iState = S_BCAST; - break; - - case 'a': /* attach */ - case 'A': - CommandAttach(pGE, pCLServing, pCEServing, - tyme); - break; - - case 'c': - case 'C': - CommandChangeFlow(pGE, pCLServing, pCEServing, + case 'a': /* attach */ + case 'A': + CommandAttach(pGE, pCLServing, pCEServing, tyme); - break; + break; - case 'd': /* down a console */ - case 'D': - CommandDown(pGE, pCLServing, pCEServing, tyme); - break; + case 'c': + case 'C': + CommandChangeFlow(pGE, pCLServing, + pCEServing, tyme); + break; - case 'e': /* redefine escape keys */ - case 'E': - pCLServing->iState = S_CATTN; - FileWrite(pCLServing->fd, FLAGFALSE, "redef: ", - -1); - break; + case 'd': /* down a console */ + case 'D': + CommandDown(pGE, pCLServing, pCEServing, + tyme); + break; - case 'f': /* force attach */ - case 'F': - CommandForce(pGE, pCLServing, pCEServing, - tyme); - break; - - case 'g': /* group info */ - case 'G': - FilePrint(pCLServing->fd, FLAGFALSE, - "group %s]\r\n", - pGE->pCEctl->server); - CommandGroup(pGE, pCLServing, pCEServing, - tyme); - break; - - case 'P': /* DEC vt100 pf1 */ - case 'h': /* help */ - case 'H': - case '?': - HelpUser(pCLServing); - break; - - case 'i': - case 'I': - FileWrite(pCLServing->fd, FLAGFALSE, - "info]\r\n", -1); - CommandInfo(pGE, pCLServing, pCEServing, tyme); - break; - - case 'L': - CommandLogging(pGE, pCLServing, pCEServing, - tyme); - break; - - case 'l': /* halt character 1 */ - if (pCEServing->fronly) { + case 'e': /* redefine escape keys */ + case 'E': + pCLServing->iState = S_CATTN; FileWrite(pCLServing->fd, FLAGFALSE, - "can't halt read-only console]\r\n", - -1); - continue; - } - pCLServing->iState = S_HALT1; - FileWrite(pCLServing->fd, FLAGFALSE, "halt ", - -1); - break; + "redef: ", -1); + break; - case 'm': /* message of the day */ - if (pCEServing->motd == (char *)0) - FileWrite(pCLServing->fd, FLAGFALSE, - "-- MOTD --]\r\n", -1); - else + case 'f': /* force attach */ + case 'F': + CommandForce(pGE, pCLServing, pCEServing, + tyme); + break; + + case 'g': /* group info */ + case 'G': FilePrint(pCLServing->fd, FLAGFALSE, - "-- MOTD -- %s]\r\n", - pCEServing->motd); - break; - - case 'o': /* close and re-open line */ - case 'O': - CommandOpen(pGE, pCLServing, pCEServing, tyme); - break; - - case '\022': /* ^R */ - FileWrite(pCLServing->fd, FLAGFALSE, "^R]\r\n", - -1); - Replay(pCEServing, pCLServing->fd, 1); - break; - - case 'R': /* DEC vt100 pf3 */ - case 'r': /* replay 20 lines */ - FileWrite(pCLServing->fd, FLAGFALSE, - "replay]\r\n", -1); - Replay(pCEServing, pCLServing->fd, 20); - break; - - case 'p': /* replay 60 lines */ - FileWrite(pCLServing->fd, FLAGFALSE, - "long replay]\r\n", -1); - Replay(pCEServing, pCLServing->fd, 60); - break; - - case 'S': /* DEC vt100 pf4 */ - case 's': /* spy mode */ - pCLServing->fwantwr = 0; - if (!pCLServing->fwr) { - FileWrite(pCLServing->fd, FLAGFALSE, - "ok]\r\n", -1); + "group %s]\r\n", + pGE->pCEctl->server); + CommandGroup(pGE, pCLServing, pCEServing, + tyme); break; - } - pCLServing->fwr = 0; - TagLogfileAct(pCEServing, "%s detached", - pCLServing->acid->string); - pCEServing->pCLwr = (CONSCLIENT *)0; - FindWrite(pCEServing); - FileWrite(pCLServing->fd, FLAGFALSE, - "spying]\r\n", -1); - break; - case 'u': /* hosts on server this */ - case 'U': - FileWrite(pCLServing->fd, FLAGFALSE, - "hosts]\r\n", -1); - CommandHosts(pGE, pCLServing, pCEServing, - tyme); - break; - - case 'v': /* version */ - case 'V': - FilePrint(pCLServing->fd, FLAGFALSE, - "version `%s']\r\n", THIS_VERSION); - break; - - case 'w': /* who */ - case 'W': - FilePrint(pCLServing->fd, FLAGFALSE, - "who %s]\r\n", pCEServing->server); - CommandWho(pGE, pCLServing, pCEServing, tyme); - break; - - case 'x': - case 'X': - FileWrite(pCLServing->fd, FLAGFALSE, - "examine]\r\n", -1); - CommandExamine(pGE, pCLServing, pCEServing, - tyme); - break; - - case '|': /* wait for client */ - if (!pCLServing->fwr) { - FileWrite(pCLServing->fd, FLAGFALSE, - "attach to run local command]\r\n", - -1); - continue; - } - FileSend(pCLServing->fd, acExec, 1, MSG_OOB); - pCLServing->fcon = 0; - pCLServing->iState = S_CWAIT; - break; - - case 'z': /* suspend the client */ - case 'Z': - case '\032': - if (1 != - FileSend(pCLServing->fd, acStop, 1, - MSG_OOB)) { + case 'P': /* DEC vt100 pf1 */ + case 'h': /* help */ + case 'H': + case '?': + HelpUser(pCLServing); break; - } - pCLServing->fcon = 0; - pCLServing->iState = S_SUSP; - if (pCEServing->pCLwr == pCLServing) { - pCLServing->fwr = 0; + + case 'i': + case 'I': + FileWrite(pCLServing->fd, FLAGFALSE, + "info]\r\n", -1); + CommandInfo(pGE, pCLServing, pCEServing, + tyme); + break; + + case 'L': + CommandLogging(pGE, pCLServing, pCEServing, + tyme); + break; + + case 'l': /* halt character 1 */ + if (pCEServing->fronly) { + FileWrite(pCLServing->fd, FLAGFALSE, + "can't halt read-only console]\r\n", + -1); + continue; + } + pCLServing->iState = S_HALT1; + FileWrite(pCLServing->fd, FLAGFALSE, + "halt ", -1); + break; + + case 'm': /* message of the day */ + if (pCEServing->motd == (char *)0) + FileWrite(pCLServing->fd, FLAGFALSE, + "-- MOTD --]\r\n", -1); + else + FilePrint(pCLServing->fd, FLAGFALSE, + "-- MOTD -- %s]\r\n", + pCEServing->motd); + break; + + case 'o': /* close and re-open line */ + case 'O': + CommandOpen(pGE, pCLServing, pCEServing, + tyme); + break; + + case '\022': /* ^R */ + FileWrite(pCLServing->fd, FLAGFALSE, + "^R]\r\n", -1); + Replay(pCEServing, pCLServing->fd, 1); + break; + + case 'R': /* DEC vt100 pf3 */ + case 'r': /* replay 20 lines */ + FileWrite(pCLServing->fd, FLAGFALSE, + "replay]\r\n", -1); + Replay(pCEServing, pCLServing->fd, 20); + break; + + case 'p': /* replay 60 lines */ + FileWrite(pCLServing->fd, FLAGFALSE, + "long replay]\r\n", -1); + Replay(pCEServing, pCLServing->fd, 60); + break; + + case 'S': /* DEC vt100 pf4 */ + case 's': /* spy mode */ pCLServing->fwantwr = 0; - pCEServing->pCLwr = (CONSCLIENT *)0; + if (!pCLServing->fwr) { + FileWrite(pCLServing->fd, FLAGFALSE, + "ok]\r\n", -1); + break; + } + pCLServing->fwr = 0; TagLogfileAct(pCEServing, "%s detached", pCLServing->acid->string); - } - break; + pCEServing->pCLwr = (CONSCLIENT *)0; + FindWrite(pCEServing); + FileWrite(pCLServing->fd, FLAGFALSE, + "spying]\r\n", -1); + break; - case '\t': /* toggle tab expand */ - if (!pCLServing->fwr) { + case 'u': /* hosts on server this */ + case 'U': FileWrite(pCLServing->fd, FLAGFALSE, - "attach to toggle tabs]\r\n", - -1); - continue; - } - if (pCEServing->type != DEVICE && - pCEServing->type != EXEC) { - FileWrite(pCLServing->fd, FLAGFALSE, - "ok]\r\n", -1); - continue; - } - if (-1 == - tcgetattr(FileFDNum(pCEServing->cofile), - &sbuf)) { - FileWrite(pCLServing->fd, FLAGFALSE, - "failed]\r\n", -1); - continue; - } -# if !defined(XTABS) /* XXX hack */ -# define XTABS TAB3 -# endif - if (XTABS == (TABDLY & sbuf.c_oflag)) { - sbuf.c_oflag &= ~TABDLY; - sbuf.c_oflag |= TAB0; - } else { - sbuf.c_oflag &= ~TABDLY; - sbuf.c_oflag |= XTABS; - } - if (-1 == - tcsetattr(FileFDNum(pCEServing->cofile), - TCSANOW, &sbuf)) { - FileWrite(pCLServing->fd, FLAGFALSE, - "failed]\r\n", -1); - continue; - } - if (XTABS == (TABDLY & sbuf.c_oflag)) - FileWrite(pCLServing->fd, FLAGFALSE, - "tabs OFF]\r\n", -1); - else - FileWrite(pCLServing->fd, FLAGFALSE, - "tabs ON]\r\n", -1); - break; + "hosts]\r\n", -1); + CommandHosts(pGE, pCLServing, pCEServing, + tyme); + break; - case 'Q': /* DEC vt100 PF2 */ - case '.': /* disconnect */ - case '\004': - case '\003': - FileWrite(pCLServing->fd, FLAGFALSE, - "disconnect]\r\n", -1); - nr = 0; - if (pCEServing->fup && - pCEServing->type == DEVICE) { + case 'v': /* version */ + case 'V': + FilePrint(pCLServing->fd, FLAGFALSE, + "version `%s']\r\n", + THIS_VERSION); + break; + + case 'w': /* who */ + case 'W': + FilePrint(pCLServing->fd, FLAGFALSE, + "who %s]\r\n", + pCEServing->server); + CommandWho(pGE, pCLServing, pCEServing, + tyme); + break; + + case 'x': + case 'X': + FileWrite(pCLServing->fd, FLAGFALSE, + "examine]\r\n", -1); + CommandExamine(pGE, pCLServing, pCEServing, + tyme); + break; + + case '|': /* wait for client */ + if (!pCLServing->fwr) { + FileWrite(pCLServing->fd, FLAGFALSE, + "attach to run local command]\r\n", + -1); + continue; + } + FileSetQuoteIAC(pCLServing->fd, FLAGFALSE); + FilePrint(pCLServing->fd, FLAGFALSE, + "%c%c", OB_IAC, OB_EXEC); + FileSetQuoteIAC(pCLServing->fd, FLAGTRUE); + pCLServing->fcon = 0; + pCLServing->iState = S_CWAIT; + break; + + case 'z': /* suspend the client */ + case 'Z': + case '\032': + FileSetQuoteIAC(pCLServing->fd, FLAGFALSE); + FilePrint(pCLServing->fd, FLAGFALSE, + "%c%c", OB_IAC, OB_SUSP); + FileSetQuoteIAC(pCLServing->fd, FLAGTRUE); + pCLServing->fcon = 0; + pCLServing->iState = S_SUSP; + if (pCEServing->pCLwr == pCLServing) { + pCLServing->fwr = 0; + pCLServing->fwantwr = 0; + pCEServing->pCLwr = (CONSCLIENT *)0; + TagLogfileAct(pCEServing, + "%s detached", + pCLServing->acid-> + string); + } + break; + + case '\t': /* toggle tab expand */ + if (!pCLServing->fwr) { + FileWrite(pCLServing->fd, FLAGFALSE, + "attach to toggle tabs]\r\n", + -1); + continue; + } + if (pCEServing->type != DEVICE && + pCEServing->type != EXEC) { + FileWrite(pCLServing->fd, FLAGFALSE, + "ok]\r\n", -1); + continue; + } if (-1 == tcgetattr(FileFDNum (pCEServing->cofile), &sbuf)) { FileWrite(pCLServing->fd, FLAGFALSE, - "[failed]\r\n", -1); + "failed]\r\n", -1); continue; } - if (0 == (sbuf.c_iflag & IXOFF)) { - sbuf.c_iflag |= IXOFF | IXON; +# if !defined(XTABS) /* XXX hack */ +# define XTABS TAB3 +# endif + if (XTABS == (TABDLY & sbuf.c_oflag)) { + sbuf.c_oflag &= ~TABDLY; + sbuf.c_oflag |= TAB0; + } else { + sbuf.c_oflag &= ~TABDLY; + sbuf.c_oflag |= XTABS; + } + if (-1 == tcsetattr(FileFDNum (pCEServing->cofile), - TCSANOW, &sbuf); + TCSANOW, &sbuf)) { + FileWrite(pCLServing->fd, FLAGFALSE, + "failed]\r\n", -1); + continue; } - } - DisconnectClient(pGE, pCLServing, (char *)0, - FLAGFALSE); - continue; + if (XTABS == (TABDLY & sbuf.c_oflag)) + FileWrite(pCLServing->fd, FLAGFALSE, + "tabs OFF]\r\n", -1); + else + FileWrite(pCLServing->fd, FLAGFALSE, + "tabs ON]\r\n", -1); + break; - case ' ': /* abort escape sequence */ - case '\n': - case '\r': - FileWrite(pCLServing->fd, FLAGFALSE, - "ignored]\r\n", -1); - break; - - case '\\': /* quote mode (send ^Q,^S) */ - if (pCEServing->fronly) { + case 'Q': /* DEC vt100 PF2 */ + case '.': /* disconnect */ + case '\004': + case '\003': FileWrite(pCLServing->fd, FLAGFALSE, - "can't write to read-only console]\r\n", - -1); - continue; - } - if (!pCLServing->fwr) { - FileWrite(pCLServing->fd, FLAGFALSE, - "attach to send character]\r\n", - -1); - continue; - } - BuildString((char *)0, pCLServing->accmd); - pCLServing->iState = S_QUOTE; - FileWrite(pCLServing->fd, FLAGFALSE, - "quote \\", -1); - break; + "disconnect]\r\n", -1); + if (pCEServing->fup && + pCEServing->type == DEVICE) { + if (-1 == + tcgetattr(FileFDNum + (pCEServing->cofile), + &sbuf)) { + FileWrite(pCLServing->fd, + FLAGFALSE, + "[failed]\r\n", -1); + continue; + } + if (0 == (sbuf.c_iflag & IXOFF)) { + sbuf.c_iflag |= IXOFF | IXON; + tcsetattr(FileFDNum + (pCEServing->cofile), + TCSANOW, &sbuf); + } + } + DisconnectClient(pGE, pCLServing, + (char *)0, FLAGFALSE); + return; - default: /* unknown sequence */ - unknownchar: - FileWrite(pCLServing->fd, FLAGFALSE, - "unknown -- use `?']\r\n", -1); - break; - } - continue; - } + case ' ': /* abort escape sequence */ + case '\n': + case '\r': + FileWrite(pCLServing->fd, FLAGFALSE, + "ignored]\r\n", -1); + break; + + case '\\': /* quote mode (send ^Q,^S) */ + if (pCEServing->fronly) { + FileWrite(pCLServing->fd, FLAGFALSE, + "can't write to read-only console]\r\n", + -1); + continue; + } + if (!pCLServing->fwr) { + FileWrite(pCLServing->fd, FLAGFALSE, + "attach to send character]\r\n", + -1); + continue; + } + BuildString((char *)0, pCLServing->accmd); + pCLServing->iState = S_QUOTE; + FileWrite(pCLServing->fd, FLAGFALSE, + "quote \\", -1); + break; + + default: /* unknown sequence */ + unknownchar: + FileWrite(pCLServing->fd, FLAGFALSE, + "unknown -- use `?']\r\n", -1); + break; + } + continue; + } + } + nr -= l; + MemMove(acIn, acIn + l, nr); } } @@ -3368,13 +3504,14 @@ FlushConsole(pCEServing) CONSENT *pCEServing; #endif { + static STRING *buf = (STRING *)0; + int offset = 0; /* we buffered console data in PutConsole() so that we can * send more than 1-byte payloads, if we get more than 1-byte * of data from a client connection. here we flush that buffer, * possibly putting it into the write buffer (but we don't really * need to worry about that here. */ - int justHadDelay = 0; if (pCEServing->wbuf->used <= 1) { return; } @@ -3384,226 +3521,202 @@ FlushConsole(pCEServing) pCEServing->wbufIAC = 0; return; } - while (!justHadDelay && pCEServing->wbuf->used > 1) { - if (pCEServing->wbufIAC == 0) { - CONDDEBUG((1, "Kiddie(): flushing %d non-IAC bytes to fd %d", - pCEServing->wbuf->used - 1, - FileFDNum(pCEServing->cofile))); - if (FileWrite - (pCEServing->cofile, FLAGFALSE, pCEServing->wbuf->string, - pCEServing->wbuf->used - 1) < 0) { - Error("[%s] write failure", pCEServing->server); - ConsoleError(pCEServing); - break; - } - BuildString((char *)0, pCEServing->wbuf); - } else { - unsigned char next; + if (buf == (STRING *)0) + buf = AllocString(); + BuildString((char *)0, buf); + + /* while wbuf + * if wbufIAC == 1, yikes + * else if wbufIAC == 0, buffer all data, move offset + * else if wbufIAC > 2, buffer data, wbufIAC = 2, move offset + * else if wbufIAC == 2, then + * if heavy + * write buffer + * if flushed, do heavy, else break + * break + * else if light + * buffer data + * search for new wbufIAC + */ + { + static STRING *s; + if (s == (STRING *)0) + s = AllocString(); + BuildString((char *)0, s); + FmtCtlStr(pCEServing->wbuf->string, pCEServing->wbuf->used, s); + CONDDEBUG((1, "Kiddie(): wbuf=%s", s->string)); + } + + while (pCEServing->wbuf->used > 1 && + offset < pCEServing->wbuf->used - 1) { + CONDDEBUG((1, "Kiddie(): wbuf->used=%d, offset=%d, wbufIAC=%d", + pCEServing->wbuf->used, offset, pCEServing->wbufIAC)); + if (pCEServing->wbufIAC >= pCEServing->wbuf->used) { /* this should never really happen...but in case it * does, just reset wbufIAC and try again. */ - if (pCEServing->wbuf->used < pCEServing->wbufIAC) { - CONDDEBUG((1, - "Kiddie(): invalid wbufIAC setting for fd %d", - FileFDNum(pCEServing->cofile))); - } else { - if ((((next = - (unsigned char)pCEServing->wbuf->string[pCEServing-> - wbufIAC - - 1]) >= '0' - && next <= '9') || (next == BREAK && - pCEServing->type != HOST))) { - CONDDEBUG((1, "Kiddie(): heavy IAC for fd %d", - FileFDNum(pCEServing->cofile))); - /* if we have data before the IAC, send it */ - if (pCEServing->wbufIAC > 2) { - CONDDEBUG((1, - "Kiddie(): heavy IAC flushing %d leading bytes for fd %d", - pCEServing->wbufIAC - 2, - FileFDNum(pCEServing->cofile))); - if (FileWrite - (pCEServing->cofile, FLAGFALSE, - pCEServing->wbuf->string, - pCEServing->wbufIAC - 2) < 0) { - Error("[%s] write failure", - pCEServing->server); - ConsoleError(pCEServing); - break; - } - } - /* if we didn't flush everything, bail and get - * it the next time around (hopefully it'll have - * cleared...or will soon. - */ - if (!FileBufEmpty(pCEServing->cofile)) { - /* if we wrote something, shift it out */ - if (pCEServing->wbufIAC > 2) { - ShiftString(pCEServing->wbuf, - pCEServing->wbufIAC - 2); - pCEServing->wbufIAC = 2; - } - CONDDEBUG((1, - "Kiddie(): heavy IAC (wait for flush) for fd %d", - FileFDNum(pCEServing->cofile))); - break; - } - - /* Do the operation */ - if (next >= '0' && next <= '9') { - int delay = BREAKDELAYDEFAULT; - if (next != '0') - delay = breakList[next - '1'].delay; - /* in theory this sets the break length to whatever - * the "default" break sequence is for the console. - * but, i think it would be better to just use the - * global default (250ms right now) so that you - * don't have to change things or get anything - * unexpected. remember, this is really just for - * idle strings... - else { - if (pCEServing->breakNum != 0 && - breakList[pCEServbing->breakNum - - 1].seq->used <= 1) - delay = - breakList[pCEServbing->breakNum - - 1].delay; - } - */ - CONDDEBUG((1, - "Kiddie(): heavy IAC - doing usleep() for fd %d (break #%c - delay %dms)", - FileFDNum(pCEServing->cofile), next, - delay)); - if (delay != 0) - usleep(delay * 1000); - } else if (next == BREAK) { - CONDDEBUG((1, - "Kiddie(): heavy IAC - doing tcsendbreak() for fd %d", - FileFDNum(pCEServing->cofile))); - if (tcsendbreak(FileFDNum(pCEServing->cofile), 0) - == -1) { - if (pCEServing->pCLwr != (CONSCLIENT *)0) - FileWrite(pCEServing->pCLwr->fd, FLAGFALSE, - "[tcsendbreak() failed]\r\n", - -1); - } - } - - /* shift things off and trigger completion */ - ShiftString(pCEServing->wbuf, pCEServing->wbufIAC); - justHadDelay = 1; - /* we do this 'cause we just potentially paused for - * a half-second doing a break...or even the - * intentional usleep(). we could take out the - * justHadDelay bits and continue with the stream, - * but this allows us to process other consoles and - * then come around and do more on this one. you - * see, someone could have a '\d\z\d\z\d\z' sequence - * as a break string and we'd have about a 2 second - * delay added up if we process it all at once. - * we're just trying to be nice here. - */ - } else { - char *iac; - int offset = 0; - static STRING *buf = (STRING *)0; - - if (buf == (STRING *)0) - buf = AllocString(); - BuildString((char *)0, buf); - - do { - CONDDEBUG((1, "Kiddie(): soft IAC for fd %d", - FileFDNum(pCEServing->cofile))); - if (pCEServing->wbufIAC == 0) { - /* if no more IAC chars, just throw the rest - * into the buffer, clear things, and stop - */ - CONDDEBUG((1, - "Kiddie(): soft IAC buffering to EOS for fd %d", - FileFDNum(pCEServing->cofile))); - BuildString(pCEServing->wbuf->string + offset, - buf); - offset = pCEServing->wbuf->used - 1; - break; - } - /* buffer everything up to the IAC */ - CONDDEBUG((1, - "Kiddie(): soft IAC buffering to IAC for fd %d", - FileFDNum(pCEServing->cofile))); - BuildStringN(pCEServing->wbuf->string + offset, - pCEServing->wbufIAC - 2, buf); - /* process allowed sequences */ - if (next == IAC) { - CONDDEBUG((1, - "Kiddie(): soft IAC processing IAC for fd %d", - FileFDNum(pCEServing->cofile))); - BuildStringChar((char)IAC, buf); - } else if (next == BREAK && - pCEServing->type == HOST) { - CONDDEBUG((1, - "Kiddie(): soft IAC processing HOST BREAK for fd %d", - FileFDNum(pCEServing->cofile))); - BuildStringChar((char)IAC, buf); - BuildStringChar((char)BREAK, buf); - } else { - CONDDEBUG((1, - "Kiddie(): soft IAC unprocessable IAC for fd %d", - FileFDNum(pCEServing->cofile))); - /* move offset up to right before IAC */ - offset += pCEServing->wbufIAC - 2; - break; - } - /* bring offset past char after IAC */ - CONDDEBUG((1, - "Kiddie(): soft IAC looking for new IAC for fd %d", - FileFDNum(pCEServing->cofile))); - offset += pCEServing->wbufIAC; - iac = - strchr(pCEServing->wbuf->string + offset, IAC); - if (iac == (char *)0) - pCEServing->wbufIAC = 0; - else - pCEServing->wbufIAC = - iac - (pCEServing->wbuf->string + offset) + - 2; - } while (offset < pCEServing->wbuf->used - 1); - - /* shift off the buffered data */ + CONDDEBUG((1, "Kiddie(): invalid wbufIAC setting for [%s]", + pCEServing->server)); + } else if (pCEServing->wbufIAC == 1) { + Error("[%s] internal failure: wbufIAC==1", pCEServing->server); + offset = pCEServing->wbuf->used - 1; /* bail */ + } else if (pCEServing->wbufIAC == 0) { + CONDDEBUG((1, + "Kiddie(): flushing final %d non-IAC bytes to [%s]", + pCEServing->wbuf->used - 1 - offset, + pCEServing->server)); + BuildStringN(pCEServing->wbuf->string + offset, + pCEServing->wbuf->used - 1 - offset, buf); + offset = pCEServing->wbuf->used - 1; + } else if (pCEServing->wbufIAC > 2) { + CONDDEBUG((1, "Kiddie(): flushing %d non-IAC bytes to [%s]", + pCEServing->wbufIAC - 2, pCEServing->server)); + BuildStringN(pCEServing->wbuf->string + offset, + pCEServing->wbufIAC - 2, buf); + offset += pCEServing->wbufIAC - 2; + pCEServing->wbufIAC = 2; + continue; + } else { /* wbufIAC == 2 */ + unsigned char next = + (unsigned char)pCEServing->wbuf->string[offset + 1]; + if ((next >= '0' && next <= '9') || + (next == BREAK && pCEServing->type != HOST)) { + CONDDEBUG((1, "Kiddie(): heavy IAC for [%s]", + pCEServing->server)); + offset += 2; + /* if we have buffered data, send it */ + if (buf->used > 1) { CONDDEBUG((1, - "Kiddie(): soft IAC shifting off %d chars for fd %d", - offset, FileFDNum(pCEServing->cofile))); - ShiftString(pCEServing->wbuf, offset); - - /* send the buffered data */ - CONDDEBUG((1, - "Kiddie(): soft IAC writing %d chars to fd %d", - buf->used - 1, - FileFDNum(pCEServing->cofile))); + "Kiddie(): heavy IAC flushing %d leading bytes for [%s]", + buf->used - 1, pCEServing->server)); if (FileWrite (pCEServing->cofile, FLAGFALSE, buf->string, buf->used - 1) < 0) { Error("[%s] write failure", pCEServing->server); ConsoleError(pCEServing); + BuildString((char *)0, buf); break; } BuildString((char *)0, buf); } + /* if we didn't flush everything, bail and get + * it the next time around (hopefully it'll have + * cleared...or will soon. + */ + if (!FileBufEmpty(pCEServing->cofile)) { + CONDDEBUG((1, + "Kiddie(): heavy IAC (wait for flush) for [%s]", + pCEServing->server)); + break; + } + + /* Do the operation */ + if (next >= '0' && next <= '9') { + int delay = BREAKDELAYDEFAULT; + if (next != '0') + delay = breakList[next - '1'].delay; + /* in theory this sets the break length to whatever + * the "default" break sequence is for the console. + * but, i think it would be better to just use the + * global default (250ms right now) so that you + * don't have to change things or get anything + * unexpected. remember, this is really just for + * idle strings... + else { + if (pCEServing->breakNum != 0 && + breakList[pCEServbing->breakNum - + 1].seq->used <= 1) + delay = + breakList[pCEServbing->breakNum - + 1].delay; + } + */ + CONDDEBUG((1, + "Kiddie(): heavy IAC - doing usleep() for [%s] (break #%c - delay %dms)", + pCEServing->server, next, delay)); + if (delay != 0) + usleep(delay * 1000); + } else if (next == BREAK) { + CONDDEBUG((1, + "Kiddie(): heavy IAC - doing tcsendbreak() for [%s]", + pCEServing->server)); + if (tcsendbreak(FileFDNum(pCEServing->cofile), 0) + == -1) { + if (pCEServing->pCLwr != (CONSCLIENT *)0) + FileWrite(pCEServing->pCLwr->fd, FLAGFALSE, + "[tcsendbreak() failed]\r\n", -1); + } + } + /* we do this 'cause we just potentially paused for + * a half-second doing a break...or even the + * intentional usleep(). we could take out the + * justHadDelay bits and continue with the stream, + * but this allows us to process other consoles and + * then come around and do more on this one. you + * see, someone could have a '\d\z\d\z\d\z' sequence + * as a break string and we'd have about a 2 second + * delay added up if we process it all at once. + * we're just trying to be nice here. + */ + break; + } else { + CONDDEBUG((1, "Kiddie(): soft IAC for fd [%s]", + pCEServing->server)); + offset += 2; + if (next == IAC) { + CONDDEBUG((1, + "Kiddie(): soft IAC processing IAC for [%s]", + pCEServing->server)); + BuildStringChar((char)IAC, buf); + } else if (next == BREAK && pCEServing->type == HOST) { + CONDDEBUG((1, + "Kiddie(): soft IAC processing HOST BREAK for [%s]", + pCEServing->server)); + BuildStringChar((char)IAC, buf); + BuildStringChar((char)BREAK, buf); + } else { + CONDDEBUG((1, + "Kiddie(): soft IAC unprocessable IAC for [%s]", + pCEServing->server)); + } } - CONDDEBUG((1, "Kiddie(): hunting for new IAC for fd %d", - FileFDNum(pCEServing->cofile))); - /* hunt for a new IAC position */ - if (pCEServing->wbuf->used > 1) { - char *iac = strchr(pCEServing->wbuf->string, IAC); - if (iac == (char *)0) - pCEServing->wbufIAC = 0; - else - pCEServing->wbufIAC = - (iac - pCEServing->wbuf->string) + 2; - } else - pCEServing->wbufIAC = 0; } + + /* hunt for a new IAC position */ + if (offset < pCEServing->wbuf->used - 1) { + char *iac = StringChar(pCEServing->wbuf, offset, (char)IAC); + CONDDEBUG((1, "Kiddie(): hunting for new IAC for [%s]", + pCEServing->server)); + if (iac == (char *)0) + pCEServing->wbufIAC = 0; + else + pCEServing->wbufIAC = + (iac - pCEServing->wbuf->string - offset) + 2; + } else + pCEServing->wbufIAC = 0; } + + if (buf->used > 1) { + CONDDEBUG((1, "Kiddie(): flushing buffer of %d bytes for [%s]", + buf->used - 1, pCEServing->server)); + if (FileWrite + (pCEServing->cofile, FLAGFALSE, buf->string, + buf->used - 1) < 0) { + Error("[%s] write failure", pCEServing->server); + ConsoleError(pCEServing); + return; + } + BuildString((char *)0, buf); + } + + /* nuke the data alread sent */ + if (offset >= pCEServing->wbuf->used - 1) { + BuildString((char *)0, pCEServing->wbuf); + } else if (offset > 0) { + ShiftString(pCEServing->wbuf, offset); + } + if (pCEServing->wbuf->used > 1) { CONDDEBUG((1, "Kiddie(): watching writability for fd %d 'cause we have buffered data", @@ -3619,9 +3732,10 @@ FlushConsole(pCEServing) } pCEServing->lastWrite = time((time_t *)0); if (pCEServing->idletimeout != (time_t)0 && - (timers[T_IDLE] == (time_t)0 || - timers[T_IDLE] > pCEServing->lastWrite + pCEServing->idletimeout)) - timers[T_IDLE] = pCEServing->lastWrite + pCEServing->idletimeout; + (timers[T_CIDLE] == (time_t)0 || + timers[T_CIDLE] > + pCEServing->lastWrite + pCEServing->idletimeout)) + timers[T_CIDLE] = pCEServing->lastWrite + pCEServing->idletimeout; } @@ -3832,8 +3946,8 @@ Kiddie(pGE, sfd) } /* process any idle timeouts */ - if (timers[T_IDLE] != (time_t)0 && tyme >= timers[T_IDLE]) { - timers[T_IDLE] = (time_t)0; + if (timers[T_CIDLE] != (time_t)0 && tyme >= timers[T_CIDLE]) { + timers[T_CIDLE] = (time_t)0; for (pCEServing = pGE->pCElist; pCEServing != (CONSENT *)0; pCEServing = pCEServing->pCEnext) { /* if we aren't in a normal state, skip it */ @@ -3847,9 +3961,9 @@ Kiddie(pGE, sfd) time_t chime = pCEServing->lastWrite + pCEServing->idletimeout; if (tyme < chime) { - if (timers[T_IDLE] == (time_t)0 || - timers[T_IDLE] > chime) - timers[T_IDLE] = chime; + if (timers[T_CIDLE] == (time_t)0 || + timers[T_CIDLE] > chime) + timers[T_CIDLE] = chime; continue; } ExpandString(pCEServing->idlestring, pCEServing, 0); @@ -3863,9 +3977,9 @@ Kiddie(pGE, sfd) */ pCEServing->lastWrite = tyme; chime = tyme + pCEServing->idletimeout; - if (timers[T_IDLE] == (time_t)0 || - timers[T_IDLE] > chime) - timers[T_IDLE] = chime; + if (timers[T_CIDLE] == (time_t)0 || + timers[T_CIDLE] > chime) + timers[T_CIDLE] = chime; } } } @@ -3980,11 +4094,11 @@ Kiddie(pGE, sfd) FD_SET(cofile, &rinit); FD_CLR(cofile, &winit); if (pCEServing->idletimeout != (time_t)0 && - (timers[T_IDLE] == (time_t)0 || - timers[T_IDLE] > + (timers[T_CIDLE] == (time_t)0 || + timers[T_CIDLE] > pCEServing->lastWrite + pCEServing->idletimeout)) - timers[T_IDLE] = + timers[T_CIDLE] = pCEServing->lastWrite + pCEServing->idletimeout; StartInit(pCEServing); @@ -4140,9 +4254,10 @@ Kiddie(pGE, sfd) continue; } - if (SetFlags(sfd, O_NONBLOCK, 0)) + if (SetFlags(sfd, O_NONBLOCK, 0)) { pGE->pCLfree->fd = FileOpenFD(fd, simpleSocket); - else + FileSetQuoteIAC(pGE->pCLfree->fd, FLAGTRUE); + } else pGE->pCLfree->fd = (CONSFILE *)0; if ((CONSFILE *)0 == pGE->pCLfree->fd) { diff --git a/conserver/group.h b/conserver/group.h index 4b87a3e..07b02dc 100644 --- a/conserver/group.h +++ b/conserver/group.h @@ -1,5 +1,5 @@ /* - * $Id: group.h,v 5.42 2003/11/28 23:36:02 bryan Exp $ + * $Id: group.h,v 5.43 2003/12/20 06:11:53 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -36,7 +36,7 @@ /* timers used to have various things happen */ #define T_STATE 0 -#define T_IDLE 1 +#define T_CIDLE 1 #define T_MARK 2 #define T_REINIT 3 #define T_AUTOUP 4 diff --git a/conserver/main.c b/conserver/main.c index f2848b8..7041a43 100644 --- a/conserver/main.c +++ b/conserver/main.c @@ -1,5 +1,5 @@ /* - * $Id: main.c,v 5.172 2003/11/20 13:56:39 bryan Exp $ + * $Id: main.c,v 5.174 2003/12/21 16:23:02 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -883,13 +883,13 @@ DumpDataStructures() "DumpDataStructures(): server=%s, type=HOST", EMPTYSTR(pCE->server))); CONDDEBUG((1, - "DumpDataStructures(): host=%s, port=%hu, telnetState=%d", - EMPTYSTR(pCE->host), pCE->port, + "DumpDataStructures(): host=%s, raw=%hu, port=%hu, telnetState=%d", + EMPTYSTR(pCE->host), pCE->raw, pCE->port, pCE->telnetState)); break; - case UNKNOWN: + case UNKNOWNTYPE: CONDDEBUG((1, - "DumpDataStructures(): server=%s, type=UNKNOWN", + "DumpDataStructures(): server=%s, type=UNKNOWNTYPE", EMPTYSTR(pCE->server))); break; } diff --git a/conserver/master.c b/conserver/master.c index af7d16f..31f45a4 100644 --- a/conserver/master.c +++ b/conserver/master.c @@ -1,5 +1,5 @@ /* - * $Id: master.c,v 5.123 2003/11/20 13:56:39 bryan Exp $ + * $Id: master.c,v 5.124 2003/12/25 19:22:00 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -433,7 +433,7 @@ DoNormalRead(pCLServing) { char *pcCmd; char *pcArgs; - int nr, i; + int nr, i, l; unsigned char acIn[BUFSIZ]; /* read connection */ @@ -442,208 +442,221 @@ DoNormalRead(pCLServing) return; } - for (i = 0; i < nr; ++i) { - if ('\n' != acIn[i]) { - BuildStringChar(acIn[i], pCLServing->accmd); + while ((l = ParseIACBuf(pCLServing->fd, acIn, &nr)) >= 0) { + if (l == 0) /* we ignore special OB_IAC stuff */ continue; - } - if ((pCLServing->accmd->used > 1) && - ('\r' == - pCLServing->accmd->string[pCLServing->accmd->used - 2])) { - pCLServing->accmd->string[pCLServing->accmd->used - 2] = - '\000'; - pCLServing->accmd->used--; - } + for (i = 0; i < l; ++i) { + if ('\n' != acIn[i]) { + BuildStringChar(acIn[i], pCLServing->accmd); + continue; + } + if ((pCLServing->accmd->used > 1) && + ('\r' == + pCLServing->accmd->string[pCLServing->accmd->used - 2])) { + pCLServing->accmd->string[pCLServing->accmd->used - 2] = + '\000'; + pCLServing->accmd->used--; + } - /* process password here...before we corrupt accmd */ - if (pCLServing->iState == S_PASSWD) { - if (CheckPasswd(pCLServing, pCLServing->accmd->string) != - AUTH_SUCCESS) { - FileWrite(pCLServing->fd, FLAGFALSE, - "invalid password\r\n", -1); + /* process password here...before we corrupt accmd */ + if (pCLServing->iState == S_PASSWD) { + if (CheckPasswd(pCLServing, pCLServing->accmd->string) != + AUTH_SUCCESS) { + FileWrite(pCLServing->fd, FLAGFALSE, + "invalid password\r\n", -1); + BuildString((char *)0, pCLServing->accmd); + DropMasterClient(pCLServing, FLAGFALSE); + return; + } + Verbose(" login %s", pCLServing->acid->string); + FileWrite(pCLServing->fd, FLAGFALSE, "ok\r\n", 4); + pCLServing->iState = S_NORMAL; BuildString((char *)0, pCLServing->accmd); - DropMasterClient(pCLServing, FLAGFALSE); - return; + continue; } - Verbose(" login %s", pCLServing->acid->string); - FileWrite(pCLServing->fd, FLAGFALSE, "ok\r\n", 4); - pCLServing->iState = S_NORMAL; - BuildString((char *)0, pCLServing->accmd); - continue; - } - if ((char *)0 != (pcArgs = strchr(pCLServing->accmd->string, ':'))) { - *pcArgs++ = '\000'; - } else if ((char *)0 != - (pcArgs = strchr(pCLServing->accmd->string, ' '))) { - *pcArgs++ = '\000'; - } - if (pcArgs != (char *)0) - pcArgs = PruneSpace(pcArgs); - pcCmd = PruneSpace(pCLServing->accmd->string); - if (strcmp(pcCmd, "help") == 0) { - static char *apcHelp1[] = { - "exit disconnect\r\n", - "help this help message\r\n", - "login log in\r\n", -#if HAVE_OPENSSL - "ssl start ssl session\r\n", -#endif - (char *)0 - }; - static char *apcHelp2[] = { - "call provide port for given console\r\n", - "exit disconnect\r\n", - "groups provide ports for group leaders\r\n", - "help this help message\r\n", - "master provide a list of master servers\r\n", - "pid provide pid of master process\r\n", - "quit* terminate conserver (SIGTERM)\r\n", - "restart* restart conserver (SIGHUP)\r\n", - "version provide version info for server\r\n", - "* = requires admin privileges\r\n", - (char *)0 - }; - char **ppc; - for (ppc = - (pCLServing->iState == S_IDENT ? apcHelp1 : apcHelp2); - (char *)0 != *ppc; ++ppc) { - FileWrite(pCLServing->fd, FLAGTRUE, *ppc, -1); + if ((char *)0 != + (pcArgs = strchr(pCLServing->accmd->string, ':'))) { + *pcArgs++ = '\000'; + } else if ((char *)0 != + (pcArgs = strchr(pCLServing->accmd->string, ' '))) { + *pcArgs++ = '\000'; } - FileWrite(pCLServing->fd, FLAGFALSE, (char *)0, 0); - } else if (strcmp(pcCmd, "exit") == 0) { - FileWrite(pCLServing->fd, FLAGFALSE, "goodbye\r\n", -1); - DropMasterClient(pCLServing, FLAGFALSE); - return; + if (pcArgs != (char *)0) + pcArgs = PruneSpace(pcArgs); + pcCmd = PruneSpace(pCLServing->accmd->string); + if (strcmp(pcCmd, "help") == 0) { + static char *apcHelp1[] = { + "exit disconnect\r\n", + "help this help message\r\n", + "login log in\r\n", #if HAVE_OPENSSL - } else if (pCLServing->iState == S_IDENT && - strcmp(pcCmd, "ssl") == 0) { - FileWrite(pCLServing->fd, FLAGFALSE, "ok\r\n", -1); - if (!AttemptSSL(pCLServing)) { + "ssl start ssl session\r\n", +#endif + (char *)0 + }; + static char *apcHelp2[] = { + "call provide port for given console\r\n", + "exit disconnect\r\n", + "groups provide ports for group leaders\r\n", + "help this help message\r\n", + "master provide a list of master servers\r\n", + "pid provide pid of master process\r\n", + "quit* terminate conserver (SIGTERM)\r\n", + "restart* restart conserver (SIGHUP)\r\n", + "version provide version info for server\r\n", + "* = requires admin privileges\r\n", + (char *)0 + }; + char **ppc; + for (ppc = + (pCLServing->iState == S_IDENT ? apcHelp1 : apcHelp2); + (char *)0 != *ppc; ++ppc) { + FileWrite(pCLServing->fd, FLAGTRUE, *ppc, -1); + } + FileWrite(pCLServing->fd, FLAGFALSE, (char *)0, 0); + } else if (strcmp(pcCmd, "exit") == 0) { + FileWrite(pCLServing->fd, FLAGFALSE, "goodbye\r\n", -1); DropMasterClient(pCLServing, FLAGFALSE); return; - } -#endif - } else if (pCLServing->iState == S_IDENT && - strcmp(pcCmd, "login") == 0) { #if HAVE_OPENSSL - if (config->sslrequired == FLAGTRUE && - FileGetType(pCLServing->fd) != SSLSocket) { - FileWrite(pCLServing->fd, FLAGFALSE, - "encryption required\r\n", -1); - } else { + } else if (pCLServing->iState == S_IDENT && + strcmp(pcCmd, "ssl") == 0) { + FileWrite(pCLServing->fd, FLAGFALSE, "ok\r\n", -1); + if (!AttemptSSL(pCLServing)) { + DropMasterClient(pCLServing, FLAGFALSE); + return; + } #endif - if (pcArgs == (char *)0) { + } else if (pCLServing->iState == S_IDENT && + strcmp(pcCmd, "login") == 0) { +#if HAVE_OPENSSL + if (config->sslrequired == FLAGTRUE && + FileGetType(pCLServing->fd) != SSLSocket) { FileWrite(pCLServing->fd, FLAGFALSE, - "login requires argument\r\n", -1); + "encryption required\r\n", -1); } else { - BuildString((char *)0, pCLServing->username); - BuildString((char *)0, pCLServing->acid); - BuildString(pcArgs, pCLServing->username); - BuildString(pcArgs, pCLServing->acid); - BuildStringChar('@', pCLServing->acid); - BuildString(pCLServing->peername->string, - pCLServing->acid); - if (pCLServing->caccess == 't' || - CheckPasswd(pCLServing, "") == AUTH_SUCCESS) { - pCLServing->iState = S_NORMAL; - Verbose(" login %s", - pCLServing->acid->string); - FileWrite(pCLServing->fd, FLAGFALSE, "ok\r\n", 4); - } else { - FilePrint(pCLServing->fd, FLAGFALSE, - "passwd? %s\r\n", myHostname); - pCLServing->iState = S_PASSWD; - } - } -#if HAVE_OPENSSL - } #endif - } else if (pCLServing->iState == S_NORMAL && - strcmp(pcCmd, "master") == 0) { - int iSep = 1; - - if ((GRPENT *)0 != pGroups) { - struct sockaddr_in lcl; - socklen_t so = sizeof(lcl); - if (-1 == - getsockname(FileFDNum(pCLServing->fd), - (struct sockaddr *)&lcl, &so)) { - FileWrite(pCLServing->fd, FLAGFALSE, - "getsockname failed, try again later\r\n", - -1); - Error("Master(): getsockname(%u): %s", - FileFDNum(pCLServing->fd), strerror(errno)); - Bye(EX_OSERR); + if (pcArgs == (char *)0) { + FileWrite(pCLServing->fd, FLAGFALSE, + "login requires argument\r\n", -1); + } else { + BuildString((char *)0, pCLServing->username); + BuildString((char *)0, pCLServing->acid); + BuildString(pcArgs, pCLServing->username); + BuildString(pcArgs, pCLServing->acid); + BuildStringChar('@', pCLServing->acid); + BuildString(pCLServing->peername->string, + pCLServing->acid); + if (pCLServing->caccess == 't' || + CheckPasswd(pCLServing, "") == AUTH_SUCCESS) { + pCLServing->iState = S_NORMAL; + Verbose(" login %s", + pCLServing->acid->string); + FileWrite(pCLServing->fd, FLAGFALSE, "ok\r\n", + 4); + } else { + FilePrint(pCLServing->fd, FLAGFALSE, + "passwd? %s\r\n", myHostname); + pCLServing->iState = S_PASSWD; + } + } +#if HAVE_OPENSSL } - FilePrint(pCLServing->fd, FLAGTRUE, "@%s", - inet_ntoa(lcl.sin_addr)); - iSep = 0; - } - if (config->redirect == FLAGTRUE) { - REMOTE *pRC; - for (pRC = pRCUniq; (REMOTE *)0 != pRC; pRC = pRC->pRCuniq) { - FilePrint(pCLServing->fd, FLAGTRUE, ":@%s" + iSep, - pRC->rhost); +#endif + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "master") == 0) { + int iSep = 1; + + if ((GRPENT *)0 != pGroups) { + struct sockaddr_in lcl; + socklen_t so = sizeof(lcl); + if (-1 == + getsockname(FileFDNum(pCLServing->fd), + (struct sockaddr *)&lcl, &so)) { + FileWrite(pCLServing->fd, FLAGFALSE, + "getsockname failed, try again later\r\n", + -1); + Error("Master(): getsockname(%u): %s", + FileFDNum(pCLServing->fd), strerror(errno)); + Bye(EX_OSERR); + } + FilePrint(pCLServing->fd, FLAGTRUE, "@%s", + inet_ntoa(lcl.sin_addr)); iSep = 0; } - } - FileWrite(pCLServing->fd, FLAGFALSE, "\r\n", -1); - } else if (pCLServing->iState == S_NORMAL && - strcmp(pcCmd, "pid") == 0) { - FilePrint(pCLServing->fd, FLAGFALSE, "%lu\r\n", - (unsigned long)thepid); - } else if (pCLServing->iState == S_NORMAL && - strcmp(pcCmd, "version") == 0) { - FilePrint(pCLServing->fd, FLAGFALSE, "version `%s'\r\n", - THIS_VERSION); - } else if (pCLServing->iState == S_NORMAL && - strcmp(pcCmd, "quit") == 0) { - if (ConsentUserOk(pADList, pCLServing->username->string) == 1) { - Verbose("quit command by %s", pCLServing->acid->string); - FileWrite(pCLServing->fd, FLAGFALSE, - "ok -- terminated\r\n", -1); - DropMasterClient(pCLServing, FLAGFALSE); - kill(thepid, SIGTERM); - return; - } else - FileWrite(pCLServing->fd, FLAGFALSE, - "unauthorized command\r\n", -1); - } else if (pCLServing->iState == S_NORMAL && - strcmp(pcCmd, "restart") == 0) { - if (ConsentUserOk(pADList, pCLServing->username->string) == 1) { - FileWrite(pCLServing->fd, FLAGFALSE, - "ok -- restarting\r\n", -1); - Verbose("restart command by %s", pCLServing->acid->string); - kill(thepid, SIGHUP); - } else - FileWrite(pCLServing->fd, FLAGFALSE, - "unauthorized command\r\n", -1); - } else if (pCLServing->iState == S_NORMAL && - strcmp(pcCmd, "groups") == 0) { - int iSep = 1; - GRPENT *pGE; + if (config->redirect == FLAGTRUE) { + REMOTE *pRC; + for (pRC = pRCUniq; (REMOTE *)0 != pRC; + pRC = pRC->pRCuniq) { + FilePrint(pCLServing->fd, FLAGTRUE, ":@%s" + iSep, + pRC->rhost); + iSep = 0; + } + } + FileWrite(pCLServing->fd, FLAGFALSE, "\r\n", -1); + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "pid") == 0) { + FilePrint(pCLServing->fd, FLAGFALSE, "%lu\r\n", + (unsigned long)thepid); + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "version") == 0) { + FilePrint(pCLServing->fd, FLAGFALSE, "version `%s'\r\n", + THIS_VERSION); + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "quit") == 0) { + if (ConsentUserOk(pADList, pCLServing->username->string) == + 1) { + Verbose("quit command by %s", + pCLServing->acid->string); + FileWrite(pCLServing->fd, FLAGFALSE, + "ok -- terminated\r\n", -1); + DropMasterClient(pCLServing, FLAGFALSE); + kill(thepid, SIGTERM); + return; + } else + FileWrite(pCLServing->fd, FLAGFALSE, + "unauthorized command\r\n", -1); + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "restart") == 0) { + if (ConsentUserOk(pADList, pCLServing->username->string) == + 1) { + FileWrite(pCLServing->fd, FLAGFALSE, + "ok -- restarting\r\n", -1); + Verbose("restart command by %s", + pCLServing->acid->string); + kill(thepid, SIGHUP); + } else + FileWrite(pCLServing->fd, FLAGFALSE, + "unauthorized command\r\n", -1); + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "groups") == 0) { + int iSep = 1; + GRPENT *pGE; - for (pGE = pGroups; pGE != (GRPENT *)0; pGE = pGE->pGEnext) { - if (0 == pGE->imembers) - continue; - FilePrint(pCLServing->fd, FLAGTRUE, ":%hu" + iSep, - pGE->port); - iSep = 0; + for (pGE = pGroups; pGE != (GRPENT *)0; pGE = pGE->pGEnext) { + if (0 == pGE->imembers) + continue; + FilePrint(pCLServing->fd, FLAGTRUE, ":%hu" + iSep, + pGE->port); + iSep = 0; + } + FileWrite(pCLServing->fd, FLAGFALSE, "\r\n", 2); + } else if (pCLServing->iState == S_NORMAL && + strcmp(pcCmd, "call") == 0) { + if (pcArgs == (char *)0) + FileWrite(pCLServing->fd, FLAGFALSE, + "call requires argument\r\n", -1); + else + CommandCall(pCLServing, pcArgs); + } else { + FileWrite(pCLServing->fd, FLAGFALSE, "unknown command\r\n", + -1); } - FileWrite(pCLServing->fd, FLAGFALSE, "\r\n", 2); - } else if (pCLServing->iState == S_NORMAL && - strcmp(pcCmd, "call") == 0) { - if (pcArgs == (char *)0) - FileWrite(pCLServing->fd, FLAGFALSE, - "call requires argument\r\n", -1); - else - CommandCall(pCLServing, pcArgs); - } else { - FileWrite(pCLServing->fd, FLAGFALSE, "unknown command\r\n", - -1); + BuildString((char *)0, pCLServing->accmd); } - BuildString((char *)0, pCLServing->accmd); + nr -= l; + MemMove(acIn, acIn + l, nr); } } @@ -872,9 +885,10 @@ Master() } /* set to non-blocking and wrap in a File object */ - if (SetFlags(cfd, O_NONBLOCK, 0)) + if (SetFlags(cfd, O_NONBLOCK, 0)) { pCLmfree->fd = FileOpenFD(cfd, simpleSocket); - else + FileSetQuoteIAC(pCLmfree->fd, FLAGTRUE); + } else pCLmfree->fd = (CONSFILE *)0; if ((CONSFILE *)0 == pCLmfree->fd) { diff --git a/conserver/readcfg.c b/conserver/readcfg.c index 1f4a8d7..8d08479 100644 --- a/conserver/readcfg.c +++ b/conserver/readcfg.c @@ -1,5 +1,5 @@ /* - * $Id: readcfg.c,v 5.160 2003/12/01 02:15:18 bryan Exp $ + * $Id: readcfg.c,v 5.162 2003/12/21 16:23:02 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -653,7 +653,7 @@ ApplyDefault(d, c) CONSENT *c; #endif { - if (d->type != UNKNOWN) + if (d->type != UNKNOWNTYPE) c->type = d->type; if (d->breakNum != 0) c->breakNum = d->breakNum; @@ -1684,6 +1684,41 @@ DefaultItemPortinc(id) ProcessPortinc(parserDefaultTemp, id); } +void +#if PROTOTYPES +ProcessProtocol(CONSENT *c, char *id) +#else +ProcessProtocol(c, id) + CONSENT *c; + char *id; +#endif +{ + c->raw = 0; + if ((id == (char *)0) || (*id == '\000')) + return; + + if (strcmp(id, "telnet") == 0) + return; + if (strcmp(id, "raw") == 0) { + c->raw = 1; + return; + } + if (isMaster) + Error("invalid protocol name `%s' [%s:%d]", id, file, line); +} + +void +#if PROTOTYPES +DefaultItemProtocol(char *id) +#else +DefaultItemProtocol(id) + char *id; +#endif +{ + CONDDEBUG((1, "DefaultItemProtocol(%s) [%s:%d]", id, file, line)); + ProcessProtocol(parserDefaultTemp, id); +} + void #if PROTOTYPES ProcessIdletimeout(CONSENT *c, char *id) @@ -1953,7 +1988,7 @@ ProcessType(c, id) char *id; #endif { - CONSTYPE t = UNKNOWN; + CONSTYPE t = UNKNOWNTYPE; if ((id == (char *)0) || (*id == '\000')) { c->type = t; return; @@ -1964,7 +1999,7 @@ ProcessType(c, id) t = EXEC; else if (strcasecmp("host", id) == 0) t = HOST; - if (t == UNKNOWN) { + if (t == UNKNOWNTYPE) { if (isMaster) Error("invalid console type `%s' [%s:%d]", id, file, line); } else @@ -2119,7 +2154,7 @@ ConsoleEnd() invalid = 1; } break; - case UNKNOWN: + case UNKNOWNTYPE: if (isMaster) Error("[%s] console type unknown [%s:%d]", parserConsoleTemp->server, file, line); @@ -2697,16 +2732,17 @@ ConsoleAdd(c) closeMatch = 0; } break; - case UNKNOWN: + case UNKNOWNTYPE: break; } /* and now the rest (minus the "runtime" members - see below) */ pCEmatch->idletimeout = c->idletimeout; if (pCEmatch->idletimeout != (time_t)0 && - (timers[T_IDLE] == (time_t)0 || - timers[T_IDLE] > pCEmatch->lastWrite + pCEmatch->idletimeout)) - timers[T_IDLE] = pCEmatch->lastWrite + pCEmatch->idletimeout; + (timers[T_CIDLE] == (time_t)0 || + timers[T_CIDLE] > + pCEmatch->lastWrite + pCEmatch->idletimeout)) + timers[T_CIDLE] = pCEmatch->lastWrite + pCEmatch->idletimeout; pCEmatch->logfilemax = c->logfilemax; if (pCEmatch->logfilemax != (off_t) 0 && @@ -3278,6 +3314,18 @@ ConsoleItemPortinc(id) ProcessPortinc(parserConsoleTemp, id); } +void +#if PROTOTYPES +ConsoleItemProtocol(char *id) +#else +ConsoleItemProtocol(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConsoleItemProtocol(%s) [%s:%d]", id, file, line)); + ProcessProtocol(parserConsoleTemp, id); +} + void #if PROTOTYPES ConsoleItemIdletimeout(char *id) @@ -4263,6 +4311,7 @@ ITEM keyDefault[] = { {"port", DefaultItemPort}, {"portbase", DefaultItemPortbase}, {"portinc", DefaultItemPortinc}, + {"protocol", DefaultItemProtocol}, {"ro", DefaultItemRo}, {"rw", DefaultItemRw}, {"timestamp", DefaultItemTimestamp}, @@ -4293,6 +4342,7 @@ ITEM keyConsole[] = { {"port", ConsoleItemPort}, {"portbase", ConsoleItemPortbase}, {"portinc", ConsoleItemPortinc}, + {"protocol", ConsoleItemProtocol}, {"ro", ConsoleItemRo}, {"rw", ConsoleItemRw}, {"timestamp", ConsoleItemTimestamp}, diff --git a/conserver/version.h b/conserver/version.h index 8b3bed2..5e9e10a 100644 --- a/conserver/version.h +++ b/conserver/version.h @@ -1,5 +1,5 @@ /* - * $Id: version.h,v 1.55 2003/12/10 18:33:48 bryan Exp $ + * $Id: version.h,v 1.56 2003/12/20 06:11:53 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -14,4 +14,4 @@ @(#) Copyright 2000 conserver.com.\n\ All rights reserved.\n" -#define THIS_VERSION "conserver.com version 8.0.9" +#define THIS_VERSION "conserver.com version 8.1.0" diff --git a/console/console.c b/console/console.c index 926a060..3f9e96e 100644 --- a/console/console.c +++ b/console/console.c @@ -1,5 +1,5 @@ /* - * $Id: console.c,v 5.152 2003/11/28 00:47:30 bryan Exp $ + * $Id: console.c,v 5.155 2004/01/08 16:12:46 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -193,7 +193,7 @@ Usage(wantfull) "D enable debug output, sent to stderr", "e esc set the initial escape characters", #if HAVE_OPENSSL - "E don't require encrypted connections", + "E don't attempt encrypted connections", #else "E ignored - encryption not compiled into code", #endif @@ -573,6 +573,7 @@ ReadReply(fd) BuildString((char *)0, result); while (1) { + int l; switch (nr = FileRead(fd, buf, sizeof(buf))) { case 0: /* fall through */ @@ -583,6 +584,13 @@ ReadReply(fd) Error("lost connection"); Bye(EX_UNAVAILABLE); default: + while ((l = ParseIACBuf(fd, buf, &nr)) >= 0) { + if (l == 0) + continue; + BuildStringN(buf, l, result); + nr -= l; + MemMove(buf, buf + l, nr); + } BuildStringN(buf, nr, result); if (toEOF) /* if toEOF, read until EOF */ continue; @@ -604,119 +612,6 @@ ReadReply(fd) return result->string; } -static int SawUrg = 0; - -/* when the conserver program gets the suspend sequence it will send us - * an out of band command to suspend ourself. We just tell the reader - * routine we saw one - */ -RETSIGTYPE -#if PROTOTYPES -OOB(int sig) -#else -OOB(sig) - int sig; -#endif -{ - ++SawUrg; -#if !HAVE_SIGACTION -#if defined(SIGURG) - SimpleSignal(SIGURG, OOB); -#endif -#endif -} - -void -#if PROTOTYPES -ProcessUrgentData(CONSFILE *pcf) -#else -ProcessUrgentData(pcf) - CONSFILE *pcf; -#endif -{ - static char acCmd; - int s; - - SawUrg = 0; - s = FileFDNum(pcf); - - /* get the pending urgent message - */ - while (recv(s, &acCmd, 1, MSG_OOB) < 0) { - switch (errno) { - case EWOULDBLOCK: - /* clear any pending input to make room */ - read(s, &acCmd, 1); - FileWrite(cfstdout, FLAGFALSE, ".", 1); - continue; - case EINVAL: - default: - Error("recv(%d): %s\r", s, strerror(errno)); - sleep(1); - continue; - } - } - switch (acCmd) { - case OB_EXEC: - FileWrite(cfstdout, FLAGFALSE, "exec: ", 6); - BuildString((char *)0, execCmd); - for (;;) { - char c; - if (read(0, &c, 1) == 0) - break; - if (c == '\n' || c == '\r') { - FileWrite(cfstdout, FLAGFALSE, "]\r\n", 3); - if (execCmd->used <= 1) { - char s = OB_DROP; - FileWrite(pcf, FLAGFALSE, &s, 1); - } - break; - } - if (c == '\a' || (c >= ' ' && c <= '~')) { - BuildStringChar(c, execCmd); - FileWrite(cfstdout, FLAGFALSE, &c, 1); - } else if ((c == '\b' || c == 0x7f) && execCmd->used > 1) { - if (execCmd->string[execCmd->used - 2] != '\a') { - FileWrite(cfstdout, FLAGFALSE, "\b \b", 3); - } - execCmd->string[execCmd->used - 2] = '\000'; - execCmd->used--; - } else if ((c == 0x15) && execCmd->used > 1) { - while (execCmd->used > 1) { - if (execCmd->string[execCmd->used - 2] != '\a') { - FileWrite(cfstdout, FLAGFALSE, "\b \b", 3); - } - execCmd->string[execCmd->used - 2] = '\000'; - execCmd->used--; - } - } - } - break; - case OB_SUSP: -#if defined(SIGSTOP) - FileWrite(cfstdout, FLAGFALSE, "stop]", 5); - C2Cooked(); - kill(getpid(), SIGSTOP); - C2Raw(); - FileWrite(cfstdout, FLAGFALSE, - "[press any character to continue", 32); -#else - FileWrite(cfstdout, FLAGFALSE, - "stop not supported -- press any character to continue", - 53); -#endif - break; - case OB_DROP: - FileWrite(cfstdout, FLAGFALSE, "dropped by server]\r\n", 20); - C2Cooked(); - Bye(EX_UNAVAILABLE); - /*NOTREACHED*/ default: - Error("unknown out of band command `%c\'\r", acCmd); - fflush(stderr); - break; - } -} - static void #if PROTOTYPES ReapVirt(void) @@ -846,9 +741,6 @@ ExecCmd() /* put the signals back that we ignore (trapped auto-reset to default) */ -#if defined(SIGURG) - SimpleSignal(SIGURG, SIG_DFL); -#endif SimpleSignal(SIGPIPE, SIG_DFL); SimpleSignal(SIGCHLD, SIG_DFL); @@ -867,10 +759,10 @@ ExecCmd() iNewGrp = setsid(); if (-1 == iNewGrp) { Error("ExecCmd(): setsid(): %s", strerror(errno)); - iNewGrp = getpid(); + iNewGrp = thepid; } # else - iNewGrp = getpid(); + iNewGrp = thepid; # endif if (dup(pout[0]) != 0 || dup(pin[1]) != 1) { @@ -890,6 +782,84 @@ ExecCmd() return; } +void +#if PROTOTYPES +DoExec(CONSFILE *pcf) +#else +DoExec(pcf) + CONSFILE *pcf; +#endif +{ + FileWrite(cfstdout, FLAGFALSE, "exec: ", 6); + BuildString((char *)0, execCmd); + for (;;) { + char c; + if (read(0, &c, 1) == 0) + break; + if (c == '\n' || c == '\r') { + FileWrite(cfstdout, FLAGFALSE, "]\r\n", 3); + break; + } + if (c == '\a' || (c >= ' ' && c <= '~')) { + BuildStringChar(c, execCmd); + FileWrite(cfstdout, FLAGFALSE, &c, 1); + } else if ((c == '\b' || c == 0x7f) && execCmd->used > 1) { + if (execCmd->string[execCmd->used - 2] != '\a') { + FileWrite(cfstdout, FLAGFALSE, "\b \b", 3); + } + execCmd->string[execCmd->used - 2] = '\000'; + execCmd->used--; + } else if ((c == 0x15) && execCmd->used > 1) { + while (execCmd->used > 1) { + if (execCmd->string[execCmd->used - 2] != '\a') { + FileWrite(cfstdout, FLAGFALSE, "\b \b", 3); + } + execCmd->string[execCmd->used - 2] = '\000'; + execCmd->used--; + } + } + } + if (execCmd != (STRING *)0 && execCmd->used > 1) { + ExecCmd(); + BuildString((char *)0, execCmd); + if (execCmdFile == (CONSFILE *)0) { /* exec failed */ + /* say forget it */ + FileSetQuoteIAC(pcf, FLAGFALSE); + FilePrint(pcf, FLAGFALSE, "%c%c", OB_IAC, OB_ABRT); + FileSetQuoteIAC(pcf, FLAGTRUE); + } else { + char *r; + /* go back to blocking mode */ + SetFlags(FileFDNum(pcf), 0, O_NONBLOCK); + /* say we're ready */ + FileSetQuoteIAC(pcf, FLAGFALSE); + FilePrint(pcf, FLAGFALSE, "%c%c", OB_IAC, OB_EXEC); + FileSetQuoteIAC(pcf, FLAGTRUE); + r = ReadReply(pcf, 0); + /* now back to non-blocking, now that we've got reply */ + SetFlags(FileFDNum(pcf), O_NONBLOCK, 0); + /* if we aren't still r/w, abort */ + if (strncmp(r, "[rw]", 4) != 0) { + FileWrite(cfstdout, FLAGFALSE, + "[no longer read-write - aborting command]\r\n", + -1); + FD_CLR(FileFDNum(execCmdFile), &rinit); + FD_CLR(FileFDOutNum(execCmdFile), &winit); + FileClose(&execCmdFile); + FileSetQuoteIAC(pcf, FLAGFALSE); + FilePrint(pcf, FLAGFALSE, "%c%c", OB_IAC, OB_ABRT); + FileSetQuoteIAC(pcf, FLAGTRUE); + kill(execCmdPid, SIGHUP); + } + } + } else { + /* say forget it */ + FileSetQuoteIAC(pcf, FLAGFALSE); + FilePrint(pcf, FLAGFALSE, "%c%c", OB_IAC, OB_ABRT); + FileSetQuoteIAC(pcf, FLAGTRUE); + } +} + /* interact with a group server (ksb) */ static int @@ -906,7 +876,7 @@ CallUp(pcf, pcMaster, pcMach, pcHow, result) int fIn = '-'; fd_set rmask, wmask; int i; - int justProcessedUrg = 0; + int justSuspended = 0; char *r = (char *)0; static char acMesg[8192]; @@ -915,9 +885,9 @@ CallUp(pcf, pcMaster, pcMach, pcHow, result) } #if !defined(__CYGWIN__) # if defined(F_SETOWN) - if (fcntl(FileFDNum(pcf), F_SETOWN, getpid()) == -1) { - Error("fcntl(F_SETOWN,%d): %d: %s", getpid(), FileFDNum(pcf), - strerror(errno)); + if (fcntl(FileFDNum(pcf), F_SETOWN, thepid) == -1) { + Error("fcntl(F_SETOWN,%lu): %d: %s", (unsigned long)thepid, + FileFDNum(pcf), strerror(errno)); } # else # if defined(SIOCSPGRP) @@ -925,7 +895,7 @@ CallUp(pcf, pcMaster, pcMach, pcHow, result) int iTemp; /* on the HP-UX systems if different */ - iTemp = -getpid(); + iTemp = -thepid; if (ioctl(FileFDNum(pcf), SIOCSPGRP, &iTemp) == -1) { Error("ioctl(%d,SIOCSPGRP): %s", FileFDNum(pcf), strerror(errno)); @@ -933,9 +903,6 @@ CallUp(pcf, pcMaster, pcMach, pcHow, result) } # endif # endif -#endif -#if defined(SIGURG) - SimpleSignal(SIGURG, OOB); #endif SimpleSignal(SIGCHLD, FlagReapVirt); @@ -1048,38 +1015,7 @@ CallUp(pcf, pcMaster, pcMach, pcHow, result) if (maxfd < FileFDNum(pcf) + 1) maxfd = FileFDNum(pcf) + 1; for (;;) { - justProcessedUrg = 0; - if (SawUrg) { - ProcessUrgentData(pcf); - justProcessedUrg = 1; - } - if (execCmd != (STRING *)0 && execCmd->used > 1) { - char *r; - char s = OB_EXEC; - ExecCmd(); - BuildString((char *)0, execCmd); - if (execCmdFile == (CONSFILE *)0) { /* exec failed */ - s = OB_DROP; - FileWrite(pcf, FLAGFALSE, &s, 1); /* say forget it */ - } else { - /* go back to blocking mode */ - SetFlags(FileFDNum(pcf), 0, O_NONBLOCK); - FileWrite(pcf, FLAGFALSE, &s, 1); /* say we're ready */ - r = ReadReply(pcf, 0); - /* now back to non-blocking now that we've got reply */ - SetFlags(FileFDNum(pcf), O_NONBLOCK, 0); - /* if we aren't still r/w, abort */ - if (strncmp(r, "[rw]", 4) != 0) { - FileWrite(cfstdout, FLAGFALSE, - "[no longer read-write - aborting command]\r\n", - -1); - FD_CLR(FileFDNum(execCmdFile), &rinit); - FD_CLR(FileFDOutNum(execCmdFile), &winit); - FileClose(&execCmdFile); - kill(execCmdPid, SIGHUP); - } - } - } + justSuspended = 0; if (fSawReapVirt) { fSawReapVirt = 0; ReapVirt(); @@ -1106,6 +1042,9 @@ CallUp(pcf, pcMaster, pcMach, pcHow, result) FD_CLR(FileFDNum(execCmdFile), &rinit); FD_CLR(FileFDOutNum(execCmdFile), &winit); FileClose(&execCmdFile); + FileSetQuoteIAC(pcf, FLAGFALSE); + FilePrint(pcf, FLAGFALSE, "%c%c", OB_IAC, OB_ABRT); + FileSetQuoteIAC(pcf, FLAGTRUE); } else { if (fStrip) { for (i = 0; i < nc; ++i) @@ -1126,21 +1065,46 @@ CallUp(pcf, pcMaster, pcMach, pcHow, result) /* anything from socket? */ if (FileCanRead(pcf, &rmask, &wmask)) { + int l; if ((nc = FileRead(pcf, acMesg, sizeof(acMesg))) < 0) { /* if we got an error/eof after returning from suspend */ - if (justProcessedUrg) { + if (justSuspended) { fprintf(stderr, "\n"); Error("lost connection"); } break; } - if (fStrip) { - for (i = 0; i < nc; ++i) - acMesg[i] &= 127; - } - FileWrite(cfstdout, FLAGFALSE, acMesg, nc); - if (execCmdFile != (CONSFILE *)0) { - FileWrite(execCmdFile, FLAGFALSE, acMesg, nc); + while ((l = ParseIACBuf(pcf, acMesg, &nc)) >= 0) { + if (l == 0) { + if (FileSawQuoteExec(pcf) == FLAGTRUE) + DoExec(pcf); + if (FileSawQuoteSusp(pcf) == FLAGTRUE) { + justSuspended = 1; +#if defined(SIGSTOP) + FileWrite(cfstdout, FLAGFALSE, "stop]", 5); + C2Cooked(); + kill(thepid, SIGSTOP); + C2Raw(); + FileWrite(cfstdout, FLAGFALSE, + "[press any character to continue", 32); +#else + FileWrite(cfstdout, FLAGFALSE, + "stop not supported -- press any character to continue", + 53); +#endif + } + continue; + } + if (fStrip) { + for (i = 0; i < l; ++i) + acMesg[i] &= 127; + } + FileWrite(cfstdout, FLAGFALSE, acMesg, l); + if (execCmdFile != (CONSFILE *)0) { + FileWrite(execCmdFile, FLAGFALSE, acMesg, l); + } + nc -= l; + MemMove(acMesg, acMesg + l, nc); } } else if (!FileBufEmpty(pcf) && FileCanWrite(pcf, &rmask, &wmask)) { CONDDEBUG((1, "CallUp(): flushing fd %d", FileFDNum(pcf))); @@ -1255,6 +1219,8 @@ DoCmds(master, ports, cmdi) if ((pcf = GetPort(server, port)) == (CONSFILE *)0) continue; + FileSetQuoteIAC(pcf, FLAGTRUE); + t = ReadReply(pcf, 0); if (strcmp(t, "ok\r\n") != 0) { FileClose(&pcf); @@ -1262,15 +1228,17 @@ DoCmds(master, ports, cmdi) continue; } #if HAVE_OPENSSL - FileWrite(pcf, FLAGFALSE, "ssl\r\n", 5); - t = ReadReply(pcf, 0); - if (strcmp(t, "ok\r\n") == 0) { - AttemptSSL(pcf); - } - if (fReqEncryption && FileGetType(pcf) != SSLSocket) { - Error("Encryption not supported by server `%s'", server); - FileClose(&pcf); - continue; + if (fReqEncryption) { + FileWrite(pcf, FLAGFALSE, "ssl\r\n", 5); + t = ReadReply(pcf, 0); + if (strcmp(t, "ok\r\n") == 0) { + AttemptSSL(pcf); + } + if (FileGetType(pcf) != SSLSocket) { + Error("Encryption not supported by server `%s'", server); + FileClose(&pcf); + continue; + } } #endif @@ -1320,6 +1288,10 @@ DoCmds(master, ports, cmdi) continue; } else count = 0; + } else if (strcmp(t, "ok\r\n") != 0) { + FileClose(&pcf); + FilePrint(cfstdout, FLAGFALSE, "%s: %s", server, t); + continue; } /* now that we're logged in, we can do something */ @@ -1457,6 +1429,8 @@ main(argc, argv) isMultiProc = 0; /* make sure stuff DOESN'T have the pid */ + thepid = getpid(); + if (textMsg == (STRING *)0) textMsg = AllocString(); if (acPorts == (STRING *)0) diff --git a/console/console.man b/console/console.man index 5ab5070..4d72e1d 100644 --- a/console/console.man +++ b/console/console.man @@ -1,5 +1,5 @@ -.\" $Id: console.man,v 1.41 2003/11/28 00:47:30 bryan Exp $ -.TH CONSOLE 1 "2003/11/28" "conserver-8.0.9" "conserver" +.\" $Id: console.man,v 1.42 2003/12/25 19:22:02 bryan Exp $ +.TH CONSOLE 1 "2003/12/25" "conserver-8.1.0" "conserver" .SH NAME console \- console server client program .SH SYNOPSIS @@ -324,7 +324,7 @@ file descriptor for the device. Commands will have values of the command, the command's pid, the pseudo-tty, and file descriptor for the pseudo-tty. Remote ports will have values of the remote hostname, remote port number, -and file descriptor for the socket connection. +``raw'' or ``telnet'' protocol, and file descriptor for the socket connection. .TP .I users-list The details of each user connected to the console. diff --git a/contrib/redhat-rpm/conserver.spec b/contrib/redhat-rpm/conserver.spec index f088ce1..4e8d314 100644 --- a/contrib/redhat-rpm/conserver.spec +++ b/contrib/redhat-rpm/conserver.spec @@ -4,7 +4,7 @@ # %define pkg conserver -%define ver 8.0.9 +%define ver 8.1.0 # define the name of the machine on which the main conserver # daemon will be running if you don't want to use the default diff --git a/contrib/solaris-package/pkginfo b/contrib/solaris-package/pkginfo index ef68097..432319d 100644 --- a/contrib/solaris-package/pkginfo +++ b/contrib/solaris-package/pkginfo @@ -1,7 +1,7 @@ PKG="conserver" NAME="Console server and client" CATEGORY="system" -VERSION="8.0.9" +VERSION="8.1.0" DESC="Console server and client" CLASSES=none ARCH=sparc