From cf461c7ce8b87e3c6580e481576022ba786be969 Mon Sep 17 00:00:00 2001 From: Bryan Stansell Date: Tue, 25 May 2004 17:41:29 -0700 Subject: [PATCH] Imported from conserver-8.1.6.tar.gz --- CHANGES | 18 +- TODO | 14 +- config.h.in | 3 + configure | 69 +++ configure.in | 47 ++ conserver.cf/conserver.cf.man | 2 +- conserver.cf/conserver.passwd.man | 2 +- conserver.html | 8 +- conserver/access.c | 40 +- conserver/consent.h | 4 +- conserver/conserver.man | 11 +- conserver/convert.c | 8 +- conserver/cutil.c | 912 +++++++++++++++++++++++++++++- conserver/cutil.h | 41 +- conserver/group.c | 22 +- conserver/group.h | 3 +- conserver/main.c | 239 +------- conserver/main.h | 3 +- conserver/readcfg.c | 837 +++------------------------ conserver/readcfg.h | 3 +- conserver/version.h | 4 +- console/Makefile.in | 4 +- console/console.c | 445 ++++++++++++--- console/console.man | 371 +++++++++++- console/readconf.c | 720 +++++++++++++++++++++++ console/readconf.h | 38 ++ contrib/redhat-rpm/conserver.spec | 2 +- contrib/solaris-package/pkginfo | 2 +- test/dotest | 13 +- 29 files changed, 2750 insertions(+), 1135 deletions(-) create mode 100644 console/readconf.c create mode 100644 console/readconf.h diff --git a/CHANGES b/CHANGES index 1a27115..7f4004e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,22 @@ CHANGES ======= +version 8.1.6 (May 25, 2004): + - added ability to configure client via sytem-wide console.cf + file and per-user .consolerc - suggested by Erik Sjolund + + - fixed bug where break strings were not properly sent - + reported by Tim Small + - fixed bug in config file 'protocol' value handling - reported + by Kees Cook + - conserver no longer uses the local domain name in the default + access list (the default list is only created if no access + list is specified in the configuration file) - inspired by + William P LePera + - added a 'terminal' console configuration block for printing + strings when attaching and detaching from consoles - suggested + by Richard Threadgill + version 8.1.5 (May 7, 2004): - changed remaining O_NDELAY flags to O_NONBLOCK - added PROTOCOLS file to describe the client/server protocol @@ -722,5 +738,5 @@ before version 6.05: and enhancements of various types were applied. # -# $Id: CHANGES,v 1.174 2004/05/07 16:04:58 bryan Exp $ +# $Id: CHANGES,v 1.179 2004/05/26 00:14:07 bryan Exp $ # diff --git a/TODO b/TODO index 93a6f93..c4e09b9 100644 --- a/TODO +++ b/TODO @@ -86,26 +86,14 @@ Bryan Stansell - not even sure if this is possible w/o confusing the client, but maybe with the new 8.1.0 client-server protocol, we can! -- send a string when connected to a console, so you can set the - xterm title, for example : Richard Threadgill - - this probably requires a client config file, so could play well - with the client config file requirement above - - allow for very long replays (hundres of lines) : John Stoffel - log rotation by date : Tom Pachla -- client config file (for -M, etc?) : Erik Sjolund - - - strict file permission checks on conserver.passwd/conserver.cf : Erik Sjolund -- embedded startup delays per remote host...or "group" of consoles in - some way 'cause some ssh connections to console servers need - significant throttling : Jay McCanta - # -# $Id: TODO,v 1.47 2004/03/12 17:34:49 bryan Exp $ +# $Id: TODO,v 1.49 2004/05/25 00:38:11 bryan Exp $ # diff --git a/config.h.in b/config.h.in index d1c6f1b..f737d52 100644 --- a/config.h.in +++ b/config.h.in @@ -1,5 +1,8 @@ /* config.h.in. Generated from configure.in by autoheader. */ +/* Client config file path */ +#undef CLIENTCONFIGFILE + /* Config file path */ #undef CONFIGFILE diff --git a/configure b/configure index 74a726f..e0a6369 100755 --- a/configure +++ b/configure @@ -847,6 +847,8 @@ Optional Packages: --with-port=PORT Specify port number [conserver] --with-base=PORT Base port for secondary channel [0] --with-master=MASTER Specify master server hostname [console] + --with-ccffile=CFFILE Specify client config filename + [SYSCONFDIR/console.cf] --with-cffile=CFFILE Specify config filename [SYSCONFDIR/conserver.cf] --with-pwdfile=PWDFILE Specify password filename @@ -1432,6 +1434,47 @@ _ACEOF echo "${ECHO_T}'console'" >&6 fi; +echo "$as_me:$LINENO: checking for client configuration filename" >&5 +echo $ECHO_N "checking for client configuration filename... $ECHO_C" >&6 + +# Check whether --with-ccffile or --without-ccffile was given. +if test "${with_ccffile+set}" = set; then + withval="$with_ccffile" + case "$withval" in + yes|no) + cat >>confdefs.h <<_ACEOF +#define CLIENTCONFIGFILE SYSCONFDIR "/console.cf" +_ACEOF + + echo "$as_me:$LINENO: result: '$sysconfdir/console.cf'" >&5 +echo "${ECHO_T}'$sysconfdir/console.cf'" >&6 + ;; + [\\/]* | ?:[\\/]* ) + cat >>confdefs.h <<_ACEOF +#define CLIENTCONFIGFILE "$withval" +_ACEOF + + echo "$as_me:$LINENO: result: '$withval'" >&5 +echo "${ECHO_T}'$withval'" >&6 + ;; + *) + cat >>confdefs.h <<_ACEOF +#define CLIENTCONFIGFILE SYSCONFDIR "/$withval" +_ACEOF + + echo "$as_me:$LINENO: result: '$sysconfdir/$withval'" >&5 +echo "${ECHO_T}'$sysconfdir/$withval'" >&6 + ;; + esac +else + cat >>confdefs.h <<_ACEOF +#define CLIENTCONFIGFILE SYSCONFDIR "/console.cf" +_ACEOF + + echo "$as_me:$LINENO: result: '$sysconfdir/console.cf'" >&5 +echo "${ECHO_T}'$sysconfdir/console.cf'" >&6 +fi; + echo "$as_me:$LINENO: checking for configuration filename" >&5 echo $ECHO_N "checking for configuration filename... $ECHO_C" >&6 @@ -1698,6 +1741,7 @@ fi; echo "$as_me:$LINENO: checking whether to use Unix domain sockets" >&5 echo $ECHO_N "checking whether to use Unix domain sockets... $ECHO_C" >&6 +cons_with_uds="NO" # Check whether --with-uds or --without-uds was given. if test "${with_uds+set}" = set; then @@ -1714,6 +1758,7 @@ _ACEOF echo "$as_me:$LINENO: result: /tmp/conserver" >&5 echo "${ECHO_T}/tmp/conserver" >&6 + cons_with_uds="YES" ;; no) echo "$as_me:$LINENO: result: no" >&5 @@ -1730,6 +1775,7 @@ _ACEOF echo "$as_me:$LINENO: result: '$withval'" >&5 echo "${ECHO_T}'$withval'" >&6 + cons_with_uds="YES" if expr "$withval" : '/' >/dev/null 2>&1; then : else @@ -5424,6 +5470,7 @@ fi +cons_with_libwrap="NO" # Check whether --with-libwrap or --without-libwrap was given. if test "${with_libwrap+set}" = set; then @@ -5627,6 +5674,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (exit $ac_status); }; }; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 + cons_with_libwrap="YES" cat >>confdefs.h <<\_ACEOF #define USE_LIBWRAP 1 _ACEOF @@ -5685,6 +5733,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (exit $ac_status); }; }; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 + cons_with_libwrap="YES" cat >>confdefs.h <<\_ACEOF #define USE_LIBWRAP 1 _ACEOF @@ -5714,6 +5763,7 @@ fi fi; +cons_with_openssl="NO" # Check whether --with-openssl or --without-openssl was given. if test "${with_openssl+set}" = set; then @@ -5916,6 +5966,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (exit $ac_status); }; }; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 + cons_with_openssl="YES" cat >>confdefs.h <<\_ACEOF #define HAVE_OPENSSL 1 _ACEOF @@ -5943,6 +5994,7 @@ fi fi; +cons_with_dmalloc="NO" # Check whether --with-dmalloc or --without-dmalloc was given. if test "${with_dmalloc+set}" = set; then @@ -6145,6 +6197,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (exit $ac_status); }; }; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 + cons_with_dmalloc="YES" cat >>confdefs.h <<\_ACEOF #define HAVE_DMALLOC 1 _ACEOF @@ -6175,6 +6228,7 @@ fi; +cons_with_pam="NO" echo "$as_me:$LINENO: checking for PAM support" >&5 echo $ECHO_N "checking for PAM support... $ECHO_C" >&6 @@ -6371,6 +6425,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (exit $ac_status); }; }; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 + cons_with_pam="YES" cat >>confdefs.h <<\_ACEOF #define HAVE_PAM 1 _ACEOF @@ -6431,6 +6486,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (exit $ac_status); }; }; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 + cons_with_pam="YES" cat >>confdefs.h <<\_ACEOF #define HAVE_PAM 1 _ACEOF @@ -8665,3 +8721,16 @@ if test "$no_create" != yes; then $ac_cs_success || { (exit 1); exit 1; } fi + + +echo "==============================================================" +echo " Feature Summary" +echo "" +echo " Unix domain sockets (--with-uds) : $cons_with_uds" +echo " TCP wrappers (--with-libwrap): $cons_with_libwrap" +echo " OpenSSL (--with-openssl): $cons_with_openssl" +echo " dmalloc (--with-dmalloc): $cons_with_dmalloc" +echo " PAM support (--with-pam) : $cons_with_pam" +echo "" +echo "==============================================================" + diff --git a/configure.in b/configure.in index 17ba677..d05a2f1 100644 --- a/configure.in +++ b/configure.in @@ -4,6 +4,7 @@ AH_TEMPLATE([DEFPORT], [Socket used to communicate]) AH_TEMPLATE([DEFBASEPORT], [Base socket used for secondary channel]) AH_TEMPLATE([MASTERHOST], [Hostname of console server]) AH_TEMPLATE([CONFIGFILE], [Config file path]) +AH_TEMPLATE([CLIENTCONFIGFILE], [Client config file path]) AH_TEMPLATE([PASSWDFILE], [Password file path]) AH_TEMPLATE([LOGFILEPATH], [Logfile path]) AH_TEMPLATE([MAXMEMB], [Number of consoles per child process]) @@ -98,6 +99,26 @@ AC_ARG_WITH(master, [AC_DEFINE_UNQUOTED(MASTERHOST, "console") AC_MSG_RESULT('console')]) +AC_MSG_CHECKING(for client configuration filename) +AC_ARG_WITH(ccffile, + AS_HELP_STRING([--with-ccffile=CFFILE],[Specify client config filename @<:@SYSCONFDIR/console.cf@:>@]), + [case "$withval" in + yes|no) + AC_DEFINE_UNQUOTED(CLIENTCONFIGFILE, [SYSCONFDIR "/console.cf"]) + AC_MSG_RESULT('$sysconfdir/console.cf') + ;; + [[\\/]]* | ?:[[\\/]]* ) + AC_DEFINE_UNQUOTED(CLIENTCONFIGFILE, ["$withval"]) + AC_MSG_RESULT('$withval') + ;; + *) + AC_DEFINE_UNQUOTED(CLIENTCONFIGFILE, [SYSCONFDIR "/$withval"]) + AC_MSG_RESULT('$sysconfdir/$withval') + ;; + esac], + [AC_DEFINE_UNQUOTED(CLIENTCONFIGFILE, [SYSCONFDIR "/console.cf"]) + AC_MSG_RESULT('$sysconfdir/console.cf')]) + AC_MSG_CHECKING(for configuration filename) AC_ARG_WITH(cffile, AS_HELP_STRING([--with-cffile=CFFILE],[Specify config filename @<:@SYSCONFDIR/conserver.cf@:>@]), @@ -233,6 +254,7 @@ AC_ARG_WITH(extmsgs, esac],[AC_MSG_RESULT(no)]) AC_MSG_CHECKING(whether to use Unix domain sockets) +cons_with_uds="NO" AC_ARG_WITH(uds, AS_HELP_STRING([--with-uds@<:@=DIR@:>@ ], [Use Unix domain sockets for client/server communication @<:@/tmp/conserver@:>@]), @@ -241,6 +263,7 @@ AC_ARG_WITH(uds, AC_DEFINE_UNQUOTED(UDSDIR, "/tmp/conserver") AC_DEFINE(USE_UNIX_DOMAIN_SOCKETS) AC_MSG_RESULT([/tmp/conserver]) + cons_with_uds="YES" ;; no) AC_MSG_RESULT(no) @@ -249,6 +272,7 @@ AC_ARG_WITH(uds, AC_DEFINE_UNQUOTED(UDSDIR, "$withval") AC_DEFINE(USE_UNIX_DOMAIN_SOCKETS) AC_MSG_RESULT('$withval') + cons_with_uds="YES" if expr "$withval" : '/' >/dev/null 2>&1; then : else @@ -343,6 +367,7 @@ AC_SEARCH_LIBS(crypt,crypt) AC_SUBST(CONSLIBS) AC_SUBST(CONSCPPFLAGS) AC_SUBST(CONSLDFLAGS) +cons_with_libwrap="NO" AC_ARG_WITH(libwrap, AS_HELP_STRING([--with-libwrap@<:@=PATH@:>@], [Compile in libwrap (tcp_wrappers) support]), @@ -370,6 +395,7 @@ AC_ARG_WITH(libwrap, int deny_severity = 0; ],[hosts_access((void *)0)], [AC_MSG_RESULT(yes) + cons_with_libwrap="YES" AC_DEFINE(USE_LIBWRAP) CONSLIBS="$CONSLIBS -lwrap" CONSLDFLAGS="$CONSLDFLAGS $WRAPLDFLAGS" @@ -382,6 +408,7 @@ AC_ARG_WITH(libwrap, int deny_severity = 0; ],[hosts_access((void *)0)], [AC_MSG_RESULT(yes) + cons_with_libwrap="YES" AC_DEFINE(USE_LIBWRAP) CONSLIBS="$CONSLIBS -lwrap -lnsl" CONSLDFLAGS="$CONSLDFLAGS $WRAPLDFLAGS" @@ -393,6 +420,7 @@ AC_ARG_WITH(libwrap, fi] ) +cons_with_openssl="NO" AC_ARG_WITH(openssl, AS_HELP_STRING([--with-openssl@<:@=PATH@:>@], [Compile in OpenSSL support]), @@ -419,6 +447,7 @@ AC_ARG_WITH(openssl, AC_TRY_LINK([#include ],[SSL_library_init()], [AC_MSG_RESULT(yes) + cons_with_openssl="YES" AC_DEFINE(HAVE_OPENSSL) have_openssl=yes], [AC_MSG_RESULT(no)])],) @@ -431,6 +460,7 @@ AC_ARG_WITH(openssl, fi] ) +cons_with_dmalloc="NO" AC_ARG_WITH(dmalloc, AS_HELP_STRING([--with-dmalloc@<:@=PATH@:>@], [Compile in dmalloc support]), @@ -457,6 +487,7 @@ AC_ARG_WITH(dmalloc, AC_TRY_LINK([#include ],[dmalloc_debug(0)], [AC_MSG_RESULT(yes) + cons_with_dmalloc="YES" AC_DEFINE(HAVE_DMALLOC) have_dmalloc=yes], [AC_MSG_RESULT(no)])],) @@ -505,6 +536,7 @@ dnl else dnl AC_MSG_RESULT(no) dnl fi],[AC_MSG_RESULT(no)]) +cons_with_pam="NO" AC_MSG_CHECKING(for PAM support) AC_ARG_WITH(pam, AS_HELP_STRING([--with-pam], @@ -517,6 +549,7 @@ AC_ARG_WITH(pam, AC_MSG_CHECKING(for PAM library -lpam) AC_TRY_LINK_FUNC([pam_start], [AC_MSG_RESULT(yes) + cons_with_pam="YES" AC_DEFINE(HAVE_PAM) CONSLIBS="$CONSLIBS -lpam"], [LIBS="$LIBS -ldl" @@ -524,6 +557,7 @@ AC_ARG_WITH(pam, AC_MSG_CHECKING(for PAM library -lpam with -ldl) AC_TRY_LINK_FUNC([pam_end], [AC_MSG_RESULT(yes) + cons_with_pam="YES" AC_DEFINE(HAVE_PAM) CONSLIBS="$CONSLIBS -lpam -ldl"], [AC_MSG_RESULT(no)])])],) @@ -566,3 +600,16 @@ dnl ### Create output files. ####################################### AC_CONFIG_FILES([Makefile conserver/Makefile conserver.cf/Makefile console/Makefile autologin/Makefile contrib/chat/Makefile]) AC_CONFIG_FILES([conserver/conserver.rc], [chmod +x conserver/conserver.rc]) AC_OUTPUT + +[ +echo "==============================================================" +echo " Feature Summary" +echo "" +echo " Unix domain sockets (--with-uds) : $cons_with_uds" +echo " TCP wrappers (--with-libwrap): $cons_with_libwrap" +echo " OpenSSL (--with-openssl): $cons_with_openssl" +echo " dmalloc (--with-dmalloc): $cons_with_dmalloc" +echo " PAM support (--with-pam) : $cons_with_pam" +echo "" +echo "==============================================================" +] diff --git a/conserver.cf/conserver.cf.man b/conserver.cf/conserver.cf.man index bcdd8b8..2090132 100644 --- a/conserver.cf/conserver.cf.man +++ b/conserver.cf/conserver.cf.man @@ -1,5 +1,5 @@ .\" $Id: conserver.cf.man,v 1.63 2004/05/07 03:42:51 bryan Exp $ -.TH CONSERVER.CF 5 "2004/05/07" "conserver-8.1.5" "conserver" +.TH CONSERVER.CF 5 "2004/05/07" "conserver-8.1.6" "conserver" .SH NAME conserver.cf \- console configuration file for .BR conserver (8) diff --git a/conserver.cf/conserver.passwd.man b/conserver.cf/conserver.passwd.man index a7d9554..ee294b1 100644 --- a/conserver.cf/conserver.passwd.man +++ b/conserver.cf/conserver.passwd.man @@ -1,5 +1,5 @@ .\" $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.5" "conserver" +.TH CONSERVER.PASSWD 5 "2004/01/08" "conserver-8.1.6" "conserver" .SH NAME conserver.passwd \- user access information for .BR conserver (8) diff --git a/conserver.html b/conserver.html index 6694a58..f6e0d60 100644 --- a/conserver.html +++ b/conserver.html @@ -181,11 +181,11 @@

Downloading

-

The current version, released on May 7, 2004, is 8.1.5.tar.gz. You can get it via +

The current version, released on May 25, 2004, is 8.1.6.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/access.c b/conserver/access.c index f4e5c72..d7d3fd9 100644 --- a/conserver/access.c +++ b/conserver/access.c @@ -1,5 +1,5 @@ /* - * $Id: access.c,v 5.71 2003/11/20 13:56:38 bryan Exp $ + * $Id: access.c,v 5.73 2004/05/23 16:44:25 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -171,7 +171,8 @@ AccType(addr, peername) hname = he->h_aliases[a++]) { if ((revNames[a] = StrDup(hname)) == (char *)0) break; - CONDDEBUG((1,"AccType(): revNames[%d]='%s'", a, hname)); + CONDDEBUG((1, "AccType(): revNames[%d]='%s'", a, + hname)); } } } @@ -280,11 +281,26 @@ SetDefAccess(pAddr, pHost) char *pHost; #endif { - char *pcDomain; - char *addr; ACCESS *a; + while (pACList != (ACCESS *)0) { + a = pACList->pACnext; + DestroyAccessList(pACList); + pACList = a; + } + +#if USE_UNIX_DOMAIN_SOCKETS + if ((pACList = (ACCESS *)calloc(1, sizeof(ACCESS))) == (ACCESS *)0) + OutOfMem(); + if ((pACList->pcwho = StrDup("127.0.0.1")) == (char *)0) + OutOfMem(); + pACList->ctrust = 'a'; + CONDDEBUG((1, "SetDefAccess(): trust=%c, who=%s", pACList->ctrust, + pACList->pcwho)); +#else while (pAddr->s_addr != (in_addr_t) 0) { + char *addr; + addr = inet_ntoa(*pAddr); if ((a = (ACCESS *)calloc(1, sizeof(ACCESS))) == (ACCESS *)0) OutOfMem(); @@ -298,21 +314,7 @@ SetDefAccess(pAddr, pHost) pACList->pcwho)); pAddr++; } - - if ((char *)0 == (pcDomain = strchr(pHost, '.'))) - return; - ++pcDomain; - - if ((a = (ACCESS *)calloc(1, sizeof(ACCESS))) == (ACCESS *)0) - OutOfMem(); - if ((a->pcwho = StrDup(pcDomain)) == (char *)0) - OutOfMem(); - a->ctrust = 'a'; - a->pACnext = pACList; - pACList = a; - - CONDDEBUG((1, "SetDefAccess(): trust=%c, who=%s", pACList->ctrust, - pACList->pcwho)); +#endif } void diff --git a/conserver/consent.h b/conserver/consent.h index ffe7b42..1c90bb5 100644 --- a/conserver/consent.h +++ b/conserver/consent.h @@ -1,5 +1,5 @@ /* - * $Id: consent.h,v 5.56 2004/02/20 14:58:14 bryan Exp $ + * $Id: consent.h,v 5.57 2004/05/21 04:38:02 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -96,7 +96,7 @@ typedef struct consent { /* console information */ unsigned short port; /* port number | portinc * port */ unsigned short portbase; /* port base */ unsigned short portinc; /* port increment */ - unsigned short raw; /* raw or telnet protocol? */ + FLAG 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 3f4566b..fca4ad3 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.46 2004/04/13 18:19:26 bryan Exp $ -.TH CONSERVER 8 "2004/04/13" "conserver-8.1.5" "conserver" +.\" $Id: conserver.man,v 1.47 2004/05/21 04:15:17 bryan Exp $ +.TH CONSERVER 8 "2004/05/21" "conserver-8.1.6" "conserver" .SH NAME conserver \- console server daemon .SH SYNOPSIS @@ -297,8 +297,9 @@ However, if was used to enable Unix domain sockets for client/server communication, this points conserver to the directory where it should store the sockets. The default -.IR master -directory, ``/tmp/conserver'', +.I master +directory +.RB (`` /tmp/conserver '') may be changed at compile time using the .B --with-uds option. @@ -454,7 +455,7 @@ The following default file locations may be overridden at compile time or by the command-line options described above. Run .B conserver \-V -(with no other options) to see the defaults set at compile time. +to see the defaults set at compile time. .PP .PD 0 .TP 25 diff --git a/conserver/convert.c b/conserver/convert.c index 2e6e041..ae275d7 100644 --- a/conserver/convert.c +++ b/conserver/convert.c @@ -1,5 +1,5 @@ /* - * $Id: convert.c,v 1.8 2003/11/20 13:56:38 bryan Exp $ + * $Id: convert.c,v 1.9 2004/05/21 04:15:17 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -42,6 +42,10 @@ #include +SECTION sections[] = { + {(char *)0, (void *)0, (void *)0, (void *)0, (void *)0} +}; + void DestroyDataStructures() { @@ -139,7 +143,7 @@ ReadLine2(fp, save, iLine) if (!peek && (ret == (char *)0)) { (*iLine)++; wholeline = BuildString(bufstr->string, wholestr); - if (wholeline[0] == '\000') + if (wholeline != (char *)0 && wholeline[0] == '\000') wholeline = (char *)0; } diff --git a/conserver/cutil.c b/conserver/cutil.c index 34609f3..dc4d59f 100644 --- a/conserver/cutil.c +++ b/conserver/cutil.c @@ -1,5 +1,5 @@ /* - * $Id: cutil.c,v 1.116 2004/03/19 05:23:21 bryan Exp $ + * $Id: cutil.c,v 1.118 2004/05/25 00:38:15 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -10,6 +10,10 @@ #include +#include +#if HAVE_SYS_SOCKIO_H +# include +#endif #if HAVE_OPENSSL #include #endif @@ -29,6 +33,7 @@ fd_set winit; int maxfd = 0; int debugLineNo = 0; char *debugFileName = (char *)0; +int isMaster = 1; /* in the routines below (the init code) we can bomb if malloc fails (ksb) */ @@ -2122,6 +2127,189 @@ PruneSpace(string) return string; } +/* fills the myAddrs array with host interface addresses */ +void +#if PROTOTYPES +ProbeInterfaces(in_addr_t bindAddr) +#else +ProbeInterfaces(bindAddr) + in_addr_t bindAddr; +#endif +{ +#ifdef SIOCGIFCONF + struct ifconf ifc; + struct ifreq *ifr; +#ifdef SIOCGIFFLAGS + struct ifreq ifrcopy; +#endif + int sock; + int r = 0, m = 0; + int bufsize = 2048; + int count = 0; + + /* if we use -M, just fill the array with that interface */ + if (bindAddr != INADDR_ANY) { + myAddrs = (struct in_addr *)calloc(2, sizeof(struct in_addr)); + if (myAddrs == (struct in_addr *)0) + OutOfMem(); +#if HAVE_MEMCPY + memcpy(&(myAddrs[0].s_addr), &bindAddr, sizeof(in_addr_t)); +#else + bcopy(&bindAddr, &(myAddrs[0].s_addr), sizeof(in_addr_t)); +#endif + Verbose("interface address %s (-M option)", inet_ntoa(myAddrs[0])); + return; + } + + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + Error("ProbeInterfaces(): socket(): %s", strerror(errno)); + Bye(EX_OSERR); + } + + while (bufsize) { + ifc.ifc_len = bufsize; + ifc.ifc_req = (struct ifreq *)malloc(ifc.ifc_len); + if (ifc.ifc_req == (struct ifreq *)0) + OutOfMem(); + if (ioctl(sock, SIOCGIFCONF, &ifc) != 0) { + free(ifc.ifc_req); + close(sock); + Error("ProbeInterfaces(): ioctl(SIOCGIFCONF): %s", + strerror(errno)); + Bye(EX_OSERR); + } + /* if the return size plus a 512 byte "buffer zone" is less than + * the buffer we passed in (bufsize), we're done. otherwise + * allocate a bigger buffer and try again. with a too-small + * buffer, some implementations (freebsd) will fill the buffer + * best it can (leaving a gap - returning <=bufsize) and others + * (linux) will return a buffer length the same size as passed + * in (==bufsize). so, we'll assume a 512 byte gap would have + * been big enough to put one more record and as long as we have + * that "buffer zone", we should have all the interfaces. + */ + if (ifc.ifc_len + 512 < bufsize) + break; + free(ifc.ifc_req); + bufsize += 2048; + } + + /* this is probably way overkill, but better to kill a few bytes + * than loop through looking for valid interfaces that are up + * twice, huh? + */ + count = ifc.ifc_len / sizeof(*ifr); + CONDDEBUG((1, "ProbeInterfaces(): ifc_len==%d max_count==%d", + ifc.ifc_len, count)); + + /* set up myAddrs array */ + if (myAddrs != (struct in_addr *)0) + free(myAddrs); + myAddrs = (struct in_addr *)0; + if (count == 0) { + free(ifc.ifc_req); + close(sock); + return; + } + myAddrs = (struct in_addr *)calloc(count + 1, sizeof(struct in_addr)); + if (myAddrs == (struct in_addr *)0) + OutOfMem(); + + for (m = r = 0; r < ifc.ifc_len;) { + struct sockaddr *sa; + ifr = (struct ifreq *)&ifc.ifc_buf[r]; + sa = (struct sockaddr *)&ifr->ifr_addr; + /* don't use less than a ifreq sized chunk */ + if ((ifc.ifc_len - r) < sizeof(*ifr)) + break; +#ifdef HAVE_SA_LEN + if (sa->sa_len > sizeof(ifr->ifr_addr)) + r += sizeof(ifr->ifr_name) + sa->sa_len; + else +#endif + r += sizeof(*ifr); + + if (sa->sa_family == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in *)sa; +#ifdef SIOCGIFFLAGS + /* make sure the interface is up */ + ifrcopy = *ifr; + if ((ioctl(sock, SIOCGIFFLAGS, &ifrcopy) == 0) && + ((ifrcopy.ifr_flags & IFF_UP) == 0)) + continue; +#endif + CONDDEBUG((1, "ProbeInterfaces(): name=%s addr=%s", + ifr->ifr_name, inet_ntoa(sin->sin_addr))); +#if HAVE_MEMCPY + memcpy(&myAddrs[m], &(sin->sin_addr), sizeof(struct in_addr)); +#else + bcopy(&(sin->sin_addr), &myAddrs[m], sizeof(struct in_addr)); +#endif + Verbose("interface address %s (%s)", inet_ntoa(myAddrs[m]), + ifr->ifr_name); + m++; + } + } + if (m == 0) { + free(myAddrs); + myAddrs = (struct in_addr *)0; + } + close(sock); + free(ifc.ifc_req); +#else /* use the hostname like the old code did (but use all addresses!) */ + int count; + struct hostent *he; + + /* if we use -M, just fill the array with that interface */ + if (bindAddr != INADDR_ANY) { + myAddrs = (struct in_addr *)calloc(2, sizeof(struct in_addr)); + if (myAddrs == (struct in_addr *)0) + OutOfMem(); +#if HAVE_MEMCPY + memcpy(&(myAddrs[0].s_addr), &bindAddr, sizeof(in_addr_t)); +#else + bcopy(&bindAddr, &(myAddrs[0].s_addr), sizeof(in_addr_t)); +#endif + Verbose("interface address %s (-M option)", inet_ntoa(myAddrs[0])); + return; + } + + Verbose("using hostname for interface addresses"); + if ((struct hostent *)0 == (he = gethostbyname(myHostname))) { + Error("ProbeInterfaces(): gethostbyname(%s): %s", myHostname, + hstrerror(h_errno)); + return; + } + if (4 != he->h_length || AF_INET != he->h_addrtype) { + Error + ("ProbeInterfaces(): gethostbyname(%s): wrong address size (4 != %d) or address family (%d != %d)", + myHostname, he->h_length, AF_INET, he->h_addrtype); + return; + } + + for (count = 0; he->h_addr_list[count] != (char *)0; count++); + if (myAddrs != (struct in_addr *)0) + free(myAddrs); + myAddrs = (struct in_addr *)0; + if (count == 0) + return; + myAddrs = (struct in_addr *)calloc(count + 1, sizeof(struct in_addr)); + if (myAddrs == (struct in_addr *)0) + OutOfMem(); + for (count--; count >= 0; count--) { +#if HAVE_MEMCPY + memcpy(&(myAddrs[count].s_addr), he->h_addr_list[count], + he->h_length); +#else + bcopy(he->h_addr_list[count], &(myAddrs[count].s_addr), + he->h_length); +#endif + Verbose("interface address %s (hostname address)", + inet_ntoa(myAddrs[count])); + } +#endif +} + int #if PROTOTYPES IsMe(char *id) @@ -2388,3 +2576,725 @@ ParseIACBuf(cfp, msg, len) } return l; } + +/* the format of the file should be as follows + * + *
[section name] { + * [item value]; + * . + * . + * } + * + * whitespace gets retained in [section name], and [item value] + * values. for example, + * + * users bryan todd ; + * + * will give users the value of 'bryan todd'. the leading and + * trailing whitespace is nuked, but the middle stuff isn't. + * + * a little note about the 'state' var... + * START = before
+ * NAME = before [section name] + * LEFTB = before left curly brace + * KEY = before + * VALUE = before [item value] + * SEMI = before semi-colon + */ + +typedef enum states { + START, + NAME, + LEFTB, + KEY, + VALUE, + SEMI +} STATES; + +typedef enum tokens { + DONE, + LEFTBRACE, + RIGHTBRACE, + SEMICOLON, + WORD, + INCLUDE +} TOKEN; + +int line = 1; /* current line number */ +char *file = (char *)0; + +TOKEN +#if PROTOTYPES +GetWord(FILE *fp, int *line, short spaceok, STRING *word) +#else +GetWord(fp, line, spaceok, word) + FILE *fp; + int *line; + short spaceok; + STRING *word; +#endif +{ + int c; + short backslash = 0; + short quote = 0; + short comment = 0; + short sawQuote = 0; + short quotedBackslash = 0; + char *include = "include"; + short checkInc = -1; + /* checkInc == -3, saw #include + * == -2, saw nothin' + * == -1, saw \n or start of file + * == 0, saw "\n#" + */ + + BuildString((char *)0, word); + while ((c = fgetc(fp)) != EOF) { + if (c == '\n') { + (*line)++; + if (checkInc == -2) + checkInc = -1; + } + if (comment) { + if (c == '\n') + comment = 0; + if (checkInc >= 0) { + if (include[checkInc] == '\000') { + if (isspace(c)) + checkInc = -3; + } else if (c == include[checkInc]) + checkInc++; + else + checkInc = -2; + } else if (checkInc == -3) { + static STRING *fname = (STRING *)0; + if (fname == (STRING *)0) + fname = AllocString(); + if (fname->used != 0 || !isspace(c)) { + if (c == '\n') { + if (fname->used > 0) { + while (fname->used > 1 && isspace((int) + (fname-> + string + [fname-> + used - + 2]))) + fname->used--; + if (fname->used > 0) + fname->string[fname->used - 1] = '\000'; + } + checkInc = -2; + if (fname->used > 0) { + BuildString((char *)0, word); + BuildString(fname->string, word); + BuildString((char *)0, fname); + return INCLUDE; + } + } else + BuildStringChar(c, fname); + } + } + continue; + } + if (backslash) { + BuildStringChar(c, word); + backslash = 0; + continue; + } + if (quote) { + if (c == '"') { + if (quotedBackslash) { + BuildStringChar(c, word); + quotedBackslash = 0; + } else + quote = 0; + } else { + if (quotedBackslash) { + BuildStringChar('\\', word); + quotedBackslash = 0; + } + if (c == '\\') + quotedBackslash = 1; + else + BuildStringChar(c, word); + } + continue; + } + if (c == '\\') { + backslash = 1; + } else if (c == '#') { + comment = 1; + if (checkInc == -1) + checkInc = 0; + } else if (c == '"') { + quote = 1; + sawQuote = 1; + } else if (isspace(c)) { + if (word->used <= 1) + continue; + if (spaceok) { + BuildStringChar(c, word); + continue; + } + gotword: + while (word->used > 1 && + isspace((int)(word->string[word->used - 2]))) + word->used--; + if (word->used > 0) + word->string[word->used - 1] = '\000'; + return WORD; + } else if (c == '{') { + if (word->used <= 1 && !sawQuote) { + BuildStringChar(c, word); + return LEFTBRACE; + } else { + ungetc(c, fp); + goto gotword; + } + } else if (c == '}') { + if (word->used <= 1 && !sawQuote) { + BuildStringChar(c, word); + return RIGHTBRACE; + } else { + ungetc(c, fp); + goto gotword; + } + } else if (c == ';') { + if (word->used <= 1 && !sawQuote) { + BuildStringChar(c, word); + return SEMICOLON; + } else { + ungetc(c, fp); + goto gotword; + } + } else { + BuildStringChar(c, word); + } + } + /* this should only happen in rare cases */ + if (quotedBackslash) { + BuildStringChar('\\', word); + quotedBackslash = 0; + } + /* if we saw "valid" data, it's a word */ + if (word->used > 1 || sawQuote) + goto gotword; + return DONE; +} + +void +#if PROTOTYPES +ParseFile(char *filename, FILE *fp, int level) +#else +ParseFile(filename, fp, level) + char *filename; + FILE *fp; + int level; +#endif +{ + /* things that should be used between recursions */ + static STATES state = START; + static STRING *word = (STRING *)0; + static short spaceok = 0; + static int secIndex = 0; + static int keyIndex = 0; + + /* other stuff that's local to each recursion */ + char *p; + TOKEN token = DONE; + int nextline = 1; /* "next" line number */ + + if (level >= 10) { + if (isMaster) + Error("ParseFile(): nesting too deep, not parsing `%s'", + filename); + return; + } + + /* set some globals */ + line = 1; + file = filename; + + /* if we're parsing the base file, set static vars */ + if (level == 0) { + state = START; + spaceok = 0; + secIndex = 0; + keyIndex = 0; + } + + /* initialize local things */ + if (word == (STRING *)0) + word = AllocString(); + + while ((token = GetWord(fp, &nextline, spaceok, word)) != DONE) { + if (token == INCLUDE) { + FILE *lfp; + if ((FILE *)0 == (lfp = fopen(word->string, "r"))) { + if (isMaster) + Error("ParseFile(): fopen(%s): %s", word->string, + strerror(errno)); + } else { + char *fname; + /* word gets destroyed, so save the name */ + fname = StrDup(word->string); + ParseFile(fname, lfp, level + 1); + fclose(lfp); + free(fname); + } + } else { + switch (state) { + case START: + switch (token) { + case WORD: + for (secIndex = 0; + (p = sections[secIndex].id) != (char *)0; + secIndex++) { + if (strcasecmp(word->string, p) == 0) { + CONDDEBUG((1, + "ReadCfg(): got keyword '%s' [%s:%d]", + word->string, file, line)); + state = NAME; + break; + } + } + if (state == START) { + if (isMaster) + Error("invalid keyword '%s' [%s:%d]", + word->string, file, line); + } + break; + case LEFTBRACE: + case RIGHTBRACE: + case SEMICOLON: + if (isMaster) + Error("invalid token '%s' [%s:%d]", + word->string, file, line); + break; + case DONE: /* just shutting up gcc */ + case INCLUDE: /* just shutting up gcc */ + break; + } + break; + case NAME: + switch (token) { + case WORD: + (*sections[secIndex].begin) (word->string); + state = LEFTB; + break; + case RIGHTBRACE: + if (isMaster) + Error("premature token '%s' [%s:%d]", + word->string, file, line); + state = START; + break; + case LEFTBRACE: + case SEMICOLON: + if (isMaster) + Error("invalid token '%s' [%s:%d]", + word->string, file, line); + break; + case DONE: /* just shutting up gcc */ + case INCLUDE: /* just shutting up gcc */ + break; + } + break; + case LEFTB: + switch (token) { + case LEFTBRACE: + state = KEY; + break; + case RIGHTBRACE: + if (isMaster) + Error("premature token '%s' [%s:%d]", + word->string, file, line); + (*sections[secIndex].abort) (); + state = START; + break; + case SEMICOLON: + if (isMaster) + Error("invalid token '%s' [%s:%d]", + word->string, file, line); + break; + case WORD: + if (isMaster) + Error("invalid word '%s' [%s:%d]", + word->string, file, line); + break; + case DONE: /* just shutting up gcc */ + case INCLUDE: /* just shutting up gcc */ + break; + } + break; + case KEY: + switch (token) { + case WORD: + for (keyIndex = 0; + (p = + sections[secIndex].items[keyIndex].id) != + (char *)0; keyIndex++) { + if (strcasecmp(word->string, p) == 0) { + CONDDEBUG((1, + "got keyword '%s' [%s:%d]", + word->string, file, line)); + state = VALUE; + break; + } + } + if (state == KEY) { + if (isMaster) + Error("invalid keyword '%s' [%s:%d]", + word->string, file, line); + } + break; + case RIGHTBRACE: + (*sections[secIndex].end) (); + state = START; + break; + case LEFTBRACE: + if (isMaster) + Error("invalid token '%s' [%s:%d]", + word->string, file, line); + break; + case SEMICOLON: + if (isMaster) + Error("premature token '%s' [%s:%d]", + word->string, file, line); + case DONE: /* just shutting up gcc */ + case INCLUDE: /* just shutting up gcc */ + break; + } + break; + case VALUE: + switch (token) { + case WORD: + (*sections[secIndex].items[keyIndex]. + reg) (word->string); + state = SEMI; + break; + case SEMICOLON: + if (isMaster) + Error("invalid token '%s' [%s:%d]", + word->string, file, line); + state = KEY; + break; + case RIGHTBRACE: + if (isMaster) + Error("premature token '%s' [%s:%d]", + word->string, file, line); + (*sections[secIndex].abort) (); + state = START; + break; + case LEFTBRACE: + if (isMaster) + Error("invalid token '%s' [%s:%d]", + word->string, file, line); + break; + case DONE: /* just shutting up gcc */ + case INCLUDE: /* just shutting up gcc */ + break; + } + break; + case SEMI: + switch (token) { + case SEMICOLON: + state = KEY; + break; + case RIGHTBRACE: + if (isMaster) + Error("premature token '%s' [%s:%d]", + word->string, file, line); + (*sections[secIndex].abort) (); + state = START; + break; + case LEFTBRACE: + if (isMaster) + Error("invalid token '%s' [%s:%d]", + word->string, file, line); + break; + case WORD: + if (isMaster) + Error("invalid word '%s' [%s:%d]", + word->string, file, line); + break; + case DONE: /* just shutting up gcc */ + case INCLUDE: /* just shutting up gcc */ + break; + } + break; + } + switch (state) { + case NAME: + case VALUE: + spaceok = 1; + break; + case KEY: + case LEFTB: + case START: + case SEMI: + spaceok = 0; + break; + } + } + line = nextline; + } + + if (level == 0) { + int i; + + /* check for proper ending of file and do any cleanup */ + switch (state) { + case START: + break; + case KEY: + case LEFTB: + case VALUE: + case SEMI: + (*sections[secIndex].abort) (); + /* fall through */ + case NAME: + if (isMaster) + Error("premature EOF seen [%s:%d]", file, line); + break; + } + + /* now clean up all the temporary space used */ + for (i = 0; sections[i].id != (char *)0; i++) { + (*sections[i].destroy) (); + } + } +} + +void +#if PROTOTYPES +ProcessSubst(SUBST * s, char **repl, char **str, char *name, char *id) +#else +ProcessSubst(s, repl, str, name, id) + SUBST *s; + char **repl; + char **str; + char *name; + char *id; +#endif +{ + /* + * (CONSENT *pCE) and (char **repl) are used when a replacement is to + * actually happen...repl is the string to munch, pCE holds the data. + * + * (char **str) is used to store a copy of (char *id), if it passes + * the format check. + * + * the idea is that this is first called when the config file is read, + * putting the result in (char **str). then we call it again, near + * the end, permuting (char **repl) with values from (CONSENT *pCE) with + * the saved string now coming in as (char *id). got it? + * + * you could pass all arguments in...then both types of actions occur. + */ + char *p; + char *repfmt[255]; + unsigned short repnum; + int i; + + enum repstate { + REP_BEGIN, + REP_LTR, + REP_EQ, + REP_INT, + REP_END + } state; + + if (str != (char **)0) { + if (*str != (char *)0) { + free(*str); + *str = (char *)0; + } + } + + if ((id == (char *)0) || (*id == '\000')) + return; + + repnum = 0; + state = REP_BEGIN; + + for (i = 0; i < 256; i++) + repfmt[i] = (char *)0; + + for (p = id; *p != '\000'; p++) { + switch (state) { + case REP_BEGIN: + /* must be printable */ + if (*p == ',' || !isgraph((int)(*p))) + goto subst_err; + + /* make sure we haven't seen this replacement char yet */ + repnum = (unsigned short)(*p); + if (repfmt[repnum] != (char *)0) { + if (isMaster) + Error + ("substitution characters of `%s' option are the same [%s:%d]", + name, file, line); + return; + } + state = REP_LTR; + break; + case REP_LTR: + if (*p != '=') + goto subst_err; + state = REP_EQ; + break; + case REP_EQ: + repfmt[repnum] = p; + if (s->tokens[(unsigned)(*(repfmt[repnum]))] != ISNOTHING) + state = REP_INT; + else + goto subst_err; + break; + case REP_INT: + if (*p == 'd' || *p == 'x' || *p == 'X') { + if (s->tokens[(unsigned)(*(repfmt[repnum]))] != + ISNUMBER) + goto subst_err; + state = REP_END; + } else if (*p == 's') { + if (s->tokens[(unsigned)(*(repfmt[repnum]))] != + ISSTRING) + goto subst_err; + state = REP_END; + } else if (!isdigit((int)(*p))) + goto subst_err; + break; + case REP_END: + if (*p != ',') + goto subst_err; + state = REP_BEGIN; + break; + } + } + + if (state != REP_END) { + subst_err: + if (isMaster) + Error + ("invalid `%s' specification `%s' (char #%d: `%c') [%s:%d]", + name, id, (p - id) + 1, *p, file, line); + return; + } + + if (str != (char **)0) { + if ((*str = StrDup(id)) == (char *)0) + OutOfMem(); + } + + if (s != (SUBST *) 0 && repl != (char **)0) { + static STRING *result = (STRING *)0; + + if (result == (STRING *)0) + result = AllocString(); + BuildString((char *)0, result); + + for (p = *repl; *p != '\000'; p++) { + if (repfmt[(unsigned short)(*p)] != (char *)0) { + char *r = repfmt[(unsigned short)(*p)]; + int plen = 0; + char *c = (char *)0; + int o = 0; + + if (s->tokens[(unsigned)(*r)] == ISSTRING) { + /* check the pattern for a length */ + if (isdigit((int)(*(r + 1)))) + plen = atoi(r + 1); + + /* this should never return zero, but just in case */ + if ((*s->callback) (*r, &c, (int *)0) == 0) + c = ""; + plen -= strlen(c); + + /* pad it out, if necessary */ + for (i = 0; i < plen; i++) + BuildStringChar(' ', result); + + /* throw in the string */ + BuildString(c, result); + } else { + int i = 0; + unsigned short port = 0; + unsigned short base = 0; + int padzero = 0; + static STRING *num = (STRING *)0; + + if (num == (STRING *)0) + num = AllocString(); + BuildString((char *)0, num); + + /* this should never return zero, but just in case */ + if ((*s->callback) (*r, (char **)0, &i) == 0) + port = 0; + else + port = (unsigned short)i; + + /* check the pattern for a length and padding */ + for (c = r + 1; *c != '\000'; c++) + if (!isdigit((int)(*c))) + break; + if (c != r + 1) { + plen = atoi(r + 1); + padzero = (r[1] == '0'); + } + + /* check for base */ + switch (*c) { + case 'd': + base = 10; + break; + case 'x': + case 'X': + base = 16; + break; + default: + return; + } + while (port >= base) { + if (port % base >= 10) + BuildStringChar((port % base) - 10 + + (*c == 'x' ? 'a' : 'A'), num); + else + BuildStringChar((port % base) + '0', num); + port /= base; + } + if (port >= 10) + BuildStringChar(port - 10 + + (*c == 'x' ? 'a' : 'A'), num); + else + BuildStringChar(port + '0', num); + + /* if we're supposed to be a certain length, pad it */ + while (num->used - 1 < plen) { + if (padzero == 0) + BuildStringChar(' ', num); + else + BuildStringChar('0', num); + } + + /* reverse the text to put it in forward order */ + o = num->used - 1; + for (i = 0; i < o / 2; i++) { + char temp; + + temp = num->string[i]; + num->string[i] + = num->string[o - i - 1]; + num->string[o - i - 1] = temp; + } + BuildStringN(num->string, o, result); + } + } else + BuildStringChar(*p, result); + } + free(*repl); + if ((*repl = StrDup(result->string)) == (char *)0) + OutOfMem(); + } + + return; +} diff --git a/conserver/cutil.h b/conserver/cutil.h index 93c060e..a50d304 100644 --- a/conserver/cutil.h +++ b/conserver/cutil.h @@ -1,5 +1,5 @@ /* - * $Id: cutil.h,v 1.61 2004/03/10 02:55:45 bryan Exp $ + * $Id: cutil.h,v 1.63 2004/05/25 00:38:15 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -89,6 +89,37 @@ typedef struct consFile { #endif } CONSFILE; +typedef struct item { + char *id; + void (*reg) PARAMS((char *)); +} ITEM; + +typedef struct section { + char *id; + void (*begin) PARAMS((char *)); + void (*end) PARAMS((void)); + void (*abort) PARAMS((void)); + void (*destroy) PARAMS((void)); + ITEM *items; +} SECTION; + +typedef enum substToken { + ISNOTHING = 0, + ISNUMBER, + ISSTRING +} SUBSTTOKEN; + +typedef struct subst { + SUBSTTOKEN tokens[255]; + /* data for callback function + */ + void *data; + /* function to retrieve a value (as a char* or int or both) for + * a substitution + */ + int (*callback) PARAMS((char, char **, int *)); +} SUBST; + extern int isMultiProc, fDebug, fVerbose, fErrorPrinted; extern char *progname; extern pid_t thepid; @@ -100,6 +131,10 @@ extern fd_set winit; extern int maxfd; extern int debugLineNo; extern char *debugFileName; +extern int line; /* used by ParseFile */ +extern char *file; /* used by ParseFile */ +extern SECTION sections[]; /* used by ParseFile */ +extern int isMaster; extern const char *StrTime PARAMS((time_t *)); extern void Debug PARAMS((int, char *, ...)); @@ -157,6 +192,10 @@ 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)); +extern void ParseFile PARAMS((char *, FILE *, int)); +extern void ProbeInterfaces PARAMS((in_addr_t)); +extern void ProcessSubst +PARAMS((SUBST *, char **, char **, char *, 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 b509f5e..cf7a910 100644 --- a/conserver/group.c +++ b/conserver/group.c @@ -1,5 +1,5 @@ /* - * $Id: group.c,v 5.298 2004/05/07 15:39:51 bryan Exp $ + * $Id: group.c,v 5.301 2004/05/25 00:38:15 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -1610,8 +1610,8 @@ PutConsole(pCEServing, c, quote) * quote == 2, telnet - processed by telnet protocol * if console != telnet, 1 == 2 */ - if (quote == 1 && pCEServing->type == HOST && !pCEServing->raw && - c == IAC) { + if (quote == 1 && pCEServing->type == HOST && + pCEServing->raw != FLAGTRUE && c == IAC) { BuildStringChar((char)c, pCEServing->wbuf); if (pCEServing->wbufIAC == 0) pCEServing->wbufIAC = pCEServing->wbuf->used; @@ -1685,11 +1685,11 @@ ExpandString(str, pCE, breaknum) ++octs; oct = oct * 8 + (s - '0'); continue; - } else if (s == 'd' && pCE != (CONSENT *)0) { + } else if (s == 'd') { PutConsole(pCE, IAC, 0); PutConsole(pCE, '0' + breaknum, 0); continue; - } else if (s == 'z' && pCE != (CONSENT *)0) { + } else if (s == 'z') { PutConsole(pCE, IAC, 0); PutConsole(pCE, BREAK, 0); continue; @@ -2148,7 +2148,7 @@ CommandInfo(pGE, pCLServing, pCEServing, tyme) case HOST: FilePrint(pCLServing->fd, FLAGTRUE, "!:%s,%hu,%s", pCE->host, pCE->netport, - (pCE->raw ? "raw" : "telnet")); + (pCE->raw == FLAGTRUE ? "raw" : "telnet")); break; case DEVICE: FilePrint(pCLServing->fd, FLAGTRUE, "/:%s,%s%c", @@ -2407,7 +2407,7 @@ DoConsoleRead(pCEServing) CONDDEBUG((1, "DoConsoleRead(): read %d bytes from fd %d", nr, cofile)); - if (pCEServing->type == HOST && !pCEServing->raw) { + if (pCEServing->type == HOST && pCEServing->raw != FLAGTRUE) { /* Do a little Telnet Protocol interpretation * state = 0: normal * = 1: Saw a IAC char @@ -3933,11 +3933,19 @@ FlushConsole(pCEServing) } if (pCEServing->wbuf->used > 1) { + char *iac = StringChar(pCEServing->wbuf, 0, (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) + 2; CONDDEBUG((1, "Kiddie(): watching writability for fd %d 'cause we have buffered data", FileFDNum(pCEServing->cofile))); FD_SET(FileFDNum(pCEServing->cofile), &winit); } else { + pCEServing->wbufIAC = 0; if (FileBufEmpty(pCEServing->cofile)) { CONDDEBUG((1, "Kiddie(): removing writability for fd %d 'cause we don't have buffered data", diff --git a/conserver/group.h b/conserver/group.h index 7de927b..37d2fa5 100644 --- a/conserver/group.h +++ b/conserver/group.h @@ -1,5 +1,5 @@ /* - * $Id: group.h,v 5.45 2004/05/07 03:42:49 bryan Exp $ + * $Id: group.h,v 5.46 2004/05/25 00:38:15 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -80,7 +80,6 @@ PARAMS((GRPENT *, CONSCLIENT *, char *, FLAG)); extern int ClientAccess PARAMS((CONSENT *, char *)); extern void DestroyClient PARAMS((CONSCLIENT *)); extern int CheckPasswd PARAMS((CONSCLIENT *, char *)); -extern void ExpandString PARAMS((char *, CONSENT *, short)); extern void DeUtmp PARAMS((GRPENT *, int)); #if HAVE_OPENSSL extern int AttemptSSL PARAMS((CONSCLIENT *)); diff --git a/conserver/main.c b/conserver/main.c index 122ce23..72624dc 100644 --- a/conserver/main.c +++ b/conserver/main.c @@ -1,5 +1,5 @@ /* - * $Id: main.c,v 5.180 2004/05/07 03:42:49 bryan Exp $ + * $Id: main.c,v 5.185 2004/05/25 23:03:01 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -40,11 +40,7 @@ #include #include -#include #include -#if HAVE_SYS_SOCKIO_H -# include -#endif #if HAVE_OPENSSL # include #endif @@ -54,9 +50,8 @@ int fAll = 0, fNoinit = 0, fVersion = 0, fStrip = 0, fReopen = 0, fNoautoreup = 0, fSyntaxOnly = 0; char *pcConfig = CONFIGFILE; -int isMaster = 1; int cMaxMemb = MAXMEMB; -in_addr_t bindAddr; +in_addr_t bindAddr = INADDR_ANY; unsigned short bindPort; unsigned short bindBasePort; static STRING *startedMsg = (STRING *)0; @@ -603,6 +598,9 @@ Version() #endif #if TRUST_REVERSE_DNS "trustrevdns", +#endif +#if USE_UNIX_DOMAIN_SOCKETS + "uds", #endif (char *)0 }; @@ -651,10 +649,12 @@ Version() BuildStringChar('0' + DMALLOC_VERSION_MINOR, acA1); BuildStringChar('.', acA1); BuildStringChar('0' + DMALLOC_VERSION_PATCH, acA1); +#if defined(DMALLOC_VERSION_BETA) if (DMALLOC_VERSION_BETA != 0) { BuildString("-b", acA1); BuildStringChar('0' + DMALLOC_VERSION_BETA, acA1); } +#endif Msg("dmalloc version: %s", acA1->string); #endif #if HAVE_OPENSSL @@ -720,6 +720,8 @@ DestroyDataStructures() DestroyBreakList(); DestroyStrings(); DestroyUserList(); + if (substData != (SUBST *) 0) + free(substData); } void @@ -851,13 +853,13 @@ DumpDataStructures() GRPENT *pGE; CONSENT *pCE; REMOTE *pRC; - char *empty = ""; #if HAVE_DMALLOC && DMALLOC_MARK_MAIN CONDDEBUG((1, "DumpDataStructures(): dmalloc / MarkMain")); dmalloc_log_changed(dmallocMarkMain, 1, 0, 1); #endif -#define EMPTYSTR(x) x == (char *)0 ? empty : x +#define EMPTYSTR(x) x == (char *)0 ? "(null)" : x +#define FLAGSTR(x) x == FLAGTRUE ? "true" : (x == FLAGFALSE ? "false" : "unset") if (!fDebug) return; @@ -896,9 +898,9 @@ DumpDataStructures() "DumpDataStructures(): server=%s, type=HOST", EMPTYSTR(pCE->server))); CONDDEBUG((1, - "DumpDataStructures(): host=%s, raw=%hu, netport=%hu, port=%hu, telnetState=%d", - EMPTYSTR(pCE->host), pCE->raw, pCE->netport, - pCE->port, pCE->telnetState)); + "DumpDataStructures(): host=%s, raw=%s, netport=%hu, port=%hu, telnetState=%d", + EMPTYSTR(pCE->host), FLAGSTR(pCE->raw), + pCE->netport, pCE->port, pCE->telnetState)); break; case UNKNOWNTYPE: CONDDEBUG((1, @@ -920,32 +922,27 @@ DumpDataStructures() CONDDEBUG((1, "DumpDataStructures(): mark=%d, nextMark=%ld, autoReup=%hu, downHard=%s", pCE->mark, pCE->nextMark, pCE->autoReUp, - pCE->downHard == FLAGTRUE ? "true" : "false")); + FLAGSTR(pCE->downHard))); CONDDEBUG((1, "DumpDataStructures(): nolog=%d, cofile=%d, activitylog=%s, breaklog=%s", pCE->nolog, FileFDNum(pCE->cofile), - pCE->activitylog == FLAGTRUE ? "true" : "false", - pCE->breaklog == FLAGTRUE ? "true" : "false")); + FLAGSTR(pCE->activitylog), FLAGSTR(pCE->breaklog))); CONDDEBUG((1, "DumpDataStructures(): ixon=%s, ixany=%s, ixoff=%s", - pCE->ixon == FLAGTRUE ? "true" : "false", - pCE->ixany == FLAGTRUE ? "true" : "false", - pCE->ixoff == FLAGTRUE ? "true" : "false")); + FLAGSTR(pCE->ixon), FLAGSTR(pCE->ixany), + FLAGSTR(pCE->ixoff))); CONDDEBUG((1, "DumpDataStructures(): autoreinit=%s, hupcl=%s, cstopb=%s, ondemand=%s", - pCE->autoreinit == FLAGTRUE ? "true" : "false", - pCE->hupcl == FLAGTRUE ? "true" : "false", - pCE->cstopb == FLAGTRUE ? "true" : "false", - pCE->ondemand == FLAGTRUE ? "true" : "false")); + FLAGSTR(pCE->autoreinit), FLAGSTR(pCE->hupcl), + FLAGSTR(pCE->cstopb), FLAGSTR(pCE->ondemand))); #if defined(CRTSCTS) CONDDEBUG((1, "DumpDataStructures(): crtscts=%s", - pCE->crtscts == FLAGTRUE ? "true" : "false")); + FLAGSTR(pCE->crtscts))); #endif CONDDEBUG((1, "DumpDataStructures(): reinitoncc=%s, striphigh=%s, unloved=%s", - pCE->reinitoncc == FLAGTRUE ? "true" : "false", - pCE->striphigh == FLAGTRUE ? "true" : "false", - pCE->unloved == FLAGTRUE ? "true" : "false")); + FLAGSTR(pCE->reinitoncc), FLAGSTR(pCE->striphigh), + FLAGSTR(pCE->unloved))); CONDDEBUG((1, "DumpDataStructures(): initpid=%lu, initcmd=%s, initfile=%d", (unsigned long)pCE->initpid, EMPTYSTR(pCE->initcmd), @@ -983,188 +980,6 @@ DumpDataStructures() } } -/* fills the myAddrs array with host interface addresses */ -void -#if PROTOTYPES -ProbeInterfaces(void) -#else -ProbeInterfaces() -#endif -{ -#ifdef SIOCGIFCONF - struct ifconf ifc; - struct ifreq *ifr; -#ifdef SIOCGIFFLAGS - struct ifreq ifrcopy; -#endif - int sock; - int r = 0, m = 0; - int bufsize = 2048; - int count = 0; - - /* if we use -M, just fill the array with that interface */ - if (bindAddr != INADDR_ANY) { - myAddrs = (struct in_addr *)calloc(2, sizeof(struct in_addr)); - if (myAddrs == (struct in_addr *)0) - OutOfMem(); -#if HAVE_MEMCPY - memcpy(&(myAddrs[0].s_addr), &bindAddr, sizeof(in_addr_t)); -#else - bcopy(&bindAddr, &(myAddrs[0].s_addr), sizeof(in_addr_t)); -#endif - Verbose("interface address %s (-M option)", inet_ntoa(myAddrs[0])); - return; - } - - if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { - Error("ProbeInterfaces(): socket(): %s", strerror(errno)); - Bye(EX_OSERR); - } - - while (bufsize) { - ifc.ifc_len = bufsize; - ifc.ifc_req = (struct ifreq *)malloc(ifc.ifc_len); - if (ifc.ifc_req == (struct ifreq *)0) - OutOfMem(); - if (ioctl(sock, SIOCGIFCONF, &ifc) != 0) { - free(ifc.ifc_req); - close(sock); - Error("ProbeInterfaces(): ioctl(SIOCGIFCONF): %s", - strerror(errno)); - Bye(EX_OSERR); - } - /* if the return size plus a 512 byte "buffer zone" is less than - * the buffer we passed in (bufsize), we're done. otherwise - * allocate a bigger buffer and try again. with a too-small - * buffer, some implementations (freebsd) will fill the buffer - * best it can (leaving a gap - returning <=bufsize) and others - * (linux) will return a buffer length the same size as passed - * in (==bufsize). so, we'll assume a 512 byte gap would have - * been big enough to put one more record and as long as we have - * that "buffer zone", we should have all the interfaces. - */ - if (ifc.ifc_len + 512 < bufsize) - break; - free(ifc.ifc_req); - bufsize += 2048; - } - - /* this is probably way overkill, but better to kill a few bytes - * than loop through looking for valid interfaces that are up - * twice, huh? - */ - count = ifc.ifc_len / sizeof(*ifr); - CONDDEBUG((1, "ProbeInterfaces(): ifc_len==%d max_count==%d", - ifc.ifc_len, count)); - - /* set up myAddrs array */ - if (myAddrs != (struct in_addr *)0) - free(myAddrs); - myAddrs = (struct in_addr *)0; - if (count == 0) { - free(ifc.ifc_req); - close(sock); - return; - } - myAddrs = (struct in_addr *)calloc(count + 1, sizeof(struct in_addr)); - if (myAddrs == (struct in_addr *)0) - OutOfMem(); - - for (m = r = 0; r < ifc.ifc_len;) { - struct sockaddr *sa; - ifr = (struct ifreq *)&ifc.ifc_buf[r]; - sa = (struct sockaddr *)&ifr->ifr_addr; - /* don't use less than a ifreq sized chunk */ - if ((ifc.ifc_len - r) < sizeof(*ifr)) - break; -#ifdef HAVE_SA_LEN - if (sa->sa_len > sizeof(ifr->ifr_addr)) - r += sizeof(ifr->ifr_name) + sa->sa_len; - else -#endif - r += sizeof(*ifr); - - if (sa->sa_family == AF_INET) { - struct sockaddr_in *sin = (struct sockaddr_in *)sa; -#ifdef SIOCGIFFLAGS - /* make sure the interface is up */ - ifrcopy = *ifr; - if ((ioctl(sock, SIOCGIFFLAGS, &ifrcopy) == 0) && - ((ifrcopy.ifr_flags & IFF_UP) == 0)) - continue; -#endif - CONDDEBUG((1, "ProbeInterfaces(): name=%s addr=%s", - ifr->ifr_name, inet_ntoa(sin->sin_addr))); -#if HAVE_MEMCPY - memcpy(&myAddrs[m], &(sin->sin_addr), sizeof(struct in_addr)); -#else - bcopy(&(sin->sin_addr), &myAddrs[m], sizeof(struct in_addr)); -#endif - Verbose("interface address %s (%s)", inet_ntoa(myAddrs[m]), - ifr->ifr_name); - m++; - } - } - if (m == 0) { - free(myAddrs); - myAddrs = (struct in_addr *)0; - } - close(sock); - free(ifc.ifc_req); -#else /* use the hostname like the old code did (but use all addresses!) */ - int count; - struct hostent *he; - - /* if we use -M, just fill the array with that interface */ - if (bindAddr != INADDR_ANY) { - myAddrs = (struct in_addr *)calloc(2, sizeof(struct in_addr)); - if (myAddrs == (struct in_addr *)0) - OutOfMem(); -#if HAVE_MEMCPY - memcpy(&(myAddrs[0].s_addr), &bindAddr, sizeof(in_addr_t)); -#else - bcopy(&bindAddr, &(myAddrs[0].s_addr), sizeof(in_addr_t)); -#endif - Verbose("interface address %s (-M option)", inet_ntoa(myAddrs[0])); - return; - } - - Verbose("using hostname for interface addresses"); - if ((struct hostent *)0 == (he = gethostbyname(myHostname))) { - Error("ProbeInterfaces(): gethostbyname(%s): %s", myHostname, - hstrerror(h_errno)); - return; - } - if (4 != he->h_length || AF_INET != he->h_addrtype) { - Error - ("ProbeInterfaces(): gethostbyname(%s): wrong address size (4 != %d) or address family (%d != %d)", - myHostname, he->h_length, AF_INET, he->h_addrtype); - return; - } - - for (count = 0; he->h_addr_list[count] != (char *)0; count++); - if (myAddrs != (struct in_addr *)0) - free(myAddrs); - myAddrs = (struct in_addr *)0; - if (count == 0) - return; - myAddrs = (struct in_addr *)calloc(count + 1, sizeof(struct in_addr)); - if (myAddrs == (struct in_addr *)0) - OutOfMem(); - for (count--; count >= 0; count--) { -#if HAVE_MEMCPY - memcpy(&(myAddrs[count].s_addr), he->h_addr_list[count], - he->h_length); -#else - bcopy(he->h_addr_list[count], &(myAddrs[count].s_addr), - he->h_length); -#endif - Verbose("interface address %s (hostname address)", - inet_ntoa(myAddrs[count])); - } -#endif -} - /* This makes sure a directory exists and tries to create it if it * doesn't. returns 0 for success, -1 for error */ @@ -1290,9 +1105,9 @@ main(argc, argv) thepid = getpid(); if ((char *)0 == (progname = strrchr(argv[0], '/'))) { - progname = StrDup(argv[0]); + progname = argv[0]; } else { - progname = StrDup(++progname); + ++progname; } setpwent(); @@ -1354,7 +1169,7 @@ main(argc, argv) #endif break; case 'C': - pcConfig = StrDup(optarg); + pcConfig = optarg; break; case 'd': optConf->daemonmode = FLAGTRUE; @@ -1520,7 +1335,7 @@ main(argc, argv) Error("gethostname(): %s", strerror(errno)); Bye(EX_OSERR); } - ProbeInterfaces(); + ProbeInterfaces(bindAddr); /* initialize the timers */ for (i = 0; i < T_MAX; i++) diff --git a/conserver/main.h b/conserver/main.h index e4d5074..1b59a5a 100644 --- a/conserver/main.h +++ b/conserver/main.h @@ -1,5 +1,5 @@ /* - * $Id: main.h,v 5.52 2004/04/13 18:12:00 bryan Exp $ + * $Id: main.h,v 5.53 2004/05/21 04:15:17 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -44,7 +44,6 @@ extern unsigned short bindPort, bindBasePort; extern char *pcConfig; extern int cMaxMemb; extern struct sockaddr_in in_port; -extern int isMaster; extern CONFIG *optConf; extern CONFIG *config; extern CONFIG defConfig; diff --git a/conserver/readcfg.c b/conserver/readcfg.c index 0c8c9b1..92a7894 100644 --- a/conserver/readcfg.c +++ b/conserver/readcfg.c @@ -1,5 +1,5 @@ /* - * $Id: readcfg.c,v 5.173 2004/05/07 03:42:49 bryan Exp $ + * $Id: readcfg.c,v 5.176 2004/05/25 00:38:15 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -123,24 +123,8 @@ AddUserList(id) } /***** internal things *****/ -typedef struct item { - char *id; - void (*reg) PARAMS((char *)); -} ITEM; - -typedef struct section { - char *id; - void (*begin) PARAMS((char *)); - void (*end) PARAMS((void)); - void (*abort) PARAMS((void)); - void (*destroy) PARAMS((void)); - ITEM *items; -} SECTION; - #define ALLWORDSEP ", \f\v\t\n\r" -int line = 1; /* current line number */ -char *file = (char *)0; int isStartup = 0; GRPENT *pGroupsOld = (GRPENT *)0; GRPENT *pGEstage = (GRPENT *)0; @@ -681,6 +665,8 @@ ApplyDefault(d, c) c->idletimeout = d->idletimeout; if (d->logfilemax != 0) c->logfilemax = d->logfilemax; + if (d->raw != FLAGUNKNOWN) + c->raw = d->raw; if (d->port != 0) c->port = d->port; if (d->netport != 0) @@ -975,239 +961,6 @@ ProcessDevice(c, id) OutOfMem(); } -void -#if PROTOTYPES -ProcessSubst(CONSENT *pCE, char **repl, char **str, char *name, char *id) -#else -ProcessSubst(pCE, repl, str, name, id) - CONSENT *pCE; - char **repl; - char **str; - char *name; - char *id; -#endif -{ - /* - * (CONSENT *pCE) and (char **repl) are used when a replacement is to - * actually happen...repl is the string to munch, pCE holds the data. - * - * (char **str) is used to store a copy of (char *id), if it passes - * the format check. - * - * the idea is that this is first called when the config file is read, - * putting the result in (char **str). then we call it again, near - * the end, permuting (char **repl) with values from (CONSENT *pCE) with - * the saved string now coming in as (char *id). got it? - * - * you could pass all arguments in...then both types of actions occur. - */ - char *p; - char *repfmt[255]; - unsigned short repnum; - int i; - - enum repstate { - REP_BEGIN, - REP_LTR, - REP_EQ, - REP_INT, - REP_END - } state; - - if (str != (char **)0) { - if (*str != (char *)0) { - free(*str); - *str = (char *)0; - } - } - - if ((id == (char *)0) || (*id == '\000')) - return; - - repnum = 0; - state = REP_BEGIN; - - for (i = 0; i < 256; i++) - repfmt[i] = (char *)0; - - for (p = id; *p != '\000'; p++) { - switch (state) { - case REP_BEGIN: - /* must be printable */ - if (*p == ',' || !isgraph((int)(*p))) - goto subst_err; - - /* make sure we haven't seen this replacement char yet */ - repnum = (unsigned short)(*p); - if (repfmt[repnum] != (char *)0) { - if (isMaster) - Error - ("substitution characters of `%s' option are the same [%s:%d]", - name, file, line); - return; - } - state = REP_LTR; - break; - case REP_LTR: - if (*p != '=') - goto subst_err; - state = REP_EQ; - break; - case REP_EQ: - repfmt[repnum] = p; - if (*p == 'h' || *p == 'c' || *p == 'p' || *p == 'P') - state = REP_INT; - else - goto subst_err; - break; - case REP_INT: - if (*p == 'd' || *p == 'x' || *p == 'X') { - if (*(repfmt[repnum]) != 'p' && - *(repfmt[repnum]) != 'P') - goto subst_err; - state = REP_END; - } else if (*p == 's') { - if (*(repfmt[repnum]) != 'h' && - *(repfmt[repnum]) != 'c') - goto subst_err; - state = REP_END; - } else if (!isdigit((int)(*p))) - goto subst_err; - break; - case REP_END: - if (*p != ',') - goto subst_err; - state = REP_BEGIN; - break; - } - } - - if (state != REP_END) { - subst_err: - if (isMaster) - Error - ("invalid `%s' specification `%s' (char #%d: `%c') [%s:%d]", - name, id, (p - id) + 1, *p, file, line); - return; - } - - if (str != (char **)0) { - if ((*str = StrDup(id)) == (char *)0) - OutOfMem(); - } - - if (pCE != (CONSENT *)0 && repl != (char **)0) { - static STRING *result = (STRING *)0; - - if (result == (STRING *)0) - result = AllocString(); - BuildString((char *)0, result); - - for (p = *repl; *p != '\000'; p++) { - if (repfmt[(unsigned short)(*p)] != (char *)0) { - char *r = repfmt[(unsigned short)(*p)]; - int plen = 0; - char *c = (char *)0; - int o = 0; - - if (*r == 'h' || *r == 'c') { - /* check the pattern for a length */ - if (isdigit((int)(*(r + 1)))) - plen = atoi(r + 1); - - if (*r == 'h') - c = pCE->host; - else if (*r == 'c') - c = pCE->server; - plen -= strlen(c); - - /* pad it out, if necessary */ - for (i = 0; i < plen; i++) - BuildStringChar(' ', result); - - /* throw in the string */ - BuildString(c, result); - } else { - unsigned short port = 0; - unsigned short base = 0; - int padzero = 0; - static STRING *num = (STRING *)0; - - if (num == (STRING *)0) - num = AllocString(); - BuildString((char *)0, num); - - if (*r == 'p') - port = pCE->port; - if (*r == 'P') - port = pCE->netport; - - /* check the pattern for a length and padding */ - for (c = r + 1; *c != '\000'; c++) - if (!isdigit((int)(*c))) - break; - if (c != r + 1) { - plen = atoi(r + 1); - padzero = (r[1] == '0'); - } - - /* check for base */ - switch (*c) { - case 'd': - base = 10; - break; - case 'x': - case 'X': - base = 16; - break; - default: - return; - } - while (port >= base) { - if (port % base >= 10) - BuildStringChar((port % base) - 10 + - (*c == 'x' ? 'a' : 'A'), num); - else - BuildStringChar((port % base) + '0', num); - port /= base; - } - if (port >= 10) - BuildStringChar(port - 10 + - (*c == 'x' ? 'a' : 'A'), num); - else - BuildStringChar(port + '0', num); - - /* if we're supposed to be a certain length, pad it */ - while (num->used - 1 < plen) { - if (padzero == 0) - BuildStringChar(' ', num); - else - BuildStringChar('0', num); - } - - /* reverse the text to put it in forward order */ - o = num->used - 1; - for (i = 0; i < o / 2; i++) { - char temp; - - temp = num->string[i]; - num->string[i] - = num->string[o - i - 1]; - num->string[o - i - 1] = temp; - } - BuildStringN(num->string, o, result); - } - } else - BuildStringChar(*p, result); - } - free(*repl); - if ((*repl = StrDup(result->string)) == (char *)0) - OutOfMem(); - } - - return; -} - void #if PROTOTYPES DefaultItemDevice(char *id) @@ -1220,6 +973,63 @@ DefaultItemDevice(id) ProcessDevice(parserDefaultTemp, id); } +SUBST *substData = (SUBST *) 0; + +int +#if PROTOTYPES +SubstCallback(char c, char **s, int *i) +#else +SubstCallback(c, s, i) + char c; + char **s; + int *i; +#endif +{ + int retval = 0; + + if (substData == (SUBST *) 0) { + if ((substData = + (SUBST *) calloc(1, sizeof(SUBST))) == (SUBST *) 0) + OutOfMem(); + substData->callback = &SubstCallback; + substData->tokens['p'] = ISNUMBER; + substData->tokens['P'] = ISNUMBER; + substData->tokens['h'] = ISSTRING; + substData->tokens['c'] = ISSTRING; + } + + if (s != (char **)0) { + CONSENT *pCE; + if (substData->data == (void *)0) + return 0; + + pCE = (CONSENT *)(substData->data); + if (c == 'h') { + (*s) = pCE->host; + retval = 1; + } else if (c == 'c') { + (*s) = pCE->server; + retval = 1; + } + } + + if (i != (int *)0) { + CONSENT *pCE; + if (substData->data == (void *)0) + return 0; + pCE = (CONSENT *)(substData->data); + if (c == 'p') { + (*i) = pCE->port; + retval = 1; + } else if (c == 'P') { + (*i) = pCE->netport; + retval = 1; + } + } + + return retval; +} + void #if PROTOTYPES DefaultItemDevicesubst(char *id) @@ -1229,8 +1039,8 @@ DefaultItemDevicesubst(id) #endif { CONDDEBUG((1, "DefaultItemDevicesubst(%s) [%s:%d]", id, file, line)); - ProcessSubst((CONSENT *)0, (char **)0, - &(parserDefaultTemp->devicesubst), "devicesubst", id); + ProcessSubst(substData, (char **)0, &(parserDefaultTemp->devicesubst), + "devicesubst", id); } void @@ -1242,7 +1052,7 @@ DefaultItemExecsubst(id) #endif { CONDDEBUG((1, "DefaultItemExecsubst(%s) [%s:%d]", id, file, line)); - ProcessSubst((CONSENT *)0, (char **)0, &(parserDefaultTemp->execsubst), + ProcessSubst(substData, (char **)0, &(parserDefaultTemp->execsubst), "execsubst", id); } @@ -1255,7 +1065,7 @@ DefaultItemInitsubst(id) #endif { CONDDEBUG((1, "DefaultItemInitsubst(%s) [%s:%d]", id, file, line)); - ProcessSubst((CONSENT *)0, (char **)0, &(parserDefaultTemp->initsubst), + ProcessSubst(substData, (char **)0, &(parserDefaultTemp->initsubst), "initsubst", id); } @@ -1859,14 +1669,17 @@ ProcessProtocol(c, id) char *id; #endif { - c->raw = 0; - if ((id == (char *)0) || (*id == '\000')) + if ((id == (char *)0) || (*id == '\000')) { + c->raw = FLAGUNKNOWN; return; + } - if (strcmp(id, "telnet") == 0) + if (strcmp(id, "telnet") == 0) { + c->raw = FLAGFALSE; return; + } if (strcmp(id, "raw") == 0) { - c->raw = 1; + c->raw = FLAGTRUE; return; } if (isMaster) @@ -2850,6 +2663,7 @@ ConsoleAdd(c) pCEmatch->portbase = c->portbase; pCEmatch->activitylog = c->activitylog; pCEmatch->breaklog = c->breaklog; + pCEmatch->raw = c->raw; pCEmatch->mark = c->mark; pCEmatch->nextMark = c->nextMark; pCEmatch->breakNum = c->breakNum; @@ -2962,17 +2776,18 @@ ConsoleDestroy() */ c->netport = c->portbase + c->portinc * c->port; + substData->data = (void *)c; /* check for substitutions */ if (c->type == DEVICE && c->devicesubst != (char *)0) - ProcessSubst(c, &(c->device), (char **)0, (char *)0, + ProcessSubst(substData, &(c->device), (char **)0, (char *)0, c->devicesubst); if (c->type == EXEC && c->execsubst != (char *)0) - ProcessSubst(c, &(c->exec), (char **)0, (char *)0, + ProcessSubst(substData, &(c->exec), (char **)0, (char *)0, c->execsubst); if (c->initcmd != (char *)0 && c->initsubst != (char *)0) - ProcessSubst(c, &(c->initcmd), (char **)0, (char *)0, + ProcessSubst(substData, &(c->initcmd), (char **)0, (char *)0, c->initsubst); /* go ahead and do the '&' substitution */ @@ -3003,6 +2818,8 @@ ConsoleDestroy() /* set the options that default false */ if (c->activitylog == FLAGUNKNOWN) c->activitylog = FLAGFALSE; + if (c->raw == FLAGUNKNOWN) + c->raw = FLAGFALSE; if (c->breaklog == FLAGUNKNOWN) c->breaklog = FLAGFALSE; if (c->hupcl == FLAGUNKNOWN) @@ -3274,8 +3091,8 @@ ConsoleItemDevicesubst(id) #endif { CONDDEBUG((1, "ConsoleItemDevicesubst(%s) [%s:%d]", id, file, line)); - ProcessSubst((CONSENT *)0, (char **)0, - &(parserConsoleTemp->devicesubst), "devicesubst", id); + ProcessSubst(substData, (char **)0, &(parserConsoleTemp->devicesubst), + "devicesubst", id); } void @@ -3287,7 +3104,7 @@ ConsoleItemExecsubst(id) #endif { CONDDEBUG((1, "ConsoleItemExecsubst(%s) [%s:%d]", id, file, line)); - ProcessSubst((CONSENT *)0, (char **)0, &(parserConsoleTemp->execsubst), + ProcessSubst(substData, (char **)0, &(parserConsoleTemp->execsubst), "execsubst", id); } @@ -3300,7 +3117,7 @@ ConsoleItemInitsubst(id) #endif { CONDDEBUG((1, "ConsoleItemInitsubst(%s) [%s:%d]", id, file, line)); - ProcessSubst((CONSENT *)0, (char **)0, &(parserConsoleTemp->initsubst), + ProcessSubst(substData, (char **)0, &(parserConsoleTemp->initsubst), "initsubst", id); } @@ -4595,484 +4412,6 @@ SECTION sections[] = { {(char *)0, (void *)0, (void *)0, (void *)0, (void *)0} }; -/* the format of the file should be as follows - * - *
[section name] { - * [item value]; - * . - * . - * } - * - * whitespace gets retained in [section name], and [item value] - * values. for example, - * - * users bryan todd ; - * - * will give users the value of 'bryan todd'. the leading and - * trailing whitespace is nuked, but the middle stuff isn't. - * - * a little note about the 'state' var... - * START = before
- * NAME = before [section name] - * LEFTB = before left curly brace - * KEY = before - * VALUE = before [item value] - * SEMI = before semi-colon - */ - -typedef enum states { - START, - NAME, - LEFTB, - KEY, - VALUE, - SEMI -} STATES; - -typedef enum tokens { - DONE, - LEFTBRACE, - RIGHTBRACE, - SEMICOLON, - WORD, - INCLUDE -} TOKEN; - -TOKEN -#if PROTOTYPES -GetWord(FILE *fp, int *line, short spaceok, STRING *word) -#else -GetWord(fp, line, spaceok, word) - FILE *fp; - int *line; - short spaceok; - STRING *word; -#endif -{ - int c; - short backslash = 0; - short quote = 0; - short comment = 0; - short sawQuote = 0; - short quotedBackslash = 0; - char *include = "include"; - short checkInc = -1; - /* checkInc == -3, saw #include - * == -2, saw nothin' - * == -1, saw \n or start of file - * == 0, saw "\n#" - */ - - BuildString((char *)0, word); - while ((c = fgetc(fp)) != EOF) { - if (c == '\n') { - (*line)++; - if (checkInc == -2) - checkInc = -1; - } - if (comment) { - if (c == '\n') - comment = 0; - if (checkInc >= 0) { - if (include[checkInc] == '\000') { - if (isspace(c)) - checkInc = -3; - } else if (c == include[checkInc]) - checkInc++; - else - checkInc = -2; - } else if (checkInc == -3) { - static STRING *fname = (STRING *)0; - if (fname == (STRING *)0) - fname = AllocString(); - if (fname->used != 0 || !isspace(c)) { - if (c == '\n') { - if (fname->used > 0) { - while (fname->used > 1 && isspace((int) - (fname-> - string - [fname-> - used - - 2]))) - fname->used--; - if (fname->used > 0) - fname->string[fname->used - 1] = '\000'; - } - checkInc = -2; - if (fname->used > 0) { - BuildString((char *)0, word); - BuildString(fname->string, word); - BuildString((char *)0, fname); - return INCLUDE; - } - } else - BuildStringChar(c, fname); - } - } - continue; - } - if (backslash) { - BuildStringChar(c, word); - backslash = 0; - continue; - } - if (quote) { - if (c == '"') { - if (quotedBackslash) { - BuildStringChar(c, word); - quotedBackslash = 0; - } else - quote = 0; - } else { - if (quotedBackslash) { - BuildStringChar('\\', word); - quotedBackslash = 0; - } - if (c == '\\') - quotedBackslash = 1; - else - BuildStringChar(c, word); - } - continue; - } - if (c == '\\') { - backslash = 1; - } else if (c == '#') { - comment = 1; - if (checkInc == -1) - checkInc = 0; - } else if (c == '"') { - quote = 1; - sawQuote = 1; - } else if (isspace(c)) { - if (word->used <= 1) - continue; - if (spaceok) { - BuildStringChar(c, word); - continue; - } - gotword: - while (word->used > 1 && - isspace((int)(word->string[word->used - 2]))) - word->used--; - if (word->used > 0) - word->string[word->used - 1] = '\000'; - return WORD; - } else if (c == '{') { - if (word->used <= 1 && !sawQuote) { - BuildStringChar(c, word); - return LEFTBRACE; - } else { - ungetc(c, fp); - goto gotword; - } - } else if (c == '}') { - if (word->used <= 1 && !sawQuote) { - BuildStringChar(c, word); - return RIGHTBRACE; - } else { - ungetc(c, fp); - goto gotword; - } - } else if (c == ';') { - if (word->used <= 1 && !sawQuote) { - BuildStringChar(c, word); - return SEMICOLON; - } else { - ungetc(c, fp); - goto gotword; - } - } else { - BuildStringChar(c, word); - } - } - /* this should only happen in rare cases */ - if (quotedBackslash) { - BuildStringChar('\\', word); - quotedBackslash = 0; - } - /* if we saw "valid" data, it's a word */ - if (word->used > 1 || sawQuote) - goto gotword; - return DONE; -} - -void -#if PROTOTYPES -ParseFile(char *filename, FILE *fp, int level) -#else -ParseFile(filename, fp, level) - char *filename; - FILE *fp; - int level; -#endif -{ - /* things that should be used between recursions */ - static STATES state = START; - static STRING *word = (STRING *)0; - static short spaceok = 0; - static int secIndex = 0; - static int keyIndex = 0; - - /* other stuff that's local to each recursion */ - char *p; - TOKEN token = DONE; - int nextline = 1; /* "next" line number */ - - if (level >= 10) { - if (isMaster) - Error("ParseFile(): nesting too deep, not parsing `%s'", - filename); - return; - } - - /* set some globals */ - line = 1; - file = filename; - - /* if we're parsing the base file, set static vars */ - if (level == 0) { - state = START; - spaceok = 0; - secIndex = 0; - keyIndex = 0; - } - - /* initialize local things */ - if (word == (STRING *)0) - word = AllocString(); - - while ((token = GetWord(fp, &nextline, spaceok, word)) != DONE) { - if (token == INCLUDE) { - FILE *lfp; - if ((FILE *)0 == (lfp = fopen(word->string, "r"))) { - if (isMaster) - Error("ParseFile(): fopen(%s): %s", word->string, - strerror(errno)); - } else { - char *fname; - /* word gets destroyed, so save the name */ - fname = StrDup(word->string); - ParseFile(fname, lfp, level + 1); - fclose(lfp); - free(fname); - } - } else { - switch (state) { - case START: - switch (token) { - case WORD: - for (secIndex = 0; - (p = sections[secIndex].id) != (char *)0; - secIndex++) { - if (strcasecmp(word->string, p) == 0) { - CONDDEBUG((1, - "ReadCfg(): got keyword '%s' [%s:%d]", - word->string, file, line)); - state = NAME; - break; - } - } - if (state == START) { - if (isMaster) - Error("invalid keyword '%s' [%s:%d]", - word->string, file, line); - } - break; - case LEFTBRACE: - case RIGHTBRACE: - case SEMICOLON: - if (isMaster) - Error("invalid token '%s' [%s:%d]", - word->string, file, line); - break; - case DONE: /* just shutting up gcc */ - case INCLUDE: /* just shutting up gcc */ - break; - } - break; - case NAME: - switch (token) { - case WORD: - (*sections[secIndex].begin) (word->string); - state = LEFTB; - break; - case RIGHTBRACE: - if (isMaster) - Error("premature token '%s' [%s:%d]", - word->string, file, line); - state = START; - break; - case LEFTBRACE: - case SEMICOLON: - if (isMaster) - Error("invalid token '%s' [%s:%d]", - word->string, file, line); - break; - case DONE: /* just shutting up gcc */ - case INCLUDE: /* just shutting up gcc */ - break; - } - break; - case LEFTB: - switch (token) { - case LEFTBRACE: - state = KEY; - break; - case RIGHTBRACE: - if (isMaster) - Error("premature token '%s' [%s:%d]", - word->string, file, line); - (*sections[secIndex].abort) (); - state = START; - break; - case SEMICOLON: - if (isMaster) - Error("invalid token '%s' [%s:%d]", - word->string, file, line); - break; - case WORD: - if (isMaster) - Error("invalid word '%s' [%s:%d]", - word->string, file, line); - break; - case DONE: /* just shutting up gcc */ - case INCLUDE: /* just shutting up gcc */ - break; - } - break; - case KEY: - switch (token) { - case WORD: - for (keyIndex = 0; - (p = - sections[secIndex].items[keyIndex].id) != - (char *)0; keyIndex++) { - if (strcasecmp(word->string, p) == 0) { - CONDDEBUG((1, - "got keyword '%s' [%s:%d]", - word->string, file, line)); - state = VALUE; - break; - } - } - if (state == KEY) { - if (isMaster) - Error("invalid keyword '%s' [%s:%d]", - word->string, file, line); - } - break; - case RIGHTBRACE: - (*sections[secIndex].end) (); - state = START; - break; - case LEFTBRACE: - if (isMaster) - Error("invalid token '%s' [%s:%d]", - word->string, file, line); - break; - case SEMICOLON: - if (isMaster) - Error("premature token '%s' [%s:%d]", - word->string, file, line); - case DONE: /* just shutting up gcc */ - case INCLUDE: /* just shutting up gcc */ - break; - } - break; - case VALUE: - switch (token) { - case WORD: - (*sections[secIndex].items[keyIndex]. - reg) (word->string); - state = SEMI; - break; - case SEMICOLON: - if (isMaster) - Error("invalid token '%s' [%s:%d]", - word->string, file, line); - state = KEY; - break; - case RIGHTBRACE: - if (isMaster) - Error("premature token '%s' [%s:%d]", - word->string, file, line); - (*sections[secIndex].abort) (); - state = START; - break; - case LEFTBRACE: - if (isMaster) - Error("invalid token '%s' [%s:%d]", - word->string, file, line); - break; - case DONE: /* just shutting up gcc */ - case INCLUDE: /* just shutting up gcc */ - break; - } - break; - case SEMI: - switch (token) { - case SEMICOLON: - state = KEY; - break; - case RIGHTBRACE: - if (isMaster) - Error("premature token '%s' [%s:%d]", - word->string, file, line); - (*sections[secIndex].abort) (); - state = START; - break; - case LEFTBRACE: - if (isMaster) - Error("invalid token '%s' [%s:%d]", - word->string, file, line); - break; - case WORD: - if (isMaster) - Error("invalid word '%s' [%s:%d]", - word->string, file, line); - break; - case DONE: /* just shutting up gcc */ - case INCLUDE: /* just shutting up gcc */ - break; - } - break; - } - switch (state) { - case NAME: - case VALUE: - spaceok = 1; - break; - case KEY: - case LEFTB: - case START: - case SEMI: - spaceok = 0; - break; - } - } - line = nextline; - } - - if (level == 0) { - /* check for proper ending of file and do any cleanup */ - switch (state) { - case START: - break; - case KEY: - case LEFTB: - case VALUE: - case SEMI: - (*sections[secIndex].abort) (); - /* fall through */ - case NAME: - if (isMaster) - Error("premature EOF seen [%s:%d]", file, line); - break; - } - } -} - void #if PROTOTYPES ReadCfg(char *filename, FILE *fp) @@ -5082,7 +4421,6 @@ ReadCfg(filename, fp) FILE *fp; #endif { - char *p; int i; #if HAVE_DMALLOC && DMALLOC_MARK_READCFG unsigned long dmallocMarkReadCfg = 0; @@ -5116,18 +4454,15 @@ ReadCfg(filename, fp) DestroyConfig(pConfig); pConfig = (CONFIG *)0; } - if ((pConfig = (CONFIG *)calloc(1, sizeof(CONFIG))) - == (CONFIG *)0) + if ((pConfig = (CONFIG *)calloc(1, sizeof(CONFIG))) == (CONFIG *)0) OutOfMem(); + /* initialize the substition bits */ + SubstCallback('\000', (char **)0, (int *)0); + /* ready to read in the data */ ParseFile(filename, fp, 0); - /* now clean up all the temporary space used */ - for (i = 0; (p = sections[i].id) != (char *)0; i++) { - (*sections[i].destroy) (); - } - #if HAVE_DMALLOC && DMALLOC_MARK_READCFG CONDDEBUG((1, "ReadCfg(): dmalloc / MarkReadCfg")); dmalloc_log_changed(dmallocMarkReadCfg, 1, 0, 1); diff --git a/conserver/readcfg.h b/conserver/readcfg.h index 42ae5c3..93ac794 100644 --- a/conserver/readcfg.h +++ b/conserver/readcfg.h @@ -1,5 +1,5 @@ /* - * $Id: readcfg.h,v 5.39 2004/05/07 03:42:49 bryan Exp $ + * $Id: readcfg.h,v 5.40 2004/05/25 23:03:01 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -43,6 +43,7 @@ extern ACCESS *pACList; /* `who do you love' (or trust) */ extern CONSENTUSERS *pADList; /* list of admin users */ extern BREAKS breakList[9]; /* list of break sequences */ extern CONFIG *pConfig; /* settings seen by config parser */ +extern SUBST *substData; /* substitution function data */ extern void ReadCfg PARAMS((char *, FILE *)); extern void ReReadCfg PARAMS((int)); diff --git a/conserver/version.h b/conserver/version.h index ba8cb19..a46fa24 100644 --- a/conserver/version.h +++ b/conserver/version.h @@ -1,5 +1,5 @@ /* - * $Id: version.h,v 1.61 2004/04/16 16:58:09 bryan Exp $ + * $Id: version.h,v 1.62 2004/05/23 16:44:45 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.1.5" +#define THIS_VERSION "conserver.com version 8.1.6" diff --git a/console/Makefile.in b/console/Makefile.in index 093ce5c..5c134ef 100644 --- a/console/Makefile.in +++ b/console/Makefile.in @@ -25,11 +25,11 @@ LIBS = @LIBS@ ### Makefile rules - no user-servicable parts below -CONSOLE_OBJS = console.o getpassword.o ../conserver/cutil.o +CONSOLE_OBJS = console.o getpassword.o readconf.o ../conserver/cutil.o CONSOLE_HDRS = ../config.h $(top_srcdir)/compat.h \ $(top_srcdir)/conserver/cutil.h \ $(top_srcdir)/conserver/version.h \ - $(srcdir)/getpassword.h + $(srcdir)/getpassword.h $(srcdir)/readconf.h ALL = console diff --git a/console/console.c b/console/console.c index b013666..74d5398 100644 --- a/console/console.c +++ b/console/console.c @@ -1,5 +1,5 @@ /* - * $Id: console.c,v 5.164 2004/04/20 01:30:13 bryan Exp $ + * $Id: console.c,v 5.167 2004/05/25 23:03:25 bryan Exp $ * * Copyright conserver.com, 2000 * @@ -34,6 +34,7 @@ #include #include #include +#include #if HAVE_OPENSSL #include #include @@ -41,24 +42,11 @@ #endif -int fReplay = 0, fVersion = 0, fStrip = 0; +int fReplay = 0, fVersion = 0; int showExecData = 1; -#if HAVE_OPENSSL -int fReqEncryption = 1; -int fAllowUnencrypted = 0; -char *pcCredFile = (char *)0; -#endif int chAttn = -1, chEsc = -1; -char *pcInMaster = -#if USE_UNIX_DOMAIN_SOCKETS - UDSDIR; -#else - MASTERHOST; /* which machine is current */ -#endif -char *pcPort = DEFPORT; unsigned short bindPort; CONSFILE *cfstdout; -char *pcUser = (char *)0; int disconnectCount = 0; STRING *execCmd = (STRING *)0; CONSFILE *execCmdFile = (CONSFILE *)0; @@ -67,6 +55,8 @@ CONSFILE *gotoConsole = (CONSFILE *)0; CONSFILE *prevConsole = (CONSFILE *)0; char *gotoName = (char *)0; char *prevName = (char *)0; +CONFIG *optConf = (CONFIG *)0; +CONFIG *config = (CONFIG *)0; #if HAVE_OPENSSL SSL_CTX *ctx = (SSL_CTX *)0; @@ -92,15 +82,17 @@ SetupSSL() Error("Could not load SSL default CA file and/or directory"); Bye(EX_UNAVAILABLE); } - if (pcCredFile != (char *)0) { - if (SSL_CTX_use_certificate_chain_file(ctx, pcCredFile) != 1) { + if (config->sslcredentials != (char *)0) { + if (SSL_CTX_use_certificate_chain_file + (ctx, config->sslcredentials) != 1) { Error("Could not load SSL certificate from '%s'", - pcCredFile); + config->sslcredentials); Bye(EX_UNAVAILABLE); } if (SSL_CTX_use_PrivateKey_file - (ctx, pcCredFile, SSL_FILETYPE_PEM) != 1) { - Error("Could not SSL private key from '%s'", pcCredFile); + (ctx, config->sslcredentials, SSL_FILETYPE_PEM) != 1) { + Error("Could not SSL private key from '%s'", + config->sslcredentials); Bye(EX_UNAVAILABLE); } } @@ -191,54 +183,56 @@ Usage(wantfull) #endif { static char *full[] = { - "7 strip the high bit off all console data", - "a(A) attach politely (and replay last 20 lines)", - "b(B) send broadcast message to all users (on master)", + "7 strip the high bit off all console data", + "a(A) attach politely (and replay last 20 lines)", + "b(B) send broadcast message to all users (on master)", #if HAVE_OPENSSL - "c cred load an SSL certificate and key from the PEM encoded file", + "c cred load an SSL certificate and key from the PEM encoded file", #else - "c cred ignored - encryption not compiled into code", + "c cred ignored - encryption not compiled into code", #endif - "d disconnect [user][@console]", - "D enable debug output, sent to stderr", - "e esc set the initial escape characters", + "C config override per-user config file", + "d disconnect [user][@console]", + "D enable debug output, sent to stderr", + "e esc set the initial escape characters", #if HAVE_OPENSSL - "E don't attempt encrypted connections", + "E don't attempt encrypted connections", #else - "E ignored - encryption not compiled into code", + "E ignored - encryption not compiled into code", #endif - "f(F) force read/write connection (and replay)", - "h output this message", - "i(I) display information in machine-parseable form (on master)", - "l user use username instead of current username", - "M mach master server to poll first", - "p port port to connect to", - "P display pids of daemon(s)", - "q(Q) send a quit command to the (master) server", - "r(R) display (master) daemon version (think 'r'emote version)", - "s(S) spy on a console (and replay)", - "t send a text message to [user][@console]", - "u show users on the various consoles", + "f(F) force read/write connection (and replay)", + "h output this message", + "i(I) display information in machine-parseable form (on master)", + "l user use username instead of current username", + "M master master server to poll first", + "n do not read system-wide config file", + "p port port to connect to", + "P display pids of daemon(s)", + "q(Q) send a quit command to the (master) server", + "r(R) display (master) daemon version (think 'r'emote version)", + "s(S) spy on a console (and replay)", + "t send a text message to [user][@console]", + "u show users on the various consoles", #if HAVE_OPENSSL - "U allow unencrypted connections if SSL not available", + "U allow unencrypted connections if SSL not available", #else - "U ignored - encryption not compiled into code", + "U ignored - encryption not compiled into code", #endif - "v be more verbose", - "V show version information", - "w(W) show who is on which console (on master)", - "x examine ports and baud rates", + "v be more verbose", + "V show version information", + "w(W) show who is on which console (on master)", + "x examine ports and baud rates", (char *)0 }; fprintf(stderr, - "usage: %s [-aAfFsS] [-7DEUv] [-c cred] [-M mach] [-p port] [-e esc] [-l username] console\n", + "usage: %s [-aAfFsS] [-7DEnUv] [-c cred] [-C config] [-M master] [-p port] [-e esc] [-l username] console\n", progname); fprintf(stderr, - " %s [-hiIPrRuVwWx] [-7DEUv] [-c cred] [-M mach] [-p port] [-d [user][@console]] [-[bB] message] [-t [user][@console] message]\n", + " %s [-hiIPrRuVwWx] [-7DEnUv] [-c cred] [-C config] [-M master] [-p port] [-d [user][@console]] [-[bB] message] [-t [user][@console] message]\n", progname); fprintf(stderr, - " %s [-qQ] [-7DEUv] [-c cred] [-M mach] [-p port]\n", + " %s [-qQ] [-7DEnUv] [-c cred] [-C config] [-M master] [-p port]\n", progname); if (wantfull) { @@ -272,6 +266,9 @@ Version() #endif #if HAVE_PAM "pam", +#endif +#if USE_UNIX_DOMAIN_SOCKETS + "uds", #endif (char *)0 }; @@ -290,6 +287,8 @@ Version() #endif Msg("default escape sequence `%s%s\'", FmtCtl(DEFATTN, acA1), FmtCtl(DEFESC, acA2)); + Msg("default site-wide configuration in `%s'", CLIENTCONFIGFILE); + Msg("default per-user configuration in `%s'", "$HOME/.consolerc"); BuildString((char *)0, acA1); if (optionlist[0] == (char *)0) @@ -310,10 +309,12 @@ Version() BuildStringChar('0' + DMALLOC_VERSION_MINOR, acA1); BuildStringChar('.', acA1); BuildStringChar('0' + DMALLOC_VERSION_PATCH, acA1); +#if defined(DMALLOC_VERSION_BETA) if (DMALLOC_VERSION_BETA != 0) { BuildString("-b", acA1); BuildStringChar('0' + DMALLOC_VERSION_BETA, acA1); } +#endif Msg("dmalloc version: %s", acA1->string); #endif #if HAVE_OPENSSL @@ -388,7 +389,7 @@ ValidateEsc() { unsigned char c1, c2; - if (!fStrip) + if (config->striphigh != FLAGTRUE) return; if (chAttn == -1 || chEsc == -1) { @@ -463,7 +464,7 @@ GetPort(pcToHost, sPort) #if USE_UNIX_DOMAIN_SOCKETS if (portPath == (STRING *)0) portPath = AllocString(); - BuildStringPrint(portPath, "%s/%hu", pcInMaster, sPort); + BuildStringPrint(portPath, "%s/%hu", config->master, sPort); port.sun_family = AF_UNIX; if (portPath->used > sizeof(port.sun_path)) { Error("GetPort: path to socket too long: %s", portPath->string); @@ -607,7 +608,15 @@ DestroyDataStructures() C2Cooked(); if (cfstdout != (CONSFILE *)0) FileUnopen(cfstdout); + DestroyConfig(pConfig); + DestroyConfig(optConf); + DestroyConfig(config); + DestroyTerminal(pTerm); + if (myAddrs != (struct in_addr *)0) + free(myAddrs); DestroyStrings(); + if (substData != (SUBST *) 0) + free(substData); } char * @@ -944,6 +953,129 @@ DoExec(pcf) } } +void +#if PROTOTYPES +ExpandString(char *str, CONSFILE *c) +#else +ExpandString(str, c) + char *str; + CONSFILE *c; +#endif +{ + char s; + short backslash = 0; + short cntrl = 0; + char oct = '\000'; + short octs = 0; + static STRING *exp = (STRING *)0; + + if (str == (char *)0 || c == (CONSFILE *)0) + return; + + if (exp == (STRING *)0) + exp = AllocString(); + + BuildString((char *)0, exp); + + backslash = 0; + cntrl = 0; + while ((s = (*str++)) != '\000') { + if (octs > 0 && octs < 3 && s >= '0' && s <= '7') { + ++octs; + oct = oct * 8 + (s - '0'); + continue; + } + if (octs != 0) { + BuildStringChar(oct, exp); + octs = 0; + oct = '\000'; + } + if (backslash) { + backslash = 0; + if (s == 'a') + s = '\a'; + else if (s == 'b') + s = '\b'; + else if (s == 'f') + s = '\f'; + else if (s == 'n') + s = '\n'; + else if (s == 'r') + s = '\r'; + else if (s == 't') + s = '\t'; + else if (s == 'v') + s = '\v'; + else if (s == '^') + s = '^'; + else if (s >= '0' && s <= '7') { + ++octs; + oct = oct * 8 + (s - '0'); + continue; + } + BuildStringChar(s, exp); + continue; + } + if (cntrl) { + cntrl = 0; + if (s == '?') + s = 0x7f; /* delete */ + else + s = s & 0x1f; + BuildStringChar(s, exp); + continue; + } + if (s == '\\') { + backslash = 1; + continue; + } + if (s == '^') { + cntrl = 1; + continue; + } + BuildStringChar(s, exp); + } + + if (octs != 0) + BuildStringChar(oct, exp); + + if (backslash) + BuildStringChar('\\', exp); + + if (cntrl) + BuildStringChar('^', exp); + + if (exp->used > 1) + FileWrite(c, FLAGFALSE, exp->string, exp->used - 1); +} + +void +#if PROTOTYPES +PrintSubst(CONSFILE *pcf, char *pcMach, char *string, char *subst) +#else +PrintSubst(pcf, pcMach, string, subst) + CONSFILE *pcf; + char *pcMach; + char *string; + char *subst; +#endif +{ + if (string == (char *)0) + return; + + if (subst != (char *)0) { + char *str; + if ((str = StrDup(string)) == (char *)0) + OutOfMem(); + substData->data = (void *)config; + config->console = pcMach; + ProcessSubst(substData, &str, (char **)0, (char *)0, subst); + ExpandString(str, pcf); + free(str); + } else + ExpandString(string, pcf); +} + void #if PROTOTYPES Interact(CONSFILE *pcf, char *pcMach) @@ -962,8 +1094,10 @@ Interact(pcf, pcMach) /* if this is true, it means we successfully moved to a new console * so we need to close the old one. */ - if (prevConsole != (CONSFILE *)0) + if (prevConsole != (CONSFILE *)0) { FileClose(&prevConsole); + PrintSubst(cfstdout, prevName, pTerm->detach, pTerm->detachsubst); + } if (prevName != (char *)0) { free(prevName); prevName = (char *)0; @@ -976,6 +1110,8 @@ Interact(pcf, pcMach) FileWrite(pcf, FLAGFALSE, "\n", 1); } + PrintSubst(cfstdout, pcMach, pTerm->attach, pTerm->attachsubst); + C2Raw(); /* set socket to non-blocking */ @@ -1024,7 +1160,7 @@ Interact(pcf, pcMach) FilePrint(pcf, FLAGFALSE, "%c%c", OB_IAC, OB_ABRT); FileSetQuoteIAC(pcf, FLAGTRUE); } else { - if (fStrip) { + if (config->striphigh == FLAGTRUE) { for (i = 0; i < nc; ++i) acMesg[i] &= 127; } @@ -1091,7 +1227,7 @@ Interact(pcf, pcMach) } continue; } - if (fStrip) { + if (config->striphigh == FLAGTRUE) { for (i = 0; i < l; ++i) acMesg[i] &= 127; } @@ -1123,7 +1259,7 @@ Interact(pcf, pcMach) } } if (execCmdFile == (CONSFILE *)0) { - if (fStrip) { + if (config->striphigh == FLAGTRUE) { for (i = 0; i < nc; ++i) acMesg[i] &= 127; } @@ -1154,7 +1290,11 @@ Interact(pcf, pcMach) } } } + C2Cooked(); + + PrintSubst(cfstdout, pcMach, pTerm->detach, pTerm->detachsubst); + if (fVerbose) printf("Console %s closed.\n", pcMach); } @@ -1386,7 +1526,7 @@ DoCmds(master, pports, cmdi) continue; } #if HAVE_OPENSSL - if (fReqEncryption) { + if (config->sslenabled == FLAGTRUE) { FileWrite(pcf, FLAGFALSE, "ssl\r\n", 5); t = ReadReply(pcf, 0); if (strcmp(t, "ok\r\n") == 0) { @@ -1397,7 +1537,7 @@ DoCmds(master, pports, cmdi) FileClose(&pcf); continue; } - } else if (fAllowUnencrypted == 0) { + } else if (config->sslrequired == FLAGTRUE) { Error("Encryption not supported by server `%s'", serverName); FileClose(&pcf); @@ -1406,7 +1546,7 @@ DoCmds(master, pports, cmdi) } #endif - FilePrint(pcf, FLAGFALSE, "login %s\r\n", pcUser); + FilePrint(pcf, FLAGFALSE, "login %s\r\n", config->username); t = ReadReply(pcf, 0); if (strncmp(t, "passwd?", 7) == 0) { @@ -1425,7 +1565,7 @@ DoCmds(master, pports, cmdi) if (tmpString->used <= 1) { char *pass; BuildStringPrint(tmpString, "Enter %s@%s's password: ", - pcUser, hostname); + config->username, hostname); pass = GetPassword(tmpString->string); if (pass == (char *)0) { Error("could not get password from tty for `%s'", @@ -1590,13 +1730,15 @@ main(argc, argv) int opt; int fLocal; static STRING *acPorts = (STRING *)0; - static char acOpts[] = "7aAb:B:c:d:De:EfFhiIl:M:p:PqQrRsSt:uUvVwWx"; + static char acOpts[] = "7aAb:B:c:C:d:De:EfFhiIl:M:np:PqQrRsSt:uUvVwWx"; extern int optind; extern int optopt; extern char *optarg; static STRING *textMsg = (STRING *)0; int cmdi; static STRING *consoleName = (STRING *)0; + short readSystemConf = 1; + char *userConf = (char *)0; isMultiProc = 0; /* make sure stuff DOESN'T have the pid */ @@ -1613,6 +1755,17 @@ main(argc, argv) ++progname; } + /* prep the config options */ + if ((optConf = (CONFIG *)calloc(1, sizeof(CONFIG))) == (CONFIG *)0) + OutOfMem(); + if ((config = (CONFIG *)calloc(1, sizeof(CONFIG))) == (CONFIG *)0) + OutOfMem(); + if ((pConfig = (CONFIG *)calloc(1, sizeof(CONFIG))) == (CONFIG *)0) + OutOfMem(); + /* and the terminal options */ + if ((pTerm = (TERM *)calloc(1, sizeof(TERM))) == (TERM *)0) + OutOfMem(); + /* command line parsing */ pcCmd = (char *)0; @@ -1620,7 +1773,7 @@ main(argc, argv) while ((opt = getopt(argc, argv, acOpts)) != EOF) { switch (opt) { case '7': /* strip high-bit */ - fStrip = 1; + optConf->striphigh = FLAGTRUE; break; case 'A': /* attach with log replay */ @@ -1641,9 +1794,15 @@ main(argc, argv) OutOfMem(); break; + case 'C': + userConf = optarg; + break; + case 'c': #if HAVE_OPENSSL - pcCredFile = optarg; + if ((optConf->sslcredentials = + StrDup(optarg)) == (char *)0) + OutOfMem(); #endif break; @@ -1661,12 +1820,13 @@ main(argc, argv) case 'E': #if HAVE_OPENSSL - fReqEncryption = 0; + optConf->sslenabled = FLAGFALSE; #endif break; case 'e': /* set escape chars */ - ParseEsc(optarg); + if ((optConf->escape = StrDup(optarg)) == (char *)0) + OutOfMem(); break; case 'F': /* force attach with log replay */ @@ -1684,15 +1844,22 @@ main(argc, argv) break; case 'l': - pcUser = optarg; + if ((optConf->username = StrDup(optarg)) == (char *)0) + OutOfMem(); break; case 'M': - pcInMaster = optarg; + if ((optConf->master = StrDup(optarg)) == (char *)0) + OutOfMem(); + break; + + case 'n': + readSystemConf = 0; break; case 'p': - pcPort = optarg; + if ((optConf->port = StrDup(optarg)) == (char *)0) + OutOfMem(); break; case 'P': /* send a pid command to the server */ @@ -1737,7 +1904,7 @@ main(argc, argv) case 'U': #if HAVE_OPENSSL - fAllowUnencrypted = 1; + optConf->sslrequired = FLAGFALSE; #endif break; @@ -1783,6 +1950,109 @@ main(argc, argv) Bye(EX_OK); } + ProbeInterfaces(INADDR_ANY); + + if (readSystemConf) + ReadConf(CLIENTCONFIGFILE, FLAGFALSE); + + if (userConf == (char *)0) { + /* read the config files */ + char *h = (char *)0; + + if (((h = getenv("HOME")) == (char *)0) && + ((pwdMe = getpwuid(getuid())) == (struct passwd *)0)) { + Error("$HOME does not exist and getpwuid fails: %d: %s", + (int)(getuid()), strerror(errno)); + } else { + if (h == (char *)0) { + if (pwdMe->pw_dir == (char *)0 || + pwdMe->pw_dir[0] == '\000') { + Error("Home directory for uid %d is not defined", + (int)(getuid())); + Bye(EX_UNAVAILABLE); + } else { + h = pwdMe->pw_dir; + } + } + } + if (h != (char *)0) { + BuildTmpString((char *)0); + BuildTmpString(h); + h = BuildTmpString("/.consolerc"); + ReadConf(h, FLAGFALSE); + BuildTmpString((char *)0); + } + } else + ReadConf(userConf, FLAGTRUE); + + if (optConf->striphigh != FLAGUNKNOWN) + config->striphigh = optConf->striphigh; + else if (pConfig->striphigh != FLAGUNKNOWN) + config->striphigh = pConfig->striphigh; + else + config->striphigh = FLAGFALSE; + + if (optConf->escape != (char *)0) + ParseEsc(optConf->escape); + else if (pConfig->escape != (char *)0) + ParseEsc(pConfig->escape); + + if (optConf->username != (char *)0) + config->username = StrDup(optConf->username); + else if (pConfig->username != (char *)0) + config->username = StrDup(pConfig->username); + else + config->username = (char *)0; + + if (optConf->master != (char *)0 && optConf->master[0] != '\000') + config->master = StrDup(optConf->master); + else if (pConfig->master != (char *)0 && pConfig->master[0] != '\000') + config->master = StrDup(pConfig->master); + else + config->master = StrDup( +#if USE_UNIX_DOMAIN_SOCKETS + UDSDIR +#else + MASTERHOST /* which machine is current */ +#endif + ); + if (config->master == (char *)0) + OutOfMem(); + + if (optConf->port != (char *)0 && optConf->port[0] != '\000') + config->port = StrDup(optConf->port); + else if (pConfig->port != (char *)0 && pConfig->port[0] != '\000') + config->port = StrDup(pConfig->port); + else + config->port = StrDup(DEFPORT); + if (config->port == (char *)0) + OutOfMem(); + +#if HAVE_OPENSSL + if (optConf->sslcredentials != (char *)0 && + optConf->sslcredentials[0] != '\000') + config->sslcredentials = StrDup(optConf->sslcredentials); + else if (pConfig->sslcredentials != (char *)0 && + pConfig->sslcredentials[0] != '\000') + config->sslcredentials = StrDup(pConfig->sslcredentials); + else + config->sslcredentials = (char *)0; + + if (optConf->sslenabled != FLAGUNKNOWN) + config->sslenabled = optConf->sslenabled; + else if (pConfig->sslenabled != FLAGUNKNOWN) + config->sslenabled = pConfig->sslenabled; + else + config->sslenabled = FLAGTRUE; + + if (optConf->sslrequired != FLAGUNKNOWN) + config->sslrequired = optConf->sslrequired; + else if (pConfig->sslrequired != FLAGUNKNOWN) + config->sslrequired = pConfig->sslrequired; + else + config->sslrequired = FLAGTRUE; +#endif + /* finish resolving the command to do */ if (pcCmd == (char *)0) { pcCmd = "attach"; @@ -1813,23 +2083,20 @@ main(argc, argv) Bye(EX_UNAVAILABLE); } #if !USE_UNIX_DOMAIN_SOCKETS - /* if we somehow lost the port (or got an empty string), reset */ - if (pcPort == (char *)0 || pcPort[0] == '\000') - pcPort = DEFPORT; - /* Look for non-numeric characters */ - for (opt = 0; pcPort[opt] != '\000'; opt++) - if (!isdigit((int)pcPort[opt])) + for (opt = 0; config->port[opt] != '\000'; opt++) + if (!isdigit((int)config->port[opt])) break; - if (pcPort[opt] == '\000') { + if (config->port[opt] == '\000') { /* numeric only */ - bindPort = atoi(pcPort); + bindPort = atoi(config->port); } else { /* non-numeric only */ struct servent *pSE; - if ((pSE = getservbyname(pcPort, "tcp")) == (struct servent *)0) { - Error("getservbyname(%s) failed", pcPort); + if ((pSE = + getservbyname(config->port, "tcp")) == (struct servent *)0) { + Error("getservbyname(%s) failed", config->port); Bye(EX_UNAVAILABLE); } else { bindPort = ntohs((u_short) pSE->s_port); @@ -1837,24 +2104,28 @@ main(argc, argv) } #endif - if (pcUser == (char *)0 || pcUser[0] == '\000') { - if (((pcUser = getenv("LOGNAME")) == (char *)0) && - ((pcUser = getenv("USER")) == (char *)0) && + if (config->username == (char *)0 || config->username[0] == '\000') { + if (config->username != (char *)0) + free(config->username); + if (((config->username = getenv("LOGNAME")) == (char *)0) && + ((config->username = getenv("USER")) == (char *)0) && ((pwdMe = getpwuid(getuid())) == (struct passwd *)0)) { Error ("$LOGNAME and $USER do not exist and getpwuid fails: %d: %s", (int)(getuid()), strerror(errno)); Bye(EX_UNAVAILABLE); } - if (pcUser == (char *)0) { + if (config->username == (char *)0) { if (pwdMe->pw_name == (char *)0 || pwdMe->pw_name[0] == '\000') { Error("Username for uid %d does not exist", (int)(getuid())); Bye(EX_UNAVAILABLE); } else { - pcUser = pwdMe->pw_name; + config->username = pwdMe->pw_name; } } + if ((config->username = StrDup(config->username)) == (char *)0) + OutOfMem(); } if (execCmd == (STRING *)0) @@ -1866,7 +2137,7 @@ main(argc, argv) BuildString((char *)0, acPorts); BuildStringChar('@', acPorts); - BuildString(pcInMaster, acPorts); + BuildString(config->master, acPorts); #if HAVE_OPENSSL SetupSSL(); /* should only do if we want ssl - provide flag! */ @@ -1890,7 +2161,7 @@ main(argc, argv) for (;;) { if (gotoConsole == (CONSFILE *)0) - DoCmds(pcInMaster, acPorts->string, cmdi); + DoCmds(config->master, acPorts->string, cmdi); else Interact(gotoConsole, gotoName); diff --git a/console/console.man b/console/console.man index 49d8eb8..3176295 100644 --- a/console/console.man +++ b/console/console.man @@ -1,15 +1,17 @@ -.\" $Id: console.man,v 1.48 2004/04/20 01:30:13 bryan Exp $ -.TH CONSOLE 1 "2004/04/20" "conserver-8.1.5" "conserver" +.\" $Id: console.man,v 1.51 2004/05/25 00:38:15 bryan Exp $ +.TH CONSOLE 1 "2004/05/25" "conserver-8.1.6" "conserver" .SH NAME console \- console server client program .SH SYNOPSIS .B console .RB [ \-aAfFsS ] -.RB [ \-7DEUv ] +.RB [ \-7DEnUv ] .RB [ \-c .IR cred ] +.RB [ \-C +.IR config ] .BR [ \-M -.IR mach ] +.IR master ] .BR [ \-p .IR port ] .BR [ \-e @@ -20,11 +22,13 @@ console \- console server client program .br .B console .RB [ \-hiIPrRuVwWx ] -.RB [ \-7DEUv ] +.RB [ \-7DEnUv ] .RB [ \-c .IR cred ] +.RB [ \-C +.IR config ] .RB [ \-M -.IR mach ] +.IR master ] .RB [ \-p .IR port ] .RB [ \-d @@ -37,11 +41,13 @@ console \- console server client program .br .B console .RB [ \-qQ ] -.RB [ \-7DEUv ] +.RB [ \-7DEnUv ] .RB [ \-c .IR cred ] +.RB [ \-C +.IR config ] .RB [ \-M -.IR mach ] +.IR master ] .RB [ \-p .IR port ] .SH DESCRIPTION @@ -120,6 +126,10 @@ to users on the primary server. Load an SSL certificate and key from the PEM encoded file .IR cred . .TP +.BI \-C config +Use the per-user configuration file +.IR conf . +.TP .B \-d Disconnect the users specified by .IR user @ console . @@ -187,19 +197,34 @@ uses $USER if its uid matches the user's real uid, or $LOGNAME if its uid matches the user's real uid, or else the name associated with the user's real uid. .TP -.BI \-M mach +.BI \-M master The .B console client program polls -.I mach +.I master as the primary server, rather than the default set at compile time (typically .RB `` console ''). The default -.I mach +.I master may be changed at compile time using the .B --with-master option. +If +.B --with-uds +is used to enable Unix domain sockets, however, this option points +.B console +to the directory which holds those sockets. +The default +.I master +directory +.RB (`` /tmp/conserver '') +may be changed at compile time using the +.B --with-uds +option. +.TP +.BI \-n +Do not read the system-wide configuration file. .TP .BI \-p port Set the port to connect to. @@ -211,6 +236,9 @@ may be changed at compile time using the .B --with-port option. +If the +.B --with-uds +option was used, this option is ignored. .TP .B \-P Display the pid of the master daemon process on each server. @@ -395,6 +423,311 @@ The idletimeout configuration option for the console. .TP .I idlestring The idlestring configuration option for the console. +.SH CONFIGURATION +.B Console +reads configuration information from the system-wide configuration file +.RB ( console.cf ), +then the per-user configuration file +.RB ( .consolerc ), +and then applies command-line arguments. +Each configuration location can override the previous. +The same happens when parsing an individual file - the later entries +always override the earlier entries. +Because of that, you should put ``global'' defaults first and +more specific defaults second. +.PP +The configuration file is read using the same parser as +.BR conserver.cf (5), +and you should check that manpage for parser details. +.B Console +recognizes the following configuration blocks. +.TP 8 +.B config +.RI [ " hostname " | " ipaddr " ] +.br +Define a configuration block for the host named +.I hostname +or using the address +.IR ipaddr . +If the value of ``*'' is used, the configuration block will be applied to +all hosts. +.RS +.TP 15 +.B escape +.I esc +.br +Set the escape sequence (see the +.B \-e +command-line flag). +.TP +.B master +.I master +.br +Set the default master to +.I master +(see the +.B \-M +command-line flag). +.TP +.B port +.I port +.br +Set the default port to +.I port +(see the +.B \-p +command-line flag). +.TP +.B sslcredentials +.I filename +.br +Set the +.SM SSL +credentials file location (see the +.B \-c +command-line flag). +.TP +.B sslenabled +.RB [ " yes " | " true " +.RB | " on " | " no " +.RB | " false " | " off " ] +.br +Set whether or not encryption is attempted when talking to servers (see the +.B \-E +command-line flag). +.TP +.B sslrequired +.RB [ " yes " | " true " +.RB | " on " | " no " +.RB | " false " | " off " ] +.br +Set whether or not encryption is required when talking to servers (see the +.B \-U +command-line flag). +.TP +.B striphigh +.RB [ " yes " | " true " +.RB | " on " | " no " +.RB | " false " | " off " ] +.br +Set whether or not to strip the high bit off all data received +(see the +.B \-7 +command-line flag). +.TP +.B username +.I user +.br +Set the username passed to the server to +.I user +(see the +.B \-l +command-line flag). +.RE +.TP 8 +.B terminal +.I type +.br +Define a configuration block when using a terminal of type +.IR type . +If the value of ``*'' is used, the configuration block will be applied to +all terminal types. +.RS +.TP 15 +.B attach +.RI [ " string " +| "" ] +.br +Set a +.I string +to print when successfully attached to a console. +Character substitions will be performed based on the +.B attachsubst +value and occur +.I before +interpretation of the special characters below. +If the null string (``""'') is used, no string will be printed. +.I string +is a simple character string with the exception of `\e' +and `^': +.RS +.RS +.sp +.PD 0 +.TP 6 +.B \ea +alert +.TP +.B \eb +backspace +.TP +.B \ef +form-feed +.TP +.B \en +newline +.TP +.B \er +carriage-return +.TP +.B \et +tab +.TP +.B \ev +vertical-tab +.TP +.B \e\e +backslash +.TP +.B \e^ +circumflex +.TP +.BI \e ooo +octal representation of a character (where +.I ooo +is one to three octal digits) +.TP +.BI \e c +character +.I c +.TP +.B ^? +delete +.TP +.BI ^ c +control character +.RI ( c +is ``and''ed with 0x1f) +.PD +.RE +.RE +.IP +An interesting use of +.B attach +and +.B attachsubst +would be: +.RS +.IP +.ft CR +.nf +terminal xterm { + attach "^[]0;conserver: U@C^G"; + attachsubst U=us,C=cs; +} +.fi +.ft +.RE +.TP +.B attachsubst +[\f2c\fP=\f2t\fP[\f2n\fP]\f2f\fP[,...] +| "" ] +.br +Perform character substitutions on the +.B attach +value. +A series of replacements can be defined by specifying a +comma-separated list of +\f2c\fP=\f2t\fP[\f2n\fP]\f2f\fP +sequences where +.I c +is any printable character, +.I t +specifies the replacement value, +.I n +is a field length (optional), +and +.I f +is the format string. +.I t +can be one of the characters below, catagorized as a string replacement +or a numeric replacement, which dictates the use of the +.I n +and +.I f +fields. +.RS +.RS +.sp +.PD 0 +.TP +String Replacement +.TP +.B u +username +.TP +.B c +console name +.sp +.PP +Numeric Replacement +.TP +none available (yet) +.PD +.RE +.RE +.IP +For string replacements, if the replacement isn't at least +.I n +characters, it will be padded with space characters on the left. +.I f +must be `s'. +For numeric replacements, the value will be formatted to at least +.I n +characters, padded with 0s if +.I n +begins with a 0, and space characters otherwise. +.I f +must be either `d', `x' or `X', specifying a decimal, lower-case +hexadecimal, or an uppercase hexadecimal conversion. +If the null string (``""'') is used, no replacements will be done. +.TP 15 +.B detach +.RI [ " string " +| "" ] +.br +Set a +.I string +to print once detached from a console. +Character substitions will be performed based on the +.B detachsubst +value. +See the +.B attach +option for an explanation of +.IR string . +If the null string (``""'') is used, no string will be printed. +.TP +.B detachsubst +[\f2c\fP=\f2t\fP[\f2n\fP]\f2f\fP[,...] +| "" ] +.br +Perform character substitutions on the +.B detach +value. +See the +.B attachsubst +option for an explanation of the format string. +.RE +.PP +A simple configuration to set a new default escape sequence and override +the master location would be: +.IP +.ft CR +.nf +# override options for all hosts +config * { + master localhost; + escape ^Ee; +} +# set things more specific to host1 +# note: if the entries were reversed, host1 +# would also use localhost. +config host1 { + master console1; +} +.fi +.ft .SH "ESCAPE SEQUENCES" The connection can be controlled by a two-character escape sequence, followed by a command. @@ -574,6 +907,22 @@ or number of days is displayed. console \-e "^[1" lv426 Requests a connection to the host ``lv426'' with the escape characters set to ``escape one''. +.SH FILES +.PP +The following default file locations may be overridden +at compile time or by the command-line options described above. +Run +.B console \-V +to see the defaults set at compile time. +.PP +.PD 0 +.TP 25 +.B /etc/console.cf +system-wide configuration file +.TP +.B $HOME/.consolerc +per-user configuration file +.PD .SH BUGS It is possible to create a loop of console connections, with ugly results. Never run diff --git a/console/readconf.c b/console/readconf.c new file mode 100644 index 0000000..d09733a --- /dev/null +++ b/console/readconf.c @@ -0,0 +1,720 @@ +/* + * $Id: readconf.c,v 5.2 2004/05/25 00:38:15 bryan Exp $ + * + * Copyright conserver.com, 2000 + * + * Maintainer/Enhancer: Bryan Stansell (bryan@conserver.com) + */ + +#include + +#include +#include + +CONFIG *parserConfigTemp = (CONFIG *)0; +CONFIG *parserConfigDefault = (CONFIG *)0; +CONFIG *pConfig = (CONFIG *)0; +TERM *parserTermTemp = (TERM *)0; +TERM *parserTermDefault = (TERM *)0; +TERM *pTerm = (TERM *)0; + +void +#if PROTOTYPES +DestroyConfig(CONFIG *c) +#else +DestroyConfig(c) + CONFIG *c; +#endif +{ + if (c == (CONFIG *)0) + return; + if (c->username != (char *)0) + free(c->username); + if (c->master != (char *)0) + free(c->master); + if (c->port != (char *)0) + free(c->port); + if (c->escape != (char *)0) + free(c->escape); +#if HAVE_OPENSSL + if (c->sslcredentials != (char *)0) + free(c->sslcredentials); +#endif + free(c); +} + +void +#if PROTOTYPES +ApplyConfigDefault(CONFIG *c) +#else +ApplyConfigDefault(c) + CONFIG *c; +#endif +{ + if (parserConfigDefault == (CONFIG *)0) + return; + + if (parserConfigDefault->username != (char *)0) { + if (c->username != (char *)0) + free(c->username); + if ((c->username = + StrDup(parserConfigDefault->username)) == (char *)0) + OutOfMem(); + } + if (parserConfigDefault->master != (char *)0) { + if (c->master != (char *)0) + free(c->master); + if ((c->master = StrDup(parserConfigDefault->master)) == (char *)0) + OutOfMem(); + } + if (parserConfigDefault->port != (char *)0) { + if (c->port != (char *)0) + free(c->port); + if ((c->port = StrDup(parserConfigDefault->port)) == (char *)0) + OutOfMem(); + } + if (parserConfigDefault->escape != (char *)0) { + if (c->escape != (char *)0) + free(c->escape); + if ((c->escape = StrDup(parserConfigDefault->escape)) == (char *)0) + OutOfMem(); + } + if (parserConfigDefault->striphigh != FLAGUNKNOWN) + c->striphigh = parserConfigDefault->striphigh; +#if HAVE_OPENSSL + if (parserConfigDefault->sslcredentials != (char *)0) { + if (c->sslcredentials != (char *)0) + free(c->sslcredentials); + if ((c->sslcredentials = + StrDup(parserConfigDefault->sslcredentials)) == (char *)0) + OutOfMem(); + } + if (parserConfigDefault->sslrequired != FLAGUNKNOWN) + c->sslrequired = parserConfigDefault->sslrequired; + if (parserConfigDefault->sslenabled != FLAGUNKNOWN) + c->sslenabled = parserConfigDefault->sslenabled; +#endif +} + +void +#if PROTOTYPES +ConfigBegin(char *id) +#else +ConfigBegin(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConfigBegin(%s) [%s:%d]", id, file, line)); + if (id == (char *)0 || id[0] == '\000') { + Error("empty config name [%s:%d]", file, line); + return; + } + if (parserConfigTemp != (CONFIG *)0) + DestroyConfig(parserConfigTemp); + if ((parserConfigTemp = (CONFIG *)calloc(1, sizeof(CONFIG))) + == (CONFIG *)0) + OutOfMem(); + ApplyConfigDefault(parserConfigTemp); + parserConfigTemp->name = AllocString(); + BuildString(id, parserConfigTemp->name); +} + +void +#if PROTOTYPES +ConfigEnd(void) +#else +ConfigEnd() +#endif +{ + CONDDEBUG((1, "ConfigEnd() [%s:%d]", file, line)); + + if (parserConfigTemp == (CONFIG *)0) + return; + + if (parserConfigTemp->name->used > 1) { + if ((parserConfigTemp->name->string[0] == '*' && + parserConfigTemp->name->string[1] == '\000') || + IsMe(parserConfigTemp->name->string)) { + DestroyConfig(parserConfigDefault); + parserConfigDefault = parserConfigTemp; + parserConfigTemp = (CONFIG *)0; + } + } + + DestroyConfig(parserConfigTemp); + parserConfigTemp = (CONFIG *)0; +} + +void +#if PROTOTYPES +ConfigAbort(void) +#else +ConfigAbort() +#endif +{ + CONDDEBUG((1, "ConfigAbort() [%s:%d]", file, line)); + if (parserConfigTemp == (CONFIG *)0) + return; + + DestroyConfig(parserConfigTemp); + parserConfigTemp = (CONFIG *)0; +} + +void +#if PROTOTYPES +ConfigDestroy(void) +#else +ConfigDestroy() +#endif +{ + CONDDEBUG((1, "ConfigDestroy() [%s:%d]", file, line)); + + if (parserConfigTemp != (CONFIG *)0) { + DestroyConfig(parserConfigTemp); + parserConfigTemp = (CONFIG *)0; + } + + if (parserConfigDefault != (CONFIG *)0) { + DestroyConfig(pConfig); + pConfig = parserConfigDefault; + parserConfigDefault = (CONFIG *)0; + } +} + +void +#if PROTOTYPES +DestroyTerminal(TERM *t) +#else +DestroyTerminal(t) + TERM *t; +#endif +{ + if (t == (TERM *)0) + return; + if (t->attach != (char *)0) + free(t->attach); + if (t->attachsubst != (char *)0) + free(t->attachsubst); + if (t->detach != (char *)0) + free(t->detach); + if (t->detachsubst != (char *)0) + free(t->detachsubst); + free(t); +} + +void +#if PROTOTYPES +ApplyTermDefault(TERM *t) +#else +ApplyTermDefault(t) + TERM *t; +#endif +{ + if (parserTermDefault == (TERM *)0) + return; + + if (parserTermDefault->attach != (char *)0) { + if (t->attach != (char *)0) + free(t->attach); + if ((t->attach = StrDup(parserTermDefault->attach)) == (char *)0) + OutOfMem(); + } + if (parserTermDefault->attachsubst != (char *)0) { + if (t->attachsubst != (char *)0) + free(t->attachsubst); + if ((t->attachsubst = + StrDup(parserTermDefault->attachsubst)) == (char *)0) + OutOfMem(); + } + if (parserTermDefault->detach != (char *)0) { + if (t->detach != (char *)0) + free(t->detach); + if ((t->detach = StrDup(parserTermDefault->detach)) == (char *)0) + OutOfMem(); + } + if (parserTermDefault->detachsubst != (char *)0) { + if (t->detachsubst != (char *)0) + free(t->detachsubst); + if ((t->detachsubst = + StrDup(parserTermDefault->detachsubst)) == (char *)0) + OutOfMem(); + } +} + +void +#if PROTOTYPES +TerminalBegin(char *id) +#else +TerminalBegin(id) + char *id; +#endif +{ + CONDDEBUG((1, "TerminalBegin(%s) [%s:%d]", id, file, line)); + if (id == (char *)0 || id[0] == '\000') { + Error("empty terminal name [%s:%d]", file, line); + return; + } + if (parserTermTemp != (TERM *)0) + DestroyTerminal(parserTermTemp); + if ((parserTermTemp = (TERM *)calloc(1, sizeof(TERM))) + == (TERM *)0) + OutOfMem(); + ApplyTermDefault(parserTermTemp); + parserTermTemp->name = AllocString(); + BuildString(id, parserTermTemp->name); +} + +void +#if PROTOTYPES +TerminalEnd(void) +#else +TerminalEnd() +#endif +{ + static char *term = (char *)0; + + CONDDEBUG((1, "TerminalEnd() [%s:%d]", file, line)); + + if (parserTermTemp == (TERM *)0) + return; + + if (term == (char *)0) { + if ((term = getenv("TERM")) == (char *)0) { + term = ""; + } + } + + if (parserTermTemp->name->used > 1) { + if ((parserTermTemp->name->string[0] == '*' && + parserTermTemp->name->string[1] == '\000') || + strcmp(parserTermTemp->name->string, term) == 0) { + DestroyTerminal(parserTermDefault); + parserTermDefault = parserTermTemp; + parserTermTemp = (TERM *)0; + } + } + + DestroyTerminal(parserTermTemp); + parserTermTemp = (TERM *)0; +} + +void +#if PROTOTYPES +TerminalAbort(void) +#else +TerminalAbort() +#endif +{ + CONDDEBUG((1, "TerminalAbort() [%s:%d]", file, line)); + if (parserTermTemp == (TERM *)0) + return; + + DestroyTerminal(parserTermTemp); + parserTermTemp = (TERM *)0; +} + +void +#if PROTOTYPES +TerminalDestroy(void) +#else +TerminalDestroy() +#endif +{ + CONDDEBUG((1, "TerminalDestroy() [%s:%d]", file, line)); + + if (parserTermTemp != (TERM *)0) { + DestroyTerminal(parserTermTemp); + parserTermTemp = (TERM *)0; + } + + if (parserTermDefault != (TERM *)0) { + DestroyTerminal(pTerm); + pTerm = parserTermDefault; + parserTermDefault = (TERM *)0; + } +} + +void +#if PROTOTYPES +ProcessYesNo(char *id, FLAG *flag) +#else +ProcessYesNo(id, flag) + char *id; + FLAG *flag; +#endif +{ + if (id == (char *)0 || id[0] == '\000') + *flag = FLAGFALSE; + else if (strcasecmp("yes", id) == 0 || strcasecmp("true", id) == 0 || + strcasecmp("on", id) == 0) + *flag = FLAGTRUE; + else if (strcasecmp("no", id) == 0 || strcasecmp("false", id) == 0 || + strcasecmp("off", id) == 0) + *flag = FLAGFALSE; +} + +void +#if PROTOTYPES +ConfigItemEscape(char *id) +#else +ConfigItemEscape(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConfigItemEscape(%s) [%s:%d]", id, file, line)); + + if (parserConfigTemp->escape != (char *)0) + free(parserConfigTemp->escape); + + if ((id == (char *)0) || (*id == '\000')) { + parserConfigTemp->escape = (char *)0; + return; + } + if ((parserConfigTemp->escape = StrDup(id)) == (char *)0) + OutOfMem(); +} + +void +#if PROTOTYPES +ConfigItemMaster(char *id) +#else +ConfigItemMaster(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConfigItemMaster(%s) [%s:%d]", id, file, line)); + + if (parserConfigTemp->master != (char *)0) + free(parserConfigTemp->master); + + if ((id == (char *)0) || (*id == '\000')) { + parserConfigTemp->master = (char *)0; + return; + } + if ((parserConfigTemp->master = StrDup(id)) == (char *)0) + OutOfMem(); +} + +void +#if PROTOTYPES +ConfigItemPort(char *id) +#else +ConfigItemPort(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConfigItemPort(%s) [%s:%d]", id, file, line)); + + if (parserConfigTemp->port != (char *)0) + free(parserConfigTemp->port); + + if ((id == (char *)0) || (*id == '\000')) { + parserConfigTemp->port = (char *)0; + return; + } + if ((parserConfigTemp->port = StrDup(id)) == (char *)0) + OutOfMem(); +} + +void +#if PROTOTYPES +ConfigItemSslcredentials(char *id) +#else +ConfigItemSslcredentials(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConfigItemSslcredentials(%s) [%s:%d]", id, file, line)); +#if HAVE_OPENSSL + if (parserConfigTemp->sslcredentials != (char *)0) + free(parserConfigTemp->sslcredentials); + + if ((id == (char *)0) || (*id == '\000')) { + parserConfigTemp->sslcredentials = (char *)0; + return; + } + if ((parserConfigTemp->sslcredentials = StrDup(id)) == (char *)0) + OutOfMem(); +#else + Error + ("sslcredentials ignored - encryption not compiled into code [%s:%d]", + file, line); +#endif +} + +void +#if PROTOTYPES +ConfigItemSslrequired(char *id) +#else +ConfigItemSslrequired(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConfigItemSslrequired(%s) [%s:%d]", id, file, line)); +#if HAVE_OPENSSL + ProcessYesNo(id, &(parserConfigTemp->sslrequired)); +#else + Error + ("sslrequired ignored - encryption not compiled into code [%s:%d]", + file, line); +#endif +} + +void +#if PROTOTYPES +ConfigItemSslenabled(char *id) +#else +ConfigItemSslenabled(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConfigItemSslenabled(%s) [%s:%d]", id, file, line)); +#if HAVE_OPENSSL + ProcessYesNo(id, &(parserConfigTemp->sslenabled)); +#else + Error("sslenabled ignored - encryption not compiled into code [%s:%d]", + file, line); +#endif +} + +void +#if PROTOTYPES +ConfigItemStriphigh(char *id) +#else +ConfigItemStriphigh(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConfigItemStriphigh(%s) [%s:%d]", id, file, line)); + ProcessYesNo(id, &(parserConfigTemp->striphigh)); +} + +void +#if PROTOTYPES +ConfigItemUsername(char *id) +#else +ConfigItemUsername(id) + char *id; +#endif +{ + CONDDEBUG((1, "ConfigItemUsername(%s) [%s:%d]", id, file, line)); + + if (parserConfigTemp->username != (char *)0) + free(parserConfigTemp->username); + + if ((id == (char *)0) || (*id == '\000')) { + parserConfigTemp->username = (char *)0; + return; + } + if ((parserConfigTemp->username = StrDup(id)) == (char *)0) + OutOfMem(); +} + +SUBST *substData = (SUBST *) 0; + +int +#if PROTOTYPES +SubstCallback(char c, char **s, int *i) +#else +SubstCallback(c, s, i) + char c; + char **s; + int *i; +#endif +{ + int retval = 0; + + if (substData == (SUBST *) 0) { + if ((substData = + (SUBST *) calloc(1, sizeof(SUBST))) == (SUBST *) 0) + OutOfMem(); + substData->callback = &SubstCallback; + substData->tokens['u'] = ISSTRING; + substData->tokens['c'] = ISSTRING; + } + + if (s != (char **)0) { + CONFIG *pc; + if (substData->data == (void *)0) + return 0; + + pc = (CONFIG *)(substData->data); + if (c == 'u') { + (*s) = pc->username; + retval = 1; + } else if (c == 'c') { + (*s) = pc->console; + retval = 1; + } + } + + return retval; +} + +void +#if PROTOTYPES +TerminalItemAttach(char *id) +#else +TerminalItemAttach(id) + char *id; +#endif +{ + CONDDEBUG((1, "TerminalItemAttach(%s) [%s:%d]", id, file, line)); + + if (parserTermTemp->attach != (char *)0) + free(parserTermTemp->attach); + + if ((id == (char *)0) || (*id == '\000')) { + parserTermTemp->attach = (char *)0; + return; + } + if ((parserTermTemp->attach = StrDup(id)) == (char *)0) + OutOfMem(); +} + +void +#if PROTOTYPES +TerminalItemAttachsubst(char *id) +#else +TerminalItemAttachsubst(id) + char *id; +#endif +{ + CONDDEBUG((1, "TerminalItemAttachsubst(%s) [%s:%d]", id, file, line)); + ProcessSubst(substData, (char **)0, &(parserTermTemp->attachsubst), + "attachsubst", id); +} + +void +#if PROTOTYPES +TerminalItemDetach(char *id) +#else +TerminalItemDetach(id) + char *id; +#endif +{ + CONDDEBUG((1, "TerminalItemDetach(%s) [%s:%d]", id, file, line)); + + if (parserTermTemp->detach != (char *)0) + free(parserTermTemp->detach); + + if ((id == (char *)0) || (*id == '\000')) { + parserTermTemp->detach = (char *)0; + return; + } + if ((parserTermTemp->detach = StrDup(id)) == (char *)0) + OutOfMem(); +} + +void +#if PROTOTYPES +TerminalItemDetachsubst(char *id) +#else +TerminalItemDetachsubst(id) + char *id; +#endif +{ + CONDDEBUG((1, "TerminalItemDetachsubst(%s) [%s:%d]", id, file, line)); + ProcessSubst(substData, (char **)0, &(parserTermTemp->detachsubst), + "detachsubst", id); +} + +ITEM keyConfig[] = { + {"escape", ConfigItemEscape}, + {"master", ConfigItemMaster}, + {"port", ConfigItemPort}, + {"sslcredentials", ConfigItemSslcredentials}, + {"sslrequired", ConfigItemSslrequired}, + {"sslenabled", ConfigItemSslenabled}, + {"striphigh", ConfigItemStriphigh}, + {"username", ConfigItemUsername}, + {(char *)0, (void *)0} +}; + +ITEM keyTerminal[] = { + {"attach", TerminalItemAttach}, + {"attachsubst", TerminalItemAttachsubst}, + {"detach", TerminalItemDetach}, + {"detachsubst", TerminalItemDetachsubst}, + {(char *)0, (void *)0} +}; + +SECTION sections[] = { + {"config", ConfigBegin, ConfigEnd, ConfigAbort, ConfigDestroy, + keyConfig}, + {"terminal", TerminalBegin, TerminalEnd, TerminalAbort, + TerminalDestroy, keyTerminal}, + {(char *)0, (void *)0, (void *)0, (void *)0, (void *)0} +}; + +void +#if PROTOTYPES +ReadConf(char *filename, FLAG verbose) +#else +ReadConf(filename, verbose) + char *filename; + FLAG verbose; +#endif +{ + FILE *fp; + + if ((FILE *)0 == (fp = fopen(filename, "r"))) { + if (verbose == FLAGTRUE) + Error("could not open `%s'", filename); + return; + } + + /* initialize the substition bits */ + SubstCallback('\000', (char **)0, (int *)0); + + parserConfigDefault = pConfig; + pConfig = (CONFIG *)0; + + parserTermDefault = pTerm; + pTerm = (TERM *)0; + + ParseFile(filename, fp, 0); + + /* shouldn't really happen, but in case i screw up the stuff + * ParseFile calls... + */ + if (pConfig == (CONFIG *)0) { + if ((pConfig = (CONFIG *)calloc(1, sizeof(CONFIG))) + == (CONFIG *)0) + OutOfMem(); + } + + if (pTerm == (TERM *)0) { + if ((pTerm = (TERM *)calloc(1, sizeof(TERM))) + == (TERM *)0) + OutOfMem(); + } + + if (fDebug) { +#define EMPTYSTR(x) x == (char *)0 ? "(null)" : x +#define FLAGSTR(x) x == FLAGTRUE ? "true" : (x == FLAGFALSE ? "false" : "unset") + CONDDEBUG((1, "pConfig->username = %s", + EMPTYSTR(pConfig->username))); + CONDDEBUG((1, "pConfig->master = %s", EMPTYSTR(pConfig->master))); + CONDDEBUG((1, "pConfig->port = %s", EMPTYSTR(pConfig->port))); + CONDDEBUG((1, "pConfig->escape = %s", EMPTYSTR(pConfig->escape))); + CONDDEBUG((1, "pConfig->striphigh = %s", + FLAGSTR(pConfig->striphigh))); +#if HAVE_OPENSSL + CONDDEBUG((1, "pConfig->sslcredentials = %s", + EMPTYSTR(pConfig->sslcredentials))); + CONDDEBUG((1, "pConfig->sslrequired = %s", + FLAGSTR(pConfig->sslrequired))); + CONDDEBUG((1, "pConfig->sslenabled = %s", + FLAGSTR(pConfig->sslenabled))); +#endif + CONDDEBUG((1, "pTerm->attach = %s", EMPTYSTR(pTerm->attach))); + CONDDEBUG((1, "pTerm->attachsubst = %s", + EMPTYSTR(pTerm->attachsubst))); + CONDDEBUG((1, "pTerm->detach = %s", EMPTYSTR(pTerm->detach))); + CONDDEBUG((1, "pTerm->detachsubst = %s", + EMPTYSTR(pTerm->detachsubst))); + } + + fclose(fp); +} diff --git a/console/readconf.h b/console/readconf.h new file mode 100644 index 0000000..b3e60dd --- /dev/null +++ b/console/readconf.h @@ -0,0 +1,38 @@ +/* + * $Id: readconf.h,v 5.3 2004/05/25 23:03:25 bryan Exp $ + * + * Copyright conserver.com, 2000 + * + * Maintainer/Enhancer: Bryan Stansell (bryan@conserver.com) + */ + +typedef struct config { + STRING *name; + char *console; + char *username; + char *master; + char *port; + char *escape; + FLAG striphigh; +#if HAVE_OPENSSL + char *sslcredentials; + FLAG sslrequired; + FLAG sslenabled; +#endif +} CONFIG; + +typedef struct term { + STRING *name; + char *attach; + char *attachsubst; + char *detach; + char *detachsubst; +} TERM; + +extern CONFIG *pConfig; +extern TERM *pTerm; +extern SUBST *substData; + +extern void ReadConf PARAMS((char *, FLAG)); +extern void DestroyConfig PARAMS((CONFIG *)); +extern void DestroyTerminal PARAMS((TERM *)); diff --git a/contrib/redhat-rpm/conserver.spec b/contrib/redhat-rpm/conserver.spec index 5eb2d7f..d71de6b 100644 --- a/contrib/redhat-rpm/conserver.spec +++ b/contrib/redhat-rpm/conserver.spec @@ -4,7 +4,7 @@ # %define pkg conserver -%define ver 8.1.5 +%define ver 8.1.6 # 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 b3cf8dd..10dd928 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.1.5" +VERSION="8.1.6" DESC="Console server and client" CLASSES=none ARCH=sparc diff --git a/test/dotest b/test/dotest index d99197d..bec0293 100755 --- a/test/dotest +++ b/test/dotest @@ -14,6 +14,7 @@ cleanup() [ "$i" != "conserver.log" ] && [ -f "$i" ] && rm -f "$i"; done [ "$exitval" = 0 ] && rm -f conserver.log + [ -d 127.0.0.1 ] && sleep 1 && rm -rf 127.0.0.1 exit $exitval } @@ -25,7 +26,7 @@ dotest() eval "$2" > test.out 2>&1 else echo "$1" | \ - ../console/console -M 127.0.0.1 -p 7777 shell > test.out 2>&1 + ../console/console -n -C /dev/null -M 127.0.0.1 -p 7777 shell > test.out 2>&1 fi if [ "$record" ]; then echo "recorded" @@ -72,7 +73,7 @@ sleep 3 [ ! -d results ] && mkdir results -dotest EVAL "../console/console -M 127.0.0.1 -p 7777 -u | sed -e 's/[0-9][0-9]*//g' -e 's/[ ][ ]*/ /g'" +dotest EVAL "../console/console -n -C /dev/null -M 127.0.0.1 -p 7777 -u | sed -e 's/[0-9][0-9]*//g' -e 's/[ ][ ]*/ /g'" dotest 'c?c.' dotest 'cl?c.' dotest 'cdc.' @@ -84,14 +85,14 @@ cp test2.cf c.cf kill -1 $pid sleep 3 -dotest EVAL "../console/console -M 127.0.0.1 -p 7777 -u | sed -e 's/[0-9][0-9]*//g' -e 's/[ ][ ]*/ /g'" +dotest EVAL "../console/console -n -C /dev/null -M 127.0.0.1 -p 7777 -u | sed -e 's/[0-9][0-9]*//g' -e 's/[ ][ ]*/ /g'" dotest 'c?c.' dotest 'cl?c.' dotest 'cdc.' dotest 'coc.' -dotest EVAL "echo 'tu.' | ../console/console -M 127.0.0.1 -p 7777 -e 'tu' shell" -dotest EVAL "../console/console -M 127.0.0.1 -p 7777 -R | sed -e 's/ [^ ]*$//'" -dotest EVAL "../console/console -M 127.0.0.1 -p 7777 -x | sed -e 's/ on [^ ]* */ on /'" +dotest EVAL "echo 'tu.' | ../console/console -n -C /dev/null -M 127.0.0.1 -p 7777 -e 'tu' shell" +dotest EVAL "../console/console -n -C /dev/null -M 127.0.0.1 -p 7777 -R | sed -e 's/ [^ ]*$//'" +dotest EVAL "../console/console -n -C /dev/null -M 127.0.0.1 -p 7777 -x | sed -e 's/ on [^ ]* */ on /'" cleanup